mirror of
https://github.com/pret/pmd-red.git
synced 2026-10-05 08:56:58 -04:00
1575 lines
58 KiB
C
1575 lines
58 KiB
C
#include "global.h"
|
|
#include "globaldata.h"
|
|
#include "dungeon_damage.h"
|
|
#include "constants/ability.h"
|
|
#include "structs/str_dungeon.h"
|
|
#include "dungeon_logic.h"
|
|
#include "dungeon_move.h"
|
|
#include "pokemon_types.h"
|
|
#include "dungeon_message.h"
|
|
#include "string_format.h"
|
|
#include "constants/dungeon_exit.h"
|
|
#include "constants/move_id.h"
|
|
#include "constants/monster.h"
|
|
#include "constants/residual_damage.h"
|
|
#include "constants/status.h"
|
|
#include "constants/type.h"
|
|
#include "constants/iq_skill.h"
|
|
#include "math.h"
|
|
#include "number_util.h"
|
|
#include "dungeon_random.h"
|
|
#include "dungeon_items.h"
|
|
#include "dungeon_info.h"
|
|
#include "dungeon_util.h"
|
|
#include "dungeon_config.h"
|
|
#include "dungeon_strings.h"
|
|
#include "dungeon_misc.h"
|
|
#include "dungeon_leveling.h"
|
|
#include "weather.h"
|
|
#include "game_options.h"
|
|
#include "dungeon_mon_sprite_render.h"
|
|
#include "constants/direction.h"
|
|
#include "constants/dungeon.h"
|
|
#include "dungeon_vram.h"
|
|
#include "dungeon_8041AD0.h"
|
|
#include "code_805D8C8.h"
|
|
#include "dungeon_map_access.h"
|
|
#include "dungeon_data.h"
|
|
#include "move_orb_effects_1.h"
|
|
#include "pokemon.h"
|
|
#include "position_util.h"
|
|
#include "random.h"
|
|
#include "sprite.h"
|
|
#include "exclusive_pokemon.h"
|
|
#include "hurl_orb.h"
|
|
#include "dungeon_mon_spawn.h"
|
|
#include "dungeon_mon_recruit.h"
|
|
#include "move_orb_actions_1.h"
|
|
#include "move_orb_effects_2.h"
|
|
#include "move_orb_effects_5.h"
|
|
#include "dungeon_tilemap.h"
|
|
#include "effect_main.h"
|
|
|
|
static bool8 HandleDealingDamageInternal_Async(Entity *attacker, Entity *target, struct DamageStruct *r5, bool32 isFalseSwipe, bool32 giveExp, s16 dungeonExitReason_, s32 arg8);
|
|
static bool8 sub_806E100(s48_16 *param_1, Entity *pokemon, Entity *target, u8 type, DamageStruct *dmgStruct);
|
|
static void ResetDamageCalcWorkingValues(void);
|
|
static void sub_806F63C(Entity *param_1);
|
|
|
|
static const u32 gUnknown_8106EFC[] = { 0, 0 };
|
|
static const s48_16 gUnknown_8106F04 = { 0x0, 0x10000 };
|
|
static const s48_16 gUnknown_8106F0C = { 0x0, 0x20000 };
|
|
static const s48_16 gUnknown_8106F14 = { 0x0, 0x18000 };
|
|
static const s48_16 gUnknown_8106F1C = { 0x0, 0x8000 };
|
|
static const s48_16 gUnknown_8106F24 = { 0x0, 0x3E70000 };
|
|
UNUSED static const s48_16 sUnusedModifier1 = { 0, 0xC000 };
|
|
UNUSED static const s48_16 sUnusedModifier2 = { 0x0, 0x17FFE };
|
|
static const s48_16 gUnknown_8106F3C = {0x0, 0x8000};
|
|
static const s48_16 gUnknown_8106F44 = {0x0, 0xE666};
|
|
static const s48_16 gUnknown_8106F4C = {0x0, 0x18000};
|
|
|
|
void HandleDealingDamage_Async(Entity *attacker, Entity *target, struct DamageStruct *dmgStruct, bool32 isFalseSwipe, bool32 giveExp, s16 dungeonExitReason_, bool32 arg8, s32 argC)
|
|
{
|
|
bool32 r9;
|
|
// Some compiler weirdness, because it won't match without creating dungeonExitReason_ again
|
|
s32 dungeonExitReason = dungeonExitReason_;
|
|
s32 returnDmg = 0;
|
|
|
|
if (HandleDealingDamageInternal_Async(attacker, target, dmgStruct, isFalseSwipe, giveExp, dungeonExitReason, argC))
|
|
return;
|
|
if (dmgStruct->tookNoDamage)
|
|
return;
|
|
if (!EntityIsValid(attacker) || !EntityIsValid(target))
|
|
return;
|
|
if (GetEntityType(attacker) != ENTITY_MONSTER || GetEntityType(target) != ENTITY_MONSTER)
|
|
return;
|
|
|
|
r9 = arg8;
|
|
if (CheckVariousStatuses(target) || GetEntInfo(target)->bideClassStatus.status != 0)
|
|
r9 = FALSE;
|
|
if (r9
|
|
&& abs(attacker->pos.x - target->pos.x) <= 1 && abs(attacker->pos.y - target->pos.y) <= 1
|
|
&& attacker != target
|
|
&& IsTypePhysical(dmgStruct->type)
|
|
&& GetEntInfo(target)->reflectClassStatus.status == STATUS_VITAL_THROW)
|
|
{
|
|
sub_8042730(target, attacker);
|
|
HandleHurlOrb(target, attacker);
|
|
}
|
|
|
|
if (GetEntInfo(target)->bideClassStatus.status == STATUS_ENRAGED) {
|
|
BoostOffensiveStat(attacker, target, gStatIndexAtkDef, 1);
|
|
}
|
|
|
|
if (!EntityIsValid(attacker) || !EntityIsValid(target))
|
|
return;
|
|
|
|
if (r9
|
|
&& attacker != target
|
|
&& abs(attacker->pos.x - target->pos.x) <= 1 && abs(attacker->pos.y - target->pos.y) <= 1)
|
|
{
|
|
bool32 isPhysical = IsTypePhysical(dmgStruct->type);
|
|
if (GetEntInfo(target)->reflectClassStatus.status == STATUS_COUNTER && isPhysical) {
|
|
sub_8041B18(target);
|
|
returnDmg += 4;
|
|
}
|
|
if (GetEntInfo(target)->reflectClassStatus.status == STATUS_MINI_COUNTER && isPhysical) {
|
|
sub_8041B18(target);
|
|
returnDmg += 1;
|
|
}
|
|
if (GetEntInfo(target)->reflectClassStatus.status == STATUS_MIRROR_COAT && !isPhysical) {
|
|
sub_8041B90(target);
|
|
returnDmg += 4;
|
|
}
|
|
|
|
if (AbilityIsActive(target, ABILITY_ROUGH_SKIN))
|
|
returnDmg += 2;
|
|
|
|
if (returnDmg) {
|
|
struct DamageStruct sp;
|
|
|
|
TryDisplayDungeonLoggableMessage3_Async(attacker, target, gUnknown_80FCFA4);
|
|
sp.dmg = (dmgStruct->dmg * returnDmg) / 4;
|
|
sp.type = dmgStruct->type;
|
|
sp.residualDmgType = RESIDUAL_DAMAGE_COUNTERATTACK;
|
|
sp.typeEffectiveness = 2;
|
|
sp.isCrit = FALSE;
|
|
sp.unkE = 0;
|
|
sp.tookNoDamage = FALSE;
|
|
HandleDealingDamageInternal_Async(target, attacker, &sp, FALSE, giveExp, dungeonExitReason, argC);
|
|
}
|
|
}
|
|
if (!EntityIsValid(attacker) || !EntityIsValid(target))
|
|
return;
|
|
|
|
// Check trapping / contact abilities
|
|
if (r9
|
|
&& attacker != target
|
|
&& abs(attacker->pos.x - target->pos.x) <= 1 && abs(attacker->pos.y - target->pos.y) <= 1)
|
|
{
|
|
bool32 isPhysical = IsTypePhysical(dmgStruct->type);
|
|
EntityInfo *attackerInfo = GetEntInfo(attacker);
|
|
|
|
if (AbilityIsActive(target, ABILITY_ARENA_TRAP)
|
|
&& !MonsterIsType(attacker, TYPE_FLYING)
|
|
&& !AbilityIsActive(attacker, ABILITY_LEVITATE)
|
|
&& DungeonRandInt(100) < gArenaTrapActivateChance)
|
|
{
|
|
attackerInfo->abilityEffectFlags |= ABILITY_FLAG_ARENA_TRAP;
|
|
}
|
|
if (AbilityIsActive(target, ABILITY_SHADOW_TAG)
|
|
&& DungeonRandInt(100) < gShadowTagActivateChance)
|
|
{
|
|
attackerInfo->abilityEffectFlags |= ABILITY_FLAG_SHADOW_TAG;
|
|
}
|
|
if (AbilityIsActive(target, ABILITY_MAGNET_PULL)
|
|
&& MonsterIsType(attacker, TYPE_STEEL)
|
|
&& DungeonRandInt(100) < gMagnetPullActivateChance)
|
|
{
|
|
attackerInfo->abilityEffectFlags |= ABILITY_FLAG_MAGNET_PULL;
|
|
}
|
|
|
|
if (AbilityIsActive(target, ABILITY_STATIC)
|
|
&& isPhysical
|
|
&& DungeonRandInt(100) < gStaticActivateChance)
|
|
{
|
|
attackerInfo->abilityEffectFlags |= ABILITY_FLAG_STATIC;
|
|
}
|
|
if (AbilityIsActive(target, ABILITY_POISON_POINT)
|
|
&& DungeonRandInt(100) < gPoisonPointActivateChance)
|
|
{
|
|
attackerInfo->abilityEffectFlags |= ABILITY_FLAG_POISON_POINT;
|
|
}
|
|
if (AbilityIsActive(target, ABILITY_EFFECT_SPORE)
|
|
&& isPhysical
|
|
&& DungeonRandInt(100) < gEffectSporeActivateChance)
|
|
{
|
|
s32 rnd = DungeonRandInt(3);
|
|
if (rnd < 1)
|
|
attackerInfo->abilityEffectFlags |= ABILITY_FLAG_EFFECT_SPORE_PSN;
|
|
else if (rnd < 2)
|
|
attackerInfo->abilityEffectFlags |= ABILITY_FLAG_EFFECT_SPORE_PRLZ;
|
|
else
|
|
attackerInfo->abilityEffectFlags |= ABILITY_FLAG_EFFECT_SPORE_SLP;
|
|
}
|
|
if (AbilityIsActive(target, ABILITY_FLAME_BODY)
|
|
&& DungeonRandInt(100) < gFlameBodyActivateChance)
|
|
{
|
|
attackerInfo->abilityEffectFlags |= ABILITY_FLAG_FLAME_BODY;
|
|
}
|
|
if (AbilityIsActive(target, ABILITY_CUTE_CHARM)
|
|
&& isPhysical
|
|
&& DungeonRandInt(100) < gCuteCharmActivateChance)
|
|
{
|
|
attackerInfo->abilityEffectFlags |= ABILITY_FLAG_CUTE_CHARM;
|
|
}
|
|
if (AbilityIsActive(target, ABILITY_STENCH)
|
|
&& DungeonRandInt(100) < gStenchActivateChance)
|
|
{
|
|
attackerInfo->abilityEffectFlags |= ABILITY_FLAG_STENCH;
|
|
}
|
|
}
|
|
if (!EntityIsValid(attacker) || !EntityIsValid(target))
|
|
return;
|
|
|
|
// Destiny Bond
|
|
if (r9) {
|
|
EntityInfo *targetInfo = GetEntInfo(target);
|
|
if (targetInfo->leechSeedClassStatus.status == STATUS_DESTINY_BOND) {
|
|
Entity *destBondTarget = gDungeon->activePokemon[targetInfo->leechSeedClassStatus.unk8];
|
|
if (destBondTarget == NULL) {
|
|
targetInfo->leechSeedClassStatus.status = 0;
|
|
}
|
|
else if (GetEntInfo(destBondTarget)->dungeonSpriteId != targetInfo->leechSeedClassStatus.unk4) {
|
|
targetInfo->leechSeedClassStatus.status = 0;
|
|
}
|
|
else {
|
|
sub_8041D00(destBondTarget, target);
|
|
DealDamageToEntity_Async(destBondTarget, dmgStruct->dmg, RESIDUAL_DAMAGE_DESTINY_BOND, DUNGEON_EXIT_FAINTED_FROM_DESTINY_BOND);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline u32 ItemId(Item *item)
|
|
{
|
|
return item->id;
|
|
}
|
|
|
|
static bool8 HandleDealingDamageInternal_Async(Entity *attacker, Entity *target, struct DamageStruct *dmgStruct, bool32 isFalseSwipe, bool32 giveExp, s16 dungeonExitReason_, s32 arg8)
|
|
{
|
|
s32 hpBefore, hpChange;
|
|
EntityInfo *targetData;
|
|
s32 dungeonExitReason = dungeonExitReason_;
|
|
bool32 var_24 = FALSE;
|
|
bool32 r10 = FALSE;
|
|
s32 r8 = 0;
|
|
Tile *unkTile = NULL;
|
|
|
|
dmgStruct->tookNoDamage = FALSE;
|
|
if (GetEntityType(target) != ENTITY_MONSTER) {
|
|
dmgStruct->tookNoDamage = TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
targetData = GetEntInfo(target);
|
|
TrySendImmobilizeSleepEndMsg(attacker, target);
|
|
SetShopkeeperAggression(attacker, target);
|
|
if (GetEntityType(attacker) == ENTITY_MONSTER
|
|
&& GetEntInfo(attacker)->sureShotClassStatus.status == STATUS_SET_DAMAGE
|
|
&& dmgStruct->unkE == 0)
|
|
{
|
|
dmgStruct->dmg = gSetDamageDmgValue;
|
|
}
|
|
|
|
if (dungeonExitReason != DUNGEON_EXIT_FAINTED_FROM_PERISH_SONG && AbilityIsActive(target, ABILITY_STURDY) && dmgStruct->dmg == 9999) {
|
|
SubstitutePlaceholderStringTags(gFormatBuffer_Monsters[1], target, 0);
|
|
TryDisplayDungeonLoggableMessage3_Async(attacker, target, gUnknown_80FCA90);
|
|
sub_8042238(attacker, target);
|
|
dmgStruct->tookNoDamage = TRUE;
|
|
return FALSE;
|
|
}
|
|
if (targetData->frozenClassStatus.status == STATUS_FROZEN) {
|
|
SubstitutePlaceholderStringTags(gFormatBuffer_Monsters[1], target, 0);
|
|
TryDisplayDungeonLoggableMessage3_Async(attacker, target, gUnknown_80F9600);
|
|
sub_8042238(attacker, target);
|
|
dmgStruct->tookNoDamage = TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
if ((targetData->sleepClassStatus.status == STATUS_SLEEP || targetData->sleepClassStatus.status == STATUS_NAPPING || targetData->sleepClassStatus.status == STATUS_NIGHTMARE)
|
|
&& targetData->sleepClassStatus.turns == 0x7F)
|
|
{
|
|
WakeUpPokemon(target);
|
|
}
|
|
|
|
if ((AbilityIsActive(target, ABILITY_VOLT_ABSORB) && dmgStruct->type == TYPE_ELECTRIC)) {
|
|
HealTargetHP(attacker, target, dmgStruct->dmg, 0, 0);
|
|
dmgStruct->tookNoDamage = TRUE;
|
|
return FALSE;
|
|
}
|
|
else if (AbilityIsActive(target, ABILITY_WATER_ABSORB) && dmgStruct->type == TYPE_WATER) {
|
|
HealTargetHP(attacker, target, dmgStruct->dmg, 0, 0);
|
|
dmgStruct->tookNoDamage = TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
if (targetData->unk152 == 0) {
|
|
if (dmgStruct->isCrit) {
|
|
TryDisplayDungeonLoggableMessage3_Async(attacker, target, gUnknown_80F9614);
|
|
}
|
|
switch (dmgStruct->typeEffectiveness) {
|
|
case EFFECTIVENESS_IMMUNE:
|
|
TryDisplayDungeonLoggableMessage3_Async(attacker, target, gUnknown_80F9630);
|
|
break;
|
|
case EFFECTIVENESS_RESIST:
|
|
TryDisplayDungeonLoggableMessage3_Async(attacker, target, gUnknown_80F9654);
|
|
break;
|
|
case EFFECTIVENESS_SUPER:
|
|
TryDisplayDungeonLoggableMessage3_Async(attacker, target, gUnknown_80F9670);
|
|
break;
|
|
}
|
|
}
|
|
|
|
SubstitutePlaceholderStringTags(gFormatBuffer_Monsters[0], attacker, 0);
|
|
SubstitutePlaceholderStringTags(gFormatBuffer_Monsters[1], target, 0);
|
|
if (dmgStruct->dmg == 0) {
|
|
if (ShouldDisplayEntity(attacker) && ShouldDisplayEntity(target)) {
|
|
if (targetData->unk152 == 0) {
|
|
TryDisplayDungeonLoggableMessage3_Async(attacker, target, gUnknown_80F9688);
|
|
}
|
|
sub_8042238(attacker, target);
|
|
}
|
|
else {
|
|
if (targetData->unk152 == 0) {
|
|
TryDisplayDungeonLoggableMessage3_Async(attacker, target, gUnknown_80F9688);
|
|
}
|
|
DungeonWaitFrames_Async(0x1E, 0x18);
|
|
}
|
|
dmgStruct->tookNoDamage = TRUE;
|
|
return FALSE;
|
|
}
|
|
else if (dmgStruct->dmg == 9999) {
|
|
if (arg8 != 0 && ShouldDisplayEntity(target)) {
|
|
unkTile = GetTileAtEntitySafe(target);
|
|
DungeonWaitFrames_Async(0x14, 0x18);
|
|
unkTile->spawnOrVisibilityFlags.spawn |= SPAWN_FLAG_TRAP;
|
|
UpdateTrapsVisibility();
|
|
}
|
|
if (targetData->unk152 == 0) {
|
|
TryDisplayDungeonLoggableMessage3_Async(attacker, target, gUnknown_80F96A8);
|
|
}
|
|
targetData->unkA0 = 999;
|
|
}
|
|
else {
|
|
const u8 *str;
|
|
|
|
gFormatArgs[0] = dmgStruct->dmg;
|
|
str = gResidualDamageMessages[dmgStruct->residualDmgType];
|
|
|
|
ASM_MATCH_TRICK(dmgStruct);
|
|
|
|
targetData->unkA0 += dmgStruct->dmg;
|
|
if (targetData->unkA0 > 999)
|
|
targetData->unkA0 = 999;
|
|
|
|
if (ShouldDisplayEntity(target)) {
|
|
if (dmgStruct->residualDmgType != RESIDUAL_DAMAGE_HUNGER) {
|
|
sub_803ED30(-dmgStruct->dmg, target, 1, -1);
|
|
}
|
|
if (targetData->unk152 == 0 && str != NULL) {
|
|
TryDisplayDungeonLoggableMessage3_Async(attacker, target, str);
|
|
}
|
|
}
|
|
else {
|
|
if (targetData->unk152 == 0 && str != NULL) {
|
|
TryDisplayDungeonLoggableMessage3_Async(attacker, target, str);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((dmgStruct->residualDmgType != RESIDUAL_DAMAGE_HUNGER || targetData->HP <= 1) && unkTile == NULL && ShouldDisplayEntity(target)) {
|
|
if ((attacker->pos.x != target->pos.x || attacker->pos.y != target->pos.y) && GetEntityType(attacker) == ENTITY_MONSTER) {
|
|
bool32 unkBool = FALSE;
|
|
if (targetData->isTeamLeader) {
|
|
if (gGameOptionsRef->damageTurn != 0 && !sub_806A458(target)) {
|
|
if (CanSeeTarget(target, attacker))
|
|
unkBool = TRUE;
|
|
else
|
|
unkBool = FALSE;
|
|
}
|
|
}
|
|
else {
|
|
unkBool = FALSE;
|
|
}
|
|
if (targetData->blinkerClassStatus.status == STATUS_BLINKER || targetData->blinkerClassStatus.status == STATUS_CROSS_EYED)
|
|
unkBool = FALSE;
|
|
if (unkBool) {
|
|
EntityInfo *info = GetEntInfo(target);
|
|
info->action.direction = (GetDirectionTowardsPosition(&target->pos, &attacker->pos) & DIRECTION_MASK);
|
|
}
|
|
TargetTileInFront(target);
|
|
}
|
|
sub_806CDD4(target, 6, GetEntInfo(target)->action.direction);
|
|
sub_80420E8(target, dmgStruct);
|
|
var_24 = TRUE;
|
|
}
|
|
|
|
// HP goes down
|
|
hpBefore = targetData->HP;
|
|
if (targetData->HP > dmgStruct->dmg)
|
|
targetData->HP -= dmgStruct->dmg;
|
|
else
|
|
targetData->HP = 0;
|
|
|
|
if (targetData->reflectClassStatus.status == STATUS_ENDURING) {
|
|
if (targetData->HP == 0) {
|
|
targetData->HP = 1;
|
|
TryDisplayDungeonLoggableMessage3_Async(attacker, target, gUnknown_8100548);
|
|
}
|
|
}
|
|
else if (isFalseSwipe == TRUE && targetData->HP == 0) {
|
|
targetData->HP = 1;
|
|
TryDisplayDungeonLoggableMessage3_Async(attacker, target, gUnknown_810056C);
|
|
}
|
|
|
|
hpChange = hpBefore - targetData->HP;
|
|
if (hpChange < 0)
|
|
hpChange = 0;
|
|
|
|
if (var_24 || unkTile != NULL)
|
|
DungeonWaitFrames_Async(0xA, 0x18);
|
|
|
|
if (targetData->HP != 0) {
|
|
if (var_24) {
|
|
sub_806CE68(target, 8);
|
|
}
|
|
if (HasHeldItem(target, ITEM_JOY_RIBBON) && hpChange > 0 && dmgStruct->dmg != 9999) {
|
|
AddExpPoints(attacker, target, hpChange);
|
|
}
|
|
|
|
if (unkTile != NULL)
|
|
{
|
|
unkTile->spawnOrVisibilityFlags.spawn &= ~(SPAWN_FLAG_TRAP);
|
|
UpdateTrapsVisibility();
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// 0 HP
|
|
if (targetData->invisibleClassStatus.status == STATUS_TRANSFORMED) {
|
|
SendTransformEndMessage(attacker, target);
|
|
}
|
|
|
|
if (unkTile != NULL) {
|
|
DungeonWaitFrames_Async(0x14, 0x18);
|
|
target->unk22 = 2;
|
|
DungeonWaitFrames_Async(0xA, 0x18);
|
|
unkTile->spawnOrVisibilityFlags.spawn &= ~(SPAWN_FLAG_TRAP);
|
|
UpdateTrapsVisibility();
|
|
}
|
|
else if (var_24) {
|
|
target->unk22 = 1;
|
|
DungeonWaitFrames_Async(0x1E, 0x18);
|
|
}
|
|
|
|
r8 = 1;
|
|
if (EntityIsValid(attacker) && GetEntityType(attacker) == ENTITY_MONSTER && attacker != target)
|
|
r8 = 0;
|
|
|
|
targetData->unk14C = 0;
|
|
SubstitutePlaceholderStringTags(gFormatBuffer_Monsters[0], attacker, 0);
|
|
SubstitutePlaceholderStringTags(gFormatBuffer_Monsters[1], target, 0);
|
|
if (dmgStruct->residualDmgType == RESIDUAL_DAMAGE_MOVE_FAIL || dmgStruct->residualDmgType == RESIDUAL_DAMAGE_RECOIL) {
|
|
if (targetData->isNotTeamMember) {
|
|
TryDisplayDungeonLoggableMessage3_Async(attacker, target, gUnknown_80F9E44);
|
|
}
|
|
else {
|
|
DisplayDungeonLoggableMessageTrue_Async(attacker, gUnknown_80F9E44);
|
|
}
|
|
}
|
|
else if (targetData->isNotTeamMember)
|
|
{
|
|
if (targetData->monsterBehavior == BEHAVIOR_RESCUE_TARGET) {
|
|
DisplayDungeonLoggableMessageTrue_Async(attacker, gUnknown_80F9DF0[r8]);
|
|
}
|
|
else {
|
|
TryDisplayDungeonLoggableMessage3_Async(attacker, target, gUnknown_80F9CC0[r8]);
|
|
}
|
|
}
|
|
else {
|
|
DungeonMon *recruitedMon = &gRecruitedPokemonRef->dungeonTeam[targetData->teamIndex];
|
|
if (targetData->isTeamLeader || (targetData->joinedAt.id == DUNGEON_JOIN_LOCATION_PARTNER && !gDungeon->unk644.canChangeLeader)) {
|
|
DisplayDungeonLoggableMessageTrue_Async(attacker, gUnknown_80F9CEC[r8]);
|
|
}
|
|
else if (IsExperienceLocked(targetData->joinedAt.id)) {
|
|
DisplayDungeonLoggableMessageTrue_Async(attacker, gUnknown_80F9DAC[r8]);
|
|
}
|
|
else if (targetData->monsterBehavior == BEHAVIOR_RESCUE_TARGET) {
|
|
DisplayDungeonLoggableMessageTrue_Async(attacker, gUnknown_80F9DF0[r8]);
|
|
}
|
|
else if (sub_806A58C(recruitedMon->recruitedPokemonId)) {
|
|
if (gDungeon->unk644.unk19 != 0) {
|
|
DisplayDungeonLoggableMessageTrue_Async(attacker, gUnknown_80F9D8C[r8]);
|
|
}
|
|
else {
|
|
DisplayDungeonLoggableMessageTrue_Async(attacker, gUnknown_80F9D84[r8]);
|
|
}
|
|
}
|
|
else {
|
|
DisplayDungeonLoggableMessageTrue_Async(attacker, gUnknown_80F9D28[r8]);
|
|
}
|
|
}
|
|
|
|
if (targetData->frozenClassStatus.status == STATUS_WRAP || targetData->frozenClassStatus.status == STATUS_WRAPPED) {
|
|
sub_8076CB4(targetData->unk9C);
|
|
}
|
|
|
|
// Try revive items
|
|
if (targetData->heldItem.flags & ITEM_FLAG_EXISTS) {
|
|
// This do/while 0 loop has no effect other than matching asm, and can be removed.
|
|
do
|
|
{
|
|
if (!(ItemSticky(&targetData->heldItem)) && !(ItemInShop(&targetData->heldItem)) && ItemId(&targetData->heldItem) == ITEM_REVIVER_ORB) {
|
|
sub_8042148(target);
|
|
target->unk22 = 0;
|
|
targetData->HP = targetData->maxHPStat;
|
|
targetData->unk158 = 0;
|
|
targetData->unk14C = 1;
|
|
targetData->belly = targetData->maxBelly;
|
|
if (targetData->isTeamLeader) {
|
|
gDungeon->unk644.emptyBellyAlert = 0;
|
|
gDungeon->unk644.itemHoldersIdentified = 0;
|
|
}
|
|
ZeroOutItem(&targetData->heldItem);
|
|
if (targetData->curseClassStatus.status == STATUS_SNATCH) {
|
|
EndCurseClassStatus(attacker, target, STATUS_SNATCH);
|
|
}
|
|
else if (targetData->curseClassStatus.status == STATUS_DECOY) {
|
|
EndCurseClassStatus(attacker, target, STATUS_DECOY);
|
|
}
|
|
sub_8078084(target);
|
|
ResetMonEntityData(targetData, 0);
|
|
sub_800DBBC();
|
|
sub_806A390(target);
|
|
sub_806CCB4(target, sub_806CEBC(target));
|
|
UpdateStatusIconFlags(target);
|
|
SubstitutePlaceholderStringTags(gFormatBuffer_Monsters[1], target, 0);
|
|
DisplayDungeonLoggableMessageTrue_Async(attacker, gUnknown_80FD46C);
|
|
sub_806F63C(target);
|
|
return FALSE;
|
|
}
|
|
} while(0);
|
|
}
|
|
|
|
if (targetData->isTeamLeader)
|
|
{
|
|
Item *heldItem = &targetData->heldItem;
|
|
if (ItemExists(heldItem) && !(ItemSticky(heldItem)) && ItemId(heldItem) == ITEM_POSSESS_ORB ) {
|
|
s32 i;
|
|
Entity *teamMember;
|
|
|
|
for (i = 0; i < MAX_TEAM_MEMBERS; i++) {
|
|
teamMember = gDungeon->teamPokemon[i];
|
|
if (EntityIsValid(teamMember)
|
|
&& teamMember != target
|
|
&& CanSeeTarget(target, teamMember)
|
|
&& abs(teamMember->pos.x - target->pos.x) <= 1 && abs(teamMember->pos.y - target->pos.y) <= 1)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (i != MAX_TEAM_MEMBERS) {
|
|
DungeonPos monPos; // r4
|
|
|
|
sub_8042148(target);
|
|
|
|
monPos = teamMember->pos;
|
|
HandleFaint_Async(teamMember, DUNGEON_EXIT_WAS_POSSESSED, target);
|
|
sub_80694C0(target, monPos.x, monPos.y, 1);
|
|
UpdateEntityPixelPos(target, NULL);
|
|
target->unk22 = 0;
|
|
targetData->HP = targetData->maxHPStat;
|
|
sub_8042A24(target);
|
|
targetData->unk158 = 0;
|
|
targetData->unk14C = 1;
|
|
targetData->belly = targetData->maxBelly;
|
|
if (targetData->isTeamLeader) {
|
|
gDungeon->unk644.emptyBellyAlert = 0;
|
|
gDungeon->unk644.itemHoldersIdentified = 0;
|
|
}
|
|
ZeroOutItem(heldItem);
|
|
if (targetData->curseClassStatus.status == STATUS_SNATCH) {
|
|
EndCurseClassStatus(attacker, target, STATUS_SNATCH);
|
|
}
|
|
else if (targetData->curseClassStatus.status == STATUS_DECOY) {
|
|
EndCurseClassStatus(attacker, target, STATUS_DECOY);
|
|
}
|
|
sub_8078084(target);
|
|
ResetMonEntityData(targetData, 0);
|
|
sub_800DBBC();
|
|
sub_806A390(target);
|
|
sub_806CCB4(target, sub_806CEBC(target));
|
|
UpdateStatusIconFlags(target);
|
|
SubstitutePlaceholderStringTags(gFormatBuffer_Monsters[0], target, 0);
|
|
SubstitutePlaceholderStringTags(gFormatBuffer_Monsters[1], teamMember, 0);
|
|
DisplayDungeonLoggableMessageTrue_Async(attacker, gUnknown_80FD484);
|
|
sub_806F63C(target);
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (IqSkillIsEnabled(target, IQ_ITEM_MASTER)) {
|
|
s32 i; // r3
|
|
Item *reviverSeed = NULL; // r4
|
|
if (ItemExists(&targetData->heldItem) && !ItemSticky(&targetData->heldItem) && ItemId(&targetData->heldItem) == ITEM_REVIVER_SEED)
|
|
reviverSeed = &targetData->heldItem;
|
|
if (reviverSeed == NULL && !targetData->isNotTeamMember) {
|
|
for (i = 0; i < INVENTORY_SIZE; i++) {
|
|
Item *bagItem = &gTeamInventoryRef->teamItems[i];
|
|
if (!(bagItem->flags & ITEM_FLAG_EXISTS))
|
|
continue;
|
|
if (bagItem->flags & ITEM_FLAG_STICKY)
|
|
continue;
|
|
if (bagItem->id == ITEM_REVIVER_SEED) {
|
|
reviverSeed = bagItem;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (reviverSeed != NULL) {
|
|
sub_8042148(target);
|
|
CreateItemWithStickyChance(reviverSeed, ITEM_PLAIN_SEED, FORCE_STICKY_NEVER);
|
|
target->unk22 = 0;
|
|
targetData->HP = targetData->maxHPStat;
|
|
targetData->unk158 = 0;
|
|
targetData->unk14C = 1;
|
|
targetData->belly = targetData->maxBelly;
|
|
if (targetData->isTeamLeader) {
|
|
gDungeon->unk644.emptyBellyAlert = 0;
|
|
gDungeon->unk644.itemHoldersIdentified = 0;
|
|
}
|
|
if (targetData->curseClassStatus.status == STATUS_SNATCH) {
|
|
EndCurseClassStatus(attacker, target, STATUS_SNATCH);
|
|
}
|
|
else if (targetData->curseClassStatus.status == STATUS_DECOY) {
|
|
EndCurseClassStatus(attacker, target, STATUS_DECOY);
|
|
}
|
|
sub_8078084(target);
|
|
ResetMonEntityData(targetData, 0);
|
|
sub_800DBBC();
|
|
sub_806A390(target);
|
|
sub_806CCB4(target, sub_806CEBC(target));
|
|
UpdateStatusIconFlags(target);
|
|
SubstitutePlaceholderStringTags(gFormatBuffer_Monsters[1], target, 0);
|
|
DisplayDungeonLoggableMessageTrue_Async(attacker, gUnknown_80FD46C);
|
|
sub_806F63C(target);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (!targetData->isTeamLeader && ItemExists(&targetData->heldItem)) {
|
|
SpawnDroppedItemWrapper(target, &target->pos, &targetData->heldItem);
|
|
ZeroOutItem(&targetData->heldItem);
|
|
}
|
|
if (targetData->bossFlag) {
|
|
gDungeon->unk644.bossSongIndex = STOP_BGM;
|
|
}
|
|
|
|
// Give exp
|
|
r10 = FALSE;
|
|
if (GetEntityType(attacker) == ENTITY_MONSTER) {
|
|
EntityInfo *attackerData = GetEntInfo(attacker);
|
|
s32 exp = CalculateEXPGain(targetData->id, targetData->level);
|
|
switch (targetData->expMultiplier) {
|
|
case EXP_BOOSTED:
|
|
exp *= 3;
|
|
exp /= 2;
|
|
break;
|
|
case EXP_HALVED:
|
|
exp /= 2;
|
|
break;
|
|
}
|
|
if (exp == 0)
|
|
exp = 1;
|
|
if (attackerData->isTeamLeader) {
|
|
SetMonSeenFlag(targetData->id);
|
|
}
|
|
if (targetData->grudge) {
|
|
attackerData->unk14B = 1;
|
|
}
|
|
|
|
if (giveExp == TRUE) {
|
|
if (!attackerData->isNotTeamMember) {
|
|
if (targetData->isNotTeamMember) {
|
|
s32 i;
|
|
|
|
AddExpPoints(attacker, attacker, exp);
|
|
for (i = 0; i < MAX_TEAM_MEMBERS; i++) {
|
|
Entity *teamMember = gDungeon->teamPokemon[i];
|
|
if (EntityIsValid(teamMember) && teamMember != attacker) {
|
|
AddExpPoints(attacker, teamMember, exp);
|
|
}
|
|
}
|
|
r10 = TRUE;
|
|
}
|
|
}
|
|
else {
|
|
if (DoEnemiesEvolveWhenKOed(gDungeon->unk644.dungeonLocation.id)) {
|
|
attackerData->unk149 = 1;
|
|
gDungeon->unkD = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (EntityIsValid(attacker) && GetEntityType(attacker) == ENTITY_MONSTER && !GetEntInfo(attacker)->isTeamLeader)
|
|
r10 = FALSE;
|
|
|
|
if (r10) {
|
|
struct unkStruct_8069D4C sp;
|
|
|
|
sub_8069D4C(&sp, target);
|
|
if (TryRecruitMonster(attacker, target)) {
|
|
if (!MonsterJoinSequence_Async(attacker, target, &sp)) {
|
|
HandleFaint_Async(target, DUNGEON_EXIT_LEFT_WITHOUT_BEING_BEFRIENDED, attacker);
|
|
}
|
|
else {
|
|
gUnknown_202F221 = 1;
|
|
}
|
|
}
|
|
else {
|
|
HandleFaint_Async(target, dungeonExitReason, attacker);
|
|
}
|
|
}
|
|
else {
|
|
HandleFaint_Async(target, dungeonExitReason, attacker);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static bool8 sub_806E100(s48_16 *param_1, Entity *pokemon, Entity *target, u8 type, DamageStruct *dmgStruct)
|
|
{
|
|
bool8 torrentFlag;
|
|
bool8 overgrowFlag;
|
|
bool8 swarmFlag;
|
|
bool8 blazeFlag;
|
|
bool8 torrentVisualFlag;
|
|
bool8 overgrowVisualFlag;
|
|
bool8 swarmVisualFlag;
|
|
bool8 blazeVisualFlag;
|
|
bool8 bVar4;
|
|
EntityInfo *targetInfo;
|
|
s32 effectiveness;
|
|
s32 index;
|
|
s32 local_38 [2];
|
|
s32 hasWonderGuard;
|
|
s32 normalOrFightingType;
|
|
EntityInfo *pokemonInfo;
|
|
u8 weather;
|
|
s32 temp;
|
|
|
|
bVar4 = FALSE;
|
|
normalOrFightingType = FALSE;
|
|
pokemonInfo = GetEntInfo(pokemon);
|
|
targetInfo = GetEntInfo(target);
|
|
FP48_16_FromS32(param_1, 1);
|
|
dmgStruct->isCrit = 0;
|
|
dmgStruct->unkE = 0;
|
|
hasWonderGuard = FALSE;
|
|
if (!EntityIsValid(target)) {
|
|
return TRUE;
|
|
}
|
|
else {
|
|
if ((type == TYPE_NORMAL) || (type == TYPE_FIGHTING)) {
|
|
normalOrFightingType = TRUE;
|
|
}
|
|
if ((AbilityIsActive(target, ABILITY_WONDER_GUARD)) && (type != TYPE_NONE)) {
|
|
hasWonderGuard = TRUE;
|
|
}
|
|
dmgStruct->typeEffectiveness = EFFECTIVENESS_NEUTRAL;
|
|
for (index = 0; index < 2; index++) {
|
|
const s48_16 *local_48[] = {&gUnknown_8106F3C, &gUnknown_8106F44, &gUnknown_8106F04, &gUnknown_8106F4C};
|
|
if (F48_16_IsZero(param_1)) break;
|
|
if (((normalOrFightingType) && (targetInfo->types[index] == TYPE_GHOST)) && (targetInfo->exposed == FALSE)) {
|
|
effectiveness = EFFECTIVENESS_IMMUNE;
|
|
gDungeon->damageCalcWorkingValues.pokemonExposed = TRUE;
|
|
}
|
|
else {
|
|
effectiveness = gTypeEffectivenessChart[type][targetInfo->types[index]];
|
|
}
|
|
if (effectiveness != EFFECTIVENESS_NEUTRAL) {
|
|
F48_16_SMul(param_1,param_1,local_48[effectiveness]);
|
|
}
|
|
local_38[index] = effectiveness;
|
|
gDungeon->damageCalcWorkingValues.unk13C[index] = effectiveness;
|
|
}
|
|
|
|
dmgStruct->typeEffectiveness = gEffectivenessChart[local_38[0]][local_38[1]];
|
|
bVar4 = TRUE;
|
|
if ((dmgStruct->typeEffectiveness != EFFECTIVENESS_SUPER) && (bVar4 = FALSE, hasWonderGuard)) {
|
|
temp = gUnknown_8106EFC[1];
|
|
param_1->hi = gUnknown_8106EFC[0];
|
|
param_1->lo = temp;
|
|
}
|
|
|
|
if (((type == TYPE_FIRE) || (type == TYPE_ICE)) && (AbilityIsActive(target,ABILITY_THICK_FAT))) {
|
|
gDungeon->damageCalcWorkingValues.unk16D = TRUE;
|
|
F48_16_SMul(param_1,param_1, &gUnknown_8106F1C);
|
|
}
|
|
if ((type == TYPE_FIRE) && (GetFlashFireStatus(target) != FLASH_FIRE_STATUS_NONE)) {
|
|
gDungeon->damageCalcWorkingValues.fill16E[0] = TRUE;
|
|
FP48_16_FromS32(param_1,0);
|
|
dmgStruct->typeEffectiveness = EFFECTIVENESS_IMMUNE;
|
|
dmgStruct->isCrit = 0;
|
|
dmgStruct->unkE = 1;
|
|
bVar4 = FALSE;
|
|
}
|
|
if ((type == TYPE_GROUND) && (AbilityIsActive(target, ABILITY_LEVITATE))) {
|
|
gDungeon->damageCalcWorkingValues.fill16E[1] = TRUE;
|
|
FP48_16_FromS32(param_1,0);
|
|
dmgStruct->typeEffectiveness = EFFECTIVENESS_IMMUNE;
|
|
dmgStruct->isCrit = 0;
|
|
dmgStruct->unkE = 1;
|
|
bVar4 = FALSE;
|
|
}
|
|
if ((type == TYPE_WATER) && (AbilityIsActive(pokemon, ABILITY_TORRENT))) {
|
|
torrentFlag = pokemonInfo->maxHPStat / 4 >= pokemonInfo->HP;
|
|
torrentVisualFlag = SetVisualFlags(pokemonInfo,0x80,torrentFlag);
|
|
if (torrentFlag) {
|
|
gDungeon->damageCalcWorkingValues.fill16E[2] = TRUE;
|
|
F48_16_SMul(param_1,param_1, &gUnknown_8106F0C);
|
|
}
|
|
if (torrentVisualFlag) {
|
|
sub_80428EC(pokemon);
|
|
TryDisplayDungeonLoggableMessage3_Async(pokemon,target,gUnknown_80FEDA8);
|
|
}
|
|
}
|
|
if ((type == TYPE_GRASS) && (AbilityIsActive(pokemon, ABILITY_OVERGROW))) {
|
|
overgrowFlag = pokemonInfo->maxHPStat / 4 >= pokemonInfo->HP;
|
|
overgrowVisualFlag = SetVisualFlags(pokemonInfo,2,overgrowFlag);
|
|
if (overgrowFlag) {
|
|
gDungeon->damageCalcWorkingValues.fill16E[3] = TRUE;
|
|
F48_16_SMul(param_1,param_1, &gUnknown_8106F0C);
|
|
}
|
|
if (overgrowVisualFlag) {
|
|
sub_80428D8(pokemon);
|
|
TryDisplayDungeonLoggableMessage3_Async(pokemon,target,gUnknown_80FED88);
|
|
}
|
|
}
|
|
if ((type == TYPE_BUG) && (AbilityIsActive(pokemon, ABILITY_SWARM))) {
|
|
swarmFlag = pokemonInfo->maxHPStat / 4 >= pokemonInfo->HP;
|
|
swarmVisualFlag = SetVisualFlags(pokemonInfo,0x10,swarmFlag);
|
|
if (swarmFlag) {
|
|
gDungeon->damageCalcWorkingValues.fill16E[4] = TRUE;
|
|
F48_16_SMul(param_1,param_1, &gUnknown_8106F0C);
|
|
}
|
|
if (swarmVisualFlag) {
|
|
sub_8042978(pokemon);
|
|
TryDisplayDungeonLoggableMessage3_Async(pokemon,target,gUnknown_80FEDC8);
|
|
}
|
|
}
|
|
if ((type == TYPE_FIRE) && (AbilityIsActive(pokemon, ABILITY_BLAZE))) {
|
|
blazeFlag = pokemonInfo->maxHPStat / 4 >= pokemonInfo->HP;
|
|
blazeVisualFlag = SetVisualFlags(pokemonInfo,0x20,blazeFlag);
|
|
if (blazeFlag) {
|
|
gDungeon->damageCalcWorkingValues.fill16E[5] = TRUE;
|
|
F48_16_SMul(param_1,param_1, &gUnknown_8106F0C);
|
|
}
|
|
if (blazeVisualFlag) {
|
|
sub_804298C(pokemon);
|
|
TryDisplayDungeonLoggableMessage3_Async(pokemon,target,gUnknown_80FEDE8);
|
|
}
|
|
}
|
|
if (!(F48_16_IsZero(param_1)) && (MonsterIsType(pokemon, type))) {
|
|
gDungeon->damageCalcWorkingValues.fill16E[6] = TRUE;
|
|
F48_16_SMul(param_1,param_1, &gUnknown_8106F14);
|
|
}
|
|
weather = GetApparentWeather(pokemon);
|
|
if (weather == WEATHER_SUNNY) {
|
|
if (type == TYPE_FIRE) {
|
|
gDungeon->damageCalcWorkingValues.unk16C = TRUE;
|
|
F48_16_SMul(param_1,param_1, &gUnknown_8106F14);
|
|
}
|
|
else if (type == TYPE_WATER) {
|
|
gDungeon->damageCalcWorkingValues.unk16C = TRUE;
|
|
F48_16_SMul(param_1,param_1, &gUnknown_8106F1C);
|
|
}
|
|
}
|
|
if (weather == WEATHER_RAIN) {
|
|
if (type == TYPE_FIRE) {
|
|
gDungeon->damageCalcWorkingValues.unk16B = TRUE;
|
|
F48_16_SMul(param_1,param_1, &gUnknown_8106F1C);
|
|
}
|
|
else if (type == TYPE_WATER) {
|
|
gDungeon->damageCalcWorkingValues.unk16B = TRUE;
|
|
F48_16_SMul(param_1,param_1, &gUnknown_8106F14);
|
|
}
|
|
}
|
|
if ((weather == WEATHER_CLOUDY) && (type != TYPE_NORMAL)) {
|
|
static const s48_16 gUnknown_8106F64 = {0x0, 0xC000};
|
|
F48_16_SMul(param_1,param_1, &gUnknown_8106F64);
|
|
gDungeon->damageCalcWorkingValues.unk16A = TRUE;
|
|
}
|
|
if (((gDungeon->weather.mudSportTurns != 0) || (weather == WEATHER_FOG)) && (type == TYPE_ELECTRIC)) {
|
|
gDungeon->damageCalcWorkingValues.fill16E[7] = TRUE;
|
|
F48_16_SMul(param_1,param_1, &gUnknown_8106F1C);
|
|
}
|
|
if ((gDungeon->weather.waterSportTurns != 0) && (type == TYPE_FIRE)) {
|
|
gDungeon->damageCalcWorkingValues.fill16E[8] = TRUE;
|
|
F48_16_SMul(param_1,param_1, &gUnknown_8106F1C);
|
|
}
|
|
if ((type == TYPE_ELECTRIC) && (pokemonInfo->bideClassStatus.status == STATUS_CHARGING)) {
|
|
gDungeon->damageCalcWorkingValues.fill16E[9] = TRUE;
|
|
F48_16_SMul(param_1,param_1, &gUnknown_8106F0C);
|
|
}
|
|
}
|
|
return bVar4;
|
|
}
|
|
|
|
s32 WeightWeakTypePicker(Entity *user, Entity *target, u8 moveType)
|
|
{
|
|
s32 weight = 1;
|
|
s32 i;
|
|
bool8 checkExposed = FALSE;
|
|
EntityInfo *userData;
|
|
EntityInfo *targetData;
|
|
|
|
if (!EntityIsValid(target))
|
|
return 1;
|
|
|
|
if (moveType == TYPE_NORMAL || moveType == TYPE_FIGHTING)
|
|
checkExposed = TRUE;
|
|
|
|
userData = GetEntInfo(user);
|
|
targetData = GetEntInfo(target);
|
|
|
|
if (moveType == TYPE_FIRE && GetFlashFireStatus(target) != FLASH_FIRE_STATUS_NONE)
|
|
return 0;
|
|
if (moveType == TYPE_ELECTRIC && AbilityIsActive(target, ABILITY_VOLT_ABSORB))
|
|
return 0;
|
|
if (moveType == TYPE_WATER && AbilityIsActive(target, ABILITY_WATER_ABSORB))
|
|
return 0;
|
|
if (moveType == TYPE_GROUND && AbilityIsActive(target, ABILITY_LEVITATE))
|
|
return 1;
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
s32 effectiveness;
|
|
u32 typeEffectivenessMultipliers[NUM_EFFECTIVENESS] = {0, 1, 2, 4};
|
|
if (checkExposed && targetData->types[i] == TYPE_GHOST && !targetData->exposed) {
|
|
effectiveness = 0;
|
|
gDungeon->damageCalcWorkingValues.pokemonExposed = TRUE;
|
|
}
|
|
else {
|
|
effectiveness = gTypeEffectivenessChart[moveType][targetData->types[i]];
|
|
}
|
|
|
|
if (weight == 0)
|
|
break;
|
|
|
|
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;
|
|
}
|
|
|
|
if ((moveType == TYPE_FIRE || moveType == TYPE_ICE) && AbilityIsActive(target, ABILITY_THICK_FAT))
|
|
return 2;
|
|
|
|
if (moveType == TYPE_WATER && AbilityIsActive(user, ABILITY_TORRENT)) {
|
|
s32 maxHPStat = userData->maxHPStat;
|
|
if (maxHPStat / 4 >= userData->HP)
|
|
weight *= 2;
|
|
}
|
|
|
|
if (moveType == TYPE_GRASS && AbilityIsActive(user, ABILITY_OVERGROW)) {
|
|
s32 maxHPStat = userData->maxHPStat;
|
|
if (maxHPStat / 4 >= userData->HP)
|
|
weight *= 2;
|
|
}
|
|
|
|
if (moveType == TYPE_BUG && AbilityIsActive(user, ABILITY_SWARM)) {
|
|
s32 maxHPStat = userData->maxHPStat;
|
|
if (maxHPStat / 4 >= userData->HP)
|
|
weight *= 2;
|
|
}
|
|
|
|
if (moveType == TYPE_FIRE && AbilityIsActive(user, ABILITY_BLAZE)) {
|
|
s32 maxHPStat = userData->maxHPStat;
|
|
if (maxHPStat / 4 >= userData->HP)
|
|
weight *= 2;
|
|
}
|
|
|
|
if (weight == 0)
|
|
return 2;
|
|
|
|
if (MonsterIsType(user, moveType))
|
|
weight *= 2;
|
|
|
|
if (GetApparentWeather(user) == WEATHER_SUNNY) {
|
|
if (moveType == TYPE_FIRE)
|
|
weight *= 2;
|
|
else if (moveType == TYPE_WATER)
|
|
return 2;
|
|
}
|
|
|
|
if (gDungeon->weather.mudSportTurns != 0 && moveType == TYPE_ELECTRIC)
|
|
return 2;
|
|
|
|
if (gDungeon->weather.waterSportTurns != 0 && moveType == TYPE_FIRE)
|
|
return 2;
|
|
|
|
if (moveType == TYPE_ELECTRIC && userData->bideClassStatus.status == STATUS_CHARGING)
|
|
weight *= 2;
|
|
|
|
if (weight >= 3)
|
|
weight = 3;
|
|
|
|
return weight + 2;
|
|
}
|
|
|
|
static void ApplyAtkDefStatBoosts(Entity *attacker, Entity *target, u8 moveType, s32 *atkStat, s32 *defStat, s32 rand)
|
|
{
|
|
bool32 isNotEnemy;
|
|
s32 atkMultiplier = 1;
|
|
s32 atkDivisor = 1;
|
|
s32 defMultiplier = 1;
|
|
s32 defDivisor = 1;
|
|
s32 splitIndex = (!IsTypePhysical(moveType)) ? 1 : 0;
|
|
|
|
if (AbilityIsActive(attacker, ABILITY_GUTS)) {
|
|
EntityInfo *entInfo = GetEntInfo(attacker);
|
|
bool8 gutsBoost = MonsterHasNegativeStatus(attacker);
|
|
bool8 visFlags_attacker_1 = SetVisualFlags(entInfo,1,gutsBoost);
|
|
|
|
if (gutsBoost) {
|
|
atkMultiplier = 2;
|
|
}
|
|
if (visFlags_attacker_1) {
|
|
sub_80428B0(attacker);
|
|
TryDisplayDungeonLoggableMessage3_Async(attacker,target, gUnknown_80FEE04); // Guts boosted its power
|
|
}
|
|
}
|
|
|
|
if ((AbilityIsActive(attacker, ABILITY_HUGE_POWER)) || (AbilityIsActive(attacker, ABILITY_PURE_POWER))) {
|
|
EntityInfo *entInfo = GetEntInfo(attacker);
|
|
bool32 hugePowerBoost = (rand < 33 && splitIndex == 0);
|
|
bool8 visFlags_attacker_2 = SetVisualFlags(entInfo,0x100,hugePowerBoost);
|
|
|
|
if (hugePowerBoost) {
|
|
atkMultiplier *= 3;
|
|
atkDivisor *= 2;
|
|
}
|
|
if (visFlags_attacker_2) {
|
|
sub_80428C4(attacker);
|
|
TryDisplayDungeonLoggableMessage3_Async(attacker,target, gUnknown_80FEE2C); // It's special ability boosted Attack
|
|
}
|
|
}
|
|
|
|
if ((AbilityIsActive(attacker, ABILITY_HUSTLE)) && (splitIndex == 0)) {
|
|
atkMultiplier *= 3;
|
|
atkDivisor *= 2;
|
|
}
|
|
|
|
if (GetEntInfo(attacker)->isNotTeamMember) {
|
|
isNotEnemy = FALSE;
|
|
}
|
|
else {
|
|
isNotEnemy = TRUE;
|
|
}
|
|
|
|
if ((AbilityIsActive(attacker, ABILITY_PLUS)) && (splitIndex == 1) && gDungeon->minusIsActive[isNotEnemy]) {
|
|
atkMultiplier *= 15;
|
|
atkDivisor *= 10;
|
|
}
|
|
if ((AbilityIsActive(attacker, ABILITY_MINUS)) && (splitIndex == 1) && gDungeon->plusIsActive[isNotEnemy]) {
|
|
atkMultiplier *= 15;
|
|
atkDivisor *= 10;
|
|
}
|
|
|
|
if (AbilityIsActive(target, ABILITY_INTIMIDATE) && (splitIndex == 0)) {
|
|
atkMultiplier *= 4;
|
|
atkDivisor *= 5;
|
|
}
|
|
|
|
if ((AbilityIsActive(target, ABILITY_MARVEL_SCALE)) && (splitIndex == 0)) {
|
|
EntityInfo *targetInfo = GetEntInfo(target);
|
|
bool8 hasNegStatus_target = MonsterHasNegativeStatus(target);
|
|
bool8 visFlags_target = SetVisualFlags(targetInfo, 8, hasNegStatus_target);
|
|
|
|
if (hasNegStatus_target) {
|
|
defMultiplier *= 3;
|
|
defDivisor *= 2;
|
|
}
|
|
if (visFlags_target) {
|
|
sub_8042940(target);
|
|
TryDisplayDungeonLoggableMessage3_Async(attacker,target, gUnknown_80FEE54); // Its special ability quickened attacks!
|
|
}
|
|
}
|
|
|
|
*atkStat *= atkMultiplier;
|
|
*defStat *= defMultiplier;
|
|
if (atkDivisor != 1) {
|
|
*atkStat = *atkStat / atkDivisor;
|
|
}
|
|
if (defDivisor != 1) {
|
|
*defStat = *defStat / defDivisor;
|
|
}
|
|
}
|
|
|
|
static inline void SetDamageOne(struct DamageStruct *dmgStruct, u8 moveType)
|
|
{
|
|
dmgStruct->dmg = 1;
|
|
dmgStruct->residualDmgType = RESIDUAL_DAMAGE_REGULAR;
|
|
dmgStruct->typeEffectiveness = EFFECTIVENESS_NEUTRAL;
|
|
dmgStruct->type = moveType;
|
|
dmgStruct->isCrit = FALSE;
|
|
dmgStruct->unkE = 0;
|
|
dmgStruct->tookNoDamage = FALSE;
|
|
}
|
|
|
|
void CalcDamage(Entity *attacker, Entity *target, u8 moveType, s32 movePower, s32 critChance, struct DamageStruct *dmgStruct, s24_8 arg8, u16 moveId, bool8 arg_10)
|
|
{
|
|
EntityInfo *attackerInfo = GetEntInfo(attacker);
|
|
EntityInfo *targetInfo = GetEntInfo(target);
|
|
s32 splitIndex = (!IsTypePhysical(moveType)) ? 1 : 0;
|
|
|
|
ResetDamageCalcWorkingValues();
|
|
if (!attackerInfo->isTeamLeader && FixedPointToInt(attackerInfo->belly) == 0) {
|
|
SetDamageOne(dmgStruct, moveType);
|
|
}
|
|
else if (moveId == MOVE_REGULAR_ATTACK && AbilityIsActive(target, ABILITY_WONDER_GUARD)) {
|
|
SetDamageOne(dmgStruct, moveType);
|
|
}
|
|
else {
|
|
s32 atkStatStage, defStatStage;
|
|
s24_8 statCalc;
|
|
s32 atkStat, defStat;
|
|
s32 rand;
|
|
s32 r6;
|
|
s48_16 unkSp1;
|
|
s48_16 unkSp2;
|
|
s48_16 unkSp3;
|
|
s48_16 unkSp4;
|
|
s48_16 unkSp5;
|
|
s48_16 unkSp6;
|
|
s48_16 unkSp7;
|
|
s48_16 unkSp8;
|
|
s48_16 unkSp9;
|
|
s48_16 unkSp10;
|
|
s48_16 unkSp11;
|
|
bool8 r5;
|
|
|
|
dmgStruct->type = moveType;
|
|
gDungeon->damageCalcWorkingValues.unk134 = moveType;
|
|
gDungeon->damageCalcWorkingValues.unk138 = splitIndex;
|
|
|
|
atkStatStage = attackerInfo->offensiveStages[splitIndex];
|
|
if (arg_10 && moveType == TYPE_FIRE) {
|
|
atkStatStage += attackerInfo->flashFireBoost;
|
|
gDungeon->damageCalcWorkingValues.rawDamageFormulaValues[2] = attackerInfo->flashFireBoost;
|
|
}
|
|
if (attackerInfo->apparentID == MONSTER_DEOXYS_ATTACK) {
|
|
atkStatStage += 2;
|
|
}
|
|
if (attackerInfo->apparentID == MONSTER_DEOXYS_DEFENSE) {
|
|
atkStatStage -= 2;
|
|
}
|
|
if (attackerInfo->apparentID == MONSTER_DEOXYS_SPEED) {
|
|
atkStatStage -= 2;
|
|
}
|
|
|
|
if (atkStatStage < 0) atkStatStage = 0;
|
|
if (atkStatStage > 20) atkStatStage = 20;
|
|
|
|
gDungeon->damageCalcWorkingValues.offensiveStages[0] = atkStatStage;
|
|
gDungeon->damageCalcWorkingValues.rawDamageFormulaValues[0] = attackerInfo->atk[splitIndex] + movePower;
|
|
statCalc = s24_8_mul(IntToF248(attackerInfo->atk[splitIndex] + movePower), gAtkStatStageMultipliers[atkStatStage]);
|
|
statCalc = s24_8_mul(statCalc, attackerInfo->offensiveMultipliers[splitIndex]);
|
|
atkStat = F248ToInt(statCalc);
|
|
|
|
defStatStage = targetInfo->defensiveStages[splitIndex];
|
|
if (splitIndex == 0 && targetInfo->bideClassStatus.status == STATUS_SKULL_BASH) {
|
|
gDungeon->damageCalcWorkingValues.unk17A = 1;
|
|
defStatStage++;
|
|
}
|
|
if (targetInfo->apparentID == MONSTER_DEOXYS_ATTACK) {
|
|
defStatStage -= 2;
|
|
}
|
|
if (targetInfo->apparentID == MONSTER_DEOXYS_DEFENSE) {
|
|
defStatStage += 2;
|
|
}
|
|
if (targetInfo->apparentID == MONSTER_DEOXYS_SPEED) {
|
|
defStatStage -= 2;
|
|
}
|
|
|
|
if (defStatStage < 0) defStatStage = 0;
|
|
if (defStatStage > 20) defStatStage = 20;
|
|
|
|
gDungeon->damageCalcWorkingValues.offensiveStages[1] = defStatStage;
|
|
gDungeon->damageCalcWorkingValues.rawDamageFormulaValues[1] = targetInfo->def[splitIndex];
|
|
statCalc = s24_8_mul(IntToF248(targetInfo->def[splitIndex]), gDefStatStageMultipliers[defStatStage]);
|
|
statCalc = s24_8_mul(statCalc, targetInfo->defensiveMultipliers[splitIndex]);
|
|
defStat = F248ToInt(statCalc);
|
|
|
|
rand = DungeonRandInt(100);
|
|
if (splitIndex == 0) {
|
|
if (HasHeldItem(attacker, ITEM_POWER_BAND)) {
|
|
atkStat += gPowerBandBoost;
|
|
gDungeon->damageCalcWorkingValues.atkItemBoost += gPowerBandBoost;
|
|
}
|
|
if (HasHeldItem(attacker, ITEM_MUNCH_BELT)) {
|
|
atkStat += gMunchBeltBoost;
|
|
gDungeon->damageCalcWorkingValues.atkItemBoost += gMunchBeltBoost;
|
|
}
|
|
if (arg_10 && HasHeldItem(target, ITEM_DEF_SCARF)) {
|
|
defStat += gDefScarfBoost;
|
|
gDungeon->damageCalcWorkingValues.defItemBoost += gDefScarfBoost;
|
|
}
|
|
}
|
|
else {
|
|
if (arg_10 && HasHeldItem(target, ITEM_ZINC_BAND)) {
|
|
defStat += gZincBandBoost;
|
|
gDungeon->damageCalcWorkingValues.spDefItemBoost += gZincBandBoost;
|
|
}
|
|
if (HasHeldItem(attacker, ITEM_SPECIAL_BAND)) {
|
|
atkStat += gSpecialBandBoost;
|
|
gDungeon->damageCalcWorkingValues.spAtkItemBoost += gSpecialBandBoost;
|
|
}
|
|
if (HasHeldItem(attacker, ITEM_MUNCH_BELT)) {
|
|
atkStat += gMunchBeltBoost;
|
|
gDungeon->damageCalcWorkingValues.spAtkItemBoost += gMunchBeltBoost;
|
|
}
|
|
}
|
|
|
|
gDungeon->damageCalcWorkingValues.rawDamageFormulaValues[3] = atkStat;
|
|
gDungeon->damageCalcWorkingValues.rawDamageFormulaValues[4] = defStat;
|
|
if (atkStat < 0) atkStat = 0;
|
|
if (atkStat >= 999) atkStat = 999;
|
|
|
|
attackerInfo->previousVisualFlags &= ~(0x100);
|
|
attackerInfo->visualFlags &= ~(0x100);
|
|
ApplyAtkDefStatBoosts(attacker, target, moveType, &atkStat, &defStat, rand);
|
|
FP48_16_FromS32(&unkSp1, atkStat - defStat);
|
|
FP48_16_FromS32(&unkSp2, 8);
|
|
F48_16_SDiv(&unkSp1, &unkSp1, &unkSp2);
|
|
if (!attackerInfo->isNotTeamMember) {
|
|
FP48_16_FromS32(&unkSp2, attackerInfo->level);
|
|
unkSp3.hi = 0;
|
|
unkSp3.lo = 0xAAAA;
|
|
F48_16_SMul(&unkSp2, &unkSp2, &unkSp3);
|
|
r6 = (attackerInfo->level * 2) / 3;
|
|
}
|
|
else {
|
|
s32 unkAtkStat2 = attackerInfo->atk[splitIndex];
|
|
s32 unkDefStat2 = 1;
|
|
ApplyAtkDefStatBoosts(attacker, target, moveType, &unkAtkStat2, &unkDefStat2, rand);
|
|
FP48_16_FromS32(&unkSp2, unkAtkStat2);
|
|
FP48_16_FromS32(&unkSp3, 3);
|
|
F48_16_SDiv(&unkSp2, &unkSp2, &unkSp3);
|
|
r6 = unkAtkStat2 / 3;
|
|
}
|
|
FP48_16_Add(&unkSp4, &unkSp1, &unkSp2);
|
|
gDungeon->damageCalcWorkingValues.rawDamageFormulaValues[5] = r6;
|
|
gDungeon->damageCalcWorkingValues.rawDamageFormulaValues[6] = FP48_16_ToS32(&unkSp4);
|
|
unkSp5 = unkSp4;
|
|
unkSp7 = unkSp4;
|
|
F48_16_SMul(&unkSp5, &unkSp5, &unkSp5);
|
|
unkSp6.hi = 0;
|
|
unkSp6.lo = 0xCCC;
|
|
F48_16_SMul(&unkSp5, &unkSp5, &unkSp6);
|
|
FP48_16_FromS32(&unkSp6, 2);
|
|
F48_16_SMul(&unkSp7, &unkSp7, &unkSp6);
|
|
FP48_16_FromS32(&unkSp6, defStat);
|
|
FP48_16_Subtract(&unkSp7, &unkSp7, &unkSp6);
|
|
FP48_16_FromS32(&unkSp6, 10);
|
|
FP48_16_Add(&unkSp7, &unkSp7, &unkSp6);
|
|
FP48_16_Add(&unkSp8, &unkSp5, &unkSp7);
|
|
if (FP48_16_SLessThan(&gUnknown_8106F24, &unkSp8)) {
|
|
unkSp8 = gUnknown_8106F24;
|
|
}
|
|
if (FP48_16_SLessThan(&unkSp8, &gUnknown_8106F04)) {
|
|
unkSp8 = gUnknown_8106F04;
|
|
}
|
|
r5 = sub_806E100(&unkSp9, attacker, target, moveType, dmgStruct);
|
|
|
|
if (moveType == TYPE_FIRE) {
|
|
s32 flashFireStatus = GetFlashFireStatus(target);
|
|
if (flashFireStatus != FLASH_FIRE_STATUS_NONE && targetInfo->unk152 == 0 && arg_10) {
|
|
targetInfo->unk152 = 1;
|
|
SubstitutePlaceholderStringTags(gFormatBuffer_Monsters[1], target, 0);
|
|
if (flashFireStatus == FLASH_FIRE_STATUS_MAXED) {
|
|
TryDisplayDungeonLoggableMessage3_Async(attacker, target, gUnknown_80FAE00); // Fire moves won't become stronger!
|
|
}
|
|
else {
|
|
TryDisplayDungeonLoggableMessage3_Async(attacker, target, gUnknown_80FADD8); // m1 used Flash Fire to absorb fire!
|
|
}
|
|
}
|
|
}
|
|
if (arg_10) {
|
|
if (splitIndex == 0 && targetInfo->reflectClassStatus.status == STATUS_REFLECT) {
|
|
sub_8041B74(target);
|
|
F48_16_SMul(&unkSp9, &unkSp9, &gUnknown_8106F1C);
|
|
gDungeon->damageCalcWorkingValues.unk166 = 1;
|
|
}
|
|
if (splitIndex == 1 && targetInfo->reflectClassStatus.status == STATUS_LIGHT_SCREEN) {
|
|
sub_8041B5C(target);
|
|
F48_16_SMul(&unkSp9, &unkSp9, &gUnknown_8106F1C);
|
|
gDungeon->damageCalcWorkingValues.unk167 = 1;
|
|
}
|
|
}
|
|
|
|
// Check crit
|
|
if (!AbilityIsActive(target, ABILITY_BATTLE_ARMOR) && !AbilityIsActive(target, ABILITY_SHELL_ARMOR)) {
|
|
s32 critOdds;
|
|
|
|
if (attackerInfo->isNotTeamMember) {
|
|
critOdds = 0;
|
|
}
|
|
else {
|
|
critOdds = critChance;
|
|
}
|
|
|
|
if (attackerInfo->sureShotClassStatus.status == STATUS_FOCUS_ENERGY) {
|
|
critOdds = 999;
|
|
gDungeon->damageCalcWorkingValues.unk168 = 1;
|
|
}
|
|
else {
|
|
if (HasHeldItem(attacker, ITEM_SCOPE_LENS)) {
|
|
critOdds += gCritOddsScopeLensPatsyBand;
|
|
gDungeon->damageCalcWorkingValues.unk164 = 1;
|
|
}
|
|
if (HasHeldItem(target, ITEM_PATSY_BAND)) {
|
|
critOdds += gCritOddsScopeLensPatsyBand;
|
|
gDungeon->damageCalcWorkingValues.unk165 = 1;
|
|
}
|
|
if (r5 && IqSkillIsEnabled(attacker, IQ_TYPE_ADVANTAGE_MASTER)) {
|
|
critOdds = gCritOddsIqAdvantageMaster;
|
|
gDungeon->damageCalcWorkingValues.unk169 = 1;
|
|
}
|
|
}
|
|
if (DungeonRandInt(100) < critOdds) {
|
|
F48_16_SMul(&unkSp9, &unkSp9, &gUnknown_8106F14);
|
|
dmgStruct->isCrit = TRUE;
|
|
}
|
|
}
|
|
|
|
gDungeon->damageCalcWorkingValues.unk154 = FP48_16_ToS32(&unkSp8);
|
|
F48_16_SMul(&unkSp8, &unkSp8, &unkSp9);
|
|
{
|
|
// Ugly hack needed to match
|
|
#ifdef NONMATCHING
|
|
s24_8 arg8_Match;
|
|
#else
|
|
register s24_8 arg8_Match asm("r2");
|
|
#endif // NONMATCHING
|
|
|
|
gDungeon->damageCalcWorkingValues.unk15C = arg8_Match = arg8;
|
|
FP48_16_FromF248(&unkSp10, arg8_Match);
|
|
F48_16_SMul(&unkSp8, &unkSp8, &unkSp10);
|
|
}
|
|
|
|
// ALSO needed to match. unk694 chosen randomly and it worked with matching.
|
|
ASM_MATCH_TRICK(gDungeon->unk644.unk50);
|
|
gDungeon->damageCalcWorkingValues.unk150 = FP48_16_ToS32(&unkSp8);
|
|
{
|
|
s32 rnd = DungeonRandInt(0x4000);
|
|
unkSp9.hi = 0;
|
|
unkSp9.lo = 0xE000 + rnd;
|
|
}
|
|
F48_16_SMul(&unkSp8, &unkSp8, &unkSp9);
|
|
FP48_16_FromS32(&unkSp11, 100);
|
|
|
|
F48_16_SMul(&unkSp9, &unkSp11, &unkSp9);
|
|
gDungeon->damageCalcWorkingValues.unk158 = FP48_16_ToS32(&unkSp9);
|
|
|
|
dmgStruct->dmg = FP48_16_ToS32(&unkSp8);
|
|
dmgStruct->residualDmgType = RESIDUAL_DAMAGE_REGULAR;
|
|
if (dmgStruct->dmg == 0) {
|
|
dmgStruct->isCrit = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
void sub_806F2BC(Entity *attacker, Entity *target, u8 moveType, s32 a2, struct DamageStruct *dmgStruct)
|
|
{
|
|
s48_16 unkSp1;
|
|
s48_16 unkSp2;
|
|
s32 a2New = a2;
|
|
|
|
if (a2New <= 0) a2New = 1;
|
|
if (a2New > 999) a2New = 999;
|
|
|
|
dmgStruct->type = moveType;
|
|
sub_806E100(&unkSp1, attacker, target, moveType, dmgStruct);
|
|
FP48_16_FromS32(&unkSp2, a2New);
|
|
F48_16_SMul(&unkSp2, &unkSp2, &unkSp1);
|
|
dmgStruct->dmg = FP48_16_ToS32(&unkSp2);
|
|
dmgStruct->residualDmgType = RESIDUAL_DAMAGE_REGULAR;
|
|
}
|
|
|
|
void DealDamageToEntity_Async(Entity *entity, s32 dmg, s32 residualDmgType, s32 dungeonExitReason_)
|
|
{
|
|
Entity spEntity;
|
|
struct DamageStruct dmgStruct;
|
|
s32 dungeonExitReason = (s16) dungeonExitReason_;
|
|
|
|
sub_80457DC(&spEntity);
|
|
dmgStruct.dmg = dmg;
|
|
dmgStruct.typeEffectiveness = EFFECTIVENESS_NEUTRAL;
|
|
dmgStruct.type = TYPE_NONE;
|
|
dmgStruct.residualDmgType = residualDmgType;
|
|
dmgStruct.isCrit = FALSE;
|
|
dmgStruct.unkE = 0;
|
|
dmgStruct.tookNoDamage = FALSE;
|
|
HandleDealingDamage_Async(&spEntity, entity, &dmgStruct, FALSE, FALSE, dungeonExitReason, FALSE, 0);
|
|
}
|
|
|
|
void sub_806F370_Async(Entity *pokemon, Entity *target, s32 dmg, s32 giveExp, bool8 *tookNoDamage, u8 moveType, s16 dungeonExitReason_, s32 residualDmgType, s32 arg_10, s32 arg_14)
|
|
{
|
|
s32 i;
|
|
struct DamageStruct dmgStruct;
|
|
s32 dungeonExitReason = dungeonExitReason_;
|
|
s32 dmgNew = dmg;
|
|
|
|
dmgStruct.typeEffectiveness = EFFECTIVENESS_NEUTRAL;
|
|
dmgStruct.residualDmgType = residualDmgType;
|
|
dmgStruct.type = moveType;
|
|
dmgStruct.isCrit = FALSE;
|
|
dmgStruct.unkE = 0;
|
|
|
|
if (moveType != TYPE_NONE) {
|
|
s32 typeEffectiveness[2];
|
|
EntityInfo *targetInfo = GetEntInfo(target);
|
|
for (i = 0; i < 2; i++) {
|
|
s32 effectiv = gTypeEffectivenessChart[moveType][targetInfo->types[i]];
|
|
typeEffectiveness[i] = effectiv;
|
|
}
|
|
if (AbilityIsActive(target, ABILITY_WONDER_GUARD)) {
|
|
if (gEffectivenessChart[typeEffectiveness[0]][typeEffectiveness[1]] != EFFECTIVENESS_SUPER) {
|
|
dmgNew = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
dmgStruct.dmg = dmgNew;
|
|
if (dmgNew == 0) {
|
|
dmgStruct.tookNoDamage = TRUE;
|
|
}
|
|
else {
|
|
dmgStruct.tookNoDamage = FALSE;
|
|
}
|
|
|
|
HandleDealingDamage_Async(pokemon, target, &dmgStruct, FALSE, giveExp, dungeonExitReason, arg_10, arg_14);
|
|
if (tookNoDamage != NULL) {
|
|
*tookNoDamage = dmgStruct.tookNoDamage;
|
|
}
|
|
}
|
|
|
|
void SetShopkeeperAggression(Entity *pokemon, Entity *target)
|
|
{
|
|
EntityInfo *info;
|
|
|
|
info = GetEntInfo(target);
|
|
|
|
if(info->shopkeeper != SHOPKEEPER_MODE_NORMAL)
|
|
{
|
|
if(GetEntityType(pokemon) == ENTITY_MONSTER)
|
|
{
|
|
if(GetEntInfo(pokemon)->isNotTeamMember)
|
|
{
|
|
info->shopkeeper = SHOPKEEPER_MODE_ATTACK_ENEMIES;
|
|
}
|
|
else
|
|
{
|
|
info->shopkeeper = SHOPKEEPER_MODE_ATTACK_TEAM;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void sub_806F480(Entity *pokemon, bool8 attackEnemies)
|
|
{
|
|
EntityInfo *info = GetEntInfo(pokemon);
|
|
|
|
if (info->shopkeeper != SHOPKEEPER_MODE_NORMAL) {
|
|
if (attackEnemies) {
|
|
info->shopkeeper = SHOPKEEPER_MODE_ATTACK_ENEMIES;
|
|
}
|
|
else {
|
|
info->shopkeeper = SHOPKEEPER_MODE_ATTACK_TEAM;
|
|
}
|
|
}
|
|
}
|
|
|
|
u8 sub_806F4A4(Entity *pokemon, u8 type)
|
|
{
|
|
EntityInfo *info = GetEntInfo(pokemon);
|
|
s32 index;
|
|
|
|
if (MonsterIsType(pokemon, TYPE_GHOST)) {
|
|
if (type == TYPE_NORMAL || type == TYPE_FIGHTING)
|
|
if (!info->exposed)
|
|
return FALSE;
|
|
}
|
|
for (index = 0; index < 2; index++) {
|
|
if (gTypeEffectivenessChart[type][info->types[index]] == EFFECTIVENESS_IMMUNE)
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static void ResetDamageCalcWorkingValues(void)
|
|
{
|
|
struct DamageCalcWorkingValues *damageCalcWorkingValues;
|
|
|
|
damageCalcWorkingValues = &gDungeon->damageCalcWorkingValues;
|
|
|
|
damageCalcWorkingValues->unk134 = 0;
|
|
damageCalcWorkingValues->unk138 = 0;
|
|
damageCalcWorkingValues->unk13C[0] = 0;
|
|
damageCalcWorkingValues->unk13C[1] = 0;
|
|
damageCalcWorkingValues->offensiveStages[0] = 0xA;
|
|
damageCalcWorkingValues->offensiveStages[1] = 0xA;
|
|
damageCalcWorkingValues->rawDamageFormulaValues[0] = 1;
|
|
damageCalcWorkingValues->rawDamageFormulaValues[1] = 1;
|
|
damageCalcWorkingValues->rawDamageFormulaValues[2] = 0;
|
|
damageCalcWorkingValues->rawDamageFormulaValues[4] = 0;
|
|
damageCalcWorkingValues->rawDamageFormulaValues[3] = 0;
|
|
damageCalcWorkingValues->rawDamageFormulaValues[5] = 0;
|
|
damageCalcWorkingValues->rawDamageFormulaValues[6] = 0;
|
|
damageCalcWorkingValues->unk150 = 0;
|
|
damageCalcWorkingValues->unk158 = 0;
|
|
damageCalcWorkingValues->unk15C = F248_ZERO;
|
|
damageCalcWorkingValues->atkItemBoost = 0;
|
|
damageCalcWorkingValues->spAtkItemBoost = 0;
|
|
damageCalcWorkingValues->defItemBoost = 0;
|
|
damageCalcWorkingValues->spDefItemBoost = 0;
|
|
damageCalcWorkingValues->unk164 = 0;
|
|
damageCalcWorkingValues->unk165 = 0;
|
|
damageCalcWorkingValues->unk166 = 0;
|
|
damageCalcWorkingValues->unk167 = 0;
|
|
damageCalcWorkingValues->unk168 = 0;
|
|
damageCalcWorkingValues->unk169 = 0;
|
|
damageCalcWorkingValues->unk16A = 0;
|
|
damageCalcWorkingValues->unk16C = 0;
|
|
damageCalcWorkingValues->unk16B = 0;
|
|
damageCalcWorkingValues->unk16D = 0;
|
|
damageCalcWorkingValues->fill16E[0] = 0;
|
|
damageCalcWorkingValues->fill16E[1] = 0;
|
|
damageCalcWorkingValues->fill16E[2] = 0;
|
|
damageCalcWorkingValues->fill16E[3] = 0;
|
|
damageCalcWorkingValues->fill16E[4] = 0;
|
|
damageCalcWorkingValues->fill16E[5] = 0;
|
|
damageCalcWorkingValues->fill16E[6] = 0;
|
|
damageCalcWorkingValues->fill16E[7] = 0;
|
|
damageCalcWorkingValues->fill16E[8] = 0;
|
|
damageCalcWorkingValues->fill16E[9] = 0;
|
|
damageCalcWorkingValues->fill16E[10] = 0;
|
|
damageCalcWorkingValues->pokemonExposed = FALSE;
|
|
damageCalcWorkingValues->unk17A = 0;
|
|
}
|
|
|
|
static const s32 gUnknown_8106F7C[] = {0, 0, 0, 1};
|
|
|
|
s32 sub_806F62C(s32 param_1)
|
|
{
|
|
return gUnknown_8106F7C[param_1];
|
|
}
|
|
|
|
static void sub_806F63C(Entity *param_1)
|
|
{
|
|
UnkDungeonGlobal_unk181E8_sub *temp = &gDungeon->unk181e8;
|
|
|
|
if (temp->cameraTarget == param_1) {
|
|
PointCameraToMonster(temp->cameraTarget);
|
|
}
|
|
}
|