#include "global.h" #include "pokemon.h" #include "battle.h" #include "random.h" #include "main.h" #include "constants/species.h" #include "constants/abilities.h" #include "constants/items.h" #include "constants/trainers.h" #include "constants/moves.h" #include "constants/hold_effects.h" #include "constants/battle_move_effects.h" #include "string_util.h" #include "text.h" #include "link.h" #include "event_data.h" #include "item.h" #include "battle_controllers.h" #include "evolution_scene.h" //Extracts the upper 16 bits of a 32-bit number #define HIHALF(n) (((n) & 0xFFFF0000) >> 16) //Extracts the lower 16 bits of a 32-bit number #define LOHALF(n) ((n) & 0xFFFF) struct Unknown_020249B4 { u8 unk0[0xC]; struct SpriteTemplate* templates; }; extern u8 gAbsentBattlerFlags; extern u8 gActiveBattler; extern u8 gBattlersCount; extern u8 gBattlerAttacker; extern u16 gBattlerPartyIndexes[]; extern u8 gBattlerTarget; extern u8 gBankInMenu; extern u8 gLastUsedAbility; extern u16 gTrainerBattleOpponent_A; extern u32 gBattleTypeFlags; extern struct SpriteTemplate gUnknown_0202499C; extern struct Unknown_020249B4* gUnknown_020249B4[2]; extern struct BattlePokemon gBattleMons[4]; extern u32 gBattleTypeFlags; extern struct BattlePokemon gBattleMons[4]; extern u16 gCurrentMove; extern u8 gCritMultiplier; extern u16 gBattleWeather; extern struct BattleEnigmaBerry gEnigmaBerries[]; extern u16 gBattleMovePower; extern u16 gTrainerBattleOpponent_A; extern u32 gBattleTypeFlags; extern s32 gBattleMoveDamage; extern u8 gUnknown_0203C7B4; extern u16 gMoveToLearn; extern u8 gStringBattler; extern const u32 gBitTable[]; extern const struct SpriteTemplate gUnknown_08329D98[]; extern const struct SpriteTemplate gUnknown_08329DF8[]; extern const union AnimCmd* gUnknown_082FF70C[]; extern const union AnimCmd* const * const gMonAnimationsSpriteAnimsPtrTable[]; extern const union AnimCmd* const * const gUnknown_08305D0C[]; extern const union AnimCmd* const * const gUnknown_0830536C[]; extern const u8 gText_BadEgg[]; extern const u8 gText_EggNickname[]; extern const u8 gFacilityClassToPicIndex[]; extern const u8 gFacilityClassToTrainerClass[]; extern const u8 gSecretBaseTrainerClasses[][5]; extern const struct BattleMove gBattleMoves[]; extern const u8 gSpeciesNames[][POKEMON_NAME_LENGTH + 1]; extern const u8 gUnknown_08329D22[]; extern const u8 gUnknown_08329D26[]; extern const u8 gHoldEffectToType[][2]; extern const u8 gStatStageRatios[][2]; extern const struct UnknownPokemonStruct3 gUnknown_08610970[]; extern const u16 gUnknown_08329D48[]; extern const u16 gUnknown_08329D54[]; extern const struct BattleMove gBattleMoves[]; extern const u8 gUnknown_08329D22[]; extern const u8 gUnknown_08329D26[]; extern const u8 gUnknown_08329D2A[]; extern const u8 gUnknown_08329EC2[]; extern bool8 ShouldGetStatBadgeBoost(u16 flagId, u8 bank); extern u8 pokemon_order_func(u8); extern u8 GetBattlerSide(u8 bank); extern u8 GetBattlerAtPosition(u8 bank); extern u8 GetBattlerPosition(u8 bank); extern u16 get_unknown_box_id(void); extern u8 StorageGetCurrentBox(void); extern void set_unknown_box_id(u8); extern struct BoxPokemon* GetBoxedMonPtr(u8 boxNumber, u8 boxPosition); extern s32 GetDeoxysStat(struct Pokemon *mon, s32 statId); extern void sub_803FA70(u8 bank); extern void ClearTemporarySpeciesSpriteData(u8 bank, bool8); extern u32 GetBoxMonDataFromAnyBox(u8 boxNo, u8 boxPos, s32 field); extern u8 sav1_map_get_name(void); extern const u8 *sub_81A1650(u8, u8 language); extern u8 BattleFrontierGetOpponentLvl(u8); extern u16 sub_806EFF0(u16); extern bool8 HealStatusConditions(struct Pokemon *mon, u32 unused, u32 healMask, u8 battleId); extern bool8 sub_806F104(void); extern bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 moveIndex, u8 e); // this file's functions union PokemonSubstruct *GetSubstruct(struct BoxPokemon *boxMon, u32 personality, u8 substructType); // EWRAM vars EWRAM_DATA u8 sLearningMoveTableID = 0; EWRAM_DATA u8 gPlayerPartyCount = 0; EWRAM_DATA u8 gEnemyPartyCount = 0; EWRAM_DATA struct Pokemon gPlayerParty[PARTY_SIZE] = {0}; EWRAM_DATA struct Pokemon gEnemyParty[PARTY_SIZE] = {0}; // const rom data const u16 gSpeciesToHoennPokedexNum[] = {203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 156, 157, 112, 113, 227, 228, 229, 230, 231, 232, 233, 234, 153, 154, 138, 139, 63, 64, 88, 89, 90, 235, 236, 237, 238, 239, 240, 241, 242, 158, 159, 243, 244, 245, 246, 247, 248, 249, 39, 40, 41, 73, 74, 75, 250, 251, 252, 66, 67, 57, 58, 59, 253, 254, 255, 256, 82, 83, 257, 92, 93, 258, 259, 106, 107, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 84, 85, 270, 271, 272, 273, 274, 275, 276, 108, 109, 169, 170, 277, 278, 279, 184, 185, 50, 51, 143, 144, 280, 281, 282, 283, 284, 167, 285, 52, 53, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 65, 181, 182, 155, 324, 137, 325, 326, 162, 163, 327, 328, 329, 91, 55, 56, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 161, 164, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 168, 357, 358, 359, 103, 104, 360, 361, 180, 362, 363, 364, 365, 115, 366, 367, 186, 165, 166, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 42, 43, 44, 25, 26, 34, 35, 114, 27, 28, 32, 33, 99, 100, 61, 62, 145, 131, 132, 60, 105, 68, 127, 128, 183, 129, 130, 140, 141, 97, 98, 116, 117, 118, 48, 49, 78, 79, 101, 102, 173, 174, 175, 119, 120, 171, 172, 125, 126, 54, 110, 111, 80, 81, 69, 76, 77, 121, 122, 160, 148, 149, 94, 36, 37, 38, 95, 96, 150, 45, 46, 47, 176, 177, 178, 152, 146, 147, 124, 123, 179, 70, 71, 72, 142, 86, 87, 133, 134, 135, 136, 29, 30, 31, 187, 188, 189, 190, 191, 192, 193, 194, 195, 198, 199, 200, 196, 197, 201, 202, 151}; const u16 gSpeciesToNationalPokedexNum[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 290, 291, 292, 276, 277, 285, 286, 327, 278, 279, 283, 284, 320, 321, 300, 301, 352, 343, 344, 299, 324, 302, 339, 340, 370, 341, 342, 349, 350, 318, 319, 328, 329, 330, 296, 297, 309, 310, 322, 323, 363, 364, 365, 331, 332, 361, 362, 337, 338, 298, 325, 326, 311, 312, 303, 307, 308, 333, 334, 360, 355, 356, 315, 287, 288, 289, 316, 317, 357, 293, 294, 295, 366, 367, 368, 359, 353, 354, 336, 335, 369, 304, 305, 306, 351, 313, 314, 345, 346, 347, 348, 280, 281, 282, 371, 372, 373, 374, 375, 376, 377, 378, 379, 382, 383, 384, 380, 381, 385, 386, 358}; const u16 gHoennToNationalOrder[] = {252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 63, 64, 65, 290, 291, 292, 293, 294, 295, 296, 297, 118, 119, 129, 130, 298, 183, 184, 74, 75, 76, 299, 300, 301, 41, 42, 169, 72, 73, 302, 303, 304, 305, 306, 66, 67, 68, 307, 308, 309, 310, 311, 312, 81, 82, 100, 101, 313, 314, 43, 44, 45, 182, 84, 85, 315, 316, 317, 318, 319, 320, 321, 322, 323, 218, 219, 324, 88, 89, 109, 110, 325, 326, 27, 28, 327, 227, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 174, 39, 40, 349, 350, 351, 120, 121, 352, 353, 354, 355, 356, 357, 358, 359, 37, 38, 172, 25, 26, 54, 55, 360, 202, 177, 178, 203, 231, 232, 127, 214, 111, 112, 361, 362, 363, 364, 365, 366, 367, 368, 369, 222, 170, 171, 370, 116, 117, 230, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 29, 30, 31, 32, 33, 34, 35, 36, 46, 47, 48, 49, 50, 51, 52, 53, 56, 57, 58, 59, 60, 61, 62, 69, 70, 71, 77, 78, 79, 80, 83, 86, 87, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 102, 103, 104, 105, 106, 107, 108, 113, 114, 115, 122, 123, 124, 125, 126, 128, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 173, 175, 176, 179, 180, 181, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 215, 216, 217, 220, 221, 223, 224, 225, 226, 228, 229, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411}; const struct SpindaSpot gSpindaSpotGraphics[] = { {16, 7, INCBIN_U16("graphics/spinda_spots/spot_0.bin")}, {40, 8, INCBIN_U16("graphics/spinda_spots/spot_1.bin")}, {22, 25, INCBIN_U16("graphics/spinda_spots/spot_2.bin")}, {34, 26, INCBIN_U16("graphics/spinda_spots/spot_3.bin")} }; #include "data/pokemon/item_effects.h" const s8 gNatureStatTable[][5] = { // Atk Def Spd Sp.Atk Sp.Def { 0, 0, 0, 0, 0}, // Hardy { +1, -1, 0, 0, 0}, // Lonely { +1, 0, -1, 0, 0}, // Brave { +1, 0, 0, -1, 0}, // Adamant { +1, 0, 0, 0, -1}, // Naughty { -1, +1, 0, 0, 0}, // Bold { 0, 0, 0, 0, 0}, // Docile { 0, +1, -1, 0, 0}, // Relaxed { 0, +1, 0, -1, 0}, // Impish { 0, +1, 0, 0, -1}, // Lax { -1, 0, +1, 0, 0}, // Timid { 0, -1, +1, 0, 0}, // Hasty { 0, 0, 0, 0, 0}, // Serious { 0, 0, +1, -1, 0}, // Jolly { 0, 0, +1, 0, -1}, // Naive { -1, 0, 0, +1, 0}, // Modest { 0, -1, 0, +1, 0}, // Mild { 0, 0, -1, +1, 0}, // Quiet { 0, 0, 0, 0, 0}, // Bashful { 0, 0, 0, +1, -1}, // Rash { -1, 0, 0, 0, +1}, // Calm { 0, -1, 0, 0, +1}, // Gentle { 0, 0, -1, 0, +1}, // Sassy { 0, 0, 0, -1, +1}, // Careful { 0, 0, 0, 0, 0}, // Quirky }; #include "data/pokemon/tmhm_learnsets.h" #include "data/pokemon/trainer_class_lookups.h" #include "data/pokemon/cry_ids.h" #include "data/pokemon/experience_tables.h" #include "data/pokemon/base_stats.h" #include "data/pokemon/level_up_learnsets.h" #include "data/pokemon/evolution.h" #include "data/pokemon/level_up_learnset_pointers.h" // code void ZeroBoxMonData(struct BoxPokemon *boxMon) { u8 *raw = (u8 *)boxMon; u32 i; for (i = 0; i < sizeof(struct BoxPokemon); i++) raw[i] = 0; } void ZeroMonData(struct Pokemon *mon) { u32 arg; ZeroBoxMonData(&mon->box); arg = 0; SetMonData(mon, MON_DATA_STATUS, &arg); SetMonData(mon, MON_DATA_LEVEL, &arg); SetMonData(mon, MON_DATA_HP, &arg); SetMonData(mon, MON_DATA_MAX_HP, &arg); SetMonData(mon, MON_DATA_ATK, &arg); SetMonData(mon, MON_DATA_DEF, &arg); SetMonData(mon, MON_DATA_SPEED, &arg); SetMonData(mon, MON_DATA_SPATK, &arg); SetMonData(mon, MON_DATA_SPDEF, &arg); arg = 255; SetMonData(mon, MON_DATA_MAIL, &arg); } void ZeroPlayerPartyMons(void) { s32 i; for (i = 0; i < PARTY_SIZE; i++) ZeroMonData(&gPlayerParty[i]); } void ZeroEnemyPartyMons(void) { s32 i; for (i = 0; i < PARTY_SIZE; i++) ZeroMonData(&gEnemyParty[i]); } void CreateMon(struct Pokemon *mon, u16 species, u8 level, u8 fixedIV, u8 hasFixedPersonality, u32 fixedPersonality, u8 otIdType, u32 fixedOtId) { u32 arg; ZeroMonData(mon); CreateBoxMon(&mon->box, species, level, fixedIV, hasFixedPersonality, fixedPersonality, otIdType, fixedOtId); SetMonData(mon, MON_DATA_LEVEL, &level); arg = 255; SetMonData(mon, MON_DATA_MAIL, &arg); CalculateMonStats(mon); } void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV, u8 hasFixedPersonality, u32 fixedPersonality, u8 otIdType, u32 fixedOtId) { u8 speciesName[POKEMON_NAME_LENGTH + 1]; u32 personality; u32 value; u16 checksum; ZeroBoxMonData(boxMon); if (hasFixedPersonality) personality = fixedPersonality; else personality = Random32(); SetBoxMonData(boxMon, MON_DATA_PERSONALITY, &personality); //Determine original trainer ID if (otIdType == OT_ID_RANDOM_NO_SHINY) //Pokemon cannot be shiny { u32 shinyValue; do { value = Random32(); shinyValue = HIHALF(value) ^ LOHALF(value) ^ HIHALF(personality) ^ LOHALF(personality); } while (shinyValue < 8); } else if (otIdType == OT_ID_PRESET) //Pokemon has a preset OT ID { value = fixedOtId; } else //Player is the OT { value = gSaveBlock2Ptr->playerTrainerId[0] | (gSaveBlock2Ptr->playerTrainerId[1] << 8) | (gSaveBlock2Ptr->playerTrainerId[2] << 16) | (gSaveBlock2Ptr->playerTrainerId[3] << 24); } SetBoxMonData(boxMon, MON_DATA_OT_ID, &value); checksum = CalculateBoxMonChecksum(boxMon); SetBoxMonData(boxMon, MON_DATA_CHECKSUM, &checksum); EncryptBoxMon(boxMon); GetSpeciesName(speciesName, species); SetBoxMonData(boxMon, MON_DATA_NICKNAME, speciesName); SetBoxMonData(boxMon, MON_DATA_LANGUAGE, &gGameLanguage); SetBoxMonData(boxMon, MON_DATA_OT_NAME, gSaveBlock2Ptr->playerName); SetBoxMonData(boxMon, MON_DATA_SPECIES, &species); SetBoxMonData(boxMon, MON_DATA_EXP, &gExperienceTables[gBaseStats[species].growthRate][level]); SetBoxMonData(boxMon, MON_DATA_FRIENDSHIP, &gBaseStats[species].friendship); value = sav1_map_get_name(); SetBoxMonData(boxMon, MON_DATA_MET_LOCATION, &value); SetBoxMonData(boxMon, MON_DATA_MET_LEVEL, &level); SetBoxMonData(boxMon, MON_DATA_MET_GAME, &gGameVersion); value = ITEM_POKE_BALL; SetBoxMonData(boxMon, MON_DATA_POKEBALL, &value); SetBoxMonData(boxMon, MON_DATA_OT_GENDER, &gSaveBlock2Ptr->playerGender); if (fixedIV < 32) { SetBoxMonData(boxMon, MON_DATA_HP_IV, &fixedIV); SetBoxMonData(boxMon, MON_DATA_ATK_IV, &fixedIV); SetBoxMonData(boxMon, MON_DATA_DEF_IV, &fixedIV); SetBoxMonData(boxMon, MON_DATA_SPEED_IV, &fixedIV); SetBoxMonData(boxMon, MON_DATA_SPATK_IV, &fixedIV); SetBoxMonData(boxMon, MON_DATA_SPDEF_IV, &fixedIV); } else { u32 iv; value = Random(); iv = value & 0x1F; SetBoxMonData(boxMon, MON_DATA_HP_IV, &iv); iv = (value & 0x3E0) >> 5; SetBoxMonData(boxMon, MON_DATA_ATK_IV, &iv); iv = (value & 0x7C00) >> 10; SetBoxMonData(boxMon, MON_DATA_DEF_IV, &iv); value = Random(); iv = value & 0x1F; SetBoxMonData(boxMon, MON_DATA_SPEED_IV, &iv); iv = (value & 0x3E0) >> 5; SetBoxMonData(boxMon, MON_DATA_SPATK_IV, &iv); iv = (value & 0x7C00) >> 10; SetBoxMonData(boxMon, MON_DATA_SPDEF_IV, &iv); } if (gBaseStats[species].ability2) { value = personality & 1; SetBoxMonData(boxMon, MON_DATA_ALT_ABILITY, &value); } GiveBoxMonInitialMoveset(boxMon); } void CreateMonWithNature(struct Pokemon *mon, u16 species, u8 level, u8 fixedIV, u8 nature) { u32 personality; do { personality = Random32(); } while (nature != GetNatureFromPersonality(personality)); CreateMon(mon, species, level, fixedIV, 1, personality, OT_ID_PLAYER_ID, 0); } void CreateMonWithGenderNatureLetter(struct Pokemon *mon, u16 species, u8 level, u8 fixedIV, u8 gender, u8 nature, u8 unownLetter) { u32 personality; if ((u8)(unownLetter - 1) < 28) { u16 actualLetter; do { personality = Random32(); actualLetter = ((((personality & 0x3000000) >> 18) | ((personality & 0x30000) >> 12) | ((personality & 0x300) >> 6) | (personality & 0x3)) % 28); } while (nature != GetNatureFromPersonality(personality) || gender != GetGenderFromSpeciesAndPersonality(species, personality) || actualLetter != unownLetter - 1); } else { do { personality = Random32(); } while (nature != GetNatureFromPersonality(personality) || gender != GetGenderFromSpeciesAndPersonality(species, personality)); } CreateMon(mon, species, level, fixedIV, 1, personality, OT_ID_PLAYER_ID, 0); } // This is only used to create Wally's Ralts. void CreateMaleMon(struct Pokemon *mon, u16 species, u8 level) { u32 personality; u32 otId; do { otId = Random32(); personality = Random32(); } while (GetGenderFromSpeciesAndPersonality(species, personality) != MON_MALE); CreateMon(mon, species, level, 32, 1, personality, OT_ID_PRESET, otId); } void CreateMonWithIVsPersonality(struct Pokemon *mon, u16 species, u8 level, u32 ivs, u32 personality) { CreateMon(mon, species, level, 0, 1, personality, OT_ID_PLAYER_ID, 0); SetMonData(mon, MON_DATA_IVS, &ivs); CalculateMonStats(mon); } void CreateMonWithIVsOTID(struct Pokemon *mon, u16 species, u8 level, u8 *ivs, u32 otId) { CreateMon(mon, species, level, 0, 0, 0, OT_ID_PRESET, otId); SetMonData(mon, MON_DATA_HP_IV, &ivs[0]); SetMonData(mon, MON_DATA_ATK_IV, &ivs[1]); SetMonData(mon, MON_DATA_DEF_IV, &ivs[2]); SetMonData(mon, MON_DATA_SPEED_IV, &ivs[3]); SetMonData(mon, MON_DATA_SPATK_IV, &ivs[4]); SetMonData(mon, MON_DATA_SPDEF_IV, &ivs[5]); CalculateMonStats(mon); } void CreateMonWithEVSpread(struct Pokemon *mon, u16 species, u8 level, u8 fixedIV, u8 evSpread) { s32 i; s32 statCount = 0; u16 evAmount; u8 evsBits; CreateMon(mon, species, level, fixedIV, 0, 0, 0, 0); evsBits = evSpread; for (i = 0; i < NUM_STATS; i++) { if (evsBits & 1) statCount++; evsBits >>= 1; } evAmount = MAX_TOTAL_EVS / statCount; evsBits = 1; for (i = 0; i < NUM_STATS; i++) { if (evSpread & evsBits) SetMonData(mon, MON_DATA_HP_EV + i, &evAmount); evsBits <<= 1; } CalculateMonStats(mon); } void sub_806819C(struct Pokemon *mon, struct UnknownPokemonStruct *src) { s32 i; u8 nickname[30]; u8 language; u8 value; CreateMon(mon, src->species, src->level, 0, 1, src->personality, 1, src->otId); for (i = 0; i < 4; i++) SetMonMoveSlot(mon, src->moves[i], i); SetMonData(mon, MON_DATA_PP_BONUSES, &src->ppBonuses); SetMonData(mon, MON_DATA_HELD_ITEM, &src->heldItem); SetMonData(mon, MON_DATA_FRIENDSHIP, &src->friendship); StringCopy(nickname, src->nickname); if (nickname[0] == EXT_CTRL_CODE_BEGIN && nickname[1] == EXT_CTRL_CODE_JPN) { language = LANGUAGE_JAPANESE; StripExtCtrlCodes(nickname); } else { language = GAME_LANGUAGE; } SetMonData(mon, MON_DATA_LANGUAGE, &language); SetMonData(mon, MON_DATA_NICKNAME, nickname); SetMonData(mon, MON_DATA_HP_EV, &src->hpEV); SetMonData(mon, MON_DATA_ATK_EV, &src->attackEV); SetMonData(mon, MON_DATA_DEF_EV, &src->defenseEV); SetMonData(mon, MON_DATA_SPEED_EV, &src->speedEV); SetMonData(mon, MON_DATA_SPATK_EV, &src->spAttackEV); SetMonData(mon, MON_DATA_SPDEF_EV, &src->spDefenseEV); value = src->altAbility; SetMonData(mon, MON_DATA_ALT_ABILITY, &value); value = src->hpIV; SetMonData(mon, MON_DATA_HP_IV, &value); value = src->attackIV; SetMonData(mon, MON_DATA_ATK_IV, &value); value = src->defenseIV; SetMonData(mon, MON_DATA_DEF_IV, &value); value = src->speedIV; SetMonData(mon, MON_DATA_SPEED_IV, &value); value = src->spAttackIV; SetMonData(mon, MON_DATA_SPATK_IV, &value); value = src->spDefenseIV; SetMonData(mon, MON_DATA_SPDEF_IV, &value); MonRestorePP(mon); CalculateMonStats(mon); } void sub_8068338(struct Pokemon *mon, struct UnknownPokemonStruct *src, bool8 lvl50) { s32 i; u8 nickname[30]; u8 level; u8 language; u8 value; if (gSaveBlock2Ptr->frontierChosenLvl != 0) level = BattleFrontierGetOpponentLvl(gSaveBlock2Ptr->frontierChosenLvl); else if (lvl50) level = 50; else level = src->level; CreateMon(mon, src->species, level, 0, 1, src->personality, 1, src->otId); for (i = 0; i < 4; i++) SetMonMoveSlot(mon, src->moves[i], i); SetMonData(mon, MON_DATA_PP_BONUSES, &src->ppBonuses); SetMonData(mon, MON_DATA_HELD_ITEM, &src->heldItem); SetMonData(mon, MON_DATA_FRIENDSHIP, &src->friendship); StringCopy(nickname, src->nickname); if (nickname[0] == EXT_CTRL_CODE_BEGIN && nickname[1] == EXT_CTRL_CODE_JPN) { language = LANGUAGE_JAPANESE; StripExtCtrlCodes(nickname); } else { language = GAME_LANGUAGE; } SetMonData(mon, MON_DATA_LANGUAGE, &language); SetMonData(mon, MON_DATA_NICKNAME, nickname); SetMonData(mon, MON_DATA_HP_EV, &src->hpEV); SetMonData(mon, MON_DATA_ATK_EV, &src->attackEV); SetMonData(mon, MON_DATA_DEF_EV, &src->defenseEV); SetMonData(mon, MON_DATA_SPEED_EV, &src->speedEV); SetMonData(mon, MON_DATA_SPATK_EV, &src->spAttackEV); SetMonData(mon, MON_DATA_SPDEF_EV, &src->spDefenseEV); value = src->altAbility; SetMonData(mon, MON_DATA_ALT_ABILITY, &value); value = src->hpIV; SetMonData(mon, MON_DATA_HP_IV, &value); value = src->attackIV; SetMonData(mon, MON_DATA_ATK_IV, &value); value = src->defenseIV; SetMonData(mon, MON_DATA_DEF_IV, &value); value = src->speedIV; SetMonData(mon, MON_DATA_SPEED_IV, &value); value = src->spAttackIV; SetMonData(mon, MON_DATA_SPATK_IV, &value); value = src->spDefenseIV; SetMonData(mon, MON_DATA_SPDEF_IV, &value); MonRestorePP(mon); CalculateMonStats(mon); } void sub_8068528(struct Pokemon *mon, const struct UnknownPokemonStruct2 *src, u8 monId) { s32 i; u16 evAmount; u8 language; u32 otId = gUnknown_08610970[src->field_0_0].field_30; u32 personality = ((gUnknown_08610970[src->field_0_0].field_30 >> 8) | ((gUnknown_08610970[src->field_0_0].field_30 & 0xFF) << 8)) + src->mons[monId].species + src->field_2; CreateMon(mon, src->mons[monId].species, BattleFrontierGetOpponentLvl(src->field_0_1 - 1), 0x1F, TRUE, personality, TRUE, otId); SetMonData(mon, MON_DATA_HELD_ITEM, &src->mons[monId].item); for (i = 0; i < 4; i++) SetMonMoveSlot(mon, src->mons[monId].moves[i], i); evAmount = MAX_TOTAL_EVS / NUM_STATS; for (i = 0; i < NUM_STATS; i++) SetMonData(mon, MON_DATA_HP_EV + i, &evAmount); language = src->language; SetMonData(mon, MON_DATA_LANGUAGE, &language); SetMonData(mon, MON_DATA_OT_NAME, sub_81A1650(src->field_0_0, language)); CalculateMonStats(mon); } void CreateMonWithEVSpreadPersonalityOTID(struct Pokemon *mon, u16 species, u8 level, u8 nature, u8 fixedIV, u8 evSpread, u32 otId) { s32 i; s32 statCount = 0; u8 evsBits; u16 evAmount; // i is reused as personality value do { i = Random32(); } while (nature != GetNatureFromPersonality(i)); CreateMon(mon, species, level, fixedIV, TRUE, i, TRUE, otId); evsBits = evSpread; for (i = 0; i < NUM_STATS; i++) { if (evsBits & 1) statCount++; evsBits >>= 1; } evAmount = MAX_TOTAL_EVS / statCount; evsBits = 1; for (i = 0; i < NUM_STATS; i++) { if (evSpread & evsBits) SetMonData(mon, MON_DATA_HP_EV + i, &evAmount); evsBits <<= 1; } CalculateMonStats(mon); } void sub_80686FC(struct Pokemon *mon, struct UnknownPokemonStruct *dest) { s32 i; u16 heldItem; dest->species = GetMonData(mon, MON_DATA_SPECIES, NULL); heldItem = GetMonData(mon, MON_DATA_HELD_ITEM, NULL); if (heldItem == ITEM_ENIGMA_BERRY) heldItem = 0; dest->heldItem = heldItem; for (i = 0; i < 4; i++) dest->moves[i] = GetMonData(mon, MON_DATA_MOVE1 + i, NULL); dest->level = GetMonData(mon, MON_DATA_LEVEL, NULL); dest->ppBonuses = GetMonData(mon, MON_DATA_PP_BONUSES, NULL); dest->otId = GetMonData(mon, MON_DATA_OT_ID, NULL); dest->hpEV = GetMonData(mon, MON_DATA_HP_EV, NULL); dest->attackEV = GetMonData(mon, MON_DATA_ATK_EV, NULL); dest->defenseEV = GetMonData(mon, MON_DATA_DEF_EV, NULL); dest->speedEV = GetMonData(mon, MON_DATA_SPEED_EV, NULL); dest->spAttackEV = GetMonData(mon, MON_DATA_SPATK_EV, NULL); dest->spDefenseEV = GetMonData(mon, MON_DATA_SPDEF_EV, NULL); dest->friendship = GetMonData(mon, MON_DATA_FRIENDSHIP, NULL); dest->hpIV = GetMonData(mon, MON_DATA_HP_IV, NULL); dest->attackIV = GetMonData(mon, MON_DATA_ATK_IV, NULL); dest->defenseIV = GetMonData(mon, MON_DATA_DEF_IV, NULL); dest->speedIV = GetMonData(mon, MON_DATA_SPEED_IV, NULL); dest->spAttackIV = GetMonData(mon, MON_DATA_SPATK_IV, NULL); dest->spDefenseIV = GetMonData(mon, MON_DATA_SPDEF_IV, NULL); dest->altAbility = GetMonData(mon, MON_DATA_ALT_ABILITY, NULL); dest->personality = GetMonData(mon, MON_DATA_PERSONALITY, NULL); GetMonData(mon, MON_DATA_NICKNAME, dest->nickname); } void CreateObedientMon(struct Pokemon *mon, u16 species, u8 level, u8 fixedIV, u8 hasFixedPersonality, u32 fixedPersonality, u8 otIdType, u32 fixedOtId) { bool32 obedient = TRUE; CreateMon(mon, species, level, fixedIV, hasFixedPersonality, fixedPersonality, otIdType, fixedOtId); SetMonData(mon, MON_DATA_OBEDIENCE, &obedient); } bool8 sub_80688F8(u8 caseId, u8 battlerId) { switch (caseId) { case 0: default: return FALSE; case 1: if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI)) return FALSE; if (!gMain.inBattle) return FALSE; if (gLinkPlayers[GetMultiplayerId()].lp_field_18 == battlerId) return FALSE; break; case 2: break; case 3: if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI)) return FALSE; if (!gMain.inBattle) return FALSE; if (battlerId == 1 || battlerId == 4 || battlerId == 5) return TRUE; return FALSE; case 4: break; case 5: if (gBattleTypeFlags & BATTLE_TYPE_LINK) { if (!gMain.inBattle) return FALSE; if (gBattleTypeFlags & BATTLE_TYPE_MULTI) { if (gLinkPlayers[GetMultiplayerId()].lp_field_18 == battlerId) return FALSE; } else { if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) return FALSE; } } else { if (!gMain.inBattle) return FALSE; if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) return FALSE; } break; } return TRUE; } s32 GetDeoxysStat(struct Pokemon *mon, s32 statId) { s32 ivVal, evVal; s32 statValue; u8 nature, statId_; if (gBattleTypeFlags & BATTLE_TYPE_20) return 0; if (GetMonData(mon, MON_DATA_SPECIES, NULL) != SPECIES_DEOXYS) return 0; ivVal = GetMonData(mon, MON_DATA_HP_IV + statId, NULL); evVal = GetMonData(mon, MON_DATA_HP_EV + statId, NULL); statValue = (u16)(((gUnknown_08329D48[statId] * 2 + ivVal + evVal / 4) * mon->level) / 100 + 5); nature = GetNature(mon); statId_ = statId; // needed to match statValue = ModifyStatByNature(nature, statValue, statId_); return statValue; } void SetDeoxysStats(void) { s32 i, value; for (i = 0; i < PARTY_SIZE; i++) { struct Pokemon *mon = &gPlayerParty[i]; if (GetMonData(mon, MON_DATA_SPECIES, NULL) != SPECIES_DEOXYS) continue; value = GetMonData(mon, MON_DATA_ATK, NULL); SetMonData(mon, MON_DATA_ATK, &value); value = GetMonData(mon, MON_DATA_DEF, NULL); SetMonData(mon, MON_DATA_DEF, &value); value = GetMonData(mon, MON_DATA_SPEED, NULL); SetMonData(mon, MON_DATA_SPEED, &value); value = GetMonData(mon, MON_DATA_SPATK, NULL); SetMonData(mon, MON_DATA_SPATK, &value); value = GetMonData(mon, MON_DATA_SPDEF, NULL); SetMonData(mon, MON_DATA_SPDEF, &value); } } u16 sub_8068B48(void) { u8 linkId; u32 arrId; if (gBattleTypeFlags & BATTLE_TYPE_x2000000) linkId = gUnknown_0203C7B4 ^ 1; else linkId = GetMultiplayerId() ^ 1; arrId = gLinkPlayers[linkId].trainerId & 7; arrId |= gLinkPlayers[linkId].gender << 3; return sub_806EFF0(gUnknown_08329D54[arrId]); } u16 sub_8068BB0(void) { u8 linkId; u32 arrId; if (gBattleTypeFlags & BATTLE_TYPE_x2000000) linkId = gUnknown_0203C7B4 ^ 1; else linkId = GetMultiplayerId() ^ 1; arrId = gLinkPlayers[linkId].trainerId & 7; arrId |= gLinkPlayers[linkId].gender << 3; return gFacilityClassToTrainerClass[gUnknown_08329D54[arrId]]; } void CreateObedientEnemyMon(void) { s32 species = gSpecialVar_0x8004; s32 level = gSpecialVar_0x8005; s32 itemId = gSpecialVar_0x8006; ZeroEnemyPartyMons(); CreateObedientMon(&gEnemyParty[0], species, level, 32, 0, 0, 0, 0); if (itemId) { u8 heldItem[2]; heldItem[0] = itemId; heldItem[1] = itemId >> 8; SetMonData(&gEnemyParty[0], MON_DATA_HELD_ITEM, heldItem); } } u16 CalculateBoxMonChecksum(struct BoxPokemon *boxMon) { u16 checksum = 0; union PokemonSubstruct *substruct0 = GetSubstruct(boxMon, boxMon->personality, 0); union PokemonSubstruct *substruct1 = GetSubstruct(boxMon, boxMon->personality, 1); union PokemonSubstruct *substruct2 = GetSubstruct(boxMon, boxMon->personality, 2); union PokemonSubstruct *substruct3 = GetSubstruct(boxMon, boxMon->personality, 3); s32 i; for (i = 0; i < 6; i++) checksum += substruct0->raw[i]; for (i = 0; i < 6; i++) checksum += substruct1->raw[i]; for (i = 0; i < 6; i++) checksum += substruct2->raw[i]; for (i = 0; i < 6; i++) checksum += substruct3->raw[i]; return checksum; } #define CALC_STAT(base, iv, ev, statIndex, field) \ { \ u8 baseStat = gBaseStats[species].base; \ s32 n = (((2 * baseStat + iv + ev / 4) * level) / 100) + 5; \ u8 nature = GetNature(mon); \ n = ModifyStatByNature(nature, n, statIndex); \ SetMonData(mon, field, &n); \ } void CalculateMonStats(struct Pokemon *mon) { s32 oldMaxHP = GetMonData(mon, MON_DATA_MAX_HP, NULL); s32 currentHP = GetMonData(mon, MON_DATA_HP, NULL); s32 hpIV = GetMonData(mon, MON_DATA_HP_IV, NULL); s32 hpEV = GetMonData(mon, MON_DATA_HP_EV, NULL); s32 attackIV = GetMonData(mon, MON_DATA_ATK_IV, NULL); s32 attackEV = GetMonData(mon, MON_DATA_ATK_EV, NULL); s32 defenseIV = GetMonData(mon, MON_DATA_DEF_IV, NULL); s32 defenseEV = GetMonData(mon, MON_DATA_DEF_EV, NULL); s32 speedIV = GetMonData(mon, MON_DATA_SPEED_IV, NULL); s32 speedEV = GetMonData(mon, MON_DATA_SPEED_EV, NULL); s32 spAttackIV = GetMonData(mon, MON_DATA_SPATK_IV, NULL); s32 spAttackEV = GetMonData(mon, MON_DATA_SPATK_EV, NULL); s32 spDefenseIV = GetMonData(mon, MON_DATA_SPDEF_IV, NULL); s32 spDefenseEV = GetMonData(mon, MON_DATA_SPDEF_EV, NULL); u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL); s32 level = GetLevelFromMonExp(mon); s32 newMaxHP; SetMonData(mon, MON_DATA_LEVEL, &level); if (species == SPECIES_SHEDINJA) { newMaxHP = 1; } else { s32 n = 2 * gBaseStats[species].baseHP + hpIV; newMaxHP = (((n + hpEV / 4) * level) / 100) + level + 10; } gBattleScripting.field_23 = newMaxHP - oldMaxHP; if (gBattleScripting.field_23 == 0) gBattleScripting.field_23 = 1; SetMonData(mon, MON_DATA_MAX_HP, &newMaxHP); CALC_STAT(baseAttack, attackIV, attackEV, 1, MON_DATA_ATK) CALC_STAT(baseDefense, defenseIV, defenseEV, 2, MON_DATA_DEF) CALC_STAT(baseSpeed, speedIV, speedEV, 3, MON_DATA_SPEED) CALC_STAT(baseSpAttack, spAttackIV, spAttackEV, 4, MON_DATA_SPATK) CALC_STAT(baseSpDefense, spDefenseIV, spDefenseEV, 5, MON_DATA_SPDEF) if (species == SPECIES_SHEDINJA) { if (currentHP != 0 || oldMaxHP == 0) currentHP = 1; else return; } else { if (currentHP == 0 && oldMaxHP == 0) currentHP = newMaxHP; else if (currentHP != 0) currentHP += newMaxHP - oldMaxHP; else return; } SetMonData(mon, MON_DATA_HP, ¤tHP); } void BoxMonToMon(const struct BoxPokemon *src, struct Pokemon *dest) { u32 value = 0; dest->box = *src; SetMonData(dest, MON_DATA_STATUS, &value); SetMonData(dest, MON_DATA_HP, &value); SetMonData(dest, MON_DATA_MAX_HP, &value); value = 255; SetMonData(dest, MON_DATA_MAIL, &value); CalculateMonStats(dest); } u8 GetLevelFromMonExp(struct Pokemon *mon) { u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL); u32 exp = GetMonData(mon, MON_DATA_EXP, NULL); s32 level = 1; while (level <= MAX_MON_LEVEL && gExperienceTables[gBaseStats[species].growthRate][level] <= exp) level++; return level - 1; } u8 GetLevelFromBoxMonExp(struct BoxPokemon *boxMon) { u16 species = GetBoxMonData(boxMon, MON_DATA_SPECIES, NULL); u32 exp = GetBoxMonData(boxMon, MON_DATA_EXP, NULL); s32 level = 1; while (level <= MAX_MON_LEVEL && gExperienceTables[gBaseStats[species].growthRate][level] <= exp) level++; return level - 1; } u16 GiveMoveToMon(struct Pokemon *mon, u16 move) { return GiveMoveToBoxMon(&mon->box, move); } u16 GiveMoveToBoxMon(struct BoxPokemon *boxMon, u16 move) { s32 i; for (i = 0; i < 4; i++) { u16 existingMove = GetBoxMonData(boxMon, MON_DATA_MOVE1 + i, NULL); if (!existingMove) { SetBoxMonData(boxMon, MON_DATA_MOVE1 + i, &move); SetBoxMonData(boxMon, MON_DATA_PP1 + i, &gBattleMoves[move].pp); return move; } if (existingMove == move) return -2; } return -1; } u16 GiveMoveToBattleMon(struct BattlePokemon *mon, u16 move) { s32 i; for (i = 0; i < 4; i++) { if (!mon->moves[i]) { mon->moves[i] = move; mon->pp[i] = gBattleMoves[move].pp; return move; } } return -1; } void SetMonMoveSlot(struct Pokemon *mon, u16 move, u8 slot) { SetMonData(mon, MON_DATA_MOVE1 + slot, &move); SetMonData(mon, MON_DATA_PP1 + slot, &gBattleMoves[move].pp); } void SetBattleMonMoveSlot(struct BattlePokemon *mon, u16 move, u8 slot) { mon->moves[slot] = move; mon->pp[slot] = gBattleMoves[move].pp; } void GiveMonInitialMoveset(struct Pokemon *mon) { GiveBoxMonInitialMoveset(&mon->box); } void GiveBoxMonInitialMoveset(struct BoxPokemon *boxMon) { u16 species = GetBoxMonData(boxMon, MON_DATA_SPECIES, NULL); s32 level = GetLevelFromBoxMonExp(boxMon); s32 i; for (i = 0; gLevelUpLearnsets[species][i] != (u16)-1; i++) { u16 moveLevel; u16 move; moveLevel = (gLevelUpLearnsets[species][i] & 0xFE00); if (moveLevel > (level << 9)) break; move = (gLevelUpLearnsets[species][i] & 0x1FF); if (GiveMoveToBoxMon(boxMon, move) == (u16)-1) DeleteFirstMoveAndGiveMoveToBoxMon(boxMon, move); } } u16 MonTryLearningNewMove(struct Pokemon *mon, bool8 firstMove) { u32 retVal = 0; u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL); u8 level = GetMonData(mon, MON_DATA_LEVEL, NULL); // since you can learn more than one move per level // the game needs to know whether you decided to // learn it or keep the old set to avoid asking // you to learn the same move over and over again if (firstMove) { sLearningMoveTableID = 0; while ((gLevelUpLearnsets[species][sLearningMoveTableID] & 0xFE00) != (level << 9)) { sLearningMoveTableID++; if (gLevelUpLearnsets[species][sLearningMoveTableID] == 0xFFFF) return 0; } } if ((gLevelUpLearnsets[species][sLearningMoveTableID] & 0xFE00) == (level << 9)) { gMoveToLearn = (gLevelUpLearnsets[species][sLearningMoveTableID] & 0x1FF); sLearningMoveTableID++; retVal = GiveMoveToMon(mon, gMoveToLearn); } return retVal; } void DeleteFirstMoveAndGiveMoveToMon(struct Pokemon *mon, u16 move) { s32 i; u16 moves[4]; u8 pp[4]; u8 ppBonuses; for (i = 0; i < 3; i++) { moves[i] = GetMonData(mon, MON_DATA_MOVE2 + i, NULL); pp[i] = GetMonData(mon, MON_DATA_PP2 + i, NULL); } ppBonuses = GetMonData(mon, MON_DATA_PP_BONUSES, NULL); ppBonuses >>= 2; moves[3] = move; pp[3] = gBattleMoves[move].pp; for (i = 0; i < 4; i++) { SetMonData(mon, MON_DATA_MOVE1 + i, &moves[i]); SetMonData(mon, MON_DATA_PP1 + i, &pp[i]); } SetMonData(mon, MON_DATA_PP_BONUSES, &ppBonuses); } void DeleteFirstMoveAndGiveMoveToBoxMon(struct BoxPokemon *boxMon, u16 move) { s32 i; u16 moves[4]; u8 pp[4]; u8 ppBonuses; for (i = 0; i < 3; i++) { moves[i] = GetBoxMonData(boxMon, MON_DATA_MOVE2 + i, NULL); pp[i] = GetBoxMonData(boxMon, MON_DATA_PP2 + i, NULL); } ppBonuses = GetBoxMonData(boxMon, MON_DATA_PP_BONUSES, NULL); ppBonuses >>= 2; moves[3] = move; pp[3] = gBattleMoves[move].pp; for (i = 0; i < 4; i++) { SetBoxMonData(boxMon, MON_DATA_MOVE1 + i, &moves[i]); SetBoxMonData(boxMon, MON_DATA_PP1 + i, &pp[i]); } SetBoxMonData(boxMon, MON_DATA_PP_BONUSES, &ppBonuses); } #define APPLY_STAT_MOD(var, mon, stat, statIndex) \ { \ (var) = (stat) * (gStatStageRatios)[(mon)->statStages[(statIndex)]][0]; \ (var) /= (gStatStageRatios)[(mon)->statStages[(statIndex)]][1]; \ } s32 CalculateBaseDamage(struct BattlePokemon *attacker, struct BattlePokemon *defender, u32 move, u16 sideStatus, u16 powerOverride, u8 typeOverride, u8 bankAtk, u8 bankDef) { u32 i; s32 damage = 0; s32 damageHelper; u8 type; u16 attack, defense; u16 spAttack, spDefense; u8 defenderHoldEffect; u8 defenderHoldEffectParam; u8 attackerHoldEffect; u8 attackerHoldEffectParam; if (!powerOverride) gBattleMovePower = gBattleMoves[move].power; else gBattleMovePower = powerOverride; if (!typeOverride) type = gBattleMoves[move].type; else type = typeOverride & 0x3F; attack = attacker->attack; defense = defender->defense; spAttack = attacker->spAttack; spDefense = defender->spDefense; if (attacker->item == ITEM_ENIGMA_BERRY) { attackerHoldEffect = gEnigmaBerries[bankAtk].holdEffect; attackerHoldEffectParam = gEnigmaBerries[bankAtk].holdEffectParam; } else { attackerHoldEffect = ItemId_GetHoldEffect(attacker->item); attackerHoldEffectParam = ItemId_GetHoldEffectParam(attacker->item); } if (defender->item == ITEM_ENIGMA_BERRY) { defenderHoldEffect = gEnigmaBerries[bankDef].holdEffect; defenderHoldEffectParam = gEnigmaBerries[bankDef].holdEffectParam; } else { defenderHoldEffect = ItemId_GetHoldEffect(defender->item); defenderHoldEffectParam = ItemId_GetHoldEffectParam(defender->item); } if (attacker->ability == ABILITY_HUGE_POWER || attacker->ability == ABILITY_PURE_POWER) attack *= 2; if (ShouldGetStatBadgeBoost(FLAG_BADGE01_GET, bankAtk)) attack = (110 * attack) / 100; if (ShouldGetStatBadgeBoost(FLAG_BADGE05_GET, bankDef)) defense = (110 * defense) / 100; if (ShouldGetStatBadgeBoost(FLAG_BADGE07_GET, bankAtk)) spAttack = (110 * spAttack) / 100; if (ShouldGetStatBadgeBoost(FLAG_BADGE07_GET, bankDef)) spDefense = (110 * spDefense) / 100; for (i = 0; i < 17; i++) { if (attackerHoldEffect == gHoldEffectToType[i][0] && type == gHoldEffectToType[i][1]) { if (type <= 8) attack = (attack * (attackerHoldEffectParam + 100)) / 100; else spAttack = (spAttack * (attackerHoldEffectParam + 100)) / 100; break; } } if (attackerHoldEffect == HOLD_EFFECT_CHOICE_BAND) attack = (150 * attack) / 100; if (attackerHoldEffect == HOLD_EFFECT_SOUL_DEW && !(gBattleTypeFlags & (BATTLE_TYPE_FRONTIER)) && (attacker->species == SPECIES_LATIAS || attacker->species == SPECIES_LATIOS)) spAttack = (150 * spAttack) / 100; if (defenderHoldEffect == HOLD_EFFECT_SOUL_DEW && !(gBattleTypeFlags & (BATTLE_TYPE_FRONTIER)) && (defender->species == SPECIES_LATIAS || defender->species == SPECIES_LATIOS)) spDefense = (150 * spDefense) / 100; if (attackerHoldEffect == HOLD_EFFECT_DEEP_SEA_TOOTH && attacker->species == SPECIES_CLAMPERL) spAttack *= 2; if (defenderHoldEffect == HOLD_EFFECT_DEEP_SEA_SCALE && defender->species == SPECIES_CLAMPERL) spDefense *= 2; if (attackerHoldEffect == HOLD_EFFECT_LIGHT_BALL && attacker->species == SPECIES_PIKACHU) spAttack *= 2; if (defenderHoldEffect == HOLD_EFFECT_METAL_POWDER && defender->species == SPECIES_DITTO) defense *= 2; if (attackerHoldEffect == HOLD_EFFECT_THICK_CLUB && (attacker->species == SPECIES_CUBONE || attacker->species == SPECIES_MAROWAK)) attack *= 2; if (defender->ability == ABILITY_THICK_FAT && (type == TYPE_FIRE || type == TYPE_ICE)) spAttack /= 2; if (attacker->ability == ABILITY_HUSTLE) attack = (150 * attack) / 100; if (attacker->ability == ABILITY_PLUS && AbilityBattleEffects(ABILITYEFFECT_FIELD_SPORT, 0, ABILITY_MINUS, 0, 0)) spAttack = (150 * spAttack) / 100; if (attacker->ability == ABILITY_MINUS && AbilityBattleEffects(ABILITYEFFECT_FIELD_SPORT, 0, ABILITY_PLUS, 0, 0)) spAttack = (150 * spAttack) / 100; if (attacker->ability == ABILITY_GUTS && attacker->status1) attack = (150 * attack) / 100; if (defender->ability == ABILITY_MARVEL_SCALE && defender->status1) defense = (150 * defense) / 100; if (type == TYPE_ELECTRIC && AbilityBattleEffects(ABILITYEFFECT_FIELD_SPORT, 0, 0, 0xFD, 0)) gBattleMovePower /= 2; if (type == TYPE_FIRE && AbilityBattleEffects(ABILITYEFFECT_FIELD_SPORT, 0, 0, 0xFE, 0)) gBattleMovePower /= 2; if (type == TYPE_GRASS && attacker->ability == ABILITY_OVERGROW && attacker->hp <= (attacker->maxHP / 3)) gBattleMovePower = (150 * gBattleMovePower) / 100; if (type == TYPE_FIRE && attacker->ability == ABILITY_BLAZE && attacker->hp <= (attacker->maxHP / 3)) gBattleMovePower = (150 * gBattleMovePower) / 100; if (type == TYPE_WATER && attacker->ability == ABILITY_TORRENT && attacker->hp <= (attacker->maxHP / 3)) gBattleMovePower = (150 * gBattleMovePower) / 100; if (type == TYPE_BUG && attacker->ability == ABILITY_SWARM && attacker->hp <= (attacker->maxHP / 3)) gBattleMovePower = (150 * gBattleMovePower) / 100; if (gBattleMoves[gCurrentMove].effect == EFFECT_EXPLOSION) defense /= 2; if (type < TYPE_MYSTERY) // is physical { if (gCritMultiplier == 2) { if (attacker->statStages[STAT_STAGE_ATK] > 6) APPLY_STAT_MOD(damage, attacker, attack, STAT_STAGE_ATK) else damage = attack; } else APPLY_STAT_MOD(damage, attacker, attack, STAT_STAGE_ATK) damage = damage * gBattleMovePower; damage *= (2 * attacker->level / 5 + 2); if (gCritMultiplier == 2) { if (defender->statStages[STAT_STAGE_DEF] < 6) APPLY_STAT_MOD(damageHelper, defender, defense, STAT_STAGE_DEF) else damageHelper = defense; } else APPLY_STAT_MOD(damageHelper, defender, defense, STAT_STAGE_DEF) damage = damage / damageHelper; damage /= 50; if ((attacker->status1 & STATUS1_BURN) && attacker->ability != ABILITY_GUTS) damage /= 2; if ((sideStatus & SIDE_STATUS_REFLECT) && gCritMultiplier == 1) { if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && CountAliveMonsInBattle(2) == 2) damage = 2 * (damage / 3); else damage /= 2; } if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && gBattleMoves[move].target == 8 && CountAliveMonsInBattle(2) == 2) damage /= 2; // moves always do at least 1 damage. if (damage == 0) damage = 1; } if (type == TYPE_MYSTERY) damage = 0; // is ??? type. does 0 damage. if (type > TYPE_MYSTERY) // is special? { if (gCritMultiplier == 2) { if (attacker->statStages[STAT_STAGE_SPATK] > 6) APPLY_STAT_MOD(damage, attacker, spAttack, STAT_STAGE_SPATK) else damage = spAttack; } else APPLY_STAT_MOD(damage, attacker, spAttack, STAT_STAGE_SPATK) damage = damage * gBattleMovePower; damage *= (2 * attacker->level / 5 + 2); if (gCritMultiplier == 2) { if (defender->statStages[STAT_STAGE_SPDEF] < 6) APPLY_STAT_MOD(damageHelper, defender, spDefense, STAT_STAGE_SPDEF) else damageHelper = spDefense; } else APPLY_STAT_MOD(damageHelper, defender, spDefense, STAT_STAGE_SPDEF) damage = (damage / damageHelper); damage /= 50; if ((sideStatus & SIDE_STATUS_LIGHTSCREEN) && gCritMultiplier == 1) { if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && CountAliveMonsInBattle(2) == 2) damage = 2 * (damage / 3); else damage /= 2; } if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && gBattleMoves[move].target == 8 && CountAliveMonsInBattle(2) == 2) damage /= 2; // are effects of weather negated with cloud nine or air lock if (!AbilityBattleEffects(ABILITYEFFECT_FIELD_SPORT, 0, ABILITY_CLOUD_NINE, 0, 0) && !AbilityBattleEffects(ABILITYEFFECT_FIELD_SPORT, 0, ABILITY_AIR_LOCK, 0, 0)) { if (gBattleWeather & WEATHER_RAIN_TEMPORARY) { switch (type) { case TYPE_FIRE: damage /= 2; break; case TYPE_WATER: damage = (15 * damage) / 10; break; } } // any weather except sun weakens solar beam if ((gBattleWeather & (WEATHER_RAIN_ANY | WEATHER_SANDSTORM_ANY | WEATHER_HAIL)) && gCurrentMove == MOVE_SOLAR_BEAM) damage /= 2; // sunny if (gBattleWeather & WEATHER_SUN_ANY) { switch (type) { case TYPE_FIRE: damage = (15 * damage) / 10; break; case TYPE_WATER: damage /= 2; break; } } } // flash fire triggered if ((gBattleResources->flags->flags[bankAtk] & UNKNOWN_FLAG_FLASH_FIRE) && type == TYPE_FIRE) damage = (15 * damage) / 10; } return damage + 2; } u8 CountAliveMonsInBattle(u8 caseId) { s32 i; u8 retVal = 0; switch (caseId) { case BATTLE_ALIVE_EXCEPT_ACTIVE: for (i = 0; i < 4; i++) { if (i != gActiveBattler && !(gAbsentBattlerFlags & gBitTable[i])) retVal++; } break; case BATTLE_ALIVE_ATK_SIDE: for (i = 0; i < 4; i++) { if (GetBattlerSide(i) == GetBattlerSide(gBattlerAttacker) && !(gAbsentBattlerFlags & gBitTable[i])) retVal++; } break; case BATTLE_ALIVE_DEF_SIDE: for (i = 0; i < 4; i++) { if (GetBattlerSide(i) == GetBattlerSide(gBattlerTarget) && !(gAbsentBattlerFlags & gBitTable[i])) retVal++; } break; } return retVal; } bool8 ShouldGetStatBadgeBoost(u16 badgeFlag, u8 bank) { if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_x2000000 | BATTLE_TYPE_FRONTIER)) return FALSE; if (GetBattlerSide(bank) != B_SIDE_PLAYER) return FALSE; if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && gTrainerBattleOpponent_A == SECRET_BASE_OPPONENT) return FALSE; if (FlagGet(badgeFlag)) return TRUE; return FALSE; } u8 GetDefaultMoveTarget(u8 bank) { u8 status = GetBattlerPosition(bank) & 1; status ^= 1; if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) return GetBattlerAtPosition(status); if (CountAliveMonsInBattle(BATTLE_ALIVE_EXCEPT_ACTIVE) > 1) { u8 val; if ((Random() & 1) == 0) val = status ^ 2; else val = status; return GetBattlerAtPosition(val); } else { if ((gAbsentBattlerFlags & gBitTable[status])) return GetBattlerAtPosition(status ^ 2); else return GetBattlerAtPosition(status); } } u8 GetMonGender(struct Pokemon *mon) { return GetBoxMonGender(&mon->box); } u8 GetBoxMonGender(struct BoxPokemon *boxMon) { u16 species = GetBoxMonData(boxMon, MON_DATA_SPECIES, NULL); u32 personality = GetBoxMonData(boxMon, MON_DATA_PERSONALITY, NULL); switch (gBaseStats[species].genderRatio) { case MON_MALE: case MON_FEMALE: case MON_GENDERLESS: return gBaseStats[species].genderRatio; } if (gBaseStats[species].genderRatio > (personality & 0xFF)) return MON_FEMALE; else return MON_MALE; } u8 GetGenderFromSpeciesAndPersonality(u16 species, u32 personality) { switch (gBaseStats[species].genderRatio) { case MON_MALE: case MON_FEMALE: case MON_GENDERLESS: return gBaseStats[species].genderRatio; } if (gBaseStats[species].genderRatio > (personality & 0xFF)) return MON_FEMALE; else return MON_MALE; } void sub_806A068(u16 species, u8 bankIdentity) { if (gMonSpritesGfxPtr != NULL) gUnknown_0202499C = gMonSpritesGfxPtr->templates[bankIdentity]; else if (gUnknown_020249B4[0]) gUnknown_0202499C = gUnknown_020249B4[0]->templates[bankIdentity]; else if (gUnknown_020249B4[1]) gUnknown_0202499C = gUnknown_020249B4[1]->templates[bankIdentity]; else gUnknown_0202499C = gUnknown_08329D98[bankIdentity]; gUnknown_0202499C.paletteTag = species; if (bankIdentity == 0 || bankIdentity == 2) gUnknown_0202499C.anims = gUnknown_082FF70C; else if (species > 500) gUnknown_0202499C.anims = gMonAnimationsSpriteAnimsPtrTable[species - 500]; else gUnknown_0202499C.anims = gMonAnimationsSpriteAnimsPtrTable[species]; } void sub_806A12C(u16 trainerSpriteId, u8 bankIdentity) { gUnknown_0202499C.paletteTag = trainerSpriteId; if (bankIdentity == 0 || bankIdentity == 2) { gUnknown_0202499C = gUnknown_08329DF8[trainerSpriteId]; gUnknown_0202499C.anims = gUnknown_08305D0C[trainerSpriteId]; } else { if (gMonSpritesGfxPtr != NULL) gUnknown_0202499C = gMonSpritesGfxPtr->templates[bankIdentity]; else gUnknown_0202499C = gUnknown_08329D98[bankIdentity]; gUnknown_0202499C.anims = gUnknown_0830536C[trainerSpriteId]; } } void sub_806A1C0(u16 arg0, u8 bankIdentity) { if (gMonSpritesGfxPtr != NULL) gUnknown_0202499C = gMonSpritesGfxPtr->templates[bankIdentity]; else gUnknown_0202499C = gUnknown_08329D98[bankIdentity]; gUnknown_0202499C.paletteTag = arg0; gUnknown_0202499C.anims = gUnknown_0830536C[arg0]; } void EncryptBoxMon(struct BoxPokemon *boxMon) { u32 i; for (i = 0; i < 12; i++) { boxMon->secure.raw[i] ^= boxMon->personality; boxMon->secure.raw[i] ^= boxMon->otId; } } void DecryptBoxMon(struct BoxPokemon *boxMon) { u32 i; for (i = 0; i < 12; i++) { boxMon->secure.raw[i] ^= boxMon->otId; boxMon->secure.raw[i] ^= boxMon->personality; } } #define SUBSTRUCT_CASE(n, v1, v2, v3, v4) \ case n: \ { \ union PokemonSubstruct *substructs0 = boxMon->secure.substructs; \ union PokemonSubstruct *substructs1 = boxMon->secure.substructs; \ union PokemonSubstruct *substructs2 = boxMon->secure.substructs; \ union PokemonSubstruct *substructs3 = boxMon->secure.substructs; \ union PokemonSubstruct *substructs4 = boxMon->secure.substructs; \ union PokemonSubstruct *substructs5 = boxMon->secure.substructs; \ union PokemonSubstruct *substructs6 = boxMon->secure.substructs; \ union PokemonSubstruct *substructs7 = boxMon->secure.substructs; \ union PokemonSubstruct *substructs8 = boxMon->secure.substructs; \ union PokemonSubstruct *substructs9 = boxMon->secure.substructs; \ union PokemonSubstruct *substructs10 = boxMon->secure.substructs; \ union PokemonSubstruct *substructs11 = boxMon->secure.substructs; \ union PokemonSubstruct *substructs12 = boxMon->secure.substructs; \ union PokemonSubstruct *substructs13 = boxMon->secure.substructs; \ union PokemonSubstruct *substructs14 = boxMon->secure.substructs; \ union PokemonSubstruct *substructs15 = boxMon->secure.substructs; \ union PokemonSubstruct *substructs16 = boxMon->secure.substructs; \ union PokemonSubstruct *substructs17 = boxMon->secure.substructs; \ union PokemonSubstruct *substructs18 = boxMon->secure.substructs; \ union PokemonSubstruct *substructs19 = boxMon->secure.substructs; \ union PokemonSubstruct *substructs20 = boxMon->secure.substructs; \ union PokemonSubstruct *substructs21 = boxMon->secure.substructs; \ union PokemonSubstruct *substructs22 = boxMon->secure.substructs; \ union PokemonSubstruct *substructs23 = boxMon->secure.substructs; \ \ switch (substructType) \ { \ case 0: \ substruct = &substructs ## n [v1]; \ break; \ case 1: \ substruct = &substructs ## n [v2]; \ break; \ case 2: \ substruct = &substructs ## n [v3]; \ break; \ case 3: \ substruct = &substructs ## n [v4]; \ break; \ } \ break; \ } \ union PokemonSubstruct *GetSubstruct(struct BoxPokemon *boxMon, u32 personality, u8 substructType) { union PokemonSubstruct *substruct = NULL; switch (personality % 24) { SUBSTRUCT_CASE( 0,0,1,2,3) SUBSTRUCT_CASE( 1,0,1,3,2) SUBSTRUCT_CASE( 2,0,2,1,3) SUBSTRUCT_CASE( 3,0,3,1,2) SUBSTRUCT_CASE( 4,0,2,3,1) SUBSTRUCT_CASE( 5,0,3,2,1) SUBSTRUCT_CASE( 6,1,0,2,3) SUBSTRUCT_CASE( 7,1,0,3,2) SUBSTRUCT_CASE( 8,2,0,1,3) SUBSTRUCT_CASE( 9,3,0,1,2) SUBSTRUCT_CASE(10,2,0,3,1) SUBSTRUCT_CASE(11,3,0,2,1) SUBSTRUCT_CASE(12,1,2,0,3) SUBSTRUCT_CASE(13,1,3,0,2) SUBSTRUCT_CASE(14,2,1,0,3) SUBSTRUCT_CASE(15,3,1,0,2) SUBSTRUCT_CASE(16,2,3,0,1) SUBSTRUCT_CASE(17,3,2,0,1) SUBSTRUCT_CASE(18,1,2,3,0) SUBSTRUCT_CASE(19,1,3,2,0) SUBSTRUCT_CASE(20,2,1,3,0) SUBSTRUCT_CASE(21,3,1,2,0) SUBSTRUCT_CASE(22,2,3,1,0) SUBSTRUCT_CASE(23,3,2,1,0) } return substruct; } u32 GetMonData(struct Pokemon *mon, s32 field, u8* data) { u32 ret; switch (field) { case MON_DATA_STATUS: ret = mon->status; break; case MON_DATA_LEVEL: ret = mon->level; break; case MON_DATA_HP: ret = mon->hp; break; case MON_DATA_MAX_HP: ret = mon->maxHP; break; case MON_DATA_ATK: ret = (u16)GetDeoxysStat(mon, STAT_ATK); if (!ret) ret = mon->attack; break; case MON_DATA_DEF: ret = (u16)GetDeoxysStat(mon, STAT_DEF); if (!ret) ret = mon->defense; break; case MON_DATA_SPEED: ret = (u16)GetDeoxysStat(mon, STAT_SPD); if (!ret) ret = mon->speed; break; case MON_DATA_SPATK: ret = (u16)GetDeoxysStat(mon, STAT_SPATK); if (!ret) ret = mon->spAttack; break; case MON_DATA_SPDEF: ret = (u16)GetDeoxysStat(mon, STAT_SPDEF); if (!ret) ret = mon->spDefense; break; case MON_DATA_ATK2: ret = mon->attack; break; case MON_DATA_DEF2: ret = mon->defense; break; case MON_DATA_SPEED2: ret = mon->speed; break; case MON_DATA_SPATK2: ret = mon->spAttack; break; case MON_DATA_SPDEF2: ret = mon->spDefense; break; case MON_DATA_MAIL: ret = mon->mail; break; default: ret = GetBoxMonData(&mon->box, field, data); break; } return ret; } u32 GetBoxMonData(struct BoxPokemon *boxMon, s32 field, u8 *data) { s32 i; u32 retVal = 0; struct PokemonSubstruct0 *substruct0 = NULL; struct PokemonSubstruct1 *substruct1 = NULL; struct PokemonSubstruct2 *substruct2 = NULL; struct PokemonSubstruct3 *substruct3 = NULL; if (field > MON_DATA_10) { substruct0 = &(GetSubstruct(boxMon, boxMon->personality, 0)->type0); substruct1 = &(GetSubstruct(boxMon, boxMon->personality, 1)->type1); substruct2 = &(GetSubstruct(boxMon, boxMon->personality, 2)->type2); substruct3 = &(GetSubstruct(boxMon, boxMon->personality, 3)->type3); DecryptBoxMon(boxMon); if (CalculateBoxMonChecksum(boxMon) != boxMon->checksum) { boxMon->isBadEgg = 1; boxMon->isEgg = 1; substruct3->isEgg = 1; } } switch (field) { case MON_DATA_PERSONALITY: retVal = boxMon->personality; break; case MON_DATA_OT_ID: retVal = boxMon->otId; break; case MON_DATA_NICKNAME: { if (boxMon->isBadEgg) { for (retVal = 0; retVal < POKEMON_NAME_LENGTH && gText_BadEgg[retVal] != EOS; data[retVal] = gText_BadEgg[retVal], retVal++) {} data[retVal] = EOS; } else if (boxMon->isEgg) { StringCopy(data, gText_EggNickname); retVal = StringLength(data); } else if (boxMon->language == LANGUAGE_JAPANESE) { data[0] = EXT_CTRL_CODE_BEGIN; data[1] = EXT_CTRL_CODE_JPN; for (retVal = 2, i = 0; i < 5 && boxMon->nickname[i] != EOS; data[retVal] = boxMon->nickname[i], retVal++, i++) {} data[retVal++] = EXT_CTRL_CODE_BEGIN; data[retVal++] = EXT_CTRL_CODE_ENG; data[retVal] = EOS; } else { for (retVal = 0; retVal < POKEMON_NAME_LENGTH; data[retVal] = boxMon->nickname[retVal], retVal++){} data[retVal] = EOS; } break; } case MON_DATA_LANGUAGE: retVal = boxMon->language; break; case MON_DATA_SANITY_BIT1: retVal = boxMon->isBadEgg; break; case MON_DATA_SANITY_BIT2: retVal = boxMon->hasSpecies; break; case MON_DATA_SANITY_BIT3: retVal = boxMon->isEgg; break; case MON_DATA_OT_NAME: { retVal = 0; while (retVal < OT_NAME_LENGTH) { data[retVal] = boxMon->otName[retVal]; retVal++; } data[retVal] = EOS; break; } case MON_DATA_MARKINGS: retVal = boxMon->markings; break; case MON_DATA_CHECKSUM: retVal = boxMon->checksum; break; case MON_DATA_10: retVal = boxMon->unknown; break; case MON_DATA_SPECIES: retVal = boxMon->isBadEgg ? SPECIES_EGG : substruct0->species; break; case MON_DATA_HELD_ITEM: retVal = substruct0->heldItem; break; case MON_DATA_EXP: retVal = substruct0->experience; break; case MON_DATA_PP_BONUSES: retVal = substruct0->ppBonuses; break; case MON_DATA_FRIENDSHIP: retVal = substruct0->friendship; break; case MON_DATA_MOVE1: case MON_DATA_MOVE2: case MON_DATA_MOVE3: case MON_DATA_MOVE4: retVal = substruct1->moves[field - MON_DATA_MOVE1]; break; case MON_DATA_PP1: case MON_DATA_PP2: case MON_DATA_PP3: case MON_DATA_PP4: retVal = substruct1->pp[field - MON_DATA_PP1]; break; case MON_DATA_HP_EV: retVal = substruct2->hpEV; break; case MON_DATA_ATK_EV: retVal = substruct2->attackEV; break; case MON_DATA_DEF_EV: retVal = substruct2->defenseEV; break; case MON_DATA_SPEED_EV: retVal = substruct2->speedEV; break; case MON_DATA_SPATK_EV: retVal = substruct2->spAttackEV; break; case MON_DATA_SPDEF_EV: retVal = substruct2->spDefenseEV; break; case MON_DATA_COOL: retVal = substruct2->cool; break; case MON_DATA_BEAUTY: retVal = substruct2->beauty; break; case MON_DATA_CUTE: retVal = substruct2->cute; break; case MON_DATA_SMART: retVal = substruct2->smart; break; case MON_DATA_TOUGH: retVal = substruct2->tough; break; case MON_DATA_SHEEN: retVal = substruct2->sheen; break; case MON_DATA_POKERUS: retVal = substruct3->pokerus; break; case MON_DATA_MET_LOCATION: retVal = substruct3->metLocation; break; case MON_DATA_MET_LEVEL: retVal = substruct3->metLevel; break; case MON_DATA_MET_GAME: retVal = substruct3->metGame; break; case MON_DATA_POKEBALL: retVal = substruct3->pokeball; break; case MON_DATA_OT_GENDER: retVal = substruct3->otGender; break; case MON_DATA_HP_IV: retVal = substruct3->hpIV; break; case MON_DATA_ATK_IV: retVal = substruct3->attackIV; break; case MON_DATA_DEF_IV: retVal = substruct3->defenseIV; break; case MON_DATA_SPEED_IV: retVal = substruct3->speedIV; break; case MON_DATA_SPATK_IV: retVal = substruct3->spAttackIV; break; case MON_DATA_SPDEF_IV: retVal = substruct3->spDefenseIV; break; case MON_DATA_IS_EGG: retVal = substruct3->isEgg; break; case MON_DATA_ALT_ABILITY: retVal = substruct3->altAbility; break; case MON_DATA_COOL_RIBBON: retVal = substruct3->coolRibbon; break; case MON_DATA_BEAUTY_RIBBON: retVal = substruct3->beautyRibbon; break; case MON_DATA_CUTE_RIBBON: retVal = substruct3->cuteRibbon; break; case MON_DATA_SMART_RIBBON: retVal = substruct3->smartRibbon; break; case MON_DATA_TOUGH_RIBBON: retVal = substruct3->toughRibbon; break; case MON_DATA_CHAMPION_RIBBON: retVal = substruct3->championRibbon; break; case MON_DATA_WINNING_RIBBON: retVal = substruct3->winningRibbon; break; case MON_DATA_VICTORY_RIBBON: retVal = substruct3->victoryRibbon; break; case MON_DATA_ARTIST_RIBBON: retVal = substruct3->artistRibbon; break; case MON_DATA_EFFORT_RIBBON: retVal = substruct3->effortRibbon; break; case MON_DATA_GIFT_RIBBON_1: retVal = substruct3->giftRibbon1; break; case MON_DATA_GIFT_RIBBON_2: retVal = substruct3->giftRibbon2; break; case MON_DATA_GIFT_RIBBON_3: retVal = substruct3->giftRibbon3; break; case MON_DATA_GIFT_RIBBON_4: retVal = substruct3->giftRibbon4; break; case MON_DATA_GIFT_RIBBON_5: retVal = substruct3->giftRibbon5; break; case MON_DATA_GIFT_RIBBON_6: retVal = substruct3->giftRibbon6; break; case MON_DATA_GIFT_RIBBON_7: retVal = substruct3->giftRibbon7; break; case MON_DATA_FATEFUL_ENCOUNTER: retVal = substruct3->fatefulEncounter; break; case MON_DATA_OBEDIENCE: retVal = substruct3->obedient; break; case MON_DATA_SPECIES2: retVal = substruct0->species; if (substruct0->species && (substruct3->isEgg || boxMon->isBadEgg)) retVal = SPECIES_EGG; break; case MON_DATA_IVS: retVal = substruct3->hpIV | (substruct3->attackIV << 5) | (substruct3->defenseIV << 10) | (substruct3->speedIV << 15) | (substruct3->spAttackIV << 20) | (substruct3->spDefenseIV << 25); break; case MON_DATA_KNOWN_MOVES: if (substruct0->species && !substruct3->isEgg) { u16 *moves = (u16 *)data; s32 i = 0; while (moves[i] != 355) { u16 move = moves[i]; if (substruct1->moves[0] == move || substruct1->moves[1] == move || substruct1->moves[2] == move || substruct1->moves[3] == move) retVal |= gBitTable[i]; i++; } } break; case MON_DATA_RIBBON_COUNT: retVal = 0; if (substruct0->species && !substruct3->isEgg) { retVal += substruct3->coolRibbon; retVal += substruct3->beautyRibbon; retVal += substruct3->cuteRibbon; retVal += substruct3->smartRibbon; retVal += substruct3->toughRibbon; retVal += substruct3->championRibbon; retVal += substruct3->winningRibbon; retVal += substruct3->victoryRibbon; retVal += substruct3->artistRibbon; retVal += substruct3->effortRibbon; retVal += substruct3->giftRibbon1; retVal += substruct3->giftRibbon2; retVal += substruct3->giftRibbon3; retVal += substruct3->giftRibbon4; retVal += substruct3->giftRibbon5; retVal += substruct3->giftRibbon6; retVal += substruct3->giftRibbon7; } break; case MON_DATA_RIBBONS: retVal = 0; if (substruct0->species && !substruct3->isEgg) { retVal = substruct3->championRibbon | (substruct3->coolRibbon << 1) | (substruct3->beautyRibbon << 4) | (substruct3->cuteRibbon << 7) | (substruct3->smartRibbon << 10) | (substruct3->toughRibbon << 13) | (substruct3->winningRibbon << 16) | (substruct3->victoryRibbon << 17) | (substruct3->artistRibbon << 18) | (substruct3->effortRibbon << 19) | (substruct3->giftRibbon1 << 20) | (substruct3->giftRibbon2 << 21) | (substruct3->giftRibbon3 << 22) | (substruct3->giftRibbon4 << 23) | (substruct3->giftRibbon5 << 24) | (substruct3->giftRibbon6 << 25) | (substruct3->giftRibbon7 << 26); } break; default: break; } if (field > MON_DATA_10) EncryptBoxMon(boxMon); return retVal; } #define SET8(lhs) (lhs) = *data #define SET16(lhs) (lhs) = data[0] + (data[1] << 8) #define SET32(lhs) (lhs) = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24) void SetMonData(struct Pokemon *mon, s32 field, const void *dataArg) { const u8* data = dataArg; switch (field) { case MON_DATA_STATUS: SET32(mon->status); break; case MON_DATA_LEVEL: SET8(mon->level); break; case MON_DATA_HP: SET16(mon->hp); break; case MON_DATA_MAX_HP: SET16(mon->maxHP); break; case MON_DATA_ATK: SET16(mon->attack); break; case MON_DATA_DEF: SET16(mon->defense); break; case MON_DATA_SPEED: SET16(mon->speed); break; case MON_DATA_SPATK: SET16(mon->spAttack); break; case MON_DATA_SPDEF: SET16(mon->spDefense); break; case MON_DATA_MAIL: SET8(mon->mail); break; case MON_DATA_SPECIES2: break; default: SetBoxMonData(&mon->box, field, data); break; } } void SetBoxMonData(struct BoxPokemon *boxMon, s32 field, const void *dataArg) { const u8* data = dataArg; struct PokemonSubstruct0 *substruct0 = NULL; struct PokemonSubstruct1 *substruct1 = NULL; struct PokemonSubstruct2 *substruct2 = NULL; struct PokemonSubstruct3 *substruct3 = NULL; if (field > MON_DATA_10) { substruct0 = &(GetSubstruct(boxMon, boxMon->personality, 0)->type0); substruct1 = &(GetSubstruct(boxMon, boxMon->personality, 1)->type1); substruct2 = &(GetSubstruct(boxMon, boxMon->personality, 2)->type2); substruct3 = &(GetSubstruct(boxMon, boxMon->personality, 3)->type3); DecryptBoxMon(boxMon); if (CalculateBoxMonChecksum(boxMon) != boxMon->checksum) { boxMon->isBadEgg = 1; boxMon->isEgg = 1; substruct3->isEgg = 1; EncryptBoxMon(boxMon); return; } } switch (field) { case MON_DATA_PERSONALITY: SET32(boxMon->personality); break; case MON_DATA_OT_ID: SET32(boxMon->otId); break; case MON_DATA_NICKNAME: { s32 i; for (i = 0; i < POKEMON_NAME_LENGTH; i++) boxMon->nickname[i] = data[i]; break; } case MON_DATA_LANGUAGE: SET8(boxMon->language); break; case MON_DATA_SANITY_BIT1: SET8(boxMon->isBadEgg); break; case MON_DATA_SANITY_BIT2: SET8(boxMon->hasSpecies); break; case MON_DATA_SANITY_BIT3: SET8(boxMon->isEgg); break; case MON_DATA_OT_NAME: { s32 i; for (i = 0; i < OT_NAME_LENGTH; i++) boxMon->otName[i] = data[i]; break; } case MON_DATA_MARKINGS: SET8(boxMon->markings); break; case MON_DATA_CHECKSUM: SET16(boxMon->checksum); break; case MON_DATA_10: SET16(boxMon->unknown); break; case MON_DATA_SPECIES: { SET16(substruct0->species); if (substruct0->species) boxMon->hasSpecies = 1; else boxMon->hasSpecies = 0; break; } case MON_DATA_HELD_ITEM: SET16(substruct0->heldItem); break; case MON_DATA_EXP: SET32(substruct0->experience); break; case MON_DATA_PP_BONUSES: SET8(substruct0->ppBonuses); break; case MON_DATA_FRIENDSHIP: SET8(substruct0->friendship); break; case MON_DATA_MOVE1: case MON_DATA_MOVE2: case MON_DATA_MOVE3: case MON_DATA_MOVE4: SET16(substruct1->moves[field - MON_DATA_MOVE1]); break; case MON_DATA_PP1: case MON_DATA_PP2: case MON_DATA_PP3: case MON_DATA_PP4: SET8(substruct1->pp[field - MON_DATA_PP1]); break; case MON_DATA_HP_EV: SET8(substruct2->hpEV); break; case MON_DATA_ATK_EV: SET8(substruct2->attackEV); break; case MON_DATA_DEF_EV: SET8(substruct2->defenseEV); break; case MON_DATA_SPEED_EV: SET8(substruct2->speedEV); break; case MON_DATA_SPATK_EV: SET8(substruct2->spAttackEV); break; case MON_DATA_SPDEF_EV: SET8(substruct2->spDefenseEV); break; case MON_DATA_COOL: SET8(substruct2->cool); break; case MON_DATA_BEAUTY: SET8(substruct2->beauty); break; case MON_DATA_CUTE: SET8(substruct2->cute); break; case MON_DATA_SMART: SET8(substruct2->smart); break; case MON_DATA_TOUGH: SET8(substruct2->tough); break; case MON_DATA_SHEEN: SET8(substruct2->sheen); break; case MON_DATA_POKERUS: SET8(substruct3->pokerus); break; case MON_DATA_MET_LOCATION: SET8(substruct3->metLocation); break; case MON_DATA_MET_LEVEL: { u8 metLevel = *data; substruct3->metLevel = metLevel; break; } case MON_DATA_MET_GAME: SET8(substruct3->metGame); break; case MON_DATA_POKEBALL: { u8 pokeball = *data; substruct3->pokeball = pokeball; break; } case MON_DATA_OT_GENDER: SET8(substruct3->otGender); break; case MON_DATA_HP_IV: SET8(substruct3->hpIV); break; case MON_DATA_ATK_IV: SET8(substruct3->attackIV); break; case MON_DATA_DEF_IV: SET8(substruct3->defenseIV); break; case MON_DATA_SPEED_IV: SET8(substruct3->speedIV); break; case MON_DATA_SPATK_IV: SET8(substruct3->spAttackIV); break; case MON_DATA_SPDEF_IV: SET8(substruct3->spDefenseIV); break; case MON_DATA_IS_EGG: SET8(substruct3->isEgg); if (substruct3->isEgg) boxMon->isEgg = 1; else boxMon->isEgg = 0; break; case MON_DATA_ALT_ABILITY: SET8(substruct3->altAbility); break; case MON_DATA_COOL_RIBBON: SET8(substruct3->coolRibbon); break; case MON_DATA_BEAUTY_RIBBON: SET8(substruct3->beautyRibbon); break; case MON_DATA_CUTE_RIBBON: SET8(substruct3->cuteRibbon); break; case MON_DATA_SMART_RIBBON: SET8(substruct3->smartRibbon); break; case MON_DATA_TOUGH_RIBBON: SET8(substruct3->toughRibbon); break; case MON_DATA_CHAMPION_RIBBON: SET8(substruct3->championRibbon); break; case MON_DATA_WINNING_RIBBON: SET8(substruct3->winningRibbon); break; case MON_DATA_VICTORY_RIBBON: SET8(substruct3->victoryRibbon); break; case MON_DATA_ARTIST_RIBBON: SET8(substruct3->artistRibbon); break; case MON_DATA_EFFORT_RIBBON: SET8(substruct3->effortRibbon); break; case MON_DATA_GIFT_RIBBON_1: SET8(substruct3->giftRibbon1); break; case MON_DATA_GIFT_RIBBON_2: SET8(substruct3->giftRibbon2); break; case MON_DATA_GIFT_RIBBON_3: SET8(substruct3->giftRibbon3); break; case MON_DATA_GIFT_RIBBON_4: SET8(substruct3->giftRibbon4); break; case MON_DATA_GIFT_RIBBON_5: SET8(substruct3->giftRibbon5); break; case MON_DATA_GIFT_RIBBON_6: SET8(substruct3->giftRibbon6); break; case MON_DATA_GIFT_RIBBON_7: SET8(substruct3->giftRibbon7); break; case MON_DATA_FATEFUL_ENCOUNTER: SET8(substruct3->fatefulEncounter); break; case MON_DATA_OBEDIENCE: SET8(substruct3->obedient); break; case MON_DATA_IVS: { u32 ivs = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); substruct3->hpIV = ivs & 0x1F; substruct3->attackIV = (ivs >> 5) & 0x1F; substruct3->defenseIV = (ivs >> 10) & 0x1F; substruct3->speedIV = (ivs >> 15) & 0x1F; substruct3->spAttackIV = (ivs >> 20) & 0x1F; substruct3->spDefenseIV = (ivs >> 25) & 0x1F; break; } default: break; } if (field > MON_DATA_10) { boxMon->checksum = CalculateBoxMonChecksum(boxMon); EncryptBoxMon(boxMon); } } void CopyMon(void *dest, void *src, size_t size) { memcpy(dest, src, size); } u8 GiveMonToPlayer(struct Pokemon *mon) { s32 i; SetMonData(mon, MON_DATA_OT_NAME, gSaveBlock2Ptr->playerName); SetMonData(mon, MON_DATA_OT_GENDER, &gSaveBlock2Ptr->playerGender); SetMonData(mon, MON_DATA_OT_ID, gSaveBlock2Ptr->playerTrainerId); i = 0; while (i < 6 && GetMonData(&gPlayerParty[i], MON_DATA_SPECIES, NULL) != SPECIES_NONE) i++; if (i >= 6) return SendMonToPC(mon); CopyMon(&gPlayerParty[i], mon, sizeof(*mon)); gPlayerPartyCount = i + 1; return MON_GIVEN_TO_PARTY; } u8 SendMonToPC(struct Pokemon* mon) { s32 boxNo, boxPos; set_unknown_box_id(VarGet(VAR_STORAGE_UNKNOWN)); boxNo = StorageGetCurrentBox(); do { for (boxPos = 0; boxPos < 30; boxPos++) { struct BoxPokemon* checkingMon = GetBoxedMonPtr(boxNo, boxPos); if (GetBoxMonData(checkingMon, MON_DATA_SPECIES, NULL) == SPECIES_NONE) { MonRestorePP(mon); CopyMon(checkingMon, &mon->box, sizeof(mon->box)); gSpecialVar_MonBoxId = boxNo; gSpecialVar_MonBoxPos = boxPos; if (get_unknown_box_id() != boxNo) FlagClear(FLAG_SYS_STORAGE_UNKNOWN_FLAG); VarSet(VAR_STORAGE_UNKNOWN, boxNo); return MON_GIVEN_TO_PC; } } boxNo++; if (boxNo == 14) boxNo = 0; } while (boxNo != StorageGetCurrentBox()); return MON_CANT_GIVE; } u8 CalculatePlayerPartyCount(void) { gPlayerPartyCount = 0; while (gPlayerPartyCount < 6 && GetMonData(&gPlayerParty[gPlayerPartyCount], MON_DATA_SPECIES, NULL) != SPECIES_NONE) { gPlayerPartyCount++; } return gPlayerPartyCount; } u8 CalculateEnemyPartyCount(void) { gEnemyPartyCount = 0; while (gEnemyPartyCount < 6 && GetMonData(&gEnemyParty[gEnemyPartyCount], MON_DATA_SPECIES, NULL) != SPECIES_NONE) { gEnemyPartyCount++; } return gEnemyPartyCount; } u8 GetMonsStateToDoubles(void) { s32 aliveCount = 0; s32 i; CalculatePlayerPartyCount(); if (gPlayerPartyCount == 1) return gPlayerPartyCount; // PLAYER_HAS_ONE_MON for (i = 0; i < gPlayerPartyCount; i++) { if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2, NULL) != SPECIES_EGG && GetMonData(&gPlayerParty[i], MON_DATA_HP, NULL) != 0 && GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2, NULL) != SPECIES_NONE) aliveCount++; } return (aliveCount > 1) ? PLAYER_HAS_TWO_USABLE_MONS : PLAYER_HAS_ONE_USABLE_MON; } u8 GetMonsStateToDoubles_2(void) { s32 aliveCount = 0; s32 i; for (i = 0; i < PARTY_SIZE; i++) { u32 species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2, NULL); if (species != SPECIES_EGG && species != SPECIES_NONE && GetMonData(&gPlayerParty[i], MON_DATA_HP, NULL) != 0) aliveCount++; } if (aliveCount == 1) return PLAYER_HAS_ONE_MON; // may have more than one, but only one is alive return (aliveCount > 1) ? PLAYER_HAS_TWO_USABLE_MONS : PLAYER_HAS_ONE_USABLE_MON; } u8 GetAbilityBySpecies(u16 species, bool8 altAbility) { if (altAbility) gLastUsedAbility = gBaseStats[species].ability2; else gLastUsedAbility = gBaseStats[species].ability1; return gLastUsedAbility; } u8 GetMonAbility(struct Pokemon *mon) { u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL); u8 altAbility = GetMonData(mon, MON_DATA_ALT_ABILITY, NULL); return GetAbilityBySpecies(species, altAbility); } void CreateSecretBaseEnemyParty(struct SecretBaseRecord *secretBaseRecord) { s32 i, j; ZeroEnemyPartyMons(); *gBattleResources->secretBase = *secretBaseRecord; for (i = 0; i < PARTY_SIZE; i++) { if (gBattleResources->secretBase->party.species[i]) { CreateMon(&gEnemyParty[i], gBattleResources->secretBase->party.species[i], gBattleResources->secretBase->party.levels[i], 15, 1, gBattleResources->secretBase->party.personality[i], 2, 0); SetMonData(&gEnemyParty[i], MON_DATA_HELD_ITEM, &gBattleResources->secretBase->party.heldItems[i]); for (j = 0; j < 6; j++) SetMonData(&gEnemyParty[i], MON_DATA_HP_EV + j, &gBattleResources->secretBase->party.EVs[i]); for (j = 0; j < 4; j++) { SetMonData(&gEnemyParty[i], MON_DATA_MOVE1 + j, &gBattleResources->secretBase->party.moves[i * 4 + j]); SetMonData(&gEnemyParty[i], MON_DATA_PP1 + j, &gBattleMoves[gBattleResources->secretBase->party.moves[i * 4 + j]].pp); } } } } u8 GetSecretBaseTrainerPicIndex(void) { u8 trainerClass = gSecretBaseTrainerClasses[gBattleResources->secretBase->gender][gBattleResources->secretBase->trainerId[0] % 5]; return gFacilityClassToPicIndex[trainerClass]; } u8 GetSecretBaseTrainerNameIndex(void) { u8 trainerClass = gSecretBaseTrainerClasses[gBattleResources->secretBase->gender][gBattleResources->secretBase->trainerId[0] % 5]; return gFacilityClassToTrainerClass[trainerClass]; } bool8 IsPlayerPartyAndPokemonStorageFull(void) { s32 i; for (i = 0; i < 6; i++) if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES, NULL) == SPECIES_NONE) return FALSE; return IsPokemonStorageFull(); } bool8 IsPokemonStorageFull(void) { s32 i, j; for (i = 0; i < 14; i++) for (j = 0; j < 30; j++) if (GetBoxMonDataFromAnyBox(i, j, MON_DATA_SPECIES) == SPECIES_NONE) return FALSE; return TRUE; } void GetSpeciesName(u8 *name, u16 species) { s32 i; for (i = 0; i <= POKEMON_NAME_LENGTH; i++) { if (species > NUM_SPECIES) name[i] = gSpeciesNames[0][i]; else name[i] = gSpeciesNames[species][i]; if (name[i] == EOS) break; } name[i] = EOS; } u8 CalculatePPWithBonus(u16 move, u8 ppBonuses, u8 moveIndex) { u8 basePP = gBattleMoves[move].pp; return basePP + ((basePP * 20 * ((gUnknown_08329D22[moveIndex] & ppBonuses) >> (2 * moveIndex))) / 100); } void RemoveMonPPBonus(struct Pokemon *mon, u8 moveIndex) { u8 ppBonuses = GetMonData(mon, MON_DATA_PP_BONUSES, NULL); ppBonuses &= gUnknown_08329D26[moveIndex]; SetMonData(mon, MON_DATA_PP_BONUSES, &ppBonuses); } void RemoveBattleMonPPBonus(struct BattlePokemon *mon, u8 moveIndex) { mon->ppBonuses &= gUnknown_08329D26[moveIndex]; } void CopyPlayerPartyMonToBattleData(u8 bank, u8 partyIndex) { u16* hpSwitchout; s32 i; u8 nickname[POKEMON_NAME_LENGTH * 2]; gBattleMons[bank].species = GetMonData(&gPlayerParty[partyIndex], MON_DATA_SPECIES, NULL); gBattleMons[bank].item = GetMonData(&gPlayerParty[partyIndex], MON_DATA_HELD_ITEM, NULL); for (i = 0; i < 4; i++) { gBattleMons[bank].moves[i] = GetMonData(&gPlayerParty[partyIndex], MON_DATA_MOVE1 + i, NULL); gBattleMons[bank].pp[i] = GetMonData(&gPlayerParty[partyIndex], MON_DATA_PP1 + i, NULL); } gBattleMons[bank].ppBonuses = GetMonData(&gPlayerParty[partyIndex], MON_DATA_PP_BONUSES, NULL); gBattleMons[bank].friendship = GetMonData(&gPlayerParty[partyIndex], MON_DATA_FRIENDSHIP, NULL); gBattleMons[bank].experience = GetMonData(&gPlayerParty[partyIndex], MON_DATA_EXP, NULL); gBattleMons[bank].hpIV = GetMonData(&gPlayerParty[partyIndex], MON_DATA_HP_IV, NULL); gBattleMons[bank].attackIV = GetMonData(&gPlayerParty[partyIndex], MON_DATA_ATK_IV, NULL); gBattleMons[bank].defenseIV = GetMonData(&gPlayerParty[partyIndex], MON_DATA_DEF_IV, NULL); gBattleMons[bank].speedIV = GetMonData(&gPlayerParty[partyIndex], MON_DATA_SPEED_IV, NULL); gBattleMons[bank].spAttackIV = GetMonData(&gPlayerParty[partyIndex], MON_DATA_SPATK_IV, NULL); gBattleMons[bank].spDefenseIV = GetMonData(&gPlayerParty[partyIndex], MON_DATA_SPDEF_IV, NULL); gBattleMons[bank].personality = GetMonData(&gPlayerParty[partyIndex], MON_DATA_PERSONALITY, NULL); gBattleMons[bank].status1 = GetMonData(&gPlayerParty[partyIndex], MON_DATA_STATUS, NULL); gBattleMons[bank].level = GetMonData(&gPlayerParty[partyIndex], MON_DATA_LEVEL, NULL); gBattleMons[bank].hp = GetMonData(&gPlayerParty[partyIndex], MON_DATA_HP, NULL); gBattleMons[bank].maxHP = GetMonData(&gPlayerParty[partyIndex], MON_DATA_MAX_HP, NULL); gBattleMons[bank].attack = GetMonData(&gPlayerParty[partyIndex], MON_DATA_ATK, NULL); gBattleMons[bank].defense = GetMonData(&gPlayerParty[partyIndex], MON_DATA_DEF, NULL); gBattleMons[bank].speed = GetMonData(&gPlayerParty[partyIndex], MON_DATA_SPEED, NULL); gBattleMons[bank].spAttack = GetMonData(&gPlayerParty[partyIndex], MON_DATA_SPATK, NULL); gBattleMons[bank].spDefense = GetMonData(&gPlayerParty[partyIndex], MON_DATA_SPDEF, NULL); gBattleMons[bank].isEgg = GetMonData(&gPlayerParty[partyIndex], MON_DATA_IS_EGG, NULL); gBattleMons[bank].altAbility = GetMonData(&gPlayerParty[partyIndex], MON_DATA_ALT_ABILITY, NULL); gBattleMons[bank].otId = GetMonData(&gPlayerParty[partyIndex], MON_DATA_OT_ID, NULL); gBattleMons[bank].type1 = gBaseStats[gBattleMons[bank].species].type1; gBattleMons[bank].type2 = gBaseStats[gBattleMons[bank].species].type2; gBattleMons[bank].ability = GetAbilityBySpecies(gBattleMons[bank].species, gBattleMons[bank].altAbility); GetMonData(&gPlayerParty[partyIndex], MON_DATA_NICKNAME, nickname); StringCopy10(gBattleMons[bank].nickname, nickname); GetMonData(&gPlayerParty[partyIndex], MON_DATA_OT_NAME, gBattleMons[bank].otName); hpSwitchout = &gBattleStruct->hpOnSwitchout[GetBattlerSide(bank)]; *hpSwitchout = gBattleMons[bank].hp; for (i = 0; i < 8; i++) gBattleMons[bank].statStages[i] = 6; gBattleMons[bank].status2 = 0; sub_803FA70(bank); ClearTemporarySpeciesSpriteData(bank, FALSE); } bool8 ExecuteTableBasedItemEffect_(struct Pokemon *mon, u16 item, u8 partyIndex, u8 moveIndex) { return PokemonUseItemEffects(mon, item, partyIndex, moveIndex, 0); } bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 moveIndex, u8 e) { u32 dataUnsigned; s32 dataSigned; s32 friendship; s32 cmdIndex; bool8 retVal = TRUE; const u8 *itemEffect; u8 var_3C = 6; u32 var_38; s8 var_34 = 0; u8 holdEffect; u8 battlerId = 4; u32 var_28 = 0; u16 heldItem; u8 r10; u32 r4; u32 r5; s8 r2; u16 evCount; heldItem = GetMonData(mon, MON_DATA_HELD_ITEM, NULL); if (heldItem == ITEM_ENIGMA_BERRY) { if (gMain.inBattle) holdEffect = gEnigmaBerries[gBankInMenu].holdEffect; else holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect; } else { holdEffect = ItemId_GetHoldEffect(heldItem); } gStringBattler = gBankInMenu; if (gMain.inBattle) { gActiveBattler = gBankInMenu; cmdIndex = (GetBattlerSide(gActiveBattler) != B_SIDE_PLAYER); while (cmdIndex < gBattlersCount) { if (gBattlerPartyIndexes[cmdIndex] == partyIndex) { battlerId = cmdIndex; break; } cmdIndex += 2; } } else { gActiveBattler = 0; battlerId = MAX_BATTLERS_COUNT; } if (!IS_POKEMON_ITEM(item)) return TRUE; if (gItemEffectTable[item - 13] == NULL && item != ITEM_ENIGMA_BERRY) return TRUE; if (item == ITEM_ENIGMA_BERRY) { if (gMain.inBattle) itemEffect = gEnigmaBerries[gActiveBattler].itemEffect; else itemEffect = gSaveBlock1Ptr->enigmaBerry.itemEffect; } else { itemEffect = gItemEffectTable[item - 13]; } for (cmdIndex = 0; cmdIndex < 6; cmdIndex++) { switch (cmdIndex) { // status healing effects case 0: if ((itemEffect[cmdIndex] & 0x80) && gMain.inBattle && battlerId != 4 && (gBattleMons[battlerId].status2 & STATUS2_INFATUATION)) { gBattleMons[battlerId].status2 &= ~STATUS2_INFATUATION; retVal = FALSE; } if ((itemEffect[cmdIndex] & 0x30) && !(gBattleMons[gActiveBattler].status2 & STATUS2_FOCUS_ENERGY)) { gBattleMons[gActiveBattler].status2 |= STATUS2_FOCUS_ENERGY; retVal = FALSE; } if ((itemEffect[cmdIndex] & 0xF) && gBattleMons[gActiveBattler].statStages[STAT_STAGE_ATK] < 12) { gBattleMons[gActiveBattler].statStages[STAT_STAGE_ATK] += itemEffect[cmdIndex] & 0xF; if (gBattleMons[gActiveBattler].statStages[STAT_STAGE_ATK] > 12) gBattleMons[gActiveBattler].statStages[STAT_STAGE_ATK] = 12; retVal = FALSE; } break; // in-battle stat boosting effects? case 1: if ((itemEffect[cmdIndex] & 0xF0) && gBattleMons[gActiveBattler].statStages[STAT_STAGE_DEF] < 12) { gBattleMons[gActiveBattler].statStages[STAT_STAGE_DEF] += (itemEffect[cmdIndex] & 0xF0) >> 4; if (gBattleMons[gActiveBattler].statStages[STAT_STAGE_DEF] > 12) gBattleMons[gActiveBattler].statStages[STAT_STAGE_DEF] = 12; retVal = FALSE; } if ((itemEffect[cmdIndex] & 0xF) && gBattleMons[gActiveBattler].statStages[STAT_STAGE_SPEED] < 12) { gBattleMons[gActiveBattler].statStages[STAT_STAGE_SPEED] += itemEffect[cmdIndex] & 0xF; if (gBattleMons[gActiveBattler].statStages[STAT_STAGE_SPEED] > 12) gBattleMons[gActiveBattler].statStages[STAT_STAGE_SPEED] = 12; retVal = FALSE; } break; // more stat boosting effects? case 2: if ((itemEffect[cmdIndex] & 0xF0) && gBattleMons[gActiveBattler].statStages[STAT_STAGE_ACC] < 12) { gBattleMons[gActiveBattler].statStages[STAT_STAGE_ACC] += (itemEffect[cmdIndex] & 0xF0) >> 4; if (gBattleMons[gActiveBattler].statStages[STAT_STAGE_ACC] > 12) gBattleMons[gActiveBattler].statStages[STAT_STAGE_ACC] = 12; retVal = FALSE; } if ((itemEffect[cmdIndex] & 0xF) && gBattleMons[gActiveBattler].statStages[STAT_STAGE_SPATK] < 12) { gBattleMons[gActiveBattler].statStages[STAT_STAGE_SPATK] += itemEffect[cmdIndex] & 0xF; if (gBattleMons[gActiveBattler].statStages[STAT_STAGE_SPATK] > 12) gBattleMons[gActiveBattler].statStages[STAT_STAGE_SPATK] = 12; retVal = FALSE; } break; case 3: if ((itemEffect[cmdIndex] & 0x80) && gSideTimers[GetBattlerSide(gActiveBattler)].mistTimer == 0) { gSideTimers[GetBattlerSide(gActiveBattler)].mistTimer = 5; retVal = FALSE; } if ((itemEffect[cmdIndex] & 0x40) // raise level && GetMonData(mon, MON_DATA_LEVEL, NULL) != MAX_MON_LEVEL) { dataUnsigned = gExperienceTables[gBaseStats[GetMonData(mon, MON_DATA_SPECIES, NULL)].growthRate][GetMonData(mon, MON_DATA_LEVEL, NULL) + 1]; SetMonData(mon, MON_DATA_EXP, &dataUnsigned); CalculateMonStats(mon); retVal = FALSE; } if ((itemEffect[cmdIndex] & 0x20) && HealStatusConditions(mon, partyIndex, 7, battlerId) == 0) { if (battlerId != 4) gBattleMons[battlerId].status2 &= ~STATUS2_NIGHTMARE; retVal = FALSE; } if ((itemEffect[cmdIndex] & 0x10) && HealStatusConditions(mon, partyIndex, STATUS1_PSN_ANY | STATUS1_TOXIC_COUNTER, battlerId) == 0) retVal = FALSE; if ((itemEffect[cmdIndex] & 8) && HealStatusConditions(mon, partyIndex, STATUS1_BURN, battlerId) == 0) retVal = FALSE; if ((itemEffect[cmdIndex] & 4) && HealStatusConditions(mon, partyIndex, STATUS1_FREEZE, battlerId) == 0) retVal = FALSE; if ((itemEffect[cmdIndex] & 2) && HealStatusConditions(mon, partyIndex, STATUS1_PARALYSIS, battlerId) == 0) retVal = FALSE; if ((itemEffect[cmdIndex] & 1) // heal confusion && gMain.inBattle && battlerId != 4 && (gBattleMons[battlerId].status2 & STATUS2_CONFUSION)) { gBattleMons[battlerId].status2 &= ~STATUS2_CONFUSION; retVal = FALSE; } break; // EV, HP, and PP raising effects case 4: r10 = itemEffect[cmdIndex]; if (r10 & 0x20) { r10 &= ~0x20; dataUnsigned = (GetMonData(mon, MON_DATA_PP_BONUSES, NULL) & gUnknown_08329D22[moveIndex]) >> (moveIndex * 2); var_38 = CalculatePPWithBonus(GetMonData(mon, MON_DATA_MOVE1 + moveIndex, NULL), GetMonData(mon, MON_DATA_PP_BONUSES, NULL), moveIndex); if (dataUnsigned <= 2 && var_38 > 4) { dataUnsigned = GetMonData(mon, MON_DATA_PP_BONUSES, NULL) + gUnknown_08329D2A[moveIndex]; SetMonData(mon, MON_DATA_PP_BONUSES, &dataUnsigned); dataUnsigned = CalculatePPWithBonus(GetMonData(mon, MON_DATA_MOVE1 + moveIndex, NULL), dataUnsigned, moveIndex) - var_38; dataUnsigned = GetMonData(mon, MON_DATA_PP1 + moveIndex, NULL) + dataUnsigned; SetMonData(mon, MON_DATA_PP1 + moveIndex, &dataUnsigned); retVal = FALSE; } } var_38 = 0; while (r10 != 0) { if (r10 & 1) { switch (var_38) { case 0: case 1: evCount = GetMonEVCount(mon); r5 = itemEffect[var_3C]; dataSigned = GetMonData(mon, gUnknown_08329EC2[var_38], NULL); r2 = r5; if (r2 > 0) { if (evCount >= MAX_TOTAL_EVS) return TRUE; if (dataSigned >= 100) break; if (dataSigned + r2 > 100) r5 = 100 - (dataSigned + r2) + r2; else r5 = r2; if (evCount + r5 > MAX_TOTAL_EVS) r5 += MAX_TOTAL_EVS - (evCount + r5); dataSigned += r5; } else { if (dataSigned == 0) { var_28 = 1; var_3C++; break; } dataSigned += r2; if (dataSigned < 0) dataSigned = 0; } SetMonData(mon, gUnknown_08329EC2[var_38], &dataSigned); CalculateMonStats(mon); var_3C++; retVal = FALSE; break; case 2: // revive? if (r10 & 0x10) { if (GetMonData(mon, MON_DATA_HP, NULL) != 0) { var_3C++; break; } if (gMain.inBattle) { if (battlerId != 4) { gAbsentBattlerFlags &= ~gBitTable[battlerId]; CopyPlayerPartyMonToBattleData(battlerId, pokemon_order_func(gBattlerPartyIndexes[battlerId])); if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER && gBattleResults.unk4 < 255) gBattleResults.unk4++; } else { gAbsentBattlerFlags &= ~gBitTable[gActiveBattler ^ 2]; if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER && gBattleResults.unk4 < 255) gBattleResults.unk4++; } } } else { if (GetMonData(mon, MON_DATA_HP, NULL) == 0) { var_3C++; break; } } dataUnsigned = itemEffect[var_3C++]; switch (dataUnsigned) { case 0xFF: dataUnsigned = GetMonData(mon, MON_DATA_MAX_HP, NULL) - GetMonData(mon, MON_DATA_HP, NULL); break; case 0xFE: dataUnsigned = GetMonData(mon, MON_DATA_MAX_HP, NULL) / 2; if (dataUnsigned == 0) dataUnsigned = 1; break; case 0xFD: dataUnsigned = gBattleScripting.field_23; break; } if (GetMonData(mon, MON_DATA_MAX_HP, NULL) != GetMonData(mon, MON_DATA_HP, NULL)) { if (e == 0) { dataUnsigned = GetMonData(mon, MON_DATA_HP, NULL) + dataUnsigned; if (dataUnsigned > GetMonData(mon, MON_DATA_MAX_HP, NULL)) dataUnsigned = GetMonData(mon, MON_DATA_MAX_HP, NULL); SetMonData(mon, MON_DATA_HP, &dataUnsigned); if (gMain.inBattle && battlerId != 4) { gBattleMons[battlerId].hp = dataUnsigned; if (!(r10 & 0x10) && GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER) { if (gBattleResults.unk3 < 255) gBattleResults.unk3++; // I have to re-use this variable to match. r5 = gActiveBattler; gActiveBattler = battlerId; BtlController_EmitGetMonData(0, 0, 0); MarkBattlerForControllerExec(gActiveBattler); gActiveBattler = r5; } } } else { gBattleMoveDamage = -dataUnsigned; } retVal = FALSE; } r10 &= 0xEF; break; case 3: if (!(r10 & 2)) { for (r5 = 0; (signed)(r5) < (signed)(4); r5++) { u16 moveId; dataUnsigned = GetMonData(mon, MON_DATA_PP1 + r5, NULL); moveId = GetMonData(mon, MON_DATA_MOVE1 + r5, NULL); if (dataUnsigned != CalculatePPWithBonus(moveId, GetMonData(mon, MON_DATA_PP_BONUSES, NULL), r5)) { dataUnsigned += itemEffect[var_3C]; moveId = GetMonData(mon, MON_DATA_MOVE1 + r5, NULL); if (dataUnsigned > CalculatePPWithBonus(moveId, GetMonData(mon, MON_DATA_PP_BONUSES, NULL), r5)) { moveId = GetMonData(mon, MON_DATA_MOVE1 + r5, NULL); dataUnsigned = CalculatePPWithBonus(moveId, GetMonData(mon, MON_DATA_PP_BONUSES, NULL), r5); } SetMonData(mon, MON_DATA_PP1 + r5, &dataUnsigned); if (gMain.inBattle && battlerId != 4 && !(gBattleMons[battlerId].status2 & STATUS2_TRANSFORMED) && !(gDisableStructs[battlerId].unk18_b & gBitTable[r5])) gBattleMons[battlerId].pp[r5] = dataUnsigned; retVal = FALSE; } } var_3C++; } else { u16 moveId; dataUnsigned = GetMonData(mon, MON_DATA_PP1 + moveIndex, NULL); moveId = GetMonData(mon, MON_DATA_MOVE1 + moveIndex, NULL); if (dataUnsigned != CalculatePPWithBonus(moveId, GetMonData(mon, MON_DATA_PP_BONUSES, NULL), moveIndex)) { dataUnsigned += itemEffect[var_3C++]; moveId = GetMonData(mon, MON_DATA_MOVE1 + moveIndex, NULL); if (dataUnsigned > CalculatePPWithBonus(moveId, GetMonData(mon, MON_DATA_PP_BONUSES, NULL), moveIndex)) { moveId = GetMonData(mon, MON_DATA_MOVE1 + moveIndex, NULL); dataUnsigned = CalculatePPWithBonus(moveId, GetMonData(mon, MON_DATA_PP_BONUSES, NULL), moveIndex); } SetMonData(mon, MON_DATA_PP1 + moveIndex, &dataUnsigned); if (gMain.inBattle && battlerId != 4 && !(gBattleMons[battlerId].status2 & STATUS2_TRANSFORMED) && !(gDisableStructs[battlerId].unk18_b & gBitTable[moveIndex])) gBattleMons[battlerId].pp[moveIndex] = dataUnsigned; retVal = FALSE; } } break; case 7: { u16 targetSpecies = GetEvolutionTargetSpecies(mon, 2, item); if (targetSpecies != SPECIES_NONE) { BeginEvolutionScene(mon, targetSpecies, 0, partyIndex); return FALSE; } } break; } } var_38++; r10 >>= 1; } break; case 5: r10 = itemEffect[cmdIndex]; var_38 = 0; while (r10 != 0) { if (r10 & 1) { switch (var_38) { case 0: case 1: case 2: case 3: evCount = GetMonEVCount(mon); r5 = itemEffect[var_3C]; dataSigned = GetMonData(mon, gUnknown_08329EC2[var_38 + 2], NULL); r2 = r5; if (r2 > 0) { if (evCount >= MAX_TOTAL_EVS) return TRUE; if (dataSigned >= 100) break; if (dataSigned + r2 > 100) r5 = 100 - (dataSigned + r2) + r2; else r5 = r2; if (evCount + r5 > MAX_TOTAL_EVS) r5 += MAX_TOTAL_EVS - (evCount + r5); dataSigned += r5; } else { if (dataSigned == 0) { var_28 = 1; var_3C++; break; } dataSigned += r2; if (dataSigned < 0) dataSigned = 0; } SetMonData(mon, gUnknown_08329EC2[var_38 + 2], &dataSigned); CalculateMonStats(mon); retVal = FALSE; var_3C++; break; case 4: dataUnsigned = (GetMonData(mon, MON_DATA_PP_BONUSES, NULL) & gUnknown_08329D22[moveIndex]) >> (moveIndex * 2); r5 = CalculatePPWithBonus(GetMonData(mon, MON_DATA_MOVE1 + moveIndex, NULL), GetMonData(mon, MON_DATA_PP_BONUSES, NULL), moveIndex); if (dataUnsigned < 3 && r5 > 4) { dataUnsigned = GetMonData(mon, MON_DATA_PP_BONUSES, NULL); dataUnsigned &= gUnknown_08329D26[moveIndex]; dataUnsigned += gUnknown_08329D2A[moveIndex] * 3; SetMonData(mon, MON_DATA_PP_BONUSES, &dataUnsigned); dataUnsigned = CalculatePPWithBonus(GetMonData(mon, MON_DATA_MOVE1 + moveIndex, NULL), dataUnsigned, moveIndex) - r5; dataUnsigned = GetMonData(mon, MON_DATA_PP1 + moveIndex, NULL) + dataUnsigned; SetMonData(mon, MON_DATA_PP1 + moveIndex, &dataUnsigned); retVal = FALSE; } break; case 5: if (GetMonData(mon, MON_DATA_FRIENDSHIP, NULL) < 100 && (retVal == 0 || var_28 != 0) && !sub_806F104() && var_34 == 0) { var_34 = itemEffect[var_3C]; friendship = GetMonData(mon, MON_DATA_FRIENDSHIP, NULL); if (var_34 > 0 && holdEffect == HOLD_EFFECT_HAPPINESS_UP) friendship += 150 * var_34 / 100; else friendship += var_34; if (var_34 > 0) { if (GetMonData(mon, MON_DATA_POKEBALL, NULL) == 11) friendship++; if (GetMonData(mon, MON_DATA_MET_LOCATION, NULL) == sav1_map_get_name()) friendship++; } if (friendship < 0) friendship = 0; if (friendship > 255) friendship = 255; SetMonData(mon, MON_DATA_FRIENDSHIP, &friendship); retVal = FALSE; } var_3C++; break; case 6: if (GetMonData(mon, MON_DATA_FRIENDSHIP, NULL) >= 100 && GetMonData(mon, MON_DATA_FRIENDSHIP, NULL) < 200 && (retVal == 0 || var_28 != 0) && !sub_806F104() && var_34 == 0) { var_34 = itemEffect[var_3C]; friendship = GetMonData(mon, MON_DATA_FRIENDSHIP, NULL); if ((s8)(var_34) > 0 && holdEffect == HOLD_EFFECT_HAPPINESS_UP) friendship += 150 * var_34 / 100; else friendship += var_34; if (var_34 > 0) { if (GetMonData(mon, MON_DATA_POKEBALL, NULL) == 11) friendship++; if (GetMonData(mon, MON_DATA_MET_LOCATION, NULL) == sav1_map_get_name()) friendship++; } if (friendship < 0) friendship = 0; if (friendship > 255) friendship = 255; SetMonData(mon, MON_DATA_FRIENDSHIP, &friendship); retVal = FALSE; } var_3C++; break; case 7: if (GetMonData(mon, MON_DATA_FRIENDSHIP, NULL) >= 200 && (retVal == 0 || var_28 != 0) && !sub_806F104() && var_34 == 0) { var_34 = itemEffect[var_3C]; friendship = GetMonData(mon, MON_DATA_FRIENDSHIP, NULL); if ((s8)(var_34) > 0 && holdEffect == HOLD_EFFECT_HAPPINESS_UP) friendship += 150 * var_34 / 100; else friendship += var_34; if (var_34 > 0) { if (GetMonData(mon, MON_DATA_POKEBALL, NULL) == 11) friendship++; if (GetMonData(mon, MON_DATA_MET_LOCATION, NULL) == sav1_map_get_name()) friendship++; } if (friendship < 0) friendship = 0; if (friendship > 255) friendship = 255; SetMonData(mon, MON_DATA_FRIENDSHIP, &friendship); retVal = FALSE; } var_3C++; break; } } var_38++; r10 >>= 1; } break; } } return retVal; }