diff options
author | Seth Barberee <seth.barberee@gmail.com> | 2022-03-11 10:10:49 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-11 10:10:49 -0800 |
commit | 30fea2d6f303e0e57b62032f56da86c8223ef1f7 (patch) | |
tree | 9636ef46bb5f555874dc8ba16c82dc79bc563a12 /src | |
parent | ea1aa9c0c5c3a4167912d1078fffdd5e69cbbe98 (diff) | |
parent | cf492fd141b33c21f369dfa7aabebf3c52cb8ec1 (diff) |
Merge pull request #98 from AnonymousRandomPerson/master
Finished attack AI decomp
Diffstat (limited to 'src')
-rw-r--r-- | src/code_800D090.c | 3 | ||||
-rw-r--r-- | src/code_801D760.c | 16 | ||||
-rw-r--r-- | src/code_8090208.c | 10 | ||||
-rw-r--r-- | src/dungeon_action.c | 7 | ||||
-rw-r--r-- | src/dungeon_ai_attack.c | 417 | ||||
-rw-r--r-- | src/dungeon_ai_attack_1.c | 175 | ||||
-rw-r--r-- | src/dungeon_ai_attack_2.c | 76 | ||||
-rw-r--r-- | src/dungeon_ai_items.c | 3 | ||||
-rw-r--r-- | src/dungeon_ai_movement.c | 3 | ||||
-rw-r--r-- | src/dungeon_pokemon_attributes.c | 6 | ||||
-rw-r--r-- | src/friend_area.c | 6 | ||||
-rw-r--r-- | src/friend_list_menu.c | 4 | ||||
-rw-r--r-- | src/items.c | 20 | ||||
-rw-r--r-- | src/kecleon_items_1.c | 14 | ||||
-rw-r--r-- | src/load_screen.c | 34 | ||||
-rw-r--r-- | src/move_util.c | 88 | ||||
-rw-r--r-- | src/moves.c | 28 | ||||
-rw-r--r-- | src/moves_1.c | 4 | ||||
-rw-r--r-- | src/pokemon_mid.c | 16 | ||||
-rw-r--r-- | src/status.c | 19 | ||||
-rw-r--r-- | src/status_checker.c | 447 | ||||
-rw-r--r-- | src/status_checks_1.c | 2 | ||||
-rw-r--r-- | src/thank_you_wonder_mail.c | 6 | ||||
-rw-r--r-- | src/type_chart.c | 27 | ||||
-rw-r--r-- | src/type_effectiveness.c | 174 | ||||
-rw-r--r-- | src/wonder_mail_2.c | 4 |
26 files changed, 1240 insertions, 369 deletions
diff --git a/src/code_800D090.c b/src/code_800D090.c index fd1c948..1744087 100644 --- a/src/code_800D090.c +++ b/src/code_800D090.c @@ -4,7 +4,6 @@ #include "config.h" #include "global.h" - extern void SoundBiasReset(void); extern void SoundBiasSet(void); @@ -70,7 +69,7 @@ void sub_800D098(void) while(REG_KEYINPUT != KEYS_MASK){} // All buttons } -void ExpandPlaceholdersBuffer(u8 *buffer, const char *text, ...) +void sprintf_2(char *buffer, const char *text, ...) { va_list vArgv; va_start(vArgv, text); diff --git a/src/code_801D760.c b/src/code_801D760.c index bdab0f2..a84aba5 100644 --- a/src/code_801D760.c +++ b/src/code_801D760.c @@ -8,6 +8,7 @@ #include "input.h" #include "text.h" #include "rescue_team_info.h" +#include "code_800D090.h" struct unkStruct_203B258 { @@ -64,15 +65,14 @@ extern void sub_8008C54(u32); extern void sub_80073B8(u32); extern void sub_80073E0(u32); void LoadTeamRankBadge(u32, u32, u32); -extern void ExpandPlaceholdersBuffer(u8 *, u32 *, ...); extern void SetBGPaletteBufferColorArray(s32 index, u8 *colorArray); extern void sub_8007E20(u32, u32, u32, u32, u32, u8 *, u32); extern struct FileArchive gTitleMenuFileArchive; extern const char gTeamRankBadgeFileName; -extern u32 gUnknown_80DBF3C; -extern u32 gUnknown_80DBF4C; +extern char gUnknown_80DBF3C[]; +extern char gUnknown_80DBF4C[]; struct TeamBadgeData { @@ -305,8 +305,8 @@ void sub_801D894(void) // Stored on stack u32 *preload_string; - u32 *r5; // R5 - u8 buffer [96]; // sp +4 + char *r5; // R5 + char buffer [96]; // sp +4 if (gUnknown_203B250->currFriendAreaLocation == NONE) { location = sub_8098FB4(); @@ -327,11 +327,11 @@ void sub_801D894(void) LoadTeamRankBadge(2, 8, 6); // Have to load before TeamRank funcs - r5 = &gUnknown_80DBF3C; // %s {COLOR_1 CYAN}%d{END_COLOR_TEXT_1} Pts. + r5 = gUnknown_80DBF3C; // %s {COLOR_1 CYAN}%d{END_COLOR_TEXT_1} Pts. rank = GetRescueTeamRank(); - ExpandPlaceholdersBuffer(buffer, r5, GetTeamRankString(rank), GetTeamRankPts()); + sprintf_2(buffer, r5, GetTeamRankString(rank), GetTeamRankPts()); xxx_call_draw_string(32, 4, buffer, 2, 0); - ExpandPlaceholdersBuffer(buffer, &gUnknown_80DBF4C, gTeamInventory_203B460->teamMoney); + sprintf_2(buffer, gUnknown_80DBF4C, gTeamInventory_203B460->teamMoney); xxx_call_draw_string(32, 18, buffer, 2, 0); sub_80073E0(2); } diff --git a/src/code_8090208.c b/src/code_8090208.c index 970154c..8322ffc 100644 --- a/src/code_8090208.c +++ b/src/code_8090208.c @@ -1,13 +1,11 @@ #include "global.h" #include "dungeon.h" +#include "code_800D090.h" extern const char gUnknown_8108F10[]; extern const char gUnknown_8108F18[]; extern const char gUnknown_8108F2C[]; -void ExpandPlaceholdersBuffer(u8 *buffer, const char *text, ...); - - struct unkDungeonStruct { u8 index; @@ -16,17 +14,17 @@ struct unkDungeonStruct void sub_8090208(u8 *buffer, struct unkDungeonStruct *dungeonLocation) { - ExpandPlaceholdersBuffer(buffer, gUnknown_8108F10, gDungeonNames[dungeonLocation->index].name1); // {COLOR_2 YELLOW_4}%s{END_COLOR_TEXT_2} (normal floor print (no B) + sprintf_2(buffer, gUnknown_8108F10, gDungeonNames[dungeonLocation->index].name1); // {COLOR_2 YELLOW_4}%s{END_COLOR_TEXT_2} (normal floor print (no B) } void PrintDungeonLocationtoBuffer(u8 *buffer, struct unkDungeonStruct *dungeonLocation) { if(gDungeons[dungeonLocation->index].stairDirection != 0){ - ExpandPlaceholdersBuffer(buffer, gUnknown_8108F18, gDungeonNames[dungeonLocation->index].name1, dungeonLocation->floor); //_F + sprintf_2(buffer, gUnknown_8108F18, gDungeonNames[dungeonLocation->index].name1, dungeonLocation->floor); //_F } else { - ExpandPlaceholdersBuffer(buffer, gUnknown_8108F2C, gDungeonNames[dungeonLocation->index].name1, dungeonLocation->floor); // B _F + sprintf_2(buffer, gUnknown_8108F2C, gDungeonNames[dungeonLocation->index].name1, dungeonLocation->floor); // B _F } } diff --git a/src/dungeon_action.c b/src/dungeon_action.c index 9034e4c..912e8b4 100644 --- a/src/dungeon_action.c +++ b/src/dungeon_action.c @@ -5,6 +5,13 @@ #include "dungeon_entity.h" #include "pokemon.h" +void ResetAction(struct DungeonActionContainer *actionPointer) +{ + actionPointer->action = DUNGEON_ACTION_NONE; + actionPointer->actionUseIndex = 0; + actionPointer->unkC = 0; +} + void SetAction(struct DungeonActionContainer *actionPointer, u16 action) { actionPointer->action = action; diff --git a/src/dungeon_ai_attack.c b/src/dungeon_ai_attack.c index 835d207..c84aca1 100644 --- a/src/dungeon_ai_attack.c +++ b/src/dungeon_ai_attack.c @@ -7,13 +7,13 @@ #include "constants/move_id.h" #include "constants/status.h" #include "constants/tactic.h" +#include "constants/targeting.h" #include "constants/type.h" #include "charge_move.h" #include "dungeon_action.h" #include "dungeon_ai_targeting.h" #include "dungeon_ai_targeting_1.h" -#include "dungeon_ai_attack_1.h" -#include "dungeon_ai_attack_2.h" +#include "dungeon_ai_targeting_2.h" #include "dungeon_capabilities_1.h" #include "dungeon_global_data.h" #include "dungeon_map_access.h" @@ -22,12 +22,15 @@ #include "dungeon_random_1.h" #include "dungeon_util.h" #include "dungeon_visibility.h" +#include "move_util.h" #include "moves.h" #include "position_util.h" #include "status_checker.h" #include "status_checks.h" +#include "status_checks_1.h" #include "targeting.h" #include "targeting_flags.h" +#include "type_effectiveness.h" #define REGULAR_ATTACK_INDEX 4 @@ -39,11 +42,6 @@ extern s32 gPotentialAttackTargetWeights[NUM_DIRECTIONS]; extern u8 gPotentialAttackTargetDirections[NUM_DIRECTIONS]; extern struct DungeonEntity *gPotentialTargets[NUM_DIRECTIONS]; -extern bool8 IsMoveUsable_1(struct DungeonEntity*, s32, bool8); -extern bool8 TargetRegularAttack(struct DungeonEntity*, u32*, bool8); -extern bool8 IsTargetInLineRange(struct DungeonEntity*, struct DungeonEntity*, s32); -extern s32 WeightMove(struct DungeonEntity*, s32, struct DungeonEntity*, u8); - void DecideAttack(struct DungeonEntity *pokemon) { struct DungeonEntityData *pokemonData = pokemon->entityData; @@ -181,7 +179,7 @@ void DecideAttack(struct DungeonEntity *pokemon) move = &pokemonData->moves[i]; if (move->moveFlags & MOVE_FLAG_EXISTS && willNotUnlinkMove[i] && - IsMoveUsable_1(pokemon, i, hasPPChecker) && + IsMoveIndexUsable(pokemon, i, hasPPChecker) && move->moveFlags & MOVE_FLAG_ENABLED) { moveTargetResults[i].moveUsable = TRUE; @@ -522,4 +520,405 @@ s32 FindMoveTarget(struct MoveTargetResults *moveTargetResults, struct DungeonEn moveTargetResults->moveWeight = 8; } return moveWeight; -}
\ No newline at end of file +} + +bool8 IsTargetInLineRange(struct DungeonEntity *user, struct DungeonEntity *target, s32 range) +{ + s32 posDiffX = user->posWorld.x - target->posWorld.x; + s32 posDiffY, maxPosDiff; + s32 direction; + if (posDiffX < 0) + { + posDiffX = -posDiffX; + } + posDiffY = user->posWorld.y - target->posWorld.y; + if (posDiffY < 0) + { + posDiffY = -posDiffY; + } + maxPosDiff = posDiffY; + if (posDiffY < posDiffX) + { + maxPosDiff = posDiffX; + } + if (maxPosDiff > RANGED_ATTACK_RANGE || maxPosDiff > range) + { + return FALSE; + } + direction = -1; + if (posDiffX == posDiffY) + { + if (user->posWorld.x < target->posWorld.x && + (user->posWorld.y < target->posWorld.y || user->posWorld.y > target->posWorld.y)) + { + returnTrue: + return TRUE; + } + if (user->posWorld.x > target->posWorld.x); // Fixes register loading order. + direction = DIRECTION_SOUTHWEST; + if (user->posWorld.x <= target->posWorld.x || user->posWorld.y <= target->posWorld.y) + { + goto checkDirectionSet; + } + goto returnTrue; + } + else if (user->posWorld.x == target->posWorld.x && user->posWorld.y < target->posWorld.y) + { + return TRUE; + } + else if (user->posWorld.x < target->posWorld.x && user->posWorld.y == target->posWorld.y) + { + return TRUE; + } + else if (user->posWorld.x == target->posWorld.x && user->posWorld.y > target->posWorld.y) + { + return TRUE; + } + else if (user->posWorld.x > target->posWorld.x && user->posWorld.y == target->posWorld.y) + { + direction = DIRECTION_WEST; + } + checkDirectionSet: + if (direction < 0) + { + return FALSE; + } + return TRUE; +} + +s32 WeightMoveIfUsable(s32 numPotentialTargets, s32 targetingFlags, struct DungeonEntity *user, struct DungeonEntity *target, struct PokemonMove *move, bool32 hasStatusChecker) +{ + s32 facingDir; + s32 targetingFlags2 = (s16) targetingFlags; + bool8 hasStatusChecker2 = hasStatusChecker; + struct DungeonEntityData *userData = user->entityData; + if ((user->posWorld.x == target->posWorld.x && user->posWorld.y == target->posWorld.y) || + (targetingFlags2 & 0xF0) == TARGETING_FLAG_TARGET_ROOM || + (targetingFlags2 & 0xF0) == TARGETING_FLAG_TARGET_FLOOR || + (targetingFlags2 & 0xF0) == TARGETING_FLAG_TARGET_SELF) + { + facingDir = userData->action.facingDir; + } + else + { + facingDir = CalculateFacingDir(&user->posWorld, &target->posWorld); + } + if (!gCanAttackInDirection[facingDir] && + CanUseStatusMove(targetingFlags2, user, target, move, hasStatusChecker2)) + { + gCanAttackInDirection[facingDir] = TRUE; + do { gPotentialAttackTargetDirections[numPotentialTargets] = facingDir; } while (0); + gPotentialAttackTargetWeights[numPotentialTargets] = WeightMove(user, targetingFlags2, target, GetMoveTypeForPokemon(user, move)); + gPotentialTargets[numPotentialTargets] = target; + numPotentialTargets++; + } + return numPotentialTargets; +} + +bool8 CanUseStatusMove(s32 targetingFlags, struct DungeonEntity *user, struct DungeonEntity *target, struct PokemonMove *move, bool32 hasStatusChecker) +{ + struct DungeonEntityData *targetData; + s32 targetingFlags2 = (s16) targetingFlags; + bool8 hasStatusChecker2 = hasStatusChecker; + bool8 hasTarget = FALSE; + u32 categoryTargetingFlags = targetingFlags2 & 0xF; + u32 *categoryTargetingFlags2 = &categoryTargetingFlags; // Fixes a regswap. + if (*categoryTargetingFlags2 == TARGETING_FLAG_TARGET_OTHER) + { + if (CanTarget(user, target, FALSE, TRUE) == TARGET_CAPABILITY_CAN_TARGET) + { + hasTarget = TRUE; + } + } + else if (categoryTargetingFlags == TARGETING_FLAG_HEAL_TEAM) + { + goto checkCanTarget; + } + else if (categoryTargetingFlags == TARGETING_FLAG_LONG_RANGE) + { + targetData = target->entityData; + goto checkThirdParty; + } + else if (categoryTargetingFlags == TARGETING_FLAG_ATTACK_ALL) + { + targetData = target->entityData; + if (user == target) + { + goto returnFalse; + } + checkThirdParty: + hasTarget = TRUE; + if (targetData->shopkeeperMode == SHOPKEEPER_FRIENDLY || + targetData->clientType == CLIENT_TYPE_DONT_MOVE || + targetData->clientType == CLIENT_TYPE_CLIENT) + { + returnFalse: + return FALSE; + } + } + else if (categoryTargetingFlags == TARGETING_FLAG_BOOST_TEAM) + { + if (user == target) + { + goto returnFalse; + } + checkCanTarget: + if (CanTarget(user, target, FALSE, TRUE) == TARGET_CAPABILITY_CANNOT_ATTACK) + { + hasTarget = TRUE; + } + } + else if ((u16) (categoryTargetingFlags - 3) <= 1) // categoryTargetingFlags == TARGETING_FLAG_ITEM + { + hasTarget = TRUE; + } + + if (hasTarget) + { + if (hasStatusChecker2) + { + if (!CanUseOnTargetWithStatusChecker(user, target, move)) + { + goto returnFalse; + } + if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_SET_TRAP) + { + goto rollMoveUseChance; + } + else if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_HEAL_HP) + { + if (!HasQuarterHPOrLess(target)) + { + if (*categoryTargetingFlags2); + goto returnFalse; + } + } + else if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_HEAL_STATUS) + { + if (!HasNegativeStatus(target)) + { + if (*categoryTargetingFlags2); // Flips the conditional. + goto returnFalse; + } + } + else if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_DREAM_EATER) + { + if (!IsSleeping(target)) + { + if (*categoryTargetingFlags2); // Flips the conditional. + goto returnFalse; + } + } + else if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_EXPOSE) + { + targetData = target->entityData; + if ((targetData->types[0] != TYPE_GHOST && targetData->types[1] != TYPE_GHOST) || targetData->exposedStatus) + { + if (*categoryTargetingFlags2); // Flips the conditional. + goto returnFalse; + } + } + else if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_HEAL_ALL) + { + if (!HasNegativeStatus(target) && !HasQuarterHPOrLess(target)) + { + if (*categoryTargetingFlags2); // Flips the conditional. + goto returnFalse; + } + } + } + else if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_SET_TRAP) + { + s32 useChance; + rollMoveUseChance: + useChance = GetMoveAccuracy(move, ACCURACY_TYPE_USE_CHANCE); + if (DungeonRandomCapped(100) >= useChance) + { + goto returnFalse; + } + } + } + return hasTarget; +} + +s32 WeightMove(struct DungeonEntity *user, s32 targetingFlags, struct DungeonEntity *target, u32 moveType) +{ +#ifndef NONMATCHING + register struct DungeonEntityData *targetData asm("r4"); +#else + struct DungeonEntityData *targetData; +#endif + s32 targetingFlags2 = (s16) targetingFlags; + u8 moveType2 = moveType; + u8 weight = 1; + struct DungeonEntityData *targetData2; + targetData2 = targetData = target->entityData; + if (!targetData->isEnemy || (targetingFlags2 & 0xF) != TARGETING_FLAG_TARGET_OTHER) + { + return 1; + } + else if (HasIQSkill(user, IQ_SKILL_EXP_GO_GETTER)) + { + // BUG: expYieldRankings has lower values as the Pokémon's experience yield increases. + // This causes Exp. Go-Getter to prioritize Pokémon worth less experience + // instead of Pokémon worth more experience. + weight = gDungeonGlobalData->expYieldRankings[targetData->entityID]; + } + else if (HasIQSkill(user, IQ_SKILL_EFFICIENCY_EXPERT)) + { + weight = -12 - targetData2->HP; + if (weight == 0) + { + weight = 1; + } + } + else if (HasIQSkill(user, IQ_SKILL_WEAK_TYPE_PICKER)) + { + weight = WeightWeakTypePicker(user, target, moveType2) + 1; + } + return weight; +} + +bool8 TargetRegularAttack(struct DungeonEntity *pokemon, u32 *targetDir, bool8 checkPetrified) +{ + struct DungeonEntityData *pokemonData = pokemon->entityData; + s32 numPotentialTargets = 0; + s32 facingDir = pokemonData->action.facingDir; + s32 faceTurnLimit = pokemonData->eyesightStatus == EYESIGHT_STATUS_BLINKER ? 1 : 8; + s32 i; + s32 potentialAttackTargetDirections[NUM_DIRECTIONS]; + s32 potentialAttackTargetWeights[NUM_DIRECTIONS]; + bool8 hasTargetingIQ = HasIQSkill(pokemon, IQ_SKILL_EXP_GO_GETTER) || HasIQSkill(pokemon, IQ_SKILL_EFFICIENCY_EXPERT); + bool8 hasStatusChecker = HasIQSkill(pokemon, IQ_SKILL_STATUS_CHECKER); + for (i = 0; i < faceTurnLimit; i++, facingDir++) + { + struct DungeonEntity *target; + facingDir &= DIRECTION_MASK; + target = GetMapTile_1(pokemon->posWorld.x + gAdjacentTileOffsets[facingDir].x, + pokemon->posWorld.y + gAdjacentTileOffsets[facingDir].y)->pokemon; + if (target != NULL && + GetEntityType(target) == ENTITY_POKEMON && + CanAttackInFront(pokemon, facingDir) && + CanTarget(pokemon, target, FALSE, checkPetrified) == TARGET_CAPABILITY_CAN_TARGET && + (!hasStatusChecker || target->entityData->immobilizeStatus != IMMOBILIZE_STATUS_FROZEN)) + { + potentialAttackTargetDirections[numPotentialTargets] = facingDir; + potentialAttackTargetWeights[numPotentialTargets] = WeightMove(pokemon, TARGETING_FLAG_TARGET_OTHER, target, TYPE_NONE); + if (!hasTargetingIQ) + { + *targetDir = facingDir; + return TRUE; + } + numPotentialTargets++; + } + } + if (numPotentialTargets == 0) + { + return FALSE; + } + else + { + s32 totalWeight = 0; + s32 maxWeight = 0; + s32 weightCounter; + s32 i; + for (i = 0; i < numPotentialTargets; i++) + { + if (maxWeight < potentialAttackTargetWeights[i]) + { + maxWeight = potentialAttackTargetWeights[i]; + } + } + for (i = 0; i < numPotentialTargets; i++) + { + if (maxWeight != potentialAttackTargetWeights[i]) + { + potentialAttackTargetWeights[i] = 0; + } + } + for (i = 0; i < numPotentialTargets; i++) + { + totalWeight += potentialAttackTargetWeights[i]; + } + weightCounter = DungeonRandomCapped(totalWeight); + for (i = 0; i < numPotentialTargets; i++) + { + weightCounter -= potentialAttackTargetWeights[i]; + if (weightCounter < 0) + { + break; + } + } + *targetDir = potentialAttackTargetDirections[i]; + return TRUE; + } + +} + +bool8 IsTargetStraightAhead(struct DungeonEntity *pokemon, struct DungeonEntity *targetPokemon, s32 facingDir, s32 maxRange) +{ + s32 posDiffX = pokemon->posWorld.x - targetPokemon->posWorld.x; + s32 effectiveMaxRange; + if (posDiffX < 0) + { + posDiffX = -posDiffX; + } + effectiveMaxRange = pokemon->posWorld.y - targetPokemon->posWorld.y; + if (effectiveMaxRange < 0) + { + effectiveMaxRange = -effectiveMaxRange; + } + if (effectiveMaxRange < posDiffX) + { + effectiveMaxRange = posDiffX; + } + if (effectiveMaxRange > maxRange) + { + effectiveMaxRange = maxRange; + } + if (!HasIQSkill(pokemon, IQ_SKILL_COURSE_CHECKER)) + { + // BUG: effectiveMaxRange is already capped at maxRange, so this condition always evaluates to TRUE. + // The AI also has range checks elsewhere, so this doesn't become an issue in most cases. + // If the AI has the Long Toss or Pierce statuses and Course Checker is disabled, + // this incorrect check causes the AI to throw items at targets further than 10 tiles away. + if (effectiveMaxRange <= maxRange) + { + return TRUE; + } + } + else + { + s32 currentPosX = pokemon->posWorld.x; + s32 currentPosY = pokemon->posWorld.y; + s32 adjacentTileOffsetX = gAdjacentTileOffsets[facingDir].x; + s32 adjacentTileOffsetY = gAdjacentTileOffsets[facingDir].y; + s32 i; + for (i = 0; i <= effectiveMaxRange; i++) + { + struct MapTile *mapTile; + currentPosX += adjacentTileOffsetX; + currentPosY += adjacentTileOffsetY; + if (currentPosX <= 0 || currentPosY <= 0 || + currentPosX >= DUNGEON_MAX_SIZE_X - 1 || currentPosY >= DUNGEON_MAX_SIZE_Y - 1) + { + break; + } + while (0); // Extra label needed to swap branch locations in ASM. + mapTile = GetMapTile_1(currentPosX, currentPosY); + if (!(mapTile->tileType & (TILE_TYPE_FLOOR | TILE_TYPE_LIQUID))) + { + break; + } + if (mapTile->pokemon == targetPokemon) + { + return TRUE; + } + if (mapTile->pokemon != NULL) + { + break; + } + } + } + return FALSE; +} diff --git a/src/dungeon_ai_attack_1.c b/src/dungeon_ai_attack_1.c deleted file mode 100644 index 023df14..0000000 --- a/src/dungeon_ai_attack_1.c +++ /dev/null @@ -1,175 +0,0 @@ -#include "global.h" -#include "dungeon_ai_attack_1.h" - -#include "constants/direction.h" -#include "constants/targeting.h" -#include "constants/type.h" -#include "dungeon_ai_targeting_2.h" -#include "dungeon_pokemon_attributes.h" -#include "dungeon_random.h" -#include "moves.h" -#include "position_util.h" -#include "status_checks_1.h" - -extern bool8 gCanAttackInDirection[NUM_DIRECTIONS]; -extern s32 gPotentialAttackTargetWeights[NUM_DIRECTIONS]; -extern u8 gPotentialAttackTargetDirections[NUM_DIRECTIONS]; -extern struct DungeonEntity *gPotentialTargets[NUM_DIRECTIONS]; - -extern s32 WeightMove(struct DungeonEntity*, s32, struct DungeonEntity*, u8); -extern bool8 CanUseOnTargetWithStatusChecker(struct DungeonEntity*, struct DungeonEntity*, struct PokemonMove*); - -s32 WeightMoveIfUsable(s32 numPotentialTargets, s32 targetingFlags, struct DungeonEntity *user, struct DungeonEntity *target, struct PokemonMove *move, bool32 hasStatusChecker) -{ - s32 facingDir; - s32 targetingFlags2 = (s16) targetingFlags; - bool8 hasStatusChecker2 = hasStatusChecker; - struct DungeonEntityData *userData = user->entityData; - if ((user->posWorld.x == target->posWorld.x && user->posWorld.y == target->posWorld.y) || - (targetingFlags2 & 0xF0) == TARGETING_FLAG_TARGET_ROOM || - (targetingFlags2 & 0xF0) == TARGETING_FLAG_TARGET_FLOOR || - (targetingFlags2 & 0xF0) == TARGETING_FLAG_TARGET_SELF) - { - facingDir = userData->action.facingDir; - } - else - { - facingDir = CalculateFacingDir(&user->posWorld, &target->posWorld); - } - if (!gCanAttackInDirection[facingDir] && - CanUseStatusMove(targetingFlags2, user, target, move, hasStatusChecker2)) - { - gCanAttackInDirection[facingDir] = TRUE; - do { gPotentialAttackTargetDirections[numPotentialTargets] = facingDir; } while (0); - gPotentialAttackTargetWeights[numPotentialTargets] = WeightMove(user, targetingFlags2, target, GetMoveTypeForPokemon(user, move)); - gPotentialTargets[numPotentialTargets] = target; - numPotentialTargets++; - } - return numPotentialTargets; -} - -bool8 CanUseStatusMove(s32 targetingFlags, struct DungeonEntity *user, struct DungeonEntity *target, struct PokemonMove *move, bool32 hasStatusChecker) -{ - struct DungeonEntityData *targetData; - s32 targetingFlags2 = (s16) targetingFlags; - bool8 hasStatusChecker2 = hasStatusChecker; - bool8 hasTarget = FALSE; - u32 categoryTargetingFlags = targetingFlags2 & 0xF; - u32 *categoryTargetingFlags2 = &categoryTargetingFlags; // Fixes a regswap. - if (*categoryTargetingFlags2 == TARGETING_FLAG_TARGET_OTHER) - { - if (CanTarget(user, target, FALSE, TRUE) == TARGET_CAPABILITY_CAN_TARGET) - { - hasTarget = TRUE; - } - } - else if (categoryTargetingFlags == TARGETING_FLAG_HEAL_TEAM) - { - goto checkCanTarget; - } - else if (categoryTargetingFlags == TARGETING_FLAG_LONG_RANGE) - { - targetData = target->entityData; - goto checkThirdParty; - } - else if (categoryTargetingFlags == TARGETING_FLAG_ATTACK_ALL) - { - targetData = target->entityData; - if (user == target) - { - goto returnFalse; - } - checkThirdParty: - hasTarget = TRUE; - if (targetData->shopkeeperMode == SHOPKEEPER_FRIENDLY || - targetData->clientType == CLIENT_TYPE_DONT_MOVE || - targetData->clientType == CLIENT_TYPE_CLIENT) - { - returnFalse: - return FALSE; - } - } - else if (categoryTargetingFlags == TARGETING_FLAG_BOOST_TEAM) - { - if (user == target) - { - goto returnFalse; - } - checkCanTarget: - if (CanTarget(user, target, FALSE, TRUE) == TARGET_CAPABILITY_CANNOT_ATTACK) - { - hasTarget = TRUE; - } - } - else if ((u16) (categoryTargetingFlags - 3) <= 1) // categoryTargetingFlags == TARGETING_FLAG_ITEM - { - hasTarget = TRUE; - } - - if (hasTarget) - { - if (hasStatusChecker2) - { - if (!CanUseOnTargetWithStatusChecker(user, target, move)) - { - goto returnFalse; - } - if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_SET_TRAP) - { - goto rollMoveUseChance; - } - else if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_HEAL_HP) - { - if (!HasQuarterHPOrLess(target)) - { - if (*categoryTargetingFlags2); - goto returnFalse; - } - } - else if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_HEAL_STATUS) - { - if (!HasNegativeStatus(target)) - { - if (*categoryTargetingFlags2); // Flips the conditional. - goto returnFalse; - } - } - else if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_DREAM_EATER) - { - if (!IsSleeping(target)) - { - if (*categoryTargetingFlags2); // Flips the conditional. - goto returnFalse; - } - } - else if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_EXPOSE) - { - targetData = target->entityData; - if ((targetData->type1 != TYPE_GHOST && targetData->type2 != TYPE_GHOST) || targetData->exposedStatus) - { - if (*categoryTargetingFlags2); // Flips the conditional. - goto returnFalse; - } - } - else if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_HEAL_ALL) - { - if (!HasNegativeStatus(target) && !HasQuarterHPOrLess(target)) - { - if (*categoryTargetingFlags2); // Flips the conditional. - goto returnFalse; - } - } - } - else if ((targetingFlags2 & 0xF00) == TARGETING_FLAG_SET_TRAP) - { - s32 useChance; - rollMoveUseChance: - useChance = GetMoveAccuracy(move, ACCURACY_TYPE_USE_CHANCE); - if (DungeonRandomCapped(100) >= useChance) - { - goto returnFalse; - } - } - } - return hasTarget; -} diff --git a/src/dungeon_ai_attack_2.c b/src/dungeon_ai_attack_2.c deleted file mode 100644 index 41e924a..0000000 --- a/src/dungeon_ai_attack_2.c +++ /dev/null @@ -1,76 +0,0 @@ -#include "global.h" -#include "dungeon_ai_attack_2.h" - -#include "constants/iq_skill.h" -#include "dungeon_global_data.h" -#include "dungeon_map_access.h" -#include "dungeon_pokemon_attributes.h" -#include "dungeon_util.h" - -bool8 IsTargetStraightAhead(struct DungeonEntity *pokemon, struct DungeonEntity *targetPokemon, s32 facingDir, s32 maxRange) -{ - s32 posDiffX = pokemon->posWorld.x - targetPokemon->posWorld.x; - s32 effectiveMaxRange; - if (posDiffX < 0) - { - posDiffX = -posDiffX; - } - effectiveMaxRange = pokemon->posWorld.y - targetPokemon->posWorld.y; - if (effectiveMaxRange < 0) - { - effectiveMaxRange = -effectiveMaxRange; - } - if (effectiveMaxRange < posDiffX) - { - effectiveMaxRange = posDiffX; - } - if (effectiveMaxRange > maxRange) - { - effectiveMaxRange = maxRange; - } - if (!HasIQSkill(pokemon, IQ_SKILL_COURSE_CHECKER)) - { - // BUG: effectiveMaxRange is already capped at maxRange, so this condition always evaluates to TRUE. - // The AI also has range checks elsewhere, so this doesn't become an issue in most cases. - // If the AI has the Long Toss or Pierce statuses and Course Checker is disabled, - // this incorrect check causes the AI to throw items at targets further than 10 tiles away. - if (effectiveMaxRange <= maxRange) - { - return TRUE; - } - } - else - { - s32 currentPosX = pokemon->posWorld.x; - s32 currentPosY = pokemon->posWorld.y; - s32 adjacentTileOffsetX = gAdjacentTileOffsets[facingDir].x; - s32 adjacentTileOffsetY = gAdjacentTileOffsets[facingDir].y; - s32 i; - for (i = 0; i <= effectiveMaxRange; i++) - { - struct MapTile *mapTile; - currentPosX += adjacentTileOffsetX; - currentPosY += adjacentTileOffsetY; - if (currentPosX <= 0 || currentPosY <= 0 || - currentPosX >= DUNGEON_MAX_SIZE_X - 1 || currentPosY >= DUNGEON_MAX_SIZE_Y - 1) - { - break; - } - while (0); // Extra label needed to swap branch locations in ASM. - mapTile = GetMapTile_1(currentPosX, currentPosY); - if (!(mapTile->tileType & (TILE_TYPE_FLOOR | TILE_TYPE_LIQUID))) - { - break; - } - if (mapTile->pokemon == targetPokemon) - { - return TRUE; - } - if (mapTile->pokemon != NULL) - { - break; - } - } - } - return FALSE; -} diff --git a/src/dungeon_ai_items.c b/src/dungeon_ai_items.c index 31d57ff..090e24a 100644 --- a/src/dungeon_ai_items.c +++ b/src/dungeon_ai_items.c @@ -6,7 +6,7 @@ #include "constants/status.h" #include "constants/targeting.h" #include "dungeon_action.h" -#include "dungeon_ai_attack_2.h" +#include "dungeon_ai_attack.h" #include "dungeon_ai_item_weight.h" #include "dungeon_ai_items.h" #include "dungeon_ai_targeting_2.h" @@ -28,7 +28,6 @@ #define NUM_POTENTIAL_ROCK_TARGETS 20 #define GROUND_ITEM_TOOLBOX_INDEX 0x80 #define HELD_ITEM_TOOLBOX_INDEX 0x81 -#define RANGED_ATTACK_RANGE 10 enum ItemTargetFlag { diff --git a/src/dungeon_ai_movement.c b/src/dungeon_ai_movement.c index 49609d7..326913a 100644 --- a/src/dungeon_ai_movement.c +++ b/src/dungeon_ai_movement.c @@ -28,7 +28,6 @@ extern char *gPtrItsaMonsterHouseMessage; extern void SendImmobilizeEndMessage(struct DungeonEntity*, struct DungeonEntity*); extern void SetMessageArgument(char[], struct DungeonEntity*, u32); -extern void ResetAction(u16*); extern void MoveIfPossible(struct DungeonEntity*, bool8); extern u8 sub_8044B28(void); extern void sub_807AB38(struct DungeonEntity *, u32); @@ -206,7 +205,7 @@ void DecideAction(struct DungeonEntity *pokemon) } } } - ResetAction(&pokemonData->action.action); + ResetAction(&pokemonData->action); if (pokemonData->clientType == CLIENT_TYPE_CLIENT) { SetWalkAction(&pokemonData->action, pokemonData->entityID); diff --git a/src/dungeon_pokemon_attributes.c b/src/dungeon_pokemon_attributes.c index bd3a1f6..0550d7d 100644 --- a/src/dungeon_pokemon_attributes.c +++ b/src/dungeon_pokemon_attributes.c @@ -95,7 +95,7 @@ bool8 HasAbility(struct DungeonEntity *pokemon, u8 ability) else { struct DungeonEntityData *pokemonData = pokemon->entityData; - if (pokemonData->ability1 == ability || pokemonData->ability2 == ability) + if (pokemonData->abilities[0] == ability || pokemonData->abilities[1] == ability) { return TRUE; } @@ -110,11 +110,11 @@ bool8 HasType(struct DungeonEntity *pokemon, u8 type) { return FALSE; } - if (pokemonData->type1 == type) + if (pokemonData->types[0] == type) { return TRUE; } - if (pokemonData->type2 == type) + if (pokemonData->types[1] == type) { return TRUE; } diff --git a/src/friend_area.c b/src/friend_area.c index 15a527e..06cf101 100644 --- a/src/friend_area.c +++ b/src/friend_area.c @@ -2,6 +2,7 @@ #include "constants/friend_area.h" #include "friend_area.h" #include "pokemon.h" +#include "code_800D090.h" bool8 gBoughtFriendAreas[NUM_FRIEND_AREAS]; EWRAM_DATA bool8 *gFriendAreas; @@ -14,7 +15,6 @@ extern const char *gFriendAreaNames[]; extern const char gUnknown_81098A4; extern const char gUnknown_81098AC; -extern void ExpandPlaceholdersBuffer(u8 *buffer, const char *r2, ...); extern void sub_8090FEC(u32, u8 *r1, u32); const struct FriendAreaSettings gFriendAreaSettings[NUM_FRIEND_AREAS] = @@ -599,7 +599,7 @@ u32 GetFriendAreaPrice(u8 index) void sub_8092558(u8 *buffer, u8 index) { // colors the friend area name green and prints to buffer? - ExpandPlaceholdersBuffer(buffer, &gUnknown_81098A4, gFriendAreaNames[index]); + sprintf_2(buffer, &gUnknown_81098A4, gFriendAreaNames[index]); } void sub_8092578(u8 *buffer, u8 index, u8 r2) @@ -609,7 +609,7 @@ void sub_8092578(u8 *buffer, u8 index, u8 r2) if(r2) { sub_8090FEC(gFriendAreaSettings[index].price, priceBuffer, 1); - ExpandPlaceholdersBuffer(buffer, &gUnknown_81098AC, gFriendAreaNames[index], 96, priceBuffer); + sprintf_2(buffer, &gUnknown_81098AC, gFriendAreaNames[index], 96, priceBuffer); } else { diff --git a/src/friend_list_menu.c b/src/friend_list_menu.c index 50b8c02..9310665 100644 --- a/src/friend_list_menu.c +++ b/src/friend_list_menu.c @@ -4,6 +4,7 @@ #include "text.h" #include "team_inventory.h" #include "constants/move.h" +#include "code_800D090.h" struct unkStruct_203B2B8 { @@ -52,7 +53,6 @@ extern void sub_8008C54(u32); extern void sub_80073B8(u32); extern void sub_80073E0(u32); extern void sub_80922B4(u8 *, const u8 *, u32); -extern void ExpandPlaceholdersBuffer(u8 *buffer, const u8 *text, ...); extern void sub_808D930(u8 *, s16); extern s32 sub_8008ED0(u8 *); extern void xxx_call_draw_string(s32 x, s32 y, u8 *, u32, u32); @@ -333,7 +333,7 @@ void sub_8026E08(u32 r0) sub_80073B8(r0); sub_80922B4(gAvailablePokemonNames, gUnknown_203B2B8->unk18->name, POKEMON_NAME_LENGTH); sub_808D930(buffer, gUnknown_203B2B8->unk18->speciesNum); - ExpandPlaceholdersBuffer(buffer1, gUnknown_80DD6E0, gAvailablePokemonNames); + sprintf_2(buffer1, gUnknown_80DD6E0, gAvailablePokemonNames); x = sub_8008ED0(buffer1); xxx_call_draw_string(((gUnknown_80DD370.unk0c << 3) - x) / 2, 3, buffer1, r0, 0); sub_80073E0(r0); diff --git a/src/items.c b/src/items.c index d1cd07b..e4bdc6a 100644 --- a/src/items.c +++ b/src/items.c @@ -8,6 +8,7 @@ #include "random.h" #include "subStruct_203B240.h" #include "team_inventory.h" +#include "code_800D090.h" #include <stddef.h> @@ -37,7 +38,6 @@ EWRAM_DATA struct Item *gItemParametersData; extern u8 GetItemType(u8); extern u32 GetItemUnkThrow(u8, u32); -extern void ExpandPlaceholdersBuffer(u8 *, const u8 *, ...); extern s32 sub_8090FEC(s32 a1, u8* a2, u8 a3); extern void sub_80073B8(u32); extern u32 sub_8097DF0(char *, struct subStruct_203B240 **); @@ -326,35 +326,35 @@ void sub_8090E14(u8* ext_buffer, struct ItemSlot* slot, struct unkStruct_8090F58 if (GetItemType(slot->itemIndex) == ITEM_TYPE_THROWABLE) { // I feel like these labels might actually be there... if (unk8) { - ExpandPlaceholdersBuffer(buffer, gUnknown_8109770, gItemParametersData[slot->itemIndex].namePointer, slot->numItems); + sprintf_2(buffer, gUnknown_8109770, gItemParametersData[slot->itemIndex].namePointer, slot->numItems); } else { - ExpandPlaceholdersBuffer(buffer, gUnknown_8109778, gItemParametersData[slot->itemIndex].namePointer); + sprintf_2(buffer, gUnknown_8109778, gItemParametersData[slot->itemIndex].namePointer); } } else if (GetItemType(slot->itemIndex) == ITEM_TYPE_ROCK) { if (unk8) { - ExpandPlaceholdersBuffer(buffer, gUnknown_8109770, gItemParametersData[slot->itemIndex].namePointer, slot->numItems); + sprintf_2(buffer, gUnknown_8109770, gItemParametersData[slot->itemIndex].namePointer, slot->numItems); } else { - ExpandPlaceholdersBuffer(buffer, gUnknown_8109778, gItemParametersData[slot->itemIndex].namePointer); + sprintf_2(buffer, gUnknown_8109778, gItemParametersData[slot->itemIndex].namePointer); } } else if (slot->itemIndex == ITEM_ID_POKE) { - ExpandPlaceholdersBuffer(buffer, gUnknown_810977C, GetMoneyValue(slot)); + sprintf_2(buffer, gUnknown_810977C, GetMoneyValue(slot)); } else { strncpy(buffer, gItemParametersData[slot->itemIndex].namePointer, 80); } if (slot->itemFlags & ITEM_FLAG_STICKY) { - ExpandPlaceholdersBuffer(ext_buffer, gUnknown_8109784, buffer); + sprintf_2(ext_buffer, gUnknown_8109784, buffer); strncpy(buffer, ext_buffer, 80); } if (a3) { if (a3->unk4 && (slot->itemFlags & ITEM_FLAG_SET)) { - ExpandPlaceholdersBuffer(ext_buffer, gUnknown_810978C, buffer); + sprintf_2(ext_buffer, gUnknown_810978C, buffer); strncpy(buffer, ext_buffer, 80); } if ((*(u32*)a3 == 1) || (*(u32*)a3 == 3)) { @@ -408,11 +408,11 @@ void sub_8090F58(void* a1, u8 *a2, struct ItemSlot *slot, struct unkStruct_8090F if (a4->unk6) { sub_8090FEC(value, buffer, 1); - ExpandPlaceholdersBuffer(a1, gUnknown_8109794, a2, a4->unk6, buffer); + sprintf_2(a1, gUnknown_8109794, a2, a4->unk6, buffer); } else { sub_8090FEC(value, buffer, 0); - ExpandPlaceholdersBuffer(a1, gUnknown_81097A4, a2, buffer); + sprintf_2(a1, gUnknown_81097A4, a2, buffer); } } diff --git a/src/kecleon_items_1.c b/src/kecleon_items_1.c index 0dea887..cd5df5b 100644 --- a/src/kecleon_items_1.c +++ b/src/kecleon_items_1.c @@ -6,6 +6,7 @@ #include "item.h" #include "kecleon_items.h" #include "team_inventory.h" +#include "code_800D090.h" extern struct unkStruct_203B210 *gUnknown_203B210; extern u8 gUnknown_80DB8E4[]; @@ -31,7 +32,6 @@ extern void sub_8008C54(u32); extern void sub_80073B8(u32); extern void sub_80073E0(u32); extern s32 sub_8013800(void *, u32); -extern void ExpandPlaceholdersBuffer(u8 *, u8 *, ...); extern void xxx_call_draw_string(s32 x, s32, u8 *, u32, u32); extern void sub_801AE84(void); extern void sub_8012D08(void *, u32); @@ -475,7 +475,7 @@ void sub_801A0D8(void) // Needed for the shifts.. u32 index_shift; u32 numItems_shift; - + sub_8008C54(gUnknown_203B214->unk34); sub_80073B8(gUnknown_203B214->unk34); xxx_call_draw_string(gUnknown_203B214->unk1E * 8 + 10,0,gUnknown_80DB8E4, @@ -505,7 +505,7 @@ void sub_801A0D8(void) xxx_call_draw_string(8,y,auStack204,gUnknown_203B214->unk34,0); } else { - ExpandPlaceholdersBuffer(auStack112,gUnknown_80DB8EC,auStack204); + sprintf_2(auStack112,gUnknown_80DB8EC,auStack204); y = sub_8013800(gUnknown_203B214,iVar4); xxx_call_draw_string(8,y,auStack112,gUnknown_203B214->unk34,0); } @@ -701,7 +701,7 @@ void sub_801A4A4(void) // Needed for the shifts.. u32 index_shift; u32 numItems_shift; - + sub_8008C54(gUnknown_203B21C->unk34); sub_80073B8(gUnknown_203B21C->unk34); xxx_call_draw_string(gUnknown_203B21C->unk1E * 8 + 10,0,gUnknown_80DB92C, @@ -731,7 +731,7 @@ void sub_801A4A4(void) xxx_call_draw_string(8,y,auStack204,gUnknown_203B21C->unk34,0); } else { - ExpandPlaceholdersBuffer(auStack112,gUnknown_80DB934,auStack204); + sprintf_2(auStack112,gUnknown_80DB934,auStack204); y = sub_8013800(gUnknown_203B21C,iVar4); xxx_call_draw_string(8,y,auStack112,gUnknown_203B21C->unk34,0); } @@ -741,7 +741,7 @@ void sub_801A4A4(void) u32 sub_801A5D8(u32 param_1,int param_2,struct UnkTextStruct2_sub *param_3,u32 param_4) { - + if (GetNumberOfFilledInventorySlots() == 0) { return 0; } @@ -781,7 +781,7 @@ u32 sub_801A6E8(u8 param_1) { s32 iVar5; struct ItemSlot local_10; - + if (param_1 == '\0') { sub_8013660(&gUnknown_203B224->unk54); return 0; diff --git a/src/load_screen.c b/src/load_screen.c index 1721bf5..1c224f5 100644 --- a/src/load_screen.c +++ b/src/load_screen.c @@ -8,6 +8,7 @@ #include "text.h" #include "pokemon.h" #include "save.h" +#include "code_800D090.h" extern const struct FileArchive gTitleMenuFileArchive; @@ -59,7 +60,6 @@ extern void sub_80920D8(u8 *); extern struct PokemonStruct *GetPlayerPokemonStruct(void); extern u8 sub_80023E4(u32); extern u8 *sub_8098FB4(); -extern void ExpandPlaceholdersBuffer(u8 *buffer, const u8 *text, ...); extern u8 *GetDungeonLocationInfo(void); extern u32 GetNumAdventures(void); extern void xxx_call_draw_string(u32 x, u32 y, const u8 *, u32, u32); @@ -179,7 +179,7 @@ ALIGNED(4) const char load_screen_fill[] = "pksdir0"; void CreateLoadScreen(u32 currMenu) { int iVar8; - + if (gLoadScreen == NULL) { gLoadScreen = MemoryAlloc(sizeof(struct LoadScreen),8); MemoryFill8((u8 *)gLoadScreen,0,sizeof(struct LoadScreen)); @@ -230,7 +230,7 @@ u32 UpdateLoadScreenMenu(void) { u32 nextMenu; u32 menuAction; - + nextMenu = MENU_NO_SCREEN_CHANGE; menuAction = 4; sub_8012FD8(&gLoadScreen->unk54); @@ -311,7 +311,7 @@ void DrawLoadScreenText(void) r2 = DrawLoadScreenTextSub(teamNameBuffer); } - ExpandPlaceholdersBuffer(gLoadScreen->formattedTeamName,gUnknown_80E7804,r2); + sprintf_2(gLoadScreen->formattedTeamName,gUnknown_80E7804,r2); xxx_call_draw_string(64,0,gLoadScreen->formattedTeamName,0,0); // Draw Player Name @@ -320,7 +320,7 @@ void DrawLoadScreenText(void) sub_80922B4(playerName, gNoNamePlaceholder, POKEMON_NAME_LENGTH); else sub_80922B4(playerName, playerInfo->name, POKEMON_NAME_LENGTH); - ExpandPlaceholdersBuffer(gLoadScreen->formattedPlayerName,gUnknown_80E7804,playerName); + sprintf_2(gLoadScreen->formattedPlayerName,gUnknown_80E7804,playerName); xxx_call_draw_string(64,12,gLoadScreen->formattedPlayerName,0,0); // Draw Location Info @@ -328,7 +328,7 @@ void DrawLoadScreenText(void) if (iVar2 == 0xf1207) PrintDungeonLocationtoBuffer(gLoadScreen->formattedLocation,GetDungeonLocationInfo()); else - ExpandPlaceholdersBuffer(gLoadScreen->formattedLocation,gQuicksaveDataDeletedText); // Quicksave data deleted + sprintf_2(gLoadScreen->formattedLocation,gQuicksaveDataDeletedText); // Quicksave data deleted } else { switch(sub_8011C1C()) @@ -337,12 +337,12 @@ void DrawLoadScreenText(void) switch(sub_8001658(0,24)) { default: - ExpandPlaceholdersBuffer(auStack356,gUnknown_80E7804,sub_8098FB4()); + sprintf_2(auStack356,gUnknown_80E7804,sub_8098FB4()); xxx_format_string(auStack356,gLoadScreen->formattedLocation,gLoadScreen->formattedPlayTime,0); break; case 0x7: case 0xB: - ExpandPlaceholdersBuffer(gLoadScreen->formattedLocation,gQuicksaveDataDeletedText); // Quicksave data deleted + sprintf_2(gLoadScreen->formattedLocation,gQuicksaveDataDeletedText); // Quicksave data deleted break; } break; @@ -350,10 +350,10 @@ void DrawLoadScreenText(void) if (iVar2 == 0xf1207) PrintDungeonLocationtoBuffer(gLoadScreen->formattedLocation,GetDungeonLocationInfo()); else - ExpandPlaceholdersBuffer(gLoadScreen->formattedLocation,gQuicksaveDataDeletedText); // Quicksave data deleted + sprintf_2(gLoadScreen->formattedLocation,gQuicksaveDataDeletedText); // Quicksave data deleted break; default: - ExpandPlaceholdersBuffer(gLoadScreen->formattedLocation,gLocationUnknownText); // Location unknown + sprintf_2(gLoadScreen->formattedLocation,gLocationUnknownText); // Location unknown break; } } @@ -361,12 +361,12 @@ void DrawLoadScreenText(void) // Draw Play Time DeconstructPlayTime(gPlayTimeRef,&hours,&minutes,&seconds); - ExpandPlaceholdersBuffer(gLoadScreen->formattedPlayTime,gPlayTimePlaceholder,hours,minutes,seconds); + sprintf_2(gLoadScreen->formattedPlayTime,gPlayTimePlaceholder,hours,minutes,seconds); xxx_call_draw_string(64,36,gLoadScreen->formattedPlayTime,0,0); - // Draw Adventures Info + // Draw Adventures Info numAdventures = GetNumAdventures(); - ExpandPlaceholdersBuffer(gLoadScreen->formattedAdventures,gNumAdventurePlaceholder,numAdventures); // %d + sprintf_2(gLoadScreen->formattedAdventures,gNumAdventurePlaceholder,numAdventures); // %d xxx_call_draw_string(64,48,gLoadScreen->formattedAdventures,0,0); // Draw Helper Info @@ -376,14 +376,14 @@ void DrawLoadScreenText(void) if(temp2->speciesIndex != SPECIES_NONE) { sub_808D930(speciesHelper,temp2->speciesIndex); sub_80922B4(nameHelper,temp2->helperName,POKEMON_NAME_LENGTH); - ExpandPlaceholdersBuffer(gLoadScreen->formattedHelperInfo,gHelperInfoPlaceholder,nameHelper,speciesHelper); // %s (%s) + sprintf_2(gLoadScreen->formattedHelperInfo,gHelperInfoPlaceholder,nameHelper,speciesHelper); // %s (%s) } else goto print_helper_placeholder; } else { print_helper_placeholder: - ExpandPlaceholdersBuffer(gLoadScreen->formattedHelperInfo,gNoHelperText); // ----- + sprintf_2(gLoadScreen->formattedHelperInfo,gNoHelperText); // ----- } xxx_call_draw_string(64,60,gLoadScreen->formattedHelperInfo,0,0); @@ -399,7 +399,7 @@ void sub_80397B4(void) int iVar3; int iVar4; s32 other_arg; - + clmkFile = OpenFileAndGetFileDataPtr(gClmkpatFileName,&gTitleMenuFileArchive); // clmkpat for(iVar3 = 0; iVar3 < 64; iVar3++) @@ -426,7 +426,7 @@ bool8 IsQuickSave(void) { int iVar1; bool8 isQuicksave; - + iVar1 = sub_8011FA8(); isQuicksave = FALSE; if (sub_8095324(1) != 0 || sub_8095324(7) != 0) diff --git a/src/move_util.c b/src/move_util.c new file mode 100644 index 0000000..4487862 --- /dev/null +++ b/src/move_util.c @@ -0,0 +1,88 @@ +#include "global.h" +#include "move_util.h" + +#include "constants/move_id.h" +#include "constants/status.h" +#include "moves.h" + +bool8 IsMoveIndexUsable(struct DungeonEntity *pokemon, s32 moveIndex, bool8 hasPPChecker) +{ + struct DungeonEntityData *pokemonData = pokemon->entityData; + struct PokemonMove *move = &pokemonData->moves[moveIndex]; + s32 i; + if (!(move->moveFlags & MOVE_FLAG_EXISTS)) + { + return FALSE; + } + if (move->moveFlags & MOVE_FLAG_LINKED) + { + return FALSE; + } + if (move->moveFlags & MOVE_FLAG_DISABLED || + move->moveFlags2 & MOVE_FLAG_SEALED) + { + return FALSE; + } + goto initMoveIndex; + returnTrue: + return TRUE; + initMoveIndex: + i = 0; + goto checkMoveUsable; + incMoveIndex: + i++; + checkMoveUsable: + if (i >= MAX_MON_MOVES) + { + return FALSE; + } + if (IsMoveUsable(pokemon, move, hasPPChecker)) + { + goto returnTrue; + } + move++; + if ((u32) move >= (u32) &pokemonData->struggleMoveFlags || !(move->moveFlags & MOVE_FLAG_LINKED)) + { + return FALSE; + } + goto incMoveIndex; +} + +bool8 IsMoveUsable(struct DungeonEntity *pokemon, struct PokemonMove *move, bool8 hasPPChecker) +{ + struct DungeonEntityData *pokemonData = pokemon->entityData; + if (move->moveID == MOVE_REGULAR_ATTACK) + { + return TRUE; + } + if (move->moveFlags & MOVE_FLAG_DISABLED || move->moveFlags2 & MOVE_FLAG_SEALED) + { + return FALSE; + } + if (hasPPChecker) + { + if (move->PP == 0) + { + return FALSE; + } + if (pokemonData->volatileStatus == VOLATILE_STATUS_TAUNTED && !MoveDealsDirectDamage(move)) + { + return FALSE; + } + if (pokemonData->volatileStatus == VOLATILE_STATUS_ENCORE) + { + if (move->moveID == MOVE_STRUGGLE) + { + if (!(pokemonData->struggleMoveFlags & MOVE_FLAG_LAST_USED)) + { + return FALSE; + } + } + else if (!(move->moveFlags & MOVE_FLAG_LAST_USED)) + { + return FALSE; + } + } + } + return TRUE; +} diff --git a/src/moves.c b/src/moves.c index 2fcbfd0..3c3e8a9 100644 --- a/src/moves.c +++ b/src/moves.c @@ -3,6 +3,7 @@ #include "file_system.h" #include "moves.h" +#include "code_800D090.h" struct MoveDataFile { @@ -37,7 +38,6 @@ extern u8 gUnknown_810992C[]; extern void sub_8093F10(struct PokemonMove *, struct PokemonMove *); extern void sub_80928C0(u8 *, struct PokemonMove *, struct unkStruct_80928C0 *); -extern void ExpandPlaceholdersBuffer(u8 *, u8 *, ...); void LoadWazaParameters(void) { @@ -51,7 +51,7 @@ u8 sub_809287C(struct PokemonMove *move) { if((move->moveFlags & MOVE_FLAG_DISABLED) != 0) return 0x32; - else if((move->sealed & 1) == 0) + else if((move->moveFlags2 & MOVE_FLAG_SEALED) == 0) return 0x34; else return 0x32; @@ -76,7 +76,7 @@ void sub_80928C0(u8 *buffer, struct PokemonMove *move, struct unkStruct_80928C0 } if (move->powerBoost != 0) - ExpandPlaceholdersBuffer(localBuffer,gUnknown_81098DC,move->powerBoost); // %+d + sprintf_2(localBuffer,gUnknown_81098DC,move->powerBoost); // %+d else localBuffer[0] = '\0'; @@ -88,14 +88,14 @@ void sub_80928C0(u8 *buffer, struct PokemonMove *move, struct unkStruct_80928C0 } switch(param_3->unk0) { case 0: - ExpandPlaceholdersBuffer + sprintf_2 (buffer,gUnknown_81098E0,uVar2, gMovesData[move->moveID].namePointer,localBuffer); break; case 1: maxPP = GetMoveMaxPP(move); - ExpandPlaceholdersBuffer + sprintf_2 (buffer,gUnknown_81098EC,uVar2,move->moveFlags & MOVE_FLAG_SET ? gUnknown_8109908 : gUnknown_810990C, gMovesData[move->moveID].namePointer,localBuffer,param_3->unk4, move->PP,maxPP); @@ -103,7 +103,7 @@ void sub_80928C0(u8 *buffer, struct PokemonMove *move, struct unkStruct_80928C0 case 2: maxPP = GetMoveMaxPP(move); - ExpandPlaceholdersBuffer + sprintf_2 (buffer,gUnknown_8109910,uVar2,move->moveFlags & MOVE_FLAG_SET ? gUnknown_8109908 : gUnknown_810990C, gMovesData[move->moveID].namePointer,localBuffer,param_3->unk4, move->PP,maxPP); @@ -111,7 +111,7 @@ void sub_80928C0(u8 *buffer, struct PokemonMove *move, struct unkStruct_80928C0 case 3: maxPP = GetMoveMaxPP(move); - ExpandPlaceholdersBuffer + sprintf_2 (buffer,gUnknown_81098EC,uVar2,move->moveFlags & MOVE_FLAG_ENABLED ? gUnknown_8109928 : gUnknown_810990C, gMovesData[move->moveID].namePointer,localBuffer,param_3->unk4, move->PP,maxPP); @@ -119,7 +119,7 @@ void sub_80928C0(u8 *buffer, struct PokemonMove *move, struct unkStruct_80928C0 case 4: maxPP = GetMoveMaxPP(move); - ExpandPlaceholdersBuffer + sprintf_2 (buffer,gUnknown_8109910,uVar2, move->moveFlags & MOVE_FLAG_ENABLED ? gUnknown_8109928 : gUnknown_810990C, gMovesData[move->moveID].namePointer,localBuffer,param_3->unk4, move->PP,maxPP); @@ -130,7 +130,7 @@ void sub_80928C0(u8 *buffer, struct PokemonMove *move, struct unkStruct_80928C0 void InitPokemonMove(struct PokemonMove *move, u16 moveID) { move->moveFlags = MOVE_FLAG_ENABLED | MOVE_FLAG_EXISTS; - move->sealed = FALSE; + move->moveFlags2 = 0; move->moveID = moveID; move->PP = GetMoveMaxPP(move); move->powerBoost = 0; @@ -143,7 +143,7 @@ void sub_8092AA8(struct PokemonMove *move, u16 moveID) else { move->moveFlags = MOVE_FLAG_ENABLED | MOVE_FLAG_EXISTS; - move->sealed = FALSE; + move->moveFlags2 = 0; move->moveID = moveID; move->PP = GetMoveMaxPP(move); move->powerBoost = 0; @@ -297,17 +297,17 @@ u8 *GetMoveUseText(u16 moveID) return gMovesData[moveID].useText; } -u8 GetMoveAffectedByMagicCoat(u16 moveID) +bool8 MoveAffectedByMagicCoat(u16 moveID) { return gMovesData[moveID].affectedByMagicCoat; } -u8 GetMoveTargetsUser(u16 moveID) +bool8 MoveTargetsUser(u16 moveID) { return gMovesData[moveID].targetsUser; } -u8 GetMoveAffectedByMuzzled(u16 moveID) +bool8 MoveAffectedByMuzzled(u16 moveID) { return gMovesData[moveID].affectedByMuzzled; } @@ -331,5 +331,5 @@ bool8 IsBlockedBySoundproof(struct PokemonMove *move) void sub_8092D54(u8 *buffer, struct PokemonMove *move) { - ExpandPlaceholdersBuffer(buffer, gUnknown_810992C, gRangeNames[GetMoveRangeType(move)]); + sprintf_2(buffer, gUnknown_810992C, gRangeNames[GetMoveRangeType(move)]); } diff --git a/src/moves_1.c b/src/moves_1.c index 80f28af..b312747 100644 --- a/src/moves_1.c +++ b/src/moves_1.c @@ -38,7 +38,7 @@ void RestorePokemonMoves(struct unkStruct_8094924 *r0, struct PokemonMove *moveS void sub_8094148(struct unkStruct_8094924 *r0, struct PokemonMove *move) { SaveIntegerBits(r0, &move->moveFlags, 4); - SaveIntegerBits(r0, &move->sealed, 1); + SaveIntegerBits(r0, &move->moveFlags2, 1); SaveIntegerBits(r0, &move->moveID, 9); SaveIntegerBits(r0, &move->PP, 7); SaveIntegerBits(r0, &move->powerBoost, 7); @@ -59,7 +59,7 @@ void sub_80941B0(struct unkStruct_8094924 *r0, struct PokemonMove *move) { memset(move, 0, sizeof(struct PokemonMove)); RestoreIntegerBits(r0, &move->moveFlags, 4); - RestoreIntegerBits(r0, &move->sealed, 1); + RestoreIntegerBits(r0, &move->moveFlags2, 1); RestoreIntegerBits(r0, &move->moveID, 9); RestoreIntegerBits(r0, &move->PP, 7); RestoreIntegerBits(r0, &move->powerBoost, 7); diff --git a/src/pokemon_mid.c b/src/pokemon_mid.c index ceb1371..d57e8a2 100644 --- a/src/pokemon_mid.c +++ b/src/pokemon_mid.c @@ -6,6 +6,7 @@ #include "subStruct_203B240.h" #include "constants/colors.h" #include "constants/move_id.h" +#include "code_800D090.h" extern struct gPokemon *gMonsterParameters; extern const char gUnknown_8107600[]; @@ -27,7 +28,6 @@ extern u16 gLevelCurrentPokeId; extern struct LevelData gLevelCurrentData[]; -extern void ExpandPlaceholdersBuffer(u8 *buffer, const char *r2, ...); extern s16 GetBaseSpecies(s16); extern void sub_80922B4(u8 *, u8 *, s32); extern int sprintf(char *, const char *, ...); @@ -239,13 +239,13 @@ void CopySpeciesNametoBuffer(u8 * buffer, s16 index) void CopyYellowSpeciesNametoBuffer(u8 *buffer, s16 index) { s32 new_index = index; - ExpandPlaceholdersBuffer(buffer, gUnknown_8107600, gMonsterParameters[new_index].species); // {COLOR_2 YELLOW}%s{END_COLOR_TEXT_2} + sprintf_2(buffer, gUnknown_8107600, gMonsterParameters[new_index].species); // {COLOR_2 YELLOW}%s{END_COLOR_TEXT_2} } void CopyCyanSpeciesNametoBuffer(u8 *buffer, s16 index) { s32 new_index = index; - ExpandPlaceholdersBuffer(buffer, gUnknown_8107608, gMonsterParameters[new_index].species); // {COLOR_2 CYAN}%s{END_COLOR_TEXT_2} + sprintf_2(buffer, gUnknown_8107608, gMonsterParameters[new_index].species); // {COLOR_2 CYAN}%s{END_COLOR_TEXT_2} } void sub_808D930(u8 *buffer, s16 index) @@ -258,10 +258,10 @@ void sub_808D930(u8 *buffer, s16 index) preload = gUnknown_8107630; // %s%c unownString = GetMonSpecies(SPECIES_UNOWN); unownIndex = GetUnownIndex(index); - ExpandPlaceholdersBuffer(buffer,preload,unownString,gUnownLetters[unownIndex]); // ABCDEFGHIJKLMNOPQRSTUVWXYZ!? + sprintf_2(buffer,preload,unownString,gUnownLetters[unownIndex]); // ABCDEFGHIJKLMNOPQRSTUVWXYZ!? } else { - ExpandPlaceholdersBuffer(buffer,gUnknown_8107638, gMonsterParameters[index].species); // %s + sprintf_2(buffer,gUnknown_8107638, gMonsterParameters[index].species); // %s } } @@ -278,7 +278,7 @@ void PrintColoredPokeNameToBuffer(u8 *buffer, struct PokemonStruct *pokemon, s32 if (colorNum == COLOR_WHITE) { colorNum = COLOR_CYAN; } - ExpandPlaceholdersBuffer(buffer,gUnknown_810763C,colorNum,nameBuffer); // {COLOR_2}%c%s{END_COLOR_TEXT_2} + sprintf_2(buffer,gUnknown_810763C,colorNum,nameBuffer); // {COLOR_2}%c%s{END_COLOR_TEXT_2} } void sub_808D9DC(u8 *buffer, u8 *param_2, s32 colorNum) @@ -289,7 +289,7 @@ void sub_808D9DC(u8 *buffer, u8 *param_2, s32 colorNum) if (colorNum == COLOR_WHITE) { colorNum = COLOR_YELLOW; } - ExpandPlaceholdersBuffer(buffer,gUnknown_810763C,colorNum,nameBuffer); // {COLOR_2}%c%s{END_COLOR_TEXT_2} + sprintf_2(buffer,gUnknown_810763C,colorNum,nameBuffer); // {COLOR_2}%c%s{END_COLOR_TEXT_2} } void sub_808DA0C(u8 *buffer, u8 *param_2) @@ -297,7 +297,7 @@ void sub_808DA0C(u8 *buffer, u8 *param_2) u8 nameBuffer [20]; sub_80922B4(nameBuffer, param_2 + 0x58, POKEMON_NAME_LENGTH); - ExpandPlaceholdersBuffer(buffer,gUnknown_8107638,nameBuffer); // %s + sprintf_2(buffer,gUnknown_8107638,nameBuffer); // %s } void PrintPokeNameToBuffer(u8 *buffer, struct PokemonStruct *pokemon) diff --git a/src/status.c b/src/status.c new file mode 100644 index 0000000..dc8a812 --- /dev/null +++ b/src/status.c @@ -0,0 +1,19 @@ +#include "global.h" +#include "status.h" + +#include "constants/ability.h" +#include "dungeon_pokemon_attributes.h" +#include "dungeon_util.h" + +u8 GetFlashFireStatus(struct DungeonEntity *pokemon) +{ + if (!EntityExists(pokemon) || !HasAbility(pokemon, ABILITY_FLASH_FIRE)) + { + return FLASH_FIRE_STATUS_NONE; + } + if (pokemon->entityData->flashFireBoost > 1) + { + return FLASH_FIRE_STATUS_MAXED; + } + return FLASH_FIRE_STATUS_NOT_MAXED; +} diff --git a/src/status_checker.c b/src/status_checker.c index 07d6c7f..0aaeddf 100644 --- a/src/status_checker.c +++ b/src/status_checker.c @@ -11,6 +11,7 @@ #include "dungeon_util.h" #include "dungeon_visibility.h" #include "map.h" +#include "moves.h" #include "number_util.h" #include "status_checks_1.h" #include "tile_types.h" @@ -130,13 +131,13 @@ bool8 CanUseOnSelfWithStatusChecker(struct DungeonEntity *pokemon, struct Pokemo case MOVE_HOWL: case MOVE_MEDITATE: case MOVE_SHARPEN: - if (pokemonData->attackStage >= MAX_STAT_STAGE) + if (pokemonData->attackStages[STAT_STAGE_ATTACK] >= MAX_STAT_STAGE) { return FALSE; } break; case MOVE_BELLY_DRUM: - if (pokemonData->attackStage >= MAX_STAT_STAGE || RoundUpFixedPoint(pokemonData->belly) <= 0) + if (pokemonData->attackStages[STAT_STAGE_ATTACK] >= MAX_STAT_STAGE || RoundUpFixedPoint(pokemonData->belly) <= 0) { return FALSE; } @@ -147,7 +148,7 @@ bool8 CanUseOnSelfWithStatusChecker(struct DungeonEntity *pokemon, struct Pokemo case MOVE_HARDEN: case MOVE_IRON_DEFENSE: case MOVE_WITHDRAW: - if (pokemonData->defenseStage >= MAX_STAT_STAGE) + if (pokemonData->defenseStages[STAT_STAGE_DEFENSE] >= MAX_STAT_STAGE) { return FALSE; } @@ -182,7 +183,7 @@ bool8 CanUseOnSelfWithStatusChecker(struct DungeonEntity *pokemon, struct Pokemo } break; case MOVE_COSMIC_POWER: - if (pokemonData->defenseStage >= MAX_STAT_STAGE && pokemonData->specialDefenseStage >= MAX_STAT_STAGE) + if (pokemonData->defenseStages[STAT_STAGE_DEFENSE] >= MAX_STAT_STAGE && pokemonData->defenseStages[STAT_STAGE_SPECIAL_DEFENSE] >= MAX_STAT_STAGE) { return FALSE; } @@ -212,7 +213,7 @@ bool8 CanUseOnSelfWithStatusChecker(struct DungeonEntity *pokemon, struct Pokemo } break; case MOVE_MINIMIZE: - if (pokemonData->evasionStage >= MAX_STAT_STAGE) + if (pokemonData->accuracyStages[STAT_STAGE_EVASION] >= MAX_STAT_STAGE) { return FALSE; } @@ -243,7 +244,7 @@ bool8 CanUseOnSelfWithStatusChecker(struct DungeonEntity *pokemon, struct Pokemo } break; case MOVE_BULK_UP: - if (pokemonData->attackStage >= MAX_STAT_STAGE && pokemonData->defenseStage >= MAX_STAT_STAGE) + if (pokemonData->attackStages[STAT_STAGE_ATTACK] >= MAX_STAT_STAGE && pokemonData->defenseStages[STAT_STAGE_DEFENSE] >= MAX_STAT_STAGE) { return FALSE; } @@ -255,7 +256,7 @@ bool8 CanUseOnSelfWithStatusChecker(struct DungeonEntity *pokemon, struct Pokemo } break; case MOVE_TAIL_GLOW: - if (pokemonData->specialAttackStage >= MAX_STAT_STAGE) + if (pokemonData->attackStages[STAT_STAGE_SPECIAL_ATTACK] >= MAX_STAT_STAGE) { return FALSE; } @@ -279,7 +280,7 @@ bool8 CanUseOnSelfWithStatusChecker(struct DungeonEntity *pokemon, struct Pokemo } break; case MOVE_DRAGON_DANCE: - if (pokemonData->attackStage >= MAX_STAT_STAGE && pokemon->entityData->movementSpeed >= MAX_MOVEMENT_SPEED) + if (pokemonData->attackStages[STAT_STAGE_ATTACK] >= MAX_STAT_STAGE && pokemon->entityData->movementSpeed >= MAX_MOVEMENT_SPEED) { return FALSE; } @@ -409,19 +410,19 @@ bool8 CanUseOnSelfWithStatusChecker(struct DungeonEntity *pokemon, struct Pokemo } break; case MOVE_DOUBLE_TEAM: - if (pokemonData->evasionStage >= MAX_STAT_STAGE) + if (pokemonData->accuracyStages[STAT_STAGE_EVASION] >= MAX_STAT_STAGE) { return FALSE; } break; case MOVE_GROWTH: - if (pokemonData->specialAttackStage >= MAX_STAT_STAGE) + if (pokemonData->attackStages[STAT_STAGE_SPECIAL_ATTACK] >= MAX_STAT_STAGE) { return FALSE; } break; case MOVE_SWORDS_DANCE: - if (pokemonData->attackStage >= MAX_STAT_STAGE) + if (pokemonData->attackStages[STAT_STAGE_ATTACK] >= MAX_STAT_STAGE) { return FALSE; } @@ -445,12 +446,12 @@ bool8 CanUseOnSelfWithStatusChecker(struct DungeonEntity *pokemon, struct Pokemo } break; case MOVE_CALM_MIND: - if (pokemonData->specialAttackStage < MAX_STAT_STAGE) + if (pokemonData->attackStages[STAT_STAGE_SPECIAL_ATTACK] < MAX_STAT_STAGE) { break; } case MOVE_AMNESIA: - if (pokemonData->specialDefenseStage >= MAX_STAT_STAGE) + if (pokemonData->defenseStages[STAT_STAGE_SPECIAL_DEFENSE] >= MAX_STAT_STAGE) { return FALSE; } @@ -492,11 +493,11 @@ bool8 CanUseOnSelfWithStatusChecker(struct DungeonEntity *pokemon, struct Pokemo struct DungeonEntity *target = gDungeonGlobalData->wildPokemon[i]; if (EntityExists(target) && target != pokemon && CanSee(pokemon, target)) { - if (target->entityData->attackStage >= MAX_STAT_STAGE) + if (target->entityData->attackStages[STAT_STAGE_ATTACK] >= MAX_STAT_STAGE) { continue; } - if (target->entityData->specialAttackStage < MAX_STAT_STAGE) + if (target->entityData->attackStages[STAT_STAGE_SPECIAL_ATTACK] < MAX_STAT_STAGE) { break; } @@ -516,11 +517,11 @@ bool8 CanUseOnSelfWithStatusChecker(struct DungeonEntity *pokemon, struct Pokemo struct DungeonEntity *target = gDungeonGlobalData->teamPokemon[i]; if (EntityExists(target) && target != pokemon && CanSee(pokemon, target)) { - if (target->entityData->attackStage >= MAX_STAT_STAGE) + if (target->entityData->attackStages[STAT_STAGE_ATTACK] >= MAX_STAT_STAGE) { continue; } - if (target->entityData->specialAttackStage < MAX_STAT_STAGE) + if (target->entityData->attackStages[STAT_STAGE_SPECIAL_ATTACK] < MAX_STAT_STAGE) { break; } @@ -535,3 +536,415 @@ bool8 CanUseOnSelfWithStatusChecker(struct DungeonEntity *pokemon, struct Pokemo } return TRUE; } + +bool8 CanUseOnTargetWithStatusChecker(struct DungeonEntity *user, struct DungeonEntity *target, struct PokemonMove *move) +{ + struct DungeonEntityData *userData = user->entityData; + struct DungeonEntityData *targetData = target->entityData; + s32 i; + if (targetData->immobilizeStatus == IMMOBILIZE_STATUS_FROZEN && MoveCannotHitFrozen(move)) + { + return FALSE; + } + switch (move->moveID) + { + case MOVE_GRASSWHISTLE: + case MOVE_HYPNOSIS: + case MOVE_LOVELY_KISS: + case MOVE_SING: + case MOVE_SLEEP_POWDER: + case MOVE_SPORE: + if (IsSleeping(target)) + { + return FALSE; + } + break; + case MOVE_YAWN: + if (targetData->sleepStatus == SLEEP_STATUS_YAWNING) + { + return FALSE; + } + if (IsSleeping(target)) + { + return FALSE; + } + break; + case MOVE_NIGHTMARE: + if (targetData->sleepStatus == SLEEP_STATUS_NIGHTMARE) + { + return FALSE; + } + break; + case MOVE_SWEET_SCENT: + if (targetData->accuracyStages[STAT_STAGE_EVASION] <= 0) + { + return FALSE; + } + break; + case MOVE_CHARM: + if (targetData->attackMultipliers[STAT_STAGE_ATTACK] < STAT_MULTIPLIER_THRESHOLD) + { + return FALSE; + } + break; + case MOVE_ENCORE: + if (targetData->volatileStatus == VOLATILE_STATUS_ENCORE) + { + return FALSE; + } + if (!HasLastUsedMove(targetData->moves)) + { + return FALSE; + } + break; + case MOVE_SUPER_FANG: + if (targetData->HP <= 1) + { + return FALSE; + } + break; + case MOVE_PAIN_SPLIT: + if (targetData->HP <= userData->HP) + { + return FALSE; + } + break; + case MOVE_TORMENT: + if (HasDisabledMove(targetData->moves) || !HasLastUsedMove(targetData->moves)) + { + return FALSE; + } + break; + case MOVE_COTTON_SPORE: + case MOVE_SCARY_FACE: + case MOVE_STRING_SHOT: + if (target->entityData->movementSpeed <= 0) + { + return FALSE; + } + break; + case MOVE_SCREECH: + if (targetData->defenseMultipliers[STAT_STAGE_DEFENSE] < STAT_MULTIPLIER_THRESHOLD) + { + return FALSE; + } + break; + case MOVE_FAKE_TEARS: + if (targetData->defenseStages[STAT_STAGE_SPECIAL_DEFENSE] <= 0) + { + return FALSE; + } + break; + case MOVE_SPITE: + if (LastUsedMoveOutOfPP(targetData->moves)) + { + return FALSE; + } + break; + case MOVE_SMOKESCREEN: + if (targetData->moveStatus == MOVE_STATUS_WHIFFER) + { + return FALSE; + } + break; + case MOVE_MEMENTO: + if (targetData->attackMultipliers[STAT_STAGE_ATTACK] < STAT_MULTIPLIER_THRESHOLD && + targetData->attackMultipliers[STAT_STAGE_SPECIAL_ATTACK] < STAT_MULTIPLIER_THRESHOLD) + { + return FALSE; + } + break; + case MOVE_WILL_O_WISP: + if (targetData->nonVolatileStatus == NON_VOLATILE_STATUS_BURNED) + { + return FALSE; + } + break; + case MOVE_FORESIGHT: + case MOVE_ODOR_SLEUTH: + if (targetData->types[0] == TYPE_GHOST || targetData->types[1] == TYPE_GHOST) + { + if (!targetData->exposedStatus) + { + break; + } + } + if (targetData->accuracyStages[STAT_STAGE_EVASION] <= DEFAULT_STAT_STAGE) + { + return FALSE; + } + break; + case MOVE_DISABLE: + case MOVE_GLARE: + case MOVE_STUN_SPORE: + case MOVE_THUNDER_WAVE: + if (targetData->nonVolatileStatus == NON_VOLATILE_STATUS_PARALYZED) + { + return FALSE; + } + break; + case MOVE_ENDEAVOR: + if (targetData->HP - userData->HP <= 0) + { + return FALSE; + } + break; + case MOVE_LEER: + case MOVE_TAIL_WHIP: + if (targetData->defenseStages[STAT_STAGE_DEFENSE] <= 0) + { + return FALSE; + } + break; + case MOVE_METAL_SOUND: + if (targetData->defenseStages[STAT_STAGE_SPECIAL_DEFENSE] <= 0) + { + return FALSE; + } + break; + case MOVE_TICKLE: + if (targetData->attackStages[STAT_STAGE_ATTACK] <= 0 && + targetData->defenseStages[STAT_STAGE_DEFENSE] <= 0) + { + return FALSE; + } + break; + case MOVE_BLOCK: + case MOVE_MEAN_LOOK: + case MOVE_SPIDER_WEB: + if (targetData->immobilizeStatus == IMMOBILIZE_STATUS_IMMOBILIZED) + { + return FALSE; + } + break; + case MOVE_HAZE: + { + for (i = 0; i < 2; i++) + { + if (targetData->attackStages[i] < DEFAULT_STAT_STAGE) break; + if (targetData->defenseStages[i] < DEFAULT_STAT_STAGE) break; + if (targetData->accuracyStages[i] < DEFAULT_STAT_STAGE || + targetData->attackMultipliers[i] < DEFAULT_STAT_MULTIPLIER || + targetData->defenseMultipliers[i] < DEFAULT_STAT_MULTIPLIER) + { + break; + } + } + if (i == 2) + { + return FALSE; + } + break; + } + case MOVE_UPROAR: + if (targetData->sleepStatus == SLEEP_STATUS_SLEEPLESS) + { + return FALSE; + } + break; + case MOVE_PSYCH_UP: + { + for (i = 0; i < 2; i++) + { + if (userData->attackStages[i] < targetData->attackStages[i]) break; + if (userData->defenseStages[i] < targetData->defenseStages[i] || + userData->accuracyStages[i] < targetData->accuracyStages[i] || + userData->attackMultipliers[i] < targetData->attackMultipliers[i] || + userData->defenseMultipliers[i] < targetData->defenseMultipliers[i]) + { + break; + } + } + if (i == 2) + { + return FALSE; + } + break; + } + case MOVE_FLASH: + case MOVE_KINESIS: + case MOVE_SAND_ATTACK: + if (targetData->accuracyStages[STAT_STAGE_ACCURACY] <= 0) + { + return FALSE; + } + break; + case MOVE_TAUNT: + if (targetData->volatileStatus == VOLATILE_STATUS_TAUNTED) + { + return FALSE; + } + break; + case MOVE_TRICK: + if (!(userData->heldItem.itemFlags & ITEM_FLAG_EXISTS) || + !(targetData->heldItem.itemFlags & ITEM_FLAG_EXISTS)) + { + return FALSE; + } + break; + case MOVE_KNOCK_OFF: + if (!(targetData->heldItem.itemFlags & ITEM_FLAG_EXISTS)) + { + return FALSE; + } + break; + case MOVE_FEATHERDANCE: + case MOVE_GROWL: + if (targetData->attackStages[STAT_STAGE_ATTACK] <= 0) + { + return FALSE; + } + break; + case MOVE_ROLE_PLAY: + if (userData->abilities[0] == targetData->abilities[0] && + userData->abilities[1] == targetData->abilities[1]) + { + return FALSE; + } + break; + case MOVE_CURSE: + if (HasType(user, TYPE_GHOST)) + { + if (targetData->waitingStatus == WAITING_STATUS_CURSED) + { + return FALSE; + } + } + else + { + if (userData->attackStages[STAT_STAGE_ATTACK] >= MAX_STAT_STAGE && + userData->defenseStages[STAT_STAGE_DEFENSE] >= MAX_STAT_STAGE) + { + return FALSE; + } + } + break; + case MOVE_IMPRISON: + case MOVE_OBSERVER: + if (targetData->volatileStatus == VOLATILE_STATUS_PAUSED) + { + return FALSE; + } + break; + case MOVE_FALSE_SWIPE: + if (targetData->HP <= 1) + { + return FALSE; + } + break; + case MOVE_LEECH_SEED: + if (targetData->linkedStatus == LINKED_STATUS_LEECH_SEED) + { + return FALSE; + } + break; + case MOVE_PERISH_SONG: + if (targetData->perishSongTimer != 0) + { + return FALSE; + } + break; + case MOVE_MIMIC: + case MOVE_SKETCH: + if (!HasLastUsedMove(targetData->moves)) + { + return FALSE; + } + break; + case MOVE_ATTRACT: + if (targetData->volatileStatus == VOLATILE_STATUS_INFATUATED) + { + return FALSE; + } + break; + case MOVE_WRAP: + if (targetData->immobilizeStatus == IMMOBILIZE_STATUS_WRAPPED_AROUND_FOE) + { + return FALSE; + } + if (targetData->immobilizeStatus == IMMOBILIZE_STATUS_WRAPPED_BY_FOE) + { + return FALSE; + } + break; + case MOVE_TOXIC: + if (targetData->nonVolatileStatus == NON_VOLATILE_STATUS_BADLY_POISONED) + { + return FALSE; + } + break; + case MOVE_POISON_GAS: + case MOVE_POISONPOWDER: + if (targetData->nonVolatileStatus == NON_VOLATILE_STATUS_POISONED) + { + return FALSE; + } + if (targetData->nonVolatileStatus == NON_VOLATILE_STATUS_BADLY_POISONED) + { + return FALSE; + } + break; + case MOVE_CONFUSE_RAY: + case MOVE_FLATTER: + case MOVE_SUPERSONIC: + case MOVE_SWAGGER: + case MOVE_SWEET_KISS: + case MOVE_TEETER_DANCE: + case MOVE_TOTTER: + if (targetData->volatileStatus == VOLATILE_STATUS_CONFUSED) + { + return FALSE; + } + break; + } + return TRUE; +} + +bool8 HasDisabledMove(struct PokemonMove *moves) +{ + s32 i; + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i].moveFlags & MOVE_FLAG_EXISTS && moves[i].moveFlags & MOVE_FLAG_DISABLED) + { + return TRUE; + } + } + if (moves[STRUGGLE_MOVE_INDEX].moveFlags & MOVE_FLAG_DISABLED) + { + return TRUE; + } + return FALSE; +} + +bool8 LastUsedMoveOutOfPP(struct PokemonMove *moves) +{ + s32 i; + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i].moveFlags & MOVE_FLAG_EXISTS && + moves[i].moveFlags & MOVE_FLAG_LAST_USED && + moves[i].PP == 0) + { + return TRUE; + } + } + return FALSE; +} + +bool8 HasLastUsedMove(struct PokemonMove *moves) +{ + s32 i; + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i].moveFlags & MOVE_FLAG_EXISTS && moves[i].moveFlags & MOVE_FLAG_LAST_USED) + { + return TRUE; + } + } + if (moves[STRUGGLE_MOVE_INDEX].moveFlags & MOVE_FLAG_LAST_USED) + { + return TRUE; + } + return FALSE; +} diff --git a/src/status_checks_1.c b/src/status_checks_1.c index c49e127..7070acd 100644 --- a/src/status_checks_1.c +++ b/src/status_checks_1.c @@ -28,7 +28,7 @@ bool8 HasNegativeStatus(struct DungeonEntity *pokemon) for (i = 0; i < MAX_MON_MOVES; i++) { struct PokemonMove *moves = pokemonData->moves; - if (moves[i].moveFlags & MOVE_FLAG_EXISTS && moves[i].sealed & TRUE) + if (moves[i].moveFlags & MOVE_FLAG_EXISTS && moves[i].moveFlags2 & MOVE_FLAG_SEALED) { return TRUE; } diff --git a/src/thank_you_wonder_mail.c b/src/thank_you_wonder_mail.c index 7e419b2..cdfb97a 100644 --- a/src/thank_you_wonder_mail.c +++ b/src/thank_you_wonder_mail.c @@ -10,6 +10,7 @@ #include "input.h" #include "text.h" #include "team_inventory.h" +#include "code_800D090.h" extern struct WonderMailStruct_203B2C4 *gUnknown_203B2C4; @@ -217,7 +218,6 @@ extern void sub_802F2C0(); extern u32 sub_80144A4(s32 *r0); extern void SetThankYouMailMenuState(u32); extern struct PokemonStruct *GetPlayerPokemonStruct(void); -extern void ExpandPlaceholdersBuffer(u8 *buffer, const char *text, ...); extern void SetMenuItems(void *menu, struct UnkTextStruct2 *, u32, const struct UnkTextStruct2 *, const struct MenuItem *entries, u32, u32, u32); extern void sub_80922B4(u8 *, u8 *, u32); extern void sub_802F204(struct unkStruct_802F204 *, u32); @@ -1286,7 +1286,7 @@ void UpdateThankYouMailText(void) case 5: pokeStruct = GetPlayerPokemonStruct(); sub_80922B4(auStack180,pokeStruct->name, POKEMON_NAME_LENGTH); - ExpandPlaceholdersBuffer(gUnknown_203B2C4->formattedString,gUnknown_80DF250,auStack180); + sprintf_2(gUnknown_203B2C4->formattedString,gUnknown_80DF250,auStack180); sub_80141B4(gUnknown_203B2C4->formattedString,0,&gUnknown_203B2C4->faceFile,0x10d); break; case 0xe: @@ -1445,7 +1445,7 @@ void UpdateThankYouMailText(void) case THANK_YOU_MAIL_COMMS_CLEANUP: pokeStruct2 = GetPlayerPokemonStruct(); sub_80922B4(auStack100, pokeStruct2->name, POKEMON_NAME_LENGTH); - ExpandPlaceholdersBuffer(gUnknown_203B2C4->formattedString,gUnknown_80DF63C,auStack100); + sprintf_2(gUnknown_203B2C4->formattedString,gUnknown_80DF63C,auStack100); sub_80141B4(gUnknown_203B2C4->formattedString,0,&gUnknown_203B2C4->faceFile,0x10d); break; case CONFIRM_ITEM_TO_SEND: diff --git a/src/type_chart.c b/src/type_chart.c new file mode 100644 index 0000000..ac2071c --- /dev/null +++ b/src/type_chart.c @@ -0,0 +1,27 @@ +#include "type_chart.h" + +#define IMMUNE EFFECTIVENESS_IMMUNE +#define RESIST EFFECTIVENESS_RESIST +#define NEUTRAL EFFECTIVENESS_NEUTRAL +#define SUPER EFFECTIVENESS_SUPER + +const s16 gTypeEffectivenessChart[NUM_TYPES][NUM_TYPES] = { + {NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL}, + {NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, RESIST, NEUTRAL, NEUTRAL, NEUTRAL, RESIST}, + {NEUTRAL, NEUTRAL, RESIST, RESIST, SUPER, NEUTRAL, SUPER, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, RESIST, NEUTRAL, RESIST, NEUTRAL, SUPER}, + {NEUTRAL, NEUTRAL, SUPER, RESIST, RESIST, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, NEUTRAL, RESIST, NEUTRAL, NEUTRAL}, + {NEUTRAL, NEUTRAL, RESIST, SUPER, RESIST, NEUTRAL, NEUTRAL, NEUTRAL, RESIST, SUPER, RESIST, NEUTRAL, RESIST, SUPER, NEUTRAL, RESIST, NEUTRAL, RESIST}, + {NEUTRAL, NEUTRAL, NEUTRAL, SUPER, RESIST, RESIST, NEUTRAL, NEUTRAL, NEUTRAL, IMMUNE, SUPER, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, RESIST, NEUTRAL, NEUTRAL}, + {NEUTRAL, NEUTRAL, RESIST, RESIST, SUPER, NEUTRAL, RESIST, NEUTRAL, NEUTRAL, SUPER, SUPER, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, NEUTRAL, RESIST}, + {NEUTRAL, SUPER, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, NEUTRAL, RESIST, NEUTRAL, RESIST, RESIST, RESIST, SUPER, NEUTRAL, NEUTRAL, SUPER, SUPER}, + {NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, NEUTRAL, NEUTRAL, NEUTRAL, RESIST, RESIST, NEUTRAL, NEUTRAL, NEUTRAL, RESIST, RESIST, NEUTRAL, NEUTRAL, IMMUNE}, + {NEUTRAL, NEUTRAL, SUPER, NEUTRAL, RESIST, SUPER, NEUTRAL, NEUTRAL, SUPER, NEUTRAL, IMMUNE, NEUTRAL, RESIST, SUPER, NEUTRAL, NEUTRAL, NEUTRAL, SUPER}, + {NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, RESIST, NEUTRAL, SUPER, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, RESIST, NEUTRAL, NEUTRAL, NEUTRAL, RESIST}, + {NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, SUPER, NEUTRAL, NEUTRAL, RESIST, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, IMMUNE, RESIST}, + {NEUTRAL, NEUTRAL, RESIST, NEUTRAL, SUPER, NEUTRAL, NEUTRAL, RESIST, RESIST, NEUTRAL, RESIST, SUPER, NEUTRAL, NEUTRAL, RESIST, NEUTRAL, SUPER, RESIST}, + {NEUTRAL, NEUTRAL, SUPER, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, RESIST, NEUTRAL, RESIST, SUPER, NEUTRAL, SUPER, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, RESIST}, + {NEUTRAL, IMMUNE, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, NEUTRAL, NEUTRAL, SUPER, NEUTRAL, RESIST, RESIST}, + {NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, NEUTRAL, RESIST}, + {NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, RESIST, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, NEUTRAL, NEUTRAL, SUPER, NEUTRAL, RESIST, RESIST}, + {NEUTRAL, NEUTRAL, RESIST, RESIST, NEUTRAL, RESIST, SUPER, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, NEUTRAL, SUPER, NEUTRAL, NEUTRAL, NEUTRAL, RESIST} +}; diff --git a/src/type_effectiveness.c b/src/type_effectiveness.c new file mode 100644 index 0000000..8a9ee04 --- /dev/null +++ b/src/type_effectiveness.c @@ -0,0 +1,174 @@ +#include "global.h" +#include "type_effectiveness.h" + +#include "constants/ability.h" +#include "constants/status.h" +#include "constants/weather.h" +#include "dungeon_global_data.h" +#include "dungeon_pokemon_attributes.h" +#include "dungeon_util.h" +#include "status.h" +#include "type_chart.h" +#include "weather.h" + +u32 gTypeEffectivenessMultipliers[] = {0, 1, 2, 4}; + +s32 WeightWeakTypePicker(struct DungeonEntity *user, struct DungeonEntity *target, u8 moveType) +{ + s32 weight = 1; + bool8 checkExposed = FALSE; + struct DungeonEntityData *userData; + struct DungeonEntityData *targetData; + u8 *targetTypes; + u8 *targetType; + u32 moveTypeOffset; + if (!EntityExists(target)) + { + return 1; + } + if (moveType == TYPE_NORMAL || moveType == TYPE_FIGHTING) + { + checkExposed = TRUE; + } + userData = user->entityData; + targetData = target->entityData; + if (moveType == TYPE_FIRE && GetFlashFireStatus(target) != FLASH_FIRE_STATUS_NONE) + { + return 0; + } + if (moveType == TYPE_ELECTRIC && HasAbility(target, ABILITY_VOLT_ABSORB)) + { + return 0; + } + if (moveType == TYPE_WATER && HasAbility(target, ABILITY_WATER_ABSORB)) + { + return 0; + } + if (moveType == TYPE_GROUND && HasAbility(target, ABILITY_LEVITATE)) + { + return 1; + } + targetTypes = targetData->types; + moveTypeOffset = moveType * NUM_TYPES * sizeof(s16); + targetType = targetData->types; + do + { + s32 effectiveness; + u32 typeEffectivenessMultipliers[NUM_EFFECTIVENESS]; + memcpy(typeEffectivenessMultipliers, gTypeEffectivenessMultipliers, NUM_EFFECTIVENESS * sizeof(u32)); + if (checkExposed && *targetType == TYPE_GHOST && !targetData->exposedStatus) + { + effectiveness = 0; + gDungeonGlobalData->pokemonExposed = TRUE; + } + else + { + effectiveness = gTypeEffectivenessChart[moveType][*targetType]; + // Used to swap variable initialization order at the loop start. + effectiveness = *(s16*)(((s8*) gTypeEffectivenessChart) + moveTypeOffset + *targetType * 2); + } + if (weight == 0) + { + goto breakLoop; + } + weight *= typeEffectivenessMultipliers[effectiveness]; + weight /= 2; + if (weight == 0) + { + // BUG: If the Pokémon's first type resists the move, the second type is ignored. + // This calculates type effectiveness incorrectly if the first type resists the move and the second type is weak to the move. + // For example, a Fire-type move is considered not very effective against a Rock/Bug-type like Anorith. + return 2; + } + } while ((s32)(++targetType) <= (s32)(targetTypes + 1)); + breakLoop: + if ((moveType == TYPE_FIRE || moveType == TYPE_ICE) && HasAbility(target, ABILITY_THICK_FAT)) + { + return 2; + } + if (moveType == TYPE_WATER && HasAbility(user, ABILITY_TORRENT)) + { + s32 maxHP = userData->maxHP; + if (maxHP < 0) + { + maxHP += 3; + } + if (maxHP >> 2 >= userData->HP) + { + weight *= 2; + } + } + if (moveType == TYPE_GRASS && HasAbility(user, ABILITY_OVERGROW)) + { + s32 maxHP = userData->maxHP; + if (maxHP < 0) + { + maxHP += 3; + } + if (maxHP >> 2 >= userData->HP) + { + weight *= 2; + } + } + if (moveType == TYPE_BUG && HasAbility(user, ABILITY_SWARM)) + { + s32 maxHP = userData->maxHP; + if (maxHP < 0) + { + maxHP += 3; + } + if (maxHP >> 2 >= userData->HP) + { + weight *= 2; + } + } + if (moveType == TYPE_FIRE && HasAbility(user, ABILITY_BLAZE)) + { + s32 maxHP = userData->maxHP; + if (maxHP < 0) + { + maxHP += 3; + } + if (maxHP >> 2 >= userData->HP) + { + weight *= 2; + } + } + if (weight == 0) + { + return 2; + } + if (HasType(user, moveType)) + { + weight *= 2; + } + targetTypes = targetData->types; + if (GetWeather(user) == WEATHER_SUNNY) + { + if (moveType == TYPE_FIRE) + { + weight *= 2; + } + else if (moveType == TYPE_WATER) + { + return 2; + } + } + if (gDungeonGlobalData->mudSportTurnsLeft != 0 && moveType == TYPE_ELECTRIC) + { + return 2; + } + if (gDungeonGlobalData->waterSportTurnsLeft != 0 && moveType == TYPE_FIRE) + { + return 2; + } + if (moveType == TYPE_ELECTRIC && userData->chargingStatus == CHARGING_STATUS_CHARGE) + { + weight *= 2; + } + if (weight > 2) + { + weight = 3; + } + return weight + 2; +} diff --git a/src/wonder_mail_2.c b/src/wonder_mail_2.c index 816dba2..6c90992 100644 --- a/src/wonder_mail_2.c +++ b/src/wonder_mail_2.c @@ -10,6 +10,7 @@ #include "sub_8095228.h" #include "gUnknown_203B46C.h" #include "wonder_mail.h" +#include "code_800D090.h" struct unkStruct_203B2C8 { @@ -139,7 +140,6 @@ extern void sub_802B5B8(void); extern void sub_802B5FC(void); extern void sub_802B624(void); -void ExpandPlaceholdersBuffer(u8 *buffer, const char *text, ...); extern void sub_802F204(struct unkStruct_802F204 *, u32); extern void sub_803C37C(u8 *, u32, u8 *); extern u32 sub_803C200(u8 *, u32); @@ -374,7 +374,7 @@ void sub_802B3E0(void) strcpy(teamNameBuffer,gRescueTeamNamePlaceholder); } // Print and expand placeholders? - ExpandPlaceholdersBuffer(gUnknown_203B2C8->teamName,gUnknown_80DF9F8,teamNameBuffer); + sprintf_2(gUnknown_203B2C8->teamName,gUnknown_80DF9F8,teamNameBuffer); // Display to screen with Pelipper face sub_80141B4(gUnknown_203B2C8->teamName, 0, &gUnknown_203B2C8->faceFile, 0x10d); break; |