summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/code_800D090.c3
-rw-r--r--src/code_801D760.c16
-rw-r--r--src/code_8090208.c10
-rw-r--r--src/dungeon_action.c7
-rw-r--r--src/dungeon_ai_attack.c417
-rw-r--r--src/dungeon_ai_attack_1.c175
-rw-r--r--src/dungeon_ai_attack_2.c76
-rw-r--r--src/dungeon_ai_items.c3
-rw-r--r--src/dungeon_ai_movement.c3
-rw-r--r--src/dungeon_pokemon_attributes.c6
-rw-r--r--src/friend_area.c6
-rw-r--r--src/friend_list_menu.c4
-rw-r--r--src/items.c20
-rw-r--r--src/kecleon_items_1.c14
-rw-r--r--src/load_screen.c34
-rw-r--r--src/move_util.c88
-rw-r--r--src/moves.c28
-rw-r--r--src/moves_1.c4
-rw-r--r--src/pokemon_mid.c16
-rw-r--r--src/status.c19
-rw-r--r--src/status_checker.c447
-rw-r--r--src/status_checks_1.c2
-rw-r--r--src/thank_you_wonder_mail.c6
-rw-r--r--src/type_chart.c27
-rw-r--r--src/type_effectiveness.c174
-rw-r--r--src/wonder_mail_2.c4
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;