From 5a094a30338639648a89b365419263761064ca86 Mon Sep 17 00:00:00 2001 From: Xhyzi Date: Tue, 15 Jun 2021 16:22:42 +0200 Subject: [PATCH 001/130] Snap Trap --- include/constants/battle_string_ids.h | 3 ++- src/battle_message.c | 5 ++++- src/battle_script_commands.c | 2 +- src/data/battle_moves.h | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index cda885694..cf26ef2ef 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -570,8 +570,9 @@ #define STRINGID_MICLEBERRYACTIVATES 566 #define STRINGID_PKMNSHOOKOFFTHETAUNT 567 #define STRINGID_PKMNGOTOVERITSINFATUATION 568 +#define STRINGID_PKMNINSNAPTRAP 569 -#define BATTLESTRINGS_COUNT 569 +#define BATTLESTRINGS_COUNT 570 // The below IDs are all indexes into battle message tables, // used to determine which of a set of messages to print. diff --git a/src/battle_message.c b/src/battle_message.c index c4f043e15..d8b0fc8f9 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -147,6 +147,7 @@ static const u8 sText_PkmnDugHole[] = _("{B_ATK_NAME_WITH_PREFIX} dug a hole!"); static const u8 sText_PkmnHidUnderwater[] = _("{B_ATK_NAME_WITH_PREFIX} hid\nunderwater!"); static const u8 sText_PkmnSprangUp[] = _("{B_ATK_NAME_WITH_PREFIX} sprang up!"); static const u8 sText_PkmnSqueezedByBind[] = _("{B_DEF_NAME_WITH_PREFIX} was squeezed by\n{B_ATK_NAME_WITH_PREFIX}'s BIND!"); +static const u8 sText_PkmnInSnapTrap[] = _("{B_DEF_NAME_WITH_PREFIX} got trapped\nby a snap trap!"); static const u8 sText_PkmnTrappedInVortex[] = _("{B_DEF_NAME_WITH_PREFIX} was trapped\nin the vortex!"); static const u8 sText_PkmnTrappedBySandTomb[] = _("{B_DEF_NAME_WITH_PREFIX} was trapped\nby SAND TOMB!"); static const u8 sText_PkmnWrappedBy[] = _("{B_DEF_NAME_WITH_PREFIX} was WRAPPED by\n{B_ATK_NAME_WITH_PREFIX}!"); @@ -699,6 +700,7 @@ static const u8 sText_PkmnGotOverItsInfatuation[] = _("{B_SCR_ACTIVE_NAME_WITH_P const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = { + [STRINGID_PKMNINSNAPTRAP - 12] = sText_PkmnInSnapTrap, [STRINGID_PKMNGOTOVERITSINFATUATION - 12] = sText_PkmnGotOverItsInfatuation, [STRINGID_PKMNSHOOKOFFTHETAUNT - 12] = sText_PkmnShookOffTheTaunt, [STRINGID_MICLEBERRYACTIVATES - 12] = sText_MicleBerryActivates, @@ -1463,6 +1465,7 @@ const u16 gWrappedStringIds[] = STRINGID_PKMNTRAPPEDINVORTEX, // MOVE_WHIRLPOOL STRINGID_PKMNTRAPPEDBYSANDTOMB,// MOVE_SAND_TOMB STRINGID_INFESTATION, // MOVE_INFESTATION + STRINGID_PKMNINSNAPTRAP, // MOVE_SNAPTRAP }; const u16 gMistUsedStringIds[] = @@ -1675,7 +1678,7 @@ const u16 gCaughtMonStringIds[] = const u16 gTrappingMoves[] = { - MOVE_BIND, MOVE_WRAP, MOVE_FIRE_SPIN, MOVE_CLAMP, MOVE_WHIRLPOOL, MOVE_SAND_TOMB, MOVE_INFESTATION, 0xFFFF + MOVE_BIND, MOVE_WRAP, MOVE_FIRE_SPIN, MOVE_CLAMP, MOVE_WHIRLPOOL, MOVE_SAND_TOMB, MOVE_INFESTATION, MOVE_SNAP_TRAP, 0xFFFF }; const u16 gRoomsStringIds[] = diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index c8a393da3..014c3c3c8 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -2895,7 +2895,7 @@ void SetMoveEffect(bool32 primary, u32 certain) for (gBattleCommunication[MULTISTRING_CHOOSER] = 0; ; gBattleCommunication[MULTISTRING_CHOOSER]++) { - if (gBattleCommunication[MULTISTRING_CHOOSER] > 5) + if (gBattleCommunication[MULTISTRING_CHOOSER] > 6) break; if (gTrappingMoves[gBattleCommunication[MULTISTRING_CHOOSER]] == gCurrentMove) break; diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index db02083b0..69b612e0c 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -10968,7 +10968,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_SNAP_TRAP] = { - .effect = EFFECT_TRAP, //TODO: add case/effect + .effect = EFFECT_TRAP, .power = 35, .type = TYPE_GRASS, .accuracy = 100, From 60ce39543e8c918110c23deec7826e237851e2a6 Mon Sep 17 00:00:00 2001 From: Xhyzi Date: Tue, 15 Jun 2021 16:25:59 +0200 Subject: [PATCH 002/130] Expanding Force --- data/battle_scripts_1.s | 2 ++ include/constants/battle_move_effects.h | 3 ++- src/battle_util.c | 4 ++++ src/data/battle_moves.h | 2 +- 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 11616e300..6e667ebfe 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -369,6 +369,7 @@ gBattleScriptsForMoveEffects:: @ 82D86A8 .4byte BattleScript_EffectSleepHit .4byte BattleScript_EffectAttackerDefenseDownHit .4byte BattleScript_EffectBodyPress + .4byte BattleScript_EffectExpandingForce BattleScript_EffectAttackerDefenseDownHit: setmoveeffect MOVE_EFFECT_DEF_MINUS_1 | MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN @@ -2059,6 +2060,7 @@ BattleScript_EffectFusionCombo: BattleScript_EffectRevelationDance: BattleScript_EffectBelch: BattleScript_EffectBodyPress: +BattleScript_EffectExpandingForce: BattleScript_HitFromAtkCanceler:: attackcanceler diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index 6174ca496..cfd4ccdef 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -353,7 +353,8 @@ #define EFFECT_SLEEP_HIT 347 // Relic Song #define EFFECT_ATTACKER_DEFENSE_DOWN_HIT 348 #define EFFECT_BODY_PRESS 349 +#define EFFECT_EXPANDING_FORCE 350 -#define NUM_BATTLE_MOVE_EFFECTS 350 +#define NUM_BATTLE_MOVE_EFFECTS 351 #endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H diff --git a/src/battle_util.c b/src/battle_util.c index 0c8f2c8d1..92662bb20 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -7210,6 +7210,10 @@ static u16 CalcMoveBasePower(u16 move, u8 battlerAtk, u8 battlerDef) if (gBattleMoves[gLastUsedMove].effect == EFFECT_FUSION_COMBO && move != gLastUsedMove) basePower *= 2; break; + case EFFECT_EXPANDING_FORCE: + if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN) + basePower = 120; + break; } if (basePower == 0) diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index 69b612e0c..b556a0a5c 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -11220,7 +11220,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_EXPANDING_FORCE] = { - .effect = EFFECT_PLACEHOLDER, //TODO + .effect = EFFECT_EXPANDING_FORCE, .power = 80, .type = TYPE_PSYCHIC, .accuracy = 100, From 62525516a4e59d32693383b9835ce07e4b4fcf27 Mon Sep 17 00:00:00 2001 From: Xhyzi Date: Tue, 15 Jun 2021 16:50:19 +0200 Subject: [PATCH 003/130] Scale Shot --- data/battle_scripts_1.s | 57 +++++++++++++++++++++++++ include/constants/battle.h | 3 +- include/constants/battle_move_effects.h | 3 +- src/data/battle_moves.h | 4 +- 4 files changed, 63 insertions(+), 4 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 6e667ebfe..d85b8cff8 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -370,6 +370,63 @@ gBattleScriptsForMoveEffects:: @ 82D86A8 .4byte BattleScript_EffectAttackerDefenseDownHit .4byte BattleScript_EffectBodyPress .4byte BattleScript_EffectExpandingForce + .4byte BattleScript_EffectScaleShot + +BattleScript_EffectScaleShot:: + attackcanceler + accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE + attackstring + ppreduce + setmultihitcounter 0x0 + initmultihitstring + sethword sMULTIHIT_EFFECT, 0x0 +BattleScript_ScaleShotLoop:: + jumpifhasnohp BS_ATTACKER, BattleScript_ScaleShotEnd + jumpifhasnohp BS_TARGET, BattleScript_ScaleShotPrintStrings + jumpifhalfword CMP_EQUAL, gChosenMove, MOVE_SLEEP_TALK, BattleScript_ScaleShotDoMultiHit + jumpifstatus BS_ATTACKER, STATUS1_SLEEP, BattleScript_ScaleShotPrintStrings +BattleScript_ScaleShotDoMultiHit:: + movevaluescleanup + copyhword sMOVE_EFFECT, sMULTIHIT_EFFECT + critcalc + damagecalc + jumpifmovehadnoeffect BattleScript_ScaleShotMultiHitNoMoreHits + adjustdamage + attackanimation + waitanimation + effectivenesssound + hitanimation BS_TARGET + waitstate + healthbarupdate BS_TARGET + datahpupdate BS_TARGET + critmessage + waitmessage 0x40 + multihitresultmessage + printstring STRINGID_EMPTYSTRING3 + waitmessage 0x1 + addbyte sMULTIHIT_STRING + 4, 0x1 + moveendto MOVEEND_NEXT_TARGET + jumpifbyte CMP_COMMON_BITS, gMoveResultFlags, MOVE_RESULT_FOE_ENDURED, BattleScript_ScaleShotPrintStrings + decrementmultihit BattleScript_ScaleShotLoop + goto BattleScript_ScaleShotPrintStrings +BattleScript_ScaleShotMultiHitNoMoreHits:: + pause 0x20 +BattleScript_ScaleShotPrintStrings:: + resultmessage + waitmessage 0x40 + jumpifmovehadnoeffect BattleScript_ScaleShotEnd + copyarray gBattleTextBuff1, sMULTIHIT_STRING, 0x6 + printstring STRINGID_HITXTIMES + waitmessage 0x40 +BattleScript_ScaleShotEnd:: + setmoveeffect MOVE_EFFECT_SPD_PLUS_1 | MOVE_EFFECT_AFFECTS_USER + seteffectwithchance + setmoveeffect MOVE_EFFECT_DEF_MINUS_1 | MOVE_EFFECT_AFFECTS_USER + seteffectwithchance + tryfaintmon BS_TARGET, FALSE, NULL + moveendcase MOVEEND_SYNCHRONIZE_TARGET + moveendfrom MOVEEND_STATUS_IMMUNITY_ABILITIES + end BattleScript_EffectAttackerDefenseDownHit: setmoveeffect MOVE_EFFECT_DEF_MINUS_1 | MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN diff --git a/include/constants/battle.h b/include/constants/battle.h index b158076bd..b925904c2 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -346,7 +346,8 @@ #define MOVE_EFFECT_THROAT_CHOP 0x43 #define MOVE_EFFECT_INCINERATE 0x44 #define MOVE_EFFECT_BUG_BITE 0x45 -#define NUM_MOVE_EFFECTS 0x46 +#define MOVE_EFFECT_SPD_PLUS_1_DEF_MINUS_1 0x46 +#define NUM_MOVE_EFFECTS 0x47 #define MOVE_EFFECT_AFFECTS_USER 0x4000 #define MOVE_EFFECT_CERTAIN 0x8000 diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index cfd4ccdef..fd26204a1 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -354,7 +354,8 @@ #define EFFECT_ATTACKER_DEFENSE_DOWN_HIT 348 #define EFFECT_BODY_PRESS 349 #define EFFECT_EXPANDING_FORCE 350 +#define EFFECT_SCALE_SHOT 351 -#define NUM_BATTLE_MOVE_EFFECTS 351 +#define NUM_BATTLE_MOVE_EFFECTS 352 #endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index b556a0a5c..83ff193a3 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -11248,12 +11248,12 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_SCALE_SHOT] = { - .effect = EFFECT_PLACEHOLDER, //TODO (EFFECT_MULTI_HIT + ABILITY_WEAK_ARMOR, + .effect = EFFECT_SCALE_SHOT, .power = 25, .type = TYPE_DRAGON, .accuracy = 90, .pp = 20, - .secondaryEffectChance = 0, + .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, .flags = FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_KINGS_ROCK_AFFECTED, From ee3f3eb78f5a51b8cb81b282a04fc2771d945bb7 Mon Sep 17 00:00:00 2001 From: Xhyzi Date: Tue, 15 Jun 2021 17:06:21 +0200 Subject: [PATCH 004/130] Meteor Beam --- data/battle_scripts_1.s | 27 +++++++++++++++++++++++++ include/constants/battle_move_effects.h | 3 ++- include/constants/battle_string_ids.h | 6 ++++-- src/battle_message.c | 3 +++ src/data/battle_moves.h | 2 +- 5 files changed, 37 insertions(+), 4 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index d85b8cff8..cc6a37668 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -371,6 +371,33 @@ gBattleScriptsForMoveEffects:: @ 82D86A8 .4byte BattleScript_EffectBodyPress .4byte BattleScript_EffectExpandingForce .4byte BattleScript_EffectScaleShot + .4byte BattleScript_EffectMeteorBeam + +BattleScript_EffectMeteorBeam:: + @ DecideTurn + jumpifstatus2 BS_ATTACKER, STATUS2_MULTIPLETURNS, BattleScript_TwoTurnMovesSecondTurn + jumpifword CMP_COMMON_BITS, gHitMarker, HITMARKER_NO_ATTACKSTRING, BattleScript_TwoTurnMovesSecondTurn + setbyte sTWOTURN_STRINGID, B_MSG_TURN1_METEOR_BEAM + call BattleScript_FirstChargingTurnMeteorBeam + jumpifnoholdeffect BS_ATTACKER, HOLD_EFFECT_POWER_HERB, BattleScript_MoveEnd + call BattleScript_PowerHerbActivation + goto BattleScript_TwoTurnMovesSecondTurn + +BattleScript_FirstChargingTurnMeteorBeam:: + attackcanceler + printstring STRINGID_EMPTYSTRING3 + ppreduce + attackanimation + waitanimation + orword gHitMarker, HITMARKER_CHARGING + setmoveeffect MOVE_EFFECT_CHARGING | MOVE_EFFECT_AFFECTS_USER + seteffectprimary + copybyte cMULTISTRING_CHOOSER, sTWOTURN_STRINGID + printfromtable gFirstTurnOfTwoStringIds + waitmessage 0x40 + setmoveeffect MOVE_EFFECT_SP_ATK_PLUS_1 | MOVE_EFFECT_AFFECTS_USER + seteffectsecondary + return BattleScript_EffectScaleShot:: attackcanceler diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index fd26204a1..47721e447 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -355,7 +355,8 @@ #define EFFECT_BODY_PRESS 349 #define EFFECT_EXPANDING_FORCE 350 #define EFFECT_SCALE_SHOT 351 +#define EFFECT_METEOR_BEAM 352 -#define NUM_BATTLE_MOVE_EFFECTS 352 +#define NUM_BATTLE_MOVE_EFFECTS 353 #endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index cf26ef2ef..c1e35a312 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -570,9 +570,10 @@ #define STRINGID_MICLEBERRYACTIVATES 566 #define STRINGID_PKMNSHOOKOFFTHETAUNT 567 #define STRINGID_PKMNGOTOVERITSINFATUATION 568 -#define STRINGID_PKMNINSNAPTRAP 569 +#define STRINGID_PKMNINSNAPTRAP 569 +#define STRINGID_METEORBEAMCHARGING 570 -#define BATTLESTRINGS_COUNT 570 +#define BATTLESTRINGS_COUNT 571 // The below IDs are all indexes into battle message tables, // used to determine which of a set of messages to print. @@ -623,6 +624,7 @@ #define B_MSG_TURN1_PHANTOM_FORCE 8 #define B_MSG_TURN1_GEOMANCY 9 #define B_MSG_TURN1_FREEZE_SHOCK 10 +#define B_MSG_TURN1_METEOR_BEAM 11 // gMoveWeatherChangeStringIds #define B_MSG_STARTED_RAIN 0 diff --git a/src/battle_message.c b/src/battle_message.c index d8b0fc8f9..fd33527a2 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -697,9 +697,11 @@ static const u8 sText_CanActFaster[] = _("{B_ATK_NAME_WITH_PREFIX} can act faste static const u8 sText_MicleBerryActivates[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} boosted the accuracy of its\nnext move using {B_LAST_ITEM}!"); static const u8 sText_PkmnShookOffTheTaunt[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} shook off\nthe taunt!"); static const u8 sText_PkmnGotOverItsInfatuation[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} got over\nits infatuation!"); +static const u8 sText_MeteorBeamCharging[] = _("{B_ATK_NAME_WITH_PREFIX} is overflowing\nwith space energy!"); const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = { + [STRINGID_METEORBEAMCHARGING - 12] = sText_MeteorBeamCharging, [STRINGID_PKMNINSNAPTRAP - 12] = sText_PkmnInSnapTrap, [STRINGID_PKMNGOTOVERITSINFATUATION - 12] = sText_PkmnGotOverItsInfatuation, [STRINGID_PKMNSHOOKOFFTHETAUNT - 12] = sText_PkmnShookOffTheTaunt, @@ -1453,6 +1455,7 @@ const u16 gFirstTurnOfTwoStringIds[] = [B_MSG_TURN1_PHANTOM_FORCE] = STRINGID_VANISHEDINSTANTLY, [B_MSG_TURN1_GEOMANCY] = STRINGID_PKNMABSORBINGPOWER, [B_MSG_TURN1_FREEZE_SHOCK] = STRINGID_CLOAKEDINAFREEZINGLIGHT, + [B_MSG_TURN1_METEOR_BEAM] = STRINGID_METEORBEAMCHARGING, }; // Index copied from move's index in gTrappingMoves diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index 83ff193a3..680c008fd 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -11262,7 +11262,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_METEOR_BEAM] = { - .effect = EFFECT_PLACEHOLDER, //TODO + .effect = EFFECT_METEOR_BEAM, .power = 120, .type = TYPE_ROCK, .accuracy = 90, From e7ec4df70bf89def1630b5e184b431d3e46eaf7a Mon Sep 17 00:00:00 2001 From: Xhyzi Date: Tue, 15 Jun 2021 17:36:50 +0200 Subject: [PATCH 005/130] Rising Voltage --- data/battle_scripts_1.s | 2 ++ include/constants/battle_move_effects.h | 3 ++- src/battle_util.c | 5 +++++ src/data/battle_moves.h | 2 +- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index cc6a37668..2e5ad0253 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -372,6 +372,7 @@ gBattleScriptsForMoveEffects:: @ 82D86A8 .4byte BattleScript_EffectExpandingForce .4byte BattleScript_EffectScaleShot .4byte BattleScript_EffectMeteorBeam + .4byte BattleScript_EffectRisingVoltage BattleScript_EffectMeteorBeam:: @ DecideTurn @@ -2145,6 +2146,7 @@ BattleScript_EffectRevelationDance: BattleScript_EffectBelch: BattleScript_EffectBodyPress: BattleScript_EffectExpandingForce: +BattleScript_EffectRisingVoltage: BattleScript_HitFromAtkCanceler:: attackcanceler diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index 47721e447..03ea11136 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -356,7 +356,8 @@ #define EFFECT_EXPANDING_FORCE 350 #define EFFECT_SCALE_SHOT 351 #define EFFECT_METEOR_BEAM 352 +#define EFFECT_RISING_VOLTAGE 353 -#define NUM_BATTLE_MOVE_EFFECTS 353 +#define NUM_BATTLE_MOVE_EFFECTS 354 #endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H diff --git a/src/battle_util.c b/src/battle_util.c index 92662bb20..4c46250dc 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -7214,6 +7214,11 @@ static u16 CalcMoveBasePower(u16 move, u8 battlerAtk, u8 battlerDef) if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN) basePower = 120; break; + case EFFECT_RISING_VOLTAGE: + if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN && !IS_BATTLER_OF_TYPE(battlerDef, TYPE_FLYING) + && gBattleMons[battlerDef].item != ITEM_AIR_BALLOON && gBattleMons[battlerDef].ability != ABILITY_LEVITATE) + basePower *= 2; + break; } if (basePower == 0) diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index 680c008fd..9e0c18298 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -11318,7 +11318,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_RISING_VOLTAGE] = { - .effect = EFFECT_PLACEHOLDER, //TODO + .effect = EFFECT_RISING_VOLTAGE, .power = 70, .type = TYPE_ELECTRIC, .accuracy = 100, From 7799e49e3a3f5ef65a39c7acd392b05b3b61961e Mon Sep 17 00:00:00 2001 From: Xhyzi Date: Tue, 15 Jun 2021 19:44:38 +0200 Subject: [PATCH 006/130] Corrosive Gas --- asm/macros/battle_script.inc | 5 +++ data/battle_scripts_1.s | 19 ++++++++++ include/battle.h | 1 + include/battle_scripts.h | 1 + include/constants/battle.h | 1 + include/constants/battle_move_effects.h | 3 +- include/constants/battle_script_commands.h | 1 + include/constants/battle_string_ids.h | 3 +- src/battle_message.c | 2 + src/battle_script_commands.c | 43 ++++++++++++++++++++-- src/battle_util.c | 5 +++ src/data/battle_moves.h | 2 +- 12 files changed, 80 insertions(+), 6 deletions(-) diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 9fa3fe0c3..9384a0f9d 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1769,6 +1769,11 @@ various \battler, VARIOUS_TRY_ACTIVATE_GRIM_NEIGH .endm + .macro trysetcorrosivegas battler:req, ptr:req + various \battler, VARIOUS_TRY_SET_CORROSIVE_GAS + .4byte \ptr + .endm + @ helpful macros .macro setstatchanger stat:req, stages:req, down:req setbyte sSTATCHANGER \stat | \stages << 3 | \down << 7 diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 2e5ad0253..e1e7fbf9d 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -373,6 +373,25 @@ gBattleScriptsForMoveEffects:: @ 82D86A8 .4byte BattleScript_EffectScaleShot .4byte BattleScript_EffectMeteorBeam .4byte BattleScript_EffectRisingVoltage + .4byte BattleScript_EffectCorrosiveGas + +BattleScript_EffectCorrosiveGas:: + attackcanceler + accuracycheck BattleScript_PrintMoveMissed, NO_ACC_CALC_CHECK_LOCK_ON + attackstring + ppreduce + jumpifstatus2 BS_TARGET, STATUS2_SUBSTITUTE, BattleScript_PrintMoveMissed + trysetcorrosivegas BS_TARGET, BattleScript_ButItFailed + attackanimation + waitanimation + printstring STRINGID_ITEMMELTED + waitmessage 0x40 + goto BattleScript_MoveEnd + +BattleScript_MeltedItem:: + printstring STRINGID_ITEMMELTED + waitmessage 0x40 + return BattleScript_EffectMeteorBeam:: @ DecideTurn diff --git a/include/battle.h b/include/battle.h index f009cbe7f..7212c4084 100644 --- a/include/battle.h +++ b/include/battle.h @@ -229,6 +229,7 @@ struct WishFutureKnock u8 wishMonId[MAX_BATTLERS_COUNT]; u8 weatherDuration; u8 knockedOffMons[2]; // Each battler is represented by a bit. The array entry is dependent on the battler's side. + u8 meltedItemMons[2]; // Same as above }; struct AI_SavedBattleMon diff --git a/include/battle_scripts.h b/include/battle_scripts.h index f0712fc43..7ae55d01f 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -369,5 +369,6 @@ extern const u8 BattleScript_JabocaRowapBerryActivates[]; extern const u8 BattleScript_NotAffectedAbilityPopUp[]; extern const u8 BattleScript_BattlerShookOffTaunt[]; extern const u8 BattleScript_BattlerGotOverItsInfatuation[]; +extern const u8 BattleScript_MeltedItem[]; #endif // GUARD_BATTLE_SCRIPTS_H diff --git a/include/constants/battle.h b/include/constants/battle.h index b925904c2..d7bae55c3 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -347,6 +347,7 @@ #define MOVE_EFFECT_INCINERATE 0x44 #define MOVE_EFFECT_BUG_BITE 0x45 #define MOVE_EFFECT_SPD_PLUS_1_DEF_MINUS_1 0x46 +#define MOVE_EFFECT_MELT_ITEM 0x4A #define NUM_MOVE_EFFECTS 0x47 #define MOVE_EFFECT_AFFECTS_USER 0x4000 diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index 03ea11136..d88b34a53 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -357,7 +357,8 @@ #define EFFECT_SCALE_SHOT 351 #define EFFECT_METEOR_BEAM 352 #define EFFECT_RISING_VOLTAGE 353 +#define EFFECT_CORROSIVE_GAS 354 -#define NUM_BATTLE_MOVE_EFFECTS 354 +#define NUM_BATTLE_MOVE_EFFECTS 355 #endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index faaf8f17e..f35dbe2e3 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -173,6 +173,7 @@ #define VARIOUS_DESTROY_ABILITY_POPUP 102 #define VARIOUS_TOTEM_BOOST 103 #define VARIOUS_TRY_ACTIVATE_GRIM_NEIGH 104 +#define VARIOUS_TRY_SET_CORROSIVE_GAS 105 // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 0 diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index c1e35a312..72f178de7 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -572,8 +572,9 @@ #define STRINGID_PKMNGOTOVERITSINFATUATION 568 #define STRINGID_PKMNINSNAPTRAP 569 #define STRINGID_METEORBEAMCHARGING 570 +#define STRINGID_ITEMMELTED 571 -#define BATTLESTRINGS_COUNT 571 +#define BATTLESTRINGS_COUNT 572 // The below IDs are all indexes into battle message tables, // used to determine which of a set of messages to print. diff --git a/src/battle_message.c b/src/battle_message.c index fd33527a2..4d1ae2ddb 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -698,9 +698,11 @@ static const u8 sText_MicleBerryActivates[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} static const u8 sText_PkmnShookOffTheTaunt[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} shook off\nthe taunt!"); static const u8 sText_PkmnGotOverItsInfatuation[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} got over\nits infatuation!"); static const u8 sText_MeteorBeamCharging[] = _("{B_ATK_NAME_WITH_PREFIX} is overflowing\nwith space energy!"); +static const u8 sText_PkmnItemMelted[] = _("{B_ATK_NAME_WITH_PREFIX} corroded\n{B_DEF_NAME_WITH_PREFIX}'s {B_LAST_ITEM}!"); const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = { + [STRINGID_ITEMMELTED - 12] = sText_PkmnItemMelted, [STRINGID_METEORBEAMCHARGING - 12] = sText_MeteorBeamCharging, [STRINGID_PKMNINSNAPTRAP - 12] = sText_PkmnInSnapTrap, [STRINGID_PKMNGOTOVERITSINFATUATION - 12] = sText_PkmnGotOverItsInfatuation, diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 014c3c3c8..9915654c5 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -3021,7 +3021,8 @@ void SetMoveEffect(bool32 primary, u32 certain) | BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_SECRET_BASE)) - && (gWishFutureKnock.knockedOffMons[side] & gBitTable[gBattlerPartyIndexes[gBattlerAttacker]])) + && (gWishFutureKnock.knockedOffMons[side] & gBitTable[gBattlerPartyIndexes[gBattlerAttacker]] + || gWishFutureKnock.meltedItemMons[side] & gBitTable[gBattlerPartyIndexes[gBattlerAttacker]])) { gBattlescriptCurrInstr++; } @@ -5267,6 +5268,11 @@ static void Cmd_switchindataupdate(void) { gBattleMons[gActiveBattler].item = 0; } + // check melted items + if (gWishFutureKnock.meltedItemMons[i] & gBitTable[gBattlerPartyIndexes[gActiveBattler]]) + { + gBattleMons[gActiveBattler].item = 0; + } if (gBattleMoves[gCurrentMove].effect == EFFECT_BATON_PASS) { @@ -8422,6 +8428,35 @@ static void Cmd_various(void) gBattlescriptCurrInstr += 7; // exit if loop failed (failsafe) } return; + case VARIOUS_TRY_SET_CORROSIVE_GAS: + if (gBattleMons[gActiveBattler].item != 0 + && CanBattlerGetOrLoseItem(gActiveBattler, gBattleMons[gActiveBattler].item) + && !NoAliveMonsForEitherParty()) + { + if (GetBattlerAbility(gActiveBattler) == ABILITY_STICKY_HOLD && IsBattlerAlive(gActiveBattler)) + { + gBattlerAbility = gActiveBattler; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_StickyHoldActivates; + } + else + { //Item is melted normally + u32 side = GetBattlerSide(gActiveBattler); + + gLastUsedItem = gBattleMons[gActiveBattler].item; + gBattleMons[gActiveBattler].item = 0; + gBattleStruct->choicedMove[gActiveBattler] = 0; + gWishFutureKnock.meltedItemMons[side] |= gBitTable[gBattlerPartyIndexes[gActiveBattler]]; + + CheckSetUnburden(gActiveBattler); + gBattlescriptCurrInstr += 7; + } + } + else + { + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); + } + return; } gBattlescriptCurrInstr += 3; @@ -11206,14 +11241,16 @@ static void Cmd_tryswapitems(void) // trick u8 sideAttacker = GetBattlerSide(gBattlerAttacker); u8 sideTarget = GetBattlerSide(gBattlerTarget); - // you can't swap items if they were knocked off in regular battles + // you can't swap items if they were knocked off or melted in regular battles if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_FRONTIER | BATTLE_TYPE_SECRET_BASE | BATTLE_TYPE_RECORDED_LINK)) && (gWishFutureKnock.knockedOffMons[sideAttacker] & gBitTable[gBattlerPartyIndexes[gBattlerAttacker]] - || gWishFutureKnock.knockedOffMons[sideTarget] & gBitTable[gBattlerPartyIndexes[gBattlerTarget]])) + || gWishFutureKnock.knockedOffMons[sideTarget] & gBitTable[gBattlerPartyIndexes[gBattlerTarget]] + || gWishFutureKnock.meltedItemMons[sideTarget] & gBitTable[gBattlerPartyIndexes[gBattlerAttacker]] + || gWishFutureKnock.meltedItemMons[sideTarget] & gBitTable[gBattlerPartyIndexes[gBattlerTarget]])) { gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); } diff --git a/src/battle_util.c b/src/battle_util.c index 4c46250dc..9d7453bab 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -7215,8 +7215,13 @@ static u16 CalcMoveBasePower(u16 move, u8 battlerAtk, u8 battlerDef) basePower = 120; break; case EFFECT_RISING_VOLTAGE: + #ifdef ITEM_EXPANSION //Air Baloon exception with item expansion branch if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN && !IS_BATTLER_OF_TYPE(battlerDef, TYPE_FLYING) && gBattleMons[battlerDef].item != ITEM_AIR_BALLOON && gBattleMons[battlerDef].ability != ABILITY_LEVITATE) + #else + if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN && !IS_BATTLER_OF_TYPE(battlerDef, TYPE_FLYING) + && gBattleMons[battlerDef].ability != ABILITY_LEVITATE) + #endif basePower *= 2; break; } diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index 9e0c18298..20449e446 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -11402,7 +11402,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_CORROSIVE_GAS] = { - .effect = EFFECT_PLACEHOLDER, //TODO + .effect = EFFECT_CORROSIVE_GAS, .power = 0, .type = TYPE_POISON, .accuracy = 100, From 0202b75822bbbc98787c28a6d19ce754b15ae5fb Mon Sep 17 00:00:00 2001 From: Xhyzi Date: Tue, 15 Jun 2021 19:57:21 +0200 Subject: [PATCH 007/130] Beak Blast --- asm/macros/battle_script.inc | 4 +++ data/battle_anim_scripts.s | 5 ++-- data/battle_scripts_1.s | 30 ++++++++++++++++++++++ include/battle.h | 1 + include/battle_scripts.h | 2 ++ include/constants/battle_anim.h | 1 + include/constants/battle_move_effects.h | 3 ++- include/constants/battle_script_commands.h | 1 + include/constants/battle_string_ids.h | 3 ++- src/battle_main.c | 14 +++++++--- src/battle_message.c | 2 ++ src/battle_script_commands.c | 10 ++++++++ src/data/battle_moves.h | 2 +- 13 files changed, 69 insertions(+), 9 deletions(-) diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 9384a0f9d..1405dd258 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1774,6 +1774,10 @@ .4byte \ptr .endm + .macro setbeakblast battler:req + various \battler, VARIOUS_SET_BEAK_BLAST + .endm + @ helpful macros .macro setstatchanger stat:req, stages:req, down:req setbyte sSTATCHANGER \stat | \stages << 3 | \down << 7 diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index 65bac00d7..ee401010a 100644 --- a/data/battle_anim_scripts.s +++ b/data/battle_anim_scripts.s @@ -822,6 +822,7 @@ gBattleAnims_General:: .4byte General_SlideOffScreen @ B_ANIM_SLIDE_OFFSCREEN .4byte General_RestoreBg @ B_ANIM_RESTORE_BG .4byte General_TotemFlare @ B_ANIM_TOTEM_FLARE + .4byte General_BeakBlastSetUp @ B_ANIM_BEAK_BLAST_SETUP .align 2 gBattleAnims_Special:: @@ -11673,7 +11674,7 @@ Move_INSTRUCT:: blendoff end -Move_BEAK_BLAST:: +General_BeakBlastSetUp: loadspritegfx ANIM_TAG_SMALL_EMBER @Fire playsewithpan SE_M_DRAGON_RAGE, SOUND_PAN_ATTACKER delay 0x3 @@ -11681,7 +11682,7 @@ Move_BEAK_BLAST:: launchtemplate gFireSpiralOutwardSpriteTemplate 0x3 0x4 0x0 0x0 0x38 0x0 waitforvisualfinish end -BeakBlastUnleash: +Move_BEAK_BLAST:: loadspritegfx ANIM_TAG_IMPACT launchtask AnimTask_BlendBattleAnimPal 0xA 0x5 ANIM_PAL_ATK 0x2 0x0 0x9 0x1F waitforvisualfinish diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index e1e7fbf9d..02da8a3bb 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -374,7 +374,37 @@ gBattleScriptsForMoveEffects:: @ 82D86A8 .4byte BattleScript_EffectMeteorBeam .4byte BattleScript_EffectRisingVoltage .4byte BattleScript_EffectCorrosiveGas + .4byte BattleScript_EffectBeakBlast +BattleScript_EffectBeakBlast:: + attackcanceler + jumpifnodamage BattleScript_HitFromAccCheck + ppreduce + printstring STRINGID_PKMNLOSTFOCUS + waitmessage 0x40 + goto BattleScript_MoveEnd + +BattleScript_BeakBlastSetUp:: + setbeakblast BS_ATTACKER + printstring STRINGID_EMPTYSTRING3 + waitmessage 0x1 + playanimation BS_ATTACKER, B_ANIM_BEAK_BLAST_SETUP, NULL + printstring STRINGID_HEATUPBEAK + waitmessage 0x40 + end2 + +BattleScript_BeakBlastBurn:: + jumpifstatus BS_TARGET, STATUS1_BURN, BattleScript_AlreadyBurned + jumpiftype BS_TARGET, TYPE_FIRE, BattleScript_NotAffected + jumpifability BS_TARGET, ABILITY_WATER_VEIL, BattleScript_WaterVeilPrevents + jumpifability BS_TARGET, ABILITY_COMATOSE, BattleScript_LeafGuardProtects + jumpifflowerveil BattleScript_FlowerVeilProtects + jumpifleafguard BattleScript_LeafGuardProtects + jumpifstatus BS_TARGET, STATUS1_ANY, BattleScript_BeakBlastBurnReturn + setmoveeffect MOVE_EFFECT_BURN | MOVE_EFFECT_AFFECTS_USER + seteffectprimary +BattleScript_BeakBlastBurnReturn: + return BattleScript_EffectCorrosiveGas:: attackcanceler accuracycheck BattleScript_PrintMoveMissed, NO_ACC_CALC_CHECK_LOCK_ON diff --git a/include/battle.h b/include/battle.h index 7212c4084..a86c6d34e 100644 --- a/include/battle.h +++ b/include/battle.h @@ -144,6 +144,7 @@ struct ProtectStruct u32 usedThroatChopPreventedMove:1; u32 micle:1; u32 custap:1; // also quick claw + u32 beakBlastCharge:1; u32 physicalDmg; u32 specialDmg; u8 physicalBattlerId; diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 7ae55d01f..ffb824f0b 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -370,5 +370,7 @@ extern const u8 BattleScript_NotAffectedAbilityPopUp[]; extern const u8 BattleScript_BattlerShookOffTaunt[]; extern const u8 BattleScript_BattlerGotOverItsInfatuation[]; extern const u8 BattleScript_MeltedItem[]; +extern const u8 BattleScript_BeakBlastSetUp[]; +extern const u8 BattleScript_BeakBlastBurn[]; #endif // GUARD_BATTLE_SCRIPTS_H diff --git a/include/constants/battle_anim.h b/include/constants/battle_anim.h index c04bc14f7..cfccef926 100644 --- a/include/constants/battle_anim.h +++ b/include/constants/battle_anim.h @@ -523,6 +523,7 @@ #define B_ANIM_SLIDE_OFFSCREEN 26 // for Emergency Exit #define B_ANIM_RESTORE_BG 27 // for Terrain Endings #define B_ANIM_TOTEM_FLARE 28 // Totem boosts aura flare +#define B_ANIM_BEAK_BLAST_SETUP 29 // special animations table (gBattleAnims_Special) #define B_ANIM_LVL_UP 0 diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index d88b34a53..1ccba4d43 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -358,7 +358,8 @@ #define EFFECT_METEOR_BEAM 352 #define EFFECT_RISING_VOLTAGE 353 #define EFFECT_CORROSIVE_GAS 354 +#define EFFECT_BEAK_BLAST 355 -#define NUM_BATTLE_MOVE_EFFECTS 355 +#define NUM_BATTLE_MOVE_EFFECTS 356 #endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index f35dbe2e3..ea96e6b4d 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -174,6 +174,7 @@ #define VARIOUS_TOTEM_BOOST 103 #define VARIOUS_TRY_ACTIVATE_GRIM_NEIGH 104 #define VARIOUS_TRY_SET_CORROSIVE_GAS 105 +#define VARIOUS_SET_BEAK_BLAST 106 // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 0 diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index 72f178de7..698b7e595 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -573,8 +573,9 @@ #define STRINGID_PKMNINSNAPTRAP 569 #define STRINGID_METEORBEAMCHARGING 570 #define STRINGID_ITEMMELTED 571 +#define STRINGID_HEATUPBEAK 572 -#define BATTLESTRINGS_COUNT 572 +#define BATTLESTRINGS_COUNT 573 // The below IDs are all indexes into battle message tables, // used to determine which of a set of messages to print. diff --git a/src/battle_main.c b/src/battle_main.c index 9cf56abf7..f053c13ef 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -4598,13 +4598,19 @@ static void CheckFocusPunch_ClearVarsBeforeTurnStarts(void) { gActiveBattler = gBattlerAttacker = gBattleStruct->focusPunchBattlerId; gBattleStruct->focusPunchBattlerId++; - if (gChosenMoveByBattler[gActiveBattler] == MOVE_FOCUS_PUNCH - && !(gBattleMons[gActiveBattler].status1 & STATUS1_SLEEP) + if (!(gBattleMons[gActiveBattler].status1 & STATUS1_SLEEP) && !(gDisableStructs[gBattlerAttacker].truantCounter) && !(gProtectStructs[gActiveBattler].noValidMoves)) { - BattleScriptExecute(BattleScript_FocusPunchSetUp); - return; + switch(gChosenMoveByBattler[gActiveBattler]) + { + case MOVE_FOCUS_PUNCH: + BattleScriptExecute(BattleScript_FocusPunchSetUp); + return; + case MOVE_BEAK_BLAST: + BattleScriptExecute(BattleScript_BeakBlastSetUp); + return; + } } } } diff --git a/src/battle_message.c b/src/battle_message.c index 4d1ae2ddb..d2ae86e13 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -699,9 +699,11 @@ static const u8 sText_PkmnShookOffTheTaunt[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX static const u8 sText_PkmnGotOverItsInfatuation[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} got over\nits infatuation!"); static const u8 sText_MeteorBeamCharging[] = _("{B_ATK_NAME_WITH_PREFIX} is overflowing\nwith space energy!"); static const u8 sText_PkmnItemMelted[] = _("{B_ATK_NAME_WITH_PREFIX} corroded\n{B_DEF_NAME_WITH_PREFIX}'s {B_LAST_ITEM}!"); +static const u8 sText_HeatingUpBeak[] = _("{B_ATK_NAME_WITH_PREFIX} started\nheating up its beak!"); const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = { + [STRINGID_HEATUPBEAK - 12] = sText_HeatingUpBeak, [STRINGID_ITEMMELTED - 12] = sText_PkmnItemMelted, [STRINGID_METEORBEAMCHARGING - 12] = sText_MeteorBeamCharging, [STRINGID_PKMNINSNAPTRAP - 12] = sText_PkmnInSnapTrap, diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 9915654c5..0565f06d1 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -4807,6 +4807,12 @@ static void Cmd_moveend(void) gBattlescriptCurrInstr = BattleScript_BanefulBunkerEffect; effect = 1; } + else if (gProtectStructs[gBattlerTarget].beakBlastCharge) + { + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_BeakBlastBurn; + effect = 1; + } } gBattleScripting.moveendState++; break; @@ -7867,6 +7873,7 @@ static void Cmd_various(void) case MOVE_MIRROR_COAT: case MOVE_METAL_BURST: case MOVE_ME_FIRST: + case MOVE_BEAK_BLAST: gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); break; default: @@ -8457,6 +8464,9 @@ static void Cmd_various(void) gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); } return; + case VARIOUS_SET_BEAK_BLAST: + gProtectStructs[gActiveBattler].beakBlastCharge = 1; + break; } gBattlescriptCurrInstr += 3; diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index 20449e446..2455b90cd 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -10127,7 +10127,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_BEAK_BLAST] = { - .effect = EFFECT_PLACEHOLDER, + .effect = EFFECT_BEAK_BLAST, .power = 100, .type = TYPE_FLYING, .accuracy = 100, From 271f19e6cb0ad7450ac127d20865aee6fb8c3f32 Mon Sep 17 00:00:00 2001 From: Xhyzi Date: Tue, 15 Jun 2021 20:01:57 +0200 Subject: [PATCH 008/130] Terrain Pulse --- data/battle_scripts_1.s | 2 ++ include/constants/battle_move_effects.h | 3 ++- src/battle_main.c | 11 +++++++++++ src/battle_util.c | 4 ++++ src/data/battle_moves.h | 2 +- 5 files changed, 20 insertions(+), 2 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 02da8a3bb..6f074b664 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -375,6 +375,7 @@ gBattleScriptsForMoveEffects:: @ 82D86A8 .4byte BattleScript_EffectRisingVoltage .4byte BattleScript_EffectCorrosiveGas .4byte BattleScript_EffectBeakBlast + .4byte BattleScript_EffectTerrainPulse BattleScript_EffectBeakBlast:: attackcanceler @@ -2196,6 +2197,7 @@ BattleScript_EffectBelch: BattleScript_EffectBodyPress: BattleScript_EffectExpandingForce: BattleScript_EffectRisingVoltage: +BattleScript_EffectTerrainPulse: BattleScript_HitFromAtkCanceler:: attackcanceler diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index 1ccba4d43..d975da2fb 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -359,7 +359,8 @@ #define EFFECT_RISING_VOLTAGE 353 #define EFFECT_CORROSIVE_GAS 354 #define EFFECT_BEAK_BLAST 355 +#define EFFECT_TERRAIN_PULSE 356 -#define NUM_BATTLE_MOVE_EFFECTS 356 +#define NUM_BATTLE_MOVE_EFFECTS 357 #endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H diff --git a/src/battle_main.c b/src/battle_main.c index f053c13ef..9f5105151 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -5070,6 +5070,17 @@ void SetTypeBeforeUsingMove(u16 move, u8 battlerAtk) if (ItemId_GetPocket(gBattleMons[battlerAtk].item) == POCKET_BERRIES) gBattleStruct->dynamicMoveType = gNaturalGiftTable[ITEM_TO_BERRY(gBattleMons[battlerAtk].item)].type; } + else if (gBattleMoves[move].effect == EFFECT_TERRAIN_PULSE) + { + if (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN) + gBattleStruct->dynamicMoveType = TYPE_FAIRY | 0x80; + else if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) + gBattleStruct->dynamicMoveType = TYPE_ELECTRIC | 0x80; + else if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN) + gBattleStruct->dynamicMoveType = TYPE_PSYCHIC | 0x80; + else if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN) + gBattleStruct->dynamicMoveType = TYPE_GRASS | 0x80; + } attackerAbility = GetBattlerAbility(battlerAtk); GET_MOVE_TYPE(move, moveType); diff --git a/src/battle_util.c b/src/battle_util.c index 9d7453bab..1f0ef56ae 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -7224,6 +7224,10 @@ static u16 CalcMoveBasePower(u16 move, u8 battlerAtk, u8 battlerDef) #endif basePower *= 2; break; + case EFFECT_TERRAIN_PULSE: + if (gFieldStatuses & (STATUS_FIELD_GRASSY_TERRAIN | STATUS_FIELD_ELECTRIC_TERRAIN | STATUS_FIELD_MISTY_TERRAIN | STATUS_FIELD_PSYCHIC_TERRAIN)) + basePower *= 2; + break; } if (basePower == 0) diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index 2455b90cd..8bcdccc85 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -11332,7 +11332,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_TERRAIN_PULSE] = { - .effect = EFFECT_PLACEHOLDER, //TODO + .effect = EFFECT_TERRAIN_PULSE, .power = 50, .type = TYPE_NORMAL, .accuracy = 100, From 155e9b6332e505596e9308a71526d1a37c11ee62 Mon Sep 17 00:00:00 2001 From: Xhyzi Date: Tue, 15 Jun 2021 20:14:10 +0200 Subject: [PATCH 009/130] Court Change --- asm/macros/battle_script.inc | 4 + data/battle_scripts_1.s | 13 ++ include/constants/battle_move_effects.h | 3 +- include/constants/battle_script_commands.h | 1 + include/constants/battle_string_ids.h | 3 +- src/battle_message.c | 2 + src/battle_script_commands.c | 163 +++++++++++++++++++++ src/data/battle_moves.h | 2 +- 8 files changed, 188 insertions(+), 3 deletions(-) diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 1405dd258..5cef3c769 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1778,6 +1778,10 @@ various \battler, VARIOUS_SET_BEAK_BLAST .endm + .macro swapsidestatuses + various BS_ATTACKER, VARIOUS_SWAP_SIDE_STATUSES + .endm + @ helpful macros .macro setstatchanger stat:req, stages:req, down:req setbyte sSTATCHANGER \stat | \stages << 3 | \down << 7 diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 6f074b664..bf501678c 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -376,6 +376,19 @@ gBattleScriptsForMoveEffects:: @ 82D86A8 .4byte BattleScript_EffectCorrosiveGas .4byte BattleScript_EffectBeakBlast .4byte BattleScript_EffectTerrainPulse + .4byte BattleScript_EffectCourtChange + +BattleScript_EffectCourtChange:: + attackcanceler + accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE + attackstring + ppreduce + swapsidestatuses + attackanimation + waitanimation + printstring STRINGID_COURTCHANGE + waitmessage 0x40 + goto BattleScript_MoveEnd BattleScript_EffectBeakBlast:: attackcanceler diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index d975da2fb..b6ad6e487 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -360,7 +360,8 @@ #define EFFECT_CORROSIVE_GAS 354 #define EFFECT_BEAK_BLAST 355 #define EFFECT_TERRAIN_PULSE 356 +#define EFFECT_COURT_CHANGE 357 -#define NUM_BATTLE_MOVE_EFFECTS 357 +#define NUM_BATTLE_MOVE_EFFECTS 358 #endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index ea96e6b4d..8ae661af3 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -175,6 +175,7 @@ #define VARIOUS_TRY_ACTIVATE_GRIM_NEIGH 104 #define VARIOUS_TRY_SET_CORROSIVE_GAS 105 #define VARIOUS_SET_BEAK_BLAST 106 +#define VARIOUS_SWAP_SIDE_STATUSES 107 // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 0 diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index 698b7e595..cfe25be1b 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -574,8 +574,9 @@ #define STRINGID_METEORBEAMCHARGING 570 #define STRINGID_ITEMMELTED 571 #define STRINGID_HEATUPBEAK 572 +#define STRINGID_COURTCHANGE 573 -#define BATTLESTRINGS_COUNT 573 +#define BATTLESTRINGS_COUNT 574 // The below IDs are all indexes into battle message tables, // used to determine which of a set of messages to print. diff --git a/src/battle_message.c b/src/battle_message.c index d2ae86e13..2a9d80424 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -700,9 +700,11 @@ static const u8 sText_PkmnGotOverItsInfatuation[] = _("{B_SCR_ACTIVE_NAME_WITH_P static const u8 sText_MeteorBeamCharging[] = _("{B_ATK_NAME_WITH_PREFIX} is overflowing\nwith space energy!"); static const u8 sText_PkmnItemMelted[] = _("{B_ATK_NAME_WITH_PREFIX} corroded\n{B_DEF_NAME_WITH_PREFIX}'s {B_LAST_ITEM}!"); static const u8 sText_HeatingUpBeak[] = _("{B_ATK_NAME_WITH_PREFIX} started\nheating up its beak!"); +static const u8 sText_CourtChange[] = _("{B_ATK_NAME_WITH_PREFIX} swapped the battle\neffects affecting each side!"); const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = { + [STRINGID_COURTCHANGE - 12] = sText_CourtChange, [STRINGID_HEATUPBEAK - 12] = sText_HeatingUpBeak, [STRINGID_ITEMMELTED - 12] = sText_PkmnItemMelted, [STRINGID_METEORBEAMCHARGING - 12] = sText_MeteorBeamCharging, diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 0565f06d1..3e91205ac 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -8467,6 +8467,169 @@ static void Cmd_various(void) case VARIOUS_SET_BEAK_BLAST: gProtectStructs[gActiveBattler].beakBlastCharge = 1; break; + case VARIOUS_SWAP_SIDE_STATUSES: + /* This code is a mess, but idk how to do it better without changing how Side Statuses and + Side timers work. + The problem is that not all side statuses are affected by Court Change*/ + + //todo: add pledge related effects + //todo: add gigamax related effects + + //swap side status sides + bits = gSideStatuses[0]; //Stores sides status temp + + //Reflect + if (gSideStatuses[1] & SIDE_STATUS_REFLECT) + gSideStatuses[0] |= SIDE_STATUS_REFLECT; + else + gSideStatuses[0] &= ~(SIDE_STATUS_REFLECT); + + if (bits & SIDE_STATUS_REFLECT) + gSideStatuses[1] |= SIDE_STATUS_REFLECT; + else + gSideStatuses[1] &= ~(SIDE_STATUS_REFLECT); + + //Light screen + if (gSideStatuses[1] & SIDE_STATUS_LIGHTSCREEN) + gSideStatuses[0] |= SIDE_STATUS_LIGHTSCREEN; + else + gSideStatuses[0] &= ~(SIDE_STATUS_LIGHTSCREEN); + + if (bits & SIDE_STATUS_LIGHTSCREEN) + gSideStatuses[1] |= SIDE_STATUS_LIGHTSCREEN; + else + gSideStatuses[1] &= ~(SIDE_STATUS_LIGHTSCREEN); + + //Safeguard + if (gSideStatuses[1] & SIDE_STATUS_SAFEGUARD) + gSideStatuses[0] |= SIDE_STATUS_SAFEGUARD; + else + gSideStatuses[0] &= ~(SIDE_STATUS_SAFEGUARD); + + if (bits & SIDE_STATUS_SAFEGUARD) + gSideStatuses[1] |= SIDE_STATUS_SAFEGUARD; + else + gSideStatuses[1] &= ~(SIDE_STATUS_SAFEGUARD); + + //Mist + if (gSideStatuses[1] & SIDE_STATUS_MIST) + gSideStatuses[0] |= SIDE_STATUS_MIST; + else + gSideStatuses[0] &= ~(SIDE_STATUS_MIST); + + if (bits & SIDE_STATUS_MIST) + gSideStatuses[1] |= SIDE_STATUS_MIST; + else + gSideStatuses[1] &= ~(SIDE_STATUS_MIST); + + //AuroraVeil + if (gSideStatuses[1] & SIDE_STATUS_AURORA_VEIL) + gSideStatuses[0] |= SIDE_STATUS_AURORA_VEIL; + else + gSideStatuses[0] &= ~(SIDE_STATUS_AURORA_VEIL); + + if (bits & SIDE_STATUS_AURORA_VEIL) + gSideStatuses[1] |= SIDE_STATUS_AURORA_VEIL; + else + gSideStatuses[1] &= ~(SIDE_STATUS_AURORA_VEIL); + + //Sticky Web + if (gSideStatuses[1] & SIDE_STATUS_STICKY_WEB) + gSideStatuses[0] |= SIDE_STATUS_STICKY_WEB; + else + gSideStatuses[0] &= ~(SIDE_STATUS_STICKY_WEB); + + if (bits & SIDE_STATUS_STICKY_WEB) + gSideStatuses[1] |= SIDE_STATUS_STICKY_WEB; + else + gSideStatuses[1] &= ~(SIDE_STATUS_STICKY_WEB); + + //Spikes + if (gSideStatuses[1] & SIDE_STATUS_SPIKES) + gSideStatuses[0] |= SIDE_STATUS_SPIKES; + else + gSideStatuses[0] &= ~(SIDE_STATUS_SPIKES); + + if (bits & SIDE_STATUS_SPIKES) + gSideStatuses[1] |= SIDE_STATUS_SPIKES; + else + gSideStatuses[1] &= ~(SIDE_STATUS_SPIKES); + + //Toxic Spikes + if (gSideStatuses[1] & SIDE_STATUS_TOXIC_SPIKES) + gSideStatuses[0] |= SIDE_STATUS_TOXIC_SPIKES; + else + gSideStatuses[0] &= ~(SIDE_STATUS_TOXIC_SPIKES); + + if (bits & SIDE_STATUS_TOXIC_SPIKES) + gSideStatuses[1] |= SIDE_STATUS_TOXIC_SPIKES; + else + gSideStatuses[1] &= ~(SIDE_STATUS_TOXIC_SPIKES); + + //Stealth Rock + if (gSideStatuses[1] & SIDE_STATUS_STEALTH_ROCK) + gSideStatuses[0] |= SIDE_STATUS_STEALTH_ROCK; + else + gSideStatuses[0] &= ~(SIDE_STATUS_STEALTH_ROCK); + + if (bits & SIDE_STATUS_STEALTH_ROCK) + gSideStatuses[1] |= SIDE_STATUS_STEALTH_ROCK; + else + gSideStatuses[1] &= ~(SIDE_STATUS_STEALTH_ROCK); + + //Tailwind + if (gSideStatuses[1] & SIDE_STATUS_TAILWIND) + gSideStatuses[0] |= SIDE_STATUS_TAILWIND; + else + gSideStatuses[0] &= ~(SIDE_STATUS_TAILWIND); + + if (bits & SIDE_STATUS_TAILWIND) + gSideStatuses[1] |= SIDE_STATUS_TAILWIND; + else + gSideStatuses[1] &= ~(SIDE_STATUS_TAILWIND); + + + //Swap affected status timers + bits = gSideTimers[0].reflectTimer; + gSideTimers[0].reflectTimer = gSideTimers[1].reflectTimer; + gSideTimers[1].reflectTimer = bits; + + bits = gSideTimers[0].lightscreenTimer; + gSideTimers[0].lightscreenTimer = gSideTimers[1].lightscreenTimer; + gSideTimers[1].lightscreenTimer = bits; + + bits = gSideTimers[0].mistTimer; + gSideTimers[0].mistTimer = gSideTimers[1].mistTimer; + gSideTimers[1].mistTimer = bits; + + bits = gSideTimers[0].safeguardTimer; + gSideTimers[0].safeguardTimer = gSideTimers[1].safeguardTimer; + gSideTimers[1].safeguardTimer = bits; + + bits = gSideTimers[0].spikesAmount; + gSideTimers[0].spikesAmount = gSideTimers[1].spikesAmount; + gSideTimers[1].spikesAmount = bits; + + bits = gSideTimers[0].toxicSpikesAmount; + gSideTimers[0].toxicSpikesAmount = gSideTimers[1].toxicSpikesAmount; + gSideTimers[1].toxicSpikesAmount = bits; + + bits = gSideTimers[0].stealthRockAmount; + gSideTimers[0].stealthRockAmount = gSideTimers[1].stealthRockAmount; + gSideTimers[1].stealthRockAmount = bits; + + bits = gSideTimers[0].stickyWebAmount; + gSideTimers[0].stickyWebAmount = gSideTimers[1].stickyWebAmount; + gSideTimers[1].stickyWebAmount = bits; + + bits = gSideTimers[0].auroraVeilTimer; + gSideTimers[0].auroraVeilTimer = gSideTimers[1].auroraVeilTimer; + gSideTimers[1].auroraVeilTimer = bits; + + bits = gSideTimers[0].tailwindTimer; + gSideTimers[0].tailwindTimer = gSideTimers[1].tailwindTimer; + gSideTimers[1].tailwindTimer = bits; + break; } gBattlescriptCurrInstr += 3; diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index 8bcdccc85..6c8bdd7b7 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -10898,7 +10898,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_COURT_CHANGE] = { - .effect = EFFECT_PLACEHOLDER, //TODO + .effect = EFFECT_COURT_CHANGE, .power = 0, .type = TYPE_NORMAL, .accuracy = 100, From c2bd046ea670c7abf4b5fd827887bbdf6495060a Mon Sep 17 00:00:00 2001 From: Xhyzi Date: Tue, 15 Jun 2021 20:22:50 +0200 Subject: [PATCH 010/130] Shell Trap --- asm/macros/battle_script.inc | 13 +++++++ data/battle_anim_scripts.s | 5 +-- data/battle_scripts_1.s | 41 ++++++++++++++++++++++ include/battle.h | 1 + include/battle_scripts.h | 3 ++ include/constants/battle_anim.h | 1 + include/constants/battle_move_effects.h | 3 +- include/constants/battle_script_commands.h | 3 ++ include/constants/battle_string_ids.h | 3 +- src/battle_main.c | 3 ++ src/battle_message.c | 2 ++ src/data/battle_moves.h | 4 +-- 12 files changed, 76 insertions(+), 6 deletions(-) diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 5cef3c769..6ae9fce29 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1782,6 +1782,19 @@ various BS_ATTACKER, VARIOUS_SWAP_SIDE_STATUSES .endm + .macro setshelltrap battler:req + various \battler, VARIOUS_SET_SHELL_TRAP + .endm + + .macro clearshelltrap battler:req + various \battler, VARIOUS_CLEAR_SHELL_TRAP + .endm + + .macro checkshelltrap battler:req, ptr:req + various \battler, VARIOUS_CHECK_SHELL_TRAP + .4byte \ptr + .endm + @ helpful macros .macro setstatchanger stat:req, stages:req, down:req setbyte sSTATCHANGER \stat | \stages << 3 | \down << 7 diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index ee401010a..96dae719f 100644 --- a/data/battle_anim_scripts.s +++ b/data/battle_anim_scripts.s @@ -823,6 +823,7 @@ gBattleAnims_General:: .4byte General_RestoreBg @ B_ANIM_RESTORE_BG .4byte General_TotemFlare @ B_ANIM_TOTEM_FLARE .4byte General_BeakBlastSetUp @ B_ANIM_BEAK_BLAST_SETUP + .4byte General_ShellTrapSetUp @ B_ANIM_SHELL_TRAP_SETUP .align 2 gBattleAnims_Special:: @@ -11831,8 +11832,7 @@ Move_AURORA_VEIL:: blendoff end -Move_SHELL_TRAP:: -ShellTrapChargeUp: +General_ShellTrapSetUp: loadspritegfx ANIM_TAG_SMALL_EMBER loadspritegfx ANIM_TAG_IMPACT monbg ANIM_TARGET @@ -11849,6 +11849,7 @@ ShellTrapChargeUp: clearmonbg ANIM_TARGET blendoff end +Move_SHELL_TRAP:: ShellTrapUnleash: loadspritegfx ANIM_TAG_IMPACT @pound loadspritegfx ANIM_TAG_SMALL_RED_EYE @red diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index bf501678c..f64b42e51 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -377,6 +377,47 @@ gBattleScriptsForMoveEffects:: @ 82D86A8 .4byte BattleScript_EffectBeakBlast .4byte BattleScript_EffectTerrainPulse .4byte BattleScript_EffectCourtChange + .4byte BattleScript_EffectShellTrap + +BattleScript_EffectShellTrap:: + checkshelltrap BS_ATTACKER, BattleScript_MoveEnd + clearshelltrap BS_ATTACKER + attackcanceler + attackstring + goto BattleScript_ButItFailed + +BattleScript_ShellTrapSetUp:: + setshelltrap BS_ATTACKER + printstring STRINGID_EMPTYSTRING3 + waitmessage 0x1 + playanimation BS_ATTACKER B_ANIM_SHELL_TRAP_SETUP, NULL + printstring STRINGID_PREPARESHELLTRAP + waitmessage 0x40 + end2 + +BattleScript_ShellTrapExplode:: + clearshelltrap BS_ATTACKER + attackcanceler + attackstring + ppreduce + critcalc + damagecalc + adjustdamage + attackanimation + waitanimation + effectivenesssound + hitanimation BS_TARGET + waitstate + healthbarupdate BS_TARGET + datahpupdate BS_TARGET + critmessage + waitmessage 0x40 + resultmessage + waitmessage 0x40 + seteffectwithchance + tryfaintmon BS_TARGET, FALSE, NULL + moveendall + end BattleScript_EffectCourtChange:: attackcanceler diff --git a/include/battle.h b/include/battle.h index a86c6d34e..18e12fc18 100644 --- a/include/battle.h +++ b/include/battle.h @@ -145,6 +145,7 @@ struct ProtectStruct u32 micle:1; u32 custap:1; // also quick claw u32 beakBlastCharge:1; + u32 shellTrap:1; u32 physicalDmg; u32 specialDmg; u8 physicalBattlerId; diff --git a/include/battle_scripts.h b/include/battle_scripts.h index ffb824f0b..71a8a50a4 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -372,5 +372,8 @@ extern const u8 BattleScript_BattlerGotOverItsInfatuation[]; extern const u8 BattleScript_MeltedItem[]; extern const u8 BattleScript_BeakBlastSetUp[]; extern const u8 BattleScript_BeakBlastBurn[]; +extern const u8 BattleScript_ShellTrapSetUp[]; +extern const u8 BattleScript_ShellTrapExplode[]; +extern const u8 BattleScript_EffectShellTrap[]; #endif // GUARD_BATTLE_SCRIPTS_H diff --git a/include/constants/battle_anim.h b/include/constants/battle_anim.h index cfccef926..c98007127 100644 --- a/include/constants/battle_anim.h +++ b/include/constants/battle_anim.h @@ -524,6 +524,7 @@ #define B_ANIM_RESTORE_BG 27 // for Terrain Endings #define B_ANIM_TOTEM_FLARE 28 // Totem boosts aura flare #define B_ANIM_BEAK_BLAST_SETUP 29 +#define B_ANIM_SHELL_TRAP_SETUP 30 // special animations table (gBattleAnims_Special) #define B_ANIM_LVL_UP 0 diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index b6ad6e487..cc5e94acd 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -361,7 +361,8 @@ #define EFFECT_BEAK_BLAST 355 #define EFFECT_TERRAIN_PULSE 356 #define EFFECT_COURT_CHANGE 357 +#define EFFECT_SHELL_TRAP 358 -#define NUM_BATTLE_MOVE_EFFECTS 358 +#define NUM_BATTLE_MOVE_EFFECTS 359 #endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 8ae661af3..6e67bd954 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -176,6 +176,9 @@ #define VARIOUS_TRY_SET_CORROSIVE_GAS 105 #define VARIOUS_SET_BEAK_BLAST 106 #define VARIOUS_SWAP_SIDE_STATUSES 107 +#define VARIOUS_SET_SHELL_TRAP 108 +#define VARIOUS_CLEAR_SHELL_TRAP 109 +#define VARIOUS_CHECK_SHELL_TRAP 110 // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 0 diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index cfe25be1b..823164717 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -575,8 +575,9 @@ #define STRINGID_ITEMMELTED 571 #define STRINGID_HEATUPBEAK 572 #define STRINGID_COURTCHANGE 573 +#define STRINGID_PREPARESHELLTRAP 574 -#define BATTLESTRINGS_COUNT 574 +#define BATTLESTRINGS_COUNT 575 // The below IDs are all indexes into battle message tables, // used to determine which of a set of messages to print. diff --git a/src/battle_main.c b/src/battle_main.c index 9f5105151..223188652 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -4610,6 +4610,9 @@ static void CheckFocusPunch_ClearVarsBeforeTurnStarts(void) case MOVE_BEAK_BLAST: BattleScriptExecute(BattleScript_BeakBlastSetUp); return; + case MOVE_SHELL_TRAP: + BattleScriptExecute(BattleScript_ShellTrapSetUp); + return; } } } diff --git a/src/battle_message.c b/src/battle_message.c index 2a9d80424..6d39cf84c 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -701,9 +701,11 @@ static const u8 sText_MeteorBeamCharging[] = _("{B_ATK_NAME_WITH_PREFIX} is over static const u8 sText_PkmnItemMelted[] = _("{B_ATK_NAME_WITH_PREFIX} corroded\n{B_DEF_NAME_WITH_PREFIX}'s {B_LAST_ITEM}!"); static const u8 sText_HeatingUpBeak[] = _("{B_ATK_NAME_WITH_PREFIX} started\nheating up its beak!"); static const u8 sText_CourtChange[] = _("{B_ATK_NAME_WITH_PREFIX} swapped the battle\neffects affecting each side!"); +static const u8 sText_PrepareShellTrap[] = _("{B_ATK_NAME_WITH_PREFIX} set\n a shell trap!"); const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = { + [STRINGID_PREPARESHELLTRAP - 12] = sText_PrepareShellTrap, [STRINGID_COURTCHANGE - 12] = sText_CourtChange, [STRINGID_HEATUPBEAK - 12] = sText_HeatingUpBeak, [STRINGID_ITEMMELTED - 12] = sText_PkmnItemMelted, diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index 6c8bdd7b7..abcd8a100 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -10197,13 +10197,13 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_SHELL_TRAP] = { - .effect = EFFECT_PLACEHOLDER, + .effect = EFFECT_SHELL_TRAP, .power = 150, .type = TYPE_FIRE, .accuracy = 100, .pp = 5, .secondaryEffectChance = 0, - .target = MOVE_TARGET_SELECTED, + .target = MOVE_TARGET_OPPONENTS_FIELD, .priority = -3, .flags = FLAG_PROTECT_AFFECTED | FLAG_KINGS_ROCK_AFFECTED, .split = SPLIT_SPECIAL, From e0b53f87fca30e0666f5cf3ba9221b4e26e2d2fa Mon Sep 17 00:00:00 2001 From: LOuroboros Date: Thu, 4 Nov 2021 10:56:14 -0300 Subject: [PATCH 011/130] Primal Reversion Tweaks -Fixed the inconsistent Primal Reversion activation in double battles. -Optimized the primal weather checks in attackcanceler a little. -Fixed the issue with multi-target fire/water moves during primal rain/sun. --- data/battle_scripts_1.s | 4 ++++ include/constants/battle.h | 1 + src/battle_script_commands.c | 30 +++++++++++++----------------- src/battle_util.c | 10 ++++------ 4 files changed, 22 insertions(+), 23 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 6d6c1dae8..6373a7750 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -7697,8 +7697,10 @@ BattleScript_DesolateLandEvaporatesWaterTypeMoves:: attackstring pause B_WAIT_TIME_SHORT ppreduce + jumpifword CMP_COMMON_BITS, gHitMarker, HITMARKER_STRING_PRINTED, BattleScript_MoveEnd printstring STRINGID_MOVEEVAPORATEDINTHEHARSHSUNLIGHT waitmessage B_WAIT_TIME_LONG + orword gHitMarker, HITMARKER_STRING_PRINTED goto BattleScript_MoveEnd BattleScript_PrimordialSeaActivates:: @@ -7715,8 +7717,10 @@ BattleScript_PrimordialSeaFizzlesOutFireTypeMoves:: attackstring pause B_WAIT_TIME_SHORT ppreduce + jumpifword CMP_COMMON_BITS, gHitMarker, HITMARKER_STRING_PRINTED, BattleScript_MoveEnd printstring STRINGID_MOVEFIZZLEDOUTINTHEHEAVYRAIN waitmessage B_WAIT_TIME_LONG + orword gHitMarker, HITMARKER_STRING_PRINTED goto BattleScript_MoveEnd BattleScript_DeltaStreamActivates:: diff --git a/include/constants/battle.h b/include/constants/battle.h index 918c3e7f0..8841a3c12 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -200,6 +200,7 @@ #define HITMARKER_CHARGING (1 << 27) #define HITMARKER_FAINTED(battler) (gBitTable[battler] << 28) #define HITMARKER_FAINTED2(battler) ((1 << 28) << battler) +#define HITMARKER_STRING_PRINTED (1 << 29) // Per-side statuses that affect an entire party #define SIDE_STATUS_REFLECT (1 << 0) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index ee9379d8d..0fb2e5599 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1337,24 +1337,20 @@ static void Cmd_attackcanceler(void) GET_MOVE_TYPE(gCurrentMove, moveType); - if (moveType == TYPE_FIRE - && (gBattleWeather & WEATHER_RAIN_PRIMAL) - && WEATHER_HAS_EFFECT - && gBattleMoves[gCurrentMove].power) + if (WEATHER_HAS_EFFECT && gBattleMoves[gCurrentMove].power) { - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_PrimordialSeaFizzlesOutFireTypeMoves; - return; - } - - if (moveType == TYPE_WATER - && (gBattleWeather & WEATHER_SUN_PRIMAL) - && WEATHER_HAS_EFFECT - && gBattleMoves[gCurrentMove].power) - { - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_DesolateLandEvaporatesWaterTypeMoves; - return; + if (moveType == TYPE_FIRE && (gBattleWeather & WEATHER_RAIN_PRIMAL)) + { + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_PrimordialSeaFizzlesOutFireTypeMoves; + return; + } + else if (moveType == TYPE_WATER && (gBattleWeather & WEATHER_SUN_PRIMAL)) + { + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_DesolateLandEvaporatesWaterTypeMoves; + return; + } } if (gBattleOutcome != 0) diff --git a/src/battle_util.c b/src/battle_util.c index f87e0a134..13908c209 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -8884,12 +8884,10 @@ bool32 CanMegaEvolve(u8 battlerId) // Check if trainer already mega evolved a pokemon. if (mega->alreadyEvolved[battlerPosition]) return FALSE; - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - { - if (IsPartnerMonFromSameTrainer(battlerId) - && (mega->alreadyEvolved[partnerPosition] || (mega->toEvolve & gBitTable[BATTLE_PARTNER(battlerId)]))) - return FALSE; - } + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && IsPartnerMonFromSameTrainer(battlerId) + && (mega->alreadyEvolved[partnerPosition] || (mega->toEvolve & gBitTable[BATTLE_PARTNER(battlerId)]))) + return FALSE; // Gets mon data. if (GetBattlerSide(battlerId) == B_SIDE_OPPONENT) From 2fe015e5ce686a5e4ffa6441d46907f849e830b9 Mon Sep 17 00:00:00 2001 From: LOuroboros Date: Sat, 13 Nov 2021 09:46:34 -0300 Subject: [PATCH 012/130] Implemented Fling --- asm/macros/battle_script.inc | 19 ++++ data/battle_scripts_1.s | 74 ++++++++++++++- include/constants/battle_config.h | 1 + include/constants/battle_script_commands.h | 4 + include/constants/battle_string_ids.h | 3 +- src/battle_message.c | 2 + src/battle_script_commands.c | 100 +++++++++++++++++++++ src/battle_util.c | 4 +- 8 files changed, 204 insertions(+), 3 deletions(-) diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index a15dd459f..c49c43d9c 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1921,6 +1921,25 @@ various BS_ATTACKER, VARIOUS_SHELL_SIDE_ARM_CHECK .endm + .macro jumpifflingfails battler:req, ptr:req + various \battler, VARIOUS_JUMP_IF_FLING_FAILS + .4byte \ptr + .endm + + .macro jumpifholdeffect battler:req, holdEffet:req, ptr:req + various \battler, VARIOUS_JUMP_IF_HOLD_EFFECT + .byte \holdEffet + .4byte \ptr + .endm + + .macro curecertainstatuses battler:req + various \battler, VARIOUS_CURE_CERTAIN_STATUSES + .endm + + .macro tryresetnegativestatstages battler:req + various \battler, VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES + .endm + @ helpful macros .macro setstatchanger stat:req, stages:req, down:req setbyte sSTATCHANGER \stat | \stages << 3 | \down << 7 diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index ee859f0e0..dd90c9bf4 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -235,7 +235,7 @@ gBattleScriptsForMoveEffects:: .4byte BattleScript_EffectDragonDance @ EFFECT_DRAGON_DANCE .4byte BattleScript_EffectCamouflage @ EFFECT_CAMOUFLAGE .4byte BattleScript_EffectHit @ EFFECT_PLEDGE - .4byte BattleScript_EffectHit @ EFFECT_FLING + .4byte BattleScript_EffectFling @ EFFECT_FLING .4byte BattleScript_EffectNaturalGift @ EFFECT_NATURAL_GIFT .4byte BattleScript_EffectWakeUpSlap @ EFFECT_WAKE_UP_SLAP .4byte BattleScript_EffectHit @ EFFECT_WRING_OUT @@ -404,6 +404,78 @@ gBattleScriptsForMoveEffects:: .4byte BattleScript_EffectClangorousSoul @ EFFECT_CLANGOROUS_SOUL .4byte BattleScript_EffectHit @ EFFECT_BOLT_BEAK +BattleScript_EffectFling: + jumpifword CMP_COMMON_BITS, gFieldStatuses, STATUS_FIELD_MAGIC_ROOM, BattleScript_ButItFailed + jumpifability BS_ATTACKER, ABILITY_KLUTZ, BattleScript_ButItFailedAtkStringPpReduce + jumpifability BS_ATTACKER, ABILITY_UNNERVE, BattleScript_ButItFailedAtkStringPpReduce + jumpifflingfails BS_ATTACKER, BattleScript_ButItFailedAtkStringPpReduce + attackcanceler + accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE + attackstring + pause B_WAIT_TIME_SHORT + setlastuseditem BS_ATTACKER + printstring STRINGID_PKMNFLUNG + waitmessage B_WAIT_TIME_SHORT + ppreduce + critcalc + damagecalc + adjustdamage + attackanimation + waitanimation + effectivenesssound + hitanimation BS_TARGET + waitstate + healthbarupdate BS_TARGET + datahpupdate BS_TARGET + critmessage + waitmessage B_WAIT_TIME_MED + resultmessage + waitmessage B_WAIT_TIME_MED +.if B_FLING_EMBARGO_ITEM <= GEN_4 + jumpifstatus3 BS_TARGET, STATUS3_EMBARGO, BattleScript_FlingEnd +.endif + jumpifholdeffect BS_ATTACKER, HOLD_EFFECT_FLAME_ORB, BattleScript_FlingFlameOrb + jumpifholdeffect BS_ATTACKER, HOLD_EFFECT_FLINCH, BattleScript_FlingFlinch + jumpifholdeffect BS_ATTACKER, HOLD_EFFECT_LIGHT_BALL, BattleScript_FlingLightBall + jumpifholdeffect BS_ATTACKER, HOLD_EFFECT_MENTAL_HERB, BattleScript_FlingMentalHerb + jumpifholdeffect BS_ATTACKER, HOLD_EFFECT_POISON_POWER, BattleScript_FlingPoisonBarb + jumpifholdeffect BS_ATTACKER, HOLD_EFFECT_TOXIC_ORB, BattleScript_FlingToxicOrb + jumpifholdeffect BS_ATTACKER, HOLD_EFFECT_RESTORE_STATS, BattleScript_FlingWhiteHerb +BattleScript_FlingFlameOrb: + setmoveeffect MOVE_EFFECT_BURN + seteffectprimary + goto BattleScript_FlingEnd +BattleScript_FlingFlinch: + setmoveeffect MOVE_EFFECT_FLINCH + seteffectprimary + goto BattleScript_FlingEnd +BattleScript_FlingLightBall: + setmoveeffect MOVE_EFFECT_PARALYSIS + seteffectprimary + goto BattleScript_FlingEnd +BattleScript_FlingMentalHerb: + curecertainstatuses BS_TARGET + goto BattleScript_FlingEnd +BattleScript_FlingPoisonBarb: + setmoveeffect MOVE_EFFECT_POISON + seteffectprimary + goto BattleScript_FlingEnd +BattleScript_FlingToxicOrb: + setmoveeffect MOVE_EFFECT_TOXIC + seteffectprimary + goto BattleScript_FlingEnd +BattleScript_FlingWhiteHerb: + tryresetnegativestatstages BS_TARGET + swapattackerwithtarget + printstring STRINGID_PKMNSTATUSNORMAL + waitmessage B_WAIT_TIME_MED + swapattackerwithtarget + goto BattleScript_FlingEnd +BattleScript_FlingEnd: + tryfaintmon BS_TARGET, FALSE, NULL + removeitem BS_ATTACKER + goto BattleScript_MoveEnd + BattleScript_EffectShellSideArm: shellsidearmcheck setmoveeffect MOVE_EFFECT_POISON diff --git a/include/constants/battle_config.h b/include/constants/battle_config.h index 8e72b2c99..793bfacf7 100644 --- a/include/constants/battle_config.h +++ b/include/constants/battle_config.h @@ -137,6 +137,7 @@ #define B_KINGS_SHIELD_LOWER_ATK GEN_7 // In Gen7+, it lowers Atk by 1 stage instead of 2 of oponents that hit it. #define B_SPEED_BUFFING_RAPID_SPIN GEN_8 // In Gen8, Rapid Spin raises the user's Speed by 1 stage. #define B_RECOIL_IF_MISS_DMG GEN_7 // In Gen5+, Jump Kick and High Jump Kick will always do half of the user's max HP when missing. +#define B_FLING_EMBARGO_ITEM GEN_7 // In Gen4, if a target is under the effects of Embargo, the user's item's hold effect doesn't activate. // Move accuracy settings #define B_TOXIC_NEVER_MISS GEN_7 // In Gen6+, if Toxic is used by a Poison-type Pokémon, it will never miss. diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 7ceb1d64b..6ace7458e 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -207,6 +207,10 @@ #define VARIOUS_CHECK_POLTERGEIST 134 #define VARIOUS_SET_OCTOLOCK 135 #define VARIOUS_CUT_1_3_HP_RAISE_STATS 136 +#define VARIOUS_JUMP_IF_FLING_FAILS 137 +#define VARIOUS_JUMP_IF_HOLD_EFFECT 138 +#define VARIOUS_CURE_CERTAIN_STATUSES 139 +#define VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES 140 // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 0 diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index d439e3e7f..89d3be8b8 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -607,8 +607,9 @@ #define STRINGID_PKMNBECAMEWEAKERTOFIRE 604 #define STRINGID_ABOUTTOUSEPOLTERGEIST 605 #define STRINGID_CANTESCAPEBECAUSEOFCURRENTMOVE 606 +#define STRINGID_TARGETGOTOVERINFATUATION 607 -#define BATTLESTRINGS_COUNT 607 +#define BATTLESTRINGS_COUNT 608 // The below IDs are all indexes into battle message tables, // used to determine which of a set of messages to print. diff --git a/src/battle_message.c b/src/battle_message.c index 30af20a78..728870d69 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -733,9 +733,11 @@ static const u8 sText_CantEscapeDueToUsedMove[] = _("{B_ATK_NAME_WITH_PREFIX} ca static const u8 sText_PkmnBecameWeakerToFire[] = _("{B_DEF_NAME_WITH_PREFIX} became\nweaker to fire!"); static const u8 sText_PkmnAboutToBeAttackedByItsItem[] = _("{B_DEF_NAME_WITH_PREFIX} is about\nto be attacked by its {B_BUFF1}!"); static const u8 sText_CantEscapeBecauseOfCurrentMove[] = _("{B_DEF_NAME_WITH_PREFIX} can no longer escape\nbecause of {B_CURRENT_MOVE}!"); +static const u8 sText_TargetGotOverInfatuation[] =_("{B_DEF_NAME_WITH_PREFIX} got over\nits infatuation!"); const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = { + [STRINGID_TARGETGOTOVERINFATUATION - 12] = sText_TargetGotOverInfatuation, [STRINGID_BATTLERTYPECHANGEDTO - 12] = sText_BattlerTypeChangedTo, [STRINGID_PASTELVEILENTERS - 12] = sText_PastelVeilEnters, [STRINGID_PASTELVEILPROTECTED -12] = sText_PastelVeilProtected, diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 3f9ba388f..88c3af2f0 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -9287,6 +9287,106 @@ static void Cmd_various(void) gBattlescriptCurrInstr += 7; return; } + case VARIOUS_JUMP_IF_FLING_FAILS: + #ifdef ITEM_EXPANSION + if (!ItemId_GetFlingPower(gBattleMons[gActiveBattler].item)) + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); + else if (!CanBattlerGetOrLoseItem(gActiveBattler, gBattleMons[gActiveBattler].item)) + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); + #else + if (!CanBattlerGetOrLoseItem(gActiveBattler, gBattleMons[gActiveBattler].item)) + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); + #endif + else + gBattlescriptCurrInstr += 7; + return; + case VARIOUS_JUMP_IF_HOLD_EFFECT: + if (GetBattlerHoldEffect(gActiveBattler, TRUE) == gBattlescriptCurrInstr[3]) + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 4); + else + gBattlescriptCurrInstr += 8; + return; + case VARIOUS_CURE_CERTAIN_STATUSES: + if (gBattleMons[gActiveBattler].status2 & STATUS2_INFATUATION) + { + gBattleMons[gActiveBattler].status2 &= ~(STATUS2_INFATUATION); + gBattleMons[gActiveBattler].status2 = 0; + BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBattler].status2); + MarkBattlerForControllerExec(gActiveBattler); + PrepareStringBattle(STRINGID_TARGETGOTOVERINFATUATION, gActiveBattler); + gBattleCommunication[MSG_DISPLAY] = 1; + } + else if (gBattleMons[gActiveBattler].status2 & STATUS2_TORMENT) + { + gBattleMons[gActiveBattler].status2 &= ~(STATUS2_TORMENT); + gBattleMons[gActiveBattler].status2 = 0; + BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBattler].status2); + MarkBattlerForControllerExec(gActiveBattler); + // Swap gBattlerTarget and gBattlerAttacker so STRINGID_BUFFERENDS works correctly + gActiveBattler = gBattlerAttacker; + gBattlerAttacker = gBattlerTarget; + gBattlerTarget = gActiveBattler; + gHitMarker |= HITMARKER_SWAP_ATTACKER_TARGET; + PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_TORMENT); + PrepareStringBattle(STRINGID_BUFFERENDS, gActiveBattler); + gBattleCommunication[MSG_DISPLAY] = 1; + // Swap gBattlerTarget and gBattlerAttacker back + if (gHitMarker & HITMARKER_SWAP_ATTACKER_TARGET) + gHitMarker &= ~(HITMARKER_SWAP_ATTACKER_TARGET); + } + else if (gDisableStructs[gActiveBattler].tauntTimer != 0) + { + gDisableStructs[gActiveBattler].tauntTimer = 0; + // Swap gBattlerTarget and gBattlerAttacker so STRINGID_BUFFERENDS works correctly + gActiveBattler = gBattlerAttacker; + gBattlerAttacker = gBattlerTarget; + gBattlerTarget = gActiveBattler; + gHitMarker |= HITMARKER_SWAP_ATTACKER_TARGET; + PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_TAUNT); + PrepareStringBattle(STRINGID_BUFFERENDS, gActiveBattler); + gBattleCommunication[MSG_DISPLAY] = 1; + // Swap gBattlerTarget and gBattlerAttacker back + if (gHitMarker & HITMARKER_SWAP_ATTACKER_TARGET) + gHitMarker &= ~(HITMARKER_SWAP_ATTACKER_TARGET); + } + else if (gDisableStructs[gActiveBattler].encoreTimer) + { + gDisableStructs[gActiveBattler].encoredMove = 0; + gDisableStructs[gActiveBattler].encoreTimer = 0; + // Swap gBattlerTarget and gBattlerAttacker so STRINGID_BUFFERENDS works correctly + gActiveBattler = gBattlerAttacker; + gBattlerAttacker = gBattlerTarget; + gBattlerTarget = gActiveBattler; + gHitMarker |= HITMARKER_SWAP_ATTACKER_TARGET; + PrepareStringBattle(STRINGID_PKMNENCOREENDED, gActiveBattler); + gBattleCommunication[MSG_DISPLAY] = 1; + // Swap gBattlerTarget and gBattlerAttacker back + if (gHitMarker & HITMARKER_SWAP_ATTACKER_TARGET) + gHitMarker &= ~(HITMARKER_SWAP_ATTACKER_TARGET); + } + else if (gDisableStructs[gActiveBattler].disableTimer) + { + gDisableStructs[gActiveBattler].disabledMove = 0; + // Swap gBattlerTarget and gBattlerAttacker so STRINGID_BUFFERENDS works correctly + gActiveBattler = gBattlerAttacker; + gBattlerAttacker = gBattlerTarget; + gBattlerTarget = gActiveBattler; + gHitMarker |= HITMARKER_SWAP_ATTACKER_TARGET; + PrepareStringBattle(STRINGID_PKMNMOVEDISABLEDNOMORE, gBattlerTarget); + gBattleCommunication[MSG_DISPLAY] = 1; + // Swap gBattlerTarget and gBattlerAttacker back + if (gHitMarker & HITMARKER_SWAP_ATTACKER_TARGET) + gHitMarker &= ~(HITMARKER_SWAP_ATTACKER_TARGET); + } + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 7); + return; + case VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES: + gActiveBattler = gBattlerTarget; + for (i = 0; i < NUM_BATTLE_STATS; i++) + if (gBattleMons[gActiveBattler].statStages[i] < DEFAULT_STAT_STAGE) + gBattleMons[gActiveBattler].statStages[i] = DEFAULT_STAT_STAGE; + gBattlescriptCurrInstr += 3; + return; } // End of switch (gBattlescriptCurrInstr[2]) gBattlescriptCurrInstr += 3; diff --git a/src/battle_util.c b/src/battle_util.c index 18847b8cc..0c8ff91b9 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -7693,7 +7693,9 @@ static u16 CalcMoveBasePower(u16 move, u8 battlerAtk, u8 battlerDef) // todo break; case EFFECT_FLING: - // todo: program Fling + Unburden interaction + #ifdef ITEM_EXPANSION + basePower = ItemId_GetFlingPower(gBattleMons[battlerAtk].item); + #endif break; case EFFECT_ERUPTION: basePower = gBattleMons[battlerAtk].hp * basePower / gBattleMons[battlerAtk].maxHP; From cbb6639f8d367fdf6a7addcb4e1d643074ad286c Mon Sep 17 00:00:00 2001 From: LOuroboros Date: Sat, 13 Nov 2021 10:53:04 -0300 Subject: [PATCH 013/130] Fling tweaks -Updated and renamed VARIOUS_JUMP_IF_FLING_FAILS (now VARIOUS_JUMP_IF_NO_FLING_POWER) -Updated BattleScript_EffectFling following Smogon's description of Fling's effect. -Refactored BattleScript_FlingMentalHerb thanks to GetMentalHerbEffect -No need to define flingPower when its value is 0 -Forced the target to eat a berry that was flung at them by overwriting their item with the berry thrown and restoring their original item after its effect finishes. -Added a preproc config for Klutz. --- asm/macros/battle_script.inc | 33 ++- data/battle_scripts_1.s | 53 ++-- include/battle.h | 1 + include/constants/battle_config.h | 2 +- include/constants/battle_script_commands.h | 279 +++++++++++---------- src/battle_script_commands.c | 138 +++++----- 6 files changed, 269 insertions(+), 237 deletions(-) diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index c49c43d9c..282fbb306 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1921,14 +1921,8 @@ various BS_ATTACKER, VARIOUS_SHELL_SIDE_ARM_CHECK .endm - .macro jumpifflingfails battler:req, ptr:req - various \battler, VARIOUS_JUMP_IF_FLING_FAILS - .4byte \ptr - .endm - - .macro jumpifholdeffect battler:req, holdEffet:req, ptr:req - various \battler, VARIOUS_JUMP_IF_HOLD_EFFECT - .byte \holdEffet + .macro jumpifnoflingpower battler:req, ptr:req + various \battler, VARIOUS_JUMP_IF_NO_FLING_POWER .4byte \ptr .endm @@ -1940,6 +1934,29 @@ various \battler, VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES .endm + .macro jumpiflastuseditemberry ptr:req + various BS_ATTACKER, VARIOUS_JUMP_IF_LAST_USED_ITEM_BERRY + .4byte \ptr + .endm + + .macro jumpiflastuseditemholdeffect battler:req, holdEffect:req, ptr:req + various \battler, VARIOUS_JUMP_IF_LAST_USED_ITEM_HOLD_EFFECT + .byte \holdEffect + .4byte \ptr + .endm + + .macro savebattleritem battler:req + various \battler, VARIOUS_SAVE_BATTLER_ITEM + .endm + + .macro restorebattleritem battler:req + various \battler, VARIOUS_RESTORE_BATTLER_ITEM + .endm + + .macro battleritemtolastuseditem battler:req + various \battler, VARIOUS_BATTLER_ITEM_TO_LAST_USED_ITEM + .endm + @ helpful macros .macro setstatchanger stat:req, stages:req, down:req setbyte sSTATCHANGER \stat | \stages << 3 | \down << 7 diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index dd90c9bf4..c395d9f7b 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -405,15 +405,18 @@ gBattleScriptsForMoveEffects:: .4byte BattleScript_EffectHit @ EFFECT_BOLT_BEAK BattleScript_EffectFling: - jumpifword CMP_COMMON_BITS, gFieldStatuses, STATUS_FIELD_MAGIC_ROOM, BattleScript_ButItFailed + jumpifnoflingpower BS_ATTACKER, BattleScript_ButItFailedAtkStringPpReduce + jumpifstatus3 BS_ATTACKER, STATUS3_EMBARGO, BattleScript_ButItFailedAtkStringPpReduce + jumpifword CMP_COMMON_BITS, gFieldStatuses, STATUS_FIELD_MAGIC_ROOM, BattleScript_ButItFailedAtkStringPpReduce +.if B_KLUTZ_FLING_INTERACTION >= GEN_5 jumpifability BS_ATTACKER, ABILITY_KLUTZ, BattleScript_ButItFailedAtkStringPpReduce - jumpifability BS_ATTACKER, ABILITY_UNNERVE, BattleScript_ButItFailedAtkStringPpReduce - jumpifflingfails BS_ATTACKER, BattleScript_ButItFailedAtkStringPpReduce +.endif + setlastuseditem BS_ATTACKER + removeitem BS_ATTACKER attackcanceler accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE attackstring pause B_WAIT_TIME_SHORT - setlastuseditem BS_ATTACKER printstring STRINGID_PKMNFLUNG waitmessage B_WAIT_TIME_SHORT ppreduce @@ -431,16 +434,27 @@ BattleScript_EffectFling: waitmessage B_WAIT_TIME_MED resultmessage waitmessage B_WAIT_TIME_MED -.if B_FLING_EMBARGO_ITEM <= GEN_4 - jumpifstatus3 BS_TARGET, STATUS3_EMBARGO, BattleScript_FlingEnd -.endif - jumpifholdeffect BS_ATTACKER, HOLD_EFFECT_FLAME_ORB, BattleScript_FlingFlameOrb - jumpifholdeffect BS_ATTACKER, HOLD_EFFECT_FLINCH, BattleScript_FlingFlinch - jumpifholdeffect BS_ATTACKER, HOLD_EFFECT_LIGHT_BALL, BattleScript_FlingLightBall - jumpifholdeffect BS_ATTACKER, HOLD_EFFECT_MENTAL_HERB, BattleScript_FlingMentalHerb - jumpifholdeffect BS_ATTACKER, HOLD_EFFECT_POISON_POWER, BattleScript_FlingPoisonBarb - jumpifholdeffect BS_ATTACKER, HOLD_EFFECT_TOXIC_ORB, BattleScript_FlingToxicOrb - jumpifholdeffect BS_ATTACKER, HOLD_EFFECT_RESTORE_STATS, BattleScript_FlingWhiteHerb + jumpiflastuseditemberry BattleScript_EffectFlingConsumeBerry + jumpiflastuseditemholdeffect BS_ATTACKER, HOLD_EFFECT_FLAME_ORB, BattleScript_FlingFlameOrb + jumpiflastuseditemholdeffect BS_ATTACKER, HOLD_EFFECT_FLINCH, BattleScript_FlingFlinch + jumpiflastuseditemholdeffect BS_ATTACKER, HOLD_EFFECT_LIGHT_BALL, BattleScript_FlingLightBall + jumpiflastuseditemholdeffect BS_ATTACKER, HOLD_EFFECT_MENTAL_HERB, BattleScript_FlingMentalHerb + jumpiflastuseditemholdeffect BS_ATTACKER, HOLD_EFFECT_POISON_POWER, BattleScript_FlingPoisonBarb + jumpiflastuseditemholdeffect BS_ATTACKER, HOLD_EFFECT_TOXIC_ORB, BattleScript_FlingToxicOrb + jumpiflastuseditemholdeffect BS_ATTACKER, HOLD_EFFECT_RESTORE_STATS, BattleScript_FlingWhiteHerb +BattleScript_EffectFlingConsumeBerry: + savebattleritem BS_TARGET + battleritemtolastuseditem BS_TARGET + setbyte sBERRY_OVERRIDE, TRUE @ override the requirements for eating berries + orword gHitMarker, HITMARKER_NO_ANIMATIONS + consumeberry BS_TARGET + bicword gHitMarker, HITMARKER_NO_ANIMATIONS + setbyte sBERRY_OVERRIDE, FALSE + restorebattleritem BS_TARGET +BattleScript_FlingEnd: + tryfaintmon BS_TARGET, FALSE, NULL + goto BattleScript_MoveEnd + BattleScript_FlingFlameOrb: setmoveeffect MOVE_EFFECT_BURN seteffectprimary @@ -455,6 +469,13 @@ BattleScript_FlingLightBall: goto BattleScript_FlingEnd BattleScript_FlingMentalHerb: curecertainstatuses BS_TARGET + savetarget + copybyte gBattlerAttacker, gBattlerTarget + playanimation BS_ATTACKER, B_ANIM_HELD_ITEM_EFFECT, NULL + printfromtable gMentalHerbCureStringIds + waitmessage B_WAIT_TIME_LONG + updatestatusicon BS_ATTACKER + restoretarget goto BattleScript_FlingEnd BattleScript_FlingPoisonBarb: setmoveeffect MOVE_EFFECT_POISON @@ -471,10 +492,6 @@ BattleScript_FlingWhiteHerb: waitmessage B_WAIT_TIME_MED swapattackerwithtarget goto BattleScript_FlingEnd -BattleScript_FlingEnd: - tryfaintmon BS_TARGET, FALSE, NULL - removeitem BS_ATTACKER - goto BattleScript_MoveEnd BattleScript_EffectShellSideArm: shellsidearmcheck diff --git a/include/battle.h b/include/battle.h index f1262b128..5035aa5a0 100644 --- a/include/battle.h +++ b/include/battle.h @@ -302,6 +302,7 @@ struct BattleHistory u8 moveHistoryIndex[MAX_BATTLERS_COUNT]; u16 trainerItems[MAX_BATTLERS_COUNT]; u8 itemsNo; + u16 heldItems[MAX_BATTLERS_COUNT]; }; struct BattleScriptsStack diff --git a/include/constants/battle_config.h b/include/constants/battle_config.h index 793bfacf7..310815d48 100644 --- a/include/constants/battle_config.h +++ b/include/constants/battle_config.h @@ -137,7 +137,7 @@ #define B_KINGS_SHIELD_LOWER_ATK GEN_7 // In Gen7+, it lowers Atk by 1 stage instead of 2 of oponents that hit it. #define B_SPEED_BUFFING_RAPID_SPIN GEN_8 // In Gen8, Rapid Spin raises the user's Speed by 1 stage. #define B_RECOIL_IF_MISS_DMG GEN_7 // In Gen5+, Jump Kick and High Jump Kick will always do half of the user's max HP when missing. -#define B_FLING_EMBARGO_ITEM GEN_7 // In Gen4, if a target is under the effects of Embargo, the user's item's hold effect doesn't activate. +#define B_KLUTZ_FLING_INTERACTION GEN_7 // In Gen5+, Pokémon with the Klutz ability can't use Fling. // Move accuracy settings #define B_TOXIC_NEVER_MISS GEN_7 // In Gen6+, if Toxic is used by a Poison-type Pokémon, it will never miss. diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 6ace7458e..e09fb0155 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -74,143 +74,148 @@ #define CMP_NO_COMMON_BITS 5 // Cmd_various -#define VARIOUS_CANCEL_MULTI_TURN_MOVES 0 -#define VARIOUS_SET_MAGIC_COAT_TARGET 1 -#define VARIOUS_IS_RUNNING_IMPOSSIBLE 2 -#define VARIOUS_GET_MOVE_TARGET 3 -#define VARIOUS_GET_BATTLER_FAINTED 4 -#define VARIOUS_RESET_INTIMIDATE_TRACE_BITS 5 -#define VARIOUS_UPDATE_CHOICE_MOVE_ON_LVL_UP 6 -#define VARIOUS_PALACE_FLAVOR_TEXT 8 -#define VARIOUS_ARENA_JUDGMENT_WINDOW 9 -#define VARIOUS_ARENA_OPPONENT_MON_LOST 10 -#define VARIOUS_ARENA_PLAYER_MON_LOST 11 -#define VARIOUS_ARENA_BOTH_MONS_LOST 12 -#define VARIOUS_EMIT_YESNOBOX 13 -#define VARIOUS_ARENA_JUDGMENT_STRING 16 -#define VARIOUS_ARENA_WAIT_STRING 17 -#define VARIOUS_WAIT_CRY 18 -#define VARIOUS_RETURN_OPPONENT_MON1 19 -#define VARIOUS_RETURN_OPPONENT_MON2 20 -#define VARIOUS_VOLUME_DOWN 21 -#define VARIOUS_VOLUME_UP 22 -#define VARIOUS_SET_ALREADY_STATUS_MOVE_ATTEMPT 23 -#define VARIOUS_SET_TELEPORT_OUTCOME 25 -#define VARIOUS_PLAY_TRAINER_DEFEATED_MUSIC 26 -#define VARIOUS_STAT_TEXT_BUFFER 27 -#define VARIOUS_SWITCHIN_ABILITIES 28 -#define VARIOUS_SAVE_TARGET 29 -#define VARIOUS_RESTORE_TARGET 30 -#define VARIOUS_INSTANT_HP_DROP 31 -#define VARIOUS_CLEAR_STATUS 32 -#define VARIOUS_RESTORE_PP 33 -#define VARIOUS_TRY_ACTIVATE_MOXIE 34 -#define VARIOUS_TRY_ACTIVATE_FELL_STINGER 35 -#define VARIOUS_PLAY_MOVE_ANIMATION 36 -#define VARIOUS_SET_LUCKY_CHANT 37 -#define VARIOUS_SUCKER_PUNCH_CHECK 38 -#define VARIOUS_SET_SIMPLE_BEAM 39 -#define VARIOUS_TRY_ENTRAINMENT 40 -#define VARIOUS_SET_LAST_USED_ABILITY 41 -#define VARIOUS_TRY_HEAL_PULSE 42 -#define VARIOUS_TRY_QUASH 43 -#define VARIOUS_INVERT_STAT_STAGES 44 -#define VARIOUS_SET_TERRAIN 45 -#define VARIOUS_TRY_ME_FIRST 46 -#define VARIOUS_JUMP_IF_BATTLE_END 47 -#define VARIOUS_TRY_ELECTRIFY 48 -#define VARIOUS_TRY_REFLECT_TYPE 49 -#define VARIOUS_TRY_SOAK 50 -#define VARIOUS_HANDLE_MEGA_EVO 51 -#define VARIOUS_TRY_LAST_RESORT 52 -#define VARIOUS_ARGUMENT_STATUS_EFFECT 53 -#define VARIOUS_TRY_HIT_SWITCH_TARGET 54 -#define VARIOUS_TRY_AUTOTOMIZE 55 -#define VARIOUS_TRY_COPYCAT 56 -#define VARIOUS_ABILITY_POPUP 57 -#define VARIOUS_DEFOG 58 -#define VARIOUS_JUMP_IF_TARGET_ALLY 59 -#define VARIOUS_TRY_SYNCHRONOISE 60 -#define VARIOUS_PSYCHO_SHIFT 61 -#define VARIOUS_CURE_STATUS 62 -#define VARIOUS_POWER_TRICK 63 -#define VARIOUS_AFTER_YOU 64 -#define VARIOUS_BESTOW 65 -#define VARIOUS_ARGUMENT_TO_MOVE_EFFECT 66 -#define VARIOUS_JUMP_IF_NOT_GROUNDED 67 -#define VARIOUS_HANDLE_TRAINER_SLIDE_MSG 68 -#define VARIOUS_TRY_TRAINER_SLIDE_MSG_FIRST_OFF 69 -#define VARIOUS_TRY_TRAINER_SLIDE_MSG_LAST_ON 70 -#define VARIOUS_SET_AURORA_VEIL 71 -#define VARIOUS_TRY_THIRD_TYPE 72 -#define VARIOUS_ACUPRESSURE 73 -#define VARIOUS_SET_POWDER 74 -#define VARIOUS_SPECTRAL_THIEF 75 -#define VARIOUS_GRAVITY_ON_AIRBORNE_MONS 76 -#define VARIOUS_CHECK_IF_GRASSY_TERRAIN_HEALS 77 -#define VARIOUS_JUMP_IF_ROAR_FAILS 78 -#define VARIOUS_TRY_INSTRUCT 79 -#define VARIOUS_JUMP_IF_NOT_BERRY 80 -#define VARIOUS_TRACE_ABILITY 81 -#define VARIOUS_UPDATE_NICK 82 -#define VARIOUS_TRY_ILLUSION_OFF 83 -#define VARIOUS_SET_SPRITEIGNORE0HP 84 -#define VARIOUS_HANDLE_FORM_CHANGE 85 -#define VARIOUS_GET_STAT_VALUE 86 -#define VARIOUS_JUMP_IF_FULL_HP 87 -#define VARIOUS_LOSE_TYPE 88 -#define VARIOUS_TRY_ACTIVATE_SOULHEART 89 -#define VARIOUS_TRY_ACTIVATE_RECEIVER 90 -#define VARIOUS_TRY_ACTIVATE_BEAST_BOOST 91 -#define VARIOUS_TRY_FRISK 92 -#define VARIOUS_JUMP_IF_SHIELDS_DOWN_PROTECTED 93 -#define VARIOUS_TRY_FAIRY_LOCK 94 -#define VARIOUS_JUMP_IF_NO_ALLY 95 -#define VARIOUS_POISON_TYPE_IMMUNITY 96 -#define VARIOUS_JUMP_IF_NO_HOLD_EFFECT 97 -#define VARIOUS_INFATUATE_WITH_BATTLER 98 -#define VARIOUS_SET_LAST_USED_ITEM 99 -#define VARIOUS_PARALYZE_TYPE_IMMUNITY 100 -#define VARIOUS_JUMP_IF_ABSENT 101 -#define VARIOUS_DESTROY_ABILITY_POPUP 102 -#define VARIOUS_TOTEM_BOOST 103 -#define VARIOUS_TRY_ACTIVATE_GRIM_NEIGH 104 -#define VARIOUS_MOVEEND_ITEM_EFFECTS 105 -#define VARIOUS_TERRAIN_SEED 106 -#define VARIOUS_MAKE_INVISIBLE 107 -#define VARIOUS_ROOM_SERVICE 108 -#define VARIOUS_JUMP_IF_TERRAIN_AFFECTED 109 -#define VARIOUS_EERIE_SPELL_PP_REDUCE 110 -#define VARIOUS_JUMP_IF_TEAM_HEALTHY 111 -#define VARIOUS_TRY_HEAL_QUARTER_HP 112 -#define VARIOUS_REMOVE_TERRAIN 113 -#define VARIOUS_JUMP_IF_PRANKSTER_BLOCKED 114 -#define VARIOUS_TRY_TO_CLEAR_PRIMAL_WEATHER 115 -#define VARIOUS_GET_ROTOTILLER_TARGETS 116 -#define VARIOUS_JUMP_IF_NOT_ROTOTILLER_AFFECTED 117 -#define VARIOUS_TRY_ACTIVATE_BATTLE_BOND 118 -#define VARIOUS_CONSUME_BERRY 119 -#define VARIOUS_JUMP_IF_CANT_REVERT_TO_PRIMAL 120 -#define VARIOUS_HANDLE_PRIMAL_REVERSION 121 -#define VARIOUS_APPLY_PLASMA_FISTS 122 -#define VARIOUS_JUMP_IF_SPECIES 123 -#define VARIOUS_UPDATE_ABILITY_POPUP 124 -#define VARIOUS_JUMP_IF_WEATHER_AFFECTED 125 -#define VARIOUS_JUMP_IF_LEAF_GUARD_PROTECTED 126 -#define VARIOUS_SET_ATTACKER_STICKY_WEB_USER 127 -#define VARIOUS_TRY_TO_APPLY_MIMICRY 128 -#define VARIOUS_PHOTON_GEYSER_CHECK 129 -#define VARIOUS_SHELL_SIDE_ARM_CHECK 130 -#define VARIOUS_TRY_NO_RETREAT 131 -#define VARIOUS_TRY_TAR_SHOT 132 -#define VARIOUS_CAN_TAR_SHOT_WORK 133 -#define VARIOUS_CHECK_POLTERGEIST 134 -#define VARIOUS_SET_OCTOLOCK 135 -#define VARIOUS_CUT_1_3_HP_RAISE_STATS 136 -#define VARIOUS_JUMP_IF_FLING_FAILS 137 -#define VARIOUS_JUMP_IF_HOLD_EFFECT 138 -#define VARIOUS_CURE_CERTAIN_STATUSES 139 -#define VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES 140 +#define VARIOUS_CANCEL_MULTI_TURN_MOVES 0 +#define VARIOUS_SET_MAGIC_COAT_TARGET 1 +#define VARIOUS_IS_RUNNING_IMPOSSIBLE 2 +#define VARIOUS_GET_MOVE_TARGET 3 +#define VARIOUS_GET_BATTLER_FAINTED 4 +#define VARIOUS_RESET_INTIMIDATE_TRACE_BITS 5 +#define VARIOUS_UPDATE_CHOICE_MOVE_ON_LVL_UP 6 +#define VARIOUS_PALACE_FLAVOR_TEXT 8 +#define VARIOUS_ARENA_JUDGMENT_WINDOW 9 +#define VARIOUS_ARENA_OPPONENT_MON_LOST 10 +#define VARIOUS_ARENA_PLAYER_MON_LOST 11 +#define VARIOUS_ARENA_BOTH_MONS_LOST 12 +#define VARIOUS_EMIT_YESNOBOX 13 +#define VARIOUS_ARENA_JUDGMENT_STRING 16 +#define VARIOUS_ARENA_WAIT_STRING 17 +#define VARIOUS_WAIT_CRY 18 +#define VARIOUS_RETURN_OPPONENT_MON1 19 +#define VARIOUS_RETURN_OPPONENT_MON2 20 +#define VARIOUS_VOLUME_DOWN 21 +#define VARIOUS_VOLUME_UP 22 +#define VARIOUS_SET_ALREADY_STATUS_MOVE_ATTEMPT 23 +#define VARIOUS_SET_TELEPORT_OUTCOME 25 +#define VARIOUS_PLAY_TRAINER_DEFEATED_MUSIC 26 +#define VARIOUS_STAT_TEXT_BUFFER 27 +#define VARIOUS_SWITCHIN_ABILITIES 28 +#define VARIOUS_SAVE_TARGET 29 +#define VARIOUS_RESTORE_TARGET 30 +#define VARIOUS_INSTANT_HP_DROP 31 +#define VARIOUS_CLEAR_STATUS 32 +#define VARIOUS_RESTORE_PP 33 +#define VARIOUS_TRY_ACTIVATE_MOXIE 34 +#define VARIOUS_TRY_ACTIVATE_FELL_STINGER 35 +#define VARIOUS_PLAY_MOVE_ANIMATION 36 +#define VARIOUS_SET_LUCKY_CHANT 37 +#define VARIOUS_SUCKER_PUNCH_CHECK 38 +#define VARIOUS_SET_SIMPLE_BEAM 39 +#define VARIOUS_TRY_ENTRAINMENT 40 +#define VARIOUS_SET_LAST_USED_ABILITY 41 +#define VARIOUS_TRY_HEAL_PULSE 42 +#define VARIOUS_TRY_QUASH 43 +#define VARIOUS_INVERT_STAT_STAGES 44 +#define VARIOUS_SET_TERRAIN 45 +#define VARIOUS_TRY_ME_FIRST 46 +#define VARIOUS_JUMP_IF_BATTLE_END 47 +#define VARIOUS_TRY_ELECTRIFY 48 +#define VARIOUS_TRY_REFLECT_TYPE 49 +#define VARIOUS_TRY_SOAK 50 +#define VARIOUS_HANDLE_MEGA_EVO 51 +#define VARIOUS_TRY_LAST_RESORT 52 +#define VARIOUS_ARGUMENT_STATUS_EFFECT 53 +#define VARIOUS_TRY_HIT_SWITCH_TARGET 54 +#define VARIOUS_TRY_AUTOTOMIZE 55 +#define VARIOUS_TRY_COPYCAT 56 +#define VARIOUS_ABILITY_POPUP 57 +#define VARIOUS_DEFOG 58 +#define VARIOUS_JUMP_IF_TARGET_ALLY 59 +#define VARIOUS_TRY_SYNCHRONOISE 60 +#define VARIOUS_PSYCHO_SHIFT 61 +#define VARIOUS_CURE_STATUS 62 +#define VARIOUS_POWER_TRICK 63 +#define VARIOUS_AFTER_YOU 64 +#define VARIOUS_BESTOW 65 +#define VARIOUS_ARGUMENT_TO_MOVE_EFFECT 66 +#define VARIOUS_JUMP_IF_NOT_GROUNDED 67 +#define VARIOUS_HANDLE_TRAINER_SLIDE_MSG 68 +#define VARIOUS_TRY_TRAINER_SLIDE_MSG_FIRST_OFF 69 +#define VARIOUS_TRY_TRAINER_SLIDE_MSG_LAST_ON 70 +#define VARIOUS_SET_AURORA_VEIL 71 +#define VARIOUS_TRY_THIRD_TYPE 72 +#define VARIOUS_ACUPRESSURE 73 +#define VARIOUS_SET_POWDER 74 +#define VARIOUS_SPECTRAL_THIEF 75 +#define VARIOUS_GRAVITY_ON_AIRBORNE_MONS 76 +#define VARIOUS_CHECK_IF_GRASSY_TERRAIN_HEALS 77 +#define VARIOUS_JUMP_IF_ROAR_FAILS 78 +#define VARIOUS_TRY_INSTRUCT 79 +#define VARIOUS_JUMP_IF_NOT_BERRY 80 +#define VARIOUS_TRACE_ABILITY 81 +#define VARIOUS_UPDATE_NICK 82 +#define VARIOUS_TRY_ILLUSION_OFF 83 +#define VARIOUS_SET_SPRITEIGNORE0HP 84 +#define VARIOUS_HANDLE_FORM_CHANGE 85 +#define VARIOUS_GET_STAT_VALUE 86 +#define VARIOUS_JUMP_IF_FULL_HP 87 +#define VARIOUS_LOSE_TYPE 88 +#define VARIOUS_TRY_ACTIVATE_SOULHEART 89 +#define VARIOUS_TRY_ACTIVATE_RECEIVER 90 +#define VARIOUS_TRY_ACTIVATE_BEAST_BOOST 91 +#define VARIOUS_TRY_FRISK 92 +#define VARIOUS_JUMP_IF_SHIELDS_DOWN_PROTECTED 93 +#define VARIOUS_TRY_FAIRY_LOCK 94 +#define VARIOUS_JUMP_IF_NO_ALLY 95 +#define VARIOUS_POISON_TYPE_IMMUNITY 96 +#define VARIOUS_JUMP_IF_NO_HOLD_EFFECT 97 +#define VARIOUS_INFATUATE_WITH_BATTLER 98 +#define VARIOUS_SET_LAST_USED_ITEM 99 +#define VARIOUS_PARALYZE_TYPE_IMMUNITY 100 +#define VARIOUS_JUMP_IF_ABSENT 101 +#define VARIOUS_DESTROY_ABILITY_POPUP 102 +#define VARIOUS_TOTEM_BOOST 103 +#define VARIOUS_TRY_ACTIVATE_GRIM_NEIGH 104 +#define VARIOUS_MOVEEND_ITEM_EFFECTS 105 +#define VARIOUS_TERRAIN_SEED 106 +#define VARIOUS_MAKE_INVISIBLE 107 +#define VARIOUS_ROOM_SERVICE 108 +#define VARIOUS_JUMP_IF_TERRAIN_AFFECTED 109 +#define VARIOUS_EERIE_SPELL_PP_REDUCE 110 +#define VARIOUS_JUMP_IF_TEAM_HEALTHY 111 +#define VARIOUS_TRY_HEAL_QUARTER_HP 112 +#define VARIOUS_REMOVE_TERRAIN 113 +#define VARIOUS_JUMP_IF_PRANKSTER_BLOCKED 114 +#define VARIOUS_TRY_TO_CLEAR_PRIMAL_WEATHER 115 +#define VARIOUS_GET_ROTOTILLER_TARGETS 116 +#define VARIOUS_JUMP_IF_NOT_ROTOTILLER_AFFECTED 117 +#define VARIOUS_TRY_ACTIVATE_BATTLE_BOND 118 +#define VARIOUS_CONSUME_BERRY 119 +#define VARIOUS_JUMP_IF_CANT_REVERT_TO_PRIMAL 120 +#define VARIOUS_HANDLE_PRIMAL_REVERSION 121 +#define VARIOUS_APPLY_PLASMA_FISTS 122 +#define VARIOUS_JUMP_IF_SPECIES 123 +#define VARIOUS_UPDATE_ABILITY_POPUP 124 +#define VARIOUS_JUMP_IF_WEATHER_AFFECTED 125 +#define VARIOUS_JUMP_IF_LEAF_GUARD_PROTECTED 126 +#define VARIOUS_SET_ATTACKER_STICKY_WEB_USER 127 +#define VARIOUS_TRY_TO_APPLY_MIMICRY 128 +#define VARIOUS_PHOTON_GEYSER_CHECK 129 +#define VARIOUS_SHELL_SIDE_ARM_CHECK 130 +#define VARIOUS_TRY_NO_RETREAT 131 +#define VARIOUS_TRY_TAR_SHOT 132 +#define VARIOUS_CAN_TAR_SHOT_WORK 133 +#define VARIOUS_CHECK_POLTERGEIST 134 +#define VARIOUS_SET_OCTOLOCK 135 +#define VARIOUS_CUT_1_3_HP_RAISE_STATS 136 +#define VARIOUS_JUMP_IF_NO_FLING_POWER 137 +#define VARIOUS_JUMP_IF_HOLD_EFFECT 138 +#define VARIOUS_CURE_CERTAIN_STATUSES 139 +#define VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES 140 +#define VARIOUS_JUMP_IF_LAST_USED_ITEM_BERRY 141 +#define VARIOUS_JUMP_IF_LAST_USED_ITEM_HOLD_EFFECT 142 +#define VARIOUS_SAVE_BATTLER_ITEM 143 +#define VARIOUS_RESTORE_BATTLER_ITEM 144 +#define VARIOUS_BATTLER_ITEM_TO_LAST_USED_ITEM 145 // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 0 diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 88c3af2f0..83daafb29 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1414,6 +1414,19 @@ static void Cmd_attackcanceler(void) GET_MOVE_TYPE(gCurrentMove, moveType); + // Unnerve prevents a Pokémon holding a Berry from using Fling. + if (gCurrentMove == MOVE_FLING + && GetBattlerAbility(gBattlerAttacker) == ABILITY_UNNERVE + && ItemId_GetPocket(gLastUsedItem) == POCKET_BERRIES) + { + // Fling removes the item just before attackcanceler kicks in. + // This is done to work around an opponent using Protect/Detect. + gBattleMons[gBattlerAttacker].item = gLastUsedItem; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_ButItFailedAtkStringPpReduce; + return; + } + if (moveType == TYPE_FIRE && (gBattleWeather & WEATHER_RAIN_PRIMAL) && WEATHER_HAS_EFFECT @@ -9287,98 +9300,56 @@ static void Cmd_various(void) gBattlescriptCurrInstr += 7; return; } - case VARIOUS_JUMP_IF_FLING_FAILS: + case VARIOUS_JUMP_IF_NO_FLING_POWER: #ifdef ITEM_EXPANSION if (!ItemId_GetFlingPower(gBattleMons[gActiveBattler].item)) gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); - else if (!CanBattlerGetOrLoseItem(gActiveBattler, gBattleMons[gActiveBattler].item)) - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); - #else - if (!CanBattlerGetOrLoseItem(gActiveBattler, gBattleMons[gActiveBattler].item)) - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); - #endif else + #endif gBattlescriptCurrInstr += 7; return; - case VARIOUS_JUMP_IF_HOLD_EFFECT: - if (GetBattlerHoldEffect(gActiveBattler, TRUE) == gBattlescriptCurrInstr[3]) - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 4); - else - gBattlescriptCurrInstr += 8; - return; case VARIOUS_CURE_CERTAIN_STATUSES: + // Check infatuation if (gBattleMons[gActiveBattler].status2 & STATUS2_INFATUATION) { gBattleMons[gActiveBattler].status2 &= ~(STATUS2_INFATUATION); - gBattleMons[gActiveBattler].status2 = 0; - BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBattler].status2); - MarkBattlerForControllerExec(gActiveBattler); - PrepareStringBattle(STRINGID_TARGETGOTOVERINFATUATION, gActiveBattler); - gBattleCommunication[MSG_DISPLAY] = 1; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_INFATUATION; // STRINGID_TARGETGOTOVERINFATUATION + StringCopy(gBattleTextBuff1, gStatusConditionString_LoveJpn); } - else if (gBattleMons[gActiveBattler].status2 & STATUS2_TORMENT) + // Check taunt + if (gDisableStructs[gActiveBattler].tauntTimer != 0) { - gBattleMons[gActiveBattler].status2 &= ~(STATUS2_TORMENT); - gBattleMons[gActiveBattler].status2 = 0; - BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBattler].status2); - MarkBattlerForControllerExec(gActiveBattler); - // Swap gBattlerTarget and gBattlerAttacker so STRINGID_BUFFERENDS works correctly - gActiveBattler = gBattlerAttacker; - gBattlerAttacker = gBattlerTarget; - gBattlerTarget = gActiveBattler; - gHitMarker |= HITMARKER_SWAP_ATTACKER_TARGET; - PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_TORMENT); - PrepareStringBattle(STRINGID_BUFFERENDS, gActiveBattler); - gBattleCommunication[MSG_DISPLAY] = 1; - // Swap gBattlerTarget and gBattlerAttacker back - if (gHitMarker & HITMARKER_SWAP_ATTACKER_TARGET) - gHitMarker &= ~(HITMARKER_SWAP_ATTACKER_TARGET); - } - else if (gDisableStructs[gActiveBattler].tauntTimer != 0) - { - gDisableStructs[gActiveBattler].tauntTimer = 0; - // Swap gBattlerTarget and gBattlerAttacker so STRINGID_BUFFERENDS works correctly - gActiveBattler = gBattlerAttacker; - gBattlerAttacker = gBattlerTarget; - gBattlerTarget = gActiveBattler; - gHitMarker |= HITMARKER_SWAP_ATTACKER_TARGET; + gDisableStructs[gActiveBattler].tauntTimer = gDisableStructs[gActiveBattler].tauntTimer2 = 0; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_TAUNT; PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_TAUNT); - PrepareStringBattle(STRINGID_BUFFERENDS, gActiveBattler); - gBattleCommunication[MSG_DISPLAY] = 1; - // Swap gBattlerTarget and gBattlerAttacker back - if (gHitMarker & HITMARKER_SWAP_ATTACKER_TARGET) - gHitMarker &= ~(HITMARKER_SWAP_ATTACKER_TARGET); } - else if (gDisableStructs[gActiveBattler].encoreTimer) + // Check encore + if (gDisableStructs[gActiveBattler].encoreTimer != 0) { gDisableStructs[gActiveBattler].encoredMove = 0; - gDisableStructs[gActiveBattler].encoreTimer = 0; - // Swap gBattlerTarget and gBattlerAttacker so STRINGID_BUFFERENDS works correctly - gActiveBattler = gBattlerAttacker; - gBattlerAttacker = gBattlerTarget; - gBattlerTarget = gActiveBattler; - gHitMarker |= HITMARKER_SWAP_ATTACKER_TARGET; - PrepareStringBattle(STRINGID_PKMNENCOREENDED, gActiveBattler); - gBattleCommunication[MSG_DISPLAY] = 1; - // Swap gBattlerTarget and gBattlerAttacker back - if (gHitMarker & HITMARKER_SWAP_ATTACKER_TARGET) - gHitMarker &= ~(HITMARKER_SWAP_ATTACKER_TARGET); + gDisableStructs[gActiveBattler].encoreTimerStartValue = gDisableStructs[gActiveBattler].encoreTimer = 0; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_ENCORE; // STRINGID_PKMNENCOREENDED } - else if (gDisableStructs[gActiveBattler].disableTimer) + // Check torment + if (gBattleMons[gActiveBattler].status2 & STATUS2_TORMENT) { - gDisableStructs[gActiveBattler].disabledMove = 0; - // Swap gBattlerTarget and gBattlerAttacker so STRINGID_BUFFERENDS works correctly - gActiveBattler = gBattlerAttacker; - gBattlerAttacker = gBattlerTarget; - gBattlerTarget = gActiveBattler; - gHitMarker |= HITMARKER_SWAP_ATTACKER_TARGET; - PrepareStringBattle(STRINGID_PKMNMOVEDISABLEDNOMORE, gBattlerTarget); - gBattleCommunication[MSG_DISPLAY] = 1; - // Swap gBattlerTarget and gBattlerAttacker back - if (gHitMarker & HITMARKER_SWAP_ATTACKER_TARGET) - gHitMarker &= ~(HITMARKER_SWAP_ATTACKER_TARGET); + gBattleMons[gActiveBattler].status2 &= ~(STATUS2_TORMENT); + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_TORMENT; } - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 7); + // Check heal block + if (gStatuses3[gActiveBattler] & STATUS3_HEAL_BLOCK) + { + gStatuses3[gActiveBattler] &= ~(STATUS3_HEAL_BLOCK); + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_HEALBLOCK; + } + // Check disable + if (gDisableStructs[gActiveBattler].disableTimer != 0) + { + gDisableStructs[gActiveBattler].disableTimer = gDisableStructs[gActiveBattler].disableTimerStartValue = 0; + gDisableStructs[gActiveBattler].disabledMove = 0; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_DISABLE; + } + gBattlescriptCurrInstr += 3; return; case VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES: gActiveBattler = gBattlerTarget; @@ -9387,6 +9358,27 @@ static void Cmd_various(void) gBattleMons[gActiveBattler].statStages[i] = DEFAULT_STAT_STAGE; gBattlescriptCurrInstr += 3; return; + case VARIOUS_JUMP_IF_LAST_USED_ITEM_BERRY: + if (ItemId_GetPocket(gLastUsedItem) == POCKET_BERRIES) + gBattlescriptCurrInstr += 7; + else + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); + return; + case VARIOUS_JUMP_IF_LAST_USED_ITEM_HOLD_EFFECT: + if (ItemId_GetHoldEffect(gLastUsedItem) == gBattlescriptCurrInstr[3]) + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 4); + else + gBattlescriptCurrInstr += 8; + return; + case VARIOUS_SAVE_BATTLER_ITEM: + gBattleResources->battleHistory->heldItems[gActiveBattler] = gBattleMons[gActiveBattler].item; + break; + case VARIOUS_RESTORE_BATTLER_ITEM: + gBattleMons[gActiveBattler].item = gBattleResources->battleHistory->heldItems[gActiveBattler]; + break; + case VARIOUS_BATTLER_ITEM_TO_LAST_USED_ITEM: + gBattleMons[gActiveBattler].item = gLastUsedItem; + break; } // End of switch (gBattlescriptCurrInstr[2]) gBattlescriptCurrInstr += 3; From de7417796699a11f083b795b66063817ef9d30b7 Mon Sep 17 00:00:00 2001 From: LOuroboros Date: Mon, 15 Nov 2021 12:52:05 -0300 Subject: [PATCH 014/130] Oops --- include/constants/battle_string_ids.h | 3 +-- src/battle_message.c | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index 6abfe20ff..7846fa521 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -609,9 +609,8 @@ #define STRINGID_CANTESCAPEBECAUSEOFCURRENTMOVE 606 #define STRINGID_NEUTRALIZINGGASENTERS 607 #define STRINGID_NEUTRALIZINGGASOVER 608 -#define STRINGID_TARGETGOTOVERINFATUATION 609 -#define BATTLESTRINGS_COUNT 610 +#define BATTLESTRINGS_COUNT 609 // The below IDs are all indexes into battle message tables, // used to determine which of a set of messages to print. diff --git a/src/battle_message.c b/src/battle_message.c index 1da9b6103..d64d02f90 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -735,11 +735,9 @@ static const u8 sText_PkmnAboutToBeAttackedByItsItem[] = _("{B_DEF_NAME_WITH_PRE static const u8 sText_CantEscapeBecauseOfCurrentMove[] = _("{B_DEF_NAME_WITH_PREFIX} can no longer escape\nbecause of {B_CURRENT_MOVE}!"); static const u8 sText_NeutralizingGasEnters[] = _("Neutralizing Gas filled the area!"); static const u8 sText_NeutralizingGasOver[] = _("The effects of Neutralizing\nGas wore off!"); -static const u8 sText_TargetGotOverInfatuation[] =_("{B_DEF_NAME_WITH_PREFIX} got over\nits infatuation!"); const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = { - [STRINGID_TARGETGOTOVERINFATUATION - 12] = sText_TargetGotOverInfatuation, [STRINGID_NEUTRALIZINGGASOVER - 12] = sText_NeutralizingGasOver, [STRINGID_NEUTRALIZINGGASENTERS - 12] = sText_NeutralizingGasEnters, [STRINGID_BATTLERTYPECHANGEDTO - 12] = sText_BattlerTypeChangedTo, From 5c485d9769d262dc16c01275524279cfd2fb3079 Mon Sep 17 00:00:00 2001 From: LOuroboros Date: Mon, 15 Nov 2021 14:02:33 -0300 Subject: [PATCH 015/130] Fixed Fling when gLastUsedItem is 0 Also renamed VARIOUS_JUMP_IF_NO_FLING_POWER to VARIOUS_JUMP_IF_FLING_FAILS. --- asm/macros/battle_script.inc | 4 ++-- data/battle_scripts_1.s | 2 +- include/constants/battle_script_commands.h | 2 +- src/battle_script_commands.c | 8 ++++++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 3999da4fc..fef12b4d5 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1925,8 +1925,8 @@ various BS_ATTACKER, VARIOUS_SHELL_SIDE_ARM_CHECK .endm - .macro jumpifnoflingpower battler:req, ptr:req - various \battler, VARIOUS_JUMP_IF_NO_FLING_POWER + .macro jumpifflingfails battler:req, ptr:req + various \battler, VARIOUS_JUMP_IF_FLING_FAILS .4byte \ptr .endm diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 2019fe388..c7d53ee55 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -405,7 +405,7 @@ gBattleScriptsForMoveEffects:: .4byte BattleScript_EffectHit @ EFFECT_BOLT_BEAK BattleScript_EffectFling: - jumpifnoflingpower BS_ATTACKER, BattleScript_ButItFailedAtkStringPpReduce + jumpifflingfails BS_ATTACKER, BattleScript_ButItFailedAtkStringPpReduce jumpifstatus3 BS_ATTACKER, STATUS3_EMBARGO, BattleScript_ButItFailedAtkStringPpReduce jumpifword CMP_COMMON_BITS, gFieldStatuses, STATUS_FIELD_MAGIC_ROOM, BattleScript_ButItFailedAtkStringPpReduce .if B_KLUTZ_FLING_INTERACTION >= GEN_5 diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 6f3620f57..0dd3fb023 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -208,7 +208,7 @@ #define VARIOUS_SET_OCTOLOCK 135 #define VARIOUS_CUT_1_3_HP_RAISE_STATS 136 #define VARIOUS_TRY_END_NEUTRALIZING_GAS 137 -#define VARIOUS_JUMP_IF_NO_FLING_POWER 138 +#define VARIOUS_JUMP_IF_FLING_FAILS 138 #define VARIOUS_JUMP_IF_HOLD_EFFECT 139 #define VARIOUS_CURE_CERTAIN_STATUSES 140 #define VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES 141 diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 1cad382a8..742bfdd76 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -9285,12 +9285,16 @@ static void Cmd_various(void) gBattlescriptCurrInstr += 7; return; } - case VARIOUS_JUMP_IF_NO_FLING_POWER: + case VARIOUS_JUMP_IF_FLING_FAILS: #ifdef ITEM_EXPANSION if (!ItemId_GetFlingPower(gBattleMons[gActiveBattler].item)) gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); - else + else if (gLastUsedItem == ITEM_NONE) + #else + if (gLastUsedItem == ITEM_NONE) #endif + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); + else gBattlescriptCurrInstr += 7; return; case VARIOUS_CURE_CERTAIN_STATUSES: From 86efd69370e9a646f89626c126c092017b71518e Mon Sep 17 00:00:00 2001 From: BuffelSaft Date: Fri, 19 Nov 2021 20:19:10 +1300 Subject: [PATCH 016/130] Finish/fix Beak Blast This was not working at all, but the basic framework was there; some small changes tidied it up and made it work. --- data/battle_scripts_1.s | 26 ++++++-------------------- src/battle_script_commands.c | 16 +++++++++++++--- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index c98b35b5e..8f898f1d2 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -403,12 +403,12 @@ gBattleScriptsForMoveEffects:: .4byte BattleScript_EffectOctolock @ EFFECT_OCTOLOCK .4byte BattleScript_EffectClangorousSoul @ EFFECT_CLANGOROUS_SOUL .4byte BattleScript_EffectHit @ EFFECT_BOLT_BEAK - .4byte BattleScript_EffectHit @ EFFECT_EXPANDING_FORCE + .4byte BattleScript_EffectHit @ EFFECT_EXPANDING_FORCE .4byte BattleScript_EffectScaleShot @ EFFECT_SCALE_SHOT .4byte BattleScript_EffectMeteorBeam @ EFFECT_METEOR_BEAM .4byte BattleScript_EffectHit @ EFFECT_RISING_VOLTAGE .4byte BattleScript_EffectCorrosiveGas @ EFFECT_CORROSIVE_GAS - .4byte BattleScript_EffectBeakBlast @ EFFECT_BEAK_BLAST + .4byte BattleScript_EffectHit @ EFFECT_BEAK_BLAST .4byte BattleScript_EffectCourtChange @ EFFECT_COURT_CHANGE .4byte BattleScript_EffectShellTrap @ EFFECT_SHELL_TRAP @@ -464,14 +464,6 @@ BattleScript_EffectCourtChange:: waitmessage 0x40 goto BattleScript_MoveEnd -BattleScript_EffectBeakBlast:: - attackcanceler - jumpifnodamage BattleScript_HitFromAccCheck - ppreduce - printstring STRINGID_PKMNLOSTFOCUS - waitmessage 0x40 - goto BattleScript_MoveEnd - BattleScript_BeakBlastSetUp:: setbeakblast BS_ATTACKER printstring STRINGID_EMPTYSTRING3 @@ -482,17 +474,11 @@ BattleScript_BeakBlastSetUp:: end2 BattleScript_BeakBlastBurn:: - jumpifstatus BS_TARGET, STATUS1_BURN, BattleScript_AlreadyBurned - jumpiftype BS_TARGET, TYPE_FIRE, BattleScript_NotAffected - jumpifability BS_TARGET, ABILITY_WATER_VEIL, BattleScript_WaterVeilPrevents - jumpifability BS_TARGET, ABILITY_COMATOSE, BattleScript_LeafGuardProtects - jumpifflowerveil BattleScript_FlowerVeilProtects - jumpifleafguardprotected BS_TARGET, BattleScript_LeafGuardProtects - jumpifstatus BS_TARGET, STATUS1_ANY, BattleScript_BeakBlastBurnReturn - setmoveeffect MOVE_EFFECT_BURN | MOVE_EFFECT_AFFECTS_USER - seteffectprimary -BattleScript_BeakBlastBurnReturn: + setbyte cMULTISTRING_CHOOSER, 0 + copybyte gEffectBattler, gBattlerAttacker + call BattleScript_MoveEffectBurn return + BattleScript_EffectCorrosiveGas:: attackcanceler accuracycheck BattleScript_PrintMoveMissed, NO_ACC_CALC_CHECK_LOCK_ON diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index b767b871e..232b97697 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1543,6 +1543,11 @@ static void Cmd_attackcanceler(void) gBattleCommunication[MISS_TYPE] = B_MSG_PROTECTED; gBattlescriptCurrInstr++; } + else if (gProtectStructs[gBattlerTarget].beakBlastCharge && IsMoveMakingContact(gCurrentMove, gBattlerAttacker)) + { + gProtectStructs[gBattlerAttacker].touchedProtectLike = TRUE; + gBattlescriptCurrInstr++; + } else { gBattlescriptCurrInstr++; @@ -4964,7 +4969,7 @@ static void Cmd_moveend(void) } else if (gProtectStructs[gBattlerTarget].obstructed && gCurrentMove != MOVE_SUCKER_PUNCH) { - gProtectStructs[gBattlerAttacker].touchedProtectLike = 0; + gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE; i = gBattlerAttacker; gBattlerAttacker = gBattlerTarget; gBattlerTarget = i; // gBattlerTarget and gBattlerAttacker are swapped in order to activate Defiant, if applicable @@ -4973,8 +4978,13 @@ static void Cmd_moveend(void) gBattlescriptCurrInstr = BattleScript_KingsShieldEffect; effect = 1; } - else if (gProtectStructs[gBattlerTarget].beakBlastCharge) + // Not strictly a protect effect, but works the same way + else if (gProtectStructs[gBattlerTarget].beakBlastCharge + && CanBeBurned(gBattlerAttacker) + && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)) { + gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE; + gBattleMons[gBattlerAttacker].status1 = STATUS1_BURN; BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_BeakBlastBurn; effect = 1; @@ -9317,7 +9327,7 @@ static void Cmd_various(void) } } case VARIOUS_SET_BEAK_BLAST: - gProtectStructs[gActiveBattler].beakBlastCharge = 1; + gProtectStructs[gBattlerAttacker].beakBlastCharge = 1; break; case VARIOUS_SWAP_SIDE_STATUSES: { From 48c91d03cdfd5f9e742ef67b0be43fb1c8c2688a Mon Sep 17 00:00:00 2001 From: BuffelSaft Date: Fri, 19 Nov 2021 20:20:16 +1300 Subject: [PATCH 017/130] Fix terrain checks on DLC moves Expanding Force and Rising Voltage now boost damage correctly. Expanding Force doesn't hit both targets yet however. --- src/battle_util.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/battle_util.c b/src/battle_util.c index cbc96ae56..e946fe8f0 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -7262,6 +7262,9 @@ u32 GetMoveTarget(u16 move, u8 setTarget) // Special cases if (move == MOVE_CURSE && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GHOST)) moveTarget = MOVE_TARGET_USER; + + if (gBattleMoves[move].effect == EFFECT_EXPANDING_FORCE && IsBattlerTerrainAffected(gBattlerAttacker, STATUS_FIELD_PSYCHIC_TERRAIN)) + moveTarget = MOVE_TARGET_BOTH; switch (moveTarget) { @@ -7991,18 +7994,12 @@ static u16 CalcMoveBasePower(u16 move, u8 battlerAtk, u8 battlerDef) basePower *= 2; break; case EFFECT_EXPANDING_FORCE: - if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN) - basePower = 120; + if (IsBattlerTerrainAffected(gBattlerAttacker, STATUS_FIELD_PSYCHIC_TERRAIN)) + MulModifier(&basePower, UQ_4_12(1.5)); break; case EFFECT_RISING_VOLTAGE: - #ifdef ITEM_EXPANSION //Air Balloon exception with item expansion branch - if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN && !IS_BATTLER_OF_TYPE(battlerDef, TYPE_FLYING) - && gBattleMons[battlerDef].item != ITEM_AIR_BALLOON && gBattleMons[battlerDef].ability != ABILITY_LEVITATE) - #else - if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN && !IS_BATTLER_OF_TYPE(battlerDef, TYPE_FLYING) - && gBattleMons[battlerDef].ability != ABILITY_LEVITATE) - #endif - basePower *= 2; + if (IsBattlerTerrainAffected(gBattlerTarget, STATUS_FIELD_ELECTRIC_TERRAIN)) + basePower *= 2; break; } From 14a2e863139d4726a24b9b32ef49e3e85743c628 Mon Sep 17 00:00:00 2001 From: BuffelSaft Date: Fri, 19 Nov 2021 21:57:32 +1300 Subject: [PATCH 018/130] Fix Scale Shot Lowers defense and raises speed instead of just lowering defense now. Tested with Contrary and min/max speed/def. --- data/battle_scripts_1.s | 24 +++++++++++++++++++++--- include/battle_scripts.h | 1 + include/constants/battle.h | 4 ++-- src/battle_main.c | 4 ++-- src/battle_script_commands.c | 7 +++++++ 5 files changed, 33 insertions(+), 7 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 8f898f1d2..d5d5707ff 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -570,9 +570,7 @@ BattleScript_ScaleShotPrintStrings:: printstring STRINGID_HITXTIMES waitmessage 0x40 BattleScript_ScaleShotEnd:: - setmoveeffect MOVE_EFFECT_SPD_PLUS_1 | MOVE_EFFECT_AFFECTS_USER - seteffectwithchance - setmoveeffect MOVE_EFFECT_DEF_MINUS_1 | MOVE_EFFECT_AFFECTS_USER + setmoveeffect MOVE_EFFECT_SCALE_SHOT | MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN seteffectwithchance tryfaintmon BS_TARGET, FALSE, NULL moveendcase MOVEEND_SYNCHRONIZE_TARGET @@ -7182,6 +7180,26 @@ BattleScript_DefSpDefDownTrySpDef:: BattleScript_DefSpDefDownRet:: return +BattleScript_DefDownSpeedUp:: + jumpifstat BS_ATTACKER, CMP_GREATER_THAN, STAT_DEF, MIN_STAT_STAGE, BattleScript_DefDownSpeedUpTryDef + jumpifstat BS_ATTACKER, CMP_EQUAL, STAT_SPEED, MAX_STAT_STAGE, BattleScript_DefDownSpeedUpRet +BattleScript_DefDownSpeedUpTryDef:: + playstatchangeanimation BS_ATTACKER, BIT_DEF, STAT_CHANGE_NEGATIVE | STAT_CHANGE_CANT_PREVENT + setstatchanger STAT_DEF, 1, TRUE + statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_BUFF_ALLOW_PTR | MOVE_EFFECT_CERTAIN, BattleScript_DefDownSpeedUpTrySpeed + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_DefDownSpeedUpTrySpeed + printfromtable gStatUpStringIds + waitmessage B_WAIT_TIME_LONG +BattleScript_DefDownSpeedUpTrySpeed: + playstatchangeanimation BS_ATTACKER, BIT_SPEED, 0 + setstatchanger STAT_SPEED, 1, FALSE + statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_BUFF_ALLOW_PTR | MOVE_EFFECT_CERTAIN, BattleScript_DefDownSpeedUpRet + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_DefDownSpeedUpRet + printfromtable gStatUpStringIds + waitmessage B_WAIT_TIME_LONG +BattleScript_DefDownSpeedUpRet:: + return + BattleScript_KnockedOff:: playanimation BS_TARGET, B_ANIM_ITEM_KNOCKOFF, NULL printstring STRINGID_PKMNKNOCKEDOFF diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 1c130b90f..7dfc1a6da 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -421,5 +421,6 @@ extern const u8 BattleScript_BeakBlastBurn[]; extern const u8 BattleScript_ShellTrapSetUp[]; extern const u8 BattleScript_ShellTrapExplode[]; extern const u8 BattleScript_EffectShellTrap[]; +extern const u8 BattleScript_DefDownSpeedUp[]; #endif // GUARD_BATTLE_SCRIPTS_H diff --git a/include/constants/battle.h b/include/constants/battle.h index 515d4ac02..46b6494b2 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -359,9 +359,9 @@ #define MOVE_EFFECT_RECOIL_HP_25 0x46 #define MOVE_EFFECT_RELIC_SONG 0x47 #define MOVE_EFFECT_TRAP_BOTH 0x48 -#define MOVE_EFFECT_SPD_PLUS_1_DEF_MINUS_1 0x49 +#define MOVE_EFFECT_SCALE_SHOT 0x49 #define MOVE_EFFECT_MELT_ITEM 0x4A -#define NUM_MOVE_EFFECTS 0x50 +#define NUM_MOVE_EFFECTS 0x4B #define MOVE_EFFECT_AFFECTS_USER 0x4000 #define MOVE_EFFECT_CERTAIN 0x8000 diff --git a/src/battle_main.c b/src/battle_main.c index c39407653..25ac66be5 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -4715,8 +4715,8 @@ static void CheckFocusPunch_ClearVarsBeforeTurnStarts(void) BattleScriptExecute(BattleScript_BeakBlastSetUp); return; case MOVE_SHELL_TRAP: - BattleScriptExecute(BattleScript_ShellTrapSetUp); - return; + BattleScriptExecute(BattleScript_ShellTrapSetUp); + return; } } } diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 232b97697..0aa068a99 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -3489,6 +3489,10 @@ void SetMoveEffect(bool32 primary, u32 certain) gBattleMons[gBattlerTarget].status2 |= STATUS2_ESCAPE_PREVENTION; gBattleMons[gBattlerAttacker].status2 |= STATUS2_ESCAPE_PREVENTION; break; + case MOVE_EFFECT_SCALE_SHOT: + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_DefDownSpeedUp; + break; } } } @@ -9329,6 +9333,9 @@ static void Cmd_various(void) case VARIOUS_SET_BEAK_BLAST: gProtectStructs[gBattlerAttacker].beakBlastCharge = 1; break; + case VARIOUS_SET_SHELL_TRAP: + gProtectStructs[gBattlerAttacker].shellTrap = 1; + break; case VARIOUS_SWAP_SIDE_STATUSES: { /* This code is a mess, but idk how to do it better without changing how Side Statuses and From bcaa17ffb31182c17c7a56134f4380bf52c33562 Mon Sep 17 00:00:00 2001 From: BuffelSaft Date: Sun, 21 Nov 2021 17:20:45 +1300 Subject: [PATCH 019/130] Finish/tidy up Court Change Use a macro to simplify timer and status updates, and swap things like reflectBattlerId to the opposing side - this is required for the effects to be properly swapped. --- include/battle.h | 7 +- src/battle_script_commands.c | 216 +++++++++-------------------------- 2 files changed, 59 insertions(+), 164 deletions(-) diff --git a/include/battle.h b/include/battle.h index 596130bfe..fbeb3ffb1 100644 --- a/include/battle.h +++ b/include/battle.h @@ -208,9 +208,6 @@ struct SideTimer u8 mistBattlerId; u8 safeguardTimer; u8 safeguardBattlerId; - u8 followmeTimer; - u8 followmeTarget:3; - u8 followmePowder:1; // Rage powder, does not affect grass type pokemon. u8 spikesAmount; u8 toxicSpikesAmount; u8 stealthRockAmount; @@ -221,6 +218,10 @@ struct SideTimer u8 tailwindBattlerId; u8 luckyChantTimer; u8 luckyChantBattlerId; + // Timers below this point are not swapped by Court Change + u8 followmeTimer; + u8 followmeTarget:3; + u8 followmePowder:1; // Rage powder, does not affect grass type pokemon. u8 retaliateTimer; }; diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 0aa068a99..b17a7555b 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -7527,6 +7527,60 @@ static bool32 IsRototillerAffected(u32 battlerId) return TRUE; } +#define COURTCHANGE_SWAP(status, structField, temp) \ +{ \ + temp = gSideStatuses[0]; \ + if (gSideStatuses[1] & status) \ + gSideStatuses[0] |= status; \ + else \ + gSideStatuses[0] &= ~(status); \ + if (temp & status) \ + gSideStatuses[1] |= status; \ + else \ + gSideStatuses[1] &= ~(status); \ + SWAP(sideTimer0->structField, sideTimer1->structField, temp);\ +} \ + +#define UPDATE_COURTCHANGED_BATTLER(structField)\ +{ \ + sideTimer0->structField ^= BIT_SIDE; \ + sideTimer1->structField ^= BIT_SIDE; \ +} \ + +static bool32 CourtChangeSwapSideStatuses(void) +{ + struct SideTimer *sideTimer0 = &gSideTimers[0]; + struct SideTimer *sideTimer1 = &gSideTimers[1]; + u32 temp; + + // TODO: add Pledge-related effects + // TODO: add Gigantamax-related effects + + // Swap timers and statuses + COURTCHANGE_SWAP(SIDE_STATUS_REFLECT, reflectTimer, temp) + COURTCHANGE_SWAP(SIDE_STATUS_LIGHTSCREEN, lightscreenTimer, temp) + COURTCHANGE_SWAP(SIDE_STATUS_MIST, mistTimer, temp); + COURTCHANGE_SWAP(SIDE_STATUS_SAFEGUARD, safeguardTimer, temp); + COURTCHANGE_SWAP(SIDE_STATUS_AURORA_VEIL, auroraVeilTimer, temp); + COURTCHANGE_SWAP(SIDE_STATUS_TAILWIND, tailwindTimer, temp); + // Lucky Chant doesn't exist in gen 8, but seems like it should be affected by Court Change + COURTCHANGE_SWAP(SIDE_STATUS_LUCKY_CHANT, luckyChantTimer, temp); + COURTCHANGE_SWAP(SIDE_STATUS_SPIKES, spikesAmount, temp); + COURTCHANGE_SWAP(SIDE_STATUS_STEALTH_ROCK, stealthRockAmount, temp); + COURTCHANGE_SWAP(SIDE_STATUS_TOXIC_SPIKES, toxicSpikesAmount, temp); + COURTCHANGE_SWAP(SIDE_STATUS_STICKY_WEB, stickyWebAmount, temp); + + // Change battler IDs of swapped effects. Needed for the correct string when they expire + // E.g. "Foe's Reflect wore off!" + UPDATE_COURTCHANGED_BATTLER(reflectBattlerId); + UPDATE_COURTCHANGED_BATTLER(lightscreenBattlerId); + UPDATE_COURTCHANGED_BATTLER(mistBattlerId); + UPDATE_COURTCHANGED_BATTLER(safeguardBattlerId); + UPDATE_COURTCHANGED_BATTLER(auroraVeilBattlerId); + UPDATE_COURTCHANGED_BATTLER(tailwindBattlerId); + UPDATE_COURTCHANGED_BATTLER(luckyChantBattlerId); +} + static void Cmd_various(void) { struct Pokemon *mon; @@ -9338,167 +9392,7 @@ static void Cmd_various(void) break; case VARIOUS_SWAP_SIDE_STATUSES: { - /* This code is a mess, but idk how to do it better without changing how Side Statuses and - Side timers work. - The problem is that not all side statuses are affected by Court Change*/ - - //todo: add pledge related effects - //todo: add gigamax related effects - - //swap side status sides - bits = gSideStatuses[0]; //Stores sides status temp - - //Reflect - if (gSideStatuses[1] & SIDE_STATUS_REFLECT) - gSideStatuses[0] |= SIDE_STATUS_REFLECT; - else - gSideStatuses[0] &= ~(SIDE_STATUS_REFLECT); - - if (bits & SIDE_STATUS_REFLECT) - gSideStatuses[1] |= SIDE_STATUS_REFLECT; - else - gSideStatuses[1] &= ~(SIDE_STATUS_REFLECT); - - //Light screen - if (gSideStatuses[1] & SIDE_STATUS_LIGHTSCREEN) - gSideStatuses[0] |= SIDE_STATUS_LIGHTSCREEN; - else - gSideStatuses[0] &= ~(SIDE_STATUS_LIGHTSCREEN); - - if (bits & SIDE_STATUS_LIGHTSCREEN) - gSideStatuses[1] |= SIDE_STATUS_LIGHTSCREEN; - else - gSideStatuses[1] &= ~(SIDE_STATUS_LIGHTSCREEN); - - //Safeguard - if (gSideStatuses[1] & SIDE_STATUS_SAFEGUARD) - gSideStatuses[0] |= SIDE_STATUS_SAFEGUARD; - else - gSideStatuses[0] &= ~(SIDE_STATUS_SAFEGUARD); - - if (bits & SIDE_STATUS_SAFEGUARD) - gSideStatuses[1] |= SIDE_STATUS_SAFEGUARD; - else - gSideStatuses[1] &= ~(SIDE_STATUS_SAFEGUARD); - - //Mist - if (gSideStatuses[1] & SIDE_STATUS_MIST) - gSideStatuses[0] |= SIDE_STATUS_MIST; - else - gSideStatuses[0] &= ~(SIDE_STATUS_MIST); - - if (bits & SIDE_STATUS_MIST) - gSideStatuses[1] |= SIDE_STATUS_MIST; - else - gSideStatuses[1] &= ~(SIDE_STATUS_MIST); - - //AuroraVeil - if (gSideStatuses[1] & SIDE_STATUS_AURORA_VEIL) - gSideStatuses[0] |= SIDE_STATUS_AURORA_VEIL; - else - gSideStatuses[0] &= ~(SIDE_STATUS_AURORA_VEIL); - - if (bits & SIDE_STATUS_AURORA_VEIL) - gSideStatuses[1] |= SIDE_STATUS_AURORA_VEIL; - else - gSideStatuses[1] &= ~(SIDE_STATUS_AURORA_VEIL); - - //Sticky Web - if (gSideStatuses[1] & SIDE_STATUS_STICKY_WEB) - gSideStatuses[0] |= SIDE_STATUS_STICKY_WEB; - else - gSideStatuses[0] &= ~(SIDE_STATUS_STICKY_WEB); - - if (bits & SIDE_STATUS_STICKY_WEB) - gSideStatuses[1] |= SIDE_STATUS_STICKY_WEB; - else - gSideStatuses[1] &= ~(SIDE_STATUS_STICKY_WEB); - - //Spikes - if (gSideStatuses[1] & SIDE_STATUS_SPIKES) - gSideStatuses[0] |= SIDE_STATUS_SPIKES; - else - gSideStatuses[0] &= ~(SIDE_STATUS_SPIKES); - - if (bits & SIDE_STATUS_SPIKES) - gSideStatuses[1] |= SIDE_STATUS_SPIKES; - else - gSideStatuses[1] &= ~(SIDE_STATUS_SPIKES); - - //Toxic Spikes - if (gSideStatuses[1] & SIDE_STATUS_TOXIC_SPIKES) - gSideStatuses[0] |= SIDE_STATUS_TOXIC_SPIKES; - else - gSideStatuses[0] &= ~(SIDE_STATUS_TOXIC_SPIKES); - - if (bits & SIDE_STATUS_TOXIC_SPIKES) - gSideStatuses[1] |= SIDE_STATUS_TOXIC_SPIKES; - else - gSideStatuses[1] &= ~(SIDE_STATUS_TOXIC_SPIKES); - - //Stealth Rock - if (gSideStatuses[1] & SIDE_STATUS_STEALTH_ROCK) - gSideStatuses[0] |= SIDE_STATUS_STEALTH_ROCK; - else - gSideStatuses[0] &= ~(SIDE_STATUS_STEALTH_ROCK); - - if (bits & SIDE_STATUS_STEALTH_ROCK) - gSideStatuses[1] |= SIDE_STATUS_STEALTH_ROCK; - else - gSideStatuses[1] &= ~(SIDE_STATUS_STEALTH_ROCK); - - //Tailwind - if (gSideStatuses[1] & SIDE_STATUS_TAILWIND) - gSideStatuses[0] |= SIDE_STATUS_TAILWIND; - else - gSideStatuses[0] &= ~(SIDE_STATUS_TAILWIND); - - if (bits & SIDE_STATUS_TAILWIND) - gSideStatuses[1] |= SIDE_STATUS_TAILWIND; - else - gSideStatuses[1] &= ~(SIDE_STATUS_TAILWIND); - - - //Swap affected status timers - bits = gSideTimers[0].reflectTimer; - gSideTimers[0].reflectTimer = gSideTimers[1].reflectTimer; - gSideTimers[1].reflectTimer = bits; - - bits = gSideTimers[0].lightscreenTimer; - gSideTimers[0].lightscreenTimer = gSideTimers[1].lightscreenTimer; - gSideTimers[1].lightscreenTimer = bits; - - bits = gSideTimers[0].mistTimer; - gSideTimers[0].mistTimer = gSideTimers[1].mistTimer; - gSideTimers[1].mistTimer = bits; - - bits = gSideTimers[0].safeguardTimer; - gSideTimers[0].safeguardTimer = gSideTimers[1].safeguardTimer; - gSideTimers[1].safeguardTimer = bits; - - bits = gSideTimers[0].spikesAmount; - gSideTimers[0].spikesAmount = gSideTimers[1].spikesAmount; - gSideTimers[1].spikesAmount = bits; - - bits = gSideTimers[0].toxicSpikesAmount; - gSideTimers[0].toxicSpikesAmount = gSideTimers[1].toxicSpikesAmount; - gSideTimers[1].toxicSpikesAmount = bits; - - bits = gSideTimers[0].stealthRockAmount; - gSideTimers[0].stealthRockAmount = gSideTimers[1].stealthRockAmount; - gSideTimers[1].stealthRockAmount = bits; - - bits = gSideTimers[0].stickyWebAmount; - gSideTimers[0].stickyWebAmount = gSideTimers[1].stickyWebAmount; - gSideTimers[1].stickyWebAmount = bits; - - bits = gSideTimers[0].auroraVeilTimer; - gSideTimers[0].auroraVeilTimer = gSideTimers[1].auroraVeilTimer; - gSideTimers[1].auroraVeilTimer = bits; - - bits = gSideTimers[0].tailwindTimer; - gSideTimers[0].tailwindTimer = gSideTimers[1].tailwindTimer; - gSideTimers[1].tailwindTimer = bits; + CourtChangeSwapSideStatuses(); break; } } // End of switch (gBattlescriptCurrInstr[2]) From abb67e96e8b6de05b9364bc02cd71b8a33abe6b3 Mon Sep 17 00:00:00 2001 From: BuffelSaft Date: Sun, 21 Nov 2021 21:49:47 +1300 Subject: [PATCH 020/130] Finish Expanding Force Hits both foes if the user is affected by Psychic Terrain. Modified targeting is also shown in the move selection screen. --- src/battle_controller_player.c | 7 +++++++ src/battle_script_commands.c | 4 +++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index e1cb2f54f..a970c38b7 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -609,6 +609,13 @@ static void HandleInputChooseMove(void) else moveTarget = MOVE_TARGET_SELECTED; } + else if (moveInfo->moves[gMoveSelectionCursor[gActiveBattler]] == MOVE_EXPANDING_FORCE) + { + if (IsBattlerTerrainAffected(gActiveBattler, STATUS_FIELD_PSYCHIC_TERRAIN)) + moveTarget = MOVE_TARGET_BOTH; + else + moveTarget = MOVE_TARGET_SELECTED; + } else { moveTarget = gBattleMoves[moveInfo->moves[gMoveSelectionCursor[gActiveBattler]]].target; diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index b17a7555b..31a2d4fc6 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -5246,7 +5246,9 @@ static void Cmd_moveend(void) if (!(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) && gBattleTypeFlags & BATTLE_TYPE_DOUBLE && !gProtectStructs[gBattlerAttacker].chargingTurn - && (gBattleMoves[gCurrentMove].target == MOVE_TARGET_BOTH || gBattleMoves[gCurrentMove].target == MOVE_TARGET_FOES_AND_ALLY) + && (gBattleMoves[gCurrentMove].target == MOVE_TARGET_BOTH + || gBattleMoves[gCurrentMove].target == MOVE_TARGET_FOES_AND_ALLY + || (gBattleMoves[gCurrentMove].effect == EFFECT_EXPANDING_FORCE && IsBattlerTerrainAffected(gBattlerAttacker, STATUS_FIELD_PSYCHIC_TERRAIN))) && !(gHitMarker & HITMARKER_NO_ATTACKSTRING)) { u8 battlerId; From 70f0018c08c1ad9028e65b13ae1bc178177b460d Mon Sep 17 00:00:00 2001 From: BuffelSaft Date: Mon, 22 Nov 2021 14:14:41 +1300 Subject: [PATCH 021/130] Partially implement Shell Trap Doesn't play the animation when the trap triggers, but kinda works? May also be incredibly buggy, but I'm not interested in working on this move any further. --- asm/macros/battle_script.inc | 5 +++-- data/battle_scripts_1.s | 2 +- include/battle.h | 13 ++++++------ src/battle_script_commands.c | 38 ++++++++++++++++++++++++++++++++---- src/data/battle_moves.h | 2 +- 5 files changed, 46 insertions(+), 14 deletions(-) diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index cf2045eb6..2498bce64 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1946,9 +1946,10 @@ various \battler, VARIOUS_CLEAR_SHELL_TRAP .endm - .macro checkshelltrap battler:req, ptr:req + .macro checkshelltrap battler:req, ptr1:req, ptr2:req various \battler, VARIOUS_CHECK_SHELL_TRAP - .4byte \ptr + .4byte \ptr1 + .4byte \ptr2 .endm @ helpful macros diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index d5d5707ff..e453e3705 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -413,7 +413,7 @@ gBattleScriptsForMoveEffects:: .4byte BattleScript_EffectShellTrap @ EFFECT_SHELL_TRAP BattleScript_EffectShellTrap:: - checkshelltrap BS_ATTACKER, BattleScript_MoveEnd + checkshelltrap BS_ATTACKER, BattleScript_ShellTrapExplode, BattleScript_MoveEnd clearshelltrap BS_ATTACKER attackcanceler attackstring diff --git a/include/battle.h b/include/battle.h index fbeb3ffb1..ad7924017 100644 --- a/include/battle.h +++ b/include/battle.h @@ -153,12 +153,13 @@ struct ProtectStruct u32 usedCustapBerry:1; // also quick claw u32 touchedProtectLike:1; // End of 32-bit bitfield - u8 disableEjectPack:1; - u8 statFell:1; - u8 pranksterElevated:1; - u8 quickDraw:1; - u8 beakBlastCharge:1; - u8 shellTrap:1; + u16 disableEjectPack:1; + u16 statFell:1; + u16 pranksterElevated:1; + u16 quickDraw:1; + u16 beakBlastCharge:1; + u16 shellTrapSet:1; + u16 shellTrapTriggered:1; u32 physicalDmg; u32 specialDmg; u8 physicalBattlerId; diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 31a2d4fc6..aa3c85375 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1543,7 +1543,8 @@ static void Cmd_attackcanceler(void) gBattleCommunication[MISS_TYPE] = B_MSG_PROTECTED; gBattlescriptCurrInstr++; } - else if (gProtectStructs[gBattlerTarget].beakBlastCharge && IsMoveMakingContact(gCurrentMove, gBattlerAttacker)) + else if ((gProtectStructs[gBattlerTarget].beakBlastCharge || gProtectStructs[gBattlerTarget].shellTrapSet) + && IsMoveMakingContact(gCurrentMove, gBattlerAttacker)) { gProtectStructs[gBattlerAttacker].touchedProtectLike = TRUE; gBattlescriptCurrInstr++; @@ -4983,7 +4984,7 @@ static void Cmd_moveend(void) effect = 1; } // Not strictly a protect effect, but works the same way - else if (gProtectStructs[gBattlerTarget].beakBlastCharge + else if (gProtectStructs[gBattlerTarget].beakBlastCharge && CanBeBurned(gBattlerAttacker) && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)) { @@ -4993,6 +4994,21 @@ static void Cmd_moveend(void) gBattlescriptCurrInstr = BattleScript_BeakBlastBurn; effect = 1; } + else if (gProtectStructs[gBattlerTarget].shellTrapSet + && !TestSheerForceFlag(gBattlerAttacker, gCurrentMove) + && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)) + { + u32 temp; + gProtectStructs[gBattlerTarget].shellTrapTriggered = TRUE; + gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE; + // Swap battlers so target attacks attacker with Shell Trap + SWAP(gBattlerAttacker, gBattlerTarget, temp); + // Set current move to Shell Trap + gCurrentMove = MOVE_SHELL_TRAP; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_EffectShellTrap; + effect = TRUE; + } } gBattleScripting.moveendState++; break; @@ -9387,10 +9403,24 @@ static void Cmd_various(void) } } case VARIOUS_SET_BEAK_BLAST: - gProtectStructs[gBattlerAttacker].beakBlastCharge = 1; + gProtectStructs[gBattlerAttacker].beakBlastCharge = TRUE; break; case VARIOUS_SET_SHELL_TRAP: - gProtectStructs[gBattlerAttacker].shellTrap = 1; + gProtectStructs[gBattlerAttacker].shellTrapSet = TRUE; + break; + case VARIOUS_CLEAR_SHELL_TRAP: + gProtectStructs[gBattlerAttacker].shellTrapSet = FALSE; + break; + case VARIOUS_CHECK_SHELL_TRAP: + // Attack with Shell Trap + if (gProtectStructs[gBattlerAttacker].shellTrapSet == TRUE && gProtectStructs[gBattlerAttacker].shellTrapTriggered == TRUE) + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); + // Attacked with Shell Trap, go to move end + else if (gProtectStructs[gBattlerAttacker].shellTrapSet == FALSE && gProtectStructs[gBattlerAttacker].shellTrapTriggered == TRUE) + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 7); + // Shell Trap failed + else + gBattlescriptCurrInstr += 11; break; case VARIOUS_SWAP_SIDE_STATUSES: { diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index bf591dac4..62c0595a6 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -10218,7 +10218,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = .accuracy = 100, .pp = 5, .secondaryEffectChance = 0, - .target = MOVE_TARGET_OPPONENTS_FIELD, + .target = MOVE_TARGET_BOTH, .priority = -3, .flags = FLAG_PROTECT_AFFECTED | FLAG_KINGS_ROCK_AFFECTED, .split = SPLIT_SPECIAL, From 42b8f18cb1fa9a1d29e8ecd9844b6a6bf54acf6b Mon Sep 17 00:00:00 2001 From: BuffelSaft Date: Mon, 22 Nov 2021 14:35:01 +1300 Subject: [PATCH 022/130] Remove Corrosive Gas code This was not working at all in testing, so it can be done by a separate PR later. --- asm/macros/battle_script.inc | 5 ----- data/battle_scripts_1.s | 19 ------------------ include/constants/battle_move_effects.h | 9 ++++----- src/battle_script_commands.c | 26 ------------------------- src/data/battle_moves.h | 2 +- 5 files changed, 5 insertions(+), 56 deletions(-) diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 2498bce64..500ec0919 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1925,11 +1925,6 @@ various BS_ATTACKER, VARIOUS_SHELL_SIDE_ARM_CHECK .endm - .macro trysetcorrosivegas battler:req, ptr:req - various \battler, VARIOUS_TRY_SET_CORROSIVE_GAS - .4byte \ptr - .endm - .macro setbeakblast battler:req various \battler, VARIOUS_SET_BEAK_BLAST .endm diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index e453e3705..99e3ad462 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -407,7 +407,6 @@ gBattleScriptsForMoveEffects:: .4byte BattleScript_EffectScaleShot @ EFFECT_SCALE_SHOT .4byte BattleScript_EffectMeteorBeam @ EFFECT_METEOR_BEAM .4byte BattleScript_EffectHit @ EFFECT_RISING_VOLTAGE - .4byte BattleScript_EffectCorrosiveGas @ EFFECT_CORROSIVE_GAS .4byte BattleScript_EffectHit @ EFFECT_BEAK_BLAST .4byte BattleScript_EffectCourtChange @ EFFECT_COURT_CHANGE .4byte BattleScript_EffectShellTrap @ EFFECT_SHELL_TRAP @@ -479,24 +478,6 @@ BattleScript_BeakBlastBurn:: call BattleScript_MoveEffectBurn return -BattleScript_EffectCorrosiveGas:: - attackcanceler - accuracycheck BattleScript_PrintMoveMissed, NO_ACC_CALC_CHECK_LOCK_ON - attackstring - ppreduce - jumpifstatus2 BS_TARGET, STATUS2_SUBSTITUTE, BattleScript_PrintMoveMissed - trysetcorrosivegas BS_TARGET, BattleScript_ButItFailed - attackanimation - waitanimation - printstring STRINGID_ITEMMELTED - waitmessage 0x40 - goto BattleScript_MoveEnd - -BattleScript_MeltedItem:: - printstring STRINGID_ITEMMELTED - waitmessage 0x40 - return - BattleScript_EffectMeteorBeam:: @ DecideTurn jumpifstatus2 BS_ATTACKER, STATUS2_MULTIPLETURNS, BattleScript_TwoTurnMovesSecondTurn diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index 5c6826394..0df43c060 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -390,11 +390,10 @@ #define EFFECT_SCALE_SHOT 384 #define EFFECT_METEOR_BEAM 385 #define EFFECT_RISING_VOLTAGE 386 -#define EFFECT_CORROSIVE_GAS 387 -#define EFFECT_BEAK_BLAST 388 -#define EFFECT_COURT_CHANGE 389 -#define EFFECT_SHELL_TRAP 390 +#define EFFECT_BEAK_BLAST 387 +#define EFFECT_COURT_CHANGE 388 +#define EFFECT_SHELL_TRAP 389 -#define NUM_BATTLE_MOVE_EFFECTS 391 +#define NUM_BATTLE_MOVE_EFFECTS 390 #endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index aa3c85375..6d65bbd62 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -9376,32 +9376,6 @@ static void Cmd_various(void) gBattlescriptCurrInstr += 7; return; } - case VARIOUS_TRY_SET_CORROSIVE_GAS: - { - if (gBattleMons[gActiveBattler].item != 0 - && CanBattlerGetOrLoseItem(gActiveBattler, gBattleMons[gActiveBattler].item) - && !NoAliveMonsForEitherParty()) - { - if (GetBattlerAbility(gActiveBattler) == ABILITY_STICKY_HOLD && IsBattlerAlive(gActiveBattler)) - { - gBattlerAbility = gActiveBattler; - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_StickyHoldActivates; - } - else - { // Item is melted normally - u32 side = GetBattlerSide(gActiveBattler); - - gLastUsedItem = gBattleMons[gActiveBattler].item; - gBattleMons[gActiveBattler].item = 0; - gBattleStruct->choicedMove[gActiveBattler] = 0; - gWishFutureKnock.meltedItemMons[side] |= gBitTable[gBattlerPartyIndexes[gActiveBattler]]; - - CheckSetUnburden(gActiveBattler); - gBattlescriptCurrInstr += 7; - } - } - } case VARIOUS_SET_BEAK_BLAST: gProtectStructs[gBattlerAttacker].beakBlastCharge = TRUE; break; diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index 62c0595a6..57b9bce4f 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -11417,7 +11417,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_CORROSIVE_GAS] = { - .effect = EFFECT_CORROSIVE_GAS, + .effect = EFFECT_PLACEHOLDER, // EFFECT_CORROSIVE_GAS, TODO .power = 0, .type = TYPE_POISON, .accuracy = 100, From d2eb5f0e6191645a677ae2c8ebcdde3937237c68 Mon Sep 17 00:00:00 2001 From: BuffelSaft Date: Mon, 22 Nov 2021 14:46:47 +1300 Subject: [PATCH 023/130] Remove shell trap effect code Left strings and animations as those were fine, but code was non-functional and fixing it was not trivial. --- asm/macros/battle_script.inc | 14 -------- data/battle_scripts_1.s | 41 ---------------------- include/battle.h | 2 -- include/battle_scripts.h | 3 -- include/constants/battle_move_effects.h | 1 - include/constants/battle_script_commands.h | 3 -- src/battle_main.c | 3 -- src/battle_script_commands.c | 35 +----------------- src/data/battle_moves.h | 2 +- 9 files changed, 2 insertions(+), 102 deletions(-) diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 500ec0919..a65ccaf44 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1933,20 +1933,6 @@ various BS_ATTACKER, VARIOUS_SWAP_SIDE_STATUSES .endm - .macro setshelltrap battler:req - various \battler, VARIOUS_SET_SHELL_TRAP - .endm - - .macro clearshelltrap battler:req - various \battler, VARIOUS_CLEAR_SHELL_TRAP - .endm - - .macro checkshelltrap battler:req, ptr1:req, ptr2:req - various \battler, VARIOUS_CHECK_SHELL_TRAP - .4byte \ptr1 - .4byte \ptr2 - .endm - @ helpful macros .macro setstatchanger stat:req, stages:req, down:req setbyte sSTATCHANGER \stat | \stages << 3 | \down << 7 diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 99e3ad462..eeeba7cf7 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -409,47 +409,6 @@ gBattleScriptsForMoveEffects:: .4byte BattleScript_EffectHit @ EFFECT_RISING_VOLTAGE .4byte BattleScript_EffectHit @ EFFECT_BEAK_BLAST .4byte BattleScript_EffectCourtChange @ EFFECT_COURT_CHANGE - .4byte BattleScript_EffectShellTrap @ EFFECT_SHELL_TRAP - -BattleScript_EffectShellTrap:: - checkshelltrap BS_ATTACKER, BattleScript_ShellTrapExplode, BattleScript_MoveEnd - clearshelltrap BS_ATTACKER - attackcanceler - attackstring - goto BattleScript_ButItFailed - -BattleScript_ShellTrapSetUp:: - setshelltrap BS_ATTACKER - printstring STRINGID_EMPTYSTRING3 - waitmessage 0x1 - playanimation BS_ATTACKER B_ANIM_SHELL_TRAP_SETUP, NULL - printstring STRINGID_PREPARESHELLTRAP - waitmessage 0x40 - end2 - -BattleScript_ShellTrapExplode:: - clearshelltrap BS_ATTACKER - attackcanceler - attackstring - ppreduce - critcalc - damagecalc - adjustdamage - attackanimation - waitanimation - effectivenesssound - hitanimation BS_TARGET - waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET - critmessage - waitmessage 0x40 - resultmessage - waitmessage 0x40 - seteffectwithchance - tryfaintmon BS_TARGET, FALSE, NULL - moveendall - end BattleScript_EffectCourtChange:: attackcanceler diff --git a/include/battle.h b/include/battle.h index ad7924017..69161ba6f 100644 --- a/include/battle.h +++ b/include/battle.h @@ -158,8 +158,6 @@ struct ProtectStruct u16 pranksterElevated:1; u16 quickDraw:1; u16 beakBlastCharge:1; - u16 shellTrapSet:1; - u16 shellTrapTriggered:1; u32 physicalDmg; u32 specialDmg; u8 physicalBattlerId; diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 7dfc1a6da..ec1dbb23c 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -418,9 +418,6 @@ extern const u8 BattleScript_NeutralizingGasExits[]; extern const u8 BattleScript_MeltedItem[]; extern const u8 BattleScript_BeakBlastSetUp[]; extern const u8 BattleScript_BeakBlastBurn[]; -extern const u8 BattleScript_ShellTrapSetUp[]; -extern const u8 BattleScript_ShellTrapExplode[]; -extern const u8 BattleScript_EffectShellTrap[]; extern const u8 BattleScript_DefDownSpeedUp[]; #endif // GUARD_BATTLE_SCRIPTS_H diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index 0df43c060..c6afed12c 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -392,7 +392,6 @@ #define EFFECT_RISING_VOLTAGE 386 #define EFFECT_BEAK_BLAST 387 #define EFFECT_COURT_CHANGE 388 -#define EFFECT_SHELL_TRAP 389 #define NUM_BATTLE_MOVE_EFFECTS 390 diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 977a69dbf..897bf35fb 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -211,9 +211,6 @@ #define VARIOUS_TRY_SET_CORROSIVE_GAS 138 #define VARIOUS_SET_BEAK_BLAST 139 #define VARIOUS_SWAP_SIDE_STATUSES 140 -#define VARIOUS_SET_SHELL_TRAP 141 -#define VARIOUS_CLEAR_SHELL_TRAP 142 -#define VARIOUS_CHECK_SHELL_TRAP 143 // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 0 diff --git a/src/battle_main.c b/src/battle_main.c index 25ac66be5..1c2d37dbc 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -4714,9 +4714,6 @@ static void CheckFocusPunch_ClearVarsBeforeTurnStarts(void) case MOVE_BEAK_BLAST: BattleScriptExecute(BattleScript_BeakBlastSetUp); return; - case MOVE_SHELL_TRAP: - BattleScriptExecute(BattleScript_ShellTrapSetUp); - return; } } } diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 6d65bbd62..a58aeed64 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1543,8 +1543,7 @@ static void Cmd_attackcanceler(void) gBattleCommunication[MISS_TYPE] = B_MSG_PROTECTED; gBattlescriptCurrInstr++; } - else if ((gProtectStructs[gBattlerTarget].beakBlastCharge || gProtectStructs[gBattlerTarget].shellTrapSet) - && IsMoveMakingContact(gCurrentMove, gBattlerAttacker)) + else if (gProtectStructs[gBattlerTarget].beakBlastCharge && IsMoveMakingContact(gCurrentMove, gBattlerAttacker)) { gProtectStructs[gBattlerAttacker].touchedProtectLike = TRUE; gBattlescriptCurrInstr++; @@ -4994,21 +4993,6 @@ static void Cmd_moveend(void) gBattlescriptCurrInstr = BattleScript_BeakBlastBurn; effect = 1; } - else if (gProtectStructs[gBattlerTarget].shellTrapSet - && !TestSheerForceFlag(gBattlerAttacker, gCurrentMove) - && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)) - { - u32 temp; - gProtectStructs[gBattlerTarget].shellTrapTriggered = TRUE; - gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE; - // Swap battlers so target attacks attacker with Shell Trap - SWAP(gBattlerAttacker, gBattlerTarget, temp); - // Set current move to Shell Trap - gCurrentMove = MOVE_SHELL_TRAP; - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_EffectShellTrap; - effect = TRUE; - } } gBattleScripting.moveendState++; break; @@ -9379,23 +9363,6 @@ static void Cmd_various(void) case VARIOUS_SET_BEAK_BLAST: gProtectStructs[gBattlerAttacker].beakBlastCharge = TRUE; break; - case VARIOUS_SET_SHELL_TRAP: - gProtectStructs[gBattlerAttacker].shellTrapSet = TRUE; - break; - case VARIOUS_CLEAR_SHELL_TRAP: - gProtectStructs[gBattlerAttacker].shellTrapSet = FALSE; - break; - case VARIOUS_CHECK_SHELL_TRAP: - // Attack with Shell Trap - if (gProtectStructs[gBattlerAttacker].shellTrapSet == TRUE && gProtectStructs[gBattlerAttacker].shellTrapTriggered == TRUE) - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); - // Attacked with Shell Trap, go to move end - else if (gProtectStructs[gBattlerAttacker].shellTrapSet == FALSE && gProtectStructs[gBattlerAttacker].shellTrapTriggered == TRUE) - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 7); - // Shell Trap failed - else - gBattlescriptCurrInstr += 11; - break; case VARIOUS_SWAP_SIDE_STATUSES: { CourtChangeSwapSideStatuses(); diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index 57b9bce4f..26c77a8e3 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -10212,7 +10212,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_SHELL_TRAP] = { - .effect = EFFECT_SHELL_TRAP, + .effect = EFFECT_PLACEHOLDER, // EFFECT_SHELL_TRAP, .power = 150, .type = TYPE_FIRE, .accuracy = 100, From 50d0cd52e8992869adb1cd5be680d9a90825e9d2 Mon Sep 17 00:00:00 2001 From: BuffelSaft Date: Mon, 22 Nov 2021 15:13:54 +1300 Subject: [PATCH 024/130] Clean up Corrosive Gas Remove code and unused move effect. --- include/battle.h | 1 - include/battle_scripts.h | 1 - include/constants/battle.h | 3 +-- src/battle_script_commands.c | 14 +++----------- 4 files changed, 4 insertions(+), 15 deletions(-) diff --git a/include/battle.h b/include/battle.h index 69161ba6f..9192d4ed3 100644 --- a/include/battle.h +++ b/include/battle.h @@ -245,7 +245,6 @@ struct WishFutureKnock u8 wishMonId[MAX_BATTLERS_COUNT]; u8 weatherDuration; u8 knockedOffMons[2]; // Each battler is represented by a bit. The array entry is dependent on the battler's side. - u8 meltedItemMons[2]; // Same as above }; struct AI_SavedBattleMon diff --git a/include/battle_scripts.h b/include/battle_scripts.h index ec1dbb23c..2f98ef7a1 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -415,7 +415,6 @@ extern const u8 BattleScript_AttackerFormChangeMoveEffect[]; extern const u8 BattleScript_BothCanNoLongerEscape[]; extern const u8 BattleScript_OctolockEndTurn[]; extern const u8 BattleScript_NeutralizingGasExits[]; -extern const u8 BattleScript_MeltedItem[]; extern const u8 BattleScript_BeakBlastSetUp[]; extern const u8 BattleScript_BeakBlastBurn[]; extern const u8 BattleScript_DefDownSpeedUp[]; diff --git a/include/constants/battle.h b/include/constants/battle.h index 46b6494b2..f615be05f 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -360,8 +360,7 @@ #define MOVE_EFFECT_RELIC_SONG 0x47 #define MOVE_EFFECT_TRAP_BOTH 0x48 #define MOVE_EFFECT_SCALE_SHOT 0x49 -#define MOVE_EFFECT_MELT_ITEM 0x4A -#define NUM_MOVE_EFFECTS 0x4B +#define NUM_MOVE_EFFECTS 0x4A #define MOVE_EFFECT_AFFECTS_USER 0x4000 #define MOVE_EFFECT_CERTAIN 0x8000 diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index a58aeed64..8e2c59d8a 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -3160,8 +3160,7 @@ void SetMoveEffect(bool32 primary, u32 certain) | BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_SECRET_BASE)) - && (gWishFutureKnock.knockedOffMons[side] & gBitTable[gBattlerPartyIndexes[gBattlerAttacker]] - || gWishFutureKnock.meltedItemMons[side] & gBitTable[gBattlerPartyIndexes[gBattlerAttacker]])) + && (gWishFutureKnock.knockedOffMons[side] & gBitTable[gBattlerPartyIndexes[gBattlerAttacker]])) { gBattlescriptCurrInstr++; } @@ -5583,11 +5582,6 @@ static void Cmd_switchindataupdate(void) { gBattleMons[gActiveBattler].item = 0; } - // check melted items - if (gWishFutureKnock.meltedItemMons[i] & gBitTable[gBattlerPartyIndexes[gActiveBattler]]) - { - gBattleMons[gActiveBattler].item = 0; - } if (gBattleMoves[gCurrentMove].effect == EFFECT_BATON_PASS) { @@ -12305,16 +12299,14 @@ static void Cmd_tryswapitems(void) // trick u8 sideAttacker = GetBattlerSide(gBattlerAttacker); u8 sideTarget = GetBattlerSide(gBattlerTarget); - // you can't swap items if they were knocked off or melted in regular battles + // You can't swap items if they were knocked off in regular battles if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_FRONTIER | BATTLE_TYPE_SECRET_BASE | BATTLE_TYPE_RECORDED_LINK)) && (gWishFutureKnock.knockedOffMons[sideAttacker] & gBitTable[gBattlerPartyIndexes[gBattlerAttacker]] - || gWishFutureKnock.knockedOffMons[sideTarget] & gBitTable[gBattlerPartyIndexes[gBattlerTarget]] - || gWishFutureKnock.meltedItemMons[sideTarget] & gBitTable[gBattlerPartyIndexes[gBattlerAttacker]] - || gWishFutureKnock.meltedItemMons[sideTarget] & gBitTable[gBattlerPartyIndexes[gBattlerTarget]])) + || gWishFutureKnock.knockedOffMons[sideTarget] & gBitTable[gBattlerPartyIndexes[gBattlerTarget]])) { gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); } From ff60882b29de2aa1a7d390adc3d1cc2f8bb21010 Mon Sep 17 00:00:00 2001 From: BuffelSaft Date: Tue, 23 Nov 2021 11:04:39 +1300 Subject: [PATCH 025/130] Requested changes --- include/constants/battle_move_effects.h | 2 +- include/constants/battle_script_commands.h | 5 ++--- include/constants/battle_string_ids.h | 8 +++----- src/battle_message.c | 4 ---- src/battle_script_commands.c | 19 ++++++++++--------- 5 files changed, 16 insertions(+), 22 deletions(-) diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index c6afed12c..9baabde5c 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -393,6 +393,6 @@ #define EFFECT_BEAK_BLAST 387 #define EFFECT_COURT_CHANGE 388 -#define NUM_BATTLE_MOVE_EFFECTS 390 +#define NUM_BATTLE_MOVE_EFFECTS 389 #endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 897bf35fb..96796ea2d 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -208,9 +208,8 @@ #define VARIOUS_SET_OCTOLOCK 135 #define VARIOUS_CUT_1_3_HP_RAISE_STATS 136 #define VARIOUS_TRY_END_NEUTRALIZING_GAS 137 -#define VARIOUS_TRY_SET_CORROSIVE_GAS 138 -#define VARIOUS_SET_BEAK_BLAST 139 -#define VARIOUS_SWAP_SIDE_STATUSES 140 +#define VARIOUS_SET_BEAK_BLAST 138 +#define VARIOUS_SWAP_SIDE_STATUSES 139 // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 0 diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index ee4b25115..ccbc5a536 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -611,12 +611,10 @@ #define STRINGID_NEUTRALIZINGGASOVER 608 #define STRINGID_PKMNINSNAPTRAP 609 #define STRINGID_METEORBEAMCHARGING 610 -#define STRINGID_ITEMMELTED 611 -#define STRINGID_HEATUPBEAK 612 -#define STRINGID_COURTCHANGE 613 -#define STRINGID_PREPARESHELLTRAP 614 +#define STRINGID_HEATUPBEAK 611 +#define STRINGID_COURTCHANGE 612 -#define BATTLESTRINGS_COUNT 615 +#define BATTLESTRINGS_COUNT 613 // The below IDs are all indexes into battle message tables, // used to determine which of a set of messages to print. diff --git a/src/battle_message.c b/src/battle_message.c index 18364849a..4ac9ef9b4 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -737,17 +737,13 @@ static const u8 sText_CantEscapeBecauseOfCurrentMove[] = _("{B_DEF_NAME_WITH_PRE static const u8 sText_NeutralizingGasEnters[] = _("Neutralizing Gas filled the area!"); static const u8 sText_NeutralizingGasOver[] = _("The effects of Neutralizing\nGas wore off!"); static const u8 sText_MeteorBeamCharging[] = _("{B_ATK_NAME_WITH_PREFIX} is overflowing\nwith space energy!"); -static const u8 sText_PkmnItemMelted[] = _("{B_ATK_NAME_WITH_PREFIX} corroded\n{B_DEF_NAME_WITH_PREFIX}'s {B_LAST_ITEM}!"); static const u8 sText_HeatingUpBeak[] = _("{B_ATK_NAME_WITH_PREFIX} started\nheating up its beak!"); static const u8 sText_CourtChange[] = _("{B_ATK_NAME_WITH_PREFIX} swapped the battle\neffects affecting each side!"); -static const u8 sText_PrepareShellTrap[] = _("{B_ATK_NAME_WITH_PREFIX} set\n a shell trap!"); const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = { - [STRINGID_PREPARESHELLTRAP - 12] = sText_PrepareShellTrap, [STRINGID_COURTCHANGE - 12] = sText_CourtChange, [STRINGID_HEATUPBEAK - 12] = sText_HeatingUpBeak, - [STRINGID_ITEMMELTED - 12] = sText_PkmnItemMelted, [STRINGID_METEORBEAMCHARGING - 12] = sText_MeteorBeamCharging, [STRINGID_PKMNINSNAPTRAP - 12] = sText_PkmnInSnapTrap, [STRINGID_NEUTRALIZINGGASOVER - 12] = sText_NeutralizingGasOver, diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 8e2c59d8a..21150f833 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -7525,15 +7525,15 @@ static bool32 IsRototillerAffected(u32 battlerId) #define COURTCHANGE_SWAP(status, structField, temp) \ { \ - temp = gSideStatuses[0]; \ - if (gSideStatuses[1] & status) \ - gSideStatuses[0] |= status; \ + temp = gSideStatuses[B_SIDE_PLAYER]; \ + if (gSideStatuses[B_SIDE_OPPONENT] & status) \ + gSideStatuses[B_SIDE_PLAYER] |= status; \ else \ - gSideStatuses[0] &= ~(status); \ + gSideStatuses[B_SIDE_PLAYER] &= ~(status); \ if (temp & status) \ - gSideStatuses[1] |= status; \ + gSideStatuses[B_SIDE_OPPONENT] |= status; \ else \ - gSideStatuses[1] &= ~(status); \ + gSideStatuses[B_SIDE_OPPONENT] &= ~(status); \ SWAP(sideTimer0->structField, sideTimer1->structField, temp);\ } \ @@ -7545,8 +7545,8 @@ static bool32 IsRototillerAffected(u32 battlerId) static bool32 CourtChangeSwapSideStatuses(void) { - struct SideTimer *sideTimer0 = &gSideTimers[0]; - struct SideTimer *sideTimer1 = &gSideTimers[1]; + struct SideTimer *sideTimer0 = &gSideTimers[B_SIDE_PLAYER]; + struct SideTimer *sideTimer1 = &gSideTimers[B_SIDE_OPPONENT]; u32 temp; // TODO: add Pledge-related effects @@ -11290,7 +11290,8 @@ static bool8 IsTwoTurnsMove(u16 move) || gBattleMoves[move].effect == EFFECT_TWO_TURNS_ATTACK || gBattleMoves[move].effect == EFFECT_SOLARBEAM || gBattleMoves[move].effect == EFFECT_SEMI_INVULNERABLE - || gBattleMoves[move].effect == EFFECT_BIDE) + || gBattleMoves[move].effect == EFFECT_BIDE + || gBattleMoves[move].effect == EFFECT_METEOR_BEAM) return TRUE; else return FALSE; From 6b8f86c276ee87bf6246bcfc2149fcffcb233833 Mon Sep 17 00:00:00 2001 From: BuffelSaft Date: Tue, 23 Nov 2021 11:05:36 +1300 Subject: [PATCH 026/130] Snap Trap placeholder anims Set up animation data for Snap Trap so it can be easily replaced with a proper animation later. --- data/battle_anim_scripts.s | 8 ++++++-- include/constants/battle_anim.h | 1 + src/battle_anim_throw.c | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index 8dbdcea73..bc3821563 100644 --- a/data/battle_anim_scripts.s +++ b/data/battle_anim_scripts.s @@ -13601,8 +13601,8 @@ Move_DRUM_BEATING:: blendoff end -Move_SNAP_TRAP:: - end @ to do: +Move_SNAP_TRAP:: @ placeholder + goto Move_BITE Move_PYRO_BALL:: loadspritegfx ANIM_TAG_FLAT_ROCK @@ -24209,6 +24209,7 @@ General_TurnTrap: jumpargeq 0, TRAP_ANIM_SAND_TOMB, Status_SandTomb jumpargeq 0, TRAP_ANIM_MAGMA_STORM, Status_MagmaStorm jumpargeq 0, TRAP_ANIM_INFESTATION, Status_Infestation + jumpargeq 0, TRAP_ANIM_SNAP_TRAP, Status_Snap_Trap goto Status_BindWrap Status_BindWrap: loadspritegfx ANIM_TAG_TENDRILS @@ -24295,6 +24296,9 @@ Status_Clamp: waitforvisualfinish end +Status_Snap_Trap: @ placeholder + goto Move_BITE + Status_SandTomb: loadspritegfx ANIM_TAG_MUD_SAND createsprite gSimplePaletteBlendSpriteTemplate, ANIM_ATTACKER, 0, 4, 2, 0, 7, RGB(19, 17, 0) diff --git a/include/constants/battle_anim.h b/include/constants/battle_anim.h index 8b0e81264..d11bc797c 100644 --- a/include/constants/battle_anim.h +++ b/include/constants/battle_anim.h @@ -569,6 +569,7 @@ #define TRAP_ANIM_SAND_TOMB 4 #define TRAP_ANIM_MAGMA_STORM 5 #define TRAP_ANIM_INFESTATION 6 +#define TRAP_ANIM_SNAP_TRAP 7 // Weather defines for battle animation scripts. #define ANIM_WEATHER_NONE 0 diff --git a/src/battle_anim_throw.c b/src/battle_anim_throw.c index f325cba07..4413a4674 100755 --- a/src/battle_anim_throw.c +++ b/src/battle_anim_throw.c @@ -2500,6 +2500,8 @@ void AnimTask_GetTrappedMoveAnimId(u8 taskId) gBattleAnimArgs[0] = TRAP_ANIM_MAGMA_STORM; else if (gBattleSpritesDataPtr->animationData->animArg == MOVE_INFESTATION) gBattleAnimArgs[0] = TRAP_ANIM_INFESTATION; + else if (gBattleSpritesDataPtr->animationData->animArg == MOVE_SNAP_TRAP) + gBattleAnimArgs[0] = TRAP_ANIM_SNAP_TRAP; else gBattleAnimArgs[0] = TRAP_ANIM_BIND; From fa0b5188bb1ecbc31ad2e604dc1a8adc488abcb7 Mon Sep 17 00:00:00 2001 From: BuffelSaft Date: Tue, 23 Nov 2021 16:56:11 +1300 Subject: [PATCH 027/130] Dynamic move targeting Properly implement Expanding Force by replacing all instances that read move target from gBattleMoves with a function. --- include/battle_util.h | 2 +- src/battle_ai_main.c | 24 ++++++------- src/battle_ai_util.c | 3 +- src/battle_anim.c | 2 +- src/battle_controller_opponent.c | 6 ++-- src/battle_controller_player.c | 18 ++++------ src/battle_controller_player_partner.c | 4 +-- src/battle_gfx_sfx_util.c | 18 +++++----- src/battle_script_commands.c | 33 +++++++++-------- src/battle_util.c | 50 ++++++++++++++++---------- src/contest.c | 2 +- 11 files changed, 87 insertions(+), 75 deletions(-) diff --git a/include/battle_util.h b/include/battle_util.h index b1a2a1534..47bc2cc56 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -163,7 +163,7 @@ bool32 IsBattlerWeatherAffected(u8 battlerId, u32 weatherFlags); void TryToApplyMimicry(u8 battlerId, bool8 various); void TryToRevertMimicry(void); void RestoreBattlerOriginalTypes(u8 battlerId); - +u32 GetMoveTargetType(u8 battlerId, u16 move); // Ability checks bool32 IsRolePlayBannedAbilityAtk(u16 ability); bool32 IsRolePlayBannedAbility(u16 ability); diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index e3b8e8d5d..dda1ff9cc 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -521,7 +521,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) u8 atkPriority = GetMovePriority(battlerAtk, move); u16 moveEffect = gBattleMoves[move].effect; s32 moveType; - u16 moveTarget = gBattleMoves[move].target; + u16 moveTarget = GetMoveTargetType(battlerAtk, move); u16 accuracy = AI_GetMoveAccuracy(battlerAtk, battlerDef, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect, move); u8 effectiveness = AI_GetMoveEffectiveness(move, battlerAtk, battlerDef); bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk); @@ -537,7 +537,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) GET_MOVE_TYPE(move, moveType); // check non-user target - if (!(gBattleMoves[move].target & MOVE_TARGET_USER)) + if (moveTarget & MOVE_TARGET_USER) { // handle negative checks on non-user target // check powder moves @@ -2336,7 +2336,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } else { - if (gBattleMoves[instructedMove].target & (MOVE_TARGET_SELECTED + if (GetMoveTargetType(battlerDef, instructedMove) & (MOVE_TARGET_SELECTED | MOVE_TARGET_DEPENDS | MOVE_TARGET_RANDOM | MOVE_TARGET_BOTH @@ -2533,7 +2533,7 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // move data u8 moveType = gBattleMoves[move].type; u16 effect = gBattleMoves[move].effect; - u16 target = gBattleMoves[move].target; + u16 moveTarget = GetMoveTargetType(battlerAtk, move); // ally data u8 battlerAtkPartner = AI_DATA->battlerAtkPartner; u16 atkPartnerAbility = AI_DATA->atkPartnerAbility; @@ -2572,7 +2572,7 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (IsAttackBoostMoveEffect(effect)) score -= 3; // encourage moves hitting multiple opponents - if (!IS_MOVE_STATUS(move) && (gBattleMoves[move].target & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY))) + if (!IS_MOVE_STATUS(move) && (moveTarget & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY))) score += 3; } } @@ -2640,7 +2640,7 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (GetMoveDamageResult(move) == MOVE_POWER_OTHER) { // partner ability checks - if (!partnerProtecting && gBattleMoves[move].target != MOVE_TARGET_BOTH && !DoesBattlerIgnoreAbilityChecks(AI_DATA->atkAbility, move)) + if (!partnerProtecting && moveTarget != MOVE_TARGET_BOTH && !DoesBattlerIgnoreAbilityChecks(AI_DATA->atkAbility, move)) { switch (atkPartnerAbility) { @@ -2840,7 +2840,7 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (instructedMove != MOVE_NONE && !IS_MOVE_STATUS(instructedMove) - && gBattleMoves[instructedMove].target & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY)) //Use instruct on multi-target moves + && (GetMoveTargetType(battlerAtkPartner, instructedMove) & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY))) // Use instruct on multi-target moves { RETURN_SCORE_PLUS(1); } @@ -3631,24 +3631,24 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); break; case MOVE_WIDE_GUARD: - if (predictedMove != MOVE_NONE && gBattleMoves[predictedMove].target & (MOVE_TARGET_FOES_AND_ALLY | MOVE_TARGET_BOTH)) + if (predictedMove != MOVE_NONE && GetMoveTargetType(battlerDef, predictedMove) & (MOVE_TARGET_FOES_AND_ALLY | MOVE_TARGET_BOTH)) { ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); } - else if (isDoubleBattle && gBattleMoves[AI_DATA->partnerMove].target & MOVE_TARGET_FOES_AND_ALLY) + else if (isDoubleBattle && GetMoveTargetType(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove) & MOVE_TARGET_FOES_AND_ALLY) { if (AI_DATA->atkAbility != ABILITY_TELEPATHY) ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); } break; case MOVE_CRAFTY_SHIELD: - if (predictedMove != MOVE_NONE && IS_MOVE_STATUS(predictedMove) && !(gBattleMoves[predictedMove].target & MOVE_TARGET_USER)) + if (predictedMove != MOVE_NONE && IS_MOVE_STATUS(predictedMove) && !(GetMoveTargetType(battlerDef, predictedMove) & MOVE_TARGET_USER)) ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); break; case MOVE_MAT_BLOCK: if (gDisableStructs[battlerAtk].isFirstTurn && predictedMove != MOVE_NONE - && !IS_MOVE_STATUS(predictedMove) && !(gBattleMoves[predictedMove].target & MOVE_TARGET_USER)) + && !IS_MOVE_STATUS(predictedMove) && !(GetMoveTargetType(battlerDef, predictedMove) & MOVE_TARGET_USER)) ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); break; case MOVE_KINGS_SHIELD: @@ -4093,7 +4093,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score += 10; break; case EFFECT_MAGIC_COAT: - if (IS_MOVE_STATUS(predictedMove) && gBattleMoves[predictedMove].target & (MOVE_TARGET_SELECTED | MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_BOTH)) + if (IS_MOVE_STATUS(predictedMove) && GetMoveTargetType(battlerDef, predictedMove) & (MOVE_TARGET_SELECTED | MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_BOTH)) score += 3; break; case EFFECT_RECYCLE: diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 47561c765..ef6b0679f 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -1919,9 +1919,8 @@ bool32 HasMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef, u8 accCheck, bool32 if (ignoreStatus && IS_MOVE_STATUS(moves[i])) continue; else if ((!IS_MOVE_STATUS(moves[i]) && gBattleMoves[moves[i]].accuracy == 0) - || gBattleMoves[moves[i]].target & (MOVE_TARGET_USER | MOVE_TARGET_OPPONENTS_FIELD)) + || GetMoveTargetType(battlerAtk, moves[i]) & (MOVE_TARGET_USER | MOVE_TARGET_OPPONENTS_FIELD)) continue; - if (AI_GetMoveAccuracy(battlerAtk, battlerDef, atkAbility, defAbility, atkHoldEffect, defHoldEffect, moves[i]) <= accCheck) return TRUE; } diff --git a/src/battle_anim.c b/src/battle_anim.c index e6152a7cf..d6761eae6 100644 --- a/src/battle_anim.c +++ b/src/battle_anim.c @@ -2195,7 +2195,7 @@ void DoMoveAnim(u16 move) gBattleAnimAttacker = gBattlerAttacker; gBattleAnimTarget = gBattlerTarget; // Make sure the anim target of moves hitting everyone is at the opposite side. - if (gBattleMoves[move].target & MOVE_TARGET_FOES_AND_ALLY && IsDoubleBattle()) + if (GetMoveTargetType(gBattlerAttacker, move) & MOVE_TARGET_FOES_AND_ALLY && IsDoubleBattle()) { while (GET_BATTLER_SIDE(gBattleAnimAttacker) == GET_BATTLER_SIDE(gBattleAnimTarget)) { diff --git a/src/battle_controller_opponent.c b/src/battle_controller_opponent.c index b43e80225..ff253730f 100644 --- a/src/battle_controller_opponent.c +++ b/src/battle_controller_opponent.c @@ -1586,9 +1586,9 @@ static void OpponentHandleChooseMove(void) BtlController_EmitTwoReturnValues(1, 15, gBattlerTarget); break; default: - if (gBattleMoves[moveInfo->moves[chosenMoveId]].target & (MOVE_TARGET_USER_OR_SELECTED | MOVE_TARGET_USER)) + if (GetMoveTargetType(gActiveBattler, moveInfo->moves[chosenMoveId]) & (MOVE_TARGET_USER_OR_SELECTED | MOVE_TARGET_USER)) gBattlerTarget = gActiveBattler; - if (gBattleMoves[moveInfo->moves[chosenMoveId]].target & MOVE_TARGET_BOTH) + if (GetMoveTargetType(gActiveBattler, moveInfo->moves[chosenMoveId]) & MOVE_TARGET_BOTH) { gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); if (gAbsentBattlerFlags & gBitTable[gBattlerTarget]) @@ -1611,7 +1611,7 @@ static void OpponentHandleChooseMove(void) move = moveInfo->moves[chosenMoveId]; } while (move == MOVE_NONE); - if (gBattleMoves[move].target & (MOVE_TARGET_USER_OR_SELECTED | MOVE_TARGET_USER)) + if (GetMoveTargetType(gActiveBattler, move) & (MOVE_TARGET_USER_OR_SELECTED | MOVE_TARGET_USER)) BtlController_EmitTwoReturnValues(1, 10, (chosenMoveId) | (gActiveBattler << 8)); else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) BtlController_EmitTwoReturnValues(1, 10, (chosenMoveId) | (GetBattlerAtPosition(Random() & 2) << 8)); diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index a970c38b7..05ad19170 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -360,6 +360,7 @@ static void HandleInputChooseTarget(void) s32 i; static const u8 identities[MAX_BATTLERS_COUNT] = {B_POSITION_PLAYER_LEFT, B_POSITION_PLAYER_RIGHT, B_POSITION_OPPONENT_RIGHT, B_POSITION_OPPONENT_LEFT}; u16 move = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_MOVE1 + gMoveSelectionCursor[gActiveBattler]); + u16 moveTarget = GetMoveTargetType(gActiveBattler, move); DoBounceEffect(gMultiUsePlayerCursor, BOUNCE_HEALTHBOX, 15, 1); for (i = 0; i < gBattlersCount; i++) @@ -400,7 +401,7 @@ static void HandleInputChooseTarget(void) PlaySE(SE_SELECT); gSprites[gBattlerSpriteIds[gMultiUsePlayerCursor]].callback = SpriteCb_HideAsMoveTarget; - if (gBattleMoves[move].target == (MOVE_TARGET_USER | MOVE_TARGET_ALLY)) + if (moveTarget == (MOVE_TARGET_USER | MOVE_TARGET_ALLY)) { gMultiUsePlayerCursor ^= BIT_FLANK; } @@ -429,7 +430,7 @@ static void HandleInputChooseTarget(void) case B_POSITION_PLAYER_RIGHT: if (gActiveBattler != gMultiUsePlayerCursor) i++; - else if (gBattleMoves[move].target & MOVE_TARGET_USER_OR_SELECTED) + else if (moveTarget & MOVE_TARGET_USER_OR_SELECTED) i++; break; case B_POSITION_OPPONENT_LEFT: @@ -449,7 +450,7 @@ static void HandleInputChooseTarget(void) PlaySE(SE_SELECT); gSprites[gBattlerSpriteIds[gMultiUsePlayerCursor]].callback = SpriteCb_HideAsMoveTarget; - if (gBattleMoves[move].target == (MOVE_TARGET_USER | MOVE_TARGET_ALLY)) + if (moveTarget == (MOVE_TARGET_USER | MOVE_TARGET_ALLY)) { gMultiUsePlayerCursor ^= BIT_FLANK; } @@ -478,7 +479,7 @@ static void HandleInputChooseTarget(void) case B_POSITION_PLAYER_RIGHT: if (gActiveBattler != gMultiUsePlayerCursor) i++; - else if (gBattleMoves[move].target & MOVE_TARGET_USER_OR_SELECTED) + else if (moveTarget & MOVE_TARGET_USER_OR_SELECTED) i++; break; case B_POSITION_OPPONENT_LEFT: @@ -609,16 +610,9 @@ static void HandleInputChooseMove(void) else moveTarget = MOVE_TARGET_SELECTED; } - else if (moveInfo->moves[gMoveSelectionCursor[gActiveBattler]] == MOVE_EXPANDING_FORCE) - { - if (IsBattlerTerrainAffected(gActiveBattler, STATUS_FIELD_PSYCHIC_TERRAIN)) - moveTarget = MOVE_TARGET_BOTH; - else - moveTarget = MOVE_TARGET_SELECTED; - } else { - moveTarget = gBattleMoves[moveInfo->moves[gMoveSelectionCursor[gActiveBattler]]].target; + moveTarget = GetMoveTargetType(gActiveBattler, moveInfo->moves[gMoveSelectionCursor[gActiveBattler]]); } if (moveTarget & MOVE_TARGET_USER) diff --git a/src/battle_controller_player_partner.c b/src/battle_controller_player_partner.c index f0540e65f..a72f1029b 100644 --- a/src/battle_controller_player_partner.c +++ b/src/battle_controller_player_partner.c @@ -1526,9 +1526,9 @@ static void PlayerPartnerHandleChooseMove(void) BattleAI_SetupAIData(0xF); chosenMoveId = BattleAI_ChooseMoveOrAction(); - if (gBattleMoves[moveInfo->moves[chosenMoveId]].target & (MOVE_TARGET_USER | MOVE_TARGET_USER_OR_SELECTED)) + if (GetMoveTargetType(gActiveBattler, moveInfo->moves[chosenMoveId]) & (MOVE_TARGET_USER_OR_SELECTED | MOVE_TARGET_USER)) gBattlerTarget = gActiveBattler; - if (gBattleMoves[moveInfo->moves[chosenMoveId]].target & MOVE_TARGET_BOTH) + if (GetMoveTargetType(gActiveBattler, moveInfo->moves[chosenMoveId]) & MOVE_TARGET_BOTH) { gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); if (gAbsentBattlerFlags & gBitTable[gBattlerTarget]) diff --git a/src/battle_gfx_sfx_util.c b/src/battle_gfx_sfx_util.c index 482a135c5..11e41ebd4 100644 --- a/src/battle_gfx_sfx_util.c +++ b/src/battle_gfx_sfx_util.c @@ -38,7 +38,7 @@ extern const struct CompressedSpriteSheet gSpriteSheet_EnemyShadow; extern const struct SpriteTemplate gSpriteTemplate_EnemyShadow; // this file's functions -static u8 GetBattlePalaceMoveGroup(u16 move); +static u8 GetBattlePalaceMoveGroup(u8 battlerId, u16 move); static u16 GetBattlePalaceTarget(void); static void SpriteCB_TrainerSlideVertical(struct Sprite *sprite); static bool8 ShouldAnimBeDoneRegardlessOfSubstitute(u8 animId); @@ -155,7 +155,7 @@ u16 ChooseMoveAndTargetInBattlePalace(void) { if (moveInfo->moves[i] == MOVE_NONE) break; - if (selectedGroup == GetBattlePalaceMoveGroup(moveInfo->moves[i]) && moveInfo->currentPp[i] != 0) + if (selectedGroup == GetBattlePalaceMoveGroup(gActiveBattler, moveInfo->moves[i]) && moveInfo->currentPp[i] != 0) selectedMoves |= gBitTable[i]; } @@ -181,11 +181,11 @@ u16 ChooseMoveAndTargetInBattlePalace(void) { // validMoveFlags is used here as a bitfield for which moves can be used for each move group type // first 4 bits are for attack (1 for each move), then 4 bits for defense, and 4 for support - if (GetBattlePalaceMoveGroup(moveInfo->moves[i]) == PALACE_MOVE_GROUP_ATTACK && !(gBitTable[i] & unusableMovesBits)) + if (GetBattlePalaceMoveGroup(gActiveBattler, moveInfo->moves[i]) == PALACE_MOVE_GROUP_ATTACK && !(gBitTable[i] & unusableMovesBits)) validMoveFlags += (1 << 0); - if (GetBattlePalaceMoveGroup(moveInfo->moves[i]) == PALACE_MOVE_GROUP_DEFENSE && !(gBitTable[i] & unusableMovesBits)) + if (GetBattlePalaceMoveGroup(gActiveBattler, moveInfo->moves[i]) == PALACE_MOVE_GROUP_DEFENSE && !(gBitTable[i] & unusableMovesBits)) validMoveFlags += (1 << 4); - if (GetBattlePalaceMoveGroup(moveInfo->moves[i]) == PALACE_MOVE_GROUP_SUPPORT && !(gBitTable[i] & unusableMovesBits)) + if (GetBattlePalaceMoveGroup(gActiveBattler, moveInfo->moves[i]) == PALACE_MOVE_GROUP_SUPPORT && !(gBitTable[i] & unusableMovesBits)) validMoveFlags += (1 << 8); } @@ -222,7 +222,7 @@ u16 ChooseMoveAndTargetInBattlePalace(void) do { i = Random() % MAX_MON_MOVES; - if (!(gBitTable[i] & unusableMovesBits) && validMoveGroup == GetBattlePalaceMoveGroup(moveInfo->moves[i])) + if (!(gBitTable[i] & unusableMovesBits) && validMoveGroup == GetBattlePalaceMoveGroup(gActiveBattler, moveInfo->moves[i])) chosenMoveId = i; } while (chosenMoveId == -1); } @@ -251,7 +251,7 @@ u16 ChooseMoveAndTargetInBattlePalace(void) } else { - moveTarget = gBattleMoves[moveInfo->moves[chosenMoveId]].target; + moveTarget = GetMoveTargetType(gActiveBattler, moveInfo->moves[chosenMoveId]); } if (moveTarget & MOVE_TARGET_USER) @@ -273,9 +273,9 @@ u16 ChooseMoveAndTargetInBattlePalace(void) #undef numValidMoveGroups #undef validMoveGroup -static u8 GetBattlePalaceMoveGroup(u16 move) +static u8 GetBattlePalaceMoveGroup(u8 battlerId, u16 move) { - switch (gBattleMoves[move].target) + switch (GetMoveTargetType(battlerId, move)) { case MOVE_TARGET_SELECTED: case MOVE_TARGET_USER_OR_SELECTED: diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 21150f833..437733f1e 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1313,12 +1313,12 @@ static const u8 sBattlePalaceNatureToFlavorTextId[NUM_NATURES] = [NATURE_QUIRKY] = B_MSG_EAGER_FOR_MORE, }; -static bool32 NoTargetPresent(u32 move) +static bool32 NoTargetPresent(u8 battlerId, u32 move) { if (!IsBattlerAlive(gBattlerTarget)) gBattlerTarget = GetMoveTarget(move, 0); - switch (gBattleMoves[move].target) + switch (GetMoveTargetType(battlerId, move)) { case MOVE_TARGET_SELECTED: case MOVE_TARGET_DEPENDS: @@ -1459,7 +1459,7 @@ static void Cmd_attackcanceler(void) } gHitMarker |= HITMARKER_OBEYS; - if (NoTargetPresent(gCurrentMove) && (!IsTwoTurnsMove(gCurrentMove) || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS))) + if (NoTargetPresent(gBattlerAttacker, gCurrentMove) && (!IsTwoTurnsMove(gCurrentMove) || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS))) { gBattlescriptCurrInstr = BattleScript_ButItFailedAtkStringPpReduce; if (!IsTwoTurnsMove(gCurrentMove) || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)) @@ -1741,6 +1741,7 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move) static void Cmd_accuracycheck(void) { u16 type, move = T2_READ_16(gBattlescriptCurrInstr + 5); + u16 moveTarget = GetMoveTargetType(gBattlerAttacker, move); if (move == ACC_CURR_MOVE) move = gCurrentMove; @@ -1770,7 +1771,7 @@ static void Cmd_accuracycheck(void) gBattleStruct->blunderPolicy = TRUE; // Only activates from missing through acc/evasion checks if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && - (gBattleMoves[move].target == MOVE_TARGET_BOTH || gBattleMoves[move].target == MOVE_TARGET_FOES_AND_ALLY)) + (moveTarget == MOVE_TARGET_BOTH || moveTarget == MOVE_TARGET_FOES_AND_ALLY)) gBattleCommunication[MISS_TYPE] = B_MSG_AVOIDED_ATK; else gBattleCommunication[MISS_TYPE] = B_MSG_MISSED; @@ -1804,7 +1805,7 @@ static void Cmd_ppreduce(void) if (!gSpecialStatuses[gBattlerAttacker].ppNotAffectedByPressure) { - switch (gBattleMoves[gCurrentMove].target) + switch (GetMoveTargetType(gBattlerAttacker, gCurrentMove)) { case MOVE_TARGET_FOES_AND_ALLY: for (i = 0; i < gBattlersCount; i++) @@ -2103,6 +2104,8 @@ static void Cmd_multihitresultmessage(void) static void Cmd_attackanimation(void) { + u16 moveTarget = GetMoveTargetType(gBattlerAttacker, gCurrentMove); + if (gBattleControllerExecFlags) return; @@ -2119,9 +2122,9 @@ static void Cmd_attackanimation(void) } else { - if ((gBattleMoves[gCurrentMove].target & MOVE_TARGET_BOTH - || gBattleMoves[gCurrentMove].target & MOVE_TARGET_FOES_AND_ALLY - || gBattleMoves[gCurrentMove].target & MOVE_TARGET_DEPENDS) + if ((moveTarget & MOVE_TARGET_BOTH + || moveTarget & MOVE_TARGET_FOES_AND_ALLY + || moveTarget & MOVE_TARGET_DEPENDS) && gBattleScripting.animTargetsHit) { gBattlescriptCurrInstr++; @@ -5237,6 +5240,8 @@ static void Cmd_moveend(void) gBattleScripting.moveendState++; break; case MOVEEND_NEXT_TARGET: // For moves hitting two opposing Pokemon. + { + u16 moveTarget = GetMoveTargetType(gBattlerAttacker, gCurrentMove); // Set a flag if move hits either target (for throat spray that can't check damage) if (!(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)) @@ -5245,14 +5250,13 @@ static void Cmd_moveend(void) if (!(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) && gBattleTypeFlags & BATTLE_TYPE_DOUBLE && !gProtectStructs[gBattlerAttacker].chargingTurn - && (gBattleMoves[gCurrentMove].target == MOVE_TARGET_BOTH - || gBattleMoves[gCurrentMove].target == MOVE_TARGET_FOES_AND_ALLY - || (gBattleMoves[gCurrentMove].effect == EFFECT_EXPANDING_FORCE && IsBattlerTerrainAffected(gBattlerAttacker, STATUS_FIELD_PSYCHIC_TERRAIN))) + && (moveTarget == MOVE_TARGET_BOTH + || moveTarget == MOVE_TARGET_FOES_AND_ALLY) && !(gHitMarker & HITMARKER_NO_ATTACKSTRING)) { u8 battlerId; - if (gBattleMoves[gCurrentMove].target == MOVE_TARGET_FOES_AND_ALLY) + if (moveTarget == MOVE_TARGET_FOES_AND_ALLY) { gHitMarker |= HITMARKER_NO_PPDEDUCT; for (battlerId = gBattlerTarget + 1; battlerId < gBattlersCount; battlerId++) @@ -5288,6 +5292,7 @@ static void Cmd_moveend(void) RecordLastUsedMoveBy(gBattlerAttacker, gCurrentMove); gBattleScripting.moveendState++; break; + } case MOVEEND_EJECT_BUTTON: if (gCurrentMove != MOVE_DRAGON_TAIL && gCurrentMove != MOVE_CIRCLE_THROW @@ -9506,7 +9511,7 @@ static void Cmd_jumpifnexttargetvalid(void) for (gBattlerTarget++; gBattlerTarget < gBattlersCount; gBattlerTarget++) { - if (gBattlerTarget == gBattlerAttacker && !(gBattleMoves[gCurrentMove].target & MOVE_TARGET_USER)) + if (gBattlerTarget == gBattlerAttacker && !(GetMoveTargetType(gBattlerAttacker, gCurrentMove) & MOVE_TARGET_USER)) continue; if (IsBattlerAlive(gBattlerTarget)) break; @@ -12000,7 +12005,7 @@ static void Cmd_selectfirstvalidtarget(void) { for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount; gBattlerTarget++) { - if (gBattlerTarget == gBattlerAttacker && !(gBattleMoves[gCurrentMove].target & MOVE_TARGET_USER)) + if (gBattlerTarget == gBattlerAttacker && !(GetMoveTargetType(gBattlerAttacker, gCurrentMove) & MOVE_TARGET_USER)) continue; if (IsBattlerAlive(gBattlerTarget)) break; diff --git a/src/battle_util.c b/src/battle_util.c index e946fe8f0..dcde7b8ce 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -237,6 +237,7 @@ bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move) void HandleAction_UseMove(void) { u32 i, side, moveType, var = 4; + u16 moveTarget = GetMoveTargetType(gBattlerAttacker, gCurrentMove); gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; if (gBattleStruct->field_91 & gBitTable[gBattlerAttacker] || !IsBattlerAlive(gBattlerAttacker)) @@ -309,14 +310,14 @@ void HandleAction_UseMove(void) // choose target side = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE; if (IsAffectedByFollowMe(gBattlerAttacker, side, gCurrentMove) - && gBattleMoves[gCurrentMove].target == MOVE_TARGET_SELECTED + && moveTarget == MOVE_TARGET_SELECTED && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gSideTimers[side].followmeTarget)) { gBattlerTarget = gSideTimers[side].followmeTarget; } else if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && gSideTimers[side].followmeTimer == 0 - && (gBattleMoves[gCurrentMove].power != 0 || gBattleMoves[gCurrentMove].target != MOVE_TARGET_USER) + && (gBattleMoves[gCurrentMove].power != 0 || moveTarget != MOVE_TARGET_USER) && ((GetBattlerAbility(*(gBattleStruct->moveTarget + gBattlerAttacker)) != ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC) || (GetBattlerAbility(*(gBattleStruct->moveTarget + gBattlerAttacker)) != ABILITY_STORM_DRAIN && moveType == TYPE_WATER))) { @@ -337,7 +338,7 @@ void HandleAction_UseMove(void) } if (var == 4) { - if (gBattleMoves[gChosenMove].target & MOVE_TARGET_RANDOM) + if (moveTarget & MOVE_TARGET_RANDOM) { if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) { @@ -354,7 +355,7 @@ void HandleAction_UseMove(void) gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT); } } - else if (gBattleMoves[gChosenMove].target & MOVE_TARGET_FOES_AND_ALLY) + else if (moveTarget & MOVE_TARGET_FOES_AND_ALLY) { for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount; gBattlerTarget++) { @@ -395,7 +396,7 @@ void HandleAction_UseMove(void) } } else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE - && gBattleMoves[gChosenMove].target & MOVE_TARGET_RANDOM) + && moveTarget & MOVE_TARGET_RANDOM) { if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) { @@ -418,7 +419,7 @@ void HandleAction_UseMove(void) gBattlerTarget = GetBattlerAtPosition(GetBattlerPosition(gBattlerTarget) ^ BIT_FLANK); } } - else if (gBattleMoves[gChosenMove].target == MOVE_TARGET_ALLY) + else if (moveTarget == MOVE_TARGET_ALLY) { if (IsBattlerAlive(BATTLE_PARTNER(gBattlerAttacker))) gBattlerTarget = BATTLE_PARTNER(gBattlerAttacker); @@ -426,7 +427,7 @@ void HandleAction_UseMove(void) gBattlerTarget = gBattlerAttacker; } else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE - && gBattleMoves[gChosenMove].target == MOVE_TARGET_FOES_AND_ALLY) + && moveTarget == MOVE_TARGET_FOES_AND_ALLY) { for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount; gBattlerTarget++) { @@ -4668,7 +4669,10 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move } break; case ABILITYEFFECT_MOVES_BLOCK: // 2 - if ((gLastUsedAbility == ABILITY_SOUNDPROOF && gBattleMoves[move].flags & FLAG_SOUND && !(gBattleMoves[move].target & MOVE_TARGET_USER)) + { + u16 moveTarget = GetMoveTargetType(battler, move); + + if ((gLastUsedAbility == ABILITY_SOUNDPROOF && gBattleMoves[move].flags & FLAG_SOUND && !(moveTarget & MOVE_TARGET_USER)) || (gLastUsedAbility == ABILITY_BULLETPROOF && gBattleMoves[move].flags & FLAG_BALLISTIC)) { if (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS) @@ -4691,14 +4695,14 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move else if (BlocksPrankster(move, gBattlerAttacker, gBattlerTarget, TRUE) && !(IS_MOVE_STATUS(move) && GetBattlerAbility(gBattlerTarget) == ABILITY_MAGIC_BOUNCE)) { - if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE) || !(gBattleMoves[move].target & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY))) + if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE) || !(moveTarget & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY))) CancelMultiTurnMoves(gBattlerAttacker); // Don't cancel moves that can hit two targets bc one target might not be protected gBattleScripting.battler = gBattlerAbility = gBattlerTarget; gBattlescriptCurrInstr = BattleScript_DarkTypePreventsPrankster; effect = 1; } - break; + } case ABILITYEFFECT_ABSORBING: // 3 if (move != MOVE_NONE) { @@ -7257,15 +7261,12 @@ u32 GetMoveTarget(u16 move, u8 setTarget) if (setTarget) moveTarget = setTarget - 1; else - moveTarget = gBattleMoves[move].target; - + moveTarget = GetMoveTargetType(gBattlerAttacker, move); + // Special cases if (move == MOVE_CURSE && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GHOST)) moveTarget = MOVE_TARGET_USER; - if (gBattleMoves[move].effect == EFFECT_EXPANDING_FORCE && IsBattlerTerrainAffected(gBattlerAttacker, STATUS_FIELD_PSYCHIC_TERRAIN)) - moveTarget = MOVE_TARGET_BOTH; - switch (moveTarget) { case MOVE_TARGET_SELECTED: @@ -7528,7 +7529,7 @@ bool32 IsBattlerProtected(u8 battlerId, u16 move) else if (gProtectStructs[battlerId].protected) return TRUE; else if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_WIDE_GUARD - && gBattleMoves[move].target & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY)) + && GetMoveTargetType(gBattlerAttacker, move) & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY)) return TRUE; else if (gProtectStructs[battlerId].banefulBunkered) return TRUE; @@ -7654,7 +7655,7 @@ u32 CountBattlerStatIncreases(u8 battlerId, bool32 countEvasionAcc) u32 GetMoveTargetCount(u16 move, u8 battlerAtk, u8 battlerDef) { - switch (gBattleMoves[move].target) + switch (GetMoveTargetType(gBattlerAttacker, move)) { case MOVE_TARGET_BOTH: return IsBattlerAlive(battlerDef) @@ -9818,7 +9819,7 @@ bool32 BlocksPrankster(u16 move, u8 battlerPrankster, u8 battlerDef, bool32 chec return FALSE; if (GetBattlerSide(battlerPrankster) == GetBattlerSide(battlerDef)) return FALSE; - if (checkTarget && (gBattleMoves[move].target & (MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_DEPENDS))) + if (checkTarget && (GetMoveTargetType(battlerPrankster, move) & (MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_DEPENDS))) return FALSE; if (!IS_BATTLER_OF_TYPE(battlerDef, TYPE_DARK)) return FALSE; @@ -9850,3 +9851,16 @@ bool32 IsBattlerWeatherAffected(u8 battlerId, u32 weatherFlags) } return FALSE; } + +// Gets move target before redirection effects etc. are applied +// Possible return values are defined in battle.h following MOVE_TARGET_SELECTED +u32 GetMoveTargetType(u8 battlerId, u16 move) +{ + u32 target; + + if (gBattleMoves[move].effect == EFFECT_EXPANDING_FORCE + && IsBattlerTerrainAffected(gActiveBattler, STATUS_FIELD_PSYCHIC_TERRAIN)) + return MOVE_TARGET_BOTH; + else + return gBattleMoves[move].target; +} diff --git a/src/contest.c b/src/contest.c index 46fa0efed..c876f02cc 100644 --- a/src/contest.c +++ b/src/contest.c @@ -5388,7 +5388,7 @@ static void SetBattleTargetSpritePosition(void) static void SetMoveTargetPosition(u16 move) { - switch (gBattleMoves[move].target) + switch (GetMoveTargetType(gBattlerAttacker, move)) { case MOVE_TARGET_USER_OR_SELECTED: case MOVE_TARGET_USER: From a89ce0c38abf74470a78091152c8f5900cdde792 Mon Sep 17 00:00:00 2001 From: BuffelSaft Date: Tue, 23 Nov 2021 22:54:30 +1300 Subject: [PATCH 028/130] Swapped webs don't trigger Defiant Track the side that originally set Sticky Web, and if it matches the side the target of the speed drop is on, don't activate Defiant. Hard to tell if this is a bug or a feature in gen 8 - maybe the swapped webs are considered a "friendly" effect? Also, fix Sticky Web not activating Defiant. --- data/battle_scripts_1.s | 1 + include/battle.h | 2 ++ include/constants/battle_script_commands.h | 1 + src/battle_script_commands.c | 39 ++++++++++++---------- src/battle_util.c | 5 ++- 5 files changed, 30 insertions(+), 18 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index eeeba7cf7..dabdf1383 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -6712,6 +6712,7 @@ BattleScript_ToxicSpikesPoisoned:: BattleScript_StickyWebOnSwitchIn:: savetarget copybyte gBattlerTarget, sBATTLER + setbyte sSTICKY_WEB_STAT_DROP, 1 printstring STRINGID_STICKYWEBSWITCHIN waitmessage B_WAIT_TIME_LONG jumpifability BS_TARGET, ABILITY_MIRROR_ARMOR, BattleScript_MirrorArmorReflectStickyWeb diff --git a/include/battle.h b/include/battle.h index f534f416b..7ccb492a6 100644 --- a/include/battle.h +++ b/include/battle.h @@ -211,6 +211,7 @@ struct SideTimer u8 toxicSpikesAmount; u8 stealthRockAmount; u8 stickyWebAmount; + u8 stickyWebBattlerSide; // Used for Court Change u8 auroraVeilTimer; u8 auroraVeilBattlerId; u8 tailwindTimer; @@ -704,6 +705,7 @@ struct BattleScripting u16 abilityPopupOverwrite; u8 switchCase; // Special switching conditions, eg. red card u8 overrideBerryRequirements; + u8 stickyWebStatDrop; // To prevent Defiant activating on a Court Change'd Sticky Web }; // rom_80A5C6C diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 96796ea2d..331794816 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -39,6 +39,7 @@ #define sABILITY_OVERWRITE gBattleScripting + 0x34 #define sSWITCH_CASE gBattleScripting + 0x36 #define sBERRY_OVERRIDE gBattleScripting + 0x37 +#define sSTICKY_WEB_STAT_DROP gBattleScripting + 0x38 #define cMULTISTRING_CHOOSER gBattleCommunication + 5 #define cMISS_TYPE gBattleCommunication + 6 diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index db3a030ae..672aa92a1 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -7536,30 +7536,30 @@ static bool32 IsRototillerAffected(u32 battlerId) return TRUE; } -#define COURTCHANGE_SWAP(status, structField, temp) \ -{ \ - temp = gSideStatuses[B_SIDE_PLAYER]; \ - if (gSideStatuses[B_SIDE_OPPONENT] & status) \ - gSideStatuses[B_SIDE_PLAYER] |= status; \ - else \ - gSideStatuses[B_SIDE_PLAYER] &= ~(status); \ - if (temp & status) \ - gSideStatuses[B_SIDE_OPPONENT] |= status; \ - else \ - gSideStatuses[B_SIDE_OPPONENT] &= ~(status); \ - SWAP(sideTimer0->structField, sideTimer1->structField, temp);\ -} \ +#define COURTCHANGE_SWAP(status, structField, temp) \ +{ \ + temp = gSideStatuses[B_SIDE_PLAYER]; \ + if (gSideStatuses[B_SIDE_OPPONENT] & status) \ + gSideStatuses[B_SIDE_PLAYER] |= status; \ + else \ + gSideStatuses[B_SIDE_PLAYER] &= ~(status); \ + if (temp & status) \ + gSideStatuses[B_SIDE_OPPONENT] |= status; \ + else \ + gSideStatuses[B_SIDE_OPPONENT] &= ~(status); \ + SWAP(sideTimerPlayer->structField, sideTimerOpp->structField, temp);\ +} \ #define UPDATE_COURTCHANGED_BATTLER(structField)\ { \ - sideTimer0->structField ^= BIT_SIDE; \ - sideTimer1->structField ^= BIT_SIDE; \ + sideTimerPlayer->structField ^= BIT_SIDE; \ + sideTimerOpp->structField ^= BIT_SIDE; \ } \ static bool32 CourtChangeSwapSideStatuses(void) { - struct SideTimer *sideTimer0 = &gSideTimers[B_SIDE_PLAYER]; - struct SideTimer *sideTimer1 = &gSideTimers[B_SIDE_OPPONENT]; + struct SideTimer *sideTimerPlayer = &gSideTimers[B_SIDE_PLAYER]; + struct SideTimer *sideTimerOpp = &gSideTimers[B_SIDE_OPPONENT]; u32 temp; // TODO: add Pledge-related effects @@ -7588,6 +7588,9 @@ static bool32 CourtChangeSwapSideStatuses(void) UPDATE_COURTCHANGED_BATTLER(auroraVeilBattlerId); UPDATE_COURTCHANGED_BATTLER(tailwindBattlerId); UPDATE_COURTCHANGED_BATTLER(luckyChantBattlerId); + + // Track which side originally set the Sticky Web + SWAP(sideTimerPlayer->stickyWebBattlerSide, sideTimerOpp->stickyWebBattlerSide, temp); } static void Cmd_various(void) @@ -11996,6 +11999,7 @@ static void Cmd_recoverbasedonsunlight(void) static void Cmd_setstickyweb(void) { u8 targetSide = GetBattlerSide(gBattlerTarget); + if (gSideStatuses[targetSide] & SIDE_STATUS_STICKY_WEB) { gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); @@ -12003,6 +12007,7 @@ static void Cmd_setstickyweb(void) else { gSideStatuses[targetSide] |= SIDE_STATUS_STICKY_WEB; + gSideTimers[targetSide].stickyWebBattlerSide = GetBattlerSide(gBattlerAttacker); // For Court Change/Defiant - set this to the user's side gSideTimers[targetSide].stickyWebAmount = 1; gBattleStruct->stickyWebUser = gBattlerAttacker; // For Mirror Armor gBattlescriptCurrInstr += 5; diff --git a/src/battle_util.c b/src/battle_util.c index 0ddff3483..7aba05fc1 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -1453,6 +1453,7 @@ bool8 WasUnableToUseMove(u8 battler) void PrepareStringBattle(u16 stringId, u8 battler) { + u32 targetSide = GetBattlerSide(gBattlerTarget); // Support for Contrary ability. // If a move attempted to raise stat - print "won't increase". // If a move attempted to lower stat - print "won't decrease". @@ -1471,8 +1472,10 @@ void PrepareStringBattle(u16 stringId, u8 battler) && ((GetBattlerAbility(gBattlerTarget) == ABILITY_DEFIANT && CompareStat(gBattlerTarget, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN)) || (GetBattlerAbility(gBattlerTarget) == ABILITY_COMPETITIVE && CompareStat(gBattlerTarget, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN))) && gSpecialStatuses[gBattlerTarget].changedStatsBattlerId != BATTLE_PARTNER(gBattlerTarget) - && gSpecialStatuses[gBattlerTarget].changedStatsBattlerId != gBattlerTarget) + // && gSpecialStatuses[gBattlerTarget].changedStatsBattlerId != gBattlerTarget) // Why was this here? Needs investigating + && !(gBattleScripting.stickyWebStatDrop == 1 && gSideTimers[targetSide].stickyWebBattlerSide == targetSide)) // Sticky Web must have been set by the foe { + gBattleScripting.stickyWebStatDrop = 0; gBattlerAbility = gBattlerTarget; BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_DefiantActivates; From fd4414fe627eb4efcb42362d18fe68872d27b478 Mon Sep 17 00:00:00 2001 From: BuffelSaft Date: Tue, 23 Nov 2021 23:01:43 +1300 Subject: [PATCH 029/130] Spaces instead of tabs --- data/battle_anim_scripts.s | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index bc3821563..be8dfb9a4 100644 --- a/data/battle_anim_scripts.s +++ b/data/battle_anim_scripts.s @@ -827,8 +827,8 @@ gBattleAnims_General:: .4byte General_GulpMissile @ B_ANIM_GULP_MISSILE .4byte General_StrongWinds @ B_ANIM_STRONG_WINDS .4byte General_PrimalReversion @ B_ANIM_PRIMAL_REVERSION - .4byte General_BeakBlastSetUp @ B_ANIM_BEAK_BLAST_SETUP - .4byte General_ShellTrapSetUp @ B_ANIM_SHELL_TRAP_SETUP + .4byte General_BeakBlastSetUp @ B_ANIM_BEAK_BLAST_SETUP + .4byte General_ShellTrapSetUp @ B_ANIM_SHELL_TRAP_SETUP .align 2 gBattleAnims_Special:: From cca7ec8c58d0becd96fb9ea6cd067d676ffafcd6 Mon Sep 17 00:00:00 2001 From: BuffelSaft Date: Wed, 24 Nov 2021 12:09:54 +1300 Subject: [PATCH 030/130] Fix and rename GetMoveTargetType Change name to GetBattlerMoveTargetType and make it actually use the battlerId argument. --- include/battle_util.h | 2 +- src/battle_ai_main.c | 18 +++++++++--------- src/battle_ai_util.c | 2 +- src/battle_anim.c | 2 +- src/battle_controller_opponent.c | 6 +++--- src/battle_controller_player.c | 4 ++-- src/battle_gfx_sfx_util.c | 4 ++-- src/battle_script_commands.c | 14 +++++++------- src/battle_util.c | 16 ++++++++-------- src/contest.c | 2 +- 10 files changed, 35 insertions(+), 35 deletions(-) diff --git a/include/battle_util.h b/include/battle_util.h index 47bc2cc56..35eea7da1 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -163,7 +163,7 @@ bool32 IsBattlerWeatherAffected(u8 battlerId, u32 weatherFlags); void TryToApplyMimicry(u8 battlerId, bool8 various); void TryToRevertMimicry(void); void RestoreBattlerOriginalTypes(u8 battlerId); -u32 GetMoveTargetType(u8 battlerId, u16 move); +u32 GetBattlerMoveTargetType(u8 battlerId, u16 move); // Ability checks bool32 IsRolePlayBannedAbilityAtk(u16 ability); bool32 IsRolePlayBannedAbility(u16 ability); diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 3b6716485..25265b973 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -484,7 +484,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) u8 atkPriority = GetMovePriority(battlerAtk, move); u16 moveEffect = gBattleMoves[move].effect; s32 moveType; - u16 moveTarget = GetMoveTargetType(battlerAtk, move); + u16 moveTarget = GetBattlerMoveTargetType(battlerAtk, move); u16 accuracy = AI_GetMoveAccuracy(battlerAtk, battlerDef, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect, move); u8 effectiveness = AI_GetMoveEffectiveness(move, battlerAtk, battlerDef); bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk); @@ -2299,7 +2299,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } else { - if (GetMoveTargetType(battlerDef, instructedMove) & (MOVE_TARGET_SELECTED + if (GetBattlerMoveTargetType(battlerDef, instructedMove) & (MOVE_TARGET_SELECTED | MOVE_TARGET_DEPENDS | MOVE_TARGET_RANDOM | MOVE_TARGET_BOTH @@ -2496,7 +2496,7 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // move data u8 moveType = gBattleMoves[move].type; u16 effect = gBattleMoves[move].effect; - u16 moveTarget = GetMoveTargetType(battlerAtk, move); + u16 moveTarget = GetBattlerMoveTargetType(battlerAtk, move); // ally data u8 battlerAtkPartner = AI_DATA->battlerAtkPartner; u16 atkPartnerAbility = AI_DATA->atkPartnerAbility; @@ -2803,7 +2803,7 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (instructedMove != MOVE_NONE && !IS_MOVE_STATUS(instructedMove) - && (GetMoveTargetType(battlerAtkPartner, instructedMove) & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY))) // Use instruct on multi-target moves + && (GetBattlerMoveTargetType(battlerAtkPartner, instructedMove) & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY))) // Use instruct on multi-target moves { RETURN_SCORE_PLUS(1); } @@ -3603,24 +3603,24 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); break; case MOVE_WIDE_GUARD: - if (predictedMove != MOVE_NONE && GetMoveTargetType(battlerDef, predictedMove) & (MOVE_TARGET_FOES_AND_ALLY | MOVE_TARGET_BOTH)) + if (predictedMove != MOVE_NONE && GetBattlerMoveTargetType(battlerDef, predictedMove) & (MOVE_TARGET_FOES_AND_ALLY | MOVE_TARGET_BOTH)) { ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); } - else if (isDoubleBattle && GetMoveTargetType(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove) & MOVE_TARGET_FOES_AND_ALLY) + else if (isDoubleBattle && GetBattlerMoveTargetType(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove) & MOVE_TARGET_FOES_AND_ALLY) { if (AI_DATA->atkAbility != ABILITY_TELEPATHY) ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); } break; case MOVE_CRAFTY_SHIELD: - if (predictedMove != MOVE_NONE && IS_MOVE_STATUS(predictedMove) && !(GetMoveTargetType(battlerDef, predictedMove) & MOVE_TARGET_USER)) + if (predictedMove != MOVE_NONE && IS_MOVE_STATUS(predictedMove) && !(GetBattlerMoveTargetType(battlerDef, predictedMove) & MOVE_TARGET_USER)) ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); break; case MOVE_MAT_BLOCK: if (gDisableStructs[battlerAtk].isFirstTurn && predictedMove != MOVE_NONE - && !IS_MOVE_STATUS(predictedMove) && !(GetMoveTargetType(battlerDef, predictedMove) & MOVE_TARGET_USER)) + && !IS_MOVE_STATUS(predictedMove) && !(GetBattlerMoveTargetType(battlerDef, predictedMove) & MOVE_TARGET_USER)) ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); break; case MOVE_KINGS_SHIELD: @@ -4065,7 +4065,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score += 10; break; case EFFECT_MAGIC_COAT: - if (IS_MOVE_STATUS(predictedMove) && GetMoveTargetType(battlerDef, predictedMove) & (MOVE_TARGET_SELECTED | MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_BOTH)) + if (IS_MOVE_STATUS(predictedMove) && GetBattlerMoveTargetType(battlerDef, predictedMove) & (MOVE_TARGET_SELECTED | MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_BOTH)) score += 3; break; case EFFECT_RECYCLE: diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 664078e55..7f30862d1 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -1921,7 +1921,7 @@ bool32 HasMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef, u8 accCheck, bool32 if (ignoreStatus && IS_MOVE_STATUS(moves[i])) continue; else if ((!IS_MOVE_STATUS(moves[i]) && gBattleMoves[moves[i]].accuracy == 0) - || GetMoveTargetType(battlerAtk, moves[i]) & (MOVE_TARGET_USER | MOVE_TARGET_OPPONENTS_FIELD)) + || GetBattlerMoveTargetType(battlerAtk, moves[i]) & (MOVE_TARGET_USER | MOVE_TARGET_OPPONENTS_FIELD)) continue; if (AI_GetMoveAccuracy(battlerAtk, battlerDef, atkAbility, defAbility, atkHoldEffect, defHoldEffect, moves[i]) <= accCheck) return TRUE; diff --git a/src/battle_anim.c b/src/battle_anim.c index d6761eae6..fba5cbcd8 100644 --- a/src/battle_anim.c +++ b/src/battle_anim.c @@ -2195,7 +2195,7 @@ void DoMoveAnim(u16 move) gBattleAnimAttacker = gBattlerAttacker; gBattleAnimTarget = gBattlerTarget; // Make sure the anim target of moves hitting everyone is at the opposite side. - if (GetMoveTargetType(gBattlerAttacker, move) & MOVE_TARGET_FOES_AND_ALLY && IsDoubleBattle()) + if (GetBattlerMoveTargetType(gBattlerAttacker, move) & MOVE_TARGET_FOES_AND_ALLY && IsDoubleBattle()) { while (GET_BATTLER_SIDE(gBattleAnimAttacker) == GET_BATTLER_SIDE(gBattleAnimTarget)) { diff --git a/src/battle_controller_opponent.c b/src/battle_controller_opponent.c index 4482c175d..448c9b480 100644 --- a/src/battle_controller_opponent.c +++ b/src/battle_controller_opponent.c @@ -1574,9 +1574,9 @@ static void OpponentHandleChooseAction(void) BtlController_EmitTwoReturnValues(1, B_ACTION_RUN, 0); break; default: - if (GetMoveTargetType(gActiveBattler, moveInfo.moves[chosenMoveId]) & (MOVE_TARGET_USER_OR_SELECTED | MOVE_TARGET_USER)) + if (GetBattlerMoveTargetType(gActiveBattler, moveInfo.moves[chosenMoveId]) & (MOVE_TARGET_USER_OR_SELECTED | MOVE_TARGET_USER)) gBattlerTarget = gActiveBattler; - if (GetMoveTargetType(gActiveBattler, moveInfo.moves[chosenMoveId]) & MOVE_TARGET_BOTH) + if (GetBattlerMoveTargetType(gActiveBattler, moveInfo.moves[chosenMoveId]) & MOVE_TARGET_BOTH) { gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); if (gAbsentBattlerFlags & gBitTable[gBattlerTarget]) @@ -1600,7 +1600,7 @@ static void OpponentHandleChooseAction(void) move = moveInfo.moves[chosenMoveId]; } while (move == MOVE_NONE); - if (GetMoveTargetType(gActiveBattler, move) & (MOVE_TARGET_USER_OR_SELECTED | MOVE_TARGET_USER)) + if (GetBattlerMoveTargetType(gActiveBattler, move) & (MOVE_TARGET_USER_OR_SELECTED | MOVE_TARGET_USER)) BtlController_EmitTwoReturnValues(1, B_ACTION_USE_MOVE, (chosenMoveId) | (gActiveBattler << 8)); else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) BtlController_EmitTwoReturnValues(1, B_ACTION_USE_MOVE, (chosenMoveId) | (GetBattlerAtPosition(Random() & 2) << 8)); diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index 05ad19170..caa3b0689 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -360,7 +360,7 @@ static void HandleInputChooseTarget(void) s32 i; static const u8 identities[MAX_BATTLERS_COUNT] = {B_POSITION_PLAYER_LEFT, B_POSITION_PLAYER_RIGHT, B_POSITION_OPPONENT_RIGHT, B_POSITION_OPPONENT_LEFT}; u16 move = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_MOVE1 + gMoveSelectionCursor[gActiveBattler]); - u16 moveTarget = GetMoveTargetType(gActiveBattler, move); + u16 moveTarget = GetBattlerMoveTargetType(gActiveBattler, move); DoBounceEffect(gMultiUsePlayerCursor, BOUNCE_HEALTHBOX, 15, 1); for (i = 0; i < gBattlersCount; i++) @@ -612,7 +612,7 @@ static void HandleInputChooseMove(void) } else { - moveTarget = GetMoveTargetType(gActiveBattler, moveInfo->moves[gMoveSelectionCursor[gActiveBattler]]); + moveTarget = GetBattlerMoveTargetType(gActiveBattler, moveInfo->moves[gMoveSelectionCursor[gActiveBattler]]); } if (moveTarget & MOVE_TARGET_USER) diff --git a/src/battle_gfx_sfx_util.c b/src/battle_gfx_sfx_util.c index 11e41ebd4..73adc442b 100644 --- a/src/battle_gfx_sfx_util.c +++ b/src/battle_gfx_sfx_util.c @@ -251,7 +251,7 @@ u16 ChooseMoveAndTargetInBattlePalace(void) } else { - moveTarget = GetMoveTargetType(gActiveBattler, moveInfo->moves[chosenMoveId]); + moveTarget = GetBattlerMoveTargetType(gActiveBattler, moveInfo->moves[chosenMoveId]); } if (moveTarget & MOVE_TARGET_USER) @@ -275,7 +275,7 @@ u16 ChooseMoveAndTargetInBattlePalace(void) static u8 GetBattlePalaceMoveGroup(u8 battlerId, u16 move) { - switch (GetMoveTargetType(battlerId, move)) + switch (GetBattlerMoveTargetType(battlerId, move)) { case MOVE_TARGET_SELECTED: case MOVE_TARGET_USER_OR_SELECTED: diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 672aa92a1..8b6b31738 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1318,7 +1318,7 @@ static bool32 NoTargetPresent(u8 battlerId, u32 move) if (!IsBattlerAlive(gBattlerTarget)) gBattlerTarget = GetMoveTarget(move, 0); - switch (GetMoveTargetType(battlerId, move)) + switch (GetBattlerMoveTargetType(battlerId, move)) { case MOVE_TARGET_SELECTED: case MOVE_TARGET_DEPENDS: @@ -1741,7 +1741,7 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move) static void Cmd_accuracycheck(void) { u16 type, move = T2_READ_16(gBattlescriptCurrInstr + 5); - u16 moveTarget = GetMoveTargetType(gBattlerAttacker, move); + u16 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, move); if (move == ACC_CURR_MOVE) move = gCurrentMove; @@ -1805,7 +1805,7 @@ static void Cmd_ppreduce(void) if (!gSpecialStatuses[gBattlerAttacker].ppNotAffectedByPressure) { - switch (GetMoveTargetType(gBattlerAttacker, gCurrentMove)) + switch (GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove)) { case MOVE_TARGET_FOES_AND_ALLY: for (i = 0; i < gBattlersCount; i++) @@ -2104,7 +2104,7 @@ static void Cmd_multihitresultmessage(void) static void Cmd_attackanimation(void) { - u16 moveTarget = GetMoveTargetType(gBattlerAttacker, gCurrentMove); + u16 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove); if (gBattleControllerExecFlags) return; @@ -5241,7 +5241,7 @@ static void Cmd_moveend(void) break; case MOVEEND_NEXT_TARGET: // For moves hitting two opposing Pokemon. { - u16 moveTarget = GetMoveTargetType(gBattlerAttacker, gCurrentMove); + u16 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove); // Set a flag if move hits either target (for throat spray that can't check damage) if (!(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)) @@ -9522,7 +9522,7 @@ static void Cmd_jumpifnexttargetvalid(void) for (gBattlerTarget++; gBattlerTarget < gBattlersCount; gBattlerTarget++) { - if (gBattlerTarget == gBattlerAttacker && !(GetMoveTargetType(gBattlerAttacker, gCurrentMove) & MOVE_TARGET_USER)) + if (gBattlerTarget == gBattlerAttacker && !(GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove) & MOVE_TARGET_USER)) continue; if (IsBattlerAlive(gBattlerTarget)) break; @@ -12018,7 +12018,7 @@ static void Cmd_selectfirstvalidtarget(void) { for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount; gBattlerTarget++) { - if (gBattlerTarget == gBattlerAttacker && !(GetMoveTargetType(gBattlerAttacker, gCurrentMove) & MOVE_TARGET_USER)) + if (gBattlerTarget == gBattlerAttacker && !(GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove) & MOVE_TARGET_USER)) continue; if (IsBattlerAlive(gBattlerTarget)) break; diff --git a/src/battle_util.c b/src/battle_util.c index 7aba05fc1..3cb6b6d86 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -237,7 +237,7 @@ bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move) void HandleAction_UseMove(void) { u32 i, side, moveType, var = 4; - u16 moveTarget = GetMoveTargetType(gBattlerAttacker, gCurrentMove); + u16 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove); gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; if (gBattleStruct->field_91 & gBitTable[gBattlerAttacker] || !IsBattlerAlive(gBattlerAttacker)) @@ -4674,7 +4674,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move break; case ABILITYEFFECT_MOVES_BLOCK: // 2 { - u16 moveTarget = GetMoveTargetType(battler, move); + u16 moveTarget = GetBattlerMoveTargetType(battler, move); if ((gLastUsedAbility == ABILITY_SOUNDPROOF && gBattleMoves[move].flags & FLAG_SOUND && !(moveTarget & MOVE_TARGET_USER)) || (gLastUsedAbility == ABILITY_BULLETPROOF && gBattleMoves[move].flags & FLAG_BALLISTIC)) @@ -7265,7 +7265,7 @@ u32 GetMoveTarget(u16 move, u8 setTarget) if (setTarget) moveTarget = setTarget - 1; else - moveTarget = GetMoveTargetType(gBattlerAttacker, move); + moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, move); // Special cases if (move == MOVE_CURSE && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GHOST)) @@ -7538,7 +7538,7 @@ bool32 IsBattlerProtected(u8 battlerId, u16 move) else if (gProtectStructs[battlerId].protected) return TRUE; else if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_WIDE_GUARD - && GetMoveTargetType(gBattlerAttacker, move) & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY)) + && GetBattlerMoveTargetType(gBattlerAttacker, move) & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY)) return TRUE; else if (gProtectStructs[battlerId].banefulBunkered) return TRUE; @@ -7664,7 +7664,7 @@ u32 CountBattlerStatIncreases(u8 battlerId, bool32 countEvasionAcc) u32 GetMoveTargetCount(u16 move, u8 battlerAtk, u8 battlerDef) { - switch (GetMoveTargetType(gBattlerAttacker, move)) + switch (GetBattlerMoveTargetType(gBattlerAttacker, move)) { case MOVE_TARGET_BOTH: return IsBattlerAlive(battlerDef) @@ -9828,7 +9828,7 @@ bool32 BlocksPrankster(u16 move, u8 battlerPrankster, u8 battlerDef, bool32 chec return FALSE; if (GetBattlerSide(battlerPrankster) == GetBattlerSide(battlerDef)) return FALSE; - if (checkTarget && (GetMoveTargetType(battlerPrankster, move) & (MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_DEPENDS))) + if (checkTarget && (GetBattlerMoveTargetType(battlerPrankster, move) & (MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_DEPENDS))) return FALSE; if (!IS_BATTLER_OF_TYPE(battlerDef, TYPE_DARK)) return FALSE; @@ -9863,12 +9863,12 @@ bool32 IsBattlerWeatherAffected(u8 battlerId, u32 weatherFlags) // Gets move target before redirection effects etc. are applied // Possible return values are defined in battle.h following MOVE_TARGET_SELECTED -u32 GetMoveTargetType(u8 battlerId, u16 move) +u32 GetBattlerMoveTargetType(u8 battlerId, u16 move) { u32 target; if (gBattleMoves[move].effect == EFFECT_EXPANDING_FORCE - && IsBattlerTerrainAffected(gActiveBattler, STATUS_FIELD_PSYCHIC_TERRAIN)) + && IsBattlerTerrainAffected(battlerId, STATUS_FIELD_PSYCHIC_TERRAIN)) return MOVE_TARGET_BOTH; else return gBattleMoves[move].target; diff --git a/src/contest.c b/src/contest.c index c876f02cc..f8e6be3ef 100644 --- a/src/contest.c +++ b/src/contest.c @@ -5388,7 +5388,7 @@ static void SetBattleTargetSpritePosition(void) static void SetMoveTargetPosition(u16 move) { - switch (GetMoveTargetType(gBattlerAttacker, move)) + switch (GetBattlerMoveTargetType(gBattlerAttacker, move)) { case MOVE_TARGET_USER_OR_SELECTED: case MOVE_TARGET_USER: From 19af517bbb4c8887e036bdf1e9ef7bf2355d9f04 Mon Sep 17 00:00:00 2001 From: LOuroboros Date: Tue, 30 Nov 2021 20:45:21 -0300 Subject: [PATCH 031/130] Edited pointless or useless Primal Reversion code Also added an equivalent to GetMegaEvolutionSpecies and GetWishMegaEvolutionSpecies for Primal Reversion. Also also modified how CanBattlerGetOrLoseItem checks for Primal Reversion. Also also also rewrote the check that triggers Primal Reversion in TryDoEventsBeforeFirstTurn. --- include/battle.h | 1 - include/battle_util.h | 1 + src/battle_main.c | 18 +++++++++++++----- src/battle_script_commands.c | 2 +- src/battle_util.c | 29 ++++++++++++++++------------- 5 files changed, 31 insertions(+), 20 deletions(-) diff --git a/include/battle.h b/include/battle.h index 5658f603c..930578a50 100644 --- a/include/battle.h +++ b/include/battle.h @@ -475,7 +475,6 @@ struct MegaEvolutionData bool8 playerSelect; u8 triggerSpriteId; bool8 isWishMegaEvo; - bool8 isPrimalReversion; }; struct Illusion diff --git a/include/battle_util.h b/include/battle_util.h index b1a2a1534..ba4f20336 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -127,6 +127,7 @@ u16 CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, u16 abilit u16 GetTypeModifier(u8 atkType, u8 defType); s32 GetStealthHazardDamage(u8 hazardType, u8 battlerId); u16 GetMegaEvolutionSpecies(u16 preEvoSpecies, u16 heldItemId); +u16 GetPrimalReversionSpecies(u16 preEvoSpecies, u16 heldItemId); u16 GetWishMegaEvolutionSpecies(u16 preEvoSpecies, u16 moveId1, u16 moveId2, u16 moveId3, u16 moveId4); bool32 CanMegaEvolve(u8 battlerId); void UndoMegaEvolution(u32 monId); diff --git a/src/battle_main.c b/src/battle_main.c index 766736048..028237aa4 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -64,6 +64,8 @@ #include "constants/trainers.h" #include "cable_club.h" +extern struct Evolution gEvolutionTable[][EVOS_PER_MON]; + extern struct MusicPlayerInfo gMPlayInfo_SE1; extern struct MusicPlayerInfo gMPlayInfo_SE2; @@ -3541,12 +3543,18 @@ static void TryDoEventsBeforeFirstTurn(void) // Primal Reversion for (i = 0; i < gBattlersCount; i++) { - if (CanMegaEvolve(i) - && GetBattlerHoldEffect(i, TRUE) == HOLD_EFFECT_PRIMAL_ORB) + if (GetBattlerHoldEffect(i, TRUE) == HOLD_EFFECT_PRIMAL_ORB) { - gBattlerAttacker = i; - BattleScriptExecute(BattleScript_PrimalReversion); - return; + for (j = 0; j < EVOS_PER_MON; j++) + { + if (gEvolutionTable[gBattleMons[i].species][j].targetSpecies != SPECIES_NONE + && gEvolutionTable[gBattleMons[i].species][j].method == EVO_PRIMAL_REVERSION) + { + gBattlerAttacker = i; + BattleScriptExecute(BattleScript_PrimalReversion); + return; + } + } } } diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 8c328926d..640e75ed8 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -8331,7 +8331,7 @@ static void Cmd_various(void) gBattleStruct->mega.playerPrimalRevertedSpecies = gBattleStruct->mega.primalRevertedSpecies[gActiveBattler]; } // Checks Primal Reversion - primalSpecies = GetMegaEvolutionSpecies(gBattleStruct->mega.primalRevertedSpecies[gActiveBattler], gBattleMons[gActiveBattler].item); + primalSpecies = GetPrimalReversionSpecies(gBattleStruct->mega.primalRevertedSpecies[gActiveBattler], gBattleMons[gActiveBattler].item); gBattleMons[gActiveBattler].species = primalSpecies; PREPARE_SPECIES_BUFFER(gBattleTextBuff1, gBattleMons[gActiveBattler].species); diff --git a/src/battle_util.c b/src/battle_util.c index 725814a0d..3b95bb84c 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -9081,8 +9081,20 @@ u16 GetMegaEvolutionSpecies(u16 preEvoSpecies, u16 heldItemId) for (i = 0; i < EVOS_PER_MON; i++) { - if ((gEvolutionTable[preEvoSpecies][i].method == EVO_MEGA_EVOLUTION - || gEvolutionTable[preEvoSpecies][i].method == EVO_PRIMAL_REVERSION) + if (gEvolutionTable[preEvoSpecies][i].method == EVO_MEGA_EVOLUTION + && gEvolutionTable[preEvoSpecies][i].param == heldItemId) + return gEvolutionTable[preEvoSpecies][i].targetSpecies; + } + return SPECIES_NONE; +} + +u16 GetPrimalReversionSpecies(u16 preEvoSpecies, u16 heldItemId) +{ + u32 i; + + for (i = 0; i < EVOS_PER_MON; i++) + { + if (gEvolutionTable[preEvoSpecies][i].method == EVO_PRIMAL_REVERSION && gEvolutionTable[preEvoSpecies][i].param == heldItemId) return gEvolutionTable[preEvoSpecies][i].targetSpecies; } @@ -9153,14 +9165,6 @@ bool32 CanMegaEvolve(u8 battlerId) gBattleStruct->mega.isWishMegaEvo = FALSE; return TRUE; } - - // Can undergo Primal Reversion. - if (holdEffect == HOLD_EFFECT_PRIMAL_ORB) - { - gBattleStruct->mega.isWishMegaEvo = FALSE; - gBattleStruct->mega.isPrimalReversion = TRUE; - return TRUE; - } } // Check if there is an entry in the evolution table for Wish Mega Evolution. @@ -9264,9 +9268,8 @@ bool32 CanBattlerGetOrLoseItem(u8 battlerId, u16 itemId) // Mail can be stolen now if (itemId == ITEM_ENIGMA_BERRY) return FALSE; - else if (GET_BASE_SPECIES_ID(species) == SPECIES_KYOGRE && itemId == ITEM_BLUE_ORB) // includes primal - return FALSE; - else if (GET_BASE_SPECIES_ID(species) == SPECIES_GROUDON && itemId == ITEM_RED_ORB) // includes primal + // Primal Reversion inducing items cannot be lost if pokemon's base species can undergo primal reversion with it. + else if (holdEffect == HOLD_EFFECT_PRIMAL_ORB && (GetPrimalReversionSpecies(GET_BASE_SPECIES_ID(species), itemId) != SPECIES_NONE)) return FALSE; // Mega stone cannot be lost if pokemon's base species can mega evolve with it. else if (holdEffect == HOLD_EFFECT_MEGA_STONE && (GetMegaEvolutionSpecies(GET_BASE_SPECIES_ID(species), itemId) != SPECIES_NONE)) From bbf7b62ceb5d4a45b489719a074bf2218b3950fd Mon Sep 17 00:00:00 2001 From: Eduardo Quezada D'Ottone Date: Sat, 11 Dec 2021 23:03:50 -0300 Subject: [PATCH 032/130] Config for lost money after losing a battle --- data/battle_scripts_1.s | 18 ++++++++++++ include/constants/battle_config.h | 1 + include/constants/battle_string_ids.h | 4 ++- src/battle_message.c | 8 +++++ src/battle_script_commands.c | 42 +++++++++++++++++++++++---- src/overworld.c | 2 ++ 6 files changed, 69 insertions(+), 6 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 24a3d16ed..a0e5577aa 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -5936,12 +5936,30 @@ BattleScript_LocalBattleLost:: jumpifbattletype BATTLE_TYPE_EREADER_TRAINER, BattleScript_LocalBattleLostEnd jumpifhalfword CMP_EQUAL, gTrainerBattleOpponent_A, TRAINER_SECRET_BASE, BattleScript_LocalBattleLostEnd BattleScript_LocalBattleLostPrintWhiteOut:: +.if B_WHITEOUT_MONEY >= GEN_4 + jumpifbattletype BATTLE_TYPE_TRAINER, BattleScript_LocalBattleLostEnd + printstring STRINGID_PLAYERWHITEOUT + waitmessage B_WAIT_TIME_LONG + getmoneyreward + printstring STRINGID_PLAYERWHITEOUT2 + waitmessage B_WAIT_TIME_LONG + end2 +BattleScript_LocalBattleLostEnd:: + printstring STRINGID_PLAYERLOSTTOENEMYTRAINER + waitmessage B_WAIT_TIME_LONG + getmoneyreward + printstring STRINGID_PLAYERPAIDPRIZEMONEY + waitmessage B_WAIT_TIME_LONG + end2 +.else printstring STRINGID_PLAYERWHITEOUT waitmessage B_WAIT_TIME_LONG printstring STRINGID_PLAYERWHITEOUT2 waitmessage B_WAIT_TIME_LONG BattleScript_LocalBattleLostEnd:: end2 +.endif + BattleScript_CheckDomeDrew:: jumpifbyte CMP_EQUAL, gBattleOutcome, B_OUTCOME_DREW, BattleScript_LocalBattleLostEnd_ BattleScript_LocalBattleLostPrintTrainersWinText:: diff --git a/include/constants/battle_config.h b/include/constants/battle_config.h index 8f8d30b56..05357b3bc 100644 --- a/include/constants/battle_config.h +++ b/include/constants/battle_config.h @@ -101,6 +101,7 @@ #define B_PARALYSIS_SPEED GEN_7 // In Gen7+, Speed is decreased by 50% instead of 75%. #define B_CONFUSION_SELF_DMG_CHANCE GEN_7 // In Gen7+, confusion has a 33.3% of self-damage, instead of 50%. #define B_MULTI_HIT_CHANCE GEN_7 // In Gen5+, multi-hit moves have different %. See Cmd_setmultihitcounter for values. +#define B_WHITEOUT_MONEY GEN_7 // In Gen4+, the amount of money lost by losing a battle is determined by the amount of badges earned. Previously, it would cut the current money by half. (While this change was also in FRLG, for the sake of simplicity, setting this to GEN_3 will result in RSE behavior.) // Exp and stat settings #define B_EXP_CATCH GEN_7 // In Gen6+, Pokémon get experience from catching. diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index 7846fa521..48352bf34 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -609,8 +609,10 @@ #define STRINGID_CANTESCAPEBECAUSEOFCURRENTMOVE 606 #define STRINGID_NEUTRALIZINGGASENTERS 607 #define STRINGID_NEUTRALIZINGGASOVER 608 +#define STRINGID_PLAYERLOSTTOENEMYTRAINER 609 +#define STRINGID_PLAYERPAIDPRIZEMONEY 610 -#define BATTLESTRINGS_COUNT 609 +#define BATTLESTRINGS_COUNT 611 // The below IDs are all indexes into battle message tables, // used to determine which of a set of messages to print. diff --git a/src/battle_message.c b/src/battle_message.c index 2f9fccaaf..ec9b66451 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -76,8 +76,14 @@ static const u8 sText_ItDoesntAffect[] = _("It doesn't affect\n{B_DEF_NAME_WITH_ static const u8 sText_AttackerFainted[] = _("{B_ATK_NAME_WITH_PREFIX}\nfainted!\p"); static const u8 sText_TargetFainted[] = _("{B_DEF_NAME_WITH_PREFIX}\nfainted!\p"); static const u8 sText_PlayerGotMoney[] = _("{B_PLAYER_NAME} got Â¥{B_BUFF1}\nfor winning!\p"); +static const u8 sText_PlayerLostToEnemyTrainer[] = _("{B_PLAYER_NAME} is out of\nusable POKéMON!\pPlayer lost against\n{B_TRAINER1_CLASS} {B_TRAINER1_NAME}!{PAUSE_UNTIL_PRESS}"); +static const u8 sText_PlayerPaidPrizeMoney[] = _("{B_PLAYER_NAME} paid Â¥{B_BUFF1} as the prize\nmoney…\p… … … …\p{B_PLAYER_NAME} whited out!{PAUSE_UNTIL_PRESS}"); static const u8 sText_PlayerWhiteout[] = _("{B_PLAYER_NAME} is out of\nusable POKéMON!\p"); +#if B_WHITEOUT_MONEY >= GEN_4 +static const u8 sText_PlayerWhiteout2[] = _("{B_PLAYER_NAME} panicked and lost Â¥{B_BUFF1}…\p… … … …\p{B_PLAYER_NAME} whited out!{PAUSE_UNTIL_PRESS}"); +#else static const u8 sText_PlayerWhiteout2[] = _("{B_PLAYER_NAME} whited out!{PAUSE_UNTIL_PRESS}"); +#endif static const u8 sText_PreventsEscape[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} prevents\nescape with {B_SCR_ACTIVE_ABILITY}!\p"); static const u8 sText_CantEscape2[] = _("Can't escape!\p"); static const u8 sText_AttackerCantEscape[] = _("{B_ATK_NAME_WITH_PREFIX} can't escape!"); @@ -827,6 +833,8 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = [STRINGID_ATTACKERFAINTED - 12] = sText_AttackerFainted, [STRINGID_TARGETFAINTED - 12] = sText_TargetFainted, [STRINGID_PLAYERGOTMONEY - 12] = sText_PlayerGotMoney, + [STRINGID_PLAYERLOSTTOENEMYTRAINER - 12] = sText_PlayerLostToEnemyTrainer, + [STRINGID_PLAYERPAIDPRIZEMONEY - 12] = sText_PlayerPaidPrizeMoney, [STRINGID_PLAYERWHITEOUT - 12] = sText_PlayerWhiteout, [STRINGID_PLAYERWHITEOUT2 - 12] = sText_PlayerWhiteout2, [STRINGID_PREVENTSESCAPE - 12] = sText_PreventsEscape, diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index b46331be1..d888cdfe1 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -284,6 +284,13 @@ static const u16 sTrappingMoves[] = MOVE_BIND, MOVE_WRAP, MOVE_FIRE_SPIN, MOVE_CLAMP, MOVE_WHIRLPOOL, MOVE_SAND_TOMB, MOVE_MAGMA_STORM, MOVE_INFESTATION, 0xFFFF }; +static const u16 sBadgeFlags[8] = { + FLAG_BADGE01_GET, FLAG_BADGE02_GET, FLAG_BADGE03_GET, FLAG_BADGE04_GET, + FLAG_BADGE05_GET, FLAG_BADGE06_GET, FLAG_BADGE07_GET, FLAG_BADGE08_GET, +}; + +static const u16 sWhiteOutBadgeMoney[9] = { 8, 16, 24, 36, 48, 64, 80, 100, 120 }; + #define STAT_CHANGE_WORKED 0 #define STAT_CHANGE_DIDNT_WORK 1 @@ -6648,13 +6655,38 @@ static u32 GetTrainerMoneyToGive(u16 trainerId) static void Cmd_getmoneyreward(void) { - u32 moneyReward = GetTrainerMoneyToGive(gTrainerBattleOpponent_A); - if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) - moneyReward += GetTrainerMoneyToGive(gTrainerBattleOpponent_B); + u32 money; + u8 sPartyLevel = 1; - AddMoney(&gSaveBlock1Ptr->money, moneyReward); - PREPARE_WORD_NUMBER_BUFFER(gBattleTextBuff1, 5, moneyReward); + if (gBattleOutcome == B_OUTCOME_WON) + { + money = GetTrainerMoneyToGive(gTrainerBattleOpponent_A); + if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + money += GetTrainerMoneyToGive(gTrainerBattleOpponent_B); + AddMoney(&gSaveBlock1Ptr->money, money); + } + else + { + s32 i, count; + for (i = 0; i < PARTY_SIZE; i++) + { + if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) != SPECIES_NONE + && GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) != SPECIES_EGG) + { + if (GetMonData(&gPlayerParty[i], MON_DATA_LEVEL) > sPartyLevel) + sPartyLevel = GetMonData(&gPlayerParty[i], MON_DATA_LEVEL); + } + } + for (count = 0, i = 0; i < ARRAY_COUNT(sBadgeFlags); i++) + { + if (FlagGet(sBadgeFlags[i]) == TRUE) + ++count; + } + money = sWhiteOutBadgeMoney[count] * sPartyLevel; + RemoveMoney(&gSaveBlock1Ptr->money, money); + } + PREPARE_WORD_NUMBER_BUFFER(gBattleTextBuff1, 5, money); gBattlescriptCurrInstr++; } diff --git a/src/overworld.c b/src/overworld.c index ee4c660bd..114674886 100644 --- a/src/overworld.c +++ b/src/overworld.c @@ -361,7 +361,9 @@ static void (*const gMovementStatusHandler[])(struct LinkPlayerObjectEvent *, st void DoWhiteOut(void) { ScriptContext2_RunNewScript(EventScript_WhiteOut); + #if B_WHITEOUT_MONEY == GEN_3 SetMoney(&gSaveBlock1Ptr->money, GetMoney(&gSaveBlock1Ptr->money) / 2); + #endif HealPlayerParty(); Overworld_ResetStateAfterWhiteOut(); SetWarpDestinationToLastHealLocation(); From 035b2332af37c2357534b8d9c35aa492ddbc4203 Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Thu, 13 Jan 2022 11:28:27 -0500 Subject: [PATCH 033/130] cache ai damage, effectiveness calcs --- include/battle.h | 36 +- include/battle_ai_main.h | 1 + include/battle_ai_util.h | 8 +- include/battle_script_commands.h | 2 +- include/battle_util.h | 1 + src/battle_ai_main.c | 1061 +++++++++++++++--------------- src/battle_ai_util.c | 290 ++++---- src/battle_debug.c | 7 +- src/battle_main.c | 3 + src/battle_script_commands.c | 17 +- src/battle_util.c | 21 +- src/battle_util2.c | 2 + 12 files changed, 690 insertions(+), 759 deletions(-) diff --git a/include/battle.h b/include/battle.h index feb22eaa5..e1981f0a6 100644 --- a/include/battle.h +++ b/include/battle.h @@ -243,33 +243,20 @@ struct AI_SavedBattleMon struct AiLogicData { - //attacker data - u16 atkAbility; - u16 atkItem; - u16 atkHoldEffect; - u8 atkParam; - u16 atkSpecies; - // target data - u16 defAbility; - u16 defItem; - u16 defHoldEffect; - u8 defParam; - u16 defSpecies; - // attacker partner data - u8 battlerAtkPartner; + u16 abilities[MAX_BATTLERS_COUNT]; + u16 items[MAX_BATTLERS_COUNT]; + u16 holdEffects[MAX_BATTLERS_COUNT]; + u8 holdEffectParams[MAX_BATTLERS_COUNT]; + u16 predictedMoves[MAX_BATTLERS_COUNT]; + u8 hpPercents[MAX_BATTLERS_COUNT]; u16 partnerMove; - u16 atkPartnerAbility; - u16 atkPartnerHoldEffect; - bool32 targetSameSide; - // target partner data - u8 battlerDefPartner; - u16 defPartnerAbility; - u16 defPartnerHoldEffect; + s32 simulatedDmg[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // attacker, target, moveIndex + u8 effectiveness[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // attacker, target, moveIndex + u8 moveLimitations[MAX_BATTLERS_COUNT]; }; struct AI_ThinkingStruct { - struct AiLogicData data; u8 aiState; u8 movesetIndex; u16 moveConsidered; @@ -278,7 +265,6 @@ struct AI_ThinkingStruct u32 aiFlags; u8 aiAction; u8 aiLogicId; - s32 simulatedDmg[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // attacker, target, move struct AI_SavedBattleMon saved[4]; bool8 switchMon; // Because all available moves have no/little effect. }; @@ -321,13 +307,14 @@ struct BattleResources struct BattleCallbacksStack* battleCallbackStack; struct StatsArray* beforeLvlUp; struct AI_ThinkingStruct *ai; + struct AiLogicData *aiData; struct BattleHistory *battleHistory; u8 bufferA[MAX_BATTLERS_COUNT][0x200]; u8 bufferB[MAX_BATTLERS_COUNT][0x200]; }; #define AI_THINKING_STRUCT ((struct AI_ThinkingStruct *)(gBattleResources->ai)) -#define AI_DATA ((struct AiLogicData *)(&gBattleResources->ai->data)) +#define AI_DATA ((struct AiLogicData *)(gBattleResources->aiData)) #define BATTLE_HISTORY ((struct BattleHistory *)(gBattleResources->battleHistory)) struct BattleResults @@ -593,7 +580,6 @@ struct BattleStruct bool8 spriteIgnore0Hp; struct Illusion illusion[MAX_BATTLERS_COUNT]; s8 aiFinalScore[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // AI, target, moves to make debugging easier - s32 aiSimulatedDamage[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // attacker, target, move to make debugging easier u8 soulheartBattlerId; u8 friskedBattler; // Frisk needs to identify 2 battlers in double battles. bool8 friskedAbility; // If identifies two mons, show the ability pop-up only once. diff --git a/include/battle_ai_main.h b/include/battle_ai_main.h index 66c614f78..185281749 100644 --- a/include/battle_ai_main.h +++ b/include/battle_ai_main.h @@ -24,6 +24,7 @@ void BattleAI_SetupItems(void); void BattleAI_SetupFlags(void); void BattleAI_SetupAIData(u8 defaultScoreMoves); u8 BattleAI_ChooseMoveOrAction(void); +void GetAiLogicData(void); extern u8 sBattler_AI; diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 5ccf68c58..42374c1af 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -33,7 +33,7 @@ bool32 CanMoveFaintBattler(u16 move, u8 battlerDef, u8 battlerAtk, u8 nHits); bool32 CanTargetFaintAiWithMod(u8 battlerDef, u8 battlerAtk, s32 hpMod, s32 dmgMod); s32 AI_GetAbility(u32 battlerId); u16 AI_GetHoldEffect(u32 battlerId); -u32 AI_GetMoveAccuracy(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u8 atkHoldEffect, u8 defHoldEffect, u16 move); +u32 AI_GetMoveAccuracy(u8 battlerAtk, u8 battlerDef, u16 move); bool32 DoesBattlerIgnoreAbilityChecks(u16 atkAbility, u16 move); bool32 AI_WeatherHasEffect(void); bool32 CanAIFaintTarget(u8 battlerAtk, u8 battlerDef, u8 numHits); @@ -45,7 +45,7 @@ bool32 HasDamagingMoveOfType(u8 battlerId, u8 type); u32 GetBattlerSecondaryDamage(u8 battlerId); bool32 BattlerWillFaintFromWeather(u8 battler, u16 ability); bool32 BattlerWillFaintFromSecondaryDamage(u8 battler, u16 ability); -bool32 ShouldTryOHKO(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u32 accuracy, u16 move); +bool32 ShouldTryOHKO(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u16 move); bool32 ShouldUseRecoilMove(u8 battlerAtk, u8 battlerDef, u32 recoilDmg, u8 moveIndex); u16 GetBattlerSideSpeedAverage(u8 battler); bool32 ShouldAbsorb(u8 battlerAtk, u8 battlerDef, u16 move, s32 damage); @@ -80,7 +80,7 @@ bool32 ShouldLowerEvasion(u8 battlerAtk, u8 battlerDef, u16 defAbility); // move checks bool32 IsAffectedByPowder(u8 battler, u16 ability, u16 holdEffect); bool32 MovesWithSplitUnusable(u32 attacker, u32 target, u32 split); -s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef); +s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef, u8 *effectiveness); u8 GetMoveDamageResult(u16 move); u32 GetCurrDamageHpPercent(u8 battlerAtk, u8 battlerDef); u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef); @@ -143,7 +143,7 @@ bool32 ShouldTrap(u8 battlerAtk, u8 battlerDef, u16 move); bool32 IsWakeupTurn(u8 battler); // partner logic -u16 GetAllyChosenMove(void); +u16 GetAllyChosenMove(u8 battlerId); bool32 IsValidDoubleBattle(u8 battlerAtk); bool32 IsTargetingPartner(u8 battlerAtk, u8 battlerDef); bool32 DoesPartnerHaveSameMoveEffect(u8 battlerAtkPartner, u8 battlerDef, u16 move, u16 partnerMove); diff --git a/include/battle_script_commands.h b/include/battle_script_commands.h index dfa81e767..f5215fdc8 100644 --- a/include/battle_script_commands.h +++ b/include/battle_script_commands.h @@ -16,7 +16,7 @@ struct StatFractions s32 CalcCritChanceStage(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recordAbility); s8 GetInverseCritChance(u8 battlerAtk, u8 battlerDef, u32 move); -u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move); +u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect); u8 GetBattlerTurnOrderNum(u8 battlerId); bool32 NoAliveMonsForEitherParty(void); void SetMoveEffect(bool32 primary, u32 certain); diff --git a/include/battle_util.h b/include/battle_util.h index 1c5216c73..53d899c9d 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -129,6 +129,7 @@ bool32 IsBattlerAlive(u8 battlerId); u8 GetBattleMonMoveSlot(struct BattlePokemon *battleMon, u16 move); u32 GetBattlerWeight(u8 battlerId); s32 CalculateMoveDamage(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, s32 fixedBasePower, bool32 isCrit, bool32 randomFactor, bool32 updateFlags); +s32 CalculateMoveDamageAndEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, u16 *typeEffectivenessModifier); u16 CalcTypeEffectivenessMultiplier(u16 move, u8 moveType, u8 battlerAtk, u8 battlerDef, bool32 recordAbilities); u16 CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, u16 abilityDef); u16 GetTypeModifier(u8 atkType, u8 defType); diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index d5815ad70..7ee638ddb 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -194,7 +194,7 @@ void BattleAI_SetupAIData(u8 defaultScoreMoves) defaultScoreMoves >>= 1; } - moveLimitations = CheckMoveLimitations(gActiveBattler, 0, MOVE_LIMITATIONS_ALL); + moveLimitations = AI_DATA->moveLimitations[gActiveBattler]; // Ignore moves that aren't possible to use. for (i = 0; i < MAX_MON_MOVES; i++) @@ -204,26 +204,6 @@ void BattleAI_SetupAIData(u8 defaultScoreMoves) } sBattler_AI = gActiveBattler; - // Simulate dmg for all AI moves against all other targets - for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount; gBattlerTarget++) - { - if (sBattler_AI == gBattlerTarget) - continue; - for (i = 0; i < MAX_MON_MOVES; i++) - { - dmg = 0; - move = gBattleMons[sBattler_AI].moves[i]; - if (gBattleMoves[move].power != 0 && !(moveLimitations & gBitTable[i])) - { - dmg = AI_CalcDamage(move, sBattler_AI, gBattlerTarget); - if (dmg == 0) - dmg = 1; - } - - AI_THINKING_STRUCT->simulatedDmg[sBattler_AI][gBattlerTarget][i] = dmg; - } - } - gBattlerTarget = SetRandomTarget(sBattler_AI); } @@ -245,29 +225,56 @@ u8 BattleAI_ChooseMoveOrAction(void) return ret; } -static void GetAiLogicData(u8 battlerAtk, u8 battlerDef) +void GetAiLogicData(void) { - // attacker data - AI_DATA->atkAbility = AI_GetAbility(battlerAtk); - AI_DATA->atkItem = gBattleMons[battlerAtk].item; - AI_DATA->atkHoldEffect = AI_GetHoldEffect(battlerAtk); - AI_DATA->atkParam = GetBattlerHoldEffectParam(battlerAtk); - AI_DATA->atkSpecies = gBattleMons[battlerAtk].species; - // target data - AI_DATA->defAbility = AI_GetAbility(battlerDef); - AI_DATA->defItem = (AI_GetHoldEffect(battlerDef) == HOLD_EFFECT_NONE) ? ITEM_NONE : gBattleMons[battlerDef].item; - AI_DATA->defHoldEffect = AI_GetHoldEffect(battlerDef); - AI_DATA->defParam = GetBattlerHoldEffectParam(battlerDef); - AI_DATA->defSpecies = gBattleMons[battlerDef].species; - // attacker partner data - AI_DATA->battlerAtkPartner = BATTLE_PARTNER(battlerAtk); - AI_DATA->partnerMove = GetAllyChosenMove(); - AI_DATA->atkPartnerAbility = AI_GetAbility(AI_DATA->battlerAtkPartner); - AI_DATA->atkPartnerHoldEffect = AI_GetHoldEffect(AI_DATA->battlerAtkPartner); - // target partner data - AI_DATA->battlerDefPartner = BATTLE_PARTNER(battlerDef); - AI_DATA->defPartnerAbility = AI_GetAbility(AI_DATA->battlerDefPartner); - AI_DATA->defPartnerHoldEffect = AI_GetHoldEffect(AI_DATA->battlerDefPartner); + u32 battlerAtk, battlerDef, i, move; + u8 effectiveness; + s32 dmg; + + if (!(gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FIRST_BATTLE | BATTLE_TYPE_SAFARI | BATTLE_TYPE_ROAMER) + && !IsWildMonSmart())) + return; + + memset(AI_DATA, 0, sizeof(struct AiLogicData)); + for (battlerAtk = 0; battlerAtk < MAX_BATTLERS_COUNT; battlerAtk++) + { + if (IsBattlerAlive(battlerAtk)) { + AI_DATA->abilities[battlerAtk] = AI_GetAbility(battlerAtk); + AI_DATA->items[battlerAtk] = gBattleMons[battlerAtk].item; + AI_DATA->holdEffects[battlerAtk] = AI_GetHoldEffect(battlerAtk); + AI_DATA->holdEffectParams[battlerAtk] = GetBattlerHoldEffectParam(battlerAtk); + AI_DATA->predictedMoves[battlerAtk] = gLastMoves[battlerAtk]; + AI_DATA->hpPercents[battlerAtk] = GetHealthPercentage(battlerAtk); + AI_DATA->moveLimitations[battlerAtk] = CheckMoveLimitations(battlerAtk, 0, MOVE_LIMITATIONS_ALL); + + // Simulate dmg for all AI moves against all other targets + for (battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) + { + if (battlerAtk == battlerDef) + continue; + + RecordKnownMove(battlerDef, gLastMoves[battlerDef]); + for (i = 0; i < MAX_MON_MOVES; i++) + { + dmg = 0; + effectiveness = AI_EFFECTIVENESS_x0; + move = gBattleMons[battlerAtk].moves[i]; + if (move != 0 + && move != 0xFFFF + && gBattleMoves[move].power != 0 + && !(AI_DATA->moveLimitations[battlerAtk] & gBitTable[i])) + { + dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness); + if (dmg == 0) + dmg = 1; + } + + AI_DATA->simulatedDmg[battlerAtk][battlerDef][i] = dmg; + AI_DATA->effectiveness[battlerAtk][battlerDef][i] = effectiveness; + } + } + } + } } static u8 ChooseMoveOrAction_Singles(void) @@ -278,9 +285,7 @@ static u8 ChooseMoveOrAction_Singles(void) s32 i, id; u32 flags = AI_THINKING_STRUCT->aiFlags; - RecordLastUsedMoveByTarget(); - GetAiLogicData(sBattler_AI, gBattlerTarget); - + AI_DATA->partnerMove = 0; // no ally while (flags != 0) { if (flags & 1) @@ -295,7 +300,6 @@ static u8 ChooseMoveOrAction_Singles(void) for (i = 0; i < MAX_MON_MOVES; i++) { gBattleStruct->aiFinalScore[sBattler_AI][gBattlerTarget][i] = AI_THINKING_STRUCT->score[i]; - gBattleStruct->aiSimulatedDamage[sBattler_AI][gBattlerTarget][i] = AI_THINKING_STRUCT->simulatedDmg[sBattler_AI][gBattlerTarget][i]; } // Check special AI actions. @@ -400,11 +404,10 @@ static u8 ChooseMoveOrAction_Doubles(void) BattleAI_SetupAIData(0xF); gBattlerTarget = i; - GetAiLogicData(sBattler_AI, gBattlerTarget); - if ((i & BIT_SIDE) != (sBattler_AI & BIT_SIDE)) RecordLastUsedMoveByTarget(); + AI_DATA->partnerMove = GetAllyChosenMove(i); AI_THINKING_STRUCT->aiLogicId = 0; AI_THINKING_STRUCT->movesetIndex = 0; flags = AI_THINKING_STRUCT->aiFlags; @@ -464,7 +467,6 @@ static u8 ChooseMoveOrAction_Doubles(void) for (j = 0; j < MAX_MON_MOVES; j++) { gBattleStruct->aiFinalScore[sBattler_AI][gBattlerTarget][j] = AI_THINKING_STRUCT->score[j]; - gBattleStruct->aiSimulatedDamage[sBattler_AI][gBattlerTarget][j] = AI_THINKING_STRUCT->simulatedDmg[sBattler_AI][gBattlerTarget][j]; } } } @@ -550,11 +552,10 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) u16 moveEffect = gBattleMoves[move].effect; s32 moveType; u16 moveTarget = gBattleMoves[move].target; - u16 accuracy = AI_GetMoveAccuracy(battlerAtk, battlerDef, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect, move); - u8 effectiveness = AI_GetMoveEffectiveness(move, battlerAtk, battlerDef); + u8 effectiveness = AI_DATA->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex]; bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk); u32 i; - u16 predictedMove = gLastMoves[battlerDef]; // TODO better move prediction + u16 predictedMove = AI_DATA->predictedMoves[battlerDef]; SetTypeBeforeUsingMove(move, battlerAtk); GET_MOVE_TYPE(move, moveType); @@ -569,7 +570,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { // handle negative checks on non-user target // check powder moves - if (TestMoveFlags(move, FLAG_POWDER) && !IsAffectedByPowder(battlerDef, AI_DATA->defAbility, AI_DATA->defHoldEffect)) + if (TestMoveFlags(move, FLAG_POWDER) && !IsAffectedByPowder(battlerDef, AI_DATA->abilities[battlerDef], AI_DATA->holdEffects[battlerDef])) { RETURN_SCORE_MINUS(20); } @@ -577,9 +578,9 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // check ground immunities if (moveType == TYPE_GROUND && !IsBattlerGrounded(battlerDef) - && ((AI_DATA->defAbility == ABILITY_LEVITATE - && DoesBattlerIgnoreAbilityChecks(AI_DATA->atkAbility, move)) - || AI_DATA->defHoldEffect == HOLD_EFFECT_AIR_BALLOON + && ((AI_DATA->abilities[battlerDef] == ABILITY_LEVITATE + && DoesBattlerIgnoreAbilityChecks(AI_DATA->abilities[battlerAtk], move)) + || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_AIR_BALLOON || (gStatuses3[battlerDef] & (STATUS3_MAGNET_RISE | STATUS3_TELEKINESIS))) && move != MOVE_THOUSAND_ARROWS) { @@ -602,9 +603,9 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } // target ability checks - if (!DoesBattlerIgnoreAbilityChecks(AI_DATA->atkAbility, move)) + if (!DoesBattlerIgnoreAbilityChecks(AI_DATA->abilities[battlerAtk], move)) { - switch (AI_DATA->defAbility) + switch (AI_DATA->abilities[battlerDef]) { case ABILITY_MAGIC_GUARD: switch (moveEffect) @@ -719,13 +720,9 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (IsShieldsDownProtected(battlerAtk) && IsNonVolatileStatusMoveEffect(moveEffect)) RETURN_SCORE_MINUS(10); break; - case ABILITY_WONDER_SKIN: - if (IS_MOVE_STATUS(move)) - accuracy = 50; - break; case ABILITY_LEAF_GUARD: if (AI_WeatherHasEffect() && (gBattleWeather & B_WEATHER_SUN) - && AI_DATA->defHoldEffect != HOLD_EFFECT_UTILITY_UMBRELLA + && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_UTILITY_UMBRELLA && IsNonVolatileStatusMoveEffect(moveEffect)) RETURN_SCORE_MINUS(10); break; @@ -734,14 +731,14 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // target partner ability checks & not attacking partner if (isDoubleBattle) { - switch (AI_DATA->defPartnerAbility) + switch (AI_DATA->abilities[BATTLE_PARTNER(battlerDef)]) { case ABILITY_LIGHTNING_ROD: - if (moveType == TYPE_ELECTRIC && !IsMoveRedirectionPrevented(move, AI_DATA->atkAbility)) + if (moveType == TYPE_ELECTRIC && !IsMoveRedirectionPrevented(move, AI_DATA->abilities[battlerAtk])) RETURN_SCORE_MINUS(20); break; case ABILITY_STORM_DRAIN: - if (moveType == TYPE_WATER && !IsMoveRedirectionPrevented(move, AI_DATA->atkAbility)) + if (moveType == TYPE_WATER && !IsMoveRedirectionPrevented(move, AI_DATA->abilities[battlerAtk])) RETURN_SCORE_MINUS(20); break; case ABILITY_MAGIC_BOUNCE: @@ -771,7 +768,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // gen7+ dark type mons immune to priority->elevated moves from prankster #if B_PRANKSTER >= GEN_7 - if (AI_DATA->atkAbility == ABILITY_PRANKSTER && IS_BATTLER_OF_TYPE(battlerDef, TYPE_DARK) && IS_MOVE_STATUS(move) + if (AI_DATA->abilities[battlerAtk] == ABILITY_PRANKSTER && IS_BATTLER_OF_TYPE(battlerDef, TYPE_DARK) && IS_MOVE_STATUS(move) && !(moveTarget & (MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_USER))) RETURN_SCORE_MINUS(10); #endif @@ -840,7 +837,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) default: break; // check move damage case EFFECT_SLEEP: - if (!AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) + if (!AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_EXPLOSION: @@ -851,7 +848,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { score -= 10; } - else if (IsAbilityOnField(ABILITY_DAMP) && !DoesBattlerIgnoreAbilityChecks(AI_DATA->atkAbility, move)) + else if (IsAbilityOnField(ABILITY_DAMP) && !DoesBattlerIgnoreAbilityChecks(AI_DATA->abilities[battlerAtk], move)) { score -= 10; } @@ -864,7 +861,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_DREAM_EATER: - if (!(gBattleMons[battlerDef].status1 & STATUS1_SLEEP) || AI_DATA->defAbility == ABILITY_COMATOSE) + if (!(gBattleMons[battlerDef].status1 & STATUS1_SLEEP) || AI_DATA->abilities[battlerDef] == ABILITY_COMATOSE) score -= 8; else if (effectiveness == AI_EFFECTIVENESS_x0) score -= 10; @@ -872,7 +869,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // stat raising effects case EFFECT_ATTACK_UP: case EFFECT_ATTACK_UP_2: - if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) + if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) score -= 10; break; case EFFECT_STUFF_CHEEKS: @@ -883,65 +880,65 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_DEFENSE_UP_2: case EFFECT_DEFENSE_UP_3: case EFFECT_DEFENSE_CURL: - if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_DEF)) + if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_DEF)) score -= 10; break; case EFFECT_SPECIAL_ATTACK_UP: case EFFECT_SPECIAL_ATTACK_UP_2: case EFFECT_SPECIAL_ATTACK_UP_3: - if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPATK) || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) + if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_SPATK) || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) score -= 10; break; case EFFECT_SPECIAL_DEFENSE_UP: case EFFECT_SPECIAL_DEFENSE_UP_2: - if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPDEF)) + if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_SPDEF)) score -= 10; break; case EFFECT_ACCURACY_UP: case EFFECT_ACCURACY_UP_2: - if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ACC)) + if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_ACC)) score -= 10; break; case EFFECT_EVASION_UP: case EFFECT_EVASION_UP_2: case EFFECT_MINIMIZE: - if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_EVASION)) + if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_EVASION)) score -= 10; break; case EFFECT_COSMIC_POWER: - if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_DEF)) + if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_DEF)) score -= 10; - else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPDEF)) + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_SPDEF)) score -= 8; break; case EFFECT_BULK_UP: - if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) + if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) score -= 10; - else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_DEF)) + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_DEF)) score -= 8; break; case EFFECT_CALM_MIND: - if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPATK)) + if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_SPATK)) score -= 10; - else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPDEF)) + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_SPDEF)) score -= 8; break; case EFFECT_DRAGON_DANCE: - if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) + if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) score -= 10; - else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPEED)) + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_SPEED)) score -= 8; break; case EFFECT_COIL: - if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ACC)) + if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_ACC)) score -= 10; - else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) score -= 8; - else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_DEF)) + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_DEF)) score -= 6; break; case EFFECT_ATTACK_ACCURACY_UP: //hone claws - if (AI_DATA->atkAbility != ABILITY_CONTRARY) + if (AI_DATA->abilities[battlerAtk] != ABILITY_CONTRARY) { if (gBattleMons[battlerAtk].statStages[STAT_ATK] >= MAX_STAT_STAGE && (gBattleMons[battlerAtk].statStages[STAT_ACC] >= MAX_STAT_STAGE || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL))) @@ -958,47 +955,47 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 20; else if (!HasMoveWithType(battlerAtk, TYPE_ELECTRIC)) score -= 10; - else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPDEF)) + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_SPDEF)) score -= 5; break; case EFFECT_QUIVER_DANCE: case EFFECT_GEOMANCY: if (gBattleMons[battlerAtk].statStages[STAT_SPATK] >= MAX_STAT_STAGE || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) score -= 10; - else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPEED)) + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_SPEED)) score -= 8; - else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPDEF)) + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_SPDEF)) score -= 6; break; case EFFECT_SHIFT_GEAR: - if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) + if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) score -= 10; - else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPEED)) + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_SPEED)) score -= 8; break; case EFFECT_SHELL_SMASH: - if (AI_DATA->atkAbility == ABILITY_CONTRARY) + if (AI_DATA->abilities[battlerAtk] == ABILITY_CONTRARY) { - if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_DEF)) + if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_DEF)) score -= 10; - else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPDEF)) + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_SPDEF)) score -= 8; } else { - if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) + if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) score -= 10; - else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPATK) || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_SPATK) || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) score -= 8; - else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPEED)) + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_SPEED)) score -= 6; } break; case EFFECT_GROWTH: case EFFECT_ATTACK_SPATK_UP: // work up - if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) + if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) score -= 10; - else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPATK) || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_SPATK) || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) score -= 8; break; case EFFECT_ROTOTILLER: @@ -1006,30 +1003,30 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { if (!(IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GRASS) && AI_IsBattlerGrounded(battlerAtk) - && (BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ATK) || BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPATK))) - && !(IS_BATTLER_OF_TYPE(AI_DATA->battlerAtkPartner, TYPE_GRASS) - && AI_IsBattlerGrounded(AI_DATA->battlerAtkPartner) - && AI_DATA->atkPartnerAbility != ABILITY_CONTRARY - && (BattlerStatCanRise(AI_DATA->battlerAtkPartner, AI_DATA->atkPartnerAbility, STAT_ATK) - || BattlerStatCanRise(AI_DATA->battlerAtkPartner, AI_DATA->atkPartnerAbility, STAT_SPATK)))) + && (BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_ATK) || BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_SPATK))) + && !(IS_BATTLER_OF_TYPE(BATTLE_PARTNER(battlerAtk), TYPE_GRASS) + && AI_IsBattlerGrounded(BATTLE_PARTNER(battlerAtk)) + && AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)] != ABILITY_CONTRARY + && (BattlerStatCanRise(BATTLE_PARTNER(battlerAtk), AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)], STAT_ATK) + || BattlerStatCanRise(BATTLE_PARTNER(battlerAtk), AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)], STAT_SPATK)))) { score -= 10; } } else if (!(IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GRASS) && AI_IsBattlerGrounded(battlerAtk) - && (BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ATK) || BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPATK)))) + && (BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_ATK) || BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_SPATK)))) { score -= 10; } break; case EFFECT_GEAR_UP: - if (AI_DATA->atkAbility == ABILITY_PLUS || AI_DATA->atkAbility == ABILITY_MINUS) + if (AI_DATA->abilities[battlerAtk] == ABILITY_PLUS || AI_DATA->abilities[battlerAtk] == ABILITY_MINUS) { // same as growth, work up - if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) + if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) score -= 10; - else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPATK) || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_SPATK) || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) score -= 8; break; } @@ -1040,13 +1037,13 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (isDoubleBattle) { - if (AI_DATA->atkPartnerAbility == ABILITY_PLUS || AI_DATA->atkPartnerAbility == ABILITY_MINUS) + if (AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_PLUS || AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_MINUS) { - if ((!BattlerStatCanRise(AI_DATA->battlerAtkPartner, AI_DATA->atkPartnerAbility, STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) - && (!BattlerStatCanRise(AI_DATA->battlerAtkPartner, AI_DATA->atkPartnerAbility, STAT_SPATK) || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL))) + if ((!BattlerStatCanRise(BATTLE_PARTNER(battlerAtk), AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)], STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) + && (!BattlerStatCanRise(BATTLE_PARTNER(battlerAtk), AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)], STAT_SPATK) || !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL))) score -= 10; } - else if (AI_DATA->atkAbility != ABILITY_PLUS && AI_DATA->atkAbility != ABILITY_MINUS) + else if (AI_DATA->abilities[battlerAtk] != ABILITY_PLUS && AI_DATA->abilities[battlerAtk] != ABILITY_MINUS) { score -= 10; // nor our or our partner's ability is plus/minus } @@ -1057,11 +1054,11 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; break; case EFFECT_MAGNETIC_FLUX: - if (AI_DATA->atkAbility == ABILITY_PLUS || AI_DATA->atkAbility == ABILITY_MINUS) + if (AI_DATA->abilities[battlerAtk] == ABILITY_PLUS || AI_DATA->abilities[battlerAtk] == ABILITY_MINUS) { - if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_DEF)) + if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_DEF)) score -= 10; - else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_SPDEF)) + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_SPDEF)) score -= 8; } else if (!isDoubleBattle) @@ -1071,14 +1068,14 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (isDoubleBattle) { - if (AI_DATA->atkPartnerAbility == ABILITY_PLUS || AI_DATA->atkPartnerAbility == ABILITY_MINUS) + if (AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_PLUS || AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_MINUS) { - if (!BattlerStatCanRise(AI_DATA->battlerAtkPartner, AI_DATA->atkPartnerAbility, STAT_DEF)) + if (!BattlerStatCanRise(BATTLE_PARTNER(battlerAtk), AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)], STAT_DEF)) score -= 10; - else if (!BattlerStatCanRise(AI_DATA->battlerAtkPartner, AI_DATA->atkPartnerAbility, STAT_SPDEF)) + else if (!BattlerStatCanRise(BATTLE_PARTNER(battlerAtk), AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)], STAT_SPDEF)) score -= 8; } - else if (AI_DATA->atkAbility != ABILITY_PLUS && AI_DATA->atkAbility != ABILITY_MINUS) + else if (AI_DATA->abilities[battlerAtk] != ABILITY_PLUS && AI_DATA->abilities[battlerAtk] != ABILITY_MINUS) { score -= 10; // nor our or our partner's ability is plus/minus } @@ -1087,49 +1084,49 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // stat lowering effects case EFFECT_ATTACK_DOWN: case EFFECT_ATTACK_DOWN_2: - if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_ATK)) //|| !HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL)) + if (!ShouldLowerStat(battlerDef, AI_DATA->abilities[battlerDef], STAT_ATK)) //|| !HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL)) score -= 10; - else if (AI_DATA->defAbility == ABILITY_HYPER_CUTTER) + else if (AI_DATA->abilities[battlerDef] == ABILITY_HYPER_CUTTER) score -= 10; break; case EFFECT_DEFENSE_DOWN: case EFFECT_DEFENSE_DOWN_2: - if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_DEF)) + if (!ShouldLowerStat(battlerDef, AI_DATA->abilities[battlerDef], STAT_DEF)) score -= 10; break; case EFFECT_SPEED_DOWN: case EFFECT_SPEED_DOWN_2: - if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_SPEED)) + if (!ShouldLowerStat(battlerDef, AI_DATA->abilities[battlerDef], STAT_SPEED)) score -= 10; - else if (AI_DATA->defAbility == ABILITY_SPEED_BOOST) + else if (AI_DATA->abilities[battlerDef] == ABILITY_SPEED_BOOST) score -= 10; break; case EFFECT_SPECIAL_ATTACK_DOWN: case EFFECT_SPECIAL_ATTACK_DOWN_2: - if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_SPATK)) //|| !HasMoveWithSplit(battlerDef, SPLIT_SPECIAL)) + if (!ShouldLowerStat(battlerDef, AI_DATA->abilities[battlerDef], STAT_SPATK)) //|| !HasMoveWithSplit(battlerDef, SPLIT_SPECIAL)) score -= 10; break; case EFFECT_SPECIAL_DEFENSE_DOWN: case EFFECT_SPECIAL_DEFENSE_DOWN_2: - if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_SPDEF)) + if (!ShouldLowerStat(battlerDef, AI_DATA->abilities[battlerDef], STAT_SPDEF)) score -= 10; break; case EFFECT_ACCURACY_DOWN: case EFFECT_ACCURACY_DOWN_2: - if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_ACC)) + if (!ShouldLowerStat(battlerDef, AI_DATA->abilities[battlerDef], STAT_ACC)) score -= 10; - else if (AI_DATA->defAbility == ABILITY_KEEN_EYE) + else if (AI_DATA->abilities[battlerDef] == ABILITY_KEEN_EYE) score -= 8; break; case EFFECT_EVASION_DOWN: case EFFECT_EVASION_DOWN_2: - if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_EVASION)) + if (!ShouldLowerStat(battlerDef, AI_DATA->abilities[battlerDef], STAT_EVASION)) score -= 10; break; case EFFECT_TICKLE: - if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_ATK)) + if (!ShouldLowerStat(battlerDef, AI_DATA->abilities[battlerDef], STAT_ATK)) score -= 10; - else if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_DEF)) + else if (!ShouldLowerStat(battlerDef, AI_DATA->abilities[battlerDef], STAT_DEF)) score -= 8; break; case EFFECT_VENOM_DRENCH: @@ -1139,18 +1136,18 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } else { - if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_SPEED)) + if (!ShouldLowerStat(battlerDef, AI_DATA->abilities[battlerDef], STAT_SPEED)) score -= 10; - else if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_SPATK)) + else if (!ShouldLowerStat(battlerDef, AI_DATA->abilities[battlerDef], STAT_SPATK)) score -= 8; - else if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_ATK)) + else if (!ShouldLowerStat(battlerDef, AI_DATA->abilities[battlerDef], STAT_ATK)) score -= 6; } break; case EFFECT_NOBLE_ROAR: - if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_SPATK)) + if (!ShouldLowerStat(battlerDef, AI_DATA->abilities[battlerDef], STAT_SPATK)) score -= 10; - else if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_ATK)) + else if (!ShouldLowerStat(battlerDef, AI_DATA->abilities[battlerDef], STAT_ATK)) score -= 8; break; case EFFECT_CAPTIVATE: @@ -1163,7 +1160,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; // other case EFFECT_HAZE: - if (PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + if (PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) { score -= 10; // partner already using haze } @@ -1171,12 +1168,12 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) { - if (gBattleMons[battlerAtk].statStages[i] > DEFAULT_STAT_STAGE || gBattleMons[AI_DATA->battlerAtkPartner].statStages[i] > DEFAULT_STAT_STAGE) + if (gBattleMons[battlerAtk].statStages[i] > DEFAULT_STAT_STAGE || gBattleMons[BATTLE_PARTNER(battlerAtk)].statStages[i] > DEFAULT_STAT_STAGE) score -= 10; // Don't want to reset our boosted stats } for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) { - if (gBattleMons[battlerDef].statStages[i] < DEFAULT_STAT_STAGE || gBattleMons[AI_DATA->battlerDefPartner].statStages[i] < DEFAULT_STAT_STAGE) + if (gBattleMons[battlerDef].statStages[i] < DEFAULT_STAT_STAGE || gBattleMons[BATTLE_PARTNER(battlerDef)].statStages[i] < DEFAULT_STAT_STAGE) score -= 10; //Don't want to reset enemy lowered stats } } @@ -1199,46 +1196,46 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) //case EFFECT_ENDEAVOR: case EFFECT_LOW_KICK: // AI_CBM_HighRiskForDamage - if (AI_DATA->defAbility == ABILITY_WONDER_GUARD && effectiveness < AI_EFFECTIVENESS_x2) + if (AI_DATA->abilities[battlerDef] == ABILITY_WONDER_GUARD && effectiveness < AI_EFFECTIVENESS_x2) score -= 10; break; case EFFECT_COUNTER: case EFFECT_MIRROR_COAT: - if (IsBattlerIncapacitated(battlerDef, AI_DATA->defAbility) || gBattleMons[battlerDef].status2 & (STATUS2_INFATUATION | STATUS2_CONFUSION)) + if (IsBattlerIncapacitated(battlerDef, AI_DATA->abilities[battlerDef]) || gBattleMons[battlerDef].status2 & (STATUS2_INFATUATION | STATUS2_CONFUSION)) score--; if (predictedMove == MOVE_NONE || GetBattleMoveSplit(predictedMove) == SPLIT_STATUS - || DoesSubstituteBlockMove(battlerAtk, AI_DATA->battlerDefPartner, predictedMove)) + || DoesSubstituteBlockMove(battlerAtk, BATTLE_PARTNER(battlerDef), predictedMove)) score -= 10; break; case EFFECT_ROAR: if (CountUsablePartyMons(battlerDef) == 0) score -= 10; - else if (AI_DATA->defAbility == ABILITY_SUCTION_CUPS) + else if (AI_DATA->abilities[battlerDef] == ABILITY_SUCTION_CUPS) score -= 10; break; case EFFECT_TOXIC_THREAD: - if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_SPEED)) + if (!ShouldLowerStat(battlerDef, AI_DATA->abilities[battlerDef], STAT_SPEED)) score--; // may still want to just poison //fallthrough case EFFECT_POISON: case EFFECT_TOXIC: - if (!AI_CanPoison(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) + if (!AI_CanPoison(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_LIGHT_SCREEN: if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_LIGHTSCREEN - || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_REFLECT: if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_REFLECT - || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_AURORA_VEIL: if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_AURORA_VEIL - || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove) + || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove) || !(gBattleWeather & B_WEATHER_HAIL)) score -= 10; break; @@ -1247,12 +1244,12 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) && move == MOVE_SHEER_COLD && IS_BATTLER_OF_TYPE(battlerDef, TYPE_ICE)) return 0; - if (!ShouldTryOHKO(battlerAtk, battlerDef, AI_DATA->atkAbility, AI_DATA->defAbility, accuracy, move)) + if (!ShouldTryOHKO(battlerAtk, battlerDef, AI_DATA->abilities[battlerAtk], AI_DATA->abilities[battlerDef], move)) score -= 10; break; case EFFECT_MIST: if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_MIST - || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_FOCUS_ENERGY: @@ -1262,17 +1259,17 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_CONFUSE: case EFFECT_SWAGGER: case EFFECT_FLATTER: - if (!AI_CanConfuse(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + if (!AI_CanConfuse(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_PARALYZE: - if (!AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) + if (!AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_SUBSTITUTE: - if (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE || AI_DATA->defAbility == ABILITY_INFILTRATOR) + if (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE || AI_DATA->abilities[battlerDef] == ABILITY_INFILTRATOR) score -= 8; - else if (GetHealthPercentage(battlerAtk) <= 25) + else if (AI_DATA->hpPercents[battlerAtk] <= 25) score -= 10; else if (B_SOUND_SUBSTITUTE >= GEN_6 && TestMoveFlagsInMoveset(battlerDef, FLAG_SOUND)) score -= 8; @@ -1280,15 +1277,15 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_LEECH_SEED: if (gStatuses3[battlerDef] & STATUS3_LEECHSEED || IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS) - || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) score -= 10; - else if (AI_DATA->defAbility == ABILITY_LIQUID_OOZE) + else if (AI_DATA->abilities[battlerDef] == ABILITY_LIQUID_OOZE) score -= 3; break; case EFFECT_DISABLE: if (gDisableStructs[battlerDef].disableTimer == 0 - && (B_MENTAL_HERB >= GEN_5 && AI_DATA->defHoldEffect != HOLD_EFFECT_MENTAL_HERB) - && !PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + && (B_MENTAL_HERB >= GEN_5 && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB) + && !PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) { if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) // Attacker should go first { @@ -1307,8 +1304,8 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_ENCORE: if (gDisableStructs[battlerDef].encoreTimer == 0 - && (B_MENTAL_HERB >= GEN_5 && AI_DATA->defHoldEffect != HOLD_EFFECT_MENTAL_HERB) - && !DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + && (B_MENTAL_HERB >= GEN_5 && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB) + && !DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) { if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) // Attacker should go first { @@ -1327,60 +1324,60 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_SNORE: case EFFECT_SLEEP_TALK: - if (IsWakeupTurn(battlerAtk) || (!(gBattleMons[battlerAtk].status1 & STATUS1_SLEEP) || AI_DATA->atkAbility != ABILITY_COMATOSE)) + if (IsWakeupTurn(battlerAtk) || (!(gBattleMons[battlerAtk].status1 & STATUS1_SLEEP) || AI_DATA->abilities[battlerAtk] != ABILITY_COMATOSE)) score -= 10; // if mon will wake up, is not asleep, or is not comatose break; case EFFECT_MEAN_LOOK: - if (IsBattlerTrapped(battlerDef, TRUE) || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + if (IsBattlerTrapped(battlerDef, TRUE) || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_NIGHTMARE: if (gBattleMons[battlerDef].status2 & STATUS2_NIGHTMARE) score -= 10; - else if (!(gBattleMons[battlerDef].status1 & STATUS1_SLEEP) || AI_DATA->defAbility == ABILITY_COMATOSE) + else if (!(gBattleMons[battlerDef].status1 & STATUS1_SLEEP) || AI_DATA->abilities[battlerDef] == ABILITY_COMATOSE) score -= 8; - else if (DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + else if (DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_CURSE: if (IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GHOST)) { if (gBattleMons[battlerDef].status2 & STATUS2_CURSED - || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) score -= 10; - else if (GetHealthPercentage(battlerAtk) <= 50) + else if (AI_DATA->hpPercents[battlerAtk] <= 50) score -= 6; } else // regular curse { - if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) + if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_ATK) || !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) score -= 10; - else if (!BattlerStatCanRise(battlerAtk, AI_DATA->atkAbility, STAT_DEF)) + else if (!BattlerStatCanRise(battlerAtk, AI_DATA->abilities[battlerAtk], STAT_DEF)) score -= 8; } break; case EFFECT_SPIKES: if (gSideTimers[GetBattlerSide(battlerDef)].spikesAmount >= 3) score -= 10; - else if (PartnerMoveIsSameNoTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove) + else if (PartnerMoveIsSameNoTarget(BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove) && gSideTimers[GetBattlerSide(battlerDef)].spikesAmount == 2) score -= 10; // only one mon needs to set up the last layer of Spikes break; case EFFECT_STEALTH_ROCK: if (gSideTimers[GetBattlerSide(battlerDef)].stealthRockAmount > 0 - || PartnerMoveIsSameNoTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) //Only one mon needs to set up Stealth Rocks + || PartnerMoveIsSameNoTarget(BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) //Only one mon needs to set up Stealth Rocks score -= 10; break; case EFFECT_TOXIC_SPIKES: if (gSideTimers[GetBattlerSide(battlerDef)].toxicSpikesAmount >= 2) score -= 10; - else if (PartnerMoveIsSameNoTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove) && gSideTimers[GetBattlerSide(battlerDef)].toxicSpikesAmount == 1) + else if (PartnerMoveIsSameNoTarget(BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove) && gSideTimers[GetBattlerSide(battlerDef)].toxicSpikesAmount == 1) score -= 10; // only one mon needs to set up the last layer of Toxic Spikes break; case EFFECT_STICKY_WEB: if (gSideTimers[GetBattlerSide(battlerDef)].stickyWebAmount) score -= 10; - else if (PartnerMoveIsSameNoTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove) && gSideTimers[GetBattlerSide(battlerDef)].stickyWebAmount) + else if (PartnerMoveIsSameNoTarget(BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove) && gSideTimers[GetBattlerSide(battlerDef)].stickyWebAmount) score -= 10; // only one mon needs to set up Sticky Web break; case EFFECT_FORESIGHT: @@ -1388,74 +1385,74 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; else if (gBattleMons[battlerDef].statStages[STAT_EVASION] <= 4 || !(IS_BATTLER_OF_TYPE(battlerDef, TYPE_GHOST)) - || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) score -= 9; break; case EFFECT_PERISH_SONG: if (isDoubleBattle) { if (CountUsablePartyMons(battlerAtk) == 0 - && AI_DATA->atkAbility != ABILITY_SOUNDPROOF - && AI_DATA->atkPartnerAbility != ABILITY_SOUNDPROOF + && AI_DATA->abilities[battlerAtk] != ABILITY_SOUNDPROOF + && AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)] != ABILITY_SOUNDPROOF && CountUsablePartyMons(FOE(battlerAtk)) >= 1) { score -= 10; //Don't wipe your team if you're going to lose } - else if ((!IsBattlerAlive(FOE(battlerAtk)) || AI_GetAbility(FOE(battlerAtk)) == ABILITY_SOUNDPROOF + else if ((!IsBattlerAlive(FOE(battlerAtk)) || AI_DATA->abilities[FOE(battlerAtk)] == ABILITY_SOUNDPROOF || gStatuses3[FOE(battlerAtk)] & STATUS3_PERISH_SONG) - && (!IsBattlerAlive(BATTLE_PARTNER(FOE(battlerAtk))) || AI_GetAbility(BATTLE_PARTNER(FOE(battlerAtk))) == ABILITY_SOUNDPROOF + && (!IsBattlerAlive(BATTLE_PARTNER(FOE(battlerAtk))) || AI_DATA->abilities[BATTLE_PARTNER(FOE(battlerAtk))] == ABILITY_SOUNDPROOF || gStatuses3[BATTLE_PARTNER(FOE(battlerAtk))] & STATUS3_PERISH_SONG)) { score -= 10; //Both enemies are perish songed } - else if (DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + else if (DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) { score -= 10; } } else { - if (CountUsablePartyMons(battlerAtk) == 0 && AI_DATA->atkAbility != ABILITY_SOUNDPROOF + if (CountUsablePartyMons(battlerAtk) == 0 && AI_DATA->abilities[battlerAtk] != ABILITY_SOUNDPROOF && CountUsablePartyMons(battlerDef) >= 1) score -= 10; - if (gStatuses3[FOE(battlerAtk)] & STATUS3_PERISH_SONG || AI_GetAbility(FOE(battlerAtk)) == ABILITY_SOUNDPROOF) + if (gStatuses3[FOE(battlerAtk)] & STATUS3_PERISH_SONG || AI_DATA->abilities[FOE(battlerAtk)] == ABILITY_SOUNDPROOF) score -= 10; } break; case EFFECT_SANDSTORM: if (gBattleWeather & (B_WEATHER_SANDSTORM | B_WEATHER_PRIMAL_ANY) - || PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove)) + || PartnerMoveEffectIsWeather(BATTLE_PARTNER(battlerAtk), AI_DATA->partnerMove)) score -= 8; break; case EFFECT_SUNNY_DAY: if (gBattleWeather & (B_WEATHER_SUN | B_WEATHER_PRIMAL_ANY) - || PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove)) + || PartnerMoveEffectIsWeather(BATTLE_PARTNER(battlerAtk), AI_DATA->partnerMove)) score -= 8; break; case EFFECT_RAIN_DANCE: if (gBattleWeather & (B_WEATHER_RAIN | B_WEATHER_PRIMAL_ANY) - || PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove)) + || PartnerMoveEffectIsWeather(BATTLE_PARTNER(battlerAtk), AI_DATA->partnerMove)) score -= 8; break; case EFFECT_HAIL: if (gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_PRIMAL_ANY) - || PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove)) + || PartnerMoveEffectIsWeather(BATTLE_PARTNER(battlerAtk), AI_DATA->partnerMove)) score -= 8; break; case EFFECT_ATTRACT: - if (!AI_CanBeInfatuated(battlerAtk, battlerDef, AI_DATA->defAbility, + if (!AI_CanBeInfatuated(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], GetGenderFromSpeciesAndPersonality(gBattleMons[battlerAtk].species, gBattleMons[battlerAtk].personality), GetGenderFromSpeciesAndPersonality(gBattleMons[battlerDef].species, gBattleMons[battlerDef].personality))) score -= 10; break; case EFFECT_SAFEGUARD: if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_SAFEGUARD - || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_MAGNITUDE: - if (AI_DATA->defAbility == ABILITY_LEVITATE) + if (AI_DATA->abilities[battlerDef] == ABILITY_LEVITATE) score -= 10; break; case EFFECT_PARTING_SHOT: @@ -1482,9 +1479,9 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 6; break; case EFFECT_BELLY_DRUM: - if (AI_DATA->atkAbility == ABILITY_CONTRARY) + if (AI_DATA->abilities[battlerAtk] == ABILITY_CONTRARY) score -= 10; - else if (GetHealthPercentage(battlerAtk) <= 60) + else if (AI_DATA->hpPercents[battlerAtk] <= 60) score -= 10; break; case EFFECT_FUTURE_SIGHT: @@ -1504,7 +1501,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } else if (move == MOVE_FAKE_OUT) // filter out first impression { - if ((AI_DATA->atkHoldEffect == HOLD_EFFECT_CHOICE_BAND || AI_DATA->atkAbility == ABILITY_GORILLA_TACTICS) + if ((AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_CHOICE_BAND || AI_DATA->abilities[battlerAtk] == ABILITY_GORILLA_TACTICS) && (CountUsablePartyMons(battlerDef) > 0 || !CanIndexMoveFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0))) { if (CountUsablePartyMons(battlerAtk) == 0) @@ -1529,27 +1526,27 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { if (AtMaxHp(battlerAtk)) score -= 10; - else if (GetHealthPercentage(battlerAtk) >= 80) + else if (AI_DATA->hpPercents[battlerAtk] >= 80) score -= 5; // do it if nothing better } break; case EFFECT_TORMENT: if (gBattleMons[battlerDef].status2 & STATUS2_TORMENT - || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) { score -= 10; break; } - if (B_MENTAL_HERB >= GEN_5 && AI_DATA->defHoldEffect == HOLD_EFFECT_MENTAL_HERB) + if (B_MENTAL_HERB >= GEN_5 && AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_MENTAL_HERB) score -= 6; break; case EFFECT_WILL_O_WISP: - if (!AI_CanBurn(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + if (!AI_CanBurn(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_MEMENTO: - if (CountUsablePartyMons(battlerAtk) == 0 || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + if (CountUsablePartyMons(battlerAtk) == 0 || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) score -= 10; else if (gBattleMons[battlerDef].statStages[STAT_ATK] == MIN_STAT_STAGE && gBattleMons[battlerDef].statStages[STAT_SPATK] == MIN_STAT_STAGE) score -= 10; @@ -1557,15 +1554,15 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_FOLLOW_ME: case EFFECT_HELPING_HAND: if (!isDoubleBattle - || !IsBattlerAlive(AI_DATA->battlerAtkPartner) - || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove) + || !IsBattlerAlive(BATTLE_PARTNER(battlerAtk)) + || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove) || (AI_DATA->partnerMove != MOVE_NONE && IS_MOVE_STATUS(AI_DATA->partnerMove)) - || *(gBattleStruct->monToSwitchIntoId + AI_DATA->battlerAtkPartner) != PARTY_SIZE) //Partner is switching out. + || *(gBattleStruct->monToSwitchIntoId + BATTLE_PARTNER(battlerAtk)) != PARTY_SIZE) //Partner is switching out. score -= 10; break; case EFFECT_TRICK: case EFFECT_KNOCK_OFF: - if (AI_DATA->defAbility == ABILITY_STICKY_HOLD) + if (AI_DATA->abilities[battlerDef] == ABILITY_STICKY_HOLD) score -= 10; break; case EFFECT_INGRAIN: @@ -1589,14 +1586,14 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; break; case EFFECT_PSYCHO_SHIFT: - if (gBattleMons[battlerAtk].status1 & STATUS1_PSN_ANY && !AI_CanPoison(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) + if (gBattleMons[battlerAtk].status1 & STATUS1_PSN_ANY && !AI_CanPoison(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove)) score -= 10; else if (gBattleMons[battlerAtk].status1 & STATUS1_BURN && !AI_CanBurn(battlerAtk, battlerDef, - AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + AI_DATA->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) score -= 10; - else if (gBattleMons[battlerAtk].status1 & STATUS1_PARALYSIS && !AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) + else if (gBattleMons[battlerAtk].status1 & STATUS1_PARALYSIS && !AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove)) score -= 10; - else if (gBattleMons[battlerAtk].status1 & STATUS1_SLEEP && !AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) + else if (gBattleMons[battlerAtk].status1 & STATUS1_SLEEP && !AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove)) score -= 10; else score -= 10; // attacker has no status to transmit @@ -1604,23 +1601,23 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_MUD_SPORT: if (gFieldStatuses & STATUS_FIELD_MUDSPORT || gStatuses4[battlerAtk] & STATUS4_MUD_SPORT - || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_WATER_SPORT: if (gFieldStatuses & STATUS_FIELD_WATERSPORT || gStatuses4[battlerAtk] & STATUS4_WATER_SPORT - || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_ABSORB: - if (AI_DATA->defAbility == ABILITY_LIQUID_OOZE) + if (AI_DATA->abilities[battlerDef] == ABILITY_LIQUID_OOZE) score -= 6; break; case EFFECT_STRENGTH_SAP: - if (AI_DATA->defAbility == ABILITY_CONTRARY) + if (AI_DATA->abilities[battlerDef] == ABILITY_CONTRARY) score -= 10; - else if (!ShouldLowerStat(battlerDef, AI_DATA->defAbility, STAT_ATK)) + else if (!ShouldLowerStat(battlerDef, AI_DATA->abilities[battlerDef], STAT_ATK)) score -= 10; break; case EFFECT_COPYCAT: @@ -1628,23 +1625,23 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) return AI_CheckBadMove(battlerAtk, battlerDef, predictedMove, score); case EFFECT_FLOWER_SHIELD: if (!IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GRASS) - && !(isDoubleBattle && IS_BATTLER_OF_TYPE(AI_DATA->battlerAtkPartner, TYPE_GRASS))) + && !(isDoubleBattle && IS_BATTLER_OF_TYPE(BATTLE_PARTNER(battlerAtk), TYPE_GRASS))) score -= 10; break; case EFFECT_AROMATIC_MIST: - if (!isDoubleBattle || gBattleMons[AI_DATA->battlerAtkPartner].hp == 0 || !BattlerStatCanRise(AI_DATA->battlerAtkPartner, AI_DATA->atkPartnerAbility, STAT_SPDEF)) + if (!isDoubleBattle || gBattleMons[BATTLE_PARTNER(battlerAtk)].hp == 0 || !BattlerStatCanRise(BATTLE_PARTNER(battlerAtk), AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)], STAT_SPDEF)) score -= 10; break; case EFFECT_BIDE: if (!HasDamagingMove(battlerDef) - || GetHealthPercentage(battlerAtk) < 30 //Close to death + || AI_DATA->hpPercents[battlerAtk] < 30 //Close to death || gBattleMons[battlerDef].status1 & (STATUS1_SLEEP | STATUS1_FREEZE)) //No point in biding if can't take damage score -= 10; break; case EFFECT_HIT_SWITCH_TARGET: - if (DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + if (DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) score -= 10; // don't scare away pokemon twice - else if (GetHealthPercentage(battlerDef) < 10 && GetBattlerSecondaryDamage(battlerDef)) + else if (AI_DATA->hpPercents[battlerDef] < 10 && GetBattlerSecondaryDamage(battlerDef)) score -= 10; // don't blow away mon that will faint soon else if (gStatuses3[battlerDef] & STATUS3_PERISH_SONG) score -= 10; @@ -1655,7 +1652,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; break; case EFFECT_REST: - if (!AI_CanSleep(battlerAtk, AI_DATA->atkAbility)) + if (!AI_CanSleep(battlerAtk, AI_DATA->abilities[battlerAtk])) score -= 10; //fallthrough case EFFECT_RESTORE_HP: @@ -1663,7 +1660,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_ROOST: if (AtMaxHp(battlerAtk)) score -= 10; - else if (GetHealthPercentage(battlerAtk) >= 90) + else if (AI_DATA->hpPercents[battlerAtk] >= 90) score -= 9; //No point in healing, but should at least do it if nothing better break; case EFFECT_MORNING_SUN: @@ -1673,31 +1670,31 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 3; else if (AtMaxHp(battlerAtk)) score -= 10; - else if (GetHealthPercentage(battlerAtk) >= 90) + else if (AI_DATA->hpPercents[battlerAtk] >= 90) score -= 9; //No point in healing, but should at least do it if nothing better break; case EFFECT_PURIFY: if (!(gBattleMons[battlerDef].status1 & STATUS1_ANY)) score -= 10; - else if (battlerDef == AI_DATA->battlerAtkPartner) + else if (battlerDef == BATTLE_PARTNER(battlerAtk)) break; //Always heal your ally else if (AtMaxHp(battlerAtk)) score -= 10; - else if (GetHealthPercentage(battlerAtk) >= 90) + else if (AI_DATA->hpPercents[battlerAtk] >= 90) score -= 8; //No point in healing, but should at least do it if nothing better break; case EFFECT_SUPER_FANG: - if (GetHealthPercentage(battlerDef) < 50) + if (AI_DATA->hpPercents[battlerDef] < 50) score -= 4; break; case EFFECT_RECOIL_IF_MISS: - if (AI_DATA->atkAbility != ABILITY_MAGIC_GUARD && accuracy < 75) + if (AI_DATA->abilities[battlerAtk] != ABILITY_MAGIC_GUARD && AI_GetMoveAccuracy(battlerAtk, battlerDef, move) < 75) score -= 6; break; case EFFECT_RECOIL_25: - if (AI_DATA->atkAbility != ABILITY_MAGIC_GUARD && AI_DATA->atkAbility != ABILITY_ROCK_HEAD) + if (AI_DATA->abilities[battlerAtk] != ABILITY_MAGIC_GUARD && AI_DATA->abilities[battlerAtk] != ABILITY_ROCK_HEAD) { - u32 recoilDmg = max(1, AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] / 4); + u32 recoilDmg = max(1, AI_DATA->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] / 4); if (!ShouldUseRecoilMove(battlerAtk, battlerDef, recoilDmg, AI_THINKING_STRUCT->movesetIndex)) score -= 10; break; @@ -1705,18 +1702,18 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_RECOIL_33: case EFFECT_RECOIL_33_STATUS: - if (AI_DATA->atkAbility != ABILITY_MAGIC_GUARD && AI_DATA->atkAbility != ABILITY_ROCK_HEAD) + if (AI_DATA->abilities[battlerAtk] != ABILITY_MAGIC_GUARD && AI_DATA->abilities[battlerAtk] != ABILITY_ROCK_HEAD) { - u32 recoilDmg = max(1, AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] / 3); + u32 recoilDmg = max(1, AI_DATA->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] / 3); if (!ShouldUseRecoilMove(battlerAtk, battlerDef, recoilDmg, AI_THINKING_STRUCT->movesetIndex)) score -= 10; break; } break; case EFFECT_RECOIL_50: - if (AI_DATA->atkAbility != ABILITY_MAGIC_GUARD && AI_DATA->atkAbility != ABILITY_ROCK_HEAD) + if (AI_DATA->abilities[battlerAtk] != ABILITY_MAGIC_GUARD && AI_DATA->abilities[battlerAtk] != ABILITY_ROCK_HEAD) { - u32 recoilDmg = max(1, AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] / 2); + u32 recoilDmg = max(1, AI_DATA->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] / 2); if (!ShouldUseRecoilMove(battlerAtk, battlerDef, recoilDmg, AI_THINKING_STRUCT->movesetIndex)) score -= 10; break; @@ -1724,13 +1721,13 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_TEETER_DANCE: if (((gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) - || (!DoesBattlerIgnoreAbilityChecks(AI_DATA->atkAbility, move) && AI_DATA->defAbility == ABILITY_OWN_TEMPO) + || (!DoesBattlerIgnoreAbilityChecks(AI_DATA->abilities[battlerAtk], move) && AI_DATA->abilities[battlerDef] == ABILITY_OWN_TEMPO) || (IsBattlerGrounded(battlerDef) && AI_IsTerrainAffected(battlerDef, STATUS_FIELD_MISTY_TERRAIN)) || (DoesSubstituteBlockMove(battlerAtk, battlerDef, move))) - && ((gBattleMons[AI_DATA->battlerDefPartner].status2 & STATUS2_CONFUSION) - || (!DoesBattlerIgnoreAbilityChecks(AI_DATA->atkAbility, move) && AI_DATA->defPartnerAbility == ABILITY_OWN_TEMPO) - || (IsBattlerGrounded(AI_DATA->battlerDefPartner) && AI_IsTerrainAffected(AI_DATA->battlerDefPartner, STATUS_FIELD_MISTY_TERRAIN)) - || (DoesSubstituteBlockMove(battlerAtk, AI_DATA->battlerDefPartner, move)))) + && ((gBattleMons[BATTLE_PARTNER(battlerDef)].status2 & STATUS2_CONFUSION) + || (!DoesBattlerIgnoreAbilityChecks(AI_DATA->abilities[battlerAtk], move) && AI_DATA->abilities[BATTLE_PARTNER(battlerDef)] == ABILITY_OWN_TEMPO) + || (IsBattlerGrounded(BATTLE_PARTNER(battlerDef)) && AI_IsTerrainAffected(BATTLE_PARTNER(battlerDef), STATUS_FIELD_MISTY_TERRAIN)) + || (DoesSubstituteBlockMove(battlerAtk, BATTLE_PARTNER(battlerDef), move)))) { score -= 10; } @@ -1741,13 +1738,13 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; break; case EFFECT_TWO_TURNS_ATTACK: - if (AI_DATA->atkHoldEffect != HOLD_EFFECT_POWER_HERB && CanTargetFaintAi(battlerDef, battlerAtk)) + if (AI_DATA->holdEffects[battlerAtk] != HOLD_EFFECT_POWER_HERB && CanTargetFaintAi(battlerDef, battlerAtk)) score -= 6; break; case EFFECT_RECHARGE: - if (AI_DATA->defAbility == ABILITY_WONDER_GUARD && effectiveness < AI_EFFECTIVENESS_x2) + if (AI_DATA->abilities[battlerDef] == ABILITY_WONDER_GUARD && effectiveness < AI_EFFECTIVENESS_x2) score -= 10; - else if (AI_DATA->atkAbility != ABILITY_TRUANT + else if (AI_DATA->abilities[battlerAtk] != ABILITY_TRUANT && !CanIndexMoveFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) score -= 2; break; @@ -1778,15 +1775,15 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_LOCK_ON: if (gStatuses3[battlerDef] & STATUS3_ALWAYS_HITS - || AI_DATA->atkAbility == ABILITY_NO_GUARD - || AI_DATA->defAbility == ABILITY_NO_GUARD - || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + || AI_DATA->abilities[battlerAtk] == ABILITY_NO_GUARD + || AI_DATA->abilities[battlerDef] == ABILITY_NO_GUARD + || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_LASER_FOCUS: if (gStatuses3[battlerAtk] & STATUS3_LASER_FOCUS) score -= 10; - else if (AI_DATA->defAbility == ABILITY_SHELL_ARMOR || AI_DATA->defAbility == ABILITY_BATTLE_ARMOR) + else if (AI_DATA->abilities[battlerDef] == ABILITY_SHELL_ARMOR || AI_DATA->abilities[battlerDef] == ABILITY_BATTLE_ARMOR) score -= 8; break; case EFFECT_SKETCH: @@ -1801,7 +1798,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // TODO break; case EFFECT_HEAL_BELL: - if (!AnyPartyMemberStatused(battlerAtk, TestMoveFlags(move, FLAG_SOUND)) || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + if (!AnyPartyMemberStatused(battlerAtk, TestMoveFlags(move, FLAG_SOUND)) || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_HIT_PREVENT_ESCAPE: @@ -1835,7 +1832,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (decreased) break; - if (IsBattlerIncapacitated(battlerDef, AI_DATA->defAbility)) + if (IsBattlerIncapacitated(battlerDef, AI_DATA->abilities[battlerDef])) { score -= 10; break; @@ -1846,8 +1843,8 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) && move != MOVE_CRAFTY_SHIELD) //These moves have infinite usage { if (GetBattlerSecondaryDamage(battlerAtk) >= gBattleMons[battlerAtk].hp - && AI_DATA->defAbility != ABILITY_MOXIE - && AI_DATA->defAbility != ABILITY_BEAST_BOOST) + && AI_DATA->abilities[battlerDef] != ABILITY_MOXIE + && AI_DATA->abilities[battlerDef] != ABILITY_BEAST_BOOST) { score -= 10; //Don't protect if you're going to faint after protecting } @@ -1881,7 +1878,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (gBattleMons[battlerDef].statStages[STAT_EVASION] <= 4 || !(IS_BATTLER_OF_TYPE(battlerDef, TYPE_DARK)) - || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) score -= 9; break; case EFFECT_BURN_UP: @@ -1894,7 +1891,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) || gSideTimers[GetBattlerSide(battlerDef)].auroraVeilTimer != 0 || gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_HAZARDS_ANY) { - if (PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + if (PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) { score -= 10; //Only need one hazards removal break; @@ -1910,7 +1907,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (isDoubleBattle) { if (IsHazardMoveEffect(gBattleMoves[AI_DATA->partnerMove].effect) // partner is going to set up hazards - && AI_WhoStrikesFirst(AI_DATA->battlerAtkPartner, battlerAtk) == AI_IS_FASTER) // partner is going to set up before the potential Defog + && AI_WhoStrikesFirst(BATTLE_PARTNER(battlerAtk), battlerAtk) == AI_IS_FASTER) // partner is going to set up before the potential Defog { score -= 10; break; // Don't use Defog if partner is going to set up hazards @@ -1919,7 +1916,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // evasion check if (gBattleMons[battlerDef].statStages[STAT_EVASION] == MIN_STAT_STAGE - || ((AI_DATA->defAbility == ABILITY_CONTRARY) && !IsTargetingPartner(battlerAtk, battlerDef))) // don't want to raise target stats unless its your partner + || ((AI_DATA->abilities[battlerDef] == ABILITY_CONTRARY) && !IsTargetingPartner(battlerAtk, battlerDef))) // don't want to raise target stats unless its your partner score -= 10; break; @@ -1927,12 +1924,12 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) { - if (gBattleMons[battlerAtk].statStages[i] > DEFAULT_STAT_STAGE || gBattleMons[AI_DATA->battlerAtkPartner].statStages[i] > DEFAULT_STAT_STAGE) + if (gBattleMons[battlerAtk].statStages[i] > DEFAULT_STAT_STAGE || gBattleMons[BATTLE_PARTNER(battlerAtk)].statStages[i] > DEFAULT_STAT_STAGE) score -= 10; // Don't want to reset our boosted stats } for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) { - if (gBattleMons[battlerDef].statStages[i] < DEFAULT_STAT_STAGE || gBattleMons[AI_DATA->battlerDefPartner].statStages[i] < DEFAULT_STAT_STAGE) + if (gBattleMons[battlerDef].statStages[i] < DEFAULT_STAT_STAGE || gBattleMons[BATTLE_PARTNER(battlerDef)].statStages[i] < DEFAULT_STAT_STAGE) score -= 10; //Don't want to copy enemy lowered stats } } @@ -1940,8 +1937,8 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_SPECTRAL_THIEF: break; case EFFECT_SOLAR_BEAM: - if (AI_DATA->atkHoldEffect == HOLD_EFFECT_POWER_HERB - || (AI_WeatherHasEffect() && gBattleWeather & B_WEATHER_SUN && AI_DATA->atkHoldEffect != HOLD_EFFECT_UTILITY_UMBRELLA)) + if (AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_POWER_HERB + || (AI_WeatherHasEffect() && gBattleWeather & B_WEATHER_SUN && AI_DATA->holdEffects[battlerAtk] != HOLD_EFFECT_UTILITY_UMBRELLA)) break; if (CanTargetFaintAi(battlerDef, battlerAtk)) //Attacker can be knocked out score -= 4; @@ -1952,39 +1949,39 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) && gBattleMoves[predictedMove].effect == EFFECT_SEMI_INVULNERABLE) score -= 10; // Don't Fly/dig/etc if opponent is going to fly/dig/etc after you - if (BattlerWillFaintFromWeather(battlerAtk, AI_DATA->atkAbility) + if (BattlerWillFaintFromWeather(battlerAtk, AI_DATA->abilities[battlerAtk]) && (move == MOVE_FLY || move == MOVE_BOUNCE)) score -= 10; // Attacker will faint while in the air break; case EFFECT_HEALING_WISH: //healing wish, lunar dance - if (CountUsablePartyMons(battlerAtk) == 0 || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + if (CountUsablePartyMons(battlerAtk) == 0 || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) score -= 10; else if (IsPartyFullyHealedExceptBattler(battlerAtk)) score -= 10; break; case EFFECT_FINAL_GAMBIT: - if (CountUsablePartyMons(battlerAtk) == 0 || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + if (CountUsablePartyMons(battlerAtk) == 0 || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_NATURE_POWER: return AI_CheckBadMove(battlerAtk, battlerDef, GetNaturePowerMove(), score); case EFFECT_TAUNT: if (gDisableStructs[battlerDef].tauntTimer > 0 - || DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) score--; break; case EFFECT_BESTOW: - if (AI_DATA->atkHoldEffect == HOLD_EFFECT_NONE + if (AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_NONE || !CanBattlerGetOrLoseItem(battlerAtk, gBattleMons[battlerAtk].item)) // AI knows its own item score -= 10; break; case EFFECT_ROLE_PLAY: - if (AI_DATA->atkAbility == AI_DATA->defAbility - || AI_DATA->defAbility == ABILITY_NONE - || IsRolePlayBannedAbilityAtk(AI_DATA->atkAbility) - || IsRolePlayBannedAbility(AI_DATA->defAbility)) + if (AI_DATA->abilities[battlerAtk] == AI_DATA->abilities[battlerDef] + || AI_DATA->abilities[battlerDef] == ABILITY_NONE + || IsRolePlayBannedAbilityAtk(AI_DATA->abilities[battlerAtk]) + || IsRolePlayBannedAbility(AI_DATA->abilities[battlerDef])) score -= 10; - else if (IsAbilityOfRating(AI_DATA->atkAbility, 5)) + else if (IsAbilityOfRating(AI_DATA->abilities[battlerAtk], 5)) score -= 4; break; case EFFECT_WISH: @@ -2006,40 +2003,40 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_YAWN: if (gStatuses3[battlerDef] & STATUS3_YAWN) score -= 10; - else if (!AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) + else if (!AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_SKILL_SWAP: - if (AI_DATA->atkAbility == ABILITY_NONE || AI_DATA->defAbility == ABILITY_NONE - || IsSkillSwapBannedAbility(AI_DATA->atkAbility) || IsSkillSwapBannedAbility(AI_DATA->defAbility)) + if (AI_DATA->abilities[battlerAtk] == ABILITY_NONE || AI_DATA->abilities[battlerDef] == ABILITY_NONE + || IsSkillSwapBannedAbility(AI_DATA->abilities[battlerAtk]) || IsSkillSwapBannedAbility(AI_DATA->abilities[battlerDef])) score -= 10; break; case EFFECT_WORRY_SEED: - if (AI_DATA->defAbility == ABILITY_INSOMNIA - || IsWorrySeedBannedAbility(AI_DATA->defAbility)) + if (AI_DATA->abilities[battlerDef] == ABILITY_INSOMNIA + || IsWorrySeedBannedAbility(AI_DATA->abilities[battlerDef])) score -= 10; break; case EFFECT_GASTRO_ACID: if (gStatuses3[battlerDef] & STATUS3_GASTRO_ACID - || IsGastroAcidBannedAbility(AI_DATA->defAbility)) + || IsGastroAcidBannedAbility(AI_DATA->abilities[battlerDef])) score -= 10; break; case EFFECT_ENTRAINMENT: - if (AI_DATA->atkAbility == ABILITY_NONE - || IsEntrainmentBannedAbilityAttacker(AI_DATA->atkAbility) - || IsEntrainmentTargetOrSimpleBeamBannedAbility(AI_DATA->defAbility)) + if (AI_DATA->abilities[battlerAtk] == ABILITY_NONE + || IsEntrainmentBannedAbilityAttacker(AI_DATA->abilities[battlerAtk]) + || IsEntrainmentTargetOrSimpleBeamBannedAbility(AI_DATA->abilities[battlerDef])) score -= 10; break; case EFFECT_CORE_ENFORCER: break; case EFFECT_SIMPLE_BEAM: - if (AI_DATA->defAbility == ABILITY_SIMPLE - || IsEntrainmentTargetOrSimpleBeamBannedAbility(AI_DATA->defAbility)) + if (AI_DATA->abilities[battlerDef] == ABILITY_SIMPLE + || IsEntrainmentTargetOrSimpleBeamBannedAbility(AI_DATA->abilities[battlerDef])) score -= 10; break; case EFFECT_SNATCH: if (!TestMoveFlagsInMoveset(battlerDef, FLAG_SNATCH_AFFECTED) - || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_POWER_TRICK: @@ -2140,42 +2137,42 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_NATURAL_GIFT: - if (AI_DATA->atkAbility == ABILITY_KLUTZ + if (AI_DATA->abilities[battlerAtk] == ABILITY_KLUTZ || gFieldStatuses & STATUS_FIELD_MAGIC_ROOM || GetPocketByItemId(gBattleMons[battlerAtk].item) != POCKET_BERRIES) score -= 10; break; case EFFECT_GRASSY_TERRAIN: - if (PartnerMoveEffectIsTerrain(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove) || gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN) + if (PartnerMoveEffectIsTerrain(BATTLE_PARTNER(battlerAtk), AI_DATA->partnerMove) || gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN) score -= 10; break; case EFFECT_ELECTRIC_TERRAIN: - if (PartnerMoveEffectIsTerrain(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove) || gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) + if (PartnerMoveEffectIsTerrain(BATTLE_PARTNER(battlerAtk), AI_DATA->partnerMove) || gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) score -= 10; break; case EFFECT_PSYCHIC_TERRAIN: - if (PartnerMoveEffectIsTerrain(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove) || gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN) + if (PartnerMoveEffectIsTerrain(BATTLE_PARTNER(battlerAtk), AI_DATA->partnerMove) || gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN) score -= 10; break; case EFFECT_MISTY_TERRAIN: - if (PartnerMoveEffectIsTerrain(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove) || gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN) + if (PartnerMoveEffectIsTerrain(BATTLE_PARTNER(battlerAtk), AI_DATA->partnerMove) || gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN) score -= 10; break; case EFFECT_PLEDGE: - if (isDoubleBattle && gBattleMons[AI_DATA->battlerAtkPartner].hp > 0) + if (isDoubleBattle && gBattleMons[BATTLE_PARTNER(battlerAtk)].hp > 0) { if (AI_DATA->partnerMove != MOVE_NONE && gBattleMoves[AI_DATA->partnerMove].effect == EFFECT_PLEDGE && move != AI_DATA->partnerMove) // Different pledge moves { - if (gBattleMons[AI_DATA->battlerAtkPartner].status1 & (STATUS1_SLEEP | STATUS1_FREEZE)) - // && gBattleMons[AI_DATA->battlerAtkPartner].status1 != 1) // Will wake up this turn - how would AI know + if (gBattleMons[BATTLE_PARTNER(battlerAtk)].status1 & (STATUS1_SLEEP | STATUS1_FREEZE)) + // && gBattleMons[BATTLE_PARTNER(battlerAtk)].status1 != 1) // Will wake up this turn - how would AI know score -= 10; // Don't use combo move if your partner will cause failure } } break; case EFFECT_TRICK_ROOM: - if (PartnerMoveIs(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove, MOVE_TRICK_ROOM)) + if (PartnerMoveIs(BATTLE_PARTNER(battlerAtk), AI_DATA->partnerMove, MOVE_TRICK_ROOM)) { score -= 10; } @@ -2191,23 +2188,23 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_MAGIC_ROOM: - if (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM || PartnerMoveIsSameNoTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + if (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM || PartnerMoveIsSameNoTarget(BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_WONDER_ROOM: - if (gFieldStatuses & STATUS_FIELD_WONDER_ROOM || PartnerMoveIsSameNoTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + if (gFieldStatuses & STATUS_FIELD_WONDER_ROOM || PartnerMoveIsSameNoTarget(BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_GRAVITY: if ((gFieldStatuses & STATUS_FIELD_GRAVITY && !IS_BATTLER_OF_TYPE(battlerAtk, TYPE_FLYING) - && AI_DATA->atkHoldEffect != HOLD_EFFECT_AIR_BALLOON) // Should revert Gravity in this case - || PartnerMoveIsSameNoTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + && AI_DATA->holdEffects[battlerAtk] != HOLD_EFFECT_AIR_BALLOON) // Should revert Gravity in this case + || PartnerMoveIsSameNoTarget(BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_ION_DELUGE: if (gFieldStatuses & STATUS_FIELD_ION_DELUGE - || PartnerMoveIsSameNoTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + || PartnerMoveIsSameNoTarget(BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_FLING: @@ -2222,19 +2219,19 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) switch (effect) { case MOVE_EFFECT_BURN: - if (!AI_CanBurn(battlerAtk, battlerDef, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + if (!AI_CanBurn(battlerAtk, battlerDef, BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) score -= 10; break; case MOVE_EFFECT_PARALYSIS: - if (!AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) + if (!AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove)) score -= 10; break; case MOVE_EFFECT_POISON: - if (!AI_CanPoison(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) + if (!AI_CanPoison(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove)) score -= 10; break; case MOVE_EFFECT_TOXIC: - if (!AI_CanPoison(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) + if (!AI_CanPoison(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove)) score -= 10; break; case MOVE_EFFECT_FREEZE: @@ -2246,34 +2243,34 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_EMBARGO: - if (AI_DATA->defAbility == ABILITY_KLUTZ + if (AI_DATA->abilities[battlerDef] == ABILITY_KLUTZ || gFieldStatuses & STATUS_FIELD_MAGIC_ROOM || gDisableStructs[battlerDef].embargoTimer != 0 - || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_POWDER: if (!HasMoveWithType(battlerDef, TYPE_FIRE) - || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_TELEKINESIS: if (gStatuses3[battlerDef] & (STATUS3_TELEKINESIS | STATUS3_ROOTED | STATUS3_SMACKED_DOWN) || gFieldStatuses & STATUS_FIELD_GRAVITY - || AI_DATA->defHoldEffect == HOLD_EFFECT_IRON_BALL + || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_IRON_BALL || IsTelekinesisBannedSpecies(gBattleMons[battlerDef].species) - || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_THROAT_CHOP: break; case EFFECT_HEAL_BLOCK: if (gDisableStructs[battlerDef].healBlockTimer != 0 - || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_SOAK: - if (PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove) + if (PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove) || (gBattleMons[battlerDef].type1 == TYPE_WATER && gBattleMons[battlerDef].type2 == TYPE_WATER && gBattleMons[battlerDef].type3 == TYPE_MYSTERY)) @@ -2283,11 +2280,11 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) switch (move) { case MOVE_TRICK_OR_TREAT: - if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GHOST) || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GHOST) || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case MOVE_FORESTS_CURSE: - if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS) || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS) || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; } @@ -2318,7 +2315,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_ELECTRIFY: if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER //|| GetMoveTypeSpecial(battlerDef, predictedMove) == TYPE_ELECTRIC // Move will already be electric type - || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_TOPSY_TURVY: @@ -2328,7 +2325,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) u8 targetNegativeStages = CountNegativeStatStages(battlerDef); if (targetPositiveStages == 0 //No good stat changes to make bad - || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) score -= 10; else if (targetNegativeStages < targetPositiveStages) @@ -2336,7 +2333,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_FAIRY_LOCK: - if ((gFieldStatuses & STATUS_FIELD_FAIRY_LOCK) || PartnerMoveIsSameNoTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + if ((gFieldStatuses & STATUS_FIELD_FAIRY_LOCK) || PartnerMoveIsSameNoTarget(BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_DO_NOTHING: @@ -2359,7 +2356,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) #endif || (gLockedMoves[battlerDef] != 0 && gLockedMoves[battlerDef] != 0xFFFF) || gBattleMons[battlerDef].status2 & STATUS2_MULTIPLETURNS - || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) { score -= 10; } @@ -2386,14 +2383,14 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_QUASH: if (!isDoubleBattle || AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER - || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_AFTER_YOU: if (!IsTargetingPartner(battlerAtk, battlerDef) || !isDoubleBattle || AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER - || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) + || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_SUCKER_PUNCH: @@ -2405,19 +2402,19 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_TAILWIND: if (gSideTimers[GetBattlerSide(battlerAtk)].tailwindTimer != 0 - || PartnerMoveIs(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove, MOVE_TAILWIND) + || PartnerMoveIs(BATTLE_PARTNER(battlerAtk), AI_DATA->partnerMove, MOVE_TAILWIND) || (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer > 1)) // Trick Room active and not ending this turn score -= 10; break; case EFFECT_LUCKY_CHANT: if (gSideTimers[GET_BATTLER_SIDE(battlerAtk)].luckyChantTimer != 0 - || PartnerMoveIsSameNoTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + || PartnerMoveIsSameNoTarget(BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_MAGNET_RISE: if (gFieldStatuses & STATUS_FIELD_GRAVITY || gDisableStructs[battlerAtk].magnetRiseTimer != 0 - || AI_DATA->atkHoldEffect == HOLD_EFFECT_IRON_BALL + || AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_IRON_BALL || gStatuses3[battlerAtk] & (STATUS3_ROOTED | STATUS3_MAGNET_RISE | STATUS3_SMACKED_DOWN) || !IsBattlerGrounded(battlerAtk)) score -= 10; @@ -2432,7 +2429,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_SYNCHRONOISE: //Check holding ring target or is of same type - if (AI_DATA->defHoldEffect == HOLD_EFFECT_RING_TARGET + if (AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_RING_TARGET || IS_BATTLER_OF_TYPE(battlerDef, gBattleMons[battlerAtk].type1) || IS_BATTLER_OF_TYPE(battlerDef, gBattleMons[battlerAtk].type2) || IS_BATTLER_OF_TYPE(battlerDef, gBattleMons[battlerAtk].type3)) @@ -2443,16 +2440,16 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_ERUPTION: if (effectiveness <= AI_EFFECTIVENESS_x0_5) score--; - if (GetHealthPercentage(battlerDef) < 50) + if (AI_DATA->hpPercents[battlerDef] < 50) score--; break; case EFFECT_VITAL_THROW: - if (WillAIStrikeFirst() && GetHealthPercentage(battlerAtk) < 40) + if (WillAIStrikeFirst() && AI_DATA->hpPercents[battlerAtk] < 40) score--; // don't want to move last break; case EFFECT_FLAIL: if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER // Opponent should go first - || GetHealthPercentage(battlerAtk) > 50) + || AI_DATA->hpPercents[battlerAtk] > 50) score -= 4; break; //TODO @@ -2467,7 +2464,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 10; if (WillFaintFromWeather(battlerAtk) || MoveBlockedBySubstitute(move, battlerAtk, battlerDef) - || GetSpeciesWeight(gBattleMons[battlerDef].species, AI_DATA->defAbility, AI_DATA->defHoldEffect, battlerDef, TRUE) >= 2000) //200.0 kg + || GetSpeciesWeight(gBattleMons[battlerDef].species, AI_DATA->abilities[battlerDef], AI_DATA->holdEffects[battlerDef], battlerDef, TRUE) >= 2000) //200.0 kg score -= 10; break; */ @@ -2516,7 +2513,7 @@ static s16 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (GetMoveDamageResult(move) == MOVE_POWER_OTHER) score--; - switch (AI_GetMoveEffectiveness(move, battlerAtk, battlerDef)) + switch (AI_DATA->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex]) { case AI_EFFECTIVENESS_x4: if (WEATHER_HAS_EFFECT @@ -2569,13 +2566,13 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) u16 effect = gBattleMoves[move].effect; u16 target = gBattleMoves[move].target; // ally data - u8 battlerAtkPartner = AI_DATA->battlerAtkPartner; - u16 atkPartnerAbility = AI_DATA->atkPartnerAbility; - u16 atkPartnerHoldEffect = AI_DATA->atkPartnerHoldEffect; + u8 battlerAtkPartner = BATTLE_PARTNER(battlerAtk); + u16 atkPartnerAbility = AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)]; + u16 atkPartnerHoldEffect = AI_DATA->holdEffects[BATTLE_PARTNER(battlerAtk)]; bool32 partnerProtecting = (gBattleMoves[AI_DATA->partnerMove].effect == EFFECT_PROTECT); - bool32 attackerHasBadAbility = (GetAbilityRating(AI_DATA->atkAbility) < 0); + bool32 attackerHasBadAbility = (GetAbilityRating(AI_DATA->abilities[battlerAtk]) < 0); bool32 partnerHasBadAbility = (GetAbilityRating(atkPartnerAbility) < 0); - u16 predictedMove = gLastMoves[battlerDef]; //for now + u16 predictedMove = AI_DATA->predictedMoves[battlerDef]; SetTypeBeforeUsingMove(move, battlerAtk); GET_MOVE_TYPE(move, moveType); @@ -2598,7 +2595,7 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_ALWAYS_CRIT: // Ally decided to use Frost Breath on us. we must have Anger Point as our ability - if (AI_DATA->atkAbility == ABILITY_ANGER_POINT) + if (AI_DATA->abilities[battlerAtk] == ABILITY_ANGER_POINT) { if (AI_WhoStrikesFirst(battlerAtk, battlerAtkPartner) == AI_IS_SLOWER) // Partner moving first { @@ -2674,7 +2671,7 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (GetMoveDamageResult(move) == MOVE_POWER_OTHER) { // partner ability checks - if (!partnerProtecting && gBattleMoves[move].target != MOVE_TARGET_BOTH && !DoesBattlerIgnoreAbilityChecks(AI_DATA->atkAbility, move)) + if (!partnerProtecting && gBattleMoves[move].target != MOVE_TARGET_BOTH && !DoesBattlerIgnoreAbilityChecks(AI_DATA->abilities[battlerAtk], move)) { switch (atkPartnerAbility) { @@ -2822,14 +2819,14 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_SKILL_SWAP: - if (AI_DATA->atkAbility != AI_DATA->atkPartnerAbility && !attackerHasBadAbility) + if (AI_DATA->abilities[battlerAtk] != AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)] && !attackerHasBadAbility) { - if (AI_DATA->atkPartnerAbility == ABILITY_TRUANT) + if (AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_TRUANT) { RETURN_SCORE_PLUS(10); } - else if (AI_DATA->atkAbility == ABILITY_COMPOUND_EYES - && HasMoveWithLowAccuracy(battlerAtkPartner, FOE(battlerAtkPartner), 90, TRUE, atkPartnerAbility, AI_GetAbility(FOE(battlerAtkPartner)), atkPartnerHoldEffect, AI_GetHoldEffect(FOE(battlerAtkPartner)))) + else if (AI_DATA->abilities[battlerAtk] == ABILITY_COMPOUND_EYES + && HasMoveWithLowAccuracy(battlerAtkPartner, FOE(battlerAtkPartner), 90, TRUE, atkPartnerAbility, AI_DATA->abilities[FOE(battlerAtkPartner)], atkPartnerHoldEffect, AI_DATA->holdEffects[FOE(battlerAtkPartner)])) { RETURN_SCORE_PLUS(3); } @@ -2850,7 +2847,7 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_ENTRAINMENT: - if (partnerHasBadAbility && IsAbilityOfRating(AI_DATA->atkAbility, 0)) + if (partnerHasBadAbility && IsAbilityOfRating(AI_DATA->abilities[battlerAtk], 0)) { RETURN_SCORE_PLUS(1); } @@ -2900,9 +2897,9 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) switch (effect) { case EFFECT_SKILL_SWAP: - if (AI_DATA->atkAbility == ABILITY_TRUANT) + if (AI_DATA->abilities[battlerAtk] == ABILITY_TRUANT) score += 5; - else if (IsAbilityOfRating(AI_DATA->atkAbility, 0) || IsAbilityOfRating(AI_DATA->defAbility, 10)) + else if (IsAbilityOfRating(AI_DATA->abilities[battlerAtk], 0) || IsAbilityOfRating(AI_DATA->abilities[battlerDef], 10)) score += 2; // we want to transfer our bad ability or take their awesome ability break; case EFFECT_EARTHQUAKE: @@ -2933,13 +2930,11 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { // move data u16 moveEffect = gBattleMoves[move].effect; - u8 effectiveness = AI_GetMoveEffectiveness(move, battlerAtk, battlerDef); + u8 effectiveness = AI_DATA->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex]; u8 atkPriority = GetMovePriority(battlerAtk, move); - u16 predictedMove = gLastMoves[battlerDef]; //for now + u16 predictedMove = AI_DATA->predictedMoves[battlerDef]; bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk); u32 i; - u8 atkHpPercent = GetHealthPercentage(battlerAtk); - u8 defHpPercent = GetHealthPercentage(battlerDef); // Targeting partner, check benefits of doing that instead if (IsTargetingPartner(battlerAtk, battlerDef)) @@ -2959,7 +2954,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score++; // check already dead - if (!IsBattlerIncapacitated(battlerDef, AI_DATA->defAbility) + if (!IsBattlerIncapacitated(battlerDef, AI_DATA->abilities[battlerDef]) && CanTargetFaintAi(battlerAtk, battlerDef) && AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER) // Opponent should go first { @@ -2984,7 +2979,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // check burn if (gBattleMons[battlerAtk].status1 & STATUS1_BURN) { - switch (AI_DATA->atkAbility) + switch (AI_DATA->abilities[battlerAtk]) { case ABILITY_GUTS: break; @@ -3001,7 +2996,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } // attacker ability checks - switch (AI_DATA->atkAbility) + switch (AI_DATA->abilities[battlerAtk]) { case ABILITY_MOXIE: case ABILITY_BEAST_BOOST: @@ -3028,7 +3023,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) IncreaseSleepScore(battlerAtk, battlerDef, move, &score); break; case EFFECT_ABSORB: - if (AI_DATA->atkHoldEffect == HOLD_EFFECT_BIG_ROOT) + if (AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_BIG_ROOT) score++; if (effectiveness <= AI_EFFECTIVENESS_x0_5 && AI_RandLessThan(50)) score -= 3; @@ -3037,7 +3032,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_MEMENTO: if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_WILL_SUICIDE && gBattleMons[battlerDef].statStages[STAT_EVASION] < 7) { - if (atkHpPercent < 50 && AI_RandLessThan(128)) + if (AI_DATA->hpPercents[battlerAtk] < 50 && AI_RandLessThan(128)) score++; } break; @@ -3055,7 +3050,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } else if (gBattleMons[battlerAtk].statStages[STAT_ATK] < 9) { - if (atkHpPercent > 90 && AI_RandLessThan(128)) + if (AI_DATA->hpPercents[battlerAtk] > 90 && AI_RandLessThan(128)) { score += 2; break; @@ -3072,11 +3067,11 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_DEFENSE_UP_3: if (!HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL)) score -= 2; - if (atkHpPercent > 90 && AI_RandLessThan(128)) + if (AI_DATA->hpPercents[battlerAtk] > 90 && AI_RandLessThan(128)) score += 2; - else if (atkHpPercent > 70 && AI_RandLessThan(200)) + else if (AI_DATA->hpPercents[battlerAtk] > 70 && AI_RandLessThan(200)) break; - else if (atkHpPercent < 40) + else if (AI_DATA->hpPercents[battlerAtk] < 40) score -= 2; break; case EFFECT_SPEED_UP: @@ -3101,7 +3096,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } else if (gBattleMons[battlerAtk].statStages[STAT_SPATK] < 9) { - if (atkHpPercent > 90 && AI_RandLessThan(128)) + if (AI_DATA->hpPercents[battlerAtk] > 90 && AI_RandLessThan(128)) { score += 2; break; @@ -3117,29 +3112,29 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_SPECIAL_DEFENSE_UP_2: if (!HasMoveWithSplit(battlerDef, SPLIT_SPECIAL)) score -= 2; - if (atkHpPercent > 90 && AI_RandLessThan(128)) + if (AI_DATA->hpPercents[battlerAtk] > 90 && AI_RandLessThan(128)) score += 2; - else if (GetHealthPercentage(battlerAtk) > 70 && AI_RandLessThan(200)) + else if (AI_DATA->hpPercents[battlerAtk] > 70 && AI_RandLessThan(200)) break; - else if (GetHealthPercentage(battlerAtk) < 40) + else if (AI_DATA->hpPercents[battlerAtk] < 40) score -= 2; break; case EFFECT_ACCURACY_UP: case EFFECT_ACCURACY_UP_2: if (gBattleMons[battlerAtk].statStages[STAT_ACC] >= 9 && !AI_RandLessThan(50)) score -= 2; - else if (atkHpPercent <= 70) + else if (AI_DATA->hpPercents[battlerAtk] <= 70) score -= 2; else score++; break; case EFFECT_EVASION_UP: case EFFECT_EVASION_UP_2: - if (atkHpPercent > 90 && !AI_RandLessThan(100)) + if (AI_DATA->hpPercents[battlerAtk] > 90 && !AI_RandLessThan(100)) score += 3; if (gBattleMons[battlerAtk].statStages[STAT_EVASION] > 9 && AI_RandLessThan(128)) score--; - if ((gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY) && atkHpPercent >= 50 && !AI_RandLessThan(80)) + if ((gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY) && AI_DATA->hpPercents[battlerAtk] >= 50 && !AI_RandLessThan(80)) score += 3; if (gStatuses3[battlerDef] & STATUS3_LEECHSEED && !AI_RandLessThan(70)) score += 3; @@ -3147,9 +3142,9 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score += 2; if (gBattleMons[battlerDef].status2 & STATUS2_CURSED && !AI_RandLessThan(70)) score += 3; - if (atkHpPercent < 70 || gBattleMons[battlerAtk].statStages[STAT_EVASION] == DEFAULT_STAT_STAGE) + if (AI_DATA->hpPercents[battlerAtk] < 70 || gBattleMons[battlerAtk].statStages[STAT_EVASION] == DEFAULT_STAT_STAGE) break; - else if (atkHpPercent < 40 || defHpPercent < 40) + else if (AI_DATA->hpPercents[battlerAtk] < 40 || AI_DATA->hpPercents[battlerDef] < 40) score -= 2; else if (!AI_RandLessThan(70)) score -= 2; @@ -3157,24 +3152,24 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // stat lowering effects case EFFECT_ATTACK_DOWN: case EFFECT_ATTACK_DOWN_2: - if (!ShouldLowerAttack(battlerAtk, battlerDef, AI_DATA->defAbility)) + if (!ShouldLowerAttack(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef])) score -= 2; if (gBattleMons[battlerDef].statStages[STAT_ATK] < DEFAULT_STAT_STAGE) score--; - else if (atkHpPercent <= 90) + else if (AI_DATA->hpPercents[battlerAtk] <= 90) score--; if (gBattleMons[battlerDef].statStages[STAT_ATK] > 3 && !AI_RandLessThan(50)) score -= 2; - else if (defHpPercent < 70) + else if (AI_DATA->hpPercents[battlerDef] < 70) score -= 2; break; case EFFECT_DEFENSE_DOWN: case EFFECT_DEFENSE_DOWN_2: - if (!ShouldLowerDefense(battlerAtk, battlerDef, AI_DATA->defAbility)) + if (!ShouldLowerDefense(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef])) score -= 2; - if ((atkHpPercent < 70 && !AI_RandLessThan(50)) || (gBattleMons[battlerDef].statStages[STAT_DEF] <= 3 && !AI_RandLessThan(50))) + if ((AI_DATA->hpPercents[battlerAtk] < 70 && !AI_RandLessThan(50)) || (gBattleMons[battlerDef].statStages[STAT_DEF] <= 3 && !AI_RandLessThan(50))) score -= 2; - if (defHpPercent <= 70) + if (AI_DATA->hpPercents[battlerDef] <= 70) score -= 2; break; case EFFECT_SPEED_DOWN: @@ -3186,32 +3181,32 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_SPECIAL_ATTACK_DOWN: case EFFECT_SPECIAL_ATTACK_DOWN_2: - if (!ShouldLowerSpAtk(battlerAtk, battlerDef, AI_DATA->defAbility)) + if (!ShouldLowerSpAtk(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef])) score -= 2; if (gBattleMons[battlerDef].statStages[STAT_SPATK] < DEFAULT_STAT_STAGE) score--; - else if (atkHpPercent <= 90) + else if (AI_DATA->hpPercents[battlerAtk] <= 90) score--; if (gBattleMons[battlerDef].statStages[STAT_SPATK] > 3 && !AI_RandLessThan(50)) score -= 2; - else if (defHpPercent < 70) + else if (AI_DATA->hpPercents[battlerDef] < 70) score -= 2; break; case EFFECT_SPECIAL_DEFENSE_DOWN: case EFFECT_SPECIAL_DEFENSE_DOWN_2: - if (!ShouldLowerSpDef(battlerAtk, battlerDef, AI_DATA->defAbility)) + if (!ShouldLowerSpDef(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef])) score -= 2; - if ((atkHpPercent < 70 && !AI_RandLessThan(50)) + if ((AI_DATA->hpPercents[battlerAtk] < 70 && !AI_RandLessThan(50)) || (gBattleMons[battlerDef].statStages[STAT_SPDEF] <= 3 && !AI_RandLessThan(50))) score -= 2; - if (defHpPercent <= 70) + if (AI_DATA->hpPercents[battlerDef] <= 70) score -= 2; break; case EFFECT_ACCURACY_DOWN: case EFFECT_ACCURACY_DOWN_2: - if (ShouldLowerAccuracy(battlerAtk, battlerDef, AI_DATA->defAbility)) + if (ShouldLowerAccuracy(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef])) score -= 2; - if ((atkHpPercent < 70 || defHpPercent < 70) && AI_RandLessThan(100)) + if ((AI_DATA->hpPercents[battlerAtk] < 70 || AI_DATA->hpPercents[battlerDef] < 70) && AI_RandLessThan(100)) score--; if (gBattleMons[battlerDef].statStages[STAT_ACC] <= 4 && !AI_RandLessThan(80)) score -= 2; @@ -3223,26 +3218,26 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score++; if (gBattleMons[battlerDef].status2 & STATUS2_CURSED && !AI_RandLessThan(70)) score += 2; - if (atkHpPercent > 70 || gBattleMons[battlerDef].statStages[STAT_ACC] < DEFAULT_STAT_STAGE) + if (AI_DATA->hpPercents[battlerAtk] > 70 || gBattleMons[battlerDef].statStages[STAT_ACC] < DEFAULT_STAT_STAGE) break; - else if (atkHpPercent < 40 || defHpPercent < 40 || !AI_RandLessThan(70)) + else if (AI_DATA->hpPercents[battlerAtk] < 40 || AI_DATA->hpPercents[battlerDef] < 40 || !AI_RandLessThan(70)) score -= 2; break; case EFFECT_EVASION_DOWN: case EFFECT_EVASION_DOWN_2: - if (!ShouldLowerEvasion(battlerAtk, battlerDef, AI_DATA->defAbility)) + if (!ShouldLowerEvasion(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef])) score -= 2; - if ((atkHpPercent < 70 || gBattleMons[battlerDef].statStages[STAT_EVASION] <= 3) && !AI_RandLessThan(50)) + if ((AI_DATA->hpPercents[battlerAtk] < 70 || gBattleMons[battlerDef].statStages[STAT_EVASION] <= 3) && !AI_RandLessThan(50)) score -= 2; - if (defHpPercent <= 70) + if (AI_DATA->hpPercents[battlerDef] <= 70) score -= 2; if (gBattleMons[battlerAtk].statStages[STAT_ACC] < DEFAULT_STAT_STAGE) score++; - if (gBattleMons[battlerDef].statStages[STAT_EVASION] < 7 || AI_DATA->atkAbility == ABILITY_NO_GUARD) + if (gBattleMons[battlerDef].statStages[STAT_EVASION] < 7 || AI_DATA->abilities[battlerAtk] == ABILITY_NO_GUARD) score -= 2; break; case EFFECT_BIDE: - if (atkHpPercent < 90) + if (AI_DATA->hpPercents[battlerAtk] < 90) score -= 2; break; case EFFECT_DREAM_EATER: @@ -3258,7 +3253,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_GROWTH: case EFFECT_ATTACK_SPATK_UP: // work up - if (GetHealthPercentage(battlerAtk) <= 40 || AI_DATA->atkAbility == ABILITY_CONTRARY) + if (AI_DATA->hpPercents[battlerAtk] <= 40 || AI_DATA->abilities[battlerAtk] == ABILITY_CONTRARY) break; if (HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) @@ -3267,24 +3262,24 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPATK, &score); break; case EFFECT_HAZE: - if (AnyStatIsRaised(AI_DATA->battlerAtkPartner) - || PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + if (AnyStatIsRaised(BATTLE_PARTNER(battlerAtk)) + || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) score -= 3; break; // fallthrough case EFFECT_ROAR: case EFFECT_CLEAR_SMOG: if (isDoubleBattle) - score += min(CountPositiveStatStages(battlerDef) + CountPositiveStatStages(AI_DATA->battlerDefPartner), 7); + score += min(CountPositiveStatStages(battlerDef) + CountPositiveStatStages(BATTLE_PARTNER(battlerDef)), 7); else score += min(CountPositiveStatStages(battlerDef), 4); break; case EFFECT_MULTI_HIT: case EFFECT_DOUBLE_HIT: case EFFECT_TRIPLE_KICK: - if (AI_MoveMakesContact(AI_DATA->atkAbility, AI_DATA->atkHoldEffect, move) - && AI_DATA->atkAbility != ABILITY_MAGIC_GUARD - && AI_DATA->defHoldEffect == HOLD_EFFECT_ROCKY_HELMET) + if (AI_MoveMakesContact(AI_DATA->abilities[battlerAtk], AI_DATA->holdEffects[battlerAtk], move) + && AI_DATA->abilities[battlerAtk] != ABILITY_MAGIC_GUARD + && AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_ROCKY_HELMET) score -= 2; break; case EFFECT_CONVERSION: @@ -3292,7 +3287,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score++; break; case EFFECT_FLINCH_HIT: - score += ShouldTryToFlinch(battlerAtk, battlerDef, AI_DATA->atkAbility, AI_DATA->defAbility, move); + score += ShouldTryToFlinch(battlerAtk, battlerDef, AI_DATA->abilities[battlerAtk], AI_DATA->abilities[battlerDef], move); break; case EFFECT_SWALLOW: if (gDisableStructs[battlerAtk].stockpileCounter == 0) @@ -3329,7 +3324,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_MOONLIGHT: if (ShouldRecover(battlerAtk, battlerDef, move, 50)) score += 3; - if (AI_DATA->atkHoldEffect == HOLD_EFFECT_BIG_ROOT) + if (AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_BIG_ROOT) score++; break; case EFFECT_TOXIC: @@ -3342,26 +3337,26 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (ShouldSetScreen(battlerAtk, battlerDef, moveEffect)) { score += 5; - if (AI_DATA->atkHoldEffect == HOLD_EFFECT_LIGHT_CLAY) + if (AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_LIGHT_CLAY) score += 2; if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_SCREENER) score += 2; } break; case EFFECT_REST: - if (!(AI_CanSleep(battlerAtk, AI_DATA->atkAbility))) + if (!(AI_CanSleep(battlerAtk, AI_DATA->abilities[battlerAtk]))) { break; } else if (ShouldRecover(battlerAtk, battlerDef, move, 100)) { - if (AI_DATA->atkHoldEffect == HOLD_EFFECT_CURE_SLP - || AI_DATA->atkHoldEffect == HOLD_EFFECT_CURE_STATUS + if (AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_CURE_SLP + || AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_CURE_STATUS || HasMoveEffect(EFFECT_SLEEP_TALK, battlerAtk) || HasMoveEffect(EFFECT_SNORE, battlerAtk) - || AI_DATA->atkAbility == ABILITY_SHED_SKIN - || AI_DATA->atkAbility == ABILITY_EARLY_BIRD - || (gBattleWeather & B_WEATHER_RAIN && gWishFutureKnock.weatherDuration != 1 && AI_DATA->atkAbility == ABILITY_HYDRATION && AI_DATA->atkHoldEffect != HOLD_EFFECT_UTILITY_UMBRELLA)) + || AI_DATA->abilities[battlerAtk] == ABILITY_SHED_SKIN + || AI_DATA->abilities[battlerAtk] == ABILITY_EARLY_BIRD + || (gBattleWeather & B_WEATHER_RAIN && gWishFutureKnock.weatherDuration != 1 && AI_DATA->abilities[battlerAtk] == ABILITY_HYDRATION && AI_DATA->holdEffects[battlerAtk] != HOLD_EFFECT_UTILITY_UMBRELLA)) { score += 2; } @@ -3394,14 +3389,14 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_FOCUS_ENERGY: case EFFECT_LASER_FOCUS: - if (AI_DATA->atkAbility == ABILITY_SUPER_LUCK - || AI_DATA->atkAbility == ABILITY_SNIPER - || AI_DATA->atkHoldEffect == HOLD_EFFECT_SCOPE_LENS + if (AI_DATA->abilities[battlerAtk] == ABILITY_SUPER_LUCK + || AI_DATA->abilities[battlerAtk] == ABILITY_SNIPER + || AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_SCOPE_LENS || TestMoveFlagsInMoveset(battlerAtk, FLAG_HIGH_CRIT)) score += 2; break; case EFFECT_CONFUSE_HIT: - if (AI_DATA->atkAbility == ABILITY_SERENE_GRACE) + if (AI_DATA->abilities[battlerAtk] == ABILITY_SERENE_GRACE) score++; //fallthrough case EFFECT_CONFUSE: @@ -3420,7 +3415,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_SPECIAL_DEFENSE_DOWN_HIT: case EFFECT_ACCURACY_DOWN_HIT: case EFFECT_EVASION_DOWN_HIT: - if (AI_DATA->atkAbility == ABILITY_SERENE_GRACE && AI_DATA->defAbility != ABILITY_CONTRARY) + if (AI_DATA->abilities[battlerAtk] == ABILITY_SERENE_GRACE && AI_DATA->abilities[battlerDef] != ABILITY_CONTRARY) score += 2; break; case EFFECT_SPEED_DOWN_HIT: @@ -3428,12 +3423,12 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score -= 2; else if (!AI_RandLessThan(70)) score++; - if (AI_DATA->atkAbility == ABILITY_SERENE_GRACE && AI_DATA->defAbility != ABILITY_CONTRARY) + if (AI_DATA->abilities[battlerAtk] == ABILITY_SERENE_GRACE && AI_DATA->abilities[battlerDef] != ABILITY_CONTRARY) score++; break; - if (ShouldLowerSpeed(battlerAtk, battlerDef, AI_DATA->defAbility)) + if (ShouldLowerSpeed(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef])) { - if (AI_DATA->atkAbility == ABILITY_SERENE_GRACE && AI_DATA->defAbility != ABILITY_CONTRARY) + if (AI_DATA->abilities[battlerAtk] == ABILITY_SERENE_GRACE && AI_DATA->abilities[battlerDef] != ABILITY_CONTRARY) score += 4; else score += 2; @@ -3452,7 +3447,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) || HasMoveEffect(battlerDef, EFFECT_CONFUSE) || HasMoveEffect(battlerDef, EFFECT_LEECH_SEED)) score += 2; - if (!gBattleMons[battlerDef].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION && GetHealthPercentage(battlerAtk) > 70)) + if (!gBattleMons[battlerDef].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION && AI_DATA->hpPercents[battlerAtk] > 70)) score++; break; case EFFECT_MIMIC: @@ -3466,8 +3461,8 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS) || gStatuses3[battlerDef] & STATUS3_LEECHSEED || HasMoveEffect(battlerDef, EFFECT_RAPID_SPIN) - || AI_DATA->defAbility == ABILITY_LIQUID_OOZE - || AI_DATA->defAbility == ABILITY_MAGIC_GUARD) + || AI_DATA->abilities[battlerDef] == ABILITY_LIQUID_OOZE + || AI_DATA->abilities[battlerDef] == ABILITY_MAGIC_GUARD) break; score += 3; if (!HasDamagingMove(battlerDef) || IsBattlerTrapped(battlerDef, FALSE)) @@ -3484,7 +3479,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_PARTING_SHOT: if (!IsDoubleBattle()) { - switch (ShouldPivot(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_THINKING_STRUCT->movesetIndex)) + switch (ShouldPivot(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_THINKING_STRUCT->movesetIndex)) { case 0: // no score -= 10; // technically should go in CheckBadMove, but this is easier/less computationally demanding @@ -3513,7 +3508,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_DISABLE: if (gDisableStructs[battlerDef].disableTimer == 0 - && (B_MENTAL_HERB >= GEN_5 && AI_DATA->defHoldEffect != HOLD_EFFECT_MENTAL_HERB)) // mental herb + && (B_MENTAL_HERB >= GEN_5 && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB)) // mental herb { if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) // AI goes first { @@ -3535,7 +3530,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_ENCORE: if (gDisableStructs[battlerDef].encoreTimer == 0 - && (B_MENTAL_HERB >= GEN_5 && AI_DATA->defHoldEffect != HOLD_EFFECT_MENTAL_HERB)) // mental herb + && (B_MENTAL_HERB >= GEN_5 && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB)) // mental herb { if (IsEncoreEncouragedEffect(gBattleMoves[gLastMoves[battlerDef]].effect)) score += 3; @@ -3545,7 +3540,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { u16 newHp = (gBattleMons[battlerAtk].hp + gBattleMons[battlerDef].hp) / 2; u16 healthBenchmark = (gBattleMons[battlerAtk].hp * 12) / 10; - if (newHp > healthBenchmark && ShouldAbsorb(battlerAtk, battlerDef, move, AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex])) + if (newHp > healthBenchmark && ShouldAbsorb(battlerAtk, battlerDef, move, AI_DATA->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex])) score += 2; } break; @@ -3557,15 +3552,15 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_LOCK_ON: if (HasMoveEffect(battlerAtk, EFFECT_OHKO)) score += 3; - else if (AI_DATA->atkAbility == ABILITY_COMPOUND_EYES && HasMoveWithLowAccuracy(battlerAtk, battlerDef, 80, TRUE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect)) + else if (AI_DATA->abilities[battlerAtk] == ABILITY_COMPOUND_EYES && HasMoveWithLowAccuracy(battlerAtk, battlerDef, 80, TRUE, AI_DATA->abilities[battlerAtk], AI_DATA->abilities[battlerDef], AI_DATA->holdEffects[battlerAtk], AI_DATA->holdEffects[battlerDef])) score += 3; - else if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 85, TRUE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect)) + else if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 85, TRUE, AI_DATA->abilities[battlerAtk], AI_DATA->abilities[battlerDef], AI_DATA->holdEffects[battlerAtk], AI_DATA->holdEffects[battlerDef])) score += 3; - else if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, TRUE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect)) + else if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, TRUE, AI_DATA->abilities[battlerAtk], AI_DATA->abilities[battlerDef], AI_DATA->holdEffects[battlerAtk], AI_DATA->holdEffects[battlerDef])) score++; break; case EFFECT_SPEED_UP_HIT: - if (AI_DATA->atkAbility == ABILITY_SERENE_GRACE && AI_DATA->defAbility != ABILITY_CONTRARY && !WillAIStrikeFirst()) + if (AI_DATA->abilities[battlerAtk] == ABILITY_SERENE_GRACE && AI_DATA->abilities[battlerDef] != ABILITY_CONTRARY && !WillAIStrikeFirst()) score += 3; break; case EFFECT_DESTINY_BOND: @@ -3590,14 +3585,14 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER || GetBattlerSide(battlerAtk) == B_SIDE_PLAYER) canSteal = TRUE; - if (canSteal && AI_DATA->atkItem == ITEM_NONE - && AI_DATA->defItem != ITEM_NONE - && CanBattlerGetOrLoseItem(battlerDef, AI_DATA->defItem) - && CanBattlerGetOrLoseItem(battlerAtk, AI_DATA->defItem) + if (canSteal && AI_DATA->items[battlerAtk] == ITEM_NONE + && AI_DATA->items[battlerDef] != ITEM_NONE + && CanBattlerGetOrLoseItem(battlerDef, AI_DATA->items[battlerDef]) + && CanBattlerGetOrLoseItem(battlerAtk, AI_DATA->items[battlerDef]) && !HasMoveEffect(battlerAtk, EFFECT_ACROBATICS) - && AI_DATA->defAbility != ABILITY_STICKY_HOLD) + && AI_DATA->abilities[battlerDef] != ABILITY_STICKY_HOLD) { - switch (AI_DATA->defHoldEffect) + switch (AI_DATA->holdEffects[battlerDef]) { case HOLD_EFFECT_NONE: break; @@ -3607,11 +3602,11 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score += 2; break; case HOLD_EFFECT_TOXIC_ORB: - if (ShouldPoisonSelf(battlerAtk, AI_DATA->atkAbility)) + if (ShouldPoisonSelf(battlerAtk, AI_DATA->abilities[battlerAtk])) score += 2; break; case HOLD_EFFECT_FLAME_ORB: - if (ShouldBurnSelf(battlerAtk, AI_DATA->atkAbility)) + if (ShouldBurnSelf(battlerAtk, AI_DATA->abilities[battlerAtk])) score += 2; break; case HOLD_EFFECT_BLACK_SLUDGE: @@ -3634,9 +3629,9 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_NIGHTMARE: - if (AI_DATA->defAbility != ABILITY_MAGIC_GUARD + if (AI_DATA->abilities[battlerDef] != ABILITY_MAGIC_GUARD && !(gBattleMons[battlerDef].status2 & STATUS2_NIGHTMARE) - && (AI_DATA->defAbility == ABILITY_COMATOSE || gBattleMons[battlerDef].status1 & STATUS1_SLEEP)) + && (AI_DATA->abilities[battlerDef] == ABILITY_COMATOSE || gBattleMons[battlerDef].status1 & STATUS1_SLEEP)) { score += 5; if (IsBattlerTrapped(battlerDef, TRUE)) @@ -3654,7 +3649,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } else { - if (AI_DATA->atkAbility == ABILITY_CONTRARY || AI_DATA->defAbility == ABILITY_MAGIC_GUARD) + if (AI_DATA->abilities[battlerAtk] == ABILITY_CONTRARY || AI_DATA->abilities[battlerDef] == ABILITY_MAGIC_GUARD) break; else if (gBattleMons[battlerAtk].statStages[STAT_ATK] < 8) score += (8 - gBattleMons[battlerAtk].statStages[STAT_ATK]); @@ -3680,7 +3675,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } else if (isDoubleBattle && gBattleMoves[AI_DATA->partnerMove].target & MOVE_TARGET_FOES_AND_ALLY) { - if (AI_DATA->atkAbility != ABILITY_TELEPATHY) + if (AI_DATA->abilities[battlerAtk] != ABILITY_TELEPATHY) ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); } break; @@ -3696,9 +3691,9 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case MOVE_KINGS_SHIELD: #if (defined SPECIES_AEGISLASH && defined SPECIES_AEGISLASH_BLADE) - if (AI_DATA->atkAbility == ABILITY_STANCE_CHANGE //Special logic for Aegislash - && AI_DATA->atkSpecies == SPECIES_AEGISLASH_BLADE - && !IsBattlerIncapacitated(battlerDef, AI_DATA->defAbility)) + if (AI_DATA->abilities[battlerAtk] == ABILITY_STANCE_CHANGE //Special logic for Aegislash + && gBattleMons[battlerAtk].species == SPECIES_AEGISLASH_BLADE + && !IsBattlerIncapacitated(battlerDef, AI_DATA->abilities[battlerDef])) { score += 3; break; @@ -3714,7 +3709,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (CanTargetFaintAi(battlerDef, battlerAtk)) { if (gBattleMons[battlerAtk].hp > gBattleMons[battlerAtk].maxHP / 4 // Pinch berry couldn't have activated yet - && IsPinchBerryItemEffect(AI_DATA->atkHoldEffect)) + && IsPinchBerryItemEffect(AI_DATA->holdEffects[battlerAtk])) { score += 3; } @@ -3730,14 +3725,14 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_STEALTH_ROCK: case EFFECT_STICKY_WEB: case EFFECT_TOXIC_SPIKES: - if (AI_DATA->defAbility == ABILITY_MAGIC_BOUNCE || CountUsablePartyMons(battlerDef) == 0) + if (AI_DATA->abilities[battlerDef] == ABILITY_MAGIC_BOUNCE || CountUsablePartyMons(battlerDef) == 0) break; if (gDisableStructs[battlerAtk].isFirstTurn) score += 2; //TODO - track entire opponent party data to determine hazard effectiveness break; case EFFECT_FORESIGHT: - if (AI_DATA->atkAbility == ABILITY_SCRAPPY) + if (AI_DATA->abilities[battlerAtk] == ABILITY_SCRAPPY) break; else if (gBattleMons[battlerDef].statStages[STAT_EVASION] > DEFAULT_STAT_STAGE || (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GHOST) @@ -3755,10 +3750,10 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score += 3; break; case EFFECT_SANDSTORM: - if (ShouldSetSandstorm(battlerAtk, AI_DATA->atkHoldEffect, AI_DATA->atkHoldEffect)) + if (ShouldSetSandstorm(battlerAtk, AI_DATA->holdEffects[battlerAtk], AI_DATA->holdEffects[battlerAtk])) { score++; - if (AI_DATA->atkHoldEffect == HOLD_EFFECT_SMOOTH_ROCK) + if (AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_SMOOTH_ROCK) score++; if (HasMoveEffect(battlerDef, EFFECT_MORNING_SUN) || HasMoveEffect(battlerDef, EFFECT_SYNTHESIS) @@ -3767,14 +3762,14 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_HAIL: - if (ShouldSetHail(battlerAtk, AI_DATA->atkAbility, AI_DATA->atkHoldEffect)) + if (ShouldSetHail(battlerAtk, AI_DATA->abilities[battlerAtk], AI_DATA->holdEffects[battlerAtk])) { - if ((HasMoveEffect(battlerAtk, EFFECT_AURORA_VEIL) || HasMoveEffect(AI_DATA->battlerAtkPartner, EFFECT_AURORA_VEIL)) + if ((HasMoveEffect(battlerAtk, EFFECT_AURORA_VEIL) || HasMoveEffect(BATTLE_PARTNER(battlerAtk), EFFECT_AURORA_VEIL)) && ShouldSetScreen(battlerAtk, battlerDef, EFFECT_AURORA_VEIL)) score += 3; score++; - if (AI_DATA->atkHoldEffect == HOLD_EFFECT_ICY_ROCK) + if (AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_ICY_ROCK) score++; if (HasMoveEffect(battlerDef, EFFECT_MORNING_SUN) || HasMoveEffect(battlerDef, EFFECT_SYNTHESIS) @@ -3783,38 +3778,38 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_RAIN_DANCE: - if (ShouldSetRain(battlerAtk, AI_DATA->atkAbility, AI_DATA->atkHoldEffect)) + if (ShouldSetRain(battlerAtk, AI_DATA->abilities[battlerAtk], AI_DATA->holdEffects[battlerAtk])) { score++; - if (AI_DATA->atkHoldEffect == HOLD_EFFECT_DAMP_ROCK) + if (AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_DAMP_ROCK) score++; if (HasMoveEffect(battlerDef, EFFECT_MORNING_SUN) || HasMoveEffect(battlerDef, EFFECT_SYNTHESIS) || HasMoveEffect(battlerDef, EFFECT_MOONLIGHT)) score += 2; - if (HasMoveWithType(battlerDef, TYPE_FIRE) || HasMoveWithType(AI_DATA->battlerDefPartner, TYPE_FIRE)) + if (HasMoveWithType(battlerDef, TYPE_FIRE) || HasMoveWithType(BATTLE_PARTNER(battlerDef), TYPE_FIRE)) score++; } break; case EFFECT_SUNNY_DAY: - if (ShouldSetSun(battlerAtk, AI_DATA->atkAbility, AI_DATA->atkHoldEffect)) + if (ShouldSetSun(battlerAtk, AI_DATA->abilities[battlerAtk], AI_DATA->holdEffects[battlerAtk])) { score++; - if (AI_DATA->atkHoldEffect == HOLD_EFFECT_HEAT_ROCK) + if (AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_HEAT_ROCK) score++; - if (HasMoveWithType(battlerDef, TYPE_WATER) || HasMoveWithType(AI_DATA->battlerDefPartner, TYPE_WATER)) + if (HasMoveWithType(battlerDef, TYPE_WATER) || HasMoveWithType(BATTLE_PARTNER(battlerDef), TYPE_WATER)) score++; - if (HasMoveEffect(battlerDef, EFFECT_THUNDER) || HasMoveEffect(AI_DATA->battlerDefPartner, EFFECT_THUNDER)) + if (HasMoveEffect(battlerDef, EFFECT_THUNDER) || HasMoveEffect(BATTLE_PARTNER(battlerDef), EFFECT_THUNDER)) score++; } break; case EFFECT_ATTACK_UP_HIT: - if (AI_DATA->atkAbility == ABILITY_SERENE_GRACE) + if (AI_DATA->abilities[battlerAtk] == ABILITY_SERENE_GRACE) IncreaseStatUpScore(battlerAtk, battlerDef, STAT_ATK, &score); break; case EFFECT_FELL_STINGER: if (gBattleMons[battlerAtk].statStages[STAT_ATK] < MAX_STAT_STAGE - && AI_DATA->atkAbility != ABILITY_CONTRARY + && AI_DATA->abilities[battlerAtk] != ABILITY_CONTRARY && CanIndexMoveFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) { if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) // Attacker goes first @@ -3824,7 +3819,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_BELLY_DRUM: - if (!CanTargetFaintAi(battlerDef, battlerAtk) && HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL) && AI_DATA->atkAbility != ABILITY_CONTRARY) + if (!CanTargetFaintAi(battlerDef, battlerAtk) && HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL) && AI_DATA->abilities[battlerAtk] != ABILITY_CONTRARY) score += (MAX_STAT_STAGE - gBattleMons[battlerAtk].statStages[STAT_ATK]); break; case EFFECT_PSYCH_UP: @@ -3885,7 +3880,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score += 8; break; case EFFECT_STOCKPILE: - if (AI_DATA->atkAbility == ABILITY_CONTRARY) + if (AI_DATA->abilities[battlerAtk] == ABILITY_CONTRARY) break; if (HasMoveEffect(battlerAtk, EFFECT_SWALLOW) || HasMoveEffect(battlerAtk, EFFECT_SPIT_UP)) @@ -3908,7 +3903,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) || HasMoveEffect(battlerAtk, EFFECT_SPECTRAL_THIEF)) score++; - if (AI_DATA->defAbility == ABILITY_CONTRARY) + if (AI_DATA->abilities[battlerDef] == ABILITY_CONTRARY) score += 2; IncreaseConfusionScore(battlerAtk, battlerDef, move, &score); @@ -3918,17 +3913,17 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) || HasMoveEffect(battlerAtk, EFFECT_SPECTRAL_THIEF)) score += 2; - if (AI_DATA->defAbility == ABILITY_CONTRARY) + if (AI_DATA->abilities[battlerDef] == ABILITY_CONTRARY) score += 2; IncreaseConfusionScore(battlerAtk, battlerDef, move, &score); break; case EFFECT_FURY_CUTTER: - if (!isDoubleBattle && AI_DATA->atkHoldEffect == HOLD_EFFECT_METRONOME) + if (!isDoubleBattle && AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_METRONOME) score += 3; break; case EFFECT_ATTRACT: - if (!isDoubleBattle && BattlerWillFaintFromSecondaryDamage(battlerDef, AI_DATA->defAbility) + if (!isDoubleBattle && BattlerWillFaintFromSecondaryDamage(battlerDef, AI_DATA->abilities[battlerDef]) && AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER) // Target goes first break; // Don't use if the attract won't have a change to activate @@ -3974,15 +3969,15 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (isDoubleBattle) { if (IsHazardMoveEffect(gBattleMoves[AI_DATA->partnerMove].effect) // Partner is going to set up hazards - && AI_WhoStrikesFirst(battlerAtk, AI_DATA->battlerAtkPartner) == AI_IS_SLOWER) // Partner going first + && AI_WhoStrikesFirst(battlerAtk, BATTLE_PARTNER(battlerAtk)) == AI_IS_SLOWER) // Partner going first break; // Don't use Defog if partner is going to set up hazards } // check defog lowering evasion - if (ShouldLowerEvasion(battlerAtk, battlerDef, AI_DATA->defAbility)) + if (ShouldLowerEvasion(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef])) { if (gBattleMons[battlerDef].statStages[STAT_EVASION] > 7 - || HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, TRUE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect)) + || HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, TRUE, AI_DATA->abilities[battlerAtk], AI_DATA->abilities[battlerDef], AI_DATA->holdEffects[battlerAtk], AI_DATA->holdEffects[battlerDef])) score += 2; // encourage lowering evasion if they are evasive or we have a move with low accuracy else score++; @@ -4003,11 +3998,11 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_FOLLOW_ME: if (isDoubleBattle && move != MOVE_SPOTLIGHT - && !IsBattlerIncapacitated(battlerDef, AI_DATA->defAbility) - && (move != MOVE_RAGE_POWDER || IsAffectedByPowder(battlerDef, AI_DATA->defAbility, AI_DATA->defHoldEffect)) // Rage Powder doesn't affect powder immunities - && IsBattlerAlive(AI_DATA->battlerAtkPartner)) + && !IsBattlerIncapacitated(battlerDef, AI_DATA->abilities[battlerDef]) + && (move != MOVE_RAGE_POWDER || IsAffectedByPowder(battlerDef, AI_DATA->abilities[battlerDef], AI_DATA->holdEffects[battlerDef])) // Rage Powder doesn't affect powder immunities + && IsBattlerAlive(BATTLE_PARTNER(battlerAtk))) { - u16 predictedMoveOnPartner = gLastMoves[AI_DATA->battlerAtkPartner]; + u16 predictedMoveOnPartner = gLastMoves[BATTLE_PARTNER(battlerAtk)]; if (predictedMoveOnPartner != MOVE_NONE && !IS_MOVE_STATUS(predictedMoveOnPartner)) score += 3; } @@ -4028,7 +4023,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_TRICK: case EFFECT_BESTOW: - switch (AI_DATA->atkHoldEffect) + switch (AI_DATA->holdEffects[battlerAtk]) { case HOLD_EFFECT_CHOICE_SCARF: score += 2; // assume its beneficial @@ -4042,15 +4037,15 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score += 2; break; case HOLD_EFFECT_TOXIC_ORB: - if (!ShouldPoisonSelf(battlerAtk, AI_DATA->atkAbility)) + if (!ShouldPoisonSelf(battlerAtk, AI_DATA->abilities[battlerAtk])) score += 2; break; case HOLD_EFFECT_FLAME_ORB: - if (!ShouldBurnSelf(battlerAtk, AI_DATA->atkAbility) && AI_CanBeBurned(battlerAtk, AI_DATA->defAbility)) + if (!ShouldBurnSelf(battlerAtk, AI_DATA->abilities[battlerAtk]) && AI_CanBeBurned(battlerAtk, AI_DATA->abilities[battlerDef])) score += 2; break; case HOLD_EFFECT_BLACK_SLUDGE: - if (!IS_BATTLER_OF_TYPE(battlerDef, TYPE_POISON) && AI_DATA->defAbility != ABILITY_MAGIC_GUARD) + if (!IS_BATTLER_OF_TYPE(battlerDef, TYPE_POISON) && AI_DATA->abilities[battlerDef] != ABILITY_MAGIC_GUARD) score += 3; break; case HOLD_EFFECT_IRON_BALL: @@ -4062,9 +4057,9 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score += 3; break; case HOLD_EFFECT_UTILITY_UMBRELLA: - if (AI_DATA->atkAbility != ABILITY_SOLAR_POWER && AI_DATA->atkAbility != ABILITY_DRY_SKIN && AI_WeatherHasEffect()) + if (AI_DATA->abilities[battlerAtk] != ABILITY_SOLAR_POWER && AI_DATA->abilities[battlerAtk] != ABILITY_DRY_SKIN && AI_WeatherHasEffect()) { - switch (AI_DATA->defAbility) + switch (AI_DATA->abilities[battlerDef]) { case ABILITY_SWIFT_SWIM: if (gBattleWeather & B_WEATHER_RAIN) @@ -4081,26 +4076,26 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case HOLD_EFFECT_EJECT_BUTTON: //if (!IsRaidBattle() && IsDynamaxed(battlerDef) && gNewBS->dynamaxData.timer[battlerDef] > 1 && if (HasDamagingMove(battlerAtk) - || (isDoubleBattle && IsBattlerAlive(AI_DATA->battlerAtkPartner) && HasDamagingMove(AI_DATA->battlerAtkPartner))) + || (isDoubleBattle && IsBattlerAlive(BATTLE_PARTNER(battlerAtk)) && HasDamagingMove(BATTLE_PARTNER(battlerAtk)))) score += 2; // Force 'em out next turn break; default: - if (move != MOVE_BESTOW && AI_DATA->atkItem == ITEM_NONE) + if (move != MOVE_BESTOW && AI_DATA->items[battlerAtk] == ITEM_NONE) { - switch (AI_DATA->defHoldEffect) + switch (AI_DATA->holdEffects[battlerDef]) { case HOLD_EFFECT_CHOICE_BAND: break; case HOLD_EFFECT_TOXIC_ORB: - if (ShouldPoisonSelf(battlerAtk, AI_DATA->atkAbility)) + if (ShouldPoisonSelf(battlerAtk, AI_DATA->abilities[battlerAtk])) score += 2; break; case HOLD_EFFECT_FLAME_ORB: - if (ShouldBurnSelf(battlerAtk, AI_DATA->atkAbility)) + if (ShouldBurnSelf(battlerAtk, AI_DATA->abilities[battlerAtk])) score += 2; break; case HOLD_EFFECT_BLACK_SLUDGE: - if (IS_BATTLER_OF_TYPE(battlerAtk, TYPE_POISON) || AI_DATA->atkAbility == ABILITY_MAGIC_GUARD) + if (IS_BATTLER_OF_TYPE(battlerAtk, TYPE_POISON) || AI_DATA->abilities[battlerAtk] == ABILITY_MAGIC_GUARD) score += 3; break; case HOLD_EFFECT_IRON_BALL: @@ -4118,21 +4113,21 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_ROLE_PLAY: - if (!IsRolePlayBannedAbilityAtk(AI_DATA->atkAbility) - && !IsRolePlayBannedAbility(AI_DATA->defAbility) - && !IsAbilityOfRating(AI_DATA->atkAbility, 5) - && IsAbilityOfRating(AI_DATA->defAbility, 5)) + if (!IsRolePlayBannedAbilityAtk(AI_DATA->abilities[battlerAtk]) + && !IsRolePlayBannedAbility(AI_DATA->abilities[battlerDef]) + && !IsAbilityOfRating(AI_DATA->abilities[battlerAtk], 5) + && IsAbilityOfRating(AI_DATA->abilities[battlerDef], 5)) score += 2; break; case EFFECT_INGRAIN: - if (AI_DATA->atkHoldEffect == HOLD_EFFECT_BIG_ROOT) + if (AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_BIG_ROOT) score += 3; else score++; break; case EFFECT_SUPERPOWER: case EFFECT_OVERHEAT: - if (AI_DATA->atkAbility == ABILITY_CONTRARY) + if (AI_DATA->abilities[battlerAtk] == ABILITY_CONTRARY) score += 10; break; case EFFECT_MAGIC_COAT: @@ -4144,12 +4139,12 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score++; if (IsRecycleEncouragedItem(GetUsedHeldItem(battlerAtk))) score++; - if (AI_DATA->atkAbility == ABILITY_RIPEN) + if (AI_DATA->abilities[battlerAtk] == ABILITY_RIPEN) { u16 item = GetUsedHeldItem(battlerAtk); u16 toHeal = (ItemId_GetHoldEffectParam(item) == 10) ? 10 : gBattleMons[battlerAtk].maxHP / ItemId_GetHoldEffectParam(item); - if (IsStatBoostingBerry(item) && atkHpPercent > 60) + if (IsStatBoostingBerry(item) && AI_DATA->hpPercents[battlerAtk] > 60) score++; else if (ShouldRestoreHpBerry(battlerAtk, item) && !CanAIFaintTarget(battlerAtk, battlerDef, 0) && ((GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0 && CanTargetFaintAiWithMod(battlerDef, battlerAtk, 0, 0)) @@ -4166,9 +4161,9 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score++; break; case EFFECT_KNOCK_OFF: - if (CanKnockOffItem(battlerDef, AI_DATA->defItem)) + if (CanKnockOffItem(battlerDef, AI_DATA->items[battlerDef])) { - switch (AI_DATA->defHoldEffect) + switch (AI_DATA->holdEffects[battlerDef]) { case HOLD_EFFECT_IRON_BALL: if (HasMoveEffect(battlerDef, EFFECT_FLING)) @@ -4184,19 +4179,19 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_SKILL_SWAP: - if (GetAbilityRating(AI_DATA->defAbility) > GetAbilityRating(AI_DATA->atkAbility)) + if (GetAbilityRating(AI_DATA->abilities[battlerDef]) > GetAbilityRating(AI_DATA->abilities[battlerAtk])) score++; break; case EFFECT_WORRY_SEED: case EFFECT_GASTRO_ACID: case EFFECT_SIMPLE_BEAM: - if (IsAbilityOfRating(AI_DATA->defAbility, 5)) + if (IsAbilityOfRating(AI_DATA->abilities[battlerDef], 5)) score += 2; break; case EFFECT_ENTRAINMENT: - if (IsAbilityOfRating(AI_DATA->defAbility, 5) || GetAbilityRating(AI_DATA->atkAbility) <= 0) + if (IsAbilityOfRating(AI_DATA->abilities[battlerDef], 5) || GetAbilityRating(AI_DATA->abilities[battlerAtk]) <= 0) { - if (AI_DATA->defAbility != AI_DATA->atkAbility && !(gStatuses3[battlerDef] & STATUS3_GASTRO_ACID)) + if (AI_DATA->abilities[battlerDef] != AI_DATA->abilities[battlerAtk] && !(gStatuses3[battlerDef] & STATUS3_GASTRO_ACID)) score += 2; } break; @@ -4236,11 +4231,11 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_TICKLE: if (gBattleMons[battlerDef].statStages[STAT_DEF] > 4 && HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL) - && AI_DATA->defAbility != ABILITY_CONTRARY && ShouldLowerDefense(battlerAtk, battlerDef, AI_DATA->defAbility)) + && AI_DATA->abilities[battlerDef] != ABILITY_CONTRARY && ShouldLowerDefense(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef])) { score += 2; } - else if (ShouldLowerAttack(battlerAtk, battlerDef, AI_DATA->defAbility)) + else if (ShouldLowerAttack(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef])) { score += 2; } @@ -4258,7 +4253,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPDEF, &score); break; case EFFECT_GEOMANCY: - if (AI_DATA->atkHoldEffect == HOLD_EFFECT_POWER_HERB) + if (AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_POWER_HERB) score += 3; //fallthrough case EFFECT_QUIVER_DANCE: @@ -4267,7 +4262,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPDEF, &score); break; case EFFECT_SHELL_SMASH: - if (AI_DATA->atkHoldEffect == HOLD_EFFECT_POWER_HERB) + if (AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_POWER_HERB) score += 3; IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPEED, &score); @@ -4345,15 +4340,15 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_BUG_BITE: // And pluck - if (gBattleMons[battlerDef].status2 & STATUS2_SUBSTITUTE || AI_DATA->defAbility == ABILITY_STICKY_HOLD) + if (gBattleMons[battlerDef].status2 & STATUS2_SUBSTITUTE || AI_DATA->abilities[battlerDef] == ABILITY_STICKY_HOLD) break; - else if (ItemId_GetPocket(AI_DATA->defItem) == POCKET_BERRIES) + else if (ItemId_GetPocket(AI_DATA->items[battlerDef]) == POCKET_BERRIES) score += 3; break; case EFFECT_INCINERATE: - if (gBattleMons[battlerDef].status2 & STATUS2_SUBSTITUTE || AI_DATA->defAbility == ABILITY_STICKY_HOLD) + if (gBattleMons[battlerDef].status2 & STATUS2_SUBSTITUTE || AI_DATA->abilities[battlerDef] == ABILITY_STICKY_HOLD) break; - else if (ItemId_GetPocket(AI_DATA->defItem) == POCKET_BERRIES || AI_DATA->defHoldEffect == HOLD_EFFECT_GEMS) + else if (ItemId_GetPocket(AI_DATA->items[battlerDef]) == POCKET_BERRIES || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_GEMS) score += 3; break; case EFFECT_SMACK_DOWN: @@ -4362,9 +4357,9 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_RELIC_SONG: #if (defined SPECIES_MELOETTA && defined SPECIES_MELOETTA_PIROUETTE) - if (AI_DATA->atkSpecies == SPECIES_MELOETTA && gBattleMons[battlerDef].defense < gBattleMons[battlerDef].spDefense) + if (gBattleMons[battlerAtk].species == SPECIES_MELOETTA && gBattleMons[battlerDef].defense < gBattleMons[battlerDef].spDefense) score += 3; // Change to pirouette if can do more damage - else if (AI_DATA->atkSpecies == SPECIES_MELOETTA_PIROUETTE && gBattleMons[battlerDef].spDefense < gBattleMons[battlerDef].defense) + else if (gBattleMons[battlerAtk].species == SPECIES_MELOETTA_PIROUETTE && gBattleMons[battlerDef].spDefense < gBattleMons[battlerDef].defense) score += 3; // Change to Aria if can do more damage #endif break; @@ -4376,13 +4371,13 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_GRASSY_TERRAIN: case EFFECT_PSYCHIC_TERRAIN: score += 2; - if (AI_DATA->atkHoldEffect == HOLD_EFFECT_TERRAIN_EXTENDER) + if (AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_TERRAIN_EXTENDER) score += 2; break; case EFFECT_PLEDGE: if (isDoubleBattle) { - if (HasMoveEffect(AI_DATA->battlerAtkPartner, EFFECT_PLEDGE)) + if (HasMoveEffect(BATTLE_PARTNER(battlerAtk), EFFECT_PLEDGE)) score += 3; // Partner might use pledge move } break; @@ -4394,9 +4389,9 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_MAGIC_ROOM: score++; - if (AI_DATA->atkHoldEffect == HOLD_EFFECT_NONE && AI_DATA->defHoldEffect != HOLD_EFFECT_NONE) + if (AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_NONE && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_NONE) score++; - if (isDoubleBattle && AI_DATA->atkPartnerHoldEffect == HOLD_EFFECT_NONE && AI_DATA->defPartnerHoldEffect != HOLD_EFFECT_NONE) + if (isDoubleBattle && AI_DATA->holdEffects[BATTLE_PARTNER(battlerAtk)] == HOLD_EFFECT_NONE && AI_DATA->holdEffects[BATTLE_PARTNER(battlerDef)] != HOLD_EFFECT_NONE) score++; break; case EFFECT_WONDER_ROOM: @@ -4409,28 +4404,28 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { if (HasSleepMoveWithLowAccuracy(battlerAtk, battlerDef)) // Has Gravity for a move like Hypnosis IncreaseSleepScore(battlerAtk, battlerDef, move, &score); - else if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, FALSE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect)) + else if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, FALSE, AI_DATA->abilities[battlerAtk], AI_DATA->abilities[battlerDef], AI_DATA->holdEffects[battlerAtk], AI_DATA->holdEffects[battlerDef])) score += 2; else score++; } break; case EFFECT_ION_DELUGE: - if ((AI_DATA->atkAbility == ABILITY_VOLT_ABSORB - || AI_DATA->atkAbility == ABILITY_MOTOR_DRIVE - || AI_DATA->atkAbility == ABILITY_LIGHTNING_ROD) + if ((AI_DATA->abilities[battlerAtk] == ABILITY_VOLT_ABSORB + || AI_DATA->abilities[battlerAtk] == ABILITY_MOTOR_DRIVE + || AI_DATA->abilities[battlerAtk] == ABILITY_LIGHTNING_ROD) && gBattleMoves[predictedMove].type == TYPE_NORMAL) score += 2; break; case EFFECT_FLING: /* TODO - switch (gFlingTable[AI_DATA->atkItem].effect) + switch (gFlingTable[AI_DATA->items[battlerAtk]].effect) { case MOVE_EFFECT_BURN: IncreaseBurnScore(battlerAtk, battlerDef, move, &score); break; case MOVE_EFFECT_FLINCH: - score += ShouldTryToFlinch(battlerAtk, battlerDef, AI_DATA->atkAbility, AI_DATA->defAbility, move); + score += ShouldTryToFlinch(battlerAtk, battlerDef, AI_DATA->abilities[battlerAtk], AI_DATA->abilities[battlerDef], move); break; case MOVE_EFFECT_PARALYSIS: IncreaseParalyzeScore(battlerAtk, battlerDef, move, &score); @@ -4450,7 +4445,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score += 3; break; case EFFECT_EMBARGO: - if (AI_DATA->defHoldEffect != HOLD_EFFECT_NONE) + if (AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_NONE) score++; break; case EFFECT_POWDER: @@ -4458,7 +4453,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score += 3; break; case EFFECT_TELEKINESIS: - if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, FALSE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect) + if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, FALSE, AI_DATA->abilities[battlerAtk], AI_DATA->abilities[battlerDef], AI_DATA->holdEffects[battlerAtk], AI_DATA->holdEffects[battlerDef]) || !IsBattlerGrounded(battlerDef)) score++; break; @@ -4471,8 +4466,8 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_HEAL_BLOCK: if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER && predictedMove != MOVE_NONE && IsHealingMoveEffect(gBattleMoves[predictedMove].effect)) score += 3; // Try to cancel healing move - else if (HasHealingEffect(battlerDef) || AI_DATA->defHoldEffect == HOLD_EFFECT_LEFTOVERS - || (AI_DATA->defHoldEffect == HOLD_EFFECT_BLACK_SLUDGE && IS_BATTLER_OF_TYPE(battlerDef, TYPE_POISON))) + else if (HasHealingEffect(battlerDef) || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_LEFTOVERS + || (AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_BLACK_SLUDGE && IS_BATTLER_OF_TYPE(battlerDef, TYPE_POISON))) score += 2; break; case EFFECT_SOAK: @@ -4480,14 +4475,14 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score += 2; // Get some super effective moves break; case EFFECT_THIRD_TYPE: - if (AI_DATA->defAbility == ABILITY_WONDER_GUARD) + if (AI_DATA->abilities[battlerDef] == ABILITY_WONDER_GUARD) score += 2; // Give target more weaknesses break; case EFFECT_ELECTRIFY: if (predictedMove != MOVE_NONE && gBattleMoves[predictedMove].type == TYPE_NORMAL - && (AI_DATA->atkAbility == ABILITY_VOLT_ABSORB - || AI_DATA->atkAbility == ABILITY_MOTOR_DRIVE - || AI_DATA->atkAbility == ABILITY_LIGHTNING_ROD)) + && (AI_DATA->abilities[battlerAtk] == ABILITY_VOLT_ABSORB + || AI_DATA->abilities[battlerAtk] == ABILITY_MOTOR_DRIVE + || AI_DATA->abilities[battlerAtk] == ABILITY_LIGHTNING_ROD)) { score += 3; } @@ -4505,7 +4500,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_QUASH: if (isDoubleBattle - && AI_WhoStrikesFirst(AI_DATA->battlerAtkPartner, battlerDef) == AI_IS_SLOWER) // Attacker partner wouldn't go before target + && AI_WhoStrikesFirst(BATTLE_PARTNER(battlerAtk), battlerDef) == AI_IS_SLOWER) // Attacker partner wouldn't go before target score++; break; case EFFECT_TAILWIND: @@ -4549,10 +4544,10 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_FLAME_BURST: if (isDoubleBattle) { - if (IsBattlerAlive(AI_DATA->battlerDefPartner) - && GetHealthPercentage(AI_DATA->battlerDefPartner) < 12 - && AI_DATA->defPartnerAbility != ABILITY_MAGIC_GUARD - && !IS_BATTLER_OF_TYPE(AI_DATA->battlerDefPartner, TYPE_FIRE)) + if (IsBattlerAlive(BATTLE_PARTNER(battlerDef)) + && AI_DATA->hpPercents[BATTLE_PARTNER(battlerDef)] < 12 + && AI_DATA->abilities[BATTLE_PARTNER(battlerDef)] != ABILITY_MAGIC_GUARD + && !IS_BATTLER_OF_TYPE(BATTLE_PARTNER(battlerDef), TYPE_FIRE)) score++; } break; @@ -4563,11 +4558,11 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_TWO_TURNS_ATTACK: case EFFECT_SKULL_BASH: case EFFECT_SOLAR_BEAM: - if (AI_DATA->atkHoldEffect == HOLD_EFFECT_POWER_HERB) + if (AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_POWER_HERB) score += 2; break; case EFFECT_COUNTER: - if (!IsBattlerIncapacitated(battlerDef, AI_DATA->defAbility) && predictedMove != MOVE_NONE) + if (!IsBattlerIncapacitated(battlerDef, AI_DATA->abilities[battlerDef]) && predictedMove != MOVE_NONE) { if (gDisableStructs[battlerDef].tauntTimer != 0) score++; // target must use damaging move @@ -4576,7 +4571,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_MIRROR_COAT: - if (!IsBattlerIncapacitated(battlerDef, AI_DATA->defAbility) && predictedMove != MOVE_NONE) + if (!IsBattlerIncapacitated(battlerDef, AI_DATA->abilities[battlerDef]) && predictedMove != MOVE_NONE) { if (gDisableStructs[battlerDef].tauntTimer != 0) score++; // target must use damaging move @@ -4587,9 +4582,9 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_FLAIL: if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) // Ai goes first { - if (GetHealthPercentage(battlerAtk) < 20) + if (AI_DATA->hpPercents[battlerAtk] < 20) score++; - else if (GetHealthPercentage(battlerAtk) < 8) + else if (AI_DATA->hpPercents[battlerAtk] < 8) score += 2; } break; @@ -4607,7 +4602,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_FOCUS_PUNCH: if (!isDoubleBattle && effectiveness > AI_EFFECTIVENESS_x0_5) { - if (IsBattlerIncapacitated(battlerDef, AI_DATA->defAbility)) + if (IsBattlerIncapacitated(battlerDef, AI_DATA->abilities[battlerDef])) score += 2; else if (gBattleMons[battlerDef].status2 & (STATUS2_INFATUATION | STATUS2_CONFUSION)) score++; @@ -4629,10 +4624,10 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_ENDEAVOR: if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER) // Opponent faster { - if (GetHealthPercentage(battlerAtk) < 40) + if (AI_DATA->hpPercents[battlerAtk] < 40) score++; } - else if (GetHealthPercentage(battlerAtk) < 50) + else if (AI_DATA->hpPercents[battlerAtk] < 50) { score++; } @@ -4824,7 +4819,7 @@ static s16 AI_PreferBatonPass(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { if (gBattleResults.battleTurnCounter == 0) score += 5; - else if (GetHealthPercentage(battlerAtk) < 60) + else if (AI_DATA->hpPercents[battlerAtk] < 60) score -= 10; else score++; @@ -4875,21 +4870,21 @@ static s16 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (IsTargetingPartner(battlerAtk, battlerDef)) { if ((effect == EFFECT_HEAL_PULSE || effect == EFFECT_HIT_ENEMY_HEAL_ALLY) - || (moveType == TYPE_ELECTRIC && AI_DATA->atkPartnerAbility == ABILITY_VOLT_ABSORB) - || (moveType == TYPE_WATER && (AI_DATA->atkPartnerAbility == ABILITY_DRY_SKIN || AI_DATA->atkPartnerAbility == ABILITY_WATER_ABSORB))) + || (moveType == TYPE_ELECTRIC && AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_VOLT_ABSORB) + || (moveType == TYPE_WATER && (AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_DRY_SKIN || AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_WATER_ABSORB))) { - if (CanTargetFaintAi(FOE(battlerAtk), AI_DATA->battlerAtkPartner) - || (CanTargetFaintAi(BATTLE_PARTNER(FOE(battlerAtk)), AI_DATA->battlerAtkPartner))) + if (CanTargetFaintAi(FOE(battlerAtk), BATTLE_PARTNER(battlerAtk)) + || (CanTargetFaintAi(BATTLE_PARTNER(FOE(battlerAtk)), BATTLE_PARTNER(battlerAtk)))) score--; - if (GetHealthPercentage(battlerDef) <= 50) + if (AI_DATA->hpPercents[battlerDef] <= 50) score++; } } else { // Consider AI HP - if (GetHealthPercentage(battlerAtk) > 70) + if (AI_DATA->hpPercents[battlerAtk] > 70) { // high hp switch (effect) @@ -4915,7 +4910,7 @@ static s16 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; } } - else if (GetHealthPercentage(battlerAtk) > 30) + else if (AI_DATA->hpPercents[battlerAtk] > 30) { // med hp if (IsStatRaisingEffect(effect) || IsStatLoweringEffect(effect)) @@ -4984,12 +4979,12 @@ static s16 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } else { - if (GetHealthPercentage(battlerDef) > 70) + if (AI_DATA->hpPercents[battlerDef] > 70) { // high HP ; // nothing yet } - else if (GetHealthPercentage(battlerDef) > 30) + else if (AI_DATA->hpPercents[battlerDef] > 30) { // med HP - check discouraged effects switch (effect) @@ -5088,7 +5083,7 @@ static s16 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // First battle logic static s16 AI_FirstBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { - if (GetHealthPercentage(battlerDef) <= 20) + if (AI_DATA->hpPercents[battlerDef] <= 20) AI_Flee(); return score; diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index fb53bb801..54b368729 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -20,6 +20,8 @@ #include "constants/moves.h" #include "constants/items.h" +static u8 AI_GetEffectiveness(u16 multiplier); + // Const Data static const s8 sAiAbilityRatings[ABILITIES_COUNT] = { @@ -590,14 +592,14 @@ u32 GetHealthPercentage(u8 battlerId) bool32 AtMaxHp(u8 battlerId) { - if (GetHealthPercentage(battlerId) == 100) + if (AI_DATA->hpPercents[battlerId] == 100) return TRUE; return FALSE; } bool32 IsBattlerTrapped(u8 battler, bool8 checkSwitch) { - u8 holdEffect = AI_GetHoldEffect(battler); + u8 holdEffect = AI_DATA->holdEffects[battler]; if (IS_BATTLER_OF_TYPE(battler, TYPE_GHOST) || (checkSwitch && holdEffect == HOLD_EFFECT_SHED_SHELL) || (!checkSwitch && GetBattlerAbility(battler) == ABILITY_RUN_AWAY) @@ -658,7 +660,7 @@ bool32 MovesWithSplitUnusable(u32 attacker, u32 target, u32 split) { s32 i, moveType; u32 usable = 0; - u32 unusable = CheckMoveLimitations(attacker, 0, MOVE_LIMITATIONS_ALL); + u32 unusable = AI_DATA->moveLimitations[attacker]; u16 *moves = GetMovesArray(attacker); for (i = 0; i < MAX_MON_MOVES; i++) @@ -713,10 +715,11 @@ static bool32 AI_GetIfCrit(u32 move, u8 battlerAtk, u8 battlerDef) return isCrit; } -s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef) +s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef, u8 *typeEffectiveness) { s32 dmg, moveType, critDmg, normalDmg; s8 critChance; + u16 effectivenessMultiplier; SaveBattlerData(battlerAtk); SaveBattlerData(battlerDef); @@ -729,7 +732,7 @@ s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef) GET_MOVE_TYPE(move, moveType); critChance = GetInverseCritChance(battlerAtk, battlerDef, move); - normalDmg = CalculateMoveDamage(move, battlerAtk, battlerDef, moveType, 0, FALSE, FALSE, FALSE); + normalDmg = CalculateMoveDamageAndEffectiveness(move, battlerAtk, battlerDef, moveType, &effectivenessMultiplier); critDmg = CalculateMoveDamage(move, battlerAtk, battlerDef, moveType, 0, TRUE, FALSE, FALSE); if(critChance == -1) @@ -742,26 +745,26 @@ s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef) { case EFFECT_LEVEL_DAMAGE: case EFFECT_PSYWAVE: - dmg = gBattleMons[battlerAtk].level * (AI_DATA->atkAbility == ABILITY_PARENTAL_BOND ? 2 : 1); + dmg = gBattleMons[battlerAtk].level * (AI_DATA->abilities[battlerAtk] == ABILITY_PARENTAL_BOND ? 2 : 1); break; case EFFECT_DRAGON_RAGE: - dmg = 40 * (AI_DATA->atkAbility == ABILITY_PARENTAL_BOND ? 2 : 1); + dmg = 40 * (AI_DATA->abilities[battlerAtk] == ABILITY_PARENTAL_BOND ? 2 : 1); break; case EFFECT_SONICBOOM: - dmg = 20 * (AI_DATA->atkAbility == ABILITY_PARENTAL_BOND ? 2 : 1); + dmg = 20 * (AI_DATA->abilities[battlerAtk] == ABILITY_PARENTAL_BOND ? 2 : 1); break; case EFFECT_MULTI_HIT: - dmg *= (AI_DATA->atkAbility == ABILITY_SKILL_LINK ? 5 : 3); + dmg *= (AI_DATA->abilities[battlerAtk] == ABILITY_SKILL_LINK ? 5 : 3); break; case EFFECT_TRIPLE_KICK: - dmg *= (AI_DATA->atkAbility == ABILITY_SKILL_LINK ? 6 : 5); + dmg *= (AI_DATA->abilities[battlerAtk] == ABILITY_SKILL_LINK ? 6 : 5); break; case EFFECT_ENDEAVOR: // If target has less HP than user, Endeavor does no damage dmg = max(0, gBattleMons[battlerDef].hp - gBattleMons[battlerAtk].hp); break; case EFFECT_SUPER_FANG: - dmg = (AI_DATA->atkAbility == ABILITY_PARENTAL_BOND + dmg = (AI_DATA->abilities[battlerAtk] == ABILITY_PARENTAL_BOND ? max(2, gBattleMons[battlerDef].hp * 3 / 4) : max(1, gBattleMons[battlerDef].hp / 2)); break; @@ -778,6 +781,9 @@ s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef) RestoreBattlerData(battlerAtk); RestoreBattlerData(battlerDef); + + // convert multiper to AI_EFFECTIVENESS_xX + *typeEffectiveness = AI_GetEffectiveness(effectivenessMultiplier); return dmg; } @@ -785,10 +791,10 @@ s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef) // Checks if one of the moves has side effects or perks static u32 WhichMoveBetter(u32 move1, u32 move2) { - s32 defAbility = AI_GetAbility(gBattlerTarget); + s32 defAbility = AI_DATA->abilities[gBattlerTarget]; // Check if physical moves hurt. - if (AI_GetHoldEffect(sBattler_AI) != HOLD_EFFECT_PROTECTIVE_PADS + if (AI_DATA->holdEffects[sBattler_AI] != HOLD_EFFECT_PROTECTIVE_PADS && (BATTLE_HISTORY->itemEffects[gBattlerTarget] == HOLD_EFFECT_ROCKY_HELMET || defAbility == ABILITY_IRON_BARBS || defAbility == ABILITY_ROUGH_SKIN)) { @@ -868,7 +874,7 @@ u8 GetMoveDamageResult(u16 move) && sIgnoredPowerfulMoveEffects[i] == IGNORED_MOVES_END && gBattleMoves[gBattleMons[sBattler_AI].moves[checkedMove]].power != 0) { - moveDmgs[checkedMove] = AI_THINKING_STRUCT->simulatedDmg[sBattler_AI][gBattlerTarget][checkedMove]; + moveDmgs[checkedMove] = AI_DATA->simulatedDmg[sBattler_AI][gBattlerTarget][checkedMove]; } else { @@ -924,7 +930,7 @@ u8 GetMoveDamageResult(u16 move) u32 GetCurrDamageHpPercent(u8 battlerAtk, u8 battlerDef) { - int bestDmg = AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex]; + int bestDmg = AI_DATA->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex]; return (bestDmg * 100) / gBattleMons[battlerDef].maxHP; } @@ -952,37 +958,28 @@ u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef) u8 AI_GetMoveEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef) { - u8 damageVar; - u32 effectivenessMultiplier; - gMoveResultFlags = 0; - gCurrentMove = move; - effectivenessMultiplier = AI_GetTypeEffectiveness(gCurrentMove, battlerAtk, battlerDef); + return AI_GetEffectiveness(AI_GetTypeEffectiveness(move, battlerAtk, battlerDef)); +} - switch (effectivenessMultiplier) +static u8 AI_GetEffectiveness(u16 multiplier) +{ + switch (multiplier) { case UQ_4_12(0.0): default: - damageVar = AI_EFFECTIVENESS_x0; - break; + return AI_EFFECTIVENESS_x0; case UQ_4_12(0.25): - damageVar = AI_EFFECTIVENESS_x0_25; - break; + return AI_EFFECTIVENESS_x0_25; case UQ_4_12(0.5): - damageVar = AI_EFFECTIVENESS_x0_5; - break; + return AI_EFFECTIVENESS_x0_5; case UQ_4_12(1.0): - damageVar = AI_EFFECTIVENESS_x1; - break; + return AI_EFFECTIVENESS_x1; case UQ_4_12(2.0): - damageVar = AI_EFFECTIVENESS_x2; - break; + return AI_EFFECTIVENESS_x2; case UQ_4_12(4.0): - damageVar = AI_EFFECTIVENESS_x4; - break; + return AI_EFFECTIVENESS_x4; } - - return damageVar; } /* Checks to see if AI will move ahead of another battler @@ -1032,13 +1029,13 @@ u8 AI_WhoStrikesFirst(u8 battlerAI, u8 battler2) bool32 CanTargetFaintAi(u8 battlerDef, u8 battlerAtk) { s32 i, dmg; - u32 unusable = CheckMoveLimitations(battlerDef, 0, MOVE_LIMITATIONS_ALL); + u32 unusable = AI_DATA->moveLimitations[battlerDef]; u16 *moves = gBattleResources->battleHistory->usedMoves[battlerDef]; for (i = 0; i < MAX_MON_MOVES; i++) { if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && !(unusable & gBitTable[i]) - && AI_CalcDamage(moves[i], battlerDef, battlerAtk) >= gBattleMons[battlerAtk].hp) + && AI_DATA->simulatedDmg[battlerDef][battlerAtk][moves[i]] >= gBattleMons[battlerAtk].hp) { return TRUE; } @@ -1052,7 +1049,7 @@ bool32 CanTargetFaintAi(u8 battlerDef, u8 battlerAtk) bool32 CanAIFaintTarget(u8 battlerAtk, u8 battlerDef, u8 numHits) { s32 i, dmg; - u32 moveLimitations = CheckMoveLimitations(battlerAtk, 0, MOVE_LIMITATIONS_ALL); + u32 moveLimitations = AI_DATA->moveLimitations[battlerAtk]; u16 *moves = gBattleMons[battlerAtk].moves; for (i = 0; i < MAX_MON_MOVES; i++) @@ -1060,7 +1057,7 @@ bool32 CanAIFaintTarget(u8 battlerAtk, u8 battlerDef, u8 numHits) if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && !(moveLimitations & gBitTable[i])) { // Use the pre-calculated value in simulatedDmg instead of re-calculating it - dmg = AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][i]; + dmg = AI_DATA->simulatedDmg[battlerAtk][battlerDef][i]; if (numHits) dmg *= numHits; @@ -1076,9 +1073,13 @@ bool32 CanAIFaintTarget(u8 battlerAtk, u8 battlerDef, u8 numHits) bool32 CanMoveFaintBattler(u16 move, u8 battlerDef, u8 battlerAtk, u8 nHits) { s32 i, dmg; - u32 unusable = CheckMoveLimitations(battlerDef, 0, MOVE_LIMITATIONS_ALL); + u8 effectiveness; + u32 unusable = AI_DATA->moveLimitations[battlerDef]; - if (move != MOVE_NONE && move != 0xFFFF && !(unusable & gBitTable[i]) && AI_CalcDamage(move, battlerDef, battlerAtk) >= gBattleMons[battlerAtk].hp) + if (move != MOVE_NONE + && move != 0xFFFF + && !(unusable & gBitTable[i]) + && AI_CalcDamage(move, battlerDef, battlerAtk, &effectiveness) >= gBattleMons[battlerAtk].hp) return TRUE; return FALSE; @@ -1088,7 +1089,7 @@ bool32 CanMoveFaintBattler(u16 move, u8 battlerDef, u8 battlerAtk, u8 nHits) bool32 CanTargetFaintAiWithMod(u8 battlerDef, u8 battlerAtk, s32 hpMod, s32 dmgMod) { u32 i; - u32 unusable = CheckMoveLimitations(battlerDef, 0, MOVE_LIMITATIONS_ALL); + u32 unusable = AI_DATA->moveLimitations[battlerDef]; s32 dmg; u16 *moves = gBattleResources->battleHistory->usedMoves[battlerDef]; u32 hpCheck = gBattleMons[battlerAtk].hp + hpMod; @@ -1098,7 +1099,7 @@ bool32 CanTargetFaintAiWithMod(u8 battlerDef, u8 battlerAtk, s32 hpMod, s32 dmgM for (i = 0; i < MAX_MON_MOVES; i++) { - dmg = AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][i]; + dmg = AI_DATA->simulatedDmg[battlerAtk][battlerDef][i]; if (dmgMod) dmg *= dmgMod; @@ -1113,9 +1114,9 @@ bool32 CanTargetFaintAiWithMod(u8 battlerDef, u8 battlerAtk, s32 hpMod, s32 dmgM bool32 AI_IsAbilityOnSide(u32 battlerId, u32 ability) { - if (IsBattlerAlive(battlerId) && AI_GetAbility(battlerId) == ability) + if (IsBattlerAlive(battlerId) && AI_DATA->abilities[battlerId] == ability) return TRUE; - else if (IsBattlerAlive(BATTLE_PARTNER(battlerId)) && AI_GetAbility(BATTLE_PARTNER(battlerId)) == ability) + else if (IsBattlerAlive(BATTLE_PARTNER(battlerId)) && AI_DATA->abilities[BATTLE_PARTNER(battlerId)] == ability) return TRUE; else return FALSE; @@ -1172,7 +1173,7 @@ u16 AI_GetHoldEffect(u32 battlerId) return HOLD_EFFECT_NONE; if (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM) return HOLD_EFFECT_NONE; - if (AI_GetAbility(battlerId) == ABILITY_KLUTZ && !(gStatuses3[battlerId] & STATUS3_GASTRO_ACID)) + if (AI_DATA->abilities[battlerId] == ABILITY_KLUTZ && !(gStatuses3[battlerId] & STATUS3_GASTRO_ACID)) return HOLD_EFFECT_NONE; return holdEffect; @@ -1190,7 +1191,7 @@ bool32 AI_IsTerrainAffected(u8 battlerId, u32 flags) // different from IsBattlerGrounded in that we don't always know battler's hold effect or ability bool32 AI_IsBattlerGrounded(u8 battlerId) { - u32 holdEffect = AI_GetHoldEffect(battlerId); + u32 holdEffect = AI_DATA->holdEffects[battlerId]; if (holdEffect == HOLD_EFFECT_IRON_BALL) return TRUE; @@ -1206,7 +1207,7 @@ bool32 AI_IsBattlerGrounded(u8 battlerId) return FALSE; else if (holdEffect == HOLD_EFFECT_AIR_BALLOON) return FALSE; - else if (AI_GetAbility(battlerId) == ABILITY_LEVITATE) + else if (AI_DATA->abilities[battlerId] == ABILITY_LEVITATE) return FALSE; else if (IS_BATTLER_OF_TYPE(battlerId, TYPE_FLYING)) return FALSE; @@ -1241,14 +1242,7 @@ bool32 AI_WeatherHasEffect(void) if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_UNAWARE) return TRUE; // AI doesn't understand weather supression (handicap) - // need to manually check since we don't necessarily know opponent ability - for (i = 0; i < gBattlersCount; i++) - { - if (IsBattlerAlive(i) - && (AI_GetAbility(i) == ABILITY_AIR_LOCK || AI_GetAbility(i) == ABILITY_CLOUD_NINE)) - return FALSE; - } - return TRUE; + return WEATHER_HAS_EFFECT; // weather damping abilities are announced } bool32 IsAromaVeilProtectedMove(u16 move) @@ -1350,70 +1344,10 @@ bool32 IsMoveRedirectionPrevented(u16 move, u16 atkAbility) return FALSE; } -// differs from GetTotalAccuracy in that we need to check AI history for item, ability, etc -u32 AI_GetMoveAccuracy(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u8 atkHoldEffect, u8 defHoldEffect, u16 move) +u32 AI_GetMoveAccuracy(u8 battlerAtk, u8 battlerDef, u16 move) { - u32 calc, moveAcc, atkParam, defParam; - s8 buff, accStage, evasionStage; - - gPotentialItemEffectBattler = battlerDef; - accStage = gBattleMons[battlerAtk].statStages[STAT_ACC]; - evasionStage = gBattleMons[battlerDef].statStages[STAT_EVASION]; - if (atkAbility == ABILITY_UNAWARE) - evasionStage = DEFAULT_STAT_STAGE; - if (gBattleMoves[move].flags & FLAG_STAT_STAGES_IGNORED) - evasionStage = DEFAULT_STAT_STAGE; - if (defAbility == ABILITY_UNAWARE) - accStage = DEFAULT_STAT_STAGE; - - if (gBattleMons[battlerDef].status2 & STATUS2_FORESIGHT || gStatuses3[battlerDef] & STATUS3_MIRACLE_EYED) - buff = accStage; - else - buff = accStage + DEFAULT_STAT_STAGE - evasionStage; - - if (buff < MIN_STAT_STAGE) - buff = MIN_STAT_STAGE; - if (buff > MAX_STAT_STAGE) - buff = MAX_STAT_STAGE; - - moveAcc = gBattleMoves[move].accuracy; - // Check Thunder and Hurricane on sunny weather. - if (WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_SUN - && (gBattleMoves[move].effect == EFFECT_THUNDER || gBattleMoves[move].effect == EFFECT_HURRICANE)) - moveAcc = 50; - // Check Wonder Skin. - if (defAbility == ABILITY_WONDER_SKIN && gBattleMoves[move].power == 0) - moveAcc = 50; - - calc = gAccuracyStageRatios[buff].dividend * moveAcc; - calc /= gAccuracyStageRatios[buff].divisor; - - if (atkAbility == ABILITY_COMPOUND_EYES) - calc = (calc * 130) / 100; // 1.3 compound eyes boost - else if (atkAbility == ABILITY_VICTORY_STAR) - calc = (calc * 110) / 100; // 1.1 victory star boost - if (IsBattlerAlive(BATTLE_PARTNER(battlerAtk)) && GetBattlerAbility(BATTLE_PARTNER(battlerAtk)) == ABILITY_VICTORY_STAR) - calc = (calc * 110) / 100; // 1.1 ally's victory star boost - - if (defAbility == ABILITY_SAND_VEIL && WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_SANDSTORM) - calc = (calc * 80) / 100; // 1.2 sand veil loss - else if (defAbility == ABILITY_SNOW_CLOAK && WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_HAIL) - calc = (calc * 80) / 100; // 1.2 snow cloak loss - else if (defAbility == ABILITY_TANGLED_FEET && gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) - calc = (calc * 50) / 100; // 1.5 tangled feet loss - - if (atkAbility == ABILITY_HUSTLE && IS_MOVE_PHYSICAL(move)) - calc = (calc * 80) / 100; // 1.2 hustle loss - - if (defHoldEffect == HOLD_EFFECT_EVASION_UP) - calc = (calc * (100 - defParam)) / 100; - - if (atkHoldEffect == HOLD_EFFECT_WIDE_LENS) - calc = (calc * (100 + atkParam)) / 100; - else if (atkHoldEffect == HOLD_EFFECT_ZOOM_LENS && GetBattlerTurnOrderNum(battlerAtk) > GetBattlerTurnOrderNum(battlerDef)); - calc = (calc * (100 + atkParam)) / 100; - - return calc; + return GetTotalAccuracy(battlerAtk, battlerDef, move, AI_DATA->abilities[battlerAtk], AI_DATA->abilities[battlerDef], + AI_DATA->holdEffects[battlerAtk], AI_DATA->holdEffects[battlerDef]); } bool32 IsSemiInvulnerable(u8 battlerDef, u16 move) @@ -1441,7 +1375,7 @@ bool32 IsMoveEncouragedToHit(u8 battlerAtk, u8 battlerDef, u16 move) if (gStatuses3[battlerDef] & STATUS3_ALWAYS_HITS || gDisableStructs[battlerDef].battlerWithSureHit == battlerAtk) return TRUE; - if (AI_GetAbility(battlerDef) == ABILITY_NO_GUARD || AI_GetAbility(battlerAtk) == ABILITY_NO_GUARD) + if (AI_DATA->abilities[battlerDef] == ABILITY_NO_GUARD || AI_DATA->abilities[battlerAtk] == ABILITY_NO_GUARD) return TRUE; if (B_TOXIC_NEVER_MISS >= GEN_6 && gBattleMoves[move].effect == EFFECT_TOXIC && IS_BATTLER_OF_TYPE(battlerAtk, TYPE_POISON)) @@ -1466,12 +1400,13 @@ bool32 IsMoveEncouragedToHit(u8 battlerAtk, u8 battlerDef, u16 move) return FALSE; } -bool32 ShouldTryOHKO(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u32 accuracy, u16 move) +bool32 ShouldTryOHKO(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u16 move) { - u32 holdEffect = AI_GetHoldEffect(battlerDef); + u32 holdEffect = AI_DATA->holdEffects[battlerDef]; + u32 accuracy = AI_GetMoveAccuracy(battlerAtk, battlerDef, move); gPotentialItemEffectBattler = battlerDef; - if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < GetBattlerHoldEffectParam(battlerDef)) + if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < AI_DATA->holdEffectParams[battlerDef]) return FALSE; //probabilistically speaking, focus band should activate so dont OHKO else if (holdEffect == HOLD_EFFECT_FOCUS_SASH && AtMaxHp(battlerDef)) return FALSE; @@ -1599,7 +1534,7 @@ void ProtectChecks(u8 battlerAtk, u8 battlerDef, u16 move, u16 predictedMove, s1 { // TODO more sophisticated logic u16 predictedEffect = gBattleMoves[predictedMove].effect; - u8 defAbility = AI_GetAbility(battlerDef); + u8 defAbility = AI_DATA->abilities[battlerDef]; u32 uses = gDisableStructs[battlerAtk].protectUses; /*if (GetMoveResultFlags(predictedMove) & (MOVE_RESULT_NO_EFFECT | MOVE_RESULT_MISSED)) @@ -1814,7 +1749,7 @@ bool32 ShouldLowerEvasion(u8 battlerAtk, u8 battlerDef, u16 defAbility) bool32 CanIndexMoveFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index, u8 numHits) { - s32 dmg = AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][index]; + s32 dmg = AI_DATA->simulatedDmg[battlerAtk][battlerDef][index]; if (numHits) dmg *= numHits; @@ -1908,7 +1843,7 @@ bool32 HasMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef, u8 accCheck, bool32 { s32 i; u16 *moves = GetMovesArray(battlerAtk); - u8 moveLimitations = CheckMoveLimitations(battlerAtk, 0, MOVE_LIMITATIONS_ALL); + u8 moveLimitations = AI_DATA->moveLimitations[battlerAtk]; for (i = 0; i < MAX_MON_MOVES; i++) { @@ -1923,7 +1858,7 @@ bool32 HasMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef, u8 accCheck, bool32 || gBattleMoves[moves[i]].target & (MOVE_TARGET_USER | MOVE_TARGET_OPPONENTS_FIELD)) continue; - if (AI_GetMoveAccuracy(battlerAtk, battlerDef, atkAbility, defAbility, atkHoldEffect, defHoldEffect, moves[i]) <= accCheck) + if (AI_GetMoveAccuracy(battlerAtk, battlerDef, moves[i]) <= accCheck) return TRUE; } } @@ -1933,7 +1868,7 @@ bool32 HasMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef, u8 accCheck, bool32 bool32 HasSleepMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef) { - u8 moveLimitations = CheckMoveLimitations(battlerAtk, 0, MOVE_LIMITATIONS_ALL); + u8 moveLimitations = AI_DATA->moveLimitations[battlerAtk]; u32 i; u16 *moves = GetMovesArray(battlerAtk); @@ -1944,7 +1879,7 @@ bool32 HasSleepMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef) if (!(gBitTable[i] & moveLimitations)) { if (gBattleMoves[moves[i]].effect == EFFECT_SLEEP - && AI_GetMoveAccuracy(battlerAtk, battlerDef, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect, moves[i]) < 85) + && AI_GetMoveAccuracy(battlerAtk, battlerDef, moves[i]) < 85) return TRUE; } } @@ -2259,7 +2194,7 @@ static u32 GetTrapDamage(u8 battlerId) { // ai has no knowledge about turns remaining u32 damage = 0; - u32 holdEffect = AI_GetHoldEffect(gBattleStruct->wrappedBy[battlerId]); + u32 holdEffect = AI_DATA->holdEffects[gBattleStruct->wrappedBy[battlerId]]; if (gBattleMons[battlerId].status2 & STATUS2_WRAPPED) { if (holdEffect == HOLD_EFFECT_BINDING_BAND) @@ -2277,7 +2212,7 @@ static u32 GetPoisonDamage(u8 battlerId) { u32 damage = 0; - if (AI_GetAbility(battlerId) == ABILITY_POISON_HEAL) + if (AI_DATA->abilities[battlerId] == ABILITY_POISON_HEAL) return damage; if (gBattleMons[battlerId].status1 & STATUS1_POISON) @@ -2323,8 +2258,8 @@ static bool32 BattlerAffectedByHail(u8 battlerId, u16 ability) static u32 GetWeatherDamage(u8 battlerId) { - u32 ability = AI_GetAbility(battlerId); - u32 holdEffect = AI_GetHoldEffect(battlerId); + u32 ability = AI_DATA->abilities[battlerId]; + u32 holdEffect = AI_DATA->holdEffects[battlerId]; u32 damage = 0; if (!AI_WeatherHasEffect()) return 0; @@ -2358,7 +2293,7 @@ u32 GetBattlerSecondaryDamage(u8 battlerId) { u32 secondaryDamage; - if (AI_GetAbility(battlerId) == ABILITY_MAGIC_GUARD) + if (AI_DATA->abilities[battlerId] == ABILITY_MAGIC_GUARD) return FALSE; secondaryDamage = GetLeechSeedDamage(battlerId) @@ -2485,13 +2420,13 @@ bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 mo return PIVOT; // Won't get the two turns, pivot if (!IS_MOVE_STATUS(move) && (shouldSwitch - || (AtMaxHp(battlerDef) && (AI_DATA->defHoldEffect == HOLD_EFFECT_FOCUS_SASH + || (AtMaxHp(battlerDef) && (AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH || defAbility == ABILITY_STURDY || defAbility == ABILITY_MULTISCALE || defAbility == ABILITY_SHADOW_SHIELD)))) return PIVOT; // pivot to break sash/sturdy/multiscale } else if (!hasStatBoost) { - if (!IS_MOVE_STATUS(move) && (AtMaxHp(battlerDef) && (AI_DATA->defHoldEffect == HOLD_EFFECT_FOCUS_SASH + if (!IS_MOVE_STATUS(move) && (AtMaxHp(battlerDef) && (AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH || defAbility == ABILITY_STURDY || defAbility == ABILITY_MULTISCALE || defAbility == ABILITY_SHADOW_SHIELD))) return PIVOT; // pivot to break sash/sturdy/multiscale @@ -2502,7 +2437,7 @@ bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 mo if (gSideStatuses[battlerAtk] & SIDE_STATUS_SPIKES && switchScore >= SWITCHING_INCREASE_CAN_REMOVE_HAZARDS) return PIVOT;*/ - /*if (BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->atkAbility) && switchScore >= SWITCHING_INCREASE_WALLS_FOE) + /*if (BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->abilities[battlerAtk]) && switchScore >= SWITCHING_INCREASE_WALLS_FOE) return PIVOT;*/ /*if (IsClassDamager(class) && switchScore >= SWITCHING_INCREASE_HAS_SUPER_EFFECTIVE_MOVE) @@ -2545,7 +2480,7 @@ bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 mo { if (CanAIFaintTarget(battlerAtk, battlerDef, 0)) { - if (!BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->atkAbility)) + if (!BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->abilities[battlerAtk])) return CAN_TRY_PIVOT; // Use this move to KO if you must } else // Can't KO the foe @@ -2557,7 +2492,7 @@ bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 mo { if (CanAIFaintTarget(battlerAtk, battlerDef, 0)) { - if (!BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->atkAbility) // This is the only move that can KO + if (!BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->abilities[battlerAtk]) // This is the only move that can KO && !hasStatBoost) //You're not wasting a valuable stat boost { return CAN_TRY_PIVOT; @@ -2568,7 +2503,7 @@ bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 mo // can knock out foe in 2 hits if (IS_MOVE_STATUS(move) && (shouldSwitch //Damaging move //&& (switchScore >= SWITCHING_INCREASE_RESIST_ALL_MOVES + SWITCHING_INCREASE_KO_FOE //remove hazards - || (AI_DATA->defHoldEffect == HOLD_EFFECT_FOCUS_SASH && AtMaxHp(battlerDef)))) + || (AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH && AtMaxHp(battlerDef)))) return DONT_PIVOT; // Pivot to break the sash else return CAN_TRY_PIVOT; @@ -2637,7 +2572,7 @@ bool32 CanKnockOffItem(u8 battler, u16 item) )) && GetBattlerSide(battler) == B_SIDE_PLAYER) return FALSE; - if (AI_GetAbility(battler) == ABILITY_STICKY_HOLD) + if (AI_DATA->abilities[battler] == ABILITY_STICKY_HOLD) return FALSE; if (!CanBattlerGetOrLoseItem(battler, item)) @@ -2684,13 +2619,13 @@ bool32 AI_CanPutToSleep(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, static bool32 AI_CanPoisonType(u8 battlerAttacker, u8 battlerTarget) { - return ((AI_GetAbility(battlerAttacker) == ABILITY_CORROSION && gBattleMoves[gCurrentMove].split == SPLIT_STATUS) + return ((AI_DATA->abilities[battlerAttacker] == ABILITY_CORROSION && gBattleMoves[gCurrentMove].split == SPLIT_STATUS) || !(IS_BATTLER_OF_TYPE(battlerTarget, TYPE_POISON) || IS_BATTLER_OF_TYPE(battlerTarget, TYPE_STEEL))); } static bool32 AI_CanBePoisoned(u8 battlerAtk, u8 battlerDef) { - u16 ability = AI_GetAbility(battlerDef); + u16 ability = AI_DATA->abilities[battlerDef]; if (!(AI_CanPoisonType(battlerAtk, battlerDef)) || gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD @@ -2729,7 +2664,7 @@ bool32 AI_CanPoison(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 return FALSE; else if (defAbility != ABILITY_CORROSION && (IS_BATTLER_OF_TYPE(battlerDef, TYPE_POISON) || IS_BATTLER_OF_TYPE(battlerDef, TYPE_STEEL))) return FALSE; - else if (IsValidDoubleBattle(battlerAtk) && AI_GetAbility(BATTLE_PARTNER(battlerDef)) == ABILITY_PASTEL_VEIL) + else if (IsValidDoubleBattle(battlerAtk) && AI_DATA->abilities[BATTLE_PARTNER(battlerDef)] == ABILITY_PASTEL_VEIL) return FALSE; return TRUE; @@ -2854,7 +2789,7 @@ u32 ShouldTryToFlinch(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbili bool32 ShouldTrap(u8 battlerAtk, u8 battlerDef, u16 move) { - if (BattlerWillFaintFromSecondaryDamage(battlerDef, AI_DATA->defAbility)) + if (BattlerWillFaintFromSecondaryDamage(battlerDef, AI_DATA->abilities[battlerDef])) return TRUE; // battler is taking secondary damage with low HP if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_STALL) @@ -2868,11 +2803,11 @@ bool32 ShouldTrap(u8 battlerAtk, u8 battlerDef, u16 move) bool32 ShouldFakeOut(u8 battlerAtk, u8 battlerDef, u16 move) { - if (AI_DATA->atkHoldEffect == HOLD_EFFECT_CHOICE_BAND && CountUsablePartyMons(battlerAtk) == 0) + if (AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_CHOICE_BAND && CountUsablePartyMons(battlerAtk) == 0) return FALSE; // don't lock attacker into fake out if can't switch out if (gDisableStructs[battlerAtk].isFirstTurn - && ShouldTryToFlinch(battlerAtk, battlerDef, AI_DATA->atkAbility, AI_DATA->defAbility, move) + && ShouldTryToFlinch(battlerAtk, battlerDef, AI_DATA->abilities[battlerAtk], AI_DATA->abilities[battlerDef], move) && !DoesSubstituteBlockMove(battlerAtk, battlerDef, move)) return TRUE; @@ -2970,7 +2905,7 @@ bool32 ShouldAbsorb(u8 battlerAtk, u8 battlerDef, u16 move, s32 damage) if (CanTargetFaintAi(battlerDef, battlerAtk) && !CanTargetFaintAiWithMod(battlerDef, battlerAtk, healDmg, 0)) return TRUE; // target can faint attacker unless they heal - else if (!CanTargetFaintAi(battlerDef, battlerAtk) && GetHealthPercentage(battlerAtk) < 60 && (Random() % 3)) + else if (!CanTargetFaintAi(battlerDef, battlerAtk) && AI_DATA->hpPercents[battlerAtk] < 60 && (Random() % 3)) return TRUE; // target can't faint attacker at all, attacker health is about half, 2/3rds rate of encouraging healing } else @@ -2988,7 +2923,7 @@ bool32 ShouldRecover(u8 battlerAtk, u8 battlerDef, u16 move, u8 healPercent) if (move == 0xFFFF || AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) { // using item or user going first - s32 damage = AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex]; + s32 damage = AI_DATA->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex]; s32 healAmount = (healPercent * damage) / 100; if (gStatuses3[battlerAtk] & STATUS3_HEAL_BLOCK) healAmount = 0; @@ -2996,7 +2931,7 @@ bool32 ShouldRecover(u8 battlerAtk, u8 battlerDef, u16 move, u8 healPercent) if (CanTargetFaintAi(battlerDef, battlerAtk) && !CanTargetFaintAiWithMod(battlerDef, battlerAtk, healAmount, 0)) return TRUE; // target can faint attacker unless they heal - else if (!CanTargetFaintAi(battlerDef, battlerAtk) && GetHealthPercentage(battlerAtk) < 60 && (Random() % 3)) + else if (!CanTargetFaintAi(battlerDef, battlerAtk) && AI_DATA->hpPercents[battlerAtk] < 60 && (Random() % 3)) return TRUE; // target can't faint attacker at all, attacker health is about half, 2/3rds rate of encouraging healing } return FALSE; @@ -3039,14 +2974,14 @@ bool32 IsValidDoubleBattle(u8 battlerAtk) return FALSE; } -u16 GetAllyChosenMove(void) +u16 GetAllyChosenMove(u8 battlerId) { - u8 partnerBattler = BATTLE_PARTNER(sBattler_AI); - + u8 partnerBattler = BATTLE_PARTNER(battlerId); + if (!IsBattlerAlive(partnerBattler) || !IsBattlerAIControlled(partnerBattler)) - return MOVE_NONE; // TODO: prediction? - else if (partnerBattler > sBattler_AI) // Battler with the lower id chooses the move first. return MOVE_NONE; + else if (partnerBattler > battlerId) // Battler with the lower id chooses the move first. + return gLastMoves[partnerBattler]; else return gBattleMons[partnerBattler].moves[gBattleStruct->chosenMovePositions[partnerBattler]]; } @@ -3184,7 +3119,7 @@ bool32 ShouldUseWishAromatherapy(u8 battlerAtk, u8 battlerDef, u16 move) party = gEnemyParty; if (CountUsablePartyMons(battlerAtk) == 0 - && (CanTargetFaintAi(battlerDef, battlerAtk) || BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->atkAbility))) + && (CanTargetFaintAi(battlerDef, battlerAtk) || BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->abilities[battlerAtk]))) return FALSE; // Don't heal if last mon and will faint for (i = 0; i < PARTY_SIZE; i++) @@ -3241,13 +3176,14 @@ s32 AI_CalcPartyMonDamage(u16 move, u8 battlerAtk, u8 battlerDef, struct Pokemon { s32 dmg; u32 i; + u8 effectiveness; struct BattlePokemon *battleMons = Alloc(sizeof(struct BattlePokemon) * MAX_BATTLERS_COUNT); for (i = 0; i < MAX_BATTLERS_COUNT; i++) battleMons[i] = gBattleMons[i]; PokemonToBattleMon(mon, &gBattleMons[battlerAtk]); - dmg = AI_CalcDamage(move, battlerAtk, battlerDef); + dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness); for (i = 0; i < MAX_BATTLERS_COUNT; i++) gBattleMons[i] = battleMons[i]; @@ -3442,10 +3378,10 @@ bool32 IsRecycleEncouragedItem(u16 item) #define STAT_UP_STAGE 10 void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score) { - if (AI_DATA->atkAbility == ABILITY_CONTRARY) + if (AI_DATA->abilities[battlerAtk] == ABILITY_CONTRARY) return; - if (GetHealthPercentage(battlerAtk) < 80 && AI_RandLessThan(128)) + if (AI_DATA->hpPercents[battlerAtk] < 80 && AI_RandLessThan(128)) return; if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) @@ -3454,7 +3390,7 @@ void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score) switch (statId) { case STAT_ATK: - if (HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL) && GetHealthPercentage(battlerAtk) > 40) + if (HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL) && AI_DATA->hpPercents[battlerAtk] > 40) { if (gBattleMons[battlerAtk].statStages[STAT_ATK] < STAT_UP_2_STAGE) *score += 2; @@ -3466,7 +3402,7 @@ void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score) break; case STAT_DEF: if ((HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL)|| IS_MOVE_PHYSICAL(gLastMoves[battlerDef])) - && GetHealthPercentage(battlerAtk) > 70) + && AI_DATA->hpPercents[battlerAtk] > 70) { if (gBattleMons[battlerAtk].statStages[STAT_DEF] < STAT_UP_2_STAGE) *score += 2; // seems better to raise def at higher HP @@ -3484,7 +3420,7 @@ void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score) } break; case STAT_SPATK: - if (HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL) && GetHealthPercentage(battlerAtk) > 40) + if (HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL) && AI_DATA->hpPercents[battlerAtk] > 40) { if (gBattleMons[battlerAtk].statStages[STAT_SPATK] < STAT_UP_2_STAGE) *score += 2; @@ -3494,7 +3430,7 @@ void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score) break; case STAT_SPDEF: if ((HasMoveWithSplit(battlerDef, SPLIT_SPECIAL) || IS_MOVE_SPECIAL(gLastMoves[battlerDef])) - && GetHealthPercentage(battlerAtk) > 70) + && AI_DATA->hpPercents[battlerAtk] > 70) { if (gBattleMons[battlerAtk].statStages[STAT_SPDEF] < STAT_UP_2_STAGE) *score += 2; // seems better to raise spdef at higher HP @@ -3503,13 +3439,13 @@ void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score) } break; case STAT_ACC: - if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 80, TRUE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect)) + if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 80, TRUE, AI_DATA->abilities[battlerAtk], AI_DATA->abilities[battlerDef], AI_DATA->holdEffects[battlerAtk], AI_DATA->holdEffects[battlerDef])) *score += 2; // has moves with less than 80% accuracy - else if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, TRUE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect)) + else if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, TRUE, AI_DATA->abilities[battlerAtk], AI_DATA->abilities[battlerDef], AI_DATA->holdEffects[battlerAtk], AI_DATA->holdEffects[battlerDef])) *(score)++; break; case STAT_EVASION: - if (!BattlerWillFaintFromWeather(battlerAtk, AI_DATA->atkAbility)) + if (!BattlerWillFaintFromWeather(battlerAtk, AI_DATA->abilities[battlerAtk])) { if (!GetBattlerSecondaryDamage(battlerAtk) && !(gStatuses3[battlerAtk] & STATUS3_ROOTED)) *score += 2; @@ -3525,7 +3461,7 @@ void IncreasePoisonScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return; - if (AI_CanPoison(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove) && GetHealthPercentage(battlerDef) > 20) + if (AI_CanPoison(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove) && AI_DATA->hpPercents[battlerDef] > 20) { if (!HasDamagingMove(battlerDef)) *score += 2; @@ -3536,7 +3472,7 @@ void IncreasePoisonScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) if (HasMoveEffect(battlerAtk, EFFECT_VENOSHOCK) || HasMoveEffect(battlerAtk, EFFECT_HEX) || HasMoveEffect(battlerAtk, EFFECT_VENOM_DRENCH) - || AI_DATA->atkAbility == ABILITY_MERCILESS) + || AI_DATA->abilities[battlerAtk] == ABILITY_MERCILESS) *(score) += 2; else *(score)++; @@ -3548,7 +3484,7 @@ void IncreaseBurnScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return; - if (AI_CanBurn(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) + if (AI_CanBurn(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) { (*score)++; // burning is good if (HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL)) @@ -3557,7 +3493,7 @@ void IncreaseBurnScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) *score += 2; // burning the target to stay alive is cool } - if (HasMoveEffect(battlerAtk, EFFECT_HEX) || HasMoveEffect(AI_DATA->battlerAtkPartner, EFFECT_HEX)) + if (HasMoveEffect(battlerAtk, EFFECT_HEX) || HasMoveEffect(BATTLE_PARTNER(battlerAtk), EFFECT_HEX)) (*score)++; } } @@ -3567,7 +3503,7 @@ void IncreaseParalyzeScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return; - if (AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) + if (AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove)) { u8 atkSpeed = GetBattlerTotalSpeedStat(battlerAtk); u8 defSpeed = GetBattlerTotalSpeedStat(battlerDef); @@ -3588,7 +3524,7 @@ void IncreaseSleepScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return; - if (AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) + if (AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove)) *score += 2; else return; @@ -3597,7 +3533,7 @@ void IncreaseSleepScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) && !(HasMoveEffect(battlerDef, EFFECT_SNORE) || HasMoveEffect(battlerDef, EFFECT_SLEEP_TALK))) (*score)++; - if (HasMoveEffect(battlerAtk, EFFECT_HEX) || HasMoveEffect(AI_DATA->battlerAtkPartner, EFFECT_HEX)) + if (HasMoveEffect(battlerAtk, EFFECT_HEX) || HasMoveEffect(BATTLE_PARTNER(battlerAtk), EFFECT_HEX)) (*score)++; } @@ -3606,13 +3542,13 @@ void IncreaseConfusionScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return; - if (AI_CanConfuse(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove) - && AI_DATA->defHoldEffect != HOLD_EFFECT_CURE_CONFUSION - && AI_DATA->defHoldEffect != HOLD_EFFECT_CURE_STATUS) + if (AI_CanConfuse(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove) + && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CURE_CONFUSION + && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CURE_STATUS) { if (gBattleMons[battlerDef].status1 & STATUS1_PARALYSIS || gBattleMons[battlerDef].status2 & STATUS2_INFATUATION - || (AI_DATA->atkAbility == ABILITY_SERENE_GRACE && HasMoveEffect(battlerAtk, EFFECT_FLINCH_HIT))) + || (AI_DATA->abilities[battlerAtk] == ABILITY_SERENE_GRACE && HasMoveEffect(battlerAtk, EFFECT_FLINCH_HIT))) *score += 3; else *score += 2; diff --git a/src/battle_debug.c b/src/battle_debug.c index 2ea46321d..0657ed2ac 100644 --- a/src/battle_debug.c +++ b/src/battle_debug.c @@ -714,7 +714,7 @@ void CB2_BattleDebugMenu(void) static void PutMovesPointsText(struct BattleDebugMenu *data) { - u32 i, j, count; + u32 i, j, count, battlerDef; u8 *text = malloc(0x50); FillWindowPixelBuffer(data->aiMovesWindowId, 0x11); @@ -727,13 +727,14 @@ static void PutMovesPointsText(struct BattleDebugMenu *data) { if (data->aiIconSpriteIds[j] == 0xFF) continue; + battlerDef = gSprites[data->aiIconSpriteIds[j]].data[0]; ConvertIntToDecimalStringN(text, - gBattleStruct->aiFinalScore[data->aiBattlerId][gSprites[data->aiIconSpriteIds[j]].data[0]][i], + gBattleStruct->aiFinalScore[data->aiBattlerId][battlerDef][i], STR_CONV_MODE_RIGHT_ALIGN, 3); AddTextPrinterParameterized(data->aiMovesWindowId, 1, text, 83 + count * 54, i * 15, 0, NULL); ConvertIntToDecimalStringN(text, - gBattleStruct->aiSimulatedDamage[data->aiBattlerId][gSprites[data->aiIconSpriteIds[j]].data[0]][i], + AI_DATA->simulatedDmg[data->aiBattlerId][battlerDef][i], STR_CONV_MODE_RIGHT_ALIGN, 3); AddTextPrinterParameterized(data->aiMovesWindowId, 1, text, 110 + count * 54, i * 15, 0, NULL); diff --git a/src/battle_main.c b/src/battle_main.c index 37845472a..336f76f6c 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -3698,6 +3698,8 @@ static void TryDoEventsBeforeFirstTurn(void) gMoveResultFlags = 0; gRandomTurnNumber = Random(); + + GetAiLogicData(); // get assumed abilities, hold effects, etc of all battlers if (gBattleTypeFlags & BATTLE_TYPE_ARENA) { @@ -3786,6 +3788,7 @@ void BattleTurnPassed(void) *(&gBattleStruct->absentBattlerFlags) = gAbsentBattlerFlags; BattlePutTextOnWindow(gText_EmptyString3, B_WIN_MSG); + GetAiLogicData(); // get assumed abilities, hold effects, etc of all battlers gBattleMainFunc = HandleTurnActionSelectionState; gRandomTurnNumber = Random(); diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index c624130a6..d3717b53d 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1657,20 +1657,14 @@ static bool32 AccuracyCalcHelper(u16 move) return FALSE; } -u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move) +u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect) { - u32 calc, moveAcc, atkHoldEffect, atkParam, defHoldEffect, defParam, atkAbility, defAbility; + u32 calc, moveAcc; s8 buff, accStage, evasionStage; + u8 atkParam = GetBattlerHoldEffectParam(battlerAtk); + u8 defParam = GetBattlerHoldEffectParam(battlerDef); - atkAbility = GetBattlerAbility(battlerAtk); - atkHoldEffect = GetBattlerHoldEffect(battlerAtk, TRUE); - atkParam = GetBattlerHoldEffectParam(battlerAtk); - - defAbility = GetBattlerAbility(battlerDef); - defHoldEffect = GetBattlerHoldEffect(battlerDef, TRUE); - defParam = GetBattlerHoldEffectParam(battlerDef); gPotentialItemEffectBattler = battlerDef; - accStage = gBattleMons[battlerAtk].statStages[STAT_ACC]; evasionStage = gBattleMons[battlerDef].statStages[STAT_EVASION]; if (atkAbility == ABILITY_UNAWARE || atkAbility == ABILITY_KEEN_EYE) @@ -1767,7 +1761,8 @@ static void Cmd_accuracycheck(void) return; // final calculation - if ((Random() % 100 + 1) > GetTotalAccuracy(gBattlerAttacker, gBattlerTarget, move)) + if ((Random() % 100 + 1) > GetTotalAccuracy(gBattlerAttacker, gBattlerTarget, move, GetBattlerAbility(gBattlerAttacker), GetBattlerAbility(gBattlerTarget), + GetBattlerHoldEffect(gBattlerAttacker, TRUE), GetBattlerHoldEffect(gBattlerTarget, TRUE))) { gMoveResultFlags |= MOVE_RESULT_MISSED; if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_BLUNDER_POLICY) diff --git a/src/battle_util.c b/src/battle_util.c index b293b9a5e..d600a26e7 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -8957,13 +8957,11 @@ static u32 CalcFinalDmg(u32 dmg, u16 move, u8 battlerAtk, u8 battlerDef, u8 move return dmg; } -s32 CalculateMoveDamage(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, s32 fixedBasePower, bool32 isCrit, bool32 randomFactor, bool32 updateFlags) +static s32 DoMoveDamageCalc(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, s32 fixedBasePower, + bool32 isCrit, bool32 randomFactor, bool32 updateFlags, u16 typeEffectivenessModifier) { s32 dmg; - u16 typeEffectivenessModifier; - - typeEffectivenessModifier = CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, updateFlags); - + // Don't calculate damage if the move has no effect on target. if (typeEffectivenessModifier == UQ_4_12(0)) return 0; @@ -8996,6 +8994,19 @@ s32 CalculateMoveDamage(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, s32 return dmg; } +s32 CalculateMoveDamage(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, s32 fixedBasePower, bool32 isCrit, bool32 randomFactor, bool32 updateFlags) +{ + return DoMoveDamageCalc(move, battlerAtk, battlerDef, moveType, fixedBasePower, isCrit, randomFactor, + updateFlags, CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, updateFlags)); +} + +// for AI - get move damage and effectiveness with one function call +s32 CalculateMoveDamageAndEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, u16 *typeEffectivenessModifier) +{ + *typeEffectivenessModifier = CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, FALSE); + return DoMoveDamageCalc(move, battlerAtk, battlerDef, moveType, 0, FALSE, FALSE, FALSE, *typeEffectivenessModifier); +} + static void MulByTypeEffectiveness(u16 *modifier, u16 move, u8 moveType, u8 battlerDef, u8 defType, u8 battlerAtk, bool32 recordAbilities) { u16 mod = GetTypeModifier(moveType, defType); diff --git a/src/battle_util2.c b/src/battle_util2.c index c269d8613..2ccc38a8a 100644 --- a/src/battle_util2.c +++ b/src/battle_util2.c @@ -26,6 +26,7 @@ void AllocateBattleResources(void) gBattleResources->battleCallbackStack = AllocZeroed(sizeof(*gBattleResources->battleCallbackStack)); gBattleResources->beforeLvlUp = AllocZeroed(sizeof(*gBattleResources->beforeLvlUp)); gBattleResources->ai = AllocZeroed(sizeof(*gBattleResources->ai)); + gBattleResources->aiData = AllocZeroed(sizeof(*gBattleResources->aiData)); gBattleResources->battleHistory = AllocZeroed(sizeof(*gBattleResources->battleHistory)); gLinkBattleSendBuffer = AllocZeroed(BATTLE_BUFFER_LINK_SIZE); @@ -57,6 +58,7 @@ void FreeBattleResources(void) FREE_AND_SET_NULL(gBattleResources->battleCallbackStack); FREE_AND_SET_NULL(gBattleResources->beforeLvlUp); FREE_AND_SET_NULL(gBattleResources->ai); + FREE_AND_SET_NULL(gBattleResources->aiData); FREE_AND_SET_NULL(gBattleResources->battleHistory); FREE_AND_SET_NULL(gBattleResources); From 078874aa1eacec94dfb47b6e081f1dd13e0d7d72 Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Thu, 13 Jan 2022 11:32:22 -0500 Subject: [PATCH 034/130] move some WEATHER_HAS_EFFECT after bitfield checks to speed up damage calcs --- src/battle_util.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/battle_util.c b/src/battle_util.c index d600a26e7..6c0788d4d 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -4400,7 +4400,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move BattleScriptPushCursorAndCallback(BattleScript_DrizzleActivates); effect++; } - else if (WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_PRIMAL_ANY && !gSpecialStatuses[battler].switchInAbilityDone) + else if (gBattleWeather & B_WEATHER_PRIMAL_ANY && WEATHER_HAS_EFFECT && !gSpecialStatuses[battler].switchInAbilityDone) { gSpecialStatuses[battler].switchInAbilityDone = TRUE; BattleScriptPushCursorAndCallback(BattleScript_BlockedByPrimalWeatherEnd3); @@ -4413,7 +4413,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move BattleScriptPushCursorAndCallback(BattleScript_SandstreamActivates); effect++; } - else if (WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_PRIMAL_ANY && !gSpecialStatuses[battler].switchInAbilityDone) + else if (gBattleWeather & B_WEATHER_PRIMAL_ANY && WEATHER_HAS_EFFECT && !gSpecialStatuses[battler].switchInAbilityDone) { gSpecialStatuses[battler].switchInAbilityDone = TRUE; BattleScriptPushCursorAndCallback(BattleScript_BlockedByPrimalWeatherEnd3); @@ -4426,7 +4426,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move BattleScriptPushCursorAndCallback(BattleScript_DroughtActivates); effect++; } - else if (WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_PRIMAL_ANY && !gSpecialStatuses[battler].switchInAbilityDone) + else if (gBattleWeather & B_WEATHER_PRIMAL_ANY && WEATHER_HAS_EFFECT && !gSpecialStatuses[battler].switchInAbilityDone) { gSpecialStatuses[battler].switchInAbilityDone = TRUE; BattleScriptPushCursorAndCallback(BattleScript_BlockedByPrimalWeatherEnd3); @@ -4439,7 +4439,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move BattleScriptPushCursorAndCallback(BattleScript_SnowWarningActivates); effect++; } - else if (WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_PRIMAL_ANY && !gSpecialStatuses[battler].switchInAbilityDone) + else if (gBattleWeather & B_WEATHER_PRIMAL_ANY && WEATHER_HAS_EFFECT && !gSpecialStatuses[battler].switchInAbilityDone) { gSpecialStatuses[battler].switchInAbilityDone = TRUE; BattleScriptPushCursorAndCallback(BattleScript_BlockedByPrimalWeatherEnd3); @@ -5316,9 +5316,9 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) && !gProtectStructs[gBattlerAttacker].confusionSelfDmg && TARGET_TURN_DAMAGED - && !(WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_SANDSTORM)) + && !(gBattleWeather & B_WEATHER_SANDSTORM && WEATHER_HAS_EFFECT)) { - if (WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_PRIMAL_ANY) + if (gBattleWeather & B_WEATHER_PRIMAL_ANY && WEATHER_HAS_EFFECT) { BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_BlockedByPrimalWeatherRet; @@ -7974,7 +7974,7 @@ static u16 CalcMoveBasePower(u16 move, u8 battlerAtk, u8 battlerDef) basePower *= 2; break; case EFFECT_WEATHER_BALL: - if (WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_ANY) + if (gBattleWeather & B_WEATHER_ANY && WEATHER_HAS_EFFECT) basePower *= 2; break; case EFFECT_PURSUIT: @@ -8176,7 +8176,7 @@ static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDe break; case ABILITY_SAND_FORCE: if ((moveType == TYPE_STEEL || moveType == TYPE_ROCK || moveType == TYPE_GROUND) - && WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_SANDSTORM) + && gBattleWeather & B_WEATHER_SANDSTORM && WEATHER_HAS_EFFECT) MulModifier(&modifier, UQ_4_12(1.3)); break; case ABILITY_RIVALRY: @@ -8785,7 +8785,7 @@ static u32 CalcDefenseStat(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, } // sandstorm sp.def boost for rock types - if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_ROCK) && WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_SANDSTORM && !usesDefStat) + if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_ROCK) && gBattleWeather & B_WEATHER_SANDSTORM && WEATHER_HAS_EFFECT && !usesDefStat) MulModifier(&modifier, UQ_4_12(1.5)); // The defensive stats of a Player's Pokémon are boosted by x1.1 (+10%) if they have the 5th badge and 7th badges. @@ -9038,7 +9038,7 @@ static void MulByTypeEffectiveness(u16 *modifier, u16 move, u8 moveType, u8 batt mod = UQ_4_12(2.0); // B_WEATHER_STRONG_WINDS weakens Super Effective moves against Flying-type Pokémon - if (WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_STRONG_WINDS) + if (gBattleWeather & B_WEATHER_STRONG_WINDS && WEATHER_HAS_EFFECT) { if (defType == TYPE_FLYING && mod >= UQ_4_12(2.0)) mod = UQ_4_12(1.0); @@ -9986,10 +9986,7 @@ u16 GetUsedHeldItem(u8 battler) bool32 IsBattlerWeatherAffected(u8 battlerId, u32 weatherFlags) { - if (!WEATHER_HAS_EFFECT) - return FALSE; - - if (gBattleWeather & weatherFlags) + if (gBattleWeather & weatherFlags && WEATHER_HAS_EFFECT) { // given weather is active -> check if its sun, rain against utility umbrella ( since only 1 weather can be active at once) if (gBattleWeather & (B_WEATHER_SUN | B_WEATHER_RAIN) && GetBattlerHoldEffect(battlerId, TRUE) == HOLD_EFFECT_UTILITY_UMBRELLA) From 8eaf0718ec3adc4d1b51358f99b65dda0dc7d4da Mon Sep 17 00:00:00 2001 From: LOuroboros Date: Sun, 23 Jan 2022 02:50:39 -0300 Subject: [PATCH 035/130] Review changes Also updated tryfaintmon call in BattleScript_FlingEnd, and updated CanFling. --- asm/macros/battle_script.inc | 4 ++-- data/battle_scripts_1.s | 7 ++----- include/constants/battle_script_commands.h | 2 +- src/battle_script_commands.c | 23 ++-------------------- src/battle_util.c | 3 ++- 5 files changed, 9 insertions(+), 30 deletions(-) diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index b7cdeec93..0aeb7309c 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1932,8 +1932,8 @@ various BS_ATTACKER, VARIOUS_SHELL_SIDE_ARM_CHECK .endm - .macro jumpifflingfails battler:req, ptr:req - various \battler, VARIOUS_JUMP_IF_FLING_FAILS + .macro jumpifcantfling battler:req, ptr:req + various \battler, VARIOUS_JUMP_IF_CANT_FLING .4byte \ptr .endm diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 7bd93c9db..7aa3c28b7 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -464,12 +464,9 @@ BattleScript_SkyDropFlyingAlreadyConfused: goto BattleScript_ThrashConfuses BattleScript_EffectFling: - jumpifflingfails BS_ATTACKER, BattleScript_ButItFailedAtkStringPpReduce + jumpifcantfling BS_ATTACKER, BattleScript_ButItFailedAtkStringPpReduce jumpifstatus3 BS_ATTACKER, STATUS3_EMBARGO, BattleScript_ButItFailedAtkStringPpReduce jumpifword CMP_COMMON_BITS, gFieldStatuses, STATUS_FIELD_MAGIC_ROOM, BattleScript_ButItFailedAtkStringPpReduce -.if B_KLUTZ_FLING_INTERACTION >= GEN_5 - jumpifability BS_ATTACKER, ABILITY_KLUTZ, BattleScript_ButItFailedAtkStringPpReduce -.endif setlastuseditem BS_ATTACKER removeitem BS_ATTACKER attackcanceler @@ -511,7 +508,7 @@ BattleScript_EffectFlingConsumeBerry: setbyte sBERRY_OVERRIDE, FALSE restorebattleritem BS_TARGET BattleScript_FlingEnd: - tryfaintmon BS_TARGET, FALSE, NULL + tryfaintmon BS_TARGET goto BattleScript_MoveEnd BattleScript_FlingFlameOrb: diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 819184c3b..594de9ef7 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -229,7 +229,7 @@ #define VARIOUS_SET_SKY_DROP 139 #define VARIOUS_CLEAR_SKY_DROP 140 #define VARIOUS_SKY_DROP_YAWN 141 -#define VARIOUS_JUMP_IF_FLING_FAILS 142 +#define VARIOUS_JUMP_IF_CANT_FLING 142 #define VARIOUS_JUMP_IF_HOLD_EFFECT 143 #define VARIOUS_CURE_CERTAIN_STATUSES 144 #define VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES 145 diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index cef2da350..17ea3eaa8 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1356,19 +1356,6 @@ static void Cmd_attackcanceler(void) GET_MOVE_TYPE(gCurrentMove, moveType); - // Unnerve prevents a Pokémon holding a Berry from using Fling. - if (gCurrentMove == MOVE_FLING - && GetBattlerAbility(gBattlerAttacker) == ABILITY_UNNERVE - && ItemId_GetPocket(gLastUsedItem) == POCKET_BERRIES) - { - // Fling removes the item just before attackcanceler kicks in. - // This is done to work around an opponent using Protect/Detect. - gBattleMons[gBattlerAttacker].item = gLastUsedItem; - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_ButItFailedAtkStringPpReduce; - return; - } - if (moveType == TYPE_FIRE && (gBattleWeather & B_WEATHER_RAIN_PRIMAL) && WEATHER_HAS_EFFECT @@ -9467,14 +9454,8 @@ static void Cmd_various(void) gBattlescriptCurrInstr += 7; return; } - case VARIOUS_JUMP_IF_FLING_FAILS: - #ifdef ITEM_EXPANSION - if (!ItemId_GetFlingPower(gBattleMons[gActiveBattler].item)) - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); - else if (gLastUsedItem == ITEM_NONE) - #else - if (gLastUsedItem == ITEM_NONE) - #endif + case VARIOUS_JUMP_IF_CANT_FLING: + if (!CanFling(gActiveBattler)) gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); else gBattlescriptCurrInstr += 7; diff --git a/src/battle_util.c b/src/battle_util.c index 23f2a3500..b531d5679 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -9620,7 +9620,9 @@ bool32 CanFling(u8 battlerId) u16 itemEffect = ItemId_GetHoldEffect(item); if (item == ITEM_NONE + #if B_KLUTZ_FLING_INTERACTION >= GEN_5 || GetBattlerAbility(battlerId) == ABILITY_KLUTZ + #endif || gFieldStatuses & STATUS_FIELD_MAGIC_ROOM || gDisableStructs[battlerId].embargoTimer != 0 || !CanBattlerGetOrLoseItem(battlerId, item) @@ -9629,7 +9631,6 @@ bool32 CanFling(u8 battlerId) #ifdef ITEM_ABILITY_CAPSULE || item == ITEM_ABILITY_CAPSULE #endif - || (ItemId_GetPocket(item) == POCKET_BERRIES && IsAbilityOnSide(battlerId, ABILITY_UNNERVE)) || GetPocketByItemId(item) == POCKET_POKE_BALLS) return FALSE; From 7916ff5f47dddb10fd7f4bd2c6ef7e5a0f10ce19 Mon Sep 17 00:00:00 2001 From: LOuroboros Date: Tue, 25 Jan 2022 21:02:26 -0300 Subject: [PATCH 036/130] Further updated CanFling --- src/battle_util.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/battle_util.c b/src/battle_util.c index b531d5679..999ced675 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -9625,13 +9625,8 @@ bool32 CanFling(u8 battlerId) #endif || gFieldStatuses & STATUS_FIELD_MAGIC_ROOM || gDisableStructs[battlerId].embargoTimer != 0 - || !CanBattlerGetOrLoseItem(battlerId, item) - //|| itemEffect == HOLD_EFFECT_PRIMAL_ORB - || itemEffect == HOLD_EFFECT_GEMS - #ifdef ITEM_ABILITY_CAPSULE - || item == ITEM_ABILITY_CAPSULE - #endif - || GetPocketByItemId(item) == POCKET_POKE_BALLS) + || ItemId_GetFlingPower(item) != 0 + || !CanBattlerGetOrLoseItem(battlerId, item)) return FALSE; return TRUE; From b33f7aed8df4c0e6d33d2ef7d71a9bda217361cc Mon Sep 17 00:00:00 2001 From: LOuroboros Date: Tue, 25 Jan 2022 23:31:23 -0300 Subject: [PATCH 037/130] Oopsie --- src/battle_util.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/battle_util.c b/src/battle_util.c index 999ced675..e785de2c2 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -9625,7 +9625,9 @@ bool32 CanFling(u8 battlerId) #endif || gFieldStatuses & STATUS_FIELD_MAGIC_ROOM || gDisableStructs[battlerId].embargoTimer != 0 + #ifdef ITEM_EXPANSION || ItemId_GetFlingPower(item) != 0 + #endif || !CanBattlerGetOrLoseItem(battlerId, item)) return FALSE; From 21244d63935b7974c4179f24e4d5de7871c16dcf Mon Sep 17 00:00:00 2001 From: LOuroboros Date: Wed, 26 Jan 2022 21:45:24 -0300 Subject: [PATCH 038/130] Modified and moved IsPinchBerryItemEffect --- include/item.h | 1 - src/battle_ai_main.c | 24 ++++++++++++++++++++++++ src/item.c | 23 ----------------------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/include/item.h b/include/item.h index f0c58c6ab..ceca83bd5 100644 --- a/include/item.h +++ b/include/item.h @@ -75,6 +75,5 @@ ItemUseFunc ItemId_GetFieldFunc(u16 itemId); u8 ItemId_GetBattleUsage(u16 itemId); ItemUseFunc ItemId_GetBattleFunc(u16 itemId); u8 ItemId_GetSecondaryId(u16 itemId); -bool32 IsPinchBerryItemEffect(u16 holdEffect); #endif // GUARD_ITEM_H diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index d5815ad70..f28cb4fe8 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -41,6 +41,7 @@ enum static u8 ChooseMoveOrAction_Singles(void); static u8 ChooseMoveOrAction_Doubles(void); static void BattleAI_DoAIProcessing(void); +static bool32 IsPinchBerryItemEffect(u16 holdEffect); // ewram EWRAM_DATA const u8 *gAIScriptPtr = NULL; // Still used in contests @@ -2928,6 +2929,29 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) return score; } +static bool32 IsPinchBerryItemEffect(u16 holdEffect) +{ + switch (holdEffect) + { + case HOLD_EFFECT_ATTACK_UP: + case HOLD_EFFECT_DEFENSE_UP: + case HOLD_EFFECT_SPEED_UP: + case HOLD_EFFECT_SP_ATTACK_UP: + case HOLD_EFFECT_SP_DEFENSE_UP: + case HOLD_EFFECT_CRITICAL_UP: + case HOLD_EFFECT_RANDOM_STAT_UP: + #ifdef HOLD_EFFECT_CUSTAP_BERRY + case HOLD_EFFECT_CUSTAP_BERRY: + #endif + #ifdef HOLD_EFFECT_MICLE_BERRY + case HOLD_EFFECT_MICLE_BERRY: + #endif + return TRUE; + } + + return FALSE; +} + // AI_FLAG_CHECK_VIABILITY - a weird mix of increasing and decreasing scores static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { diff --git a/src/item.c b/src/item.c index e9b94ae6f..156034262 100644 --- a/src/item.c +++ b/src/item.c @@ -947,26 +947,3 @@ u8 ItemId_GetSecondaryId(u16 itemId) { return gItems[SanitizeItemId(itemId)].secondaryId; } - -bool32 IsPinchBerryItemEffect(u16 holdEffect) -{ - switch (holdEffect) - { - case HOLD_EFFECT_ATTACK_UP: - case HOLD_EFFECT_DEFENSE_UP: - case HOLD_EFFECT_SPEED_UP: - case HOLD_EFFECT_SP_ATTACK_UP: - case HOLD_EFFECT_SP_DEFENSE_UP: - case HOLD_EFFECT_CRITICAL_UP: - case HOLD_EFFECT_RANDOM_STAT_UP: - #ifdef HOLD_EFFECT_CUSTAP_BERRY - case HOLD_EFFECT_CUSTAP_BERRY: - #endif - #ifdef HOLD_EFFECT_MICLE_BERRY - case HOLD_EFFECT_MICLE_BERRY: - #endif - return TRUE; - } - - return FALSE; -} From 88b732632538795a5194ce5b100c37f58f47ecb3 Mon Sep 17 00:00:00 2001 From: LOuroboros Date: Wed, 26 Jan 2022 21:46:35 -0300 Subject: [PATCH 039/130] Ported the IE's flingPower item field and ItemId_GetFlingPower --- include/item.h | 2 ++ src/item.c | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/include/item.h b/include/item.h index ceca83bd5..a1d8324bb 100644 --- a/include/item.h +++ b/include/item.h @@ -21,6 +21,7 @@ struct Item u8 battleUsage; ItemUseFunc battleUseFunc; u8 secondaryId; + u8 flingPower; }; struct BagPocket @@ -75,5 +76,6 @@ ItemUseFunc ItemId_GetFieldFunc(u16 itemId); u8 ItemId_GetBattleUsage(u16 itemId); ItemUseFunc ItemId_GetBattleFunc(u16 itemId); u8 ItemId_GetSecondaryId(u16 itemId); +u8 ItemId_GetFlingPower(u16 itemId); #endif // GUARD_ITEM_H diff --git a/src/item.c b/src/item.c index 156034262..f1320a7ac 100644 --- a/src/item.c +++ b/src/item.c @@ -947,3 +947,8 @@ u8 ItemId_GetSecondaryId(u16 itemId) { return gItems[SanitizeItemId(itemId)].secondaryId; } + +u8 ItemId_GetFlingPower(u16 itemId) +{ + return gItems[SanitizeItemId(itemId)].flingPower; +} From 0a27b575dc7764d976ae5bcd7bc48365cf6e1dc3 Mon Sep 17 00:00:00 2001 From: BuffelSaft Date: Thu, 27 Jan 2022 17:24:11 +1300 Subject: [PATCH 040/130] Fix merge error in battle scripts --- data/battle_scripts_1.s | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index fec6a18d7..ebcaf38d7 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -403,6 +403,7 @@ gBattleScriptsForMoveEffects:: .4byte BattleScript_EffectOctolock @ EFFECT_OCTOLOCK .4byte BattleScript_EffectClangorousSoul @ EFFECT_CLANGOROUS_SOUL .4byte BattleScript_EffectHit @ EFFECT_BOLT_BEAK + .4byte BattleScript_EffectSkyDrop @ EFFECT_SKY_DROP .4byte BattleScript_EffectHit @ EFFECT_EXPANDING_FORCE .4byte BattleScript_EffectScaleShot @ EFFECT_SCALE_SHOT .4byte BattleScript_EffectMeteorBeam @ EFFECT_METEOR_BEAM @@ -512,11 +513,10 @@ BattleScript_ScaleShotPrintStrings:: BattleScript_ScaleShotEnd:: setmoveeffect MOVE_EFFECT_SCALE_SHOT | MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN seteffectwithchance - tryfaintmon BS_TARGET, FALSE, NULL + tryfaintmon BS_TARGET moveendcase MOVEEND_SYNCHRONIZE_TARGET moveendfrom MOVEEND_STATUS_IMMUNITY_ABILITIES end - .4byte BattleScript_EffectSkyDrop @ EFFECT_SKY_DROP BattleScript_EffectSkyDrop: jumpifstatus2 BS_ATTACKER, STATUS2_MULTIPLETURNS, BattleScript_SkyDropTurn2 From 389a38b3cd3bffa87b6fec09c4f8daa8dd977005 Mon Sep 17 00:00:00 2001 From: Eduardo Quezada D'Ottone Date: Sat, 12 Feb 2022 23:55:54 -0300 Subject: [PATCH 041/130] Config for Facade being affected by burns --- include/constants/battle_config.h | 1 + src/battle_util.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/constants/battle_config.h b/include/constants/battle_config.h index 6306ca687..ab5a613d8 100644 --- a/include/constants/battle_config.h +++ b/include/constants/battle_config.h @@ -116,6 +116,7 @@ // Damage settings #define B_BURN_DAMAGE GEN_7 // In Gen7+, burn damage is 1/16th of max HP instead of 1/8th. +#define B_BURN_FACADE_DMG GEN_7 // In Gen6+, burn's effect of lowering the Attack stat no longer applies to Facade. #define B_BINDING_DAMAGE GEN_7 // In Gen6+, binding damage is 1/8 of max HP instead of 1/16. (With Binding Band, 1/6 and 1/8 respectively.) #define B_PSYWAVE_DMG GEN_7 // Psywave's damage formula. See Cmd_psywavedamageeffect. #define B_PAYBACK_SWITCH_BOOST GEN_7 // In Gen5+, if the opponent switches out, Payback's damage will no longer be doubled. diff --git a/src/battle_util.c b/src/battle_util.c index 4127b9bd4..d9831f8f6 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -8869,7 +8869,8 @@ static u32 CalcFinalDmg(u32 dmg, u16 move, u8 battlerAtk, u8 battlerDef, u8 move // check burn if (gBattleMons[battlerAtk].status1 & STATUS1_BURN && IS_MOVE_PHYSICAL(move) - && gBattleMoves[move].effect != EFFECT_FACADE && abilityAtk != ABILITY_GUTS) + && (gBattleMoves[move].effect != EFFECT_FACADE || B_BURN_FACADE_DMG < GEN_6) + && abilityAtk != ABILITY_GUTS) dmg = ApplyModifier(UQ_4_12(0.5), dmg); // check sunny/rain weather From 76e0b3896044572bcb063176eda30146add07bd5 Mon Sep 17 00:00:00 2001 From: Eduardo Quezada D'Ottone Date: Sat, 12 Feb 2022 23:57:23 -0300 Subject: [PATCH 042/130] =?UTF-8?q?Config=20for=20Pok=C3=A9mon=20with=20Ob?= =?UTF-8?q?livious=20being=20affected=20by=20Taunt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/constants/battle_config.h | 1 + src/battle_script_commands.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/constants/battle_config.h b/include/constants/battle_config.h index ab5a613d8..d989e746d 100644 --- a/include/constants/battle_config.h +++ b/include/constants/battle_config.h @@ -182,6 +182,7 @@ #define B_SYNCHRONIZE_NATURE GEN_8 // In Gen8, if a Pokémon with Synchronize is leading the party, it's 100% guaranteed that wild Pokémon will have the same ability, as opposed to 50% previously. #define B_SYNCHRONIZE_TOXIC GEN_8 // In Gen5+, if a Pokémon with Synchronize is badly poisoned, the opponent will also become badly poisoned. Previously, the opponent would become regular poisoned. #define B_UPDATED_INTIMIDATE GEN_8 // In Gen8, Intimidate doesn't work on opponents with the Inner Focus, Scrappy, Own Tempo or Oblivious abilities. +#define B_OBLIVIOUS_TAUNT GEN_7 // In Gen6+, Pokémon with Oblivious can't be taunted. // Item settings #define B_HP_BERRIES GEN_7 // In Gen4+, berries which restore hp activate immediately after HP drops to half. In Gen3, the effect occurs at the end of the turn. diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index e67eb917b..00be0d2f2 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -12297,13 +12297,16 @@ static void Cmd_jumpifnodamage(void) static void Cmd_settaunt(void) { +#if B_OBLIVIOUS_TAUNT >= GEN_6 if (GetBattlerAbility(gBattlerTarget) == ABILITY_OBLIVIOUS) { gBattlescriptCurrInstr = BattleScript_NotAffectedAbilityPopUp; gLastUsedAbility = ABILITY_OBLIVIOUS; RecordAbilityBattle(gBattlerTarget, ABILITY_OBLIVIOUS); } - else if (gDisableStructs[gBattlerTarget].tauntTimer == 0) + else +#endif + if (gDisableStructs[gBattlerTarget].tauntTimer == 0) { #if B_TAUNT_TURNS >= GEN_5 u8 turns = 4; From 748ce99de3aad3b6a588e82ba5cc659a613881e4 Mon Sep 17 00:00:00 2001 From: Eduardo Quezada D'Ottone Date: Sun, 13 Feb 2022 00:17:37 -0300 Subject: [PATCH 043/130] Config for Ingrain grounding the user --- include/constants/battle_config.h | 1 + src/battle_util.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/include/constants/battle_config.h b/include/constants/battle_config.h index d989e746d..9715e802f 100644 --- a/include/constants/battle_config.h +++ b/include/constants/battle_config.h @@ -170,6 +170,7 @@ #define B_BRICK_BREAK GEN_7 // In Gen4+, you can destroy your own side's screens. In Gen 5+, screens are not removed if the target is immune. #define B_WISH_HP_SOURCE GEN_7 // In Gen5+, Wish heals half of the user's max HP instead of the target's. #define B_RAMPAGE_CANCELLING GEN_7 // In Gen5+, a failed Thrash, etc, will cancel except on its last turn. +#define B_ROOTED_GROUNDING GEN_7 // In Gen4+, Ingrain causes the affected Pokémon to become grounded. // Ability settings #define B_EXPANDED_ABILITY_NAMES TRUE // If TRUE, ability names are increased from 12 characters to 16 characters. diff --git a/src/battle_util.c b/src/battle_util.c index d9831f8f6..a6040eab1 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -7736,8 +7736,10 @@ bool32 IsBattlerGrounded(u8 battlerId) return TRUE; else if (gFieldStatuses & STATUS_FIELD_GRAVITY) return TRUE; +#if B_ROOTED_GROUNDING >= GEN_4 else if (gStatuses3[battlerId] & STATUS3_ROOTED) return TRUE; +#endif else if (gStatuses3[battlerId] & STATUS3_SMACKED_DOWN) return TRUE; From d73e6faab8ede9ba127806971d7944eacdd49f72 Mon Sep 17 00:00:00 2001 From: Eduardo Quezada D'Ottone Date: Sun, 13 Feb 2022 00:30:37 -0300 Subject: [PATCH 044/130] Config for Growth being affected by sunlight --- data/battle_scripts_1.s | 4 ++++ include/constants/battle_config.h | 1 + 2 files changed, 5 insertions(+) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 624e911bc..c26d11950 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -1907,7 +1907,9 @@ BattleScript_GrowthDoMoveAnim:: waitanimation setbyte sSTAT_ANIM_PLAYED, FALSE playstatchangeanimation BS_ATTACKER, BIT_ATK | BIT_SPATK, 0 +.if B_GROWTH_UNDER_SUN >= GEN_5 jumpifweatheraffected BS_ATTACKER, B_WEATHER_SUN, BattleScript_GrowthAtk2 +.endif setstatchanger STAT_ATK, 1, FALSE goto BattleScript_GrowthAtk BattleScript_GrowthAtk2: @@ -1918,7 +1920,9 @@ BattleScript_GrowthAtk: printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_GrowthTrySpAtk:: +.if B_GROWTH_UNDER_SUN >= GEN_5 jumpifweatheraffected BS_ATTACKER, B_WEATHER_SUN, BattleScript_GrowthSpAtk2 +.endif setstatchanger STAT_SPATK, 1, FALSE goto BattleScript_GrowthSpAtk BattleScript_GrowthSpAtk2: diff --git a/include/constants/battle_config.h b/include/constants/battle_config.h index 9715e802f..29ecf2135 100644 --- a/include/constants/battle_config.h +++ b/include/constants/battle_config.h @@ -171,6 +171,7 @@ #define B_WISH_HP_SOURCE GEN_7 // In Gen5+, Wish heals half of the user's max HP instead of the target's. #define B_RAMPAGE_CANCELLING GEN_7 // In Gen5+, a failed Thrash, etc, will cancel except on its last turn. #define B_ROOTED_GROUNDING GEN_7 // In Gen4+, Ingrain causes the affected Pokémon to become grounded. +#define B_GROWTH_UNDER_SUN GEN_7 // In Gen5+, Growth's effects are doubled when under the effects of the sun. // Ability settings #define B_EXPANDED_ABILITY_NAMES TRUE // If TRUE, ability names are increased from 12 characters to 16 characters. From c849197a8890c8ddced5b35e84c01d32a20655f0 Mon Sep 17 00:00:00 2001 From: Eduardo Quezada D'Ottone Date: Sun, 13 Feb 2022 00:45:35 -0300 Subject: [PATCH 045/130] Config for Minimize raising 2 stages --- data/battle_scripts_1.s | 4 ++++ include/constants/battle_config.h | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index c26d11950..cbdf1bef4 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -4341,7 +4341,11 @@ BattleScript_NightmareWorked:: BattleScript_EffectMinimize:: attackcanceler setminimize +.if B_MINIMIZE_EVASION >= GEN_5 + setstatchanger STAT_EVASION, 2, FALSE +.else setstatchanger STAT_EVASION, 1, FALSE +.endif goto BattleScript_EffectStatUpAfterAtkCanceler BattleScript_EffectCurse:: diff --git a/include/constants/battle_config.h b/include/constants/battle_config.h index 29ecf2135..4aa4bebdd 100644 --- a/include/constants/battle_config.h +++ b/include/constants/battle_config.h @@ -152,6 +152,8 @@ #define B_SPEED_BUFFING_RAPID_SPIN GEN_8 // In Gen8, Rapid Spin raises the user's Speed by 1 stage. #define B_RECOIL_IF_MISS_DMG GEN_7 // In Gen5+, Jump Kick and High Jump Kick will always do half of the user's max HP when missing. #define B_UPDATED_CONVERSION GEN_7 // In Gen6+, Conversion changes the user's type to match their first move's. Before, it would choose a move at random. +#define B_PP_REDUCED_BY_SPITE GEN_7 // In Gen4+, Spite reduces the foe's last move's PP by 4, instead of 2 to 5. +#define B_MINIMIZE_EVASION GEN_7 // In Gen5+, Minimize raises evasion by 2 stages instead of 1. // Move accuracy settings #define B_TOXIC_NEVER_MISS GEN_7 // In Gen6+, if Toxic is used by a Poison-type Pokémon, it will never miss. @@ -161,7 +163,6 @@ // Other move settings #define B_SOUND_SUBSTITUTE GEN_7 // In Gen6+, sound moves bypass Substitute. #define B_INCINERATE_GEMS GEN_7 // In Gen6+, Incinerate can destroy Gems. -#define B_PP_REDUCED_BY_SPITE GEN_7 // In Gen4+, Spite reduces the foe's last move's PP by 4, instead of 2 to 5. #define B_CAN_SPITE_FAIL GEN_7 // In Gen4+, Spite can no longer fail if the foe's last move only has 1 remaining PP. #define B_CRASH_IF_TARGET_IMMUNE GEN_7 // In Gen4+, The user of Jump Kick or High Jump Kick will "keep going and crash" if it attacks a target that is immune to the move. #define B_MEMENTO_FAIL GEN_7 // In Gen4+, Memento fails if there is no target or if the target is protected or behind substitute. But not if Atk/Sp. Atk are at -6. From dde65d5cea2e8a89cdd91e24483bae5557ac4cfc Mon Sep 17 00:00:00 2001 From: Eduardo Quezada D'Ottone Date: Sun, 13 Feb 2022 01:07:42 -0300 Subject: [PATCH 046/130] =?UTF-8?q?Config=20for=20Sheer=20Cold=20being=20l?= =?UTF-8?q?ess=20accurate=20when=20not=20used=20by=20Ice=20type=20Pok?= =?UTF-8?q?=C3=A9mon?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/constants/battle_config.h | 1 + src/battle_script_commands.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/include/constants/battle_config.h b/include/constants/battle_config.h index 4aa4bebdd..ab70634a8 100644 --- a/include/constants/battle_config.h +++ b/include/constants/battle_config.h @@ -159,6 +159,7 @@ #define B_TOXIC_NEVER_MISS GEN_7 // In Gen6+, if Toxic is used by a Poison-type Pokémon, it will never miss. #define B_MINIMIZE_DMG_ACC GEN_7 // In Gen6+, moves that causes double damage to minimized Pokémon will also skip accuracy checks. #define B_BLIZZARD_HAIL GEN_7 // In Gen4+, Blizzard bypasses accuracy checks if it's hailing. +#define B_SHEER_COLD_ACC GEN_7 // In Gen7+, Sheer Cold's base chance of hitting is reduced to 20% if the user isn't Ice-typed. // Other move settings #define B_SOUND_SUBSTITUTE GEN_7 // In Gen6+, sound moves bypass Substitute. diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 00be0d2f2..75357dbed 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -10728,6 +10728,10 @@ static void Cmd_tryKO(void) else { u16 odds = gBattleMoves[gCurrentMove].accuracy + (gBattleMons[gBattlerAttacker].level - gBattleMons[gBattlerTarget].level); + #if B_SHEER_COLD_ACC >= GEN_7 + if (!IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_ICE)) + odds -= 10; + #endif if (Random() % 100 + 1 < odds && gBattleMons[gBattlerAttacker].level >= gBattleMons[gBattlerTarget].level) lands = TRUE; } From 5e9767e06716c15ea9d3750f3abab203c8fdcbd2 Mon Sep 17 00:00:00 2001 From: Eduardo Quezada D'Ottone Date: Sun, 13 Feb 2022 01:13:44 -0300 Subject: [PATCH 047/130] Fixed actually checking for Sheer Cold instead of affecting all OHKO moves --- src/battle_script_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 75357dbed..d3c1d4e21 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -10729,7 +10729,7 @@ static void Cmd_tryKO(void) { u16 odds = gBattleMoves[gCurrentMove].accuracy + (gBattleMons[gBattlerAttacker].level - gBattleMons[gBattlerTarget].level); #if B_SHEER_COLD_ACC >= GEN_7 - if (!IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_ICE)) + if (gCurrentMove == MOVE_SHEER_COLD && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_ICE)) odds -= 10; #endif if (Random() % 100 + 1 < odds && gBattleMons[gBattlerAttacker].level >= gBattleMons[gBattlerTarget].level) From 9a88021448dd8d9c8e1f23ea385dab90f1fb8651 Mon Sep 17 00:00:00 2001 From: Eduardo Quezada D'Ottone Date: Thu, 17 Feb 2022 21:39:15 -0300 Subject: [PATCH 048/130] Remove repeated ability check in battle_ai_util.c --- src/battle_ai_util.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 62d831b20..fe37f31ec 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -1505,7 +1505,6 @@ bool32 ShouldSetSandstorm(u8 battler, u16 ability, u16 holdEffect) if (ability == ABILITY_SAND_VEIL || ability == ABILITY_SAND_RUSH || ability == ABILITY_SAND_FORCE - || ability == ABILITY_SAND_FORCE || ability == ABILITY_OVERCOAT || ability == ABILITY_MAGIC_GUARD || holdEffect == HOLD_EFFECT_SAFETY_GOGGLES From 5d58cdd2971b8644e60bc65bd79177d4f5bf4d93 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Mon, 28 Feb 2022 13:34:39 -0500 Subject: [PATCH 049/130] Fix bunny hoppy typo --- include/constants/event_object_movement.h | 16 ++++----- src/data/object_events/object_event_anims.h | 32 +++++++++--------- src/event_object_movement.c | 36 ++++++++++----------- 3 files changed, 42 insertions(+), 42 deletions(-) diff --git a/include/constants/event_object_movement.h b/include/constants/event_object_movement.h index 2c4273524..a9d59935e 100755 --- a/include/constants/event_object_movement.h +++ b/include/constants/event_object_movement.h @@ -273,14 +273,14 @@ #define ANIM_RUN_WEST (ANIM_STD_COUNT + 2) #define ANIM_RUN_EAST (ANIM_STD_COUNT + 3) -#define ANIM_BUNNY_HOPPY_BACK_WHEEL_SOUTH (ANIM_STD_COUNT + 0) -#define ANIM_BUNNY_HOPPY_BACK_WHEEL_NORTH (ANIM_STD_COUNT + 1) -#define ANIM_BUNNY_HOPPY_BACK_WHEEL_WEST (ANIM_STD_COUNT + 2) -#define ANIM_BUNNY_HOPPY_BACK_WHEEL_EAST (ANIM_STD_COUNT + 3) -#define ANIM_BUNNY_HOPPY_FRONT_WHEEL_SOUTH (ANIM_STD_COUNT + 4) -#define ANIM_BUNNY_HOPPY_FRONT_WHEEL_NORTH (ANIM_STD_COUNT + 5) -#define ANIM_BUNNY_HOPPY_FRONT_WHEEL_WEST (ANIM_STD_COUNT + 6) -#define ANIM_BUNNY_HOPPY_FRONT_WHEEL_EAST (ANIM_STD_COUNT + 7) +#define ANIM_BUNNY_HOP_BACK_WHEEL_SOUTH (ANIM_STD_COUNT + 0) +#define ANIM_BUNNY_HOP_BACK_WHEEL_NORTH (ANIM_STD_COUNT + 1) +#define ANIM_BUNNY_HOP_BACK_WHEEL_WEST (ANIM_STD_COUNT + 2) +#define ANIM_BUNNY_HOP_BACK_WHEEL_EAST (ANIM_STD_COUNT + 3) +#define ANIM_BUNNY_HOP_FRONT_WHEEL_SOUTH (ANIM_STD_COUNT + 4) +#define ANIM_BUNNY_HOP_FRONT_WHEEL_NORTH (ANIM_STD_COUNT + 5) +#define ANIM_BUNNY_HOP_FRONT_WHEEL_WEST (ANIM_STD_COUNT + 6) +#define ANIM_BUNNY_HOP_FRONT_WHEEL_EAST (ANIM_STD_COUNT + 7) #define ANIM_STANDING_WHEELIE_BACK_WHEEL_SOUTH (ANIM_STD_COUNT + 8) #define ANIM_STANDING_WHEELIE_BACK_WHEEL_NORTH (ANIM_STD_COUNT + 9) #define ANIM_STANDING_WHEELIE_BACK_WHEEL_WEST (ANIM_STD_COUNT + 10) diff --git a/src/data/object_events/object_event_anims.h b/src/data/object_events/object_event_anims.h index a5fb41462..f96e52de5 100755 --- a/src/data/object_events/object_event_anims.h +++ b/src/data/object_events/object_event_anims.h @@ -413,56 +413,56 @@ static const union AnimCmd sAnim_GetOnOffSurfBlobEast[] = ANIMCMD_JUMP(0), }; -static const union AnimCmd sAnim_BunnyHoppyBackWheelSouth[] = +static const union AnimCmd sAnim_BunnyHopBackWheelSouth[] = { ANIMCMD_FRAME(9, 4), ANIMCMD_FRAME(10, 4), ANIMCMD_END, }; -static const union AnimCmd sAnim_BunnyHoppyBackWheelNorth[] = +static const union AnimCmd sAnim_BunnyHopBackWheelNorth[] = { ANIMCMD_FRAME(13, 4), ANIMCMD_FRAME(14, 4), ANIMCMD_END, }; -static const union AnimCmd sAnim_BunnyHoppyBackWheelWest[] = +static const union AnimCmd sAnim_BunnyHopBackWheelWest[] = { ANIMCMD_FRAME(17, 4), ANIMCMD_FRAME(18, 4), ANIMCMD_END, }; -static const union AnimCmd sAnim_BunnyHoppyBackWheelEast[] = +static const union AnimCmd sAnim_BunnyHopBackWheelEast[] = { ANIMCMD_FRAME(17, 4, .hFlip = TRUE), ANIMCMD_FRAME(18, 4, .hFlip = TRUE), ANIMCMD_END, }; -static const union AnimCmd sAnim_BunnyHoppyFrontWheelSouth[] = +static const union AnimCmd sAnim_BunnyHopFrontWheelSouth[] = { ANIMCMD_FRAME(11, 4), ANIMCMD_FRAME(12, 4), ANIMCMD_END, }; -static const union AnimCmd sAnim_BunnyHoppyFrontWheelNorth[] = +static const union AnimCmd sAnim_BunnyHopFrontWheelNorth[] = { ANIMCMD_FRAME(15, 4), ANIMCMD_FRAME(16, 4), ANIMCMD_END, }; -static const union AnimCmd sAnim_BunnyHoppyFrontWheelWest[] = +static const union AnimCmd sAnim_BunnyHopFrontWheelWest[] = { ANIMCMD_FRAME(19, 4), ANIMCMD_FRAME(20, 4), ANIMCMD_END, }; -static const union AnimCmd sAnim_BunnyHoppyFrontWheelEast[] = +static const union AnimCmd sAnim_BunnyHopFrontWheelEast[] = { ANIMCMD_FRAME(19, 4, .hFlip = TRUE), ANIMCMD_FRAME(20, 4, .hFlip = TRUE), @@ -1024,14 +1024,14 @@ static const union AnimCmd *const sAnimTable_AcroBike[] = { [ANIM_STD_GO_FASTEST_NORTH] = sAnim_GoFastestNorth, [ANIM_STD_GO_FASTEST_WEST] = sAnim_GoFastestWest, [ANIM_STD_GO_FASTEST_EAST] = sAnim_GoFastestEast, - [ANIM_BUNNY_HOPPY_BACK_WHEEL_SOUTH] = sAnim_BunnyHoppyBackWheelSouth, - [ANIM_BUNNY_HOPPY_BACK_WHEEL_NORTH] = sAnim_BunnyHoppyBackWheelNorth, - [ANIM_BUNNY_HOPPY_BACK_WHEEL_WEST] = sAnim_BunnyHoppyBackWheelWest, - [ANIM_BUNNY_HOPPY_BACK_WHEEL_EAST] = sAnim_BunnyHoppyBackWheelEast, - [ANIM_BUNNY_HOPPY_FRONT_WHEEL_SOUTH] = sAnim_BunnyHoppyFrontWheelSouth, - [ANIM_BUNNY_HOPPY_FRONT_WHEEL_NORTH] = sAnim_BunnyHoppyFrontWheelNorth, - [ANIM_BUNNY_HOPPY_FRONT_WHEEL_WEST] = sAnim_BunnyHoppyFrontWheelWest, - [ANIM_BUNNY_HOPPY_FRONT_WHEEL_EAST] = sAnim_BunnyHoppyFrontWheelEast, + [ANIM_BUNNY_HOP_BACK_WHEEL_SOUTH] = sAnim_BunnyHopBackWheelSouth, + [ANIM_BUNNY_HOP_BACK_WHEEL_NORTH] = sAnim_BunnyHopBackWheelNorth, + [ANIM_BUNNY_HOP_BACK_WHEEL_WEST] = sAnim_BunnyHopBackWheelWest, + [ANIM_BUNNY_HOP_BACK_WHEEL_EAST] = sAnim_BunnyHopBackWheelEast, + [ANIM_BUNNY_HOP_FRONT_WHEEL_SOUTH] = sAnim_BunnyHopFrontWheelSouth, + [ANIM_BUNNY_HOP_FRONT_WHEEL_NORTH] = sAnim_BunnyHopFrontWheelNorth, + [ANIM_BUNNY_HOP_FRONT_WHEEL_WEST] = sAnim_BunnyHopFrontWheelWest, + [ANIM_BUNNY_HOP_FRONT_WHEEL_EAST] = sAnim_BunnyHopFrontWheelEast, [ANIM_STANDING_WHEELIE_BACK_WHEEL_SOUTH] = sAnim_StandingWheelieBackWheelSouth, [ANIM_STANDING_WHEELIE_BACK_WHEEL_NORTH] = sAnim_StandingWheelieBackWheelNorth, [ANIM_STANDING_WHEELIE_BACK_WHEEL_WEST] = sAnim_StandingWheelieBackWheelWest, diff --git a/src/event_object_movement.c b/src/event_object_movement.c index df79a1d62..eb699e89f 100644 --- a/src/event_object_movement.c +++ b/src/event_object_movement.c @@ -744,26 +744,26 @@ static const u8 sJumpSpecialDirectionAnimNums[] = { // used for jumping onto sur [DIR_NORTHEAST] = ANIM_GET_ON_OFF_POKEMON_NORTH, }; static const u8 sAcroWheelieDirectionAnimNums[] = { - [DIR_NONE] = ANIM_BUNNY_HOPPY_BACK_WHEEL_SOUTH, - [DIR_SOUTH] = ANIM_BUNNY_HOPPY_BACK_WHEEL_SOUTH, - [DIR_NORTH] = ANIM_BUNNY_HOPPY_BACK_WHEEL_NORTH, - [DIR_WEST] = ANIM_BUNNY_HOPPY_BACK_WHEEL_WEST, - [DIR_EAST] = ANIM_BUNNY_HOPPY_BACK_WHEEL_EAST, - [DIR_SOUTHWEST] = ANIM_BUNNY_HOPPY_BACK_WHEEL_SOUTH, - [DIR_SOUTHEAST] = ANIM_BUNNY_HOPPY_BACK_WHEEL_SOUTH, - [DIR_NORTHWEST] = ANIM_BUNNY_HOPPY_BACK_WHEEL_NORTH, - [DIR_NORTHEAST] = ANIM_BUNNY_HOPPY_BACK_WHEEL_NORTH, + [DIR_NONE] = ANIM_BUNNY_HOP_BACK_WHEEL_SOUTH, + [DIR_SOUTH] = ANIM_BUNNY_HOP_BACK_WHEEL_SOUTH, + [DIR_NORTH] = ANIM_BUNNY_HOP_BACK_WHEEL_NORTH, + [DIR_WEST] = ANIM_BUNNY_HOP_BACK_WHEEL_WEST, + [DIR_EAST] = ANIM_BUNNY_HOP_BACK_WHEEL_EAST, + [DIR_SOUTHWEST] = ANIM_BUNNY_HOP_BACK_WHEEL_SOUTH, + [DIR_SOUTHEAST] = ANIM_BUNNY_HOP_BACK_WHEEL_SOUTH, + [DIR_NORTHWEST] = ANIM_BUNNY_HOP_BACK_WHEEL_NORTH, + [DIR_NORTHEAST] = ANIM_BUNNY_HOP_BACK_WHEEL_NORTH, }; static const u8 sAcroUnusedDirectionAnimNums[] = { - [DIR_NONE] = ANIM_BUNNY_HOPPY_FRONT_WHEEL_SOUTH, - [DIR_SOUTH] = ANIM_BUNNY_HOPPY_FRONT_WHEEL_SOUTH, - [DIR_NORTH] = ANIM_BUNNY_HOPPY_FRONT_WHEEL_NORTH, - [DIR_WEST] = ANIM_BUNNY_HOPPY_FRONT_WHEEL_WEST, - [DIR_EAST] = ANIM_BUNNY_HOPPY_FRONT_WHEEL_EAST, - [DIR_SOUTHWEST] = ANIM_BUNNY_HOPPY_FRONT_WHEEL_SOUTH, - [DIR_SOUTHEAST] = ANIM_BUNNY_HOPPY_FRONT_WHEEL_SOUTH, - [DIR_NORTHWEST] = ANIM_BUNNY_HOPPY_FRONT_WHEEL_NORTH, - [DIR_NORTHEAST] = ANIM_BUNNY_HOPPY_FRONT_WHEEL_NORTH, + [DIR_NONE] = ANIM_BUNNY_HOP_FRONT_WHEEL_SOUTH, + [DIR_SOUTH] = ANIM_BUNNY_HOP_FRONT_WHEEL_SOUTH, + [DIR_NORTH] = ANIM_BUNNY_HOP_FRONT_WHEEL_NORTH, + [DIR_WEST] = ANIM_BUNNY_HOP_FRONT_WHEEL_WEST, + [DIR_EAST] = ANIM_BUNNY_HOP_FRONT_WHEEL_EAST, + [DIR_SOUTHWEST] = ANIM_BUNNY_HOP_FRONT_WHEEL_SOUTH, + [DIR_SOUTHEAST] = ANIM_BUNNY_HOP_FRONT_WHEEL_SOUTH, + [DIR_NORTHWEST] = ANIM_BUNNY_HOP_FRONT_WHEEL_NORTH, + [DIR_NORTHEAST] = ANIM_BUNNY_HOP_FRONT_WHEEL_NORTH, }; static const u8 sAcroEndWheelieDirectionAnimNums[] = { [DIR_NONE] = ANIM_STANDING_WHEELIE_BACK_WHEEL_SOUTH, From 8bf7e7b6f5abad1a4f0772a88ed415079edb7df8 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Wed, 2 Mar 2022 19:45:28 -0500 Subject: [PATCH 050/130] Improve egg hatch documentation --- .../egg_hatch.png => pokemon/egg/hatch.png} | Bin .../egg_shard.png => pokemon/egg/shard.png} | Bin src/egg_hatch.c | 476 ++++++++++-------- 3 files changed, 265 insertions(+), 211 deletions(-) rename graphics/{misc/egg_hatch.png => pokemon/egg/hatch.png} (100%) rename graphics/{misc/egg_shard.png => pokemon/egg/shard.png} (100%) diff --git a/graphics/misc/egg_hatch.png b/graphics/pokemon/egg/hatch.png similarity index 100% rename from graphics/misc/egg_hatch.png rename to graphics/pokemon/egg/hatch.png diff --git a/graphics/misc/egg_shard.png b/graphics/pokemon/egg/shard.png similarity index 100% rename from graphics/misc/egg_shard.png rename to graphics/pokemon/egg/shard.png diff --git a/src/egg_hatch.c b/src/egg_hatch.c index 283ec753a..5dd83c9b1 100644 --- a/src/egg_hatch.c +++ b/src/egg_hatch.c @@ -37,16 +37,24 @@ #include "battle.h" // to get rid of later #include "constants/rgb.h" +#define GFXTAG_EGG 12345 +#define GFXTAG_EGG_SHARD 23456 + +#define PALTAG_EGG 54321 + +#define EGG_X (DISPLAY_WIDTH / 2) +#define EGG_Y (DISPLAY_HEIGHT / 2 - 5) + struct EggHatchData { - u8 eggSpriteID; - u8 pokeSpriteID; - u8 CB2_state; - u8 CB2_PalCounter; - u8 eggPartyID; + u8 eggSpriteId; + u8 monSpriteId; + u8 state; + u8 delayTimer; + u8 eggPartyId; u8 unused_5; u8 unused_6; - u8 eggShardVelocityID; + u8 eggShardVelocityId; u8 windowId; u8 unused_9; u8 unused_A; @@ -58,29 +66,27 @@ extern const u32 gTradePlatform_Tilemap[]; extern const u8 gText_HatchedFromEgg[]; extern const u8 gText_NicknameHatchPrompt[]; -static void Task_EggHatch(u8 taskID); -static void CB2_EggHatch_0(void); -static void CB2_EggHatch_1(void); -static void SpriteCB_Egg_0(struct Sprite* sprite); -static void SpriteCB_Egg_1(struct Sprite* sprite); -static void SpriteCB_Egg_2(struct Sprite* sprite); -static void SpriteCB_Egg_3(struct Sprite* sprite); -static void SpriteCB_Egg_4(struct Sprite* sprite); -static void SpriteCB_Egg_5(struct Sprite* sprite); -static void SpriteCB_EggShard(struct Sprite* sprite); -static void EggHatchPrintMessage(u8 windowId, u8* string, u8 x, u8 y, u8 speed); +static void Task_EggHatch(u8); +static void CB2_LoadEggHatch(void); +static void CB2_EggHatch(void); +static void SpriteCB_Egg_Shake1(struct Sprite*); +static void SpriteCB_Egg_Shake2(struct Sprite*); +static void SpriteCB_Egg_Shake3(struct Sprite*); +static void SpriteCB_Egg_WaitHatch(struct Sprite*); +static void SpriteCB_Egg_Hatch(struct Sprite*); +static void SpriteCB_Egg_Reveal(struct Sprite*); +static void SpriteCB_EggShard(struct Sprite*); +static void EggHatchPrintMessage(u8, u8*, u8, u8, u8); static void CreateRandomEggShardSprite(void); -static void CreateEggShardSprite(u8 x, u8 y, s16 data1, s16 data2, s16 data3, u8 spriteAnimIndex); +static void CreateEggShardSprite(u8, u8, s16, s16, s16, u8); -// IWRAM bss static struct EggHatchData *sEggHatchData; -// rom data -static const u16 sEggPalette[] = INCBIN_U16("graphics/pokemon/egg/normal.gbapal"); -static const u8 sEggHatchTiles[] = INCBIN_U8("graphics/misc/egg_hatch.4bpp"); -static const u8 sEggShardTiles[] = INCBIN_U8("graphics/misc/egg_shard.4bpp"); +static const u16 sEggPalette[] = INCBIN_U16("graphics/pokemon/egg/normal.gbapal"); +static const u8 sEggHatchTiles[] = INCBIN_U8("graphics/pokemon/egg/hatch.4bpp"); +static const u8 sEggShardTiles[] = INCBIN_U8("graphics/pokemon/egg/shard.4bpp"); -static const struct OamData sOamData_EggHatch = +static const struct OamData sOamData_Egg = { .y = 0, .affineMode = ST_OAM_AFFINE_OFF, @@ -97,64 +103,71 @@ static const struct OamData sOamData_EggHatch = .affineParam = 0, }; -static const union AnimCmd sSpriteAnim_EggHatch0[] = +static const union AnimCmd sSpriteAnim_Egg_Normal[] = { ANIMCMD_FRAME(0, 5), ANIMCMD_END }; -static const union AnimCmd sSpriteAnim_EggHatch1[] = +static const union AnimCmd sSpriteAnim_Egg_Cracked1[] = { ANIMCMD_FRAME(16, 5), ANIMCMD_END }; -static const union AnimCmd sSpriteAnim_EggHatch2[] = +static const union AnimCmd sSpriteAnim_Egg_Cracked2[] = { ANIMCMD_FRAME(32, 5), ANIMCMD_END }; -static const union AnimCmd sSpriteAnim_EggHatch3[] = +static const union AnimCmd sSpriteAnim_Egg_Cracked3[] = { ANIMCMD_FRAME(48, 5), ANIMCMD_END }; -static const union AnimCmd *const sSpriteAnimTable_EggHatch[] = +enum { + EGG_ANIM_NORMAL, + EGG_ANIM_CRACKED_1, + EGG_ANIM_CRACKED_2, + EGG_ANIM_CRACKED_3, +}; + +static const union AnimCmd *const sSpriteAnimTable_Egg[] = { - sSpriteAnim_EggHatch0, - sSpriteAnim_EggHatch1, - sSpriteAnim_EggHatch2, - sSpriteAnim_EggHatch3, + [EGG_ANIM_NORMAL] = sSpriteAnim_Egg_Normal, + [EGG_ANIM_CRACKED_1] = sSpriteAnim_Egg_Cracked1, + [EGG_ANIM_CRACKED_2] = sSpriteAnim_Egg_Cracked2, + [EGG_ANIM_CRACKED_3] = sSpriteAnim_Egg_Cracked3, }; static const struct SpriteSheet sEggHatch_Sheet = { .data = sEggHatchTiles, - .size = 2048, - .tag = 12345, + .size = 0x800, + .tag = GFXTAG_EGG, }; static const struct SpriteSheet sEggShards_Sheet = { .data = sEggShardTiles, - .size = 128, - .tag = 23456, + .size = 0x80, + .tag = GFXTAG_EGG_SHARD, }; static const struct SpritePalette sEgg_SpritePalette = { .data = sEggPalette, - .tag = 54321 + .tag = PALTAG_EGG }; -static const struct SpriteTemplate sSpriteTemplate_EggHatch = +static const struct SpriteTemplate sSpriteTemplate_Egg = { - .tileTag = 12345, - .paletteTag = 54321, - .oam = &sOamData_EggHatch, - .anims = sSpriteAnimTable_EggHatch, + .tileTag = GFXTAG_EGG, + .paletteTag = PALTAG_EGG, + .oam = &sOamData_Egg, + .anims = sSpriteAnimTable_Egg, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCallbackDummy @@ -211,8 +224,8 @@ static const union AnimCmd *const sSpriteAnimTable_EggShard[] = static const struct SpriteTemplate sSpriteTemplate_EggShard = { - .tileTag = 23456, - .paletteTag = 54321, + .tileTag = GFXTAG_EGG_SHARD, + .paletteTag = PALTAG_EGG, .oam = &sOamData_EggShard, .anims = sSpriteAnimTable_EggShard, .images = NULL, @@ -220,7 +233,7 @@ static const struct SpriteTemplate sSpriteTemplate_EggShard = .callback = SpriteCB_EggShard }; -static const struct BgTemplate sBgTemplates_EggHatch[2] = +static const struct BgTemplate sBgTemplates_EggHatch[] = { { .bg = 0, @@ -243,7 +256,7 @@ static const struct BgTemplate sBgTemplates_EggHatch[2] = }, }; -static const struct WindowTemplate sWinTemplates_EggHatch[2] = +static const struct WindowTemplate sWinTemplates_EggHatch[] = { { .bg = 0, @@ -270,9 +283,14 @@ static const struct WindowTemplate sYesNoWinTemplate = static const s16 sEggShardVelocities[][2] = { + // First shake {Q_8_8(-1.5), Q_8_8(-3.75)}, + + // Third shake {Q_8_8(-5), Q_8_8(-3)}, {Q_8_8(3.5), Q_8_8(-3)}, + + // Hatching {Q_8_8(-4), Q_8_8(-3.75)}, {Q_8_8(2), Q_8_8(-1.5)}, {Q_8_8(-0.5), Q_8_8(-6.75)}, @@ -291,8 +309,6 @@ static const s16 sEggShardVelocities[][2] = {Q_8_8(2.5), Q_8_8(-7.5)}, }; -// code - static void CreateHatchedMon(struct Pokemon *egg, struct Pokemon *temp) { u16 species; @@ -301,21 +317,17 @@ static void CreateHatchedMon(struct Pokemon *egg, struct Pokemon *temp) u16 moves[MAX_MON_MOVES]; u32 ivs[NUM_STATS]; - species = GetMonData(egg, MON_DATA_SPECIES); for (i = 0; i < MAX_MON_MOVES; i++) - { moves[i] = GetMonData(egg, MON_DATA_MOVE1 + i); - } personality = GetMonData(egg, MON_DATA_PERSONALITY); for (i = 0; i < NUM_STATS; i++) - { ivs[i] = GetMonData(egg, MON_DATA_HP_IV + i); - } + // The language is initially read from the Egg but is later overwritten below language = GetMonData(egg, MON_DATA_LANGUAGE); gameMet = GetMonData(egg, MON_DATA_MET_GAME); markings = GetMonData(egg, MON_DATA_MARKINGS); @@ -325,14 +337,10 @@ static void CreateHatchedMon(struct Pokemon *egg, struct Pokemon *temp) CreateMon(temp, species, EGG_HATCH_LEVEL, USE_RANDOM_IVS, TRUE, personality, OT_ID_PLAYER_ID, 0); for (i = 0; i < MAX_MON_MOVES; i++) - { SetMonData(temp, MON_DATA_MOVE1 + i, &moves[i]); - } for (i = 0; i < NUM_STATS; i++) - { SetMonData(temp, MON_DATA_HP_IV + i, &ivs[i]); - } language = GAME_LANGUAGE; SetMonData(temp, MON_DATA_LANGUAGE, &language); @@ -350,34 +358,35 @@ static void CreateHatchedMon(struct Pokemon *egg, struct Pokemon *temp) static void AddHatchedMonToParty(u8 id) { u8 isEgg = 0x46; // ? - u16 pokeNum; - u8 name[12]; + u16 species; + u8 name[POKEMON_NAME_LENGTH + 1]; u16 ball; - u16 caughtLvl; - u8 mapNameID; + u16 metLevel; + u8 metLocation; struct Pokemon* mon = &gPlayerParty[id]; CreateHatchedMon(mon, &gEnemyParty[0]); SetMonData(mon, MON_DATA_IS_EGG, &isEgg); - pokeNum = GetMonData(mon, MON_DATA_SPECIES); - GetSpeciesName(name, pokeNum); + species = GetMonData(mon, MON_DATA_SPECIES); + GetSpeciesName(name, species); SetMonData(mon, MON_DATA_NICKNAME, name); - pokeNum = SpeciesToNationalPokedexNum(pokeNum); - GetSetPokedexFlag(pokeNum, FLAG_SET_SEEN); - GetSetPokedexFlag(pokeNum, FLAG_SET_CAUGHT); + species = SpeciesToNationalPokedexNum(species); + GetSetPokedexFlag(species, FLAG_SET_SEEN); + GetSetPokedexFlag(species, FLAG_SET_CAUGHT); GetMonNickname2(mon, gStringVar1); ball = ITEM_POKE_BALL; SetMonData(mon, MON_DATA_POKEBALL, &ball); - caughtLvl = 0; - SetMonData(mon, MON_DATA_MET_LEVEL, &caughtLvl); + // A met level of 0 is interpreted on the summary screen as "hatched at" + metLevel = 0; + SetMonData(mon, MON_DATA_MET_LEVEL, &metLevel); - mapNameID = GetCurrentRegionMapSectionId(); - SetMonData(mon, MON_DATA_MET_LOCATION, &mapNameID); + metLocation = GetCurrentRegionMapSectionId(); + SetMonData(mon, MON_DATA_MET_LOCATION, &metLocation); MonRestorePP(mon); CalculateMonStats(mon); @@ -396,7 +405,7 @@ static bool8 _CheckDaycareMonReceivedMail(struct DayCare *daycare, u8 daycareId) GetBoxMonNickname(&daycareMon->mon, nickname); if (daycareMon->mail.message.itemId != ITEM_NONE && (StringCompareWithoutExtCtrlCodes(nickname, daycareMon->mail.monName) != 0 - || StringCompareWithoutExtCtrlCodes(gSaveBlock2Ptr->playerName, daycareMon->mail.otName) != 0)) + || StringCompareWithoutExtCtrlCodes(gSaveBlock2Ptr->playerName, daycareMon->mail.otName) != 0)) { StringCopy(gStringVar1, nickname); TVShowConvertInternationalString(gStringVar2, daycareMon->mail.otName, daycareMon->mail.gameLanguage); @@ -411,26 +420,27 @@ bool8 CheckDaycareMonReceivedMail(void) return _CheckDaycareMonReceivedMail(&gSaveBlock1Ptr->daycare, gSpecialVar_0x8004); } -static u8 EggHatchCreateMonSprite(u8 useAlt, u8 switchID, u8 pokeID, u16* speciesLoc) +static u8 EggHatchCreateMonSprite(u8 useAlt, u8 state, u8 partyId, u16* speciesLoc) { u8 position = 0; - u8 spriteID = 0; + u8 spriteId = 0; struct Pokemon* mon = NULL; if (useAlt == FALSE) { - mon = &gPlayerParty[pokeID]; + mon = &gPlayerParty[partyId]; position = B_POSITION_OPPONENT_LEFT; } if (useAlt == TRUE) { // Alternate sprite allocation position. Never reached. - mon = &gPlayerParty[pokeID]; + mon = &gPlayerParty[partyId]; position = B_POSITION_OPPONENT_RIGHT; } - switch (switchID) + switch (state) { case 0: + // Load mon sprite gfx { u16 species = GetMonData(mon, MON_DATA_SPECIES); u32 pid = GetMonData(mon, MON_DATA_PERSONALITY); @@ -442,13 +452,14 @@ static u8 EggHatchCreateMonSprite(u8 useAlt, u8 switchID, u8 pokeID, u16* specie } break; case 1: + // Create mon sprite SetMultiuseSpriteTemplateToPokemon(GetMonSpritePalStruct(mon)->tag, position); - spriteID = CreateSprite(&gMultiuseSpriteTemplate, 120, 75, 6); - gSprites[spriteID].invisible = TRUE; - gSprites[spriteID].callback = SpriteCallbackDummy; + spriteId = CreateSprite(&gMultiuseSpriteTemplate, EGG_X, EGG_Y, 6); + gSprites[spriteId].invisible = TRUE; + gSprites[spriteId].callback = SpriteCallbackDummy; break; } - return spriteID; + return spriteId; } static void VBlankCB_EggHatch(void) @@ -465,28 +476,28 @@ void EggHatch(void) FadeScreen(FADE_TO_BLACK, 0); } -static void Task_EggHatch(u8 taskID) +static void Task_EggHatch(u8 taskId) { if (!gPaletteFade.active) { CleanupOverworldWindowsAndTilemaps(); - SetMainCallback2(CB2_EggHatch_0); + SetMainCallback2(CB2_LoadEggHatch); gFieldCallback = FieldCB_ContinueScriptHandleMusic; - DestroyTask(taskID); + DestroyTask(taskId); } } -static void CB2_EggHatch_0(void) +static void CB2_LoadEggHatch(void) { switch (gMain.state) { case 0: SetGpuReg(REG_OFFSET_DISPCNT, 0); - sEggHatchData = Alloc(sizeof(struct EggHatchData)); + sEggHatchData = Alloc(sizeof(*sEggHatchData)); AllocateMonSpritesGfx(); - sEggHatchData->eggPartyID = gSpecialVar_0x8004; - sEggHatchData->eggShardVelocityID = 0; + sEggHatchData->eggPartyId = gSpecialVar_0x8004; + sEggHatchData->eggShardVelocityId = 0; SetVBlankCallback(VBlankCB_EggHatch); gSpecialVar_0x8005 = GetCurrentMapMusic(); @@ -532,15 +543,15 @@ static void CB2_EggHatch_0(void) break; case 4: CopyBgTilemapBufferToVram(0); - AddHatchedMonToParty(sEggHatchData->eggPartyID); + AddHatchedMonToParty(sEggHatchData->eggPartyId); gMain.state++; break; case 5: - EggHatchCreateMonSprite(FALSE, 0, sEggHatchData->eggPartyID, &sEggHatchData->species); + EggHatchCreateMonSprite(FALSE, 0, sEggHatchData->eggPartyId, &sEggHatchData->species); gMain.state++; break; case 6: - sEggHatchData->pokeSpriteID = EggHatchCreateMonSprite(FALSE, 1, sEggHatchData->eggPartyID, &sEggHatchData->species); + sEggHatchData->monSpriteId = EggHatchCreateMonSprite(FALSE, 1, sEggHatchData->eggPartyId, &sEggHatchData->species); gMain.state++; break; case 7: @@ -552,8 +563,8 @@ static void CB2_EggHatch_0(void) gMain.state++; break; case 8: - SetMainCallback2(CB2_EggHatch_1); - sEggHatchData->CB2_state = 0; + SetMainCallback2(CB2_EggHatch); + sEggHatchData->state = 0; break; } RunTasks(); @@ -571,121 +582,127 @@ static void EggHatchSetMonNickname(void) SetMainCallback2(CB2_ReturnToField); } -static void Task_EggHatchPlayBGM(u8 taskID) +#define tTimer data[0] + +static void Task_EggHatchPlayBGM(u8 taskId) { - if (gTasks[taskID].data[0] == 0) + if (gTasks[taskId].tTimer == 0) { StopMapMusic(); PlayRainStoppingSoundEffect(); } - if (gTasks[taskID].data[0] == 1) + + if (gTasks[taskId].tTimer == 1) PlayBGM(MUS_EVOLUTION_INTRO); - if (gTasks[taskID].data[0] > 60) + + if (gTasks[taskId].tTimer > 60) { PlayBGM(MUS_EVOLUTION); - DestroyTask(taskID); - // UB: task is destroyed, yet the value is incremented - #ifdef UBFIX - return; - #endif + DestroyTask(taskId); } - gTasks[taskID].data[0]++; + gTasks[taskId].tTimer++; } -static void CB2_EggHatch_1(void) +static void CB2_EggHatch(void) { u16 species; u8 gender; u32 personality; - switch (sEggHatchData->CB2_state) + switch (sEggHatchData->state) { case 0: - BeginNormalPaletteFade(PALETTES_ALL, 0, 0x10, 0, RGB_BLACK); - sEggHatchData->eggSpriteID = CreateSprite(&sSpriteTemplate_EggHatch, 120, 75, 5); + BeginNormalPaletteFade(PALETTES_ALL, 0, 16, 0, RGB_BLACK); + sEggHatchData->eggSpriteId = CreateSprite(&sSpriteTemplate_Egg, EGG_X, EGG_Y, 5); ShowBg(0); ShowBg(1); - sEggHatchData->CB2_state++; + sEggHatchData->state++; CreateTask(Task_EggHatchPlayBGM, 5); break; case 1: if (!gPaletteFade.active) { FillWindowPixelBuffer(sEggHatchData->windowId, PIXEL_FILL(0)); - sEggHatchData->CB2_PalCounter = 0; - sEggHatchData->CB2_state++; + sEggHatchData->delayTimer = 0; + sEggHatchData->state++; } break; case 2: - if (++sEggHatchData->CB2_PalCounter > 30) + if (++sEggHatchData->delayTimer > 30) { - sEggHatchData->CB2_state++; - gSprites[sEggHatchData->eggSpriteID].callback = SpriteCB_Egg_0; + // Start hatching animation + sEggHatchData->state++; + gSprites[sEggHatchData->eggSpriteId].callback = SpriteCB_Egg_Shake1; } break; case 3: - if (gSprites[sEggHatchData->eggSpriteID].callback == SpriteCallbackDummy) + // Wait for hatching animation to finish + if (gSprites[sEggHatchData->eggSpriteId].callback == SpriteCallbackDummy) { - species = GetMonData(&gPlayerParty[sEggHatchData->eggPartyID], MON_DATA_SPECIES); - DoMonFrontSpriteAnimation(&gSprites[sEggHatchData->pokeSpriteID], species, FALSE, 1); - sEggHatchData->CB2_state++; + species = GetMonData(&gPlayerParty[sEggHatchData->eggPartyId], MON_DATA_SPECIES); + DoMonFrontSpriteAnimation(&gSprites[sEggHatchData->monSpriteId], species, FALSE, 1); + sEggHatchData->state++; } break; case 4: - if (gSprites[sEggHatchData->pokeSpriteID].callback == SpriteCallbackDummy) - { - sEggHatchData->CB2_state++; - } + // Wait for Pokémon's front sprite animation + if (gSprites[sEggHatchData->monSpriteId].callback == SpriteCallbackDummy) + sEggHatchData->state++; break; case 5: - GetMonNickname2(&gPlayerParty[sEggHatchData->eggPartyID], gStringVar1); + // "{mon} hatched from egg" message/fanfare + GetMonNickname2(&gPlayerParty[sEggHatchData->eggPartyId], gStringVar1); StringExpandPlaceholders(gStringVar4, gText_HatchedFromEgg); EggHatchPrintMessage(sEggHatchData->windowId, gStringVar4, 0, 3, TEXT_SKIP_DRAW); PlayFanfare(MUS_EVOLVED); - sEggHatchData->CB2_state++; + sEggHatchData->state++; PutWindowTilemap(sEggHatchData->windowId); CopyWindowToVram(sEggHatchData->windowId, COPYWIN_FULL); break; case 6: if (IsFanfareTaskInactive()) - sEggHatchData->CB2_state++; + sEggHatchData->state++; break; - case 7: + case 7: // Twice? if (IsFanfareTaskInactive()) - sEggHatchData->CB2_state++; + sEggHatchData->state++; break; case 8: - GetMonNickname2(&gPlayerParty[sEggHatchData->eggPartyID], gStringVar1); + // Ready the nickname prompt + GetMonNickname2(&gPlayerParty[sEggHatchData->eggPartyId], gStringVar1); StringExpandPlaceholders(gStringVar4, gText_NicknameHatchPrompt); EggHatchPrintMessage(sEggHatchData->windowId, gStringVar4, 0, 2, 1); - sEggHatchData->CB2_state++; + sEggHatchData->state++; break; case 9: + // Print the nickname prompt if (!IsTextPrinterActive(sEggHatchData->windowId)) { LoadUserWindowBorderGfx(sEggHatchData->windowId, 0x140, 0xE0); CreateYesNoMenu(&sYesNoWinTemplate, 0x140, 0xE, 0); - sEggHatchData->CB2_state++; + sEggHatchData->state++; } break; case 10: + // Handle the nickname prompt input switch (Menu_ProcessInputNoWrapClearOnChoose()) { - case 0: - GetMonNickname2(&gPlayerParty[sEggHatchData->eggPartyID], gStringVar3); - species = GetMonData(&gPlayerParty[sEggHatchData->eggPartyID], MON_DATA_SPECIES); - gender = GetMonGender(&gPlayerParty[sEggHatchData->eggPartyID]); - personality = GetMonData(&gPlayerParty[sEggHatchData->eggPartyID], MON_DATA_PERSONALITY, 0); + case 0: // Yes + GetMonNickname2(&gPlayerParty[sEggHatchData->eggPartyId], gStringVar3); + species = GetMonData(&gPlayerParty[sEggHatchData->eggPartyId], MON_DATA_SPECIES); + gender = GetMonGender(&gPlayerParty[sEggHatchData->eggPartyId]); + personality = GetMonData(&gPlayerParty[sEggHatchData->eggPartyId], MON_DATA_PERSONALITY, 0); DoNamingScreen(NAMING_SCREEN_NICKNAME, gStringVar3, species, gender, personality, EggHatchSetMonNickname); break; - case 1: - case -1: - sEggHatchData->CB2_state++; + case 1: // No + case MENU_B_PRESSED: + sEggHatchData->state++; + break; } break; case 11: - BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_BLACK); - sEggHatchData->CB2_state++; + BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); + sEggHatchData->state++; break; case 12: if (!gPaletteFade.active) @@ -707,136 +724,170 @@ static void CB2_EggHatch_1(void) UpdatePaletteFade(); } -static void SpriteCB_Egg_0(struct Sprite* sprite) +#define sTimer data[0] +#define sSinIdx data[1] +#define sDelayTimer data[2] + +static void SpriteCB_Egg_Shake1(struct Sprite* sprite) { - if (++sprite->data[0] > 20) + if (++sprite->sTimer > 20) { - sprite->callback = SpriteCB_Egg_1; - sprite->data[0] = 0; + sprite->callback = SpriteCB_Egg_Shake2; + sprite->sTimer = 0; } else { - sprite->data[1] = (sprite->data[1] + 20) & 0xFF; - sprite->x2 = Sin(sprite->data[1], 1); - if (sprite->data[0] == 15) + // Shake egg + sprite->sSinIdx = (sprite->sSinIdx + 20) & 0xFF; + sprite->x2 = Sin(sprite->sSinIdx, 1); + if (sprite->sTimer == 15) { + // First egg crack PlaySE(SE_BALL); - StartSpriteAnim(sprite, 1); + StartSpriteAnim(sprite, EGG_ANIM_CRACKED_1); CreateRandomEggShardSprite(); } } } -static void SpriteCB_Egg_1(struct Sprite* sprite) +static void SpriteCB_Egg_Shake2(struct Sprite* sprite) { - if (++sprite->data[2] > 30) + if (++sprite->sDelayTimer > 30) { - if (++sprite->data[0] > 20) + if (++sprite->sTimer > 20) { - sprite->callback = SpriteCB_Egg_2; - sprite->data[0] = 0; - sprite->data[2] = 0; + sprite->callback = SpriteCB_Egg_Shake3; + sprite->sTimer = 0; + sprite->sDelayTimer = 0; } else { - sprite->data[1] = (sprite->data[1] + 20) & 0xFF; - sprite->x2 = Sin(sprite->data[1], 2); - if (sprite->data[0] == 15) + // Shake egg + sprite->sSinIdx = (sprite->sSinIdx + 20) & 0xFF; + sprite->x2 = Sin(sprite->sSinIdx, 2); + if (sprite->sTimer == 15) { + // Second egg crack PlaySE(SE_BALL); - StartSpriteAnim(sprite, 2); + StartSpriteAnim(sprite, EGG_ANIM_CRACKED_2); } } } } -static void SpriteCB_Egg_2(struct Sprite* sprite) +static void SpriteCB_Egg_Shake3(struct Sprite* sprite) { - if (++sprite->data[2] > 30) + if (++sprite->sDelayTimer > 30) { - if (++sprite->data[0] > 38) + if (++sprite->sTimer > 38) { u16 species; - - sprite->callback = SpriteCB_Egg_3; - sprite->data[0] = 0; - species = GetMonData(&gPlayerParty[sEggHatchData->eggPartyID], MON_DATA_SPECIES); - gSprites[sEggHatchData->pokeSpriteID].x2 = 0; - gSprites[sEggHatchData->pokeSpriteID].y2 = 0; + sprite->callback = SpriteCB_Egg_WaitHatch; + sprite->sTimer = 0; + species = GetMonData(&gPlayerParty[sEggHatchData->eggPartyId], MON_DATA_SPECIES); + gSprites[sEggHatchData->monSpriteId].x2 = 0; + gSprites[sEggHatchData->monSpriteId].y2 = 0; } else { - sprite->data[1] = (sprite->data[1] + 20) & 0xFF; - sprite->x2 = Sin(sprite->data[1], 2); - if (sprite->data[0] == 15) + // Shake egg + sprite->sSinIdx = (sprite->sSinIdx + 20) & 0xFF; + sprite->x2 = Sin(sprite->sSinIdx, 2); + if (sprite->sTimer == 15) { + // Third egg crack + // This ineffectually sets the animation to the frame it's already using. + // They likely meant to use the 3rd and final cracked frame of the egg, which goes unused as a result. PlaySE(SE_BALL); - StartSpriteAnim(sprite, 2); + #ifdef BUGFIX + StartSpriteAnim(sprite, EGG_ANIM_CRACKED_3); + #else + StartSpriteAnim(sprite, EGG_ANIM_CRACKED_2); + #endif CreateRandomEggShardSprite(); CreateRandomEggShardSprite(); } - if (sprite->data[0] == 30) + if (sprite->sTimer == 30) PlaySE(SE_BALL); } } } -static void SpriteCB_Egg_3(struct Sprite* sprite) +static void SpriteCB_Egg_WaitHatch(struct Sprite* sprite) { - if (++sprite->data[0] > 50) + if (++sprite->sTimer > 50) { - sprite->callback = SpriteCB_Egg_4; - sprite->data[0] = 0; + sprite->callback = SpriteCB_Egg_Hatch; + sprite->sTimer = 0; } } -static void SpriteCB_Egg_4(struct Sprite* sprite) +static void SpriteCB_Egg_Hatch(struct Sprite* sprite) { s16 i; - if (sprite->data[0] == 0) - BeginNormalPaletteFade(PALETTES_ALL, -1, 0, 0x10, RGB_WHITEALPHA); - if (sprite->data[0] < 4u) + + // Fade to white to hide transition from egg to Pokémon + if (sprite->sTimer == 0) + BeginNormalPaletteFade(PALETTES_ALL, -1, 0, 16, RGB_WHITEALPHA); + + // Create a shower of 16 egg shards in 4 groups of 4 + if ((u32)sprite->sTimer < 4) { - for (i = 0; i <= 3; i++) + for (i = 0; i < 4; i++) CreateRandomEggShardSprite(); } - sprite->data[0]++; + + sprite->sTimer++; + if (!gPaletteFade.active) { + // Screen is hidden by the fade to white, hide egg PlaySE(SE_EGG_HATCH); sprite->invisible = TRUE; - sprite->callback = SpriteCB_Egg_5; - sprite->data[0] = 0; + sprite->callback = SpriteCB_Egg_Reveal; + sprite->sTimer = 0; } } -static void SpriteCB_Egg_5(struct Sprite* sprite) +static void SpriteCB_Egg_Reveal(struct Sprite* sprite) { - if (sprite->data[0] == 0) + if (sprite->sTimer == 0) { - gSprites[sEggHatchData->pokeSpriteID].invisible = FALSE; - StartSpriteAffineAnim(&gSprites[sEggHatchData->pokeSpriteID], BATTLER_AFFINE_EMERGE); + // Reveal hatched Pokémon + gSprites[sEggHatchData->monSpriteId].invisible = FALSE; + StartSpriteAffineAnim(&gSprites[sEggHatchData->monSpriteId], BATTLER_AFFINE_EMERGE); } - if (sprite->data[0] == 8) - BeginNormalPaletteFade(PALETTES_ALL, -1, 0x10, 0, RGB_WHITEALPHA); - if (sprite->data[0] <= 9) - gSprites[sEggHatchData->pokeSpriteID].y -= 1; - if (sprite->data[0] > 40) - sprite->callback = SpriteCallbackDummy; - sprite->data[0]++; + + // Fade back from white for reveal + if (sprite->sTimer == 8) + BeginNormalPaletteFade(PALETTES_ALL, -1, 16, 0, RGB_WHITEALPHA); + + if (sprite->sTimer <= 9) + gSprites[sEggHatchData->monSpriteId].y--; + + if (sprite->sTimer > 40) + sprite->callback = SpriteCallbackDummy; // Finished + + sprite->sTimer++; } +#define sVelocX data[1] +#define sVelocY data[2] +#define sAccelY data[3] +#define sDeltaX data[4] +#define sDeltaY data[5] + static void SpriteCB_EggShard(struct Sprite* sprite) { - sprite->data[4] += sprite->data[1]; - sprite->data[5] += sprite->data[2]; + sprite->sDeltaX += sprite->sVelocX; + sprite->sDeltaY += sprite->sVelocY; - sprite->x2 = sprite->data[4] / 256; - sprite->y2 = sprite->data[5] / 256; + sprite->x2 = sprite->sDeltaX / 256; + sprite->y2 = sprite->sDeltaY / 256; - sprite->data[2] += sprite->data[3]; + sprite->sVelocY += sprite->sAccelY; - if (sprite->y + sprite->y2 > sprite->y + 20 && sprite->data[2] > 0) + if (sprite->y + sprite->y2 > sprite->y + 20 && sprite->sVelocY > 0) DestroySprite(sprite); } @@ -844,20 +895,23 @@ static void CreateRandomEggShardSprite(void) { u16 spriteAnimIndex; - s16 velocity1 = sEggShardVelocities[sEggHatchData->eggShardVelocityID][0]; - s16 velocity2 = sEggShardVelocities[sEggHatchData->eggShardVelocityID][1]; - sEggHatchData->eggShardVelocityID++; - spriteAnimIndex = Random() % 4; - CreateEggShardSprite(120, 60, velocity1, velocity2, 100, spriteAnimIndex); + s16 velocityX = sEggShardVelocities[sEggHatchData->eggShardVelocityId][0]; + s16 velocityY = sEggShardVelocities[sEggHatchData->eggShardVelocityId][1]; + sEggHatchData->eggShardVelocityId++; + + // Randomly choose one of the 4 shard images + spriteAnimIndex = Random() % ARRAY_COUNT(sSpriteAnimTable_EggShard); + + CreateEggShardSprite(EGG_X, EGG_Y - 15, velocityX, velocityY, 100, spriteAnimIndex); } -static void CreateEggShardSprite(u8 x, u8 y, s16 data1, s16 data2, s16 data3, u8 spriteAnimIndex) +static void CreateEggShardSprite(u8 x, u8 y, s16 velocityX, s16 velocityY, s16 acceleration, u8 spriteAnimIndex) { - u8 spriteID = CreateSprite(&sSpriteTemplate_EggShard, x, y, 4); - gSprites[spriteID].data[1] = data1; - gSprites[spriteID].data[2] = data2; - gSprites[spriteID].data[3] = data3; - StartSpriteAnim(&gSprites[spriteID], spriteAnimIndex); + u8 spriteId = CreateSprite(&sSpriteTemplate_EggShard, x, y, 4); + gSprites[spriteId].sVelocX = velocityX; + gSprites[spriteId].sVelocY = velocityY; + gSprites[spriteId].sAccelY = acceleration; + StartSpriteAnim(&gSprites[spriteId], spriteAnimIndex); } static void EggHatchPrintMessage(u8 windowId, u8* string, u8 x, u8 y, u8 speed) From f78f46a1e28667632bf25c968ffb97aea84bdb15 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Thu, 3 Mar 2022 14:54:05 -0500 Subject: [PATCH 051/130] Use ARRAY_COUNT for obj event subsprite tables --- .../object_events/object_event_subsprites.h | 96 +++++++++---------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/src/data/object_events/object_event_subsprites.h b/src/data/object_events/object_event_subsprites.h index b508509ca..808491992 100755 --- a/src/data/object_events/object_event_subsprites.h +++ b/src/data/object_events/object_event_subsprites.h @@ -78,12 +78,12 @@ static const struct Subsprite sOamTable_16x16_4[] = { }; static const struct SubspriteTable sOamTables_16x16[] = { - {0, NULL}, - {1, sOamTable_16x16_0}, - {1, sOamTable_16x16_1}, - {2, sOamTable_16x16_2}, - {2, sOamTable_16x16_3}, - {2, sOamTable_16x16_4} + {}, + {ARRAY_COUNT(sOamTable_16x16_0), sOamTable_16x16_0}, + {ARRAY_COUNT(sOamTable_16x16_1), sOamTable_16x16_1}, + {ARRAY_COUNT(sOamTable_16x16_2), sOamTable_16x16_2}, + {ARRAY_COUNT(sOamTable_16x16_3), sOamTable_16x16_3}, + {ARRAY_COUNT(sOamTable_16x16_4), sOamTable_16x16_4} }; static const struct Subsprite sOamTable_16x32_0[] = { @@ -174,12 +174,12 @@ static const struct Subsprite sOamTable_16x32_4[] = { }; static const struct SubspriteTable sOamTables_16x32[] = { - {0, NULL}, - {1, sOamTable_16x32_0}, - {1, sOamTable_16x32_1}, - {3, sOamTable_16x32_2}, - {2, sOamTable_16x32_3}, - {2, sOamTable_16x32_4} + {}, + {ARRAY_COUNT(sOamTable_16x32_0), sOamTable_16x32_0}, + {ARRAY_COUNT(sOamTable_16x32_1), sOamTable_16x32_1}, + {ARRAY_COUNT(sOamTable_16x32_2), sOamTable_16x32_2}, + {ARRAY_COUNT(sOamTable_16x32_3), sOamTable_16x32_3}, + {ARRAY_COUNT(sOamTable_16x32_4), sOamTable_16x32_4} }; static const struct Subsprite sOamTable_32x32_0[] = { @@ -270,12 +270,12 @@ static const struct Subsprite sOamTable_32x32_4[] = { }; static const struct SubspriteTable sOamTables_32x32[] = { - {0, NULL}, - {1, sOamTable_32x32_0}, - {1, sOamTable_32x32_1}, - {3, sOamTable_32x32_2}, - {2, sOamTable_32x32_3}, - {2, sOamTable_32x32_4} + {}, + {ARRAY_COUNT(sOamTable_32x32_0), sOamTable_32x32_0}, + {ARRAY_COUNT(sOamTable_32x32_1), sOamTable_32x32_1}, + {ARRAY_COUNT(sOamTable_32x32_2), sOamTable_32x32_2}, + {ARRAY_COUNT(sOamTable_32x32_3), sOamTable_32x32_3}, + {ARRAY_COUNT(sOamTable_32x32_4), sOamTable_32x32_4} }; static const struct Subsprite sOamTable_48x48[] = { @@ -378,12 +378,12 @@ static const struct Subsprite sOamTable_48x48[] = { }; static const struct SubspriteTable sOamTables_48x48[] = { - {12, sOamTable_48x48}, - {12, sOamTable_48x48}, - {12, sOamTable_48x48}, - {12, sOamTable_48x48}, - {12, sOamTable_48x48}, - {12, sOamTable_48x48} + {ARRAY_COUNT(sOamTable_48x48), sOamTable_48x48}, + {ARRAY_COUNT(sOamTable_48x48), sOamTable_48x48}, + {ARRAY_COUNT(sOamTable_48x48), sOamTable_48x48}, + {ARRAY_COUNT(sOamTable_48x48), sOamTable_48x48}, + {ARRAY_COUNT(sOamTable_48x48), sOamTable_48x48}, + {ARRAY_COUNT(sOamTable_48x48), sOamTable_48x48} }; static const struct Subsprite sOamTable_64x32_0[] = { @@ -432,12 +432,12 @@ static const struct Subsprite sOamTable_64x32_3[] = { // Unused static const struct SubspriteTable sOamTables_64x32[] = { - {0, NULL}, - {1, sOamTable_64x32_0}, - {1, sOamTable_64x32_1}, - {1, sOamTable_64x32_2}, - {1, sOamTable_64x32_3}, - {1, sOamTable_64x32_3} + {}, + {ARRAY_COUNT(sOamTable_64x32_0), sOamTable_64x32_0}, + {ARRAY_COUNT(sOamTable_64x32_1), sOamTable_64x32_1}, + {ARRAY_COUNT(sOamTable_64x32_2), sOamTable_64x32_2}, + {ARRAY_COUNT(sOamTable_64x32_3), sOamTable_64x32_3}, + {ARRAY_COUNT(sOamTable_64x32_3), sOamTable_64x32_3} }; static const struct Subsprite sOamTable_64x64_0[] = { @@ -485,12 +485,12 @@ static const struct Subsprite sOamTable_64x64_3[] = { }; static const struct SubspriteTable sOamTables_64x64[] = { - {0, NULL}, - {1, sOamTable_64x64_0}, - {1, sOamTable_64x64_1}, - {1, sOamTable_64x64_2}, - {1, sOamTable_64x64_3}, - {1, sOamTable_64x64_3} + {}, + {ARRAY_COUNT(sOamTable_64x64_0), sOamTable_64x64_0}, + {ARRAY_COUNT(sOamTable_64x64_1), sOamTable_64x64_1}, + {ARRAY_COUNT(sOamTable_64x64_2), sOamTable_64x64_2}, + {ARRAY_COUNT(sOamTable_64x64_3), sOamTable_64x64_3}, + {ARRAY_COUNT(sOamTable_64x64_3), sOamTable_64x64_3} }; static const struct Subsprite sOamTable_96x40_0[] = { @@ -987,12 +987,12 @@ static const struct Subsprite sOamTable_96x40_3[] = { // Used by SS Tidal static const struct SubspriteTable sOamTables_96x40[] = { - {15, sOamTable_96x40_0}, - {15, sOamTable_96x40_0}, - {15, sOamTable_96x40_1}, - {15, sOamTable_96x40_2}, - {15, sOamTable_96x40_3}, - {15, sOamTable_96x40_3} + {ARRAY_COUNT(sOamTable_96x40_0), sOamTable_96x40_0}, + {ARRAY_COUNT(sOamTable_96x40_0), sOamTable_96x40_0}, + {ARRAY_COUNT(sOamTable_96x40_1), sOamTable_96x40_1}, + {ARRAY_COUNT(sOamTable_96x40_2), sOamTable_96x40_2}, + {ARRAY_COUNT(sOamTable_96x40_3), sOamTable_96x40_3}, + {ARRAY_COUNT(sOamTable_96x40_3), sOamTable_96x40_3} }; static const struct Subsprite sOamTable_88x32_0[] = { @@ -1521,10 +1521,10 @@ static const struct Subsprite sOamTable_88x32_3[] = { // Used by Submarine Shadow static const struct SubspriteTable sOamTables_88x32[] = { - {16, sOamTable_88x32_0}, - {16, sOamTable_88x32_0}, - {16, sOamTable_88x32_1}, - {16, sOamTable_88x32_2}, - {16, sOamTable_88x32_3}, - {16, sOamTable_88x32_3} + {ARRAY_COUNT(sOamTable_88x32_0), sOamTable_88x32_0}, + {ARRAY_COUNT(sOamTable_88x32_0), sOamTable_88x32_0}, + {ARRAY_COUNT(sOamTable_88x32_1), sOamTable_88x32_1}, + {ARRAY_COUNT(sOamTable_88x32_2), sOamTable_88x32_2}, + {ARRAY_COUNT(sOamTable_88x32_3), sOamTable_88x32_3}, + {ARRAY_COUNT(sOamTable_88x32_3), sOamTable_88x32_3} }; From d66413557288082f0b553b209b51fede7d8810c8 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Thu, 10 Mar 2022 10:33:23 -0500 Subject: [PATCH 052/130] Add usage of battle strings table offset constant --- include/battle_arena.h | 2 +- include/constants/battle_string_ids.h | 10 +- src/battle_arena.c | 2 +- src/battle_controller_opponent.c | 2 +- src/battle_controller_player.c | 2 +- src/battle_message.c | 746 +++++++++++++------------- src/battle_tv.c | 2 +- src/evolution_scene.c | 44 +- 8 files changed, 406 insertions(+), 404 deletions(-) diff --git a/include/battle_arena.h b/include/battle_arena.h index c9a18ef61..cc0e72c0c 100644 --- a/include/battle_arena.h +++ b/include/battle_arena.h @@ -6,7 +6,7 @@ u8 BattleArena_ShowJudgmentWindow(u8 *state); void BattleArena_InitPoints(void); void BattleArena_AddMindPoints(u8 battler); void BattleArena_AddSkillPoints(u8 battler); -void BattleArena_DeductMindPoints(u8 battler, u16 stringId); +void BattleArena_DeductSkillPoints(u8 battler, u16 stringId); void DrawArenaRefereeTextBox(void); void EraseArenaRefereeTextBox(void); diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index c8d37aac6..d5d0698b9 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -1,10 +1,6 @@ #ifndef GUARD_CONSTANTS_BATTLE_STRING_IDS_H #define GUARD_CONSTANTS_BATTLE_STRING_IDS_H -#define BATTLESTRINGS_COUNT 369 - -#define BATTLESTRINGS_ID_ADDER 12 // all battlestrings have its ID + 12, because first 5 are reserved - #define STRINGID_INTROMSG 0 #define STRINGID_INTROSENDOUT 1 #define STRINGID_RETURNMON 2 @@ -383,6 +379,12 @@ #define STRINGID_TRAINER1WINTEXT 379 #define STRINGID_TRAINER2WINTEXT 380 +#define BATTLESTRINGS_COUNT 381 + +// This is the string id that gBattleStringsTable starts with. +// String ids before this (e.g. STRINGID_INTROMSG) are not in the table, +// and are instead handled explicitly by BufferStringBattle. +#define BATTLESTRINGS_TABLE_START STRINGID_TRAINER1LOSETEXT // The below IDs are all indexes into battle message tables, // used to determine which of a set of messages to print. diff --git a/src/battle_arena.c b/src/battle_arena.c index f744a3b2b..a7c74366b 100644 --- a/src/battle_arena.c +++ b/src/battle_arena.c @@ -741,7 +741,7 @@ void BattleArena_AddSkillPoints(u8 battler) } } -void BattleArena_DeductMindPoints(u8 battler, u16 stringId) +void BattleArena_DeductSkillPoints(u8 battler, u16 stringId) { s8 *skillPoints = gBattleStruct->arenaSkillPoints; diff --git a/src/battle_controller_opponent.c b/src/battle_controller_opponent.c index c3830780b..ead5a8768 100644 --- a/src/battle_controller_opponent.c +++ b/src/battle_controller_opponent.c @@ -1523,7 +1523,7 @@ static void OpponentHandlePrintString(void) BufferStringBattle(*stringId); BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_MSG); gBattlerControllerFuncs[gActiveBattler] = CompleteOnInactiveTextPrinter; - BattleArena_DeductMindPoints(gActiveBattler, *stringId); + BattleArena_DeductSkillPoints(gActiveBattler, *stringId); } static void OpponentHandlePrintSelectionString(void) diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index 2133d5b6f..5b69030df 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -2551,7 +2551,7 @@ static void PlayerHandlePrintString(void) BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_MSG); gBattlerControllerFuncs[gActiveBattler] = CompleteOnInactiveTextPrinter2; BattleTv_SetDataBasedOnString(*stringId); - BattleArena_DeductMindPoints(gActiveBattler, *stringId); + BattleArena_DeductSkillPoints(gActiveBattler, *stringId); } static void PlayerHandlePrintSelectionString(void) diff --git a/src/battle_message.c b/src/battle_message.c index 1df935694..9d1b88ba7 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -514,377 +514,377 @@ static const u8 sText_Trainer2WinText[]; static const u8 sText_TwoInGameTrainersDefeated[]; static const u8 sText_Trainer2LoseText[]; -const u8 * const gBattleStringsTable[BATTLESTRINGS_COUNT] = +const u8 * const gBattleStringsTable[BATTLESTRINGS_COUNT - BATTLESTRINGS_TABLE_START] = { - [STRINGID_TRAINER1LOSETEXT - 12] = sText_Trainer1LoseText, - [STRINGID_PKMNGAINEDEXP - 12] = sText_PkmnGainedEXP, - [STRINGID_PKMNGREWTOLV - 12] = sText_PkmnGrewToLv, - [STRINGID_PKMNLEARNEDMOVE - 12] = sText_PkmnLearnedMove, - [STRINGID_TRYTOLEARNMOVE1 - 12] = sText_TryToLearnMove1, - [STRINGID_TRYTOLEARNMOVE2 - 12] = sText_TryToLearnMove2, - [STRINGID_TRYTOLEARNMOVE3 - 12] = sText_TryToLearnMove3, - [STRINGID_PKMNFORGOTMOVE - 12] = sText_PkmnForgotMove, - [STRINGID_STOPLEARNINGMOVE - 12] = sText_StopLearningMove, - [STRINGID_DIDNOTLEARNMOVE - 12] = sText_DidNotLearnMove, - [STRINGID_PKMNLEARNEDMOVE2 - 12] = sText_PkmnLearnedMove2, - [STRINGID_ATTACKMISSED - 12] = sText_AttackMissed, - [STRINGID_PKMNPROTECTEDITSELF - 12] = sText_PkmnProtectedItself, - [STRINGID_STATSWONTINCREASE2 - 12] = sText_StatsWontIncrease2, - [STRINGID_AVOIDEDDAMAGE - 12] = sText_AvoidedDamage, - [STRINGID_ITDOESNTAFFECT - 12] = sText_ItDoesntAffect, - [STRINGID_ATTACKERFAINTED - 12] = sText_AttackerFainted, - [STRINGID_TARGETFAINTED - 12] = sText_TargetFainted, - [STRINGID_PLAYERGOTMONEY - 12] = sText_PlayerGotMoney, - [STRINGID_PLAYERWHITEOUT - 12] = sText_PlayerWhiteout, - [STRINGID_PLAYERWHITEOUT2 - 12] = sText_PlayerWhiteout2, - [STRINGID_PREVENTSESCAPE - 12] = sText_PreventsEscape, - [STRINGID_HITXTIMES - 12] = sText_HitXTimes, - [STRINGID_PKMNFELLASLEEP - 12] = sText_PkmnFellAsleep, - [STRINGID_PKMNMADESLEEP - 12] = sText_PkmnMadeSleep, - [STRINGID_PKMNALREADYASLEEP - 12] = sText_PkmnAlreadyAsleep, - [STRINGID_PKMNALREADYASLEEP2 - 12] = sText_PkmnAlreadyAsleep2, - [STRINGID_PKMNWASNTAFFECTED - 12] = sText_PkmnWasntAffected, - [STRINGID_PKMNWASPOISONED - 12] = sText_PkmnWasPoisoned, - [STRINGID_PKMNPOISONEDBY - 12] = sText_PkmnPoisonedBy, - [STRINGID_PKMNHURTBYPOISON - 12] = sText_PkmnHurtByPoison, - [STRINGID_PKMNALREADYPOISONED - 12] = sText_PkmnAlreadyPoisoned, - [STRINGID_PKMNBADLYPOISONED - 12] = sText_PkmnBadlyPoisoned, - [STRINGID_PKMNENERGYDRAINED - 12] = sText_PkmnEnergyDrained, - [STRINGID_PKMNWASBURNED - 12] = sText_PkmnWasBurned, - [STRINGID_PKMNBURNEDBY - 12] = sText_PkmnBurnedBy, - [STRINGID_PKMNHURTBYBURN - 12] = sText_PkmnHurtByBurn, - [STRINGID_PKMNWASFROZEN - 12] = sText_PkmnWasFrozen, - [STRINGID_PKMNFROZENBY - 12] = sText_PkmnFrozenBy, - [STRINGID_PKMNISFROZEN - 12] = sText_PkmnIsFrozen, - [STRINGID_PKMNWASDEFROSTED - 12] = sText_PkmnWasDefrosted, - [STRINGID_PKMNWASDEFROSTED2 - 12] = sText_PkmnWasDefrosted2, - [STRINGID_PKMNWASDEFROSTEDBY - 12] = sText_PkmnWasDefrostedBy, - [STRINGID_PKMNWASPARALYZED - 12] = sText_PkmnWasParalyzed, - [STRINGID_PKMNWASPARALYZEDBY - 12] = sText_PkmnWasParalyzedBy, - [STRINGID_PKMNISPARALYZED - 12] = sText_PkmnIsParalyzed, - [STRINGID_PKMNISALREADYPARALYZED - 12] = sText_PkmnIsAlreadyParalyzed, - [STRINGID_PKMNHEALEDPARALYSIS - 12] = sText_PkmnHealedParalysis, - [STRINGID_PKMNDREAMEATEN - 12] = sText_PkmnDreamEaten, - [STRINGID_STATSWONTINCREASE - 12] = sText_StatsWontIncrease, - [STRINGID_STATSWONTDECREASE - 12] = sText_StatsWontDecrease, - [STRINGID_TEAMSTOPPEDWORKING - 12] = sText_TeamStoppedWorking, - [STRINGID_FOESTOPPEDWORKING - 12] = sText_FoeStoppedWorking, - [STRINGID_PKMNISCONFUSED - 12] = sText_PkmnIsConfused, - [STRINGID_PKMNHEALEDCONFUSION - 12] = sText_PkmnHealedConfusion, - [STRINGID_PKMNWASCONFUSED - 12] = sText_PkmnWasConfused, - [STRINGID_PKMNALREADYCONFUSED - 12] = sText_PkmnAlreadyConfused, - [STRINGID_PKMNFELLINLOVE - 12] = sText_PkmnFellInLove, - [STRINGID_PKMNINLOVE - 12] = sText_PkmnInLove, - [STRINGID_PKMNIMMOBILIZEDBYLOVE - 12] = sText_PkmnImmobilizedByLove, - [STRINGID_PKMNBLOWNAWAY - 12] = sText_PkmnBlownAway, - [STRINGID_PKMNCHANGEDTYPE - 12] = sText_PkmnChangedType, - [STRINGID_PKMNFLINCHED - 12] = sText_PkmnFlinched, - [STRINGID_PKMNREGAINEDHEALTH - 12] = sText_PkmnRegainedHealth, - [STRINGID_PKMNHPFULL - 12] = sText_PkmnHPFull, - [STRINGID_PKMNRAISEDSPDEF - 12] = sText_PkmnRaisedSpDef, - [STRINGID_PKMNRAISEDDEF - 12] = sText_PkmnRaisedDef, - [STRINGID_PKMNCOVEREDBYVEIL - 12] = sText_PkmnCoveredByVeil, - [STRINGID_PKMNUSEDSAFEGUARD - 12] = sText_PkmnUsedSafeguard, - [STRINGID_PKMNSAFEGUARDEXPIRED - 12] = sText_PkmnSafeguardExpired, - [STRINGID_PKMNWENTTOSLEEP - 12] = sText_PkmnWentToSleep, - [STRINGID_PKMNSLEPTHEALTHY - 12] = sText_PkmnSleptHealthy, - [STRINGID_PKMNWHIPPEDWHIRLWIND - 12] = sText_PkmnWhippedWhirlwind, - [STRINGID_PKMNTOOKSUNLIGHT - 12] = sText_PkmnTookSunlight, - [STRINGID_PKMNLOWEREDHEAD - 12] = sText_PkmnLoweredHead, - [STRINGID_PKMNISGLOWING - 12] = sText_PkmnIsGlowing, - [STRINGID_PKMNFLEWHIGH - 12] = sText_PkmnFlewHigh, - [STRINGID_PKMNDUGHOLE - 12] = sText_PkmnDugHole, - [STRINGID_PKMNSQUEEZEDBYBIND - 12] = sText_PkmnSqueezedByBind, - [STRINGID_PKMNTRAPPEDINVORTEX - 12] = sText_PkmnTrappedInVortex, - [STRINGID_PKMNWRAPPEDBY - 12] = sText_PkmnWrappedBy, - [STRINGID_PKMNCLAMPED - 12] = sText_PkmnClamped, - [STRINGID_PKMNHURTBY - 12] = sText_PkmnHurtBy, - [STRINGID_PKMNFREEDFROM - 12] = sText_PkmnFreedFrom, - [STRINGID_PKMNCRASHED - 12] = sText_PkmnCrashed, - [STRINGID_PKMNSHROUDEDINMIST - 12] = gText_PkmnShroudedInMist, - [STRINGID_PKMNPROTECTEDBYMIST - 12] = sText_PkmnProtectedByMist, - [STRINGID_PKMNGETTINGPUMPED - 12] = gText_PkmnGettingPumped, - [STRINGID_PKMNHITWITHRECOIL - 12] = sText_PkmnHitWithRecoil, - [STRINGID_PKMNPROTECTEDITSELF2 - 12] = sText_PkmnProtectedItself2, - [STRINGID_PKMNBUFFETEDBYSANDSTORM - 12] = sText_PkmnBuffetedBySandstorm, - [STRINGID_PKMNPELTEDBYHAIL - 12] = sText_PkmnPeltedByHail, - [STRINGID_PKMNSEEDED - 12] = sText_PkmnSeeded, - [STRINGID_PKMNEVADEDATTACK - 12] = sText_PkmnEvadedAttack, - [STRINGID_PKMNSAPPEDBYLEECHSEED - 12] = sText_PkmnSappedByLeechSeed, - [STRINGID_PKMNFASTASLEEP - 12] = sText_PkmnFastAsleep, - [STRINGID_PKMNWOKEUP - 12] = sText_PkmnWokeUp, - [STRINGID_PKMNUPROARKEPTAWAKE - 12] = sText_PkmnUproarKeptAwake, - [STRINGID_PKMNWOKEUPINUPROAR - 12] = sText_PkmnWokeUpInUproar, - [STRINGID_PKMNCAUSEDUPROAR - 12] = sText_PkmnCausedUproar, - [STRINGID_PKMNMAKINGUPROAR - 12] = sText_PkmnMakingUproar, - [STRINGID_PKMNCALMEDDOWN - 12] = sText_PkmnCalmedDown, - [STRINGID_PKMNCANTSLEEPINUPROAR - 12] = sText_PkmnCantSleepInUproar, - [STRINGID_PKMNSTOCKPILED - 12] = sText_PkmnStockpiled, - [STRINGID_PKMNCANTSTOCKPILE - 12] = sText_PkmnCantStockpile, - [STRINGID_PKMNCANTSLEEPINUPROAR2 - 12] = sText_PkmnCantSleepInUproar2, - [STRINGID_UPROARKEPTPKMNAWAKE - 12] = sText_UproarKeptPkmnAwake, - [STRINGID_PKMNSTAYEDAWAKEUSING - 12] = sText_PkmnStayedAwakeUsing, - [STRINGID_PKMNSTORINGENERGY - 12] = sText_PkmnStoringEnergy, - [STRINGID_PKMNUNLEASHEDENERGY - 12] = sText_PkmnUnleashedEnergy, - [STRINGID_PKMNFATIGUECONFUSION - 12] = sText_PkmnFatigueConfusion, - [STRINGID_PLAYERPICKEDUPMONEY - 12] = sText_PlayerPickedUpMoney, - [STRINGID_PKMNUNAFFECTED - 12] = sText_PkmnUnaffected, - [STRINGID_PKMNTRANSFORMEDINTO - 12] = sText_PkmnTransformedInto, - [STRINGID_PKMNMADESUBSTITUTE - 12] = sText_PkmnMadeSubstitute, - [STRINGID_PKMNHASSUBSTITUTE - 12] = sText_PkmnHasSubstitute, - [STRINGID_SUBSTITUTEDAMAGED - 12] = sText_SubstituteDamaged, - [STRINGID_PKMNSUBSTITUTEFADED - 12] = sText_PkmnSubstituteFaded, - [STRINGID_PKMNMUSTRECHARGE - 12] = sText_PkmnMustRecharge, - [STRINGID_PKMNRAGEBUILDING - 12] = sText_PkmnRageBuilding, - [STRINGID_PKMNMOVEWASDISABLED - 12] = sText_PkmnMoveWasDisabled, - [STRINGID_PKMNMOVEISDISABLED - 12] = sText_PkmnMoveIsDisabled, - [STRINGID_PKMNMOVEDISABLEDNOMORE - 12] = sText_PkmnMoveDisabledNoMore, - [STRINGID_PKMNGOTENCORE - 12] = sText_PkmnGotEncore, - [STRINGID_PKMNENCOREENDED - 12] = sText_PkmnEncoreEnded, - [STRINGID_PKMNTOOKAIM - 12] = sText_PkmnTookAim, - [STRINGID_PKMNSKETCHEDMOVE - 12] = sText_PkmnSketchedMove, - [STRINGID_PKMNTRYINGTOTAKEFOE - 12] = sText_PkmnTryingToTakeFoe, - [STRINGID_PKMNTOOKFOE - 12] = sText_PkmnTookFoe, - [STRINGID_PKMNREDUCEDPP - 12] = sText_PkmnReducedPP, - [STRINGID_PKMNSTOLEITEM - 12] = sText_PkmnStoleItem, - [STRINGID_TARGETCANTESCAPENOW - 12] = sText_TargetCantEscapeNow, - [STRINGID_PKMNFELLINTONIGHTMARE - 12] = sText_PkmnFellIntoNightmare, - [STRINGID_PKMNLOCKEDINNIGHTMARE - 12] = sText_PkmnLockedInNightmare, - [STRINGID_PKMNLAIDCURSE - 12] = sText_PkmnLaidCurse, - [STRINGID_PKMNAFFLICTEDBYCURSE - 12] = sText_PkmnAfflictedByCurse, - [STRINGID_SPIKESSCATTERED - 12] = sText_SpikesScattered, - [STRINGID_PKMNHURTBYSPIKES - 12] = sText_PkmnHurtBySpikes, - [STRINGID_PKMNIDENTIFIED - 12] = sText_PkmnIdentified, - [STRINGID_PKMNPERISHCOUNTFELL - 12] = sText_PkmnPerishCountFell, - [STRINGID_PKMNBRACEDITSELF - 12] = sText_PkmnBracedItself, - [STRINGID_PKMNENDUREDHIT - 12] = sText_PkmnEnduredHit, - [STRINGID_MAGNITUDESTRENGTH - 12] = sText_MagnitudeStrength, - [STRINGID_PKMNCUTHPMAXEDATTACK - 12] = sText_PkmnCutHPMaxedAttack, - [STRINGID_PKMNCOPIEDSTATCHANGES - 12] = sText_PkmnCopiedStatChanges, - [STRINGID_PKMNGOTFREE - 12] = sText_PkmnGotFree, - [STRINGID_PKMNSHEDLEECHSEED - 12] = sText_PkmnShedLeechSeed, - [STRINGID_PKMNBLEWAWAYSPIKES - 12] = sText_PkmnBlewAwaySpikes, - [STRINGID_PKMNFLEDFROMBATTLE - 12] = sText_PkmnFledFromBattle, - [STRINGID_PKMNFORESAWATTACK - 12] = sText_PkmnForesawAttack, - [STRINGID_PKMNTOOKATTACK - 12] = sText_PkmnTookAttack, - [STRINGID_PKMNATTACK - 12] = sText_PkmnAttack, - [STRINGID_PKMNCENTERATTENTION - 12] = sText_PkmnCenterAttention, - [STRINGID_PKMNCHARGINGPOWER - 12] = sText_PkmnChargingPower, - [STRINGID_NATUREPOWERTURNEDINTO - 12] = sText_NaturePowerTurnedInto, - [STRINGID_PKMNSTATUSNORMAL - 12] = sText_PkmnStatusNormal, - [STRINGID_PKMNHASNOMOVESLEFT - 12] = sText_PkmnHasNoMovesLeft, - [STRINGID_PKMNSUBJECTEDTOTORMENT - 12] = sText_PkmnSubjectedToTorment, - [STRINGID_PKMNCANTUSEMOVETORMENT - 12] = sText_PkmnCantUseMoveTorment, - [STRINGID_PKMNTIGHTENINGFOCUS - 12] = sText_PkmnTighteningFocus, - [STRINGID_PKMNFELLFORTAUNT - 12] = sText_PkmnFellForTaunt, - [STRINGID_PKMNCANTUSEMOVETAUNT - 12] = sText_PkmnCantUseMoveTaunt, - [STRINGID_PKMNREADYTOHELP - 12] = sText_PkmnReadyToHelp, - [STRINGID_PKMNSWITCHEDITEMS - 12] = sText_PkmnSwitchedItems, - [STRINGID_PKMNCOPIEDFOE - 12] = sText_PkmnCopiedFoe, - [STRINGID_PKMNMADEWISH - 12] = sText_PkmnMadeWish, - [STRINGID_PKMNWISHCAMETRUE - 12] = sText_PkmnWishCameTrue, - [STRINGID_PKMNPLANTEDROOTS - 12] = sText_PkmnPlantedRoots, - [STRINGID_PKMNABSORBEDNUTRIENTS - 12] = sText_PkmnAbsorbedNutrients, - [STRINGID_PKMNANCHOREDITSELF - 12] = sText_PkmnAnchoredItself, - [STRINGID_PKMNWASMADEDROWSY - 12] = sText_PkmnWasMadeDrowsy, - [STRINGID_PKMNKNOCKEDOFF - 12] = sText_PkmnKnockedOff, - [STRINGID_PKMNSWAPPEDABILITIES - 12] = sText_PkmnSwappedAbilities, - [STRINGID_PKMNSEALEDOPPONENTMOVE - 12] = sText_PkmnSealedOpponentMove, - [STRINGID_PKMNCANTUSEMOVESEALED - 12] = sText_PkmnCantUseMoveSealed, - [STRINGID_PKMNWANTSGRUDGE - 12] = sText_PkmnWantsGrudge, - [STRINGID_PKMNLOSTPPGRUDGE - 12] = sText_PkmnLostPPGrudge, - [STRINGID_PKMNSHROUDEDITSELF - 12] = sText_PkmnShroudedItself, - [STRINGID_PKMNMOVEBOUNCED - 12] = sText_PkmnMoveBounced, - [STRINGID_PKMNWAITSFORTARGET - 12] = sText_PkmnWaitsForTarget, - [STRINGID_PKMNSNATCHEDMOVE - 12] = sText_PkmnSnatchedMove, - [STRINGID_PKMNMADEITRAIN - 12] = sText_PkmnMadeItRain, - [STRINGID_PKMNRAISEDSPEED - 12] = sText_PkmnRaisedSpeed, - [STRINGID_PKMNPROTECTEDBY - 12] = sText_PkmnProtectedBy, - [STRINGID_PKMNPREVENTSUSAGE - 12] = sText_PkmnPreventsUsage, - [STRINGID_PKMNRESTOREDHPUSING - 12] = sText_PkmnRestoredHPUsing, - [STRINGID_PKMNCHANGEDTYPEWITH - 12] = sText_PkmnChangedTypeWith, - [STRINGID_PKMNPREVENTSPARALYSISWITH - 12] = sText_PkmnPreventsParalysisWith, - [STRINGID_PKMNPREVENTSROMANCEWITH - 12] = sText_PkmnPreventsRomanceWith, - [STRINGID_PKMNPREVENTSPOISONINGWITH - 12] = sText_PkmnPreventsPoisoningWith, - [STRINGID_PKMNPREVENTSCONFUSIONWITH - 12] = sText_PkmnPreventsConfusionWith, - [STRINGID_PKMNRAISEDFIREPOWERWITH - 12] = sText_PkmnRaisedFirePowerWith, - [STRINGID_PKMNANCHORSITSELFWITH - 12] = sText_PkmnAnchorsItselfWith, - [STRINGID_PKMNCUTSATTACKWITH - 12] = sText_PkmnCutsAttackWith, - [STRINGID_PKMNPREVENTSSTATLOSSWITH - 12] = sText_PkmnPreventsStatLossWith, - [STRINGID_PKMNHURTSWITH - 12] = sText_PkmnHurtsWith, - [STRINGID_PKMNTRACED - 12] = sText_PkmnTraced, - [STRINGID_STATSHARPLY - 12] = sText_StatSharply, - [STRINGID_STATROSE - 12] = gText_StatRose, - [STRINGID_STATHARSHLY - 12] = sText_StatHarshly, - [STRINGID_STATFELL - 12] = sText_StatFell, - [STRINGID_ATTACKERSSTATROSE - 12] = sText_AttackersStatRose, - [STRINGID_DEFENDERSSTATROSE - 12] = gText_DefendersStatRose, - [STRINGID_ATTACKERSSTATFELL - 12] = sText_AttackersStatFell, - [STRINGID_DEFENDERSSTATFELL - 12] = sText_DefendersStatFell, - [STRINGID_CRITICALHIT - 12] = sText_CriticalHit, - [STRINGID_ONEHITKO - 12] = sText_OneHitKO, - [STRINGID_123POOF - 12] = sText_123Poof, - [STRINGID_ANDELLIPSIS - 12] = sText_AndEllipsis, - [STRINGID_NOTVERYEFFECTIVE - 12] = sText_NotVeryEffective, - [STRINGID_SUPEREFFECTIVE - 12] = sText_SuperEffective, - [STRINGID_GOTAWAYSAFELY - 12] = sText_GotAwaySafely, - [STRINGID_WILDPKMNFLED - 12] = sText_WildPkmnFled, - [STRINGID_NORUNNINGFROMTRAINERS - 12] = sText_NoRunningFromTrainers, - [STRINGID_CANTESCAPE - 12] = sText_CantEscape, - [STRINGID_DONTLEAVEBIRCH - 12] = sText_DontLeaveBirch, - [STRINGID_BUTNOTHINGHAPPENED - 12] = sText_ButNothingHappened, - [STRINGID_BUTITFAILED - 12] = sText_ButItFailed, - [STRINGID_ITHURTCONFUSION - 12] = sText_ItHurtConfusion, - [STRINGID_MIRRORMOVEFAILED - 12] = sText_MirrorMoveFailed, - [STRINGID_STARTEDTORAIN - 12] = sText_StartedToRain, - [STRINGID_DOWNPOURSTARTED - 12] = sText_DownpourStarted, - [STRINGID_RAINCONTINUES - 12] = sText_RainContinues, - [STRINGID_DOWNPOURCONTINUES - 12] = sText_DownpourContinues, - [STRINGID_RAINSTOPPED - 12] = sText_RainStopped, - [STRINGID_SANDSTORMBREWED - 12] = sText_SandstormBrewed, - [STRINGID_SANDSTORMRAGES - 12] = sText_SandstormRages, - [STRINGID_SANDSTORMSUBSIDED - 12] = sText_SandstormSubsided, - [STRINGID_SUNLIGHTGOTBRIGHT - 12] = sText_SunlightGotBright, - [STRINGID_SUNLIGHTSTRONG - 12] = sText_SunlightStrong, - [STRINGID_SUNLIGHTFADED - 12] = sText_SunlightFaded, - [STRINGID_STARTEDHAIL - 12] = sText_StartedHail, - [STRINGID_HAILCONTINUES - 12] = sText_HailContinues, - [STRINGID_HAILSTOPPED - 12] = sText_HailStopped, - [STRINGID_FAILEDTOSPITUP - 12] = sText_FailedToSpitUp, - [STRINGID_FAILEDTOSWALLOW - 12] = sText_FailedToSwallow, - [STRINGID_WINDBECAMEHEATWAVE - 12] = sText_WindBecameHeatWave, - [STRINGID_STATCHANGESGONE - 12] = sText_StatChangesGone, - [STRINGID_COINSSCATTERED - 12] = sText_CoinsScattered, - [STRINGID_TOOWEAKFORSUBSTITUTE - 12] = sText_TooWeakForSubstitute, - [STRINGID_SHAREDPAIN - 12] = sText_SharedPain, - [STRINGID_BELLCHIMED - 12] = sText_BellChimed, - [STRINGID_FAINTINTHREE - 12] = sText_FaintInThree, - [STRINGID_NOPPLEFT - 12] = sText_NoPPLeft, - [STRINGID_BUTNOPPLEFT - 12] = sText_ButNoPPLeft, - [STRINGID_PLAYERUSEDITEM - 12] = sText_PlayerUsedItem, - [STRINGID_WALLYUSEDITEM - 12] = sText_WallyUsedItem, - [STRINGID_TRAINERBLOCKEDBALL - 12] = sText_TrainerBlockedBall, - [STRINGID_DONTBEATHIEF - 12] = sText_DontBeAThief, - [STRINGID_ITDODGEDBALL - 12] = sText_ItDodgedBall, - [STRINGID_YOUMISSEDPKMN - 12] = sText_YouMissedPkmn, - [STRINGID_PKMNBROKEFREE - 12] = sText_PkmnBrokeFree, - [STRINGID_ITAPPEAREDCAUGHT - 12] = sText_ItAppearedCaught, - [STRINGID_AARGHALMOSTHADIT - 12] = sText_AarghAlmostHadIt, - [STRINGID_SHOOTSOCLOSE - 12] = sText_ShootSoClose, - [STRINGID_GOTCHAPKMNCAUGHT - 12] = sText_GotchaPkmnCaught, - [STRINGID_GOTCHAPKMNCAUGHT2 - 12] = sText_GotchaPkmnCaught2, - [STRINGID_GIVENICKNAMECAPTURED - 12] = sText_GiveNicknameCaptured, - [STRINGID_PKMNSENTTOPC - 12] = sText_PkmnSentToPC, - [STRINGID_PKMNDATAADDEDTODEX - 12] = sText_PkmnDataAddedToDex, - [STRINGID_ITISRAINING - 12] = sText_ItIsRaining, - [STRINGID_SANDSTORMISRAGING - 12] = sText_SandstormIsRaging, - [STRINGID_CANTESCAPE2 - 12] = sText_CantEscape2, - [STRINGID_PKMNIGNORESASLEEP - 12] = sText_PkmnIgnoresAsleep, - [STRINGID_PKMNIGNOREDORDERS - 12] = sText_PkmnIgnoredOrders, - [STRINGID_PKMNBEGANTONAP - 12] = sText_PkmnBeganToNap, - [STRINGID_PKMNLOAFING - 12] = sText_PkmnLoafing, - [STRINGID_PKMNWONTOBEY - 12] = sText_PkmnWontObey, - [STRINGID_PKMNTURNEDAWAY - 12] = sText_PkmnTurnedAway, - [STRINGID_PKMNPRETENDNOTNOTICE - 12] = sText_PkmnPretendNotNotice, - [STRINGID_ENEMYABOUTTOSWITCHPKMN - 12] = sText_EnemyAboutToSwitchPkmn, - [STRINGID_CREPTCLOSER - 12] = sText_CreptCloser, - [STRINGID_CANTGETCLOSER - 12] = sText_CantGetCloser, - [STRINGID_PKMNWATCHINGCAREFULLY - 12] = sText_PkmnWatchingCarefully, - [STRINGID_PKMNCURIOUSABOUTX - 12] = sText_PkmnCuriousAboutX, - [STRINGID_PKMNENTHRALLEDBYX - 12] = sText_PkmnEnthralledByX, - [STRINGID_PKMNIGNOREDX - 12] = sText_PkmnIgnoredX, - [STRINGID_THREWPOKEBLOCKATPKMN - 12] = sText_ThrewPokeblockAtPkmn, - [STRINGID_OUTOFSAFARIBALLS - 12] = sText_OutOfSafariBalls, - [STRINGID_PKMNSITEMCUREDPARALYSIS - 12] = sText_PkmnsItemCuredParalysis, - [STRINGID_PKMNSITEMCUREDPOISON - 12] = sText_PkmnsItemCuredPoison, - [STRINGID_PKMNSITEMHEALEDBURN - 12] = sText_PkmnsItemHealedBurn, - [STRINGID_PKMNSITEMDEFROSTEDIT - 12] = sText_PkmnsItemDefrostedIt, - [STRINGID_PKMNSITEMWOKEIT - 12] = sText_PkmnsItemWokeIt, - [STRINGID_PKMNSITEMSNAPPEDOUT - 12] = sText_PkmnsItemSnappedOut, - [STRINGID_PKMNSITEMCUREDPROBLEM - 12] = sText_PkmnsItemCuredProblem, - [STRINGID_PKMNSITEMRESTOREDHEALTH - 12] = sText_PkmnsItemRestoredHealth, - [STRINGID_PKMNSITEMRESTOREDPP - 12] = sText_PkmnsItemRestoredPP, - [STRINGID_PKMNSITEMRESTOREDSTATUS - 12] = sText_PkmnsItemRestoredStatus, - [STRINGID_PKMNSITEMRESTOREDHPALITTLE - 12] = sText_PkmnsItemRestoredHPALittle, - [STRINGID_ITEMALLOWSONLYYMOVE - 12] = sText_ItemAllowsOnlyYMove, - [STRINGID_PKMNHUNGONWITHX - 12] = sText_PkmnHungOnWithX, - [STRINGID_EMPTYSTRING3 - 12] = gText_EmptyString3, - [STRINGID_PKMNSXPREVENTSBURNS - 12] = sText_PkmnsXPreventsBurns, - [STRINGID_PKMNSXBLOCKSY - 12] = sText_PkmnsXBlocksY, - [STRINGID_PKMNSXRESTOREDHPALITTLE2 - 12] = sText_PkmnsXRestoredHPALittle2, - [STRINGID_PKMNSXWHIPPEDUPSANDSTORM - 12] = sText_PkmnsXWhippedUpSandstorm, - [STRINGID_PKMNSXPREVENTSYLOSS - 12] = sText_PkmnsXPreventsYLoss, - [STRINGID_PKMNSXINFATUATEDY - 12] = sText_PkmnsXInfatuatedY, - [STRINGID_PKMNSXMADEYINEFFECTIVE - 12] = sText_PkmnsXMadeYIneffective, - [STRINGID_PKMNSXCUREDYPROBLEM - 12] = sText_PkmnsXCuredYProblem, - [STRINGID_ITSUCKEDLIQUIDOOZE - 12] = sText_ItSuckedLiquidOoze, - [STRINGID_PKMNTRANSFORMED - 12] = sText_PkmnTransformed, - [STRINGID_ELECTRICITYWEAKENED - 12] = sText_ElectricityWeakened, - [STRINGID_FIREWEAKENED - 12] = sText_FireWeakened, - [STRINGID_PKMNHIDUNDERWATER - 12] = sText_PkmnHidUnderwater, - [STRINGID_PKMNSPRANGUP - 12] = sText_PkmnSprangUp, - [STRINGID_HMMOVESCANTBEFORGOTTEN - 12] = sText_HMMovesCantBeForgotten, - [STRINGID_XFOUNDONEY - 12] = sText_XFoundOneY, - [STRINGID_PLAYERDEFEATEDTRAINER1 - 12] = sText_PlayerDefeatedLinkTrainerTrainer1, - [STRINGID_SOOTHINGAROMA - 12] = sText_SoothingAroma, - [STRINGID_ITEMSCANTBEUSEDNOW - 12] = sText_ItemsCantBeUsedNow, - [STRINGID_FORXCOMMAYZ - 12] = sText_ForXCommaYZ, - [STRINGID_USINGITEMSTATOFPKMNROSE - 12] = sText_UsingItemTheStatOfPkmnRose, - [STRINGID_PKMNUSEDXTOGETPUMPED - 12] = sText_PkmnUsedXToGetPumped, - [STRINGID_PKMNSXMADEYUSELESS - 12] = sText_PkmnsXMadeYUseless, - [STRINGID_PKMNTRAPPEDBYSANDTOMB - 12] = sText_PkmnTrappedBySandTomb, - [STRINGID_EMPTYSTRING4 - 12] = sText_EmptyString4, - [STRINGID_ABOOSTED - 12] = sText_ABoosted, - [STRINGID_PKMNSXINTENSIFIEDSUN - 12] = sText_PkmnsXIntensifiedSun, - [STRINGID_PKMNMAKESGROUNDMISS - 12] = sText_PkmnMakesGroundMiss, - [STRINGID_YOUTHROWABALLNOWRIGHT - 12] = sText_YouThrowABallNowRight, - [STRINGID_PKMNSXTOOKATTACK - 12] = sText_PkmnsXTookAttack, - [STRINGID_PKMNCHOSEXASDESTINY - 12] = sText_PkmnChoseXAsDestiny, - [STRINGID_PKMNLOSTFOCUS - 12] = sText_PkmnLostFocus, - [STRINGID_USENEXTPKMN - 12] = sText_UseNextPkmn, - [STRINGID_PKMNFLEDUSINGITS - 12] = sText_PkmnFledUsingIts, - [STRINGID_PKMNFLEDUSING - 12] = sText_PkmnFledUsing, - [STRINGID_PKMNWASDRAGGEDOUT - 12] = sText_PkmnWasDraggedOut, - [STRINGID_PREVENTEDFROMWORKING - 12] = sText_PreventedFromWorking, - [STRINGID_PKMNSITEMNORMALIZEDSTATUS - 12] = sText_PkmnsItemNormalizedStatus, - [STRINGID_TRAINER1USEDITEM - 12] = sText_Trainer1UsedItem, - [STRINGID_BOXISFULL - 12] = sText_BoxIsFull, - [STRINGID_PKMNAVOIDEDATTACK - 12] = sText_PkmnAvoidedAttack, - [STRINGID_PKMNSXMADEITINEFFECTIVE - 12] = sText_PkmnsXMadeItIneffective, - [STRINGID_PKMNSXPREVENTSFLINCHING - 12] = sText_PkmnsXPreventsFlinching, - [STRINGID_PKMNALREADYHASBURN - 12] = sText_PkmnAlreadyHasBurn, - [STRINGID_STATSWONTDECREASE2 - 12] = sText_StatsWontDecrease2, - [STRINGID_PKMNSXBLOCKSY2 - 12] = sText_PkmnsXBlocksY2, - [STRINGID_PKMNSXWOREOFF - 12] = sText_PkmnsXWoreOff, - [STRINGID_PKMNRAISEDDEFALITTLE - 12] = sText_PkmnRaisedDefALittle, - [STRINGID_PKMNRAISEDSPDEFALITTLE - 12] = sText_PkmnRaisedSpDefALittle, - [STRINGID_THEWALLSHATTERED - 12] = sText_TheWallShattered, - [STRINGID_PKMNSXPREVENTSYSZ - 12] = sText_PkmnsXPreventsYsZ, - [STRINGID_PKMNSXCUREDITSYPROBLEM - 12] = sText_PkmnsXCuredItsYProblem, - [STRINGID_ATTACKERCANTESCAPE - 12] = sText_AttackerCantEscape, - [STRINGID_PKMNOBTAINEDX - 12] = sText_PkmnObtainedX, - [STRINGID_PKMNOBTAINEDX2 - 12] = sText_PkmnObtainedX2, - [STRINGID_PKMNOBTAINEDXYOBTAINEDZ - 12] = sText_PkmnObtainedXYObtainedZ, - [STRINGID_BUTNOEFFECT - 12] = sText_ButNoEffect, - [STRINGID_PKMNSXHADNOEFFECTONY - 12] = sText_PkmnsXHadNoEffectOnY, - [STRINGID_TWOENEMIESDEFEATED - 12] = sText_TwoInGameTrainersDefeated, - [STRINGID_TRAINER2LOSETEXT - 12] = sText_Trainer2LoseText, - [STRINGID_PKMNINCAPABLEOFPOWER - 12] = sText_PkmnIncapableOfPower, - [STRINGID_GLINTAPPEARSINEYE - 12] = sText_GlintAppearsInEye, - [STRINGID_PKMNGETTINGINTOPOSITION - 12] = sText_PkmnGettingIntoPosition, - [STRINGID_PKMNBEGANGROWLINGDEEPLY - 12] = sText_PkmnBeganGrowlingDeeply, - [STRINGID_PKMNEAGERFORMORE - 12] = sText_PkmnEagerForMore, - [STRINGID_DEFEATEDOPPONENTBYREFEREE - 12] = sText_DefeatedOpponentByReferee, - [STRINGID_LOSTTOOPPONENTBYREFEREE - 12] = sText_LostToOpponentByReferee, - [STRINGID_TIEDOPPONENTBYREFEREE - 12] = sText_TiedOpponentByReferee, - [STRINGID_QUESTIONFORFEITMATCH - 12] = sText_QuestionForfeitMatch, - [STRINGID_FORFEITEDMATCH - 12] = sText_ForfeitedMatch, - [STRINGID_PKMNTRANSFERREDSOMEONESPC - 12] = gText_PkmnTransferredSomeonesPC, - [STRINGID_PKMNTRANSFERREDLANETTESPC - 12] = gText_PkmnTransferredLanettesPC, - [STRINGID_PKMNBOXSOMEONESPCFULL - 12] = gText_PkmnTransferredSomeonesPCBoxFull, - [STRINGID_PKMNBOXLANETTESPCFULL - 12] = gText_PkmnTransferredLanettesPCBoxFull, - [STRINGID_TRAINER1WINTEXT - 12] = sText_Trainer1WinText, - [STRINGID_TRAINER2WINTEXT - 12] = sText_Trainer2WinText, + [STRINGID_TRAINER1LOSETEXT - BATTLESTRINGS_TABLE_START] = sText_Trainer1LoseText, + [STRINGID_PKMNGAINEDEXP - BATTLESTRINGS_TABLE_START] = sText_PkmnGainedEXP, + [STRINGID_PKMNGREWTOLV - BATTLESTRINGS_TABLE_START] = sText_PkmnGrewToLv, + [STRINGID_PKMNLEARNEDMOVE - BATTLESTRINGS_TABLE_START] = sText_PkmnLearnedMove, + [STRINGID_TRYTOLEARNMOVE1 - BATTLESTRINGS_TABLE_START] = sText_TryToLearnMove1, + [STRINGID_TRYTOLEARNMOVE2 - BATTLESTRINGS_TABLE_START] = sText_TryToLearnMove2, + [STRINGID_TRYTOLEARNMOVE3 - BATTLESTRINGS_TABLE_START] = sText_TryToLearnMove3, + [STRINGID_PKMNFORGOTMOVE - BATTLESTRINGS_TABLE_START] = sText_PkmnForgotMove, + [STRINGID_STOPLEARNINGMOVE - BATTLESTRINGS_TABLE_START] = sText_StopLearningMove, + [STRINGID_DIDNOTLEARNMOVE - BATTLESTRINGS_TABLE_START] = sText_DidNotLearnMove, + [STRINGID_PKMNLEARNEDMOVE2 - BATTLESTRINGS_TABLE_START] = sText_PkmnLearnedMove2, + [STRINGID_ATTACKMISSED - BATTLESTRINGS_TABLE_START] = sText_AttackMissed, + [STRINGID_PKMNPROTECTEDITSELF - BATTLESTRINGS_TABLE_START] = sText_PkmnProtectedItself, + [STRINGID_STATSWONTINCREASE2 - BATTLESTRINGS_TABLE_START] = sText_StatsWontIncrease2, + [STRINGID_AVOIDEDDAMAGE - BATTLESTRINGS_TABLE_START] = sText_AvoidedDamage, + [STRINGID_ITDOESNTAFFECT - BATTLESTRINGS_TABLE_START] = sText_ItDoesntAffect, + [STRINGID_ATTACKERFAINTED - BATTLESTRINGS_TABLE_START] = sText_AttackerFainted, + [STRINGID_TARGETFAINTED - BATTLESTRINGS_TABLE_START] = sText_TargetFainted, + [STRINGID_PLAYERGOTMONEY - BATTLESTRINGS_TABLE_START] = sText_PlayerGotMoney, + [STRINGID_PLAYERWHITEOUT - BATTLESTRINGS_TABLE_START] = sText_PlayerWhiteout, + [STRINGID_PLAYERWHITEOUT2 - BATTLESTRINGS_TABLE_START] = sText_PlayerWhiteout2, + [STRINGID_PREVENTSESCAPE - BATTLESTRINGS_TABLE_START] = sText_PreventsEscape, + [STRINGID_HITXTIMES - BATTLESTRINGS_TABLE_START] = sText_HitXTimes, + [STRINGID_PKMNFELLASLEEP - BATTLESTRINGS_TABLE_START] = sText_PkmnFellAsleep, + [STRINGID_PKMNMADESLEEP - BATTLESTRINGS_TABLE_START] = sText_PkmnMadeSleep, + [STRINGID_PKMNALREADYASLEEP - BATTLESTRINGS_TABLE_START] = sText_PkmnAlreadyAsleep, + [STRINGID_PKMNALREADYASLEEP2 - BATTLESTRINGS_TABLE_START] = sText_PkmnAlreadyAsleep2, + [STRINGID_PKMNWASNTAFFECTED - BATTLESTRINGS_TABLE_START] = sText_PkmnWasntAffected, + [STRINGID_PKMNWASPOISONED - BATTLESTRINGS_TABLE_START] = sText_PkmnWasPoisoned, + [STRINGID_PKMNPOISONEDBY - BATTLESTRINGS_TABLE_START] = sText_PkmnPoisonedBy, + [STRINGID_PKMNHURTBYPOISON - BATTLESTRINGS_TABLE_START] = sText_PkmnHurtByPoison, + [STRINGID_PKMNALREADYPOISONED - BATTLESTRINGS_TABLE_START] = sText_PkmnAlreadyPoisoned, + [STRINGID_PKMNBADLYPOISONED - BATTLESTRINGS_TABLE_START] = sText_PkmnBadlyPoisoned, + [STRINGID_PKMNENERGYDRAINED - BATTLESTRINGS_TABLE_START] = sText_PkmnEnergyDrained, + [STRINGID_PKMNWASBURNED - BATTLESTRINGS_TABLE_START] = sText_PkmnWasBurned, + [STRINGID_PKMNBURNEDBY - BATTLESTRINGS_TABLE_START] = sText_PkmnBurnedBy, + [STRINGID_PKMNHURTBYBURN - BATTLESTRINGS_TABLE_START] = sText_PkmnHurtByBurn, + [STRINGID_PKMNWASFROZEN - BATTLESTRINGS_TABLE_START] = sText_PkmnWasFrozen, + [STRINGID_PKMNFROZENBY - BATTLESTRINGS_TABLE_START] = sText_PkmnFrozenBy, + [STRINGID_PKMNISFROZEN - BATTLESTRINGS_TABLE_START] = sText_PkmnIsFrozen, + [STRINGID_PKMNWASDEFROSTED - BATTLESTRINGS_TABLE_START] = sText_PkmnWasDefrosted, + [STRINGID_PKMNWASDEFROSTED2 - BATTLESTRINGS_TABLE_START] = sText_PkmnWasDefrosted2, + [STRINGID_PKMNWASDEFROSTEDBY - BATTLESTRINGS_TABLE_START] = sText_PkmnWasDefrostedBy, + [STRINGID_PKMNWASPARALYZED - BATTLESTRINGS_TABLE_START] = sText_PkmnWasParalyzed, + [STRINGID_PKMNWASPARALYZEDBY - BATTLESTRINGS_TABLE_START] = sText_PkmnWasParalyzedBy, + [STRINGID_PKMNISPARALYZED - BATTLESTRINGS_TABLE_START] = sText_PkmnIsParalyzed, + [STRINGID_PKMNISALREADYPARALYZED - BATTLESTRINGS_TABLE_START] = sText_PkmnIsAlreadyParalyzed, + [STRINGID_PKMNHEALEDPARALYSIS - BATTLESTRINGS_TABLE_START] = sText_PkmnHealedParalysis, + [STRINGID_PKMNDREAMEATEN - BATTLESTRINGS_TABLE_START] = sText_PkmnDreamEaten, + [STRINGID_STATSWONTINCREASE - BATTLESTRINGS_TABLE_START] = sText_StatsWontIncrease, + [STRINGID_STATSWONTDECREASE - BATTLESTRINGS_TABLE_START] = sText_StatsWontDecrease, + [STRINGID_TEAMSTOPPEDWORKING - BATTLESTRINGS_TABLE_START] = sText_TeamStoppedWorking, + [STRINGID_FOESTOPPEDWORKING - BATTLESTRINGS_TABLE_START] = sText_FoeStoppedWorking, + [STRINGID_PKMNISCONFUSED - BATTLESTRINGS_TABLE_START] = sText_PkmnIsConfused, + [STRINGID_PKMNHEALEDCONFUSION - BATTLESTRINGS_TABLE_START] = sText_PkmnHealedConfusion, + [STRINGID_PKMNWASCONFUSED - BATTLESTRINGS_TABLE_START] = sText_PkmnWasConfused, + [STRINGID_PKMNALREADYCONFUSED - BATTLESTRINGS_TABLE_START] = sText_PkmnAlreadyConfused, + [STRINGID_PKMNFELLINLOVE - BATTLESTRINGS_TABLE_START] = sText_PkmnFellInLove, + [STRINGID_PKMNINLOVE - BATTLESTRINGS_TABLE_START] = sText_PkmnInLove, + [STRINGID_PKMNIMMOBILIZEDBYLOVE - BATTLESTRINGS_TABLE_START] = sText_PkmnImmobilizedByLove, + [STRINGID_PKMNBLOWNAWAY - BATTLESTRINGS_TABLE_START] = sText_PkmnBlownAway, + [STRINGID_PKMNCHANGEDTYPE - BATTLESTRINGS_TABLE_START] = sText_PkmnChangedType, + [STRINGID_PKMNFLINCHED - BATTLESTRINGS_TABLE_START] = sText_PkmnFlinched, + [STRINGID_PKMNREGAINEDHEALTH - BATTLESTRINGS_TABLE_START] = sText_PkmnRegainedHealth, + [STRINGID_PKMNHPFULL - BATTLESTRINGS_TABLE_START] = sText_PkmnHPFull, + [STRINGID_PKMNRAISEDSPDEF - BATTLESTRINGS_TABLE_START] = sText_PkmnRaisedSpDef, + [STRINGID_PKMNRAISEDDEF - BATTLESTRINGS_TABLE_START] = sText_PkmnRaisedDef, + [STRINGID_PKMNCOVEREDBYVEIL - BATTLESTRINGS_TABLE_START] = sText_PkmnCoveredByVeil, + [STRINGID_PKMNUSEDSAFEGUARD - BATTLESTRINGS_TABLE_START] = sText_PkmnUsedSafeguard, + [STRINGID_PKMNSAFEGUARDEXPIRED - BATTLESTRINGS_TABLE_START] = sText_PkmnSafeguardExpired, + [STRINGID_PKMNWENTTOSLEEP - BATTLESTRINGS_TABLE_START] = sText_PkmnWentToSleep, + [STRINGID_PKMNSLEPTHEALTHY - BATTLESTRINGS_TABLE_START] = sText_PkmnSleptHealthy, + [STRINGID_PKMNWHIPPEDWHIRLWIND - BATTLESTRINGS_TABLE_START] = sText_PkmnWhippedWhirlwind, + [STRINGID_PKMNTOOKSUNLIGHT - BATTLESTRINGS_TABLE_START] = sText_PkmnTookSunlight, + [STRINGID_PKMNLOWEREDHEAD - BATTLESTRINGS_TABLE_START] = sText_PkmnLoweredHead, + [STRINGID_PKMNISGLOWING - BATTLESTRINGS_TABLE_START] = sText_PkmnIsGlowing, + [STRINGID_PKMNFLEWHIGH - BATTLESTRINGS_TABLE_START] = sText_PkmnFlewHigh, + [STRINGID_PKMNDUGHOLE - BATTLESTRINGS_TABLE_START] = sText_PkmnDugHole, + [STRINGID_PKMNSQUEEZEDBYBIND - BATTLESTRINGS_TABLE_START] = sText_PkmnSqueezedByBind, + [STRINGID_PKMNTRAPPEDINVORTEX - BATTLESTRINGS_TABLE_START] = sText_PkmnTrappedInVortex, + [STRINGID_PKMNWRAPPEDBY - BATTLESTRINGS_TABLE_START] = sText_PkmnWrappedBy, + [STRINGID_PKMNCLAMPED - BATTLESTRINGS_TABLE_START] = sText_PkmnClamped, + [STRINGID_PKMNHURTBY - BATTLESTRINGS_TABLE_START] = sText_PkmnHurtBy, + [STRINGID_PKMNFREEDFROM - BATTLESTRINGS_TABLE_START] = sText_PkmnFreedFrom, + [STRINGID_PKMNCRASHED - BATTLESTRINGS_TABLE_START] = sText_PkmnCrashed, + [STRINGID_PKMNSHROUDEDINMIST - BATTLESTRINGS_TABLE_START] = gText_PkmnShroudedInMist, + [STRINGID_PKMNPROTECTEDBYMIST - BATTLESTRINGS_TABLE_START] = sText_PkmnProtectedByMist, + [STRINGID_PKMNGETTINGPUMPED - BATTLESTRINGS_TABLE_START] = gText_PkmnGettingPumped, + [STRINGID_PKMNHITWITHRECOIL - BATTLESTRINGS_TABLE_START] = sText_PkmnHitWithRecoil, + [STRINGID_PKMNPROTECTEDITSELF2 - BATTLESTRINGS_TABLE_START] = sText_PkmnProtectedItself2, + [STRINGID_PKMNBUFFETEDBYSANDSTORM - BATTLESTRINGS_TABLE_START] = sText_PkmnBuffetedBySandstorm, + [STRINGID_PKMNPELTEDBYHAIL - BATTLESTRINGS_TABLE_START] = sText_PkmnPeltedByHail, + [STRINGID_PKMNSEEDED - BATTLESTRINGS_TABLE_START] = sText_PkmnSeeded, + [STRINGID_PKMNEVADEDATTACK - BATTLESTRINGS_TABLE_START] = sText_PkmnEvadedAttack, + [STRINGID_PKMNSAPPEDBYLEECHSEED - BATTLESTRINGS_TABLE_START] = sText_PkmnSappedByLeechSeed, + [STRINGID_PKMNFASTASLEEP - BATTLESTRINGS_TABLE_START] = sText_PkmnFastAsleep, + [STRINGID_PKMNWOKEUP - BATTLESTRINGS_TABLE_START] = sText_PkmnWokeUp, + [STRINGID_PKMNUPROARKEPTAWAKE - BATTLESTRINGS_TABLE_START] = sText_PkmnUproarKeptAwake, + [STRINGID_PKMNWOKEUPINUPROAR - BATTLESTRINGS_TABLE_START] = sText_PkmnWokeUpInUproar, + [STRINGID_PKMNCAUSEDUPROAR - BATTLESTRINGS_TABLE_START] = sText_PkmnCausedUproar, + [STRINGID_PKMNMAKINGUPROAR - BATTLESTRINGS_TABLE_START] = sText_PkmnMakingUproar, + [STRINGID_PKMNCALMEDDOWN - BATTLESTRINGS_TABLE_START] = sText_PkmnCalmedDown, + [STRINGID_PKMNCANTSLEEPINUPROAR - BATTLESTRINGS_TABLE_START] = sText_PkmnCantSleepInUproar, + [STRINGID_PKMNSTOCKPILED - BATTLESTRINGS_TABLE_START] = sText_PkmnStockpiled, + [STRINGID_PKMNCANTSTOCKPILE - BATTLESTRINGS_TABLE_START] = sText_PkmnCantStockpile, + [STRINGID_PKMNCANTSLEEPINUPROAR2 - BATTLESTRINGS_TABLE_START] = sText_PkmnCantSleepInUproar2, + [STRINGID_UPROARKEPTPKMNAWAKE - BATTLESTRINGS_TABLE_START] = sText_UproarKeptPkmnAwake, + [STRINGID_PKMNSTAYEDAWAKEUSING - BATTLESTRINGS_TABLE_START] = sText_PkmnStayedAwakeUsing, + [STRINGID_PKMNSTORINGENERGY - BATTLESTRINGS_TABLE_START] = sText_PkmnStoringEnergy, + [STRINGID_PKMNUNLEASHEDENERGY - BATTLESTRINGS_TABLE_START] = sText_PkmnUnleashedEnergy, + [STRINGID_PKMNFATIGUECONFUSION - BATTLESTRINGS_TABLE_START] = sText_PkmnFatigueConfusion, + [STRINGID_PLAYERPICKEDUPMONEY - BATTLESTRINGS_TABLE_START] = sText_PlayerPickedUpMoney, + [STRINGID_PKMNUNAFFECTED - BATTLESTRINGS_TABLE_START] = sText_PkmnUnaffected, + [STRINGID_PKMNTRANSFORMEDINTO - BATTLESTRINGS_TABLE_START] = sText_PkmnTransformedInto, + [STRINGID_PKMNMADESUBSTITUTE - BATTLESTRINGS_TABLE_START] = sText_PkmnMadeSubstitute, + [STRINGID_PKMNHASSUBSTITUTE - BATTLESTRINGS_TABLE_START] = sText_PkmnHasSubstitute, + [STRINGID_SUBSTITUTEDAMAGED - BATTLESTRINGS_TABLE_START] = sText_SubstituteDamaged, + [STRINGID_PKMNSUBSTITUTEFADED - BATTLESTRINGS_TABLE_START] = sText_PkmnSubstituteFaded, + [STRINGID_PKMNMUSTRECHARGE - BATTLESTRINGS_TABLE_START] = sText_PkmnMustRecharge, + [STRINGID_PKMNRAGEBUILDING - BATTLESTRINGS_TABLE_START] = sText_PkmnRageBuilding, + [STRINGID_PKMNMOVEWASDISABLED - BATTLESTRINGS_TABLE_START] = sText_PkmnMoveWasDisabled, + [STRINGID_PKMNMOVEISDISABLED - BATTLESTRINGS_TABLE_START] = sText_PkmnMoveIsDisabled, + [STRINGID_PKMNMOVEDISABLEDNOMORE - BATTLESTRINGS_TABLE_START] = sText_PkmnMoveDisabledNoMore, + [STRINGID_PKMNGOTENCORE - BATTLESTRINGS_TABLE_START] = sText_PkmnGotEncore, + [STRINGID_PKMNENCOREENDED - BATTLESTRINGS_TABLE_START] = sText_PkmnEncoreEnded, + [STRINGID_PKMNTOOKAIM - BATTLESTRINGS_TABLE_START] = sText_PkmnTookAim, + [STRINGID_PKMNSKETCHEDMOVE - BATTLESTRINGS_TABLE_START] = sText_PkmnSketchedMove, + [STRINGID_PKMNTRYINGTOTAKEFOE - BATTLESTRINGS_TABLE_START] = sText_PkmnTryingToTakeFoe, + [STRINGID_PKMNTOOKFOE - BATTLESTRINGS_TABLE_START] = sText_PkmnTookFoe, + [STRINGID_PKMNREDUCEDPP - BATTLESTRINGS_TABLE_START] = sText_PkmnReducedPP, + [STRINGID_PKMNSTOLEITEM - BATTLESTRINGS_TABLE_START] = sText_PkmnStoleItem, + [STRINGID_TARGETCANTESCAPENOW - BATTLESTRINGS_TABLE_START] = sText_TargetCantEscapeNow, + [STRINGID_PKMNFELLINTONIGHTMARE - BATTLESTRINGS_TABLE_START] = sText_PkmnFellIntoNightmare, + [STRINGID_PKMNLOCKEDINNIGHTMARE - BATTLESTRINGS_TABLE_START] = sText_PkmnLockedInNightmare, + [STRINGID_PKMNLAIDCURSE - BATTLESTRINGS_TABLE_START] = sText_PkmnLaidCurse, + [STRINGID_PKMNAFFLICTEDBYCURSE - BATTLESTRINGS_TABLE_START] = sText_PkmnAfflictedByCurse, + [STRINGID_SPIKESSCATTERED - BATTLESTRINGS_TABLE_START] = sText_SpikesScattered, + [STRINGID_PKMNHURTBYSPIKES - BATTLESTRINGS_TABLE_START] = sText_PkmnHurtBySpikes, + [STRINGID_PKMNIDENTIFIED - BATTLESTRINGS_TABLE_START] = sText_PkmnIdentified, + [STRINGID_PKMNPERISHCOUNTFELL - BATTLESTRINGS_TABLE_START] = sText_PkmnPerishCountFell, + [STRINGID_PKMNBRACEDITSELF - BATTLESTRINGS_TABLE_START] = sText_PkmnBracedItself, + [STRINGID_PKMNENDUREDHIT - BATTLESTRINGS_TABLE_START] = sText_PkmnEnduredHit, + [STRINGID_MAGNITUDESTRENGTH - BATTLESTRINGS_TABLE_START] = sText_MagnitudeStrength, + [STRINGID_PKMNCUTHPMAXEDATTACK - BATTLESTRINGS_TABLE_START] = sText_PkmnCutHPMaxedAttack, + [STRINGID_PKMNCOPIEDSTATCHANGES - BATTLESTRINGS_TABLE_START] = sText_PkmnCopiedStatChanges, + [STRINGID_PKMNGOTFREE - BATTLESTRINGS_TABLE_START] = sText_PkmnGotFree, + [STRINGID_PKMNSHEDLEECHSEED - BATTLESTRINGS_TABLE_START] = sText_PkmnShedLeechSeed, + [STRINGID_PKMNBLEWAWAYSPIKES - BATTLESTRINGS_TABLE_START] = sText_PkmnBlewAwaySpikes, + [STRINGID_PKMNFLEDFROMBATTLE - BATTLESTRINGS_TABLE_START] = sText_PkmnFledFromBattle, + [STRINGID_PKMNFORESAWATTACK - BATTLESTRINGS_TABLE_START] = sText_PkmnForesawAttack, + [STRINGID_PKMNTOOKATTACK - BATTLESTRINGS_TABLE_START] = sText_PkmnTookAttack, + [STRINGID_PKMNATTACK - BATTLESTRINGS_TABLE_START] = sText_PkmnAttack, + [STRINGID_PKMNCENTERATTENTION - BATTLESTRINGS_TABLE_START] = sText_PkmnCenterAttention, + [STRINGID_PKMNCHARGINGPOWER - BATTLESTRINGS_TABLE_START] = sText_PkmnChargingPower, + [STRINGID_NATUREPOWERTURNEDINTO - BATTLESTRINGS_TABLE_START] = sText_NaturePowerTurnedInto, + [STRINGID_PKMNSTATUSNORMAL - BATTLESTRINGS_TABLE_START] = sText_PkmnStatusNormal, + [STRINGID_PKMNHASNOMOVESLEFT - BATTLESTRINGS_TABLE_START] = sText_PkmnHasNoMovesLeft, + [STRINGID_PKMNSUBJECTEDTOTORMENT - BATTLESTRINGS_TABLE_START] = sText_PkmnSubjectedToTorment, + [STRINGID_PKMNCANTUSEMOVETORMENT - BATTLESTRINGS_TABLE_START] = sText_PkmnCantUseMoveTorment, + [STRINGID_PKMNTIGHTENINGFOCUS - BATTLESTRINGS_TABLE_START] = sText_PkmnTighteningFocus, + [STRINGID_PKMNFELLFORTAUNT - BATTLESTRINGS_TABLE_START] = sText_PkmnFellForTaunt, + [STRINGID_PKMNCANTUSEMOVETAUNT - BATTLESTRINGS_TABLE_START] = sText_PkmnCantUseMoveTaunt, + [STRINGID_PKMNREADYTOHELP - BATTLESTRINGS_TABLE_START] = sText_PkmnReadyToHelp, + [STRINGID_PKMNSWITCHEDITEMS - BATTLESTRINGS_TABLE_START] = sText_PkmnSwitchedItems, + [STRINGID_PKMNCOPIEDFOE - BATTLESTRINGS_TABLE_START] = sText_PkmnCopiedFoe, + [STRINGID_PKMNMADEWISH - BATTLESTRINGS_TABLE_START] = sText_PkmnMadeWish, + [STRINGID_PKMNWISHCAMETRUE - BATTLESTRINGS_TABLE_START] = sText_PkmnWishCameTrue, + [STRINGID_PKMNPLANTEDROOTS - BATTLESTRINGS_TABLE_START] = sText_PkmnPlantedRoots, + [STRINGID_PKMNABSORBEDNUTRIENTS - BATTLESTRINGS_TABLE_START] = sText_PkmnAbsorbedNutrients, + [STRINGID_PKMNANCHOREDITSELF - BATTLESTRINGS_TABLE_START] = sText_PkmnAnchoredItself, + [STRINGID_PKMNWASMADEDROWSY - BATTLESTRINGS_TABLE_START] = sText_PkmnWasMadeDrowsy, + [STRINGID_PKMNKNOCKEDOFF - BATTLESTRINGS_TABLE_START] = sText_PkmnKnockedOff, + [STRINGID_PKMNSWAPPEDABILITIES - BATTLESTRINGS_TABLE_START] = sText_PkmnSwappedAbilities, + [STRINGID_PKMNSEALEDOPPONENTMOVE - BATTLESTRINGS_TABLE_START] = sText_PkmnSealedOpponentMove, + [STRINGID_PKMNCANTUSEMOVESEALED - BATTLESTRINGS_TABLE_START] = sText_PkmnCantUseMoveSealed, + [STRINGID_PKMNWANTSGRUDGE - BATTLESTRINGS_TABLE_START] = sText_PkmnWantsGrudge, + [STRINGID_PKMNLOSTPPGRUDGE - BATTLESTRINGS_TABLE_START] = sText_PkmnLostPPGrudge, + [STRINGID_PKMNSHROUDEDITSELF - BATTLESTRINGS_TABLE_START] = sText_PkmnShroudedItself, + [STRINGID_PKMNMOVEBOUNCED - BATTLESTRINGS_TABLE_START] = sText_PkmnMoveBounced, + [STRINGID_PKMNWAITSFORTARGET - BATTLESTRINGS_TABLE_START] = sText_PkmnWaitsForTarget, + [STRINGID_PKMNSNATCHEDMOVE - BATTLESTRINGS_TABLE_START] = sText_PkmnSnatchedMove, + [STRINGID_PKMNMADEITRAIN - BATTLESTRINGS_TABLE_START] = sText_PkmnMadeItRain, + [STRINGID_PKMNRAISEDSPEED - BATTLESTRINGS_TABLE_START] = sText_PkmnRaisedSpeed, + [STRINGID_PKMNPROTECTEDBY - BATTLESTRINGS_TABLE_START] = sText_PkmnProtectedBy, + [STRINGID_PKMNPREVENTSUSAGE - BATTLESTRINGS_TABLE_START] = sText_PkmnPreventsUsage, + [STRINGID_PKMNRESTOREDHPUSING - BATTLESTRINGS_TABLE_START] = sText_PkmnRestoredHPUsing, + [STRINGID_PKMNCHANGEDTYPEWITH - BATTLESTRINGS_TABLE_START] = sText_PkmnChangedTypeWith, + [STRINGID_PKMNPREVENTSPARALYSISWITH - BATTLESTRINGS_TABLE_START] = sText_PkmnPreventsParalysisWith, + [STRINGID_PKMNPREVENTSROMANCEWITH - BATTLESTRINGS_TABLE_START] = sText_PkmnPreventsRomanceWith, + [STRINGID_PKMNPREVENTSPOISONINGWITH - BATTLESTRINGS_TABLE_START] = sText_PkmnPreventsPoisoningWith, + [STRINGID_PKMNPREVENTSCONFUSIONWITH - BATTLESTRINGS_TABLE_START] = sText_PkmnPreventsConfusionWith, + [STRINGID_PKMNRAISEDFIREPOWERWITH - BATTLESTRINGS_TABLE_START] = sText_PkmnRaisedFirePowerWith, + [STRINGID_PKMNANCHORSITSELFWITH - BATTLESTRINGS_TABLE_START] = sText_PkmnAnchorsItselfWith, + [STRINGID_PKMNCUTSATTACKWITH - BATTLESTRINGS_TABLE_START] = sText_PkmnCutsAttackWith, + [STRINGID_PKMNPREVENTSSTATLOSSWITH - BATTLESTRINGS_TABLE_START] = sText_PkmnPreventsStatLossWith, + [STRINGID_PKMNHURTSWITH - BATTLESTRINGS_TABLE_START] = sText_PkmnHurtsWith, + [STRINGID_PKMNTRACED - BATTLESTRINGS_TABLE_START] = sText_PkmnTraced, + [STRINGID_STATSHARPLY - BATTLESTRINGS_TABLE_START] = sText_StatSharply, + [STRINGID_STATROSE - BATTLESTRINGS_TABLE_START] = gText_StatRose, + [STRINGID_STATHARSHLY - BATTLESTRINGS_TABLE_START] = sText_StatHarshly, + [STRINGID_STATFELL - BATTLESTRINGS_TABLE_START] = sText_StatFell, + [STRINGID_ATTACKERSSTATROSE - BATTLESTRINGS_TABLE_START] = sText_AttackersStatRose, + [STRINGID_DEFENDERSSTATROSE - BATTLESTRINGS_TABLE_START] = gText_DefendersStatRose, + [STRINGID_ATTACKERSSTATFELL - BATTLESTRINGS_TABLE_START] = sText_AttackersStatFell, + [STRINGID_DEFENDERSSTATFELL - BATTLESTRINGS_TABLE_START] = sText_DefendersStatFell, + [STRINGID_CRITICALHIT - BATTLESTRINGS_TABLE_START] = sText_CriticalHit, + [STRINGID_ONEHITKO - BATTLESTRINGS_TABLE_START] = sText_OneHitKO, + [STRINGID_123POOF - BATTLESTRINGS_TABLE_START] = sText_123Poof, + [STRINGID_ANDELLIPSIS - BATTLESTRINGS_TABLE_START] = sText_AndEllipsis, + [STRINGID_NOTVERYEFFECTIVE - BATTLESTRINGS_TABLE_START] = sText_NotVeryEffective, + [STRINGID_SUPEREFFECTIVE - BATTLESTRINGS_TABLE_START] = sText_SuperEffective, + [STRINGID_GOTAWAYSAFELY - BATTLESTRINGS_TABLE_START] = sText_GotAwaySafely, + [STRINGID_WILDPKMNFLED - BATTLESTRINGS_TABLE_START] = sText_WildPkmnFled, + [STRINGID_NORUNNINGFROMTRAINERS - BATTLESTRINGS_TABLE_START] = sText_NoRunningFromTrainers, + [STRINGID_CANTESCAPE - BATTLESTRINGS_TABLE_START] = sText_CantEscape, + [STRINGID_DONTLEAVEBIRCH - BATTLESTRINGS_TABLE_START] = sText_DontLeaveBirch, + [STRINGID_BUTNOTHINGHAPPENED - BATTLESTRINGS_TABLE_START] = sText_ButNothingHappened, + [STRINGID_BUTITFAILED - BATTLESTRINGS_TABLE_START] = sText_ButItFailed, + [STRINGID_ITHURTCONFUSION - BATTLESTRINGS_TABLE_START] = sText_ItHurtConfusion, + [STRINGID_MIRRORMOVEFAILED - BATTLESTRINGS_TABLE_START] = sText_MirrorMoveFailed, + [STRINGID_STARTEDTORAIN - BATTLESTRINGS_TABLE_START] = sText_StartedToRain, + [STRINGID_DOWNPOURSTARTED - BATTLESTRINGS_TABLE_START] = sText_DownpourStarted, + [STRINGID_RAINCONTINUES - BATTLESTRINGS_TABLE_START] = sText_RainContinues, + [STRINGID_DOWNPOURCONTINUES - BATTLESTRINGS_TABLE_START] = sText_DownpourContinues, + [STRINGID_RAINSTOPPED - BATTLESTRINGS_TABLE_START] = sText_RainStopped, + [STRINGID_SANDSTORMBREWED - BATTLESTRINGS_TABLE_START] = sText_SandstormBrewed, + [STRINGID_SANDSTORMRAGES - BATTLESTRINGS_TABLE_START] = sText_SandstormRages, + [STRINGID_SANDSTORMSUBSIDED - BATTLESTRINGS_TABLE_START] = sText_SandstormSubsided, + [STRINGID_SUNLIGHTGOTBRIGHT - BATTLESTRINGS_TABLE_START] = sText_SunlightGotBright, + [STRINGID_SUNLIGHTSTRONG - BATTLESTRINGS_TABLE_START] = sText_SunlightStrong, + [STRINGID_SUNLIGHTFADED - BATTLESTRINGS_TABLE_START] = sText_SunlightFaded, + [STRINGID_STARTEDHAIL - BATTLESTRINGS_TABLE_START] = sText_StartedHail, + [STRINGID_HAILCONTINUES - BATTLESTRINGS_TABLE_START] = sText_HailContinues, + [STRINGID_HAILSTOPPED - BATTLESTRINGS_TABLE_START] = sText_HailStopped, + [STRINGID_FAILEDTOSPITUP - BATTLESTRINGS_TABLE_START] = sText_FailedToSpitUp, + [STRINGID_FAILEDTOSWALLOW - BATTLESTRINGS_TABLE_START] = sText_FailedToSwallow, + [STRINGID_WINDBECAMEHEATWAVE - BATTLESTRINGS_TABLE_START] = sText_WindBecameHeatWave, + [STRINGID_STATCHANGESGONE - BATTLESTRINGS_TABLE_START] = sText_StatChangesGone, + [STRINGID_COINSSCATTERED - BATTLESTRINGS_TABLE_START] = sText_CoinsScattered, + [STRINGID_TOOWEAKFORSUBSTITUTE - BATTLESTRINGS_TABLE_START] = sText_TooWeakForSubstitute, + [STRINGID_SHAREDPAIN - BATTLESTRINGS_TABLE_START] = sText_SharedPain, + [STRINGID_BELLCHIMED - BATTLESTRINGS_TABLE_START] = sText_BellChimed, + [STRINGID_FAINTINTHREE - BATTLESTRINGS_TABLE_START] = sText_FaintInThree, + [STRINGID_NOPPLEFT - BATTLESTRINGS_TABLE_START] = sText_NoPPLeft, + [STRINGID_BUTNOPPLEFT - BATTLESTRINGS_TABLE_START] = sText_ButNoPPLeft, + [STRINGID_PLAYERUSEDITEM - BATTLESTRINGS_TABLE_START] = sText_PlayerUsedItem, + [STRINGID_WALLYUSEDITEM - BATTLESTRINGS_TABLE_START] = sText_WallyUsedItem, + [STRINGID_TRAINERBLOCKEDBALL - BATTLESTRINGS_TABLE_START] = sText_TrainerBlockedBall, + [STRINGID_DONTBEATHIEF - BATTLESTRINGS_TABLE_START] = sText_DontBeAThief, + [STRINGID_ITDODGEDBALL - BATTLESTRINGS_TABLE_START] = sText_ItDodgedBall, + [STRINGID_YOUMISSEDPKMN - BATTLESTRINGS_TABLE_START] = sText_YouMissedPkmn, + [STRINGID_PKMNBROKEFREE - BATTLESTRINGS_TABLE_START] = sText_PkmnBrokeFree, + [STRINGID_ITAPPEAREDCAUGHT - BATTLESTRINGS_TABLE_START] = sText_ItAppearedCaught, + [STRINGID_AARGHALMOSTHADIT - BATTLESTRINGS_TABLE_START] = sText_AarghAlmostHadIt, + [STRINGID_SHOOTSOCLOSE - BATTLESTRINGS_TABLE_START] = sText_ShootSoClose, + [STRINGID_GOTCHAPKMNCAUGHT - BATTLESTRINGS_TABLE_START] = sText_GotchaPkmnCaught, + [STRINGID_GOTCHAPKMNCAUGHT2 - BATTLESTRINGS_TABLE_START] = sText_GotchaPkmnCaught2, + [STRINGID_GIVENICKNAMECAPTURED - BATTLESTRINGS_TABLE_START] = sText_GiveNicknameCaptured, + [STRINGID_PKMNSENTTOPC - BATTLESTRINGS_TABLE_START] = sText_PkmnSentToPC, + [STRINGID_PKMNDATAADDEDTODEX - BATTLESTRINGS_TABLE_START] = sText_PkmnDataAddedToDex, + [STRINGID_ITISRAINING - BATTLESTRINGS_TABLE_START] = sText_ItIsRaining, + [STRINGID_SANDSTORMISRAGING - BATTLESTRINGS_TABLE_START] = sText_SandstormIsRaging, + [STRINGID_CANTESCAPE2 - BATTLESTRINGS_TABLE_START] = sText_CantEscape2, + [STRINGID_PKMNIGNORESASLEEP - BATTLESTRINGS_TABLE_START] = sText_PkmnIgnoresAsleep, + [STRINGID_PKMNIGNOREDORDERS - BATTLESTRINGS_TABLE_START] = sText_PkmnIgnoredOrders, + [STRINGID_PKMNBEGANTONAP - BATTLESTRINGS_TABLE_START] = sText_PkmnBeganToNap, + [STRINGID_PKMNLOAFING - BATTLESTRINGS_TABLE_START] = sText_PkmnLoafing, + [STRINGID_PKMNWONTOBEY - BATTLESTRINGS_TABLE_START] = sText_PkmnWontObey, + [STRINGID_PKMNTURNEDAWAY - BATTLESTRINGS_TABLE_START] = sText_PkmnTurnedAway, + [STRINGID_PKMNPRETENDNOTNOTICE - BATTLESTRINGS_TABLE_START] = sText_PkmnPretendNotNotice, + [STRINGID_ENEMYABOUTTOSWITCHPKMN - BATTLESTRINGS_TABLE_START] = sText_EnemyAboutToSwitchPkmn, + [STRINGID_CREPTCLOSER - BATTLESTRINGS_TABLE_START] = sText_CreptCloser, + [STRINGID_CANTGETCLOSER - BATTLESTRINGS_TABLE_START] = sText_CantGetCloser, + [STRINGID_PKMNWATCHINGCAREFULLY - BATTLESTRINGS_TABLE_START] = sText_PkmnWatchingCarefully, + [STRINGID_PKMNCURIOUSABOUTX - BATTLESTRINGS_TABLE_START] = sText_PkmnCuriousAboutX, + [STRINGID_PKMNENTHRALLEDBYX - BATTLESTRINGS_TABLE_START] = sText_PkmnEnthralledByX, + [STRINGID_PKMNIGNOREDX - BATTLESTRINGS_TABLE_START] = sText_PkmnIgnoredX, + [STRINGID_THREWPOKEBLOCKATPKMN - BATTLESTRINGS_TABLE_START] = sText_ThrewPokeblockAtPkmn, + [STRINGID_OUTOFSAFARIBALLS - BATTLESTRINGS_TABLE_START] = sText_OutOfSafariBalls, + [STRINGID_PKMNSITEMCUREDPARALYSIS - BATTLESTRINGS_TABLE_START] = sText_PkmnsItemCuredParalysis, + [STRINGID_PKMNSITEMCUREDPOISON - BATTLESTRINGS_TABLE_START] = sText_PkmnsItemCuredPoison, + [STRINGID_PKMNSITEMHEALEDBURN - BATTLESTRINGS_TABLE_START] = sText_PkmnsItemHealedBurn, + [STRINGID_PKMNSITEMDEFROSTEDIT - BATTLESTRINGS_TABLE_START] = sText_PkmnsItemDefrostedIt, + [STRINGID_PKMNSITEMWOKEIT - BATTLESTRINGS_TABLE_START] = sText_PkmnsItemWokeIt, + [STRINGID_PKMNSITEMSNAPPEDOUT - BATTLESTRINGS_TABLE_START] = sText_PkmnsItemSnappedOut, + [STRINGID_PKMNSITEMCUREDPROBLEM - BATTLESTRINGS_TABLE_START] = sText_PkmnsItemCuredProblem, + [STRINGID_PKMNSITEMRESTOREDHEALTH - BATTLESTRINGS_TABLE_START] = sText_PkmnsItemRestoredHealth, + [STRINGID_PKMNSITEMRESTOREDPP - BATTLESTRINGS_TABLE_START] = sText_PkmnsItemRestoredPP, + [STRINGID_PKMNSITEMRESTOREDSTATUS - BATTLESTRINGS_TABLE_START] = sText_PkmnsItemRestoredStatus, + [STRINGID_PKMNSITEMRESTOREDHPALITTLE - BATTLESTRINGS_TABLE_START] = sText_PkmnsItemRestoredHPALittle, + [STRINGID_ITEMALLOWSONLYYMOVE - BATTLESTRINGS_TABLE_START] = sText_ItemAllowsOnlyYMove, + [STRINGID_PKMNHUNGONWITHX - BATTLESTRINGS_TABLE_START] = sText_PkmnHungOnWithX, + [STRINGID_EMPTYSTRING3 - BATTLESTRINGS_TABLE_START] = gText_EmptyString3, + [STRINGID_PKMNSXPREVENTSBURNS - BATTLESTRINGS_TABLE_START] = sText_PkmnsXPreventsBurns, + [STRINGID_PKMNSXBLOCKSY - BATTLESTRINGS_TABLE_START] = sText_PkmnsXBlocksY, + [STRINGID_PKMNSXRESTOREDHPALITTLE2 - BATTLESTRINGS_TABLE_START] = sText_PkmnsXRestoredHPALittle2, + [STRINGID_PKMNSXWHIPPEDUPSANDSTORM - BATTLESTRINGS_TABLE_START] = sText_PkmnsXWhippedUpSandstorm, + [STRINGID_PKMNSXPREVENTSYLOSS - BATTLESTRINGS_TABLE_START] = sText_PkmnsXPreventsYLoss, + [STRINGID_PKMNSXINFATUATEDY - BATTLESTRINGS_TABLE_START] = sText_PkmnsXInfatuatedY, + [STRINGID_PKMNSXMADEYINEFFECTIVE - BATTLESTRINGS_TABLE_START] = sText_PkmnsXMadeYIneffective, + [STRINGID_PKMNSXCUREDYPROBLEM - BATTLESTRINGS_TABLE_START] = sText_PkmnsXCuredYProblem, + [STRINGID_ITSUCKEDLIQUIDOOZE - BATTLESTRINGS_TABLE_START] = sText_ItSuckedLiquidOoze, + [STRINGID_PKMNTRANSFORMED - BATTLESTRINGS_TABLE_START] = sText_PkmnTransformed, + [STRINGID_ELECTRICITYWEAKENED - BATTLESTRINGS_TABLE_START] = sText_ElectricityWeakened, + [STRINGID_FIREWEAKENED - BATTLESTRINGS_TABLE_START] = sText_FireWeakened, + [STRINGID_PKMNHIDUNDERWATER - BATTLESTRINGS_TABLE_START] = sText_PkmnHidUnderwater, + [STRINGID_PKMNSPRANGUP - BATTLESTRINGS_TABLE_START] = sText_PkmnSprangUp, + [STRINGID_HMMOVESCANTBEFORGOTTEN - BATTLESTRINGS_TABLE_START] = sText_HMMovesCantBeForgotten, + [STRINGID_XFOUNDONEY - BATTLESTRINGS_TABLE_START] = sText_XFoundOneY, + [STRINGID_PLAYERDEFEATEDTRAINER1 - BATTLESTRINGS_TABLE_START] = sText_PlayerDefeatedLinkTrainerTrainer1, + [STRINGID_SOOTHINGAROMA - BATTLESTRINGS_TABLE_START] = sText_SoothingAroma, + [STRINGID_ITEMSCANTBEUSEDNOW - BATTLESTRINGS_TABLE_START] = sText_ItemsCantBeUsedNow, + [STRINGID_FORXCOMMAYZ - BATTLESTRINGS_TABLE_START] = sText_ForXCommaYZ, + [STRINGID_USINGITEMSTATOFPKMNROSE - BATTLESTRINGS_TABLE_START] = sText_UsingItemTheStatOfPkmnRose, + [STRINGID_PKMNUSEDXTOGETPUMPED - BATTLESTRINGS_TABLE_START] = sText_PkmnUsedXToGetPumped, + [STRINGID_PKMNSXMADEYUSELESS - BATTLESTRINGS_TABLE_START] = sText_PkmnsXMadeYUseless, + [STRINGID_PKMNTRAPPEDBYSANDTOMB - BATTLESTRINGS_TABLE_START] = sText_PkmnTrappedBySandTomb, + [STRINGID_EMPTYSTRING4 - BATTLESTRINGS_TABLE_START] = sText_EmptyString4, + [STRINGID_ABOOSTED - BATTLESTRINGS_TABLE_START] = sText_ABoosted, + [STRINGID_PKMNSXINTENSIFIEDSUN - BATTLESTRINGS_TABLE_START] = sText_PkmnsXIntensifiedSun, + [STRINGID_PKMNMAKESGROUNDMISS - BATTLESTRINGS_TABLE_START] = sText_PkmnMakesGroundMiss, + [STRINGID_YOUTHROWABALLNOWRIGHT - BATTLESTRINGS_TABLE_START] = sText_YouThrowABallNowRight, + [STRINGID_PKMNSXTOOKATTACK - BATTLESTRINGS_TABLE_START] = sText_PkmnsXTookAttack, + [STRINGID_PKMNCHOSEXASDESTINY - BATTLESTRINGS_TABLE_START] = sText_PkmnChoseXAsDestiny, + [STRINGID_PKMNLOSTFOCUS - BATTLESTRINGS_TABLE_START] = sText_PkmnLostFocus, + [STRINGID_USENEXTPKMN - BATTLESTRINGS_TABLE_START] = sText_UseNextPkmn, + [STRINGID_PKMNFLEDUSINGITS - BATTLESTRINGS_TABLE_START] = sText_PkmnFledUsingIts, + [STRINGID_PKMNFLEDUSING - BATTLESTRINGS_TABLE_START] = sText_PkmnFledUsing, + [STRINGID_PKMNWASDRAGGEDOUT - BATTLESTRINGS_TABLE_START] = sText_PkmnWasDraggedOut, + [STRINGID_PREVENTEDFROMWORKING - BATTLESTRINGS_TABLE_START] = sText_PreventedFromWorking, + [STRINGID_PKMNSITEMNORMALIZEDSTATUS - BATTLESTRINGS_TABLE_START] = sText_PkmnsItemNormalizedStatus, + [STRINGID_TRAINER1USEDITEM - BATTLESTRINGS_TABLE_START] = sText_Trainer1UsedItem, + [STRINGID_BOXISFULL - BATTLESTRINGS_TABLE_START] = sText_BoxIsFull, + [STRINGID_PKMNAVOIDEDATTACK - BATTLESTRINGS_TABLE_START] = sText_PkmnAvoidedAttack, + [STRINGID_PKMNSXMADEITINEFFECTIVE - BATTLESTRINGS_TABLE_START] = sText_PkmnsXMadeItIneffective, + [STRINGID_PKMNSXPREVENTSFLINCHING - BATTLESTRINGS_TABLE_START] = sText_PkmnsXPreventsFlinching, + [STRINGID_PKMNALREADYHASBURN - BATTLESTRINGS_TABLE_START] = sText_PkmnAlreadyHasBurn, + [STRINGID_STATSWONTDECREASE2 - BATTLESTRINGS_TABLE_START] = sText_StatsWontDecrease2, + [STRINGID_PKMNSXBLOCKSY2 - BATTLESTRINGS_TABLE_START] = sText_PkmnsXBlocksY2, + [STRINGID_PKMNSXWOREOFF - BATTLESTRINGS_TABLE_START] = sText_PkmnsXWoreOff, + [STRINGID_PKMNRAISEDDEFALITTLE - BATTLESTRINGS_TABLE_START] = sText_PkmnRaisedDefALittle, + [STRINGID_PKMNRAISEDSPDEFALITTLE - BATTLESTRINGS_TABLE_START] = sText_PkmnRaisedSpDefALittle, + [STRINGID_THEWALLSHATTERED - BATTLESTRINGS_TABLE_START] = sText_TheWallShattered, + [STRINGID_PKMNSXPREVENTSYSZ - BATTLESTRINGS_TABLE_START] = sText_PkmnsXPreventsYsZ, + [STRINGID_PKMNSXCUREDITSYPROBLEM - BATTLESTRINGS_TABLE_START] = sText_PkmnsXCuredItsYProblem, + [STRINGID_ATTACKERCANTESCAPE - BATTLESTRINGS_TABLE_START] = sText_AttackerCantEscape, + [STRINGID_PKMNOBTAINEDX - BATTLESTRINGS_TABLE_START] = sText_PkmnObtainedX, + [STRINGID_PKMNOBTAINEDX2 - BATTLESTRINGS_TABLE_START] = sText_PkmnObtainedX2, + [STRINGID_PKMNOBTAINEDXYOBTAINEDZ - BATTLESTRINGS_TABLE_START] = sText_PkmnObtainedXYObtainedZ, + [STRINGID_BUTNOEFFECT - BATTLESTRINGS_TABLE_START] = sText_ButNoEffect, + [STRINGID_PKMNSXHADNOEFFECTONY - BATTLESTRINGS_TABLE_START] = sText_PkmnsXHadNoEffectOnY, + [STRINGID_TWOENEMIESDEFEATED - BATTLESTRINGS_TABLE_START] = sText_TwoInGameTrainersDefeated, + [STRINGID_TRAINER2LOSETEXT - BATTLESTRINGS_TABLE_START] = sText_Trainer2LoseText, + [STRINGID_PKMNINCAPABLEOFPOWER - BATTLESTRINGS_TABLE_START] = sText_PkmnIncapableOfPower, + [STRINGID_GLINTAPPEARSINEYE - BATTLESTRINGS_TABLE_START] = sText_GlintAppearsInEye, + [STRINGID_PKMNGETTINGINTOPOSITION - BATTLESTRINGS_TABLE_START] = sText_PkmnGettingIntoPosition, + [STRINGID_PKMNBEGANGROWLINGDEEPLY - BATTLESTRINGS_TABLE_START] = sText_PkmnBeganGrowlingDeeply, + [STRINGID_PKMNEAGERFORMORE - BATTLESTRINGS_TABLE_START] = sText_PkmnEagerForMore, + [STRINGID_DEFEATEDOPPONENTBYREFEREE - BATTLESTRINGS_TABLE_START] = sText_DefeatedOpponentByReferee, + [STRINGID_LOSTTOOPPONENTBYREFEREE - BATTLESTRINGS_TABLE_START] = sText_LostToOpponentByReferee, + [STRINGID_TIEDOPPONENTBYREFEREE - BATTLESTRINGS_TABLE_START] = sText_TiedOpponentByReferee, + [STRINGID_QUESTIONFORFEITMATCH - BATTLESTRINGS_TABLE_START] = sText_QuestionForfeitMatch, + [STRINGID_FORFEITEDMATCH - BATTLESTRINGS_TABLE_START] = sText_ForfeitedMatch, + [STRINGID_PKMNTRANSFERREDSOMEONESPC - BATTLESTRINGS_TABLE_START] = gText_PkmnTransferredSomeonesPC, + [STRINGID_PKMNTRANSFERREDLANETTESPC - BATTLESTRINGS_TABLE_START] = gText_PkmnTransferredLanettesPC, + [STRINGID_PKMNBOXSOMEONESPCFULL - BATTLESTRINGS_TABLE_START] = gText_PkmnTransferredSomeonesPCBoxFull, + [STRINGID_PKMNBOXLANETTESPCFULL - BATTLESTRINGS_TABLE_START] = gText_PkmnTransferredLanettesPCBoxFull, + [STRINGID_TRAINER1WINTEXT - BATTLESTRINGS_TABLE_START] = sText_Trainer1WinText, + [STRINGID_TRAINER2WINTEXT - BATTLESTRINGS_TABLE_START] = sText_Trainer2WinText, }; const u16 gMissStringIds[] = @@ -2331,14 +2331,14 @@ void BufferStringBattle(u16 stringID) } break; default: // load a string from the table - if (stringID >= BATTLESTRINGS_COUNT + BATTLESTRINGS_ID_ADDER) + if (stringID >= BATTLESTRINGS_COUNT) { gDisplayedStringBattle[0] = EOS; return; } else { - stringPtr = gBattleStringsTable[stringID - BATTLESTRINGS_ID_ADDER]; + stringPtr = gBattleStringsTable[stringID - BATTLESTRINGS_TABLE_START]; } break; } @@ -2862,7 +2862,7 @@ static void ExpandBattleTextBuffPlaceholders(const u8 *src, u8 *dst) { case B_BUFF_STRING: // battle string hword = T1_READ_16(&src[srcID + 1]); - StringAppend(dst, gBattleStringsTable[hword - BATTLESTRINGS_ID_ADDER]); + StringAppend(dst, gBattleStringsTable[hword - BATTLESTRINGS_TABLE_START]); srcID += 3; break; case B_BUFF_NUMBER: // int to string diff --git a/src/battle_tv.c b/src/battle_tv.c index f65bf73ea..b9008b47a 100644 --- a/src/battle_tv.c +++ b/src/battle_tv.c @@ -570,7 +570,7 @@ void BattleTv_SetDataBasedOnString(u16 stringId) moveSlot = GetBattlerMoveSlotId(gBattlerAttacker, gBattleMsgDataPtr->currentMove); - if (moveSlot >= MAX_MON_MOVES && IsNotSpecialBattleString(stringId) && stringId > BATTLESTRINGS_ID_ADDER) + if (moveSlot >= MAX_MON_MOVES && IsNotSpecialBattleString(stringId) && stringId > BATTLESTRINGS_TABLE_START) { tvPtr->side[atkSide].faintCause = FNT_OTHER; return; diff --git a/src/evolution_scene.c b/src/evolution_scene.c index 327e48d19..bde11ddb5 100644 --- a/src/evolution_scene.c +++ b/src/evolution_scene.c @@ -855,7 +855,7 @@ static void Task_EvolutionScene(u8 taskId) { BufferMoveToLearnIntoBattleTextBuff2(); PlayFanfare(MUS_LEVEL_UP); - BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_PKMNLEARNEDMOVE - BATTLESTRINGS_ID_ADDER]); + BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_PKMNLEARNEDMOVE - BATTLESTRINGS_TABLE_START]); BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_MSG); gTasks[taskId].tLearnsFirstMove = 0x40; // re-used as a counter gTasks[taskId].tState++; @@ -873,7 +873,7 @@ static void Task_EvolutionScene(u8 taskId) { // "{mon} is trying to learn {move}" BufferMoveToLearnIntoBattleTextBuff2(); - BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_TRYTOLEARNMOVE1 - BATTLESTRINGS_ID_ADDER]); + BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_TRYTOLEARNMOVE1 - BATTLESTRINGS_TABLE_START]); BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_MSG); gTasks[taskId].tLearnMoveState++; } @@ -882,7 +882,7 @@ static void Task_EvolutionScene(u8 taskId) if (!IsTextPrinterActive(0) && !IsSEPlaying()) { // "But, {mon} can't learn more than four moves" - BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_TRYTOLEARNMOVE2 - BATTLESTRINGS_ID_ADDER]); + BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_TRYTOLEARNMOVE2 - BATTLESTRINGS_TABLE_START]); BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_MSG); gTasks[taskId].tLearnMoveState++; } @@ -891,7 +891,7 @@ static void Task_EvolutionScene(u8 taskId) if (!IsTextPrinterActive(0) && !IsSEPlaying()) { // "Delete a move to make room for {move}?" - BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_TRYTOLEARNMOVE3 - BATTLESTRINGS_ID_ADDER]); + BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_TRYTOLEARNMOVE3 - BATTLESTRINGS_TABLE_START]); BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_MSG); gTasks[taskId].tLearnMoveYesState = MVSTATE_SHOW_MOVE_SELECT; gTasks[taskId].tLearnMoveNoState = MVSTATE_ASK_CANCEL; @@ -979,7 +979,7 @@ static void Task_EvolutionScene(u8 taskId) if (IsHMMove2(move)) { // Can't forget HMs - BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_HMMOVESCANTBEFORGOTTEN - BATTLESTRINGS_ID_ADDER]); + BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_HMMOVESCANTBEFORGOTTEN - BATTLESTRINGS_TABLE_START]); BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_MSG); gTasks[taskId].tLearnMoveState = MVSTATE_RETRY_AFTER_HM; } @@ -996,14 +996,14 @@ static void Task_EvolutionScene(u8 taskId) } break; case MVSTATE_FORGET_MSG_1: - BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_123POOF - BATTLESTRINGS_ID_ADDER]); + BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_123POOF - BATTLESTRINGS_TABLE_START]); BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_MSG); gTasks[taskId].tLearnMoveState++; break; case MVSTATE_FORGET_MSG_2: if (!IsTextPrinterActive(0) && !IsSEPlaying()) { - BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_PKMNFORGOTMOVE - BATTLESTRINGS_ID_ADDER]); + BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_PKMNFORGOTMOVE - BATTLESTRINGS_TABLE_START]); BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_MSG); gTasks[taskId].tLearnMoveState++; } @@ -1011,20 +1011,20 @@ static void Task_EvolutionScene(u8 taskId) case MVSTATE_LEARNED_MOVE: if (!IsTextPrinterActive(0) && !IsSEPlaying()) { - BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_ANDELLIPSIS - BATTLESTRINGS_ID_ADDER]); + BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_ANDELLIPSIS - BATTLESTRINGS_TABLE_START]); BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_MSG); gTasks[taskId].tState = EVOSTATE_LEARNED_MOVE; } break; case MVSTATE_ASK_CANCEL: - BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_STOPLEARNINGMOVE - BATTLESTRINGS_ID_ADDER]); + BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_STOPLEARNINGMOVE - BATTLESTRINGS_TABLE_START]); BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_MSG); gTasks[taskId].tLearnMoveYesState = MVSTATE_CANCEL; gTasks[taskId].tLearnMoveNoState = MVSTATE_INTRO_MSG_1; gTasks[taskId].tLearnMoveState = MVSTATE_PRINT_YES_NO; break; case MVSTATE_CANCEL: - BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_DIDNOTLEARNMOVE - BATTLESTRINGS_ID_ADDER]); + BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_DIDNOTLEARNMOVE - BATTLESTRINGS_TABLE_START]); BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_MSG); gTasks[taskId].tState = EVOSTATE_TRY_LEARN_MOVE; break; @@ -1258,7 +1258,7 @@ static void Task_TradeEvolutionScene(u8 taskId) { BufferMoveToLearnIntoBattleTextBuff2(); PlayFanfare(MUS_LEVEL_UP); - BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_PKMNLEARNEDMOVE - BATTLESTRINGS_ID_ADDER]); + BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_PKMNLEARNEDMOVE - BATTLESTRINGS_TABLE_START]); DrawTextOnTradeWindow(0, gDisplayedStringBattle, 1); gTasks[taskId].tLearnsFirstMove = 0x40; // re-used as a counter gTasks[taskId].tState++; @@ -1276,7 +1276,7 @@ static void Task_TradeEvolutionScene(u8 taskId) { // "{mon} is trying to learn {move}" BufferMoveToLearnIntoBattleTextBuff2(); - BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_TRYTOLEARNMOVE1 - BATTLESTRINGS_ID_ADDER]); + BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_TRYTOLEARNMOVE1 - BATTLESTRINGS_TABLE_START]); DrawTextOnTradeWindow(0, gDisplayedStringBattle, 1); gTasks[taskId].tLearnMoveState++; } @@ -1285,7 +1285,7 @@ static void Task_TradeEvolutionScene(u8 taskId) if (!IsTextPrinterActive(0) && !IsSEPlaying()) { // "But, {mon} can't learn more than four moves" - BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_TRYTOLEARNMOVE2 - BATTLESTRINGS_ID_ADDER]); + BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_TRYTOLEARNMOVE2 - BATTLESTRINGS_TABLE_START]); DrawTextOnTradeWindow(0, gDisplayedStringBattle, 1); gTasks[taskId].tLearnMoveState++; } @@ -1294,7 +1294,7 @@ static void Task_TradeEvolutionScene(u8 taskId) if (!IsTextPrinterActive(0) && !IsSEPlaying()) { // "Delete a move to make room for {move}?" - BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_TRYTOLEARNMOVE3 - BATTLESTRINGS_ID_ADDER]); + BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_TRYTOLEARNMOVE3 - BATTLESTRINGS_TABLE_START]); DrawTextOnTradeWindow(0, gDisplayedStringBattle, 1); gTasks[taskId].tLearnMoveYesState = T_MVSTATE_SHOW_MOVE_SELECT; gTasks[taskId].tLearnMoveNoState = T_MVSTATE_ASK_CANCEL; @@ -1315,7 +1315,7 @@ static void Task_TradeEvolutionScene(u8 taskId) { case 0: // YES sEvoCursorPos = 0; - BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_EMPTYSTRING3 - BATTLESTRINGS_ID_ADDER]); + BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_EMPTYSTRING3 - BATTLESTRINGS_TABLE_START]); DrawTextOnTradeWindow(0, gDisplayedStringBattle, 1); gTasks[taskId].tLearnMoveState = gTasks[taskId].tLearnMoveYesState; if (gTasks[taskId].tLearnMoveState == T_MVSTATE_SHOW_MOVE_SELECT) @@ -1324,7 +1324,7 @@ static void Task_TradeEvolutionScene(u8 taskId) case 1: // NO case MENU_B_PRESSED: sEvoCursorPos = 1; - BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_EMPTYSTRING3 - BATTLESTRINGS_ID_ADDER]); + BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_EMPTYSTRING3 - BATTLESTRINGS_TABLE_START]); DrawTextOnTradeWindow(0, gDisplayedStringBattle, 1); gTasks[taskId].tLearnMoveState = gTasks[taskId].tLearnMoveNoState; break; @@ -1363,7 +1363,7 @@ static void Task_TradeEvolutionScene(u8 taskId) if (IsHMMove2(move)) { // Can't forget HMs - BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_HMMOVESCANTBEFORGOTTEN - BATTLESTRINGS_ID_ADDER]); + BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_HMMOVESCANTBEFORGOTTEN - BATTLESTRINGS_TABLE_START]); DrawTextOnTradeWindow(0, gDisplayedStringBattle, 1); gTasks[taskId].tLearnMoveState = T_MVSTATE_RETRY_AFTER_HM; } @@ -1374,7 +1374,7 @@ static void Task_TradeEvolutionScene(u8 taskId) RemoveMonPPBonus(mon, var); SetMonMoveSlot(mon, gMoveToLearn, var); - BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_123POOF - BATTLESTRINGS_ID_ADDER]); + BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_123POOF - BATTLESTRINGS_TABLE_START]); DrawTextOnTradeWindow(0, gDisplayedStringBattle, 1); gTasks[taskId].tLearnMoveState++; } @@ -1384,7 +1384,7 @@ static void Task_TradeEvolutionScene(u8 taskId) case T_MVSTATE_FORGET_MSG: if (!IsTextPrinterActive(0) && !IsSEPlaying()) { - BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_PKMNFORGOTMOVE - BATTLESTRINGS_ID_ADDER]); + BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_PKMNFORGOTMOVE - BATTLESTRINGS_TABLE_START]); DrawTextOnTradeWindow(0, gDisplayedStringBattle, 1); gTasks[taskId].tLearnMoveState++; } @@ -1392,20 +1392,20 @@ static void Task_TradeEvolutionScene(u8 taskId) case T_MVSTATE_LEARNED_MOVE: if (!IsTextPrinterActive(0) && !IsSEPlaying()) { - BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_ANDELLIPSIS - BATTLESTRINGS_ID_ADDER]); + BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_ANDELLIPSIS - BATTLESTRINGS_TABLE_START]); DrawTextOnTradeWindow(0, gDisplayedStringBattle, 1); gTasks[taskId].tState = T_EVOSTATE_LEARNED_MOVE; } break; case T_MVSTATE_ASK_CANCEL: - BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_STOPLEARNINGMOVE - BATTLESTRINGS_ID_ADDER]); + BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_STOPLEARNINGMOVE - BATTLESTRINGS_TABLE_START]); DrawTextOnTradeWindow(0, gDisplayedStringBattle, 1); gTasks[taskId].tLearnMoveYesState = T_MVSTATE_CANCEL; gTasks[taskId].tLearnMoveNoState = T_MVSTATE_INTRO_MSG_1; gTasks[taskId].tLearnMoveState = T_MVSTATE_PRINT_YES_NO; break; case T_MVSTATE_CANCEL: - BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_DIDNOTLEARNMOVE - BATTLESTRINGS_ID_ADDER]); + BattleStringExpandPlaceholdersToDisplayedString(gBattleStringsTable[STRINGID_DIDNOTLEARNMOVE - BATTLESTRINGS_TABLE_START]); DrawTextOnTradeWindow(0, gDisplayedStringBattle, 1); gTasks[taskId].tState = T_EVOSTATE_TRY_LEARN_MOVE; break; From bb91b1b0d1cf70fa49cb0b1f2a309ad541927164 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Thu, 10 Mar 2022 16:36:41 -0500 Subject: [PATCH 053/130] Update generic macro argument names --- asm/macros/event.inc | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/asm/macros/event.inc b/asm/macros/event.inc index 58e37d0a6..661e675c9 100644 --- a/asm/macros/event.inc +++ b/asm/macros/event.inc @@ -828,10 +828,10 @@ .endm @ Sets the movement type (MOVEMENT_TYPE_*) for an object's template. - .macro setobjectmovementtype word:req, byte:req + .macro setobjectmovementtype localId:req, movementType:req .byte 0x65 - .2byte \word - .byte \byte + .2byte \localId + .byte \movementType .endm @ If a standard message box (or its text) is being drawn on-screen, this command blocks script execution until the @@ -1451,48 +1451,48 @@ .endm @ Equivalent to goto using the relative address set by setvaddress. - .macro vgoto pointer:req + .macro vgoto destination:req .byte 0xb9 - .4byte \pointer + .4byte \destination .endm @ Equivalent to call using the relative address set by setvaddress. - .macro vcall pointer:req + .macro vcall destination:req .byte 0xba - .4byte \pointer + .4byte \destination .endm @ Equivalent to goto_if using the relative address set by setvaddress. - .macro vgoto_if byte:req, pointer:req + .macro vgoto_if condition:req, destination:req .byte 0xbb - .byte \byte - .4byte \pointer + .byte \condition + .4byte \destination .endm @ Equivalent to call_if using the relative address set by setvaddress. - .macro vcall_if byte:req, pointer:req + .macro vcall_if condition:req, destination:req .byte 0xbc - .byte \byte - .4byte \pointer + .byte \condition + .4byte \destination .endm @ Equivalent to message using the relative address set by setvaddress. - .macro vmessage pointer:req + .macro vmessage text:req .byte 0xbd - .4byte \pointer + .4byte \text .endm @ Expands the given text at the pointer (- the relative address set by setvaddress) into gStringVar4 - .macro vbuffermessage ptr:req + .macro vbuffermessage text:req .byte 0xbe - .4byte \ptr + .4byte \text .endm @ Equivalent to bufferstring using the relative address set by setvaddress. - .macro vbufferstring stringVarIndex:req, pointer:req + .macro vbufferstring stringVarIndex:req, text:req .byte 0xbf stringvar \stringVarIndex - .4byte \pointer + .4byte \text .endm @ Create a window showing how many Coins the player has. @@ -1549,9 +1549,9 @@ .endm @ Used only in FireRed/LeafGreen, does nothing in Emerald. - .macro loadhelp pointer:req + .macro loadhelp text:req .byte 0xc8 - .4byte \pointer + .4byte \text .endm @ Used only in FireRed/LeafGreen, does nothing in Emerald. From 0a0157b62c29172eabd07f0c0eb02d6567957c2c Mon Sep 17 00:00:00 2001 From: GriffinR Date: Mon, 14 Mar 2022 15:54:47 -0400 Subject: [PATCH 054/130] Name unknown_16.png --- .../pics/{unknown_16.png => jump_long_grass.png} | Bin spritesheet_rules.mk | 2 +- src/data/object_events/object_event_graphics.h | 2 +- src/field_effect_helpers.c | 2 ++ 4 files changed, 4 insertions(+), 2 deletions(-) rename graphics/field_effects/pics/{unknown_16.png => jump_long_grass.png} (100%) diff --git a/graphics/field_effects/pics/unknown_16.png b/graphics/field_effects/pics/jump_long_grass.png similarity index 100% rename from graphics/field_effects/pics/unknown_16.png rename to graphics/field_effects/pics/jump_long_grass.png diff --git a/spritesheet_rules.mk b/spritesheet_rules.mk index ae7971960..9fb184638 100644 --- a/spritesheet_rules.mk +++ b/spritesheet_rules.mk @@ -636,7 +636,7 @@ $(FLDEFFGFXDIR)/tall_grass.4bpp: %.4bpp: %.png $(FLDEFFGFXDIR)/tree_disguise.4bpp: %.4bpp: %.png $(GFX) $< $@ -mwidth 2 -mheight 4 -$(FLDEFFGFXDIR)/unknown_16.4bpp: %.4bpp: %.png +$(FLDEFFGFXDIR)/jump_long_grass.4bpp: %.4bpp: %.png $(GFX) $< $@ -mwidth 2 -mheight 2 $(FLDEFFGFXDIR)/unknown_17.4bpp: %.4bpp: %.png diff --git a/src/data/object_events/object_event_graphics.h b/src/data/object_events/object_event_graphics.h index 81d83a856..6ee56cc78 100755 --- a/src/data/object_events/object_event_graphics.h +++ b/src/data/object_events/object_event_graphics.h @@ -305,7 +305,7 @@ const u16 gFieldEffectObjectPalette1[] = INCBIN_U16("graphics/field_effects/pale const u32 gFieldEffectObjectPic_GroundImpactDust[] = INCBIN_U32("graphics/field_effects/pics/ground_impact_dust.4bpp"); const u32 gFieldEffectObjectPic_JumpTallGrass[] = INCBIN_U32("graphics/field_effects/pics/jump_tall_grass.4bpp"); const u32 gUnusedGrass3[] = INCBIN_U32("graphics/field_effects/pics/unused_grass_3.4bpp"); -const u32 gFieldEffectObjectPic_JumpLongGrass[] = INCBIN_U32("graphics/field_effects/pics/unknown_16.4bpp"); +const u32 gFieldEffectObjectPic_JumpLongGrass[] = INCBIN_U32("graphics/field_effects/pics/jump_long_grass.4bpp"); const u32 gFieldEffectObjectPic_Unknown17[] = INCBIN_U32("graphics/field_effects/pics/unknown_17.4bpp"); const u32 gFieldEffectObjectPic_UnusedGrass2[] = INCBIN_U32("graphics/field_effects/pics/unused_grass_2.4bpp"); const u32 gFieldEffectObjectPic_LongGrass[] = INCBIN_U32("graphics/field_effects/pics/long_grass.4bpp"); diff --git a/src/field_effect_helpers.c b/src/field_effect_helpers.c index 65617038d..036ff33f2 100755 --- a/src/field_effect_helpers.c +++ b/src/field_effect_helpers.c @@ -487,6 +487,8 @@ void UpdateLongGrassFieldEffect(struct Sprite *sprite) #undef sCurrentMap #undef sObjectMoved +// Effectively unused as it's not possible in vanilla to jump onto long grass (no adjacent ledges, and can't ride the Acro Bike in it). +// The graphics for this effect do not visually correspond to tall grass either. Perhaps these graphics were its original design? u32 FldEff_JumpLongGrass(void) { u8 spriteId; From 058783c14841b87dab93b114f216ed1417b27db3 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Mon, 14 Mar 2022 16:01:17 -0400 Subject: [PATCH 055/130] Fix comment mistake --- src/field_effect_helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/field_effect_helpers.c b/src/field_effect_helpers.c index 036ff33f2..c3332c7fc 100755 --- a/src/field_effect_helpers.c +++ b/src/field_effect_helpers.c @@ -488,7 +488,7 @@ void UpdateLongGrassFieldEffect(struct Sprite *sprite) #undef sObjectMoved // Effectively unused as it's not possible in vanilla to jump onto long grass (no adjacent ledges, and can't ride the Acro Bike in it). -// The graphics for this effect do not visually correspond to tall grass either. Perhaps these graphics were its original design? +// The graphics for this effect do not visually correspond to long grass either. Perhaps these graphics were its original design? u32 FldEff_JumpLongGrass(void) { u8 spriteId; From f8b3a1c6584a76cd3e3f2721c5fb3a54bbf3a4f6 Mon Sep 17 00:00:00 2001 From: Andrea Jemmett <1787979+acidghost@users.noreply.github.com> Date: Wed, 16 Mar 2022 14:41:12 +0100 Subject: [PATCH 056/130] Fix finding libpng in gbagfx and rsfont On macOS 12, Homebrew installs libpng in a custom location. --- tools/gbagfx/Makefile | 2 ++ tools/rsfont/Makefile | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tools/gbagfx/Makefile b/tools/gbagfx/Makefile index b4244aa8d..8728fa8d0 100644 --- a/tools/gbagfx/Makefile +++ b/tools/gbagfx/Makefile @@ -1,8 +1,10 @@ CC = gcc CFLAGS = -Wall -Wextra -Werror -Wno-sign-compare -std=c11 -O2 -DPNG_SKIP_SETJMP_CHECK +CFLAGS += $(shell pkg-config --cflags libpng) LIBS = -lpng -lz +LDFLAGS += $(shell pkg-config --libs-only-L libpng) SRCS = main.c convert_png.c gfx.c jasc_pal.c lz.c rl.c util.c font.c huff.c diff --git a/tools/rsfont/Makefile b/tools/rsfont/Makefile index 0bc88a42b..92e44b545 100644 --- a/tools/rsfont/Makefile +++ b/tools/rsfont/Makefile @@ -1,8 +1,10 @@ CC ?= gcc CFLAGS = -Wall -Wextra -Werror -std=c11 -O2 -DPNG_SKIP_SETJMP_CHECK +CFLAGS += $(shell pkg-config --cflags libpng) LIBS = -lpng -lz +LDFLAGS += $(shell pkg-config --libs-only-L libpng) SRCS = main.c convert_png.c util.c font.c From a127cb32bb95410b5b417bbcb2b89271ba3f1539 Mon Sep 17 00:00:00 2001 From: LOuroboros Date: Wed, 30 Mar 2022 02:05:54 -0300 Subject: [PATCH 057/130] Removed pointless use of preproc directives --- src/battle_util.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/battle_util.c b/src/battle_util.c index 93206b526..3b2d9e2ca 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -7964,9 +7964,7 @@ static u16 CalcMoveBasePower(u16 move, u8 battlerAtk, u8 battlerDef) // todo break; case EFFECT_FLING: - #ifdef ITEM_EXPANSION basePower = ItemId_GetFlingPower(gBattleMons[battlerAtk].item); - #endif break; case EFFECT_ERUPTION: basePower = gBattleMons[battlerAtk].hp * basePower / gBattleMons[battlerAtk].maxHP; @@ -9644,9 +9642,7 @@ bool32 CanFling(u8 battlerId) #endif || gFieldStatuses & STATUS_FIELD_MAGIC_ROOM || gDisableStructs[battlerId].embargoTimer != 0 - #ifdef ITEM_EXPANSION || ItemId_GetFlingPower(item) != 0 - #endif || !CanBattlerGetOrLoseItem(battlerId, item)) return FALSE; From 66cbe29c1408feef07772ba0b8a5b89995fa3056 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Wed, 30 Mar 2022 09:37:03 -0400 Subject: [PATCH 058/130] Add bugfix for Battle Factory trainer IVs --- include/battle_factory.h | 2 +- src/battle_factory.c | 24 ++++++++++++++++-------- src/battle_tower.c | 11 ++++++++--- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/include/battle_factory.h b/include/battle_factory.h index 5606d60d1..d414bdb3b 100644 --- a/include/battle_factory.h +++ b/include/battle_factory.h @@ -3,7 +3,7 @@ void CallBattleFactoryFunction(void); bool8 InBattleFactory(void); -u8 GetFactoryMonFixedIV(u8 arg0, u8 arg1); +u8 GetFactoryMonFixedIV(u8 challengeNum, bool8 isLastBattle); void FillFactoryBrainParty(void); u8 GetNumPastRentalsRank(u8 battleMode, u8 lvlMode); u32 GetAiScriptsInBattleFactory(void); diff --git a/src/battle_factory.c b/src/battle_factory.c index 23fa664f3..d88ed37f9 100644 --- a/src/battle_factory.c +++ b/src/battle_factory.c @@ -720,17 +720,25 @@ static void RestorePlayerPartyHeldItems(void) } } -u8 GetFactoryMonFixedIV(u8 arg0, u8 arg1) +// Get the IV to use for the opponent's pokémon. +// The IVs get higher for each subsequent challenge and for +// the last trainer in each challenge. Noland is an exception +// to this, as he uses the IVs that would be used by the regular +// trainers 2 challenges ahead of the current one. +// Due to a mistake in FillFactoryFrontierTrainerParty, the +// challenge number used to determine the IVs for regular trainers +// is Battle Tower's instead of Battle Factory's. +u8 GetFactoryMonFixedIV(u8 challengeNum, bool8 isLastBattle) { - u8 a1; - u8 a2 = (arg1 != 0) ? 1 : 0; + u8 ivSet; + bool8 useHigherIV = isLastBattle ? TRUE : FALSE; - if (arg0 > 8) - a1 = 7; + if (challengeNum > 8) + ivSet = 7; else - a1 = arg0; + ivSet = challengeNum; - return sFixedIVTable[a1][a2]; + return sFixedIVTable[ivSet][useHigherIV]; } void FillFactoryBrainParty(void) @@ -746,7 +754,7 @@ void FillFactoryBrainParty(void) u8 lvlMode = gSaveBlock2Ptr->frontier.lvlMode; u8 battleMode = VarGet(VAR_FRONTIER_BATTLE_MODE); u8 challengeNum = gSaveBlock2Ptr->frontier.factoryWinStreaks[battleMode][lvlMode] / 7; - fixedIV = GetFactoryMonFixedIV(challengeNum + 2, 0); + fixedIV = GetFactoryMonFixedIV(challengeNum + 2, FALSE); monLevel = SetFacilityPtrsGetLevel(); i = 0; otId = T1_READ_32(gSaveBlock2Ptr->playerTrainerId); diff --git a/src/battle_tower.c b/src/battle_tower.c index b747a3dc0..989412e9e 100644 --- a/src/battle_tower.c +++ b/src/battle_tower.c @@ -1827,13 +1827,18 @@ static void FillFactoryFrontierTrainerParty(u16 trainerId, u8 firstMonId) if (trainerId < FRONTIER_TRAINERS_COUNT) { - u8 lvlMode = gSaveBlock2Ptr->frontier.lvlMode; // Unused variable. + u8 lvlMode = gSaveBlock2Ptr->frontier.lvlMode; u8 battleMode = VarGet(VAR_FRONTIER_BATTLE_MODE); + // By mistake Battle Tower's Level 50 challenge number is used to determine the IVs for Battle Factory. + #ifdef BUGFIX + u8 challengeNum = gSaveBlock2Ptr->frontier.factoryWinStreaks[battleMode][lvlMode] / 7; + #else u8 challengeNum = gSaveBlock2Ptr->frontier.towerWinStreaks[battleMode][FRONTIER_LVL_50] / 7; + #endif if (gSaveBlock2Ptr->frontier.curChallengeBattleNum < 6) - fixedIV = GetFactoryMonFixedIV(challengeNum, 0); + fixedIV = GetFactoryMonFixedIV(challengeNum, FALSE); else - fixedIV = GetFactoryMonFixedIV(challengeNum, 1); + fixedIV = GetFactoryMonFixedIV(challengeNum, TRUE); // Last trainer in challenge uses higher IVs } else if (trainerId == TRAINER_EREADER) { From 62f3f144ab499ff47c4451212b7350e0815a57c7 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Fri, 4 Mar 2022 11:02:19 -0500 Subject: [PATCH 059/130] Clean up some trainer hill --- asm/macros/trainer_hill.inc | 8 +- data/maps/TrainerHill_Entrance/scripts.inc | 2 +- include/constants/trainer_hill.h | 27 +- include/ereader_helpers.h | 2 +- include/global.h | 11 +- include/trainer_hill.h | 40 +- src/data/battle_frontier/trainer_hill.h | 957 ++++++--------------- src/ereader_helpers.c | 122 ++- src/trainer_hill.c | 167 ++-- 9 files changed, 456 insertions(+), 880 deletions(-) diff --git a/asm/macros/trainer_hill.inc b/asm/macros/trainer_hill.inc index 65c8c6bef..988e2867a 100644 --- a/asm/macros/trainer_hill.inc +++ b/asm/macros/trainer_hill.inc @@ -100,9 +100,9 @@ special CallTrainerHillFunction .endm - @ Set the challenge mode to HILL_TAG_* (Normal, Variety, Unique, or Expert) - .macro trainerhill_settag tag:req - setvar VAR_0x8004, TRAINER_HILL_FUNC_SET_TAG - copyvar VAR_0x8005, \tag + @ Set the challenge mode to HILL_MODE_* (Normal, Variety, Unique, or Expert) + .macro trainerhill_setmode mode:req + setvar VAR_0x8004, TRAINER_HILL_FUNC_SET_MODE + copyvar VAR_0x8005, \mode special CallTrainerHillFunction .endm diff --git a/data/maps/TrainerHill_Entrance/scripts.inc b/data/maps/TrainerHill_Entrance/scripts.inc index 8989883e4..2dd001a3b 100644 --- a/data/maps/TrainerHill_Entrance/scripts.inc +++ b/data/maps/TrainerHill_Entrance/scripts.inc @@ -157,7 +157,7 @@ TrainerHill_Entrance_EventScript_ChooseChallenge:: switch VAR_RESULT case 4, TrainerHill_Entrance_EventScript_CancelEntry case MULTI_B_PRESSED, TrainerHill_Entrance_EventScript_CancelEntry - trainerhill_settag VAR_RESULT + trainerhill_setmode VAR_RESULT setvar VAR_TRAINER_HILL_IS_ACTIVE, 1 setvar VAR_TEMP_5, 0 special HealPlayerParty diff --git a/include/constants/trainer_hill.h b/include/constants/trainer_hill.h index 0e802bba8..371763faf 100644 --- a/include/constants/trainer_hill.h +++ b/include/constants/trainer_hill.h @@ -8,6 +8,12 @@ #define TRAINER_HILL_ROOF 5 #define TRAINER_HILL_ENTRANCE 6 +#define HILL_MODE_NORMAL 0 +#define HILL_MODE_VARIETY 1 +#define HILL_MODE_UNIQUE 2 +#define HILL_MODE_EXPERT 3 +#define NUM_TRAINER_HILL_MODES 4 + #define NUM_TRAINER_HILL_FLOORS 4 #define NUM_TRAINER_HILL_FLOORS_JP 2 @@ -30,20 +36,33 @@ #define TRAINER_HILL_FUNC_SET_GAME_SAVED 14 #define TRAINER_HILL_FUNC_CLEAR_GAME_SAVED 15 #define TRAINER_HILL_FUNC_GET_WON 16 -#define TRAINER_HILL_FUNC_SET_TAG 17 +#define TRAINER_HILL_FUNC_SET_MODE 17 #define TRAINER_HILL_TEXT_INTRO 2 #define TRAINER_HILL_TEXT_PLAYER_LOST 3 #define TRAINER_HILL_TEXT_PLAYER_WON 4 #define TRAINER_HILL_TEXT_AFTER 5 -#define TRAINER_HILL_TRAINERS_PER_FLOOR 2 -#define NUM_TRAINER_HILL_TRAINERS (NUM_TRAINER_HILL_FLOORS * TRAINER_HILL_TRAINERS_PER_FLOOR) -#define NUM_TRAINER_HILL_TRAINERS_JP (NUM_TRAINER_HILL_FLOORS_JP * TRAINER_HILL_TRAINERS_PER_FLOOR) +#define HILL_TRAINERS_PER_FLOOR 2 +#define NUM_TRAINER_HILL_TRAINERS (NUM_TRAINER_HILL_FLOORS * HILL_TRAINERS_PER_FLOOR) +#define NUM_TRAINER_HILL_TRAINERS_JP (NUM_TRAINER_HILL_FLOORS_JP * HILL_TRAINERS_PER_FLOOR) // Values returned by TrainerHillGetChallengeStatus #define TRAINER_HILL_PLAYER_STATUS_LOST 0 #define TRAINER_HILL_PLAYER_STATUS_ECARD_SCANNED 1 #define TRAINER_HILL_PLAYER_STATUS_NORMAL 2 +#define HILL_TRAINER_NAME_LENGTH 11 + +#define TRAINER_HILL_OTID 0x10000000 + +// The full map of each Trainer Hill floor is 16x21. +// The first 5x21 at the top is the entrance/exit area, +// and the remaining 16x16 is the randomized portion of +// the room where the trainers are. +#define HILL_FLOOR_WIDTH 16 +#define HILL_FLOOR_HEIGHT_MAIN 16 +#define HILL_FLOOR_HEIGHT_MARGIN 5 +#define HILL_FLOOR_HEIGHT (HILL_FLOOR_HEIGHT_MAIN + HILL_FLOOR_HEIGHT_MARGIN) + #endif diff --git a/include/ereader_helpers.h b/include/ereader_helpers.h index 8bf3dc43b..29386bcb2 100755 --- a/include/ereader_helpers.h +++ b/include/ereader_helpers.h @@ -35,7 +35,7 @@ struct EReaderTrainerHillTrainer { u8 trainerNum; struct TrainerHillTrainer trainer; - struct TrHillDisplay display; + struct TrainerHillFloorMap map; u32 checksum; }; // size=0x274 diff --git a/include/global.h b/include/global.h index 0122ecd5c..89f725176 100644 --- a/include/global.h +++ b/include/global.h @@ -14,6 +14,7 @@ #include "constants/maps.h" #include "constants/pokemon.h" #include "constants/easy_chat.h" +#include "constants/trainer_hill.h" // Prevent cross-jump optimization. #define BLOCK_CROSS_JUMP asm(""); @@ -279,8 +280,6 @@ struct BattleTowerPokemon u8 friendship; }; -#define NULL_BATTLE_TOWER_POKEMON { .nickname = __("$$$$$$$$$$$") } - struct EmeraldBattleTowerRecord { /*0x00*/ u8 lvlMode; // 0 = level 50, 1 = level 100 @@ -808,7 +807,7 @@ struct TrainerNameRecord u8 trainerName[PLAYER_NAME_LENGTH + 1]; }; -struct SaveTrainerHill +struct TrainerHillSave { /*0x3D64*/ u32 timer; /*0x3D68*/ u32 bestTime; @@ -820,7 +819,7 @@ struct SaveTrainerHill /*0x3D6E*/ u16 hasLost:1; /*0x3D6E*/ u16 maybeECardScanDuringChallenge:1; /*0x3D6E*/ u16 field_3D6E_0f:1; - /*0x3D6E*/ u16 tag:2; + /*0x3D6E*/ u16 mode:2; // HILL_MODE_* }; struct WonderNewsMetadata @@ -1003,7 +1002,7 @@ struct SaveBlock1 /*0x31F8*/ struct EnigmaBerry enigmaBerry; /*0x322C*/ struct MysteryGiftSave mysteryGift; /*0x3598*/ u8 unused_3598[0x180]; - /*0x3718*/ u32 trainerHillTimes[4]; + /*0x3718*/ u32 trainerHillTimes[NUM_TRAINER_HILL_MODES]; /*0x3728*/ struct RamScript ramScript; /*0x3B14*/ struct RecordMixingGift recordMixingGift; /*0x3B24*/ u8 seen2[NUM_DEX_FLAG_BYTES]; @@ -1011,7 +1010,7 @@ struct SaveBlock1 /*0x3B98*/ struct TrainerNameRecord trainerNameRecords[20]; /*0x3C88*/ u8 registeredTexts[UNION_ROOM_KB_ROW_COUNT][21]; /*0x3D5A*/ u8 unused_3D5A[10]; - /*0x3D64*/ struct SaveTrainerHill trainerHill; + /*0x3D64*/ struct TrainerHillSave trainerHill; /*0x3D70*/ struct WaldaPhrase waldaPhrase; // sizeof: 0x3D88 }; diff --git a/include/trainer_hill.h b/include/trainer_hill.h index 647ba9647..857cabeae 100644 --- a/include/trainer_hill.h +++ b/include/trainer_hill.h @@ -1,7 +1,7 @@ #ifndef GUARD_TRAINER_HILL_H #define GUARD_TRAINER_HILL_H -#define HILL_TRAINER_NAME_LENGTH 11 +#define DUMMY_HILL_MON { .nickname = __("$$$$$$$$$$$") } struct TrainerHillTrainer { @@ -15,44 +15,30 @@ struct TrainerHillTrainer struct BattleTowerPokemon mons[PARTY_SIZE]; }; -struct TrHillRoomTrainers +struct TrainerHillFloorMap { - u8 name[2][HILL_TRAINER_NAME_LENGTH]; - u8 facilityClass[2]; + u8 metatileData[HILL_FLOOR_WIDTH * HILL_FLOOR_HEIGHT_MAIN]; // Add NUM_METATILES_IN_PRIMARY to the values in this array to get metatile ids. + u16 collisionData[HILL_FLOOR_WIDTH]; // One bit for each tile in column-major order, so every array entry is one row. 1 = impassable, 0 = passable + u8 trainerCoords[HILL_TRAINERS_PER_FLOOR]; // Starting at (0,6). Format is 0bYYYYXXXX. + u8 trainerDirections; // DIR_* - 1, 4 bits per trainer + u8 trainerRanges; // 4 bits per trainer }; -struct TrHillDisplay -{ - // Metatile data. Add 0x200 to the values in this array to get metatiles. - // This data then overwrites the metatiles in the map starting at (0,5) - u8 metatileData[0x100]; - // Collision data. One bit for each tile in column-major order, - // so every array entry is one row. 1 = impassable, 0 = passable - u16 collisionData[16]; - // Trainer coordinates, starting at (0,6). Format is 0bYYYYXXXX. - u8 coords[2]; - // Trainer facing directions. Same as (DIR_* - 1). - // Effectively an array of nibbles, one for each trainer. - u8 direction; - // Trainer sight ranges. Effectively an array of nibbles, one for each trainer. - u8 range; -}; - -struct TrHillFloor +struct TrainerHillFloor { u8 trainerNum1; u8 trainerNum2; - struct TrainerHillTrainer trainers[2]; - struct TrHillDisplay display; + struct TrainerHillTrainer trainers[HILL_TRAINERS_PER_FLOOR]; + struct TrainerHillFloorMap map; }; -struct TrHillTag +struct TrainerHillChallenge { u8 numTrainers; u8 unused1; u8 numFloors; - u32 checksum; - struct TrHillFloor floors[0]; + u32 checksum; // A byte array sum of the floor data + struct TrainerHillFloor floors[0]; // Floor data is assumed to follow, so this will be intentionally read out of bounds }; extern u32 *gTrainerHillVBlankCounter; diff --git a/src/data/battle_frontier/trainer_hill.h b/src/data/battle_frontier/trainer_hill.h index 75785b258..413ec8e12 100644 --- a/src/data/battle_frontier/trainer_hill.h +++ b/src/data/battle_frontier/trainer_hill.h @@ -1,20 +1,23 @@ -#define TRAINER_HILL_OTID 0x10000000 - // NOTE: Each of these macros turn data into one byte. Therefore ranges for all arguments is 0-15 -// See struct TrHillDisplay for more info about each +// See struct TrainerHillFloorMap for more info about each #define COORDS_XY(x,y) ((y<<4)|(x)) #define TRAINER_DIRS(a, b) (((a-1)<<4)|(b-1)) #define TRAINER_RANGE(a, b) ((a<<4)|(b)) -static const struct TrHillTag sDataTagJPDefault = { +// WARNING: While not referenced directly, the floor data in this file is referenced by virtue +// of coming after its corresponding challenge (see SetUpDataStruct in trainer_hill.c). +// Do not insert data between a pair of 'sChallenge_Mode' and 'sFloors_Mode'. + +// Unused +static const struct TrainerHillChallenge sChallenge_JPDefault = { .numTrainers = NUM_TRAINER_HILL_TRAINERS_JP, .unused1 = 1, .numFloors = NUM_TRAINER_HILL_FLOORS_JP, .checksum = 0x0 }; - -static const struct TrHillFloor sDataTagJPDefault_Floors[] = { +// Unused +static const struct TrainerHillFloor sFloors_JPDefault[] = { [0] = { .trainerNum1 = 0, .trainerNum2 = 0, @@ -32,8 +35,6 @@ static const struct TrHillFloor sDataTagJPDefault_Floors[] = { .species = SPECIES_ZIGZAGOON, .heldItem = ITEM_SITRUS_BERRY, .moves = { MOVE_HEADBUTT, MOVE_PIN_MISSILE, MOVE_GROWL, MOVE_TAIL_WHIP }, - .level = 0, - .ppBonuses = 0x0, .hpEV = 110, .attackEV = 100, .defenseEV = 100, @@ -50,14 +51,12 @@ static const struct TrHillFloor sDataTagJPDefault_Floors[] = { .abilityNum = 0, .personality = 0x80, .nickname = __("ジグザグマ$$$$$$"), - .friendship = 255 + .friendship = MAX_FRIENDSHIP }, [1] = { .species = SPECIES_SHROOMISH, .heldItem = ITEM_PECHA_BERRY, .moves = { MOVE_MEGA_DRAIN, MOVE_LEECH_SEED, MOVE_POISON_POWDER, MOVE_GROWTH }, - .level = 0, - .ppBonuses = 0x0, .hpEV = 120, .attackEV = 0, .defenseEV = 120, @@ -74,14 +73,12 @@ static const struct TrHillFloor sDataTagJPDefault_Floors[] = { .abilityNum = 0, .personality = 0x0, .nickname = __("キノココ$$$$$$$"), - .friendship = 255 + .friendship = MAX_FRIENDSHIP }, [2] = { .species = SPECIES_SANDSHREW, .heldItem = ITEM_QUICK_CLAW, .moves = { MOVE_SCRATCH, MOVE_POISON_STING, MOVE_SAND_ATTACK, MOVE_SWIFT }, - .level = 0, - .ppBonuses = 0x0, .hpEV = 110, .attackEV = 100, .defenseEV = 100, @@ -98,11 +95,11 @@ static const struct TrHillFloor sDataTagJPDefault_Floors[] = { .abilityNum = 0, .personality = 0x80, .nickname = __("サンド$$$$$$$$"), - .friendship = 255 + .friendship = MAX_FRIENDSHIP }, - [3] = NULL_BATTLE_TOWER_POKEMON, - [4] = NULL_BATTLE_TOWER_POKEMON, - [5] = NULL_BATTLE_TOWER_POKEMON + [3] = DUMMY_HILL_MON, + [4] = DUMMY_HILL_MON, + [5] = DUMMY_HILL_MON } }, [1] = { @@ -114,15 +111,13 @@ static const struct TrHillFloor sDataTagJPDefault_Floors[] = { .speechLose = { EC_WORD_OH_QUES, EC_MOVE(EARTHQUAKE), EC_WORD_EXISTS, EC_WORD_OF, EC_WORD_WITHOUT, EC_WORD_EXCL }, .speechAfter = { EC_WORD_YOU_RE, EC_WORD_PROBABLY, EC_WORD_END, EC_WORD_UNTIL, EC_WORD_GOING, EC_WORD_ANYWHERE }, .mons = { - [0] = NULL_BATTLE_TOWER_POKEMON, - [1] = NULL_BATTLE_TOWER_POKEMON, - [2] = NULL_BATTLE_TOWER_POKEMON, + [0] = DUMMY_HILL_MON, + [1] = DUMMY_HILL_MON, + [2] = DUMMY_HILL_MON, [3] = { .species = SPECIES_WINGULL, .heldItem = ITEM_CHERI_BERRY, .moves = { MOVE_WATER_GUN, MOVE_WING_ATTACK, MOVE_GROWL, MOVE_SUPERSONIC }, - .level = 0, - .ppBonuses = 0x0, .hpEV = 110, .attackEV = 100, .defenseEV = 100, @@ -139,14 +134,12 @@ static const struct TrHillFloor sDataTagJPDefault_Floors[] = { .abilityNum = 0, .personality = 0x0, .nickname = __("キャモメ$$$$$$$"), - .friendship = 255 + .friendship = MAX_FRIENDSHIP }, [4] = { .species = SPECIES_NUMEL, .heldItem = ITEM_FOCUS_BAND, .moves = { MOVE_EMBER, MOVE_DIG, MOVE_TACKLE, MOVE_FOCUS_ENERGY }, - .level = 0, - .ppBonuses = 0x0, .hpEV = 110, .attackEV = 100, .defenseEV = 100, @@ -163,14 +156,12 @@ static const struct TrHillFloor sDataTagJPDefault_Floors[] = { .abilityNum = 0, .personality = 0x96, .nickname = __("ドンメル$$$$$$$"), - .friendship = 255 + .friendship = MAX_FRIENDSHIP }, [5] = { .species = SPECIES_SURSKIT, .heldItem = ITEM_PERSIM_BERRY, .moves = { MOVE_BUBBLE_BEAM, MOVE_MUD_SHOT, MOVE_QUICK_ATTACK, MOVE_AGILITY }, - .level = 0, - .ppBonuses = 0x0, .hpEV = 100, .attackEV = 100, .defenseEV = 100, @@ -187,12 +178,12 @@ static const struct TrHillFloor sDataTagJPDefault_Floors[] = { .abilityNum = 0, .personality = 0x0, .nickname = __("アメタマ$$$$$$$"), - .friendship = 255 + .friendship = MAX_FRIENDSHIP }, } }, }, - .display = { + .map = { .metatileData = { 0x31, 0x35, 0x35, 0x3b, 0x26, 0x26, 0x1b, 0x1c, 0x1d, 0x25, 0x39, 0x3a, 0x3b, 0x3b, 0x3b, 0x08, 0x31, 0x2b, 0x2b, 0x3b, 0x34, 0x34, 0x2b, 0x2b, 0x34, 0x33, 0x3f, 0x3f, 0x3f, 0x3f, 0x3b, 0x08, @@ -212,9 +203,9 @@ static const struct TrHillFloor sDataTagJPDefault_Floors[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, }, .collisionData = { 0x0381, 0x6fc1, 0x6341, 0x6041, 0x7f41, 0x4401, 0x5541, 0x5541, 0x11c1, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, - .coords = { COORDS_XY(8,2), COORDS_XY(8,7) }, - .direction = TRAINER_DIRS(DIR_SOUTH, DIR_NORTH), - .range = TRAINER_RANGE(2, 3) + .trainerCoords = { COORDS_XY(8,2), COORDS_XY(8,7) }, + .trainerDirections = TRAINER_DIRS(DIR_SOUTH, DIR_NORTH), + .trainerRanges = TRAINER_RANGE(2, 3) } }, [1] = { @@ -234,8 +225,6 @@ static const struct TrHillFloor sDataTagJPDefault_Floors[] = { .species = SPECIES_ELECTRIKE, .heldItem = ITEM_CHERI_BERRY, .moves = { MOVE_SPARK, MOVE_THUNDER_WAVE, MOVE_QUICK_ATTACK, MOVE_ROAR }, - .level = 0, - .ppBonuses = 0x0, .hpEV = 120, .attackEV = 120, .defenseEV = 0, @@ -252,14 +241,12 @@ static const struct TrHillFloor sDataTagJPDefault_Floors[] = { .abilityNum = 1, .personality = 0x0, .nickname = __("ラクライ$$$$$$$"), - .friendship = 255 + .friendship = MAX_FRIENDSHIP }, [1] = { .species = SPECIES_CORPHISH, .heldItem = ITEM_QUICK_CLAW, .moves = { MOVE_KNOCK_OFF, MOVE_CRABHAMMER, MOVE_TAUNT, MOVE_PROTECT }, - .level = 0, - .ppBonuses = 0x0, .hpEV = 100, .attackEV = 110, .defenseEV = 100, @@ -276,14 +263,12 @@ static const struct TrHillFloor sDataTagJPDefault_Floors[] = { .abilityNum = 1, .personality = 0x96, .nickname = __("ヘイガニ$$$$$$$"), - .friendship = 255 + .friendship = MAX_FRIENDSHIP }, [2] = { .species = SPECIES_BALTOY, .heldItem = ITEM_PERSIM_BERRY, .moves = { MOVE_PSYBEAM, MOVE_ROCK_TOMB, MOVE_MUD_SLAP, MOVE_HARDEN }, - .level = 0, - .ppBonuses = 0x0, .hpEV = 100, .attackEV = 100, .defenseEV = 100, @@ -300,11 +285,11 @@ static const struct TrHillFloor sDataTagJPDefault_Floors[] = { .abilityNum = 0, .personality = 0x96, .nickname = __("ヤジロン$$$$$$$"), - .friendship = 255 + .friendship = MAX_FRIENDSHIP }, - [3] = NULL_BATTLE_TOWER_POKEMON, - [4] = NULL_BATTLE_TOWER_POKEMON, - [5] = NULL_BATTLE_TOWER_POKEMON, + [3] = DUMMY_HILL_MON, + [4] = DUMMY_HILL_MON, + [5] = DUMMY_HILL_MON, } }, [1] = { @@ -316,15 +301,13 @@ static const struct TrHillFloor sDataTagJPDefault_Floors[] = { .speechLose = { EC_WORD_AWFUL, EC_WORD_GWAH, EC_WORD_HOPELESS, EC_WORD_CAN_T_WIN, EC_WORD_IS, EC_WORD_NONE }, .speechAfter = { EC_WORD_AWW, EC_EMPTY_WORD, EC_EMPTY_WORD, EC_WORD_ALMOST, EC_WORD_GOOD, EC_WORD_ANYWHERE }, .mons = { - [0] = NULL_BATTLE_TOWER_POKEMON, - [1] = NULL_BATTLE_TOWER_POKEMON, - [2] = NULL_BATTLE_TOWER_POKEMON, + [0] = DUMMY_HILL_MON, + [1] = DUMMY_HILL_MON, + [2] = DUMMY_HILL_MON, [3] = { .species = SPECIES_SPHEAL, .heldItem = ITEM_FOCUS_BAND, .moves = { MOVE_ICE_BALL, MOVE_BODY_SLAM, MOVE_WATER_GUN, MOVE_ENCORE }, - .level = 0, - .ppBonuses = 0x0, .hpEV = 100, .attackEV = 100, .defenseEV = 100, @@ -341,14 +324,12 @@ static const struct TrHillFloor sDataTagJPDefault_Floors[] = { .abilityNum = 0, .personality = 0x80, .nickname = __("タマザラシ$$$$$$"), - .friendship = 255 + .friendship = MAX_FRIENDSHIP }, [4] = { .species = SPECIES_SPOINK, .heldItem = ITEM_PERSIM_BERRY, .moves = { MOVE_PSYWAVE, MOVE_FUTURE_SIGHT, MOVE_CONFUSE_RAY, MOVE_MAGIC_COAT }, - .level = 0, - .ppBonuses = 0x0, .hpEV = 100, .attackEV = 0, .defenseEV = 100, @@ -365,14 +346,12 @@ static const struct TrHillFloor sDataTagJPDefault_Floors[] = { .abilityNum = 1, .personality = 0xf, .nickname = __("ãƒ�ãƒ�ブー$$$$$$$"), - .friendship = 255 + .friendship = MAX_FRIENDSHIP }, [5] = { .species = SPECIES_POOCHYENA, .heldItem = ITEM_PECHA_BERRY, .moves = { MOVE_BITE, MOVE_POISON_FANG, MOVE_SWAGGER, MOVE_SCARY_FACE }, - .level = 0, - .ppBonuses = 0x0, .hpEV = 70, .attackEV = 80, .defenseEV = 80, @@ -389,12 +368,12 @@ static const struct TrHillFloor sDataTagJPDefault_Floors[] = { .abilityNum = 0, .personality = 0x96, .nickname = __("ãƒ�ãƒ�エナ$$$$$$$"), - .friendship = 255 + .friendship = MAX_FRIENDSHIP }, } }, }, - .display = { + .map = { .metatileData = { 0x31, 0x3b, 0x35, 0x3b, 0x39, 0x26, 0x1b, 0x1c, 0x1d, 0x25, 0x39, 0x3a, 0x3b, 0x35, 0x3b, 0x08, 0x31, 0x3b, 0x2b, 0x3b, 0x3b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x3b, 0x3b, 0x3b, 0x2b, 0x3b, 0x08, @@ -414,14 +393,14 @@ static const struct TrHillFloor sDataTagJPDefault_Floors[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, }, .collisionData = { 0x0381, 0x27c5, 0x27c5, 0x27c5, 0x27c5, 0x27c5, 0x26c5, 0x2005, 0x3efd, 0x1, 0x6ff, 0x7ff, 0x7ff, 0xffff, 0xffff, 0xffff }, - .coords = { COORDS_XY(7,6), COORDS_XY(7,10) }, - .direction = TRAINER_DIRS(DIR_SOUTH, DIR_NORTH), - .range = TRAINER_RANGE(3, 3) + .trainerCoords = { COORDS_XY(7,6), COORDS_XY(7,10) }, + .trainerDirections = TRAINER_DIRS(DIR_SOUTH, DIR_NORTH), + .trainerRanges = TRAINER_RANGE(3, 3) } }, }; -static const struct TrHillTag sDataTagNormal = +static const struct TrainerHillChallenge sChallenge_Normal = { .numTrainers = NUM_TRAINER_HILL_TRAINERS, .unused1 = 2, @@ -429,7 +408,7 @@ static const struct TrHillTag sDataTagNormal = .checksum = 0x00051E05 }; -static const struct TrHillFloor sDataTagNormal_Floors[] = +static const struct TrainerHillFloor sFloors_Normal[] = { [0] = { @@ -453,8 +432,6 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .species = SPECIES_MISDREAVUS, .heldItem = ITEM_BRIGHT_POWDER, .moves = {MOVE_SHADOW_BALL, MOVE_PSYCHIC, MOVE_THUNDERBOLT, MOVE_CONFUSE_RAY}, - .level = 0, - .ppBonuses = 0, .attackEV = 155, .speedEV = 255, .spAttackEV = 100, @@ -468,15 +445,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0x0, .nickname = _("MISDREAVUS"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_SOLROCK, .heldItem = ITEM_FOCUS_BAND, .moves = {MOVE_PSYCHIC, MOVE_FLAMETHROWER, MOVE_ROCK_SLIDE, MOVE_CALM_MIND}, - .level = 0, - .ppBonuses = 0, .hpEV = 200, .defenseEV = 100, .spAttackEV = 110, @@ -491,15 +466,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0xF, .nickname = _("SOLROCK"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [2] = { .species = SPECIES_CLAYDOL, .heldItem = ITEM_SHELL_BELL, .moves = {MOVE_EARTHQUAKE, MOVE_PSYCHIC, MOVE_SHADOW_BALL, MOVE_ICE_BEAM}, - .level = 0, - .ppBonuses = 0, .hpEV = 255, .defenseEV = 135, .spDefenseEV = 120, @@ -513,15 +486,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0xC, .nickname = _("CLAYDOL"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_WEEZING, .heldItem = ITEM_SALAC_BERRY, .moves = {MOVE_SLUDGE_BOMB, MOVE_SHADOW_BALL, MOVE_FRUSTRATION, MOVE_DESTINY_BOND}, - .level = 0, - .ppBonuses = 0, .hpEV = 110, .attackEV = 200, .spDefenseEV = 200, @@ -542,8 +513,6 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .species = SPECIES_LUNATONE, .heldItem = ITEM_FOCUS_BAND, .moves = {MOVE_PSYCHIC, MOVE_ICE_BEAM, MOVE_ROCK_SLIDE, MOVE_CALM_MIND}, - .level = 0, - .ppBonuses = 0, .hpEV = 200, .defenseEV = 100, .spAttackEV = 110, @@ -558,15 +527,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0xF, .nickname = _("LUNATONE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [5] = { .species = SPECIES_FLYGON, .heldItem = ITEM_CHOICE_BAND, .moves = {MOVE_EARTHQUAKE, MOVE_DRAGON_CLAW, MOVE_CRUNCH, MOVE_FLAMETHROWER}, - .level = 0, - .ppBonuses = 0, .attackEV = 155, .speedEV = 255, .spAttackEV = 100, @@ -580,7 +547,7 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0x83, .nickname = _("FLYGON"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, }, }, @@ -600,8 +567,6 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .species = SPECIES_SEALEO, .heldItem = ITEM_NEVER_MELT_ICE, .moves = {MOVE_BLIZZARD, MOVE_ICE_BALL, MOVE_ENCORE, MOVE_HAIL}, - .level = 0, - .ppBonuses = 0, .hpEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -614,15 +579,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0xF, .nickname = _("SEALEO"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_AMPHAROS, .heldItem = ITEM_MAGNET, .moves = {MOVE_THUNDER, MOVE_THUNDER_WAVE, MOVE_COTTON_SPORE, MOVE_LIGHT_SCREEN}, - .level = 0, - .ppBonuses = 0, .speedEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -635,15 +598,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0xF, .nickname = _("AMPHAROS"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [2] = { .species = SPECIES_MACHOKE, .heldItem = ITEM_BLACK_BELT, .moves = {MOVE_DYNAMIC_PUNCH, MOVE_MUD_SLAP, MOVE_COUNTER, MOVE_SCARY_FACE}, - .level = 0, - .ppBonuses = 0, .hpEV = 255, .attackEV = 255, .otId = TRAINER_HILL_OTID, @@ -656,15 +617,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0x4E, .nickname = _("MACHOKE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_FLAREON, .heldItem = ITEM_CHARCOAL, .moves = {MOVE_FIRE_BLAST, MOVE_BITE, MOVE_QUICK_ATTACK, MOVE_SAND_ATTACK}, - .level = 0, - .ppBonuses = 0, .speedEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -677,15 +636,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0x28, .nickname = _("FLAREON"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [4] = { .species = SPECIES_MAGNETON, .heldItem = ITEM_MAGNET, .moves = {MOVE_ZAP_CANNON, MOVE_THUNDER_WAVE, MOVE_SCREECH, MOVE_METAL_SOUND}, - .level = 0, - .ppBonuses = 0, .speedEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -698,15 +655,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0x0, .nickname = _("MAGNETON"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [5] = { .species = SPECIES_PINSIR, .heldItem = ITEM_QUICK_CLAW, .moves = {MOVE_GUILLOTINE, MOVE_BRICK_BREAK, MOVE_SWAGGER, MOVE_FAINT_ATTACK}, - .level = 0, - .ppBonuses = 0, .hpEV = 200, .defenseEV = 155, .spDefenseEV = 155, @@ -720,12 +675,12 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0x85, .nickname = _("PINSIR"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, }, }, }, - .display = { + .map = { .metatileData = { 0x31, 0x3B, 0x35, 0x35, 0x26, 0x26, 0x1B, 0x1C, 0x1D, 0x25, 0x26, 0x3A, 0x3B, 0x35, 0x3B, 0x08, 0x31, 0x3B, 0x2C, 0x2C, 0x2C, 0x2B, 0x24, 0x24, 0x24, 0x24, 0x2C, 0x3B, 0x3B, 0x2C, 0x3B, 0x08, @@ -745,10 +700,10 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, }, .collisionData = {0x0381, 0x3FE5, 0x0401, 0xBDED, 0x8425, 0xDFBD, 0x0221, 0x7E7F, 0x0941, 0x7F7D, 0x0911, 0x7FF7, 0x4101, 0x79F9, 0x0803, 0xFFFF}, - .coords = {COORDS_XY(11,1), COORDS_XY(13,2)}, - .direction = TRAINER_DIRS(DIR_WEST, DIR_NORTH), - .range = TRAINER_RANGE(2, 1), - } + .trainerCoords = {COORDS_XY(11,1), COORDS_XY(13,2)}, + .trainerDirections = TRAINER_DIRS(DIR_WEST, DIR_NORTH), + .trainerRanges = TRAINER_RANGE(2, 1), + } }, [1] = { @@ -772,8 +727,6 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .species = SPECIES_MEDITITE, .heldItem = ITEM_FOCUS_BAND, .moves = {MOVE_FOCUS_PUNCH, MOVE_PROTECT, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .attackEV = 252, .spDefenseEV = 6, @@ -787,15 +740,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0x80, .nickname = _("MEDITITE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_HERACROSS, .heldItem = ITEM_FOCUS_BAND, .moves = {MOVE_FOCUS_PUNCH, MOVE_PROTECT, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .attackEV = 252, .spDefenseEV = 6, @@ -809,15 +760,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 1, .personality = 0x80, .nickname = _("HERACROSS"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [2] = { .species = SPECIES_HITMONTOP, .heldItem = ITEM_SHELL_BELL, .moves = {MOVE_FOCUS_PUNCH, MOVE_PROTECT, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .attackEV = 252, .spDefenseEV = 6, @@ -831,15 +780,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0x3, .nickname = _("HITMONTOP"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_MACHOP, .heldItem = ITEM_SALAC_BERRY, .moves = {MOVE_FOCUS_PUNCH, MOVE_REVENGE, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .attackEV = 252, .spDefenseEV = 6, @@ -853,15 +800,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0x4E, .nickname = _("MACHOP"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [4] = { .species = SPECIES_PINSIR, .heldItem = ITEM_SALAC_BERRY, .moves = {MOVE_FOCUS_PUNCH, MOVE_REVENGE, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .attackEV = 252, .spDefenseEV = 6, @@ -875,15 +820,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0x80, .nickname = _("PINSIR"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [5] = { .species = SPECIES_HITMONCHAN, .heldItem = ITEM_FOCUS_BAND, .moves = {MOVE_FOCUS_PUNCH, MOVE_REVENGE, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .attackEV = 252, .spDefenseEV = 6, @@ -897,7 +840,7 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0x3, .nickname = _("HITMONCHAN"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, }, }, @@ -917,8 +860,6 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .species = SPECIES_VULPIX, .heldItem = ITEM_LUM_BERRY, .moves = {MOVE_WILL_O_WISP, MOVE_CONFUSE_RAY, MOVE_TAIL_WHIP, MOVE_OVERHEAT}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .defenseEV = 252, .spDefenseEV = 6, @@ -932,15 +873,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0xF, .nickname = _("VULPIX"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_MINUN, .heldItem = ITEM_FOCUS_BAND, .moves = {MOVE_THUNDER_WAVE, MOVE_CHARM, MOVE_ENCORE, MOVE_SPARK}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .defenseEV = 252, .spAttackEV = 6, @@ -954,15 +893,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0x8C, .nickname = _("MINUN"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [2] = { .species = SPECIES_ROSELIA, .heldItem = ITEM_LUM_BERRY, .moves = {MOVE_TOXIC, MOVE_LEECH_SEED, MOVE_SWEET_SCENT, MOVE_GIGA_DRAIN}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .defenseEV = 252, .spAttackEV = 6, @@ -976,15 +913,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 1, .personality = 0xF, .nickname = _("ROSELIA"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_MR_MIME, .heldItem = ITEM_SITRUS_BERRY, .moves = {MOVE_SAFEGUARD, MOVE_REFLECT, MOVE_LIGHT_SCREEN, MOVE_PSYCHIC}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .defenseEV = 252, .spDefenseEV = 6, @@ -998,15 +933,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0x82, .nickname = _("MR. MIME"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [4] = { .species = SPECIES_PLUSLE, .heldItem = ITEM_SITRUS_BERRY, .moves = {MOVE_RAIN_DANCE, MOVE_LIGHT_SCREEN, MOVE_HELPING_HAND, MOVE_THUNDER}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .defenseEV = 252, .spDefenseEV = 6, @@ -1020,15 +953,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0x5, .nickname = _("PLUSLE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [5] = { .species = SPECIES_TOGEPI, .heldItem = ITEM_SITRUS_BERRY, .moves = {MOVE_LIGHT_SCREEN, MOVE_REFLECT, MOVE_FOLLOW_ME, MOVE_METRONOME}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .defenseEV = 252, .spDefenseEV = 6, @@ -1042,12 +973,12 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 1, .personality = 0x37, .nickname = _("TOGEPI"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, }, }, }, - .display = { + .map = { .metatileData = { 0xD1, 0xD5, 0xD5, 0xD5, 0xD9, 0xD9, 0x1B, 0x1C, 0x1D, 0xC5, 0xC6, 0xCE, 0xD5, 0xDB, 0xD5, 0x08, 0xD1, 0xCB, 0xC4, 0xC4, 0xDB, 0xDB, 0xC4, 0xC4, 0xC4, 0xCC, 0xCC, 0xCC, 0xCB, 0xDB, 0xCB, 0x08, @@ -1067,10 +998,10 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, }, .collisionData = {0x0381, 0x73FB, 0x400B, 0x400B, 0x51EB, 0x538B, 0x51BB, 0x518B, 0x51EB, 0x518B, 0x51BB, 0x5003, 0x501F, 0x101F, 0x101F, 0xFFFF}, - .coords = {COORDS_XY(4,11), COORDS_XY(9,14)}, - .direction = TRAINER_DIRS(DIR_SOUTH, DIR_EAST), - .range = TRAINER_RANGE(3, 5), - } + .trainerCoords = {COORDS_XY(4,11), COORDS_XY(9,14)}, + .trainerDirections = TRAINER_DIRS(DIR_SOUTH, DIR_EAST), + .trainerRanges = TRAINER_RANGE(3, 5), + } }, [2] = { @@ -1094,8 +1025,6 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .species = SPECIES_VAPOREON, .heldItem = ITEM_FOCUS_BAND, .moves = {MOVE_HAZE, MOVE_HELPING_HAND, MOVE_TICKLE, MOVE_WATER_PULSE}, - .level = 0, - .ppBonuses = 0, .hpEV = 250, .defenseEV = 130, .spDefenseEV = 130, @@ -1116,8 +1045,6 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .species = SPECIES_DODRIO, .heldItem = ITEM_KINGS_ROCK, .moves = {MOVE_HAZE, MOVE_TRI_ATTACK, MOVE_TAUNT, MOVE_TORMENT}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .speedEV = 252, .spDefenseEV = 6, @@ -1138,8 +1065,6 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .species = SPECIES_OMASTAR, .heldItem = ITEM_QUICK_CLAW, .moves = {MOVE_HAZE, MOVE_HYDRO_PUMP, MOVE_TICKLE, MOVE_ATTRACT}, - .level = 0, - .ppBonuses = 0, .hpEV = 250, .defenseEV = 130, .spDefenseEV = 130, @@ -1153,15 +1078,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0x14, .nickname = _("OMASTAR"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_LICKITUNG, .heldItem = ITEM_CHESTO_BERRY, .moves = {MOVE_BELLY_DRUM, MOVE_REST, MOVE_MUD_SLAP, MOVE_SWAGGER}, - .level = 0, - .ppBonuses = 0, .hpEV = 250, .defenseEV = 130, .spDefenseEV = 130, @@ -1175,15 +1098,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0x8, .nickname = _("LICKITUNG"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [4] = { .species = SPECIES_SLOWBRO, .heldItem = ITEM_LEFTOVERS, .moves = {MOVE_BELLY_DRUM, MOVE_MUD_SLAP, MOVE_SWAGGER, MOVE_AMNESIA}, - .level = 0, - .ppBonuses = 0, .hpEV = 250, .defenseEV = 130, .spDefenseEV = 130, @@ -1204,8 +1125,6 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .species = SPECIES_LINOONE, .heldItem = ITEM_LUM_BERRY, .moves = {MOVE_BELLY_DRUM, MOVE_REST, MOVE_MUD_SLAP, MOVE_SWAGGER}, - .level = 0, - .ppBonuses = 0, .hpEV = 250, .defenseEV = 130, .spDefenseEV = 130, @@ -1219,7 +1138,7 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0x8, .nickname = _("LINOONE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, }, }, @@ -1239,8 +1158,6 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .species = SPECIES_SKITTY, .heldItem = ITEM_FOCUS_BAND, .moves = {MOVE_PSYCH_UP, MOVE_DOUBLE_EDGE, MOVE_SHADOW_BALL, MOVE_IRON_TAIL}, - .level = 0, - .ppBonuses = 0, .attackEV = 252, .speedEV = 252, .otId = TRAINER_HILL_OTID, @@ -1253,15 +1170,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0xCB, .nickname = _("SKITTY"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_MEDICHAM, .heldItem = ITEM_QUICK_CLAW, .moves = {MOVE_PSYCH_UP, MOVE_HI_JUMP_KICK, MOVE_MEGA_KICK, MOVE_ROCK_SLIDE}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .attackEV = 6, .speedEV = 252, @@ -1282,8 +1197,6 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .species = SPECIES_STANTLER, .heldItem = ITEM_SHELL_BELL, .moves = {MOVE_PSYCH_UP, MOVE_RETURN, MOVE_EARTHQUAKE, MOVE_SHADOW_BALL}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .attackEV = 252, .speedEV = 6, @@ -1304,8 +1217,6 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .species = SPECIES_NIDOQUEEN, .heldItem = ITEM_SALAC_BERRY, .moves = {MOVE_SUPERPOWER, MOVE_BITE, MOVE_CHARM, MOVE_FLATTER}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .attackEV = 252, .spDefenseEV = 6, @@ -1326,8 +1237,6 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .species = SPECIES_NINETALES, .heldItem = ITEM_SALAC_BERRY, .moves = {MOVE_OVERHEAT, MOVE_QUICK_ATTACK, MOVE_SPITE, MOVE_TAIL_WHIP}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .speedEV = 252, .spAttackEV = 252, @@ -1341,15 +1250,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0xD7, .nickname = _("NINETALES"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [5] = { .species = SPECIES_CHARIZARD, .heldItem = ITEM_SALAC_BERRY, .moves = {MOVE_OVERHEAT, MOVE_BEAT_UP, MOVE_SCARY_FACE, MOVE_GROWL}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .speedEV = 252, .spAttackEV = 252, @@ -1363,12 +1270,12 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0x28, .nickname = _("CHARIZARD"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, }, }, }, - .display = { + .map = { .metatileData = { 0x31, 0x35, 0x35, 0x35, 0x26, 0x26, 0x13, 0x14, 0x15, 0x38, 0x26, 0x2E, 0x35, 0x35, 0x3B, 0x08, 0x69, 0x63, 0x64, 0x64, 0x64, 0x64, 0x71, 0x71, 0x71, 0x72, 0x64, 0x64, 0x64, 0x63, 0x73, 0x08, @@ -1388,10 +1295,10 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = 0x69, 0x42, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x42, 0x73, 0x08, }, .collisionData = {0x0381, 0x7C3D, 0x4005, 0x4005, 0x4005, 0x4045, 0x4005, 0x4805, 0x4005, 0x4045, 0x4005, 0x4205, 0x4005, 0x4045, 0x1, 0x1}, - .coords = {COORDS_XY(5,2), COORDS_XY(9,2)}, - .direction = TRAINER_DIRS(DIR_WEST, DIR_EAST), - .range = TRAINER_RANGE(3, 3), - } + .trainerCoords = {COORDS_XY(5,2), COORDS_XY(9,2)}, + .trainerDirections = TRAINER_DIRS(DIR_WEST, DIR_EAST), + .trainerRanges = TRAINER_RANGE(3, 3), + } }, [3] = { @@ -1415,8 +1322,6 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .species = SPECIES_ALAKAZAM, .heldItem = ITEM_PETAYA_BERRY, .moves = {MOVE_SKILL_SWAP, MOVE_FIRE_PUNCH, MOVE_ICE_PUNCH, MOVE_REFLECT}, - .level = 0, - .ppBonuses = 0, .speedEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -1429,15 +1334,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0x41, .nickname = _("ALAKAZAM"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_BLISSEY, .heldItem = ITEM_LEFTOVERS, .moves = {MOVE_SKILL_SWAP, MOVE_EGG_BOMB, MOVE_THUNDERBOLT, MOVE_SING}, - .level = 0, - .ppBonuses = 0, .defenseEV = 255, .spAttackEV = 155, .spDefenseEV = 100, @@ -1451,15 +1354,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 1, .personality = 0xF, .nickname = _("BLISSEY"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [2] = { .species = SPECIES_GRUMPIG, .heldItem = ITEM_TWISTED_SPOON, .moves = {MOVE_SKILL_SWAP, MOVE_PSYCHIC, MOVE_CONFUSE_RAY, MOVE_REST}, - .level = 0, - .ppBonuses = 0, .hpEV = 110, .defenseEV = 200, .spAttackEV = 200, @@ -1473,15 +1374,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0x8C, .nickname = _("GRUMPIG"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_GARDEVOIR, .heldItem = ITEM_SALAC_BERRY, .moves = {MOVE_SKILL_SWAP, MOVE_DREAM_EATER, MOVE_HYPNOSIS, MOVE_PROTECT}, - .level = 0, - .ppBonuses = 0, .speedEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -1494,15 +1393,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 1, .personality = 0xF, .nickname = _("GARDEVOIR"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [4] = { .species = SPECIES_VENOMOTH, .heldItem = ITEM_BRIGHT_POWDER, .moves = {MOVE_SKILL_SWAP, MOVE_SIGNAL_BEAM, MOVE_SLEEP_POWDER, MOVE_TOXIC}, - .level = 0, - .ppBonuses = 0, .attackEV = 255, .speedEV = 255, .otId = TRAINER_HILL_OTID, @@ -1515,15 +1412,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0x80, .nickname = _("VENOMOTH"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [5] = { .species = SPECIES_ESPEON, .heldItem = ITEM_LUM_BERRY, .moves = {MOVE_SKILL_SWAP, MOVE_PSYBEAM, MOVE_SWIFT, MOVE_ATTRACT}, - .level = 0, - .ppBonuses = 0, .speedEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -1536,7 +1431,7 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0xF, .nickname = _("ESPEON"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, }, }, @@ -1556,8 +1451,6 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .species = SPECIES_WEEZING, .heldItem = ITEM_POISON_BARB, .moves = {MOVE_TOXIC, MOVE_SLUDGE_BOMB, MOVE_SMOKESCREEN, MOVE_HAZE}, - .level = 0, - .ppBonuses = 0, .hpEV = 255, .attackEV = 255, .otId = TRAINER_HILL_OTID, @@ -1570,15 +1463,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0x3, .nickname = _("WEEZING"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_GLOOM, .heldItem = ITEM_MIRACLE_SEED, .moves = {MOVE_PETAL_DANCE, MOVE_SYNTHESIS, MOVE_SUNNY_DAY, MOVE_SOLAR_BEAM}, - .level = 0, - .ppBonuses = 0, .speedEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -1591,15 +1482,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0x8C, .nickname = _("GLOOM"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [2] = { .species = SPECIES_MUK, .heldItem = ITEM_BRIGHT_POWDER, .moves = {MOVE_SCREECH, MOVE_DISABLE, MOVE_SLUDGE_BOMB, MOVE_ACID_ARMOR}, - .level = 0, - .ppBonuses = 0, .hpEV = 255, .attackEV = 255, .otId = TRAINER_HILL_OTID, @@ -1612,15 +1501,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0x3, .nickname = _("MUK"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_TROPIUS, .heldItem = ITEM_WHITE_HERB, .moves = {MOVE_SUNNY_DAY, MOVE_SOLAR_BEAM, MOVE_SWEET_SCENT, MOVE_AERIAL_ACE}, - .level = 0, - .ppBonuses = 0, .attackEV = 120, .speedEV = 255, .spAttackEV = 135, @@ -1634,15 +1521,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0x83, .nickname = _("TROPIUS"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [4] = { .species = SPECIES_BELLOSSOM, .heldItem = ITEM_MENTAL_HERB, .moves = {MOVE_SWEET_SCENT, MOVE_PETAL_DANCE, MOVE_STUN_SPORE, MOVE_SLUDGE_BOMB}, - .level = 0, - .ppBonuses = 0, .hpEV = 255, .speedEV = 255, .otId = TRAINER_HILL_OTID, @@ -1655,15 +1540,13 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0x6, .nickname = _("BELLOSSOM"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [5] = { .species = SPECIES_MEGANIUM, .heldItem = ITEM_MIRACLE_SEED, .moves = {MOVE_RAZOR_LEAF, MOVE_BODY_SLAM, MOVE_LEECH_SEED, MOVE_SYNTHESIS}, - .level = 0, - .ppBonuses = 0, .attackEV = 200, .speedEV = 110, .spAttackEV = 200, @@ -1677,12 +1560,12 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = .abilityNum = 0, .personality = 0x1F, .nickname = _("MEGANIUM"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, }, }, }, - .display = { + .map = { .metatileData = { 0x31, 0x3B, 0x3B, 0x3B, 0x39, 0x26, 0x1B, 0x1C, 0x1D, 0x25, 0x39, 0x3A, 0x3B, 0x3B, 0x3B, 0x08, 0x1F, 0x17, 0x17, 0x17, 0x17, 0x2B, 0x24, 0x24, 0x24, 0x2B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x08, @@ -1702,14 +1585,14 @@ static const struct TrHillFloor sDataTagNormal_Floors[] = 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, }, .collisionData = {0x0381, 0x7C1, 0x8441, 0x8477, 0x8441, 0xA441, 0x0401, 0x1, 0x8401, 0x8465, 0x0445, 0x1441, 0x8449, 0x8449, 0x87C1, 0xFFFF}, - .coords = {COORDS_XY(7,4), COORDS_XY(7,10)}, - .direction = TRAINER_DIRS(DIR_SOUTH, DIR_NORTH), - .range = TRAINER_RANGE(3, 3), - } + .trainerCoords = {COORDS_XY(7,4), COORDS_XY(7,10)}, + .trainerDirections = TRAINER_DIRS(DIR_SOUTH, DIR_NORTH), + .trainerRanges = TRAINER_RANGE(3, 3), + } }, }; -static const struct TrHillTag sDataTagVariety = +static const struct TrainerHillChallenge sChallenge_Variety = { .numTrainers = NUM_TRAINER_HILL_TRAINERS, .unused1 = 1, @@ -1717,7 +1600,7 @@ static const struct TrHillTag sDataTagVariety = .checksum = 0x00054C15 }; -static const struct TrHillFloor sDataTagVariety_Floors[] = { +static const struct TrainerHillFloor sFloors_Variety[] = { [0] = { .trainerNum1 = 41, @@ -1740,8 +1623,6 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .species = SPECIES_DELIBIRD, .heldItem = ITEM_SITRUS_BERRY, .moves = {MOVE_PRESENT, MOVE_SPLASH, MOVE_HAIL, MOVE_PROTECT}, - .level = 0, - .ppBonuses = 0, .attackEV = 255, .speedEV = 255, .otId = TRAINER_HILL_OTID, @@ -1754,15 +1635,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 1, .personality = 0x8A, .nickname = _("DELIBIRD"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_CLEFAIRY, .heldItem = ITEM_SITRUS_BERRY, .moves = {MOVE_PRESENT, MOVE_COSMIC_POWER, MOVE_LIGHT_SCREEN, MOVE_MOONLIGHT}, - .level = 0, - .ppBonuses = 0, .attackEV = 255, .speedEV = 255, .otId = TRAINER_HILL_OTID, @@ -1775,15 +1654,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0xD, .nickname = _("CLEFAIRY"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [2] = { .species = SPECIES_PIKACHU, .heldItem = ITEM_SITRUS_BERRY, .moves = {MOVE_PRESENT, MOVE_GROWL, MOVE_TAIL_WHIP, MOVE_AGILITY}, - .level = 0, - .ppBonuses = 0, .attackEV = 255, .speedEV = 255, .otId = TRAINER_HILL_OTID, @@ -1796,15 +1673,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0xD, .nickname = _("PIKACHU"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_MARILL, .heldItem = ITEM_SITRUS_BERRY, .moves = {MOVE_PRESENT, MOVE_DEFENSE_CURL, MOVE_TAIL_WHIP, MOVE_ENDURE}, - .level = 0, - .ppBonuses = 0, .attackEV = 255, .speedEV = 255, .otId = TRAINER_HILL_OTID, @@ -1817,15 +1692,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 1, .personality = 0x8A, .nickname = _("MARILL"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [4] = { .species = SPECIES_JIGGLYPUFF, .heldItem = ITEM_SITRUS_BERRY, .moves = {MOVE_PRESENT, MOVE_SING, MOVE_DISABLE, MOVE_REST}, - .level = 0, - .ppBonuses = 0, .attackEV = 255, .speedEV = 255, .otId = TRAINER_HILL_OTID, @@ -1838,15 +1711,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0xD, .nickname = _("JIGGLYPUFF"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [5] = { .species = SPECIES_TOGETIC, .heldItem = ITEM_SITRUS_BERRY, .moves = {MOVE_PRESENT, MOVE_CHARM, MOVE_SWEET_KISS, MOVE_WISH}, - .level = 0, - .ppBonuses = 0, .attackEV = 255, .speedEV = 255, .otId = TRAINER_HILL_OTID, @@ -1859,7 +1730,7 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 1, .personality = 0x26, .nickname = _("TOGETIC"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, }, }, @@ -1879,8 +1750,6 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .species = SPECIES_WIGGLYTUFF, .heldItem = ITEM_SILK_SCARF, .moves = {MOVE_ROLLOUT, MOVE_DEFENSE_CURL, MOVE_SING, MOVE_DREAM_EATER}, - .level = 0, - .ppBonuses = 0, .hpEV = 255, .speedEV = 255, .otId = TRAINER_HILL_OTID, @@ -1893,15 +1762,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0xC1, .nickname = _("WIGGLYTUFF"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_SABLEYE, .heldItem = ITEM_SILK_SCARF, .moves = {MOVE_ASTONISH, MOVE_FAINT_ATTACK, MOVE_DETECT, MOVE_CONFUSE_RAY}, - .level = 0, - .ppBonuses = 0, .hpEV = 255, .speedEV = 255, .otId = TRAINER_HILL_OTID, @@ -1914,15 +1781,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0x87, .nickname = _("SABLEYE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [2] = { .species = SPECIES_GRUMPIG, .heldItem = ITEM_SILK_SCARF, .moves = {MOVE_PSYBEAM, MOVE_MAGIC_COAT, MOVE_BOUNCE, MOVE_FUTURE_SIGHT}, - .level = 0, - .ppBonuses = 0, .hpEV = 255, .speedEV = 255, .otId = TRAINER_HILL_OTID, @@ -1935,15 +1800,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0xA, .nickname = _("GRUMPIG"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_CORSOLA, .heldItem = ITEM_SILK_SCARF, .moves = {MOVE_BUBBLE_BEAM, MOVE_ROCK_BLAST, MOVE_REFLECT, MOVE_LIGHT_SCREEN}, - .level = 0, - .ppBonuses = 0, .hpEV = 255, .speedEV = 255, .otId = TRAINER_HILL_OTID, @@ -1956,15 +1819,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0x12, .nickname = _("CORSOLA"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [4] = { .species = SPECIES_CLAMPERL, .heldItem = ITEM_SILK_SCARF, .moves = {MOVE_WHIRLPOOL, MOVE_IRON_DEFENSE, MOVE_ENDURE, MOVE_CONFUSE_RAY}, - .level = 0, - .ppBonuses = 0, .hpEV = 255, .speedEV = 255, .otId = TRAINER_HILL_OTID, @@ -1977,15 +1838,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0xA, .nickname = _("CLAMPERL"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [5] = { .species = SPECIES_STARMIE, .heldItem = ITEM_SILK_SCARF, .moves = {MOVE_DIVE, MOVE_ICY_WIND, MOVE_SWIFT, MOVE_SKILL_SWAP}, - .level = 0, - .ppBonuses = 0, .hpEV = 255, .speedEV = 255, .otId = TRAINER_HILL_OTID, @@ -1998,12 +1857,12 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0xA, .nickname = _("STARMIE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, }, }, }, - .display = { + .map = { .metatileData = { 0x31, 0x3B, 0x3B, 0x3B, 0x39, 0x39, 0x13, 0x14, 0x15, 0x38, 0x39, 0x3A, 0x3B, 0x3B, 0x3B, 0x08, 0x40, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x40, 0x41, 0x41, 0x08, @@ -2023,9 +1882,9 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { 0x40, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x08, }, .collisionData = {0x0381, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1}, - .coords = {COORDS_XY(5,8), COORDS_XY(9,8)}, - .direction = TRAINER_DIRS(DIR_WEST, DIR_EAST), - .range = TRAINER_RANGE(3, 3), + .trainerCoords = {COORDS_XY(5,8), COORDS_XY(9,8)}, + .trainerDirections = TRAINER_DIRS(DIR_WEST, DIR_EAST), + .trainerRanges = TRAINER_RANGE(3, 3), } }, [1] = @@ -2050,8 +1909,6 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .species = SPECIES_JIGGLYPUFF, .heldItem = ITEM_BRIGHT_POWDER, .moves = {MOVE_SING, MOVE_HYPER_VOICE, MOVE_ATTRACT, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 85, .attackEV = 85, .defenseEV = 85, @@ -2068,15 +1925,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0x0, .nickname = _("JIGGLYPUFF"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_JYNX, .heldItem = ITEM_BRIGHT_POWDER, .moves = {MOVE_PERISH_SONG, MOVE_FAKE_TEARS, MOVE_ATTRACT, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 85, .attackEV = 85, .defenseEV = 85, @@ -2093,15 +1948,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0x0, .nickname = _("JYNX"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [2] = { .species = SPECIES_EXPLOUD, .heldItem = ITEM_BRIGHT_POWDER, .moves = {MOVE_HOWL, MOVE_HYPER_VOICE, MOVE_ATTRACT, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 85, .attackEV = 85, .defenseEV = 85, @@ -2118,15 +1971,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0x96, .nickname = _("EXPLOUD"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_ABSOL, .heldItem = ITEM_BRIGHT_POWDER, .moves = {MOVE_SWORDS_DANCE, MOVE_SLASH, MOVE_ATTRACT, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 85, .attackEV = 85, .defenseEV = 85, @@ -2143,15 +1994,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0x96, .nickname = _("ABSOL"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [4] = { .species = SPECIES_PIDGEOTTO, .heldItem = ITEM_BRIGHT_POWDER, .moves = {MOVE_FEATHER_DANCE, MOVE_AERIAL_ACE, MOVE_ATTRACT, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 85, .attackEV = 85, .defenseEV = 85, @@ -2168,15 +2017,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0x96, .nickname = _("PIDGEOTTO"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [5] = { .species = SPECIES_ALTARIA, .heldItem = ITEM_BRIGHT_POWDER, .moves = {MOVE_DRAGON_DANCE, MOVE_AERIAL_ACE, MOVE_ATTRACT, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 85, .attackEV = 85, .defenseEV = 85, @@ -2193,7 +2040,7 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0x0, .nickname = _("ALTARIA"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, }, }, @@ -2213,8 +2060,6 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .species = SPECIES_CHIMECHO, .heldItem = ITEM_FOCUS_BAND, .moves = {MOVE_UPROAR, MOVE_ATTRACT, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .attackEV = 252, .speedEV = 252, @@ -2228,15 +2073,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0xD, .nickname = _("CHIMECHO"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_WHISMUR, .heldItem = ITEM_FOCUS_BAND, .moves = {MOVE_UPROAR, MOVE_ATTRACT, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .attackEV = 252, .speedEV = 252, @@ -2250,15 +2093,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0xD, .nickname = _("WHISMUR"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [2] = { .species = SPECIES_YANMA, .heldItem = ITEM_FOCUS_BAND, .moves = {MOVE_UPROAR, MOVE_ATTRACT, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .attackEV = 252, .speedEV = 252, @@ -2272,15 +2113,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0x8A, .nickname = _("YANMA"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_ILLUMISE, .heldItem = ITEM_BRIGHT_POWDER, .moves = {MOVE_ENCORE, MOVE_ATTRACT, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .defenseEV = 6, .speedEV = 252, @@ -2294,15 +2133,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0xA, .nickname = _("ILLUMISE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [4] = { .species = SPECIES_SPHEAL, .heldItem = ITEM_FOCUS_BAND, .moves = {MOVE_ENCORE, MOVE_ATTRACT, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .speedEV = 252, .spDefenseEV = 6, @@ -2316,15 +2153,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0xA, .nickname = _("SPHEAL"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [5] = { .species = SPECIES_VIGOROTH, .heldItem = ITEM_FOCUS_BAND, .moves = {MOVE_ENCORE, MOVE_ATTRACT, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .defenseEV = 6, .speedEV = 252, @@ -2338,12 +2173,12 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0x87, .nickname = _("VIGOROTH"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, }, }, }, - .display = { + .map = { .metatileData = { 0x31, 0x3B, 0x3B, 0x3B, 0x39, 0x39, 0x13, 0x14, 0x15, 0x38, 0x39, 0x3A, 0x3B, 0x3B, 0x3B, 0x08, 0x91, 0x9B, 0x9C, 0x96, 0x40, 0x40, 0x96, 0x9B, 0x96, 0x40, 0x40, 0x96, 0x9B, 0x9C, 0x9B, 0x08, @@ -2363,9 +2198,9 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, }, .collisionData = {0x0381, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0xFFFF}, - .coords = {COORDS_XY(3,8), COORDS_XY(11,8)}, - .direction = TRAINER_DIRS(DIR_WEST, DIR_EAST), - .range = TRAINER_RANGE(7, 7), + .trainerCoords = {COORDS_XY(3,8), COORDS_XY(11,8)}, + .trainerDirections = TRAINER_DIRS(DIR_WEST, DIR_EAST), + .trainerRanges = TRAINER_RANGE(7, 7), } }, [2] = @@ -2390,8 +2225,6 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .species = SPECIES_WOOPER, .heldItem = ITEM_FIGY_BERRY, .moves = {MOVE_RAIN_DANCE, MOVE_YAWN, MOVE_SURF, MOVE_HAZE}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .speedEV = 6, .spAttackEV = 252, @@ -2405,15 +2238,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0x8C, .nickname = _("WOOPER"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_POLIWAG, .heldItem = ITEM_WIKI_BERRY, .moves = {MOVE_SURF, MOVE_ICE_BEAM, MOVE_MIST, MOVE_HYPNOSIS}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .speedEV = 6, .spAttackEV = 252, @@ -2427,15 +2258,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 1, .personality = 0x3, .nickname = _("POLIWAG"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [2] = { .species = SPECIES_PSYDUCK, .heldItem = ITEM_AGUAV_BERRY, .moves = {MOVE_HYPNOSIS, MOVE_SURF, MOVE_DISABLE, MOVE_SEISMIC_TOSS}, - .level = 0, - .ppBonuses = 0, .hpEV = 250, .defenseEV = 130, .spDefenseEV = 130, @@ -2449,15 +2278,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0x3, .nickname = _("PSYDUCK"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_RHYDON, .heldItem = ITEM_SOFT_SAND, .moves = {MOVE_EARTHQUAKE, MOVE_MAGNITUDE, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .attackEV = 252, .speedEV = 6, @@ -2478,8 +2305,6 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .species = SPECIES_RHYHORN, .heldItem = ITEM_SOFT_SAND, .moves = {MOVE_EARTHQUAKE, MOVE_MAGNITUDE, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .attackEV = 252, .speedEV = 252, @@ -2500,8 +2325,6 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .species = SPECIES_CUBONE, .heldItem = ITEM_SOFT_SAND, .moves = {MOVE_EARTHQUAKE, MOVE_NONE, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .attackEV = 252, .speedEV = 252, @@ -2535,8 +2358,6 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .species = SPECIES_MAGNEMITE, .heldItem = ITEM_MAGNET, .moves = {MOVE_THUNDER, MOVE_ZAP_CANNON, MOVE_SPARK, MOVE_THUNDER_SHOCK}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .speedEV = 252, .spAttackEV = 252, @@ -2550,15 +2371,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0x8C, .nickname = _("MAGNEMITE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_ELECTABUZZ, .heldItem = ITEM_MAGNET, .moves = {MOVE_THUNDER, MOVE_THUNDERBOLT, MOVE_THUNDER_PUNCH, MOVE_SHOCK_WAVE}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .speedEV = 252, .spAttackEV = 252, @@ -2572,15 +2391,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0x41, .nickname = _("ELECTABUZZ"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [2] = { .species = SPECIES_FLAAFFY, .heldItem = ITEM_MAGNET, .moves = {MOVE_THUNDER, MOVE_THUNDERBOLT, MOVE_SHOCK_WAVE, MOVE_THUNDER_SHOCK}, - .level = 0, - .ppBonuses = 0, .hpEV = 250, .spAttackEV = 130, .otId = TRAINER_HILL_OTID, @@ -2593,15 +2410,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0x0, .nickname = _("FLAAFFY"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_BALTOY, .heldItem = ITEM_SILK_SCARF, .moves = {MOVE_EXPLOSION, MOVE_SELF_DESTRUCT, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .attackEV = 252, .speedEV = 252, @@ -2622,8 +2437,6 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .species = SPECIES_PINECO, .heldItem = ITEM_SILK_SCARF, .moves = {MOVE_EXPLOSION, MOVE_SELF_DESTRUCT, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .attackEV = 252, .speedEV = 6, @@ -2644,8 +2457,6 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .species = SPECIES_VOLTORB, .heldItem = ITEM_SILK_SCARF, .moves = {MOVE_EXPLOSION, MOVE_SELF_DESTRUCT, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .attackEV = 252, .speedEV = 252, @@ -2664,7 +2475,7 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { }, }, }, - .display = { + .map = { .metatileData = { 0x31, 0x3B, 0x3B, 0x3B, 0x39, 0x39, 0x1B, 0x1C, 0x1D, 0x38, 0x39, 0x3A, 0x3B, 0x3B, 0x3B, 0x08, 0x91, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x84, 0x84, 0x84, 0x9A, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x08, @@ -2684,9 +2495,9 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { 0x17, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0x17, 0xBB, 0xBB, 0x08, }, .collisionData = {0x0381, 0x0381, 0x7FF7, 0x1, 0x7FF7, 0x1, 0x7FF7, 0x1, 0x7FF7, 0x1, 0x7FF7, 0x1, 0x7FF7, 0x1, 0x7FF7, 0x1}, - .coords = {COORDS_XY(9,1), COORDS_XY(14,1)}, - .direction = TRAINER_DIRS(DIR_WEST, DIR_EAST), - .range = TRAINER_RANGE(4, 4), + .trainerCoords = {COORDS_XY(9,1), COORDS_XY(14,1)}, + .trainerDirections = TRAINER_DIRS(DIR_WEST, DIR_EAST), + .trainerRanges = TRAINER_RANGE(4, 4), } }, [3] = @@ -2711,8 +2522,6 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .species = SPECIES_UNOWN, .heldItem = ITEM_MIRACLE_SEED, .moves = {MOVE_HIDDEN_POWER, MOVE_NONE, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -2725,15 +2534,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0x202, .nickname = _("UNOWN"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_UNOWN, .heldItem = ITEM_MYSTIC_WATER, .moves = {MOVE_HIDDEN_POWER, MOVE_NONE, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -2746,15 +2553,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0x10001, .nickname = _("UNOWN"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [2] = { .species = SPECIES_UNOWN, .heldItem = ITEM_BLACK_BELT, .moves = {MOVE_HIDDEN_POWER, MOVE_NONE, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -2767,15 +2572,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0x102, .nickname = _("UNOWN"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_SPINDA, .heldItem = ITEM_LUM_BERRY, .moves = {MOVE_TEETER_DANCE, MOVE_DIZZY_PUNCH, MOVE_CALM_MIND, MOVE_BATON_PASS}, - .level = 0, - .ppBonuses = 0, .hpEV = 110, .defenseEV = 200, .spDefenseEV = 200, @@ -2789,15 +2592,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0x88FE980F, .nickname = _("SPINDA"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [4] = { .species = SPECIES_PLUSLE, .heldItem = ITEM_BRIGHT_POWDER, .moves = {MOVE_HELPING_HAND, MOVE_THUNDERBOLT, MOVE_AGILITY, MOVE_BATON_PASS}, - .level = 0, - .ppBonuses = 0, .speedEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -2810,15 +2611,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0xF, .nickname = _("PLUSLE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [5] = { .species = SPECIES_VOLBEAT, .heldItem = ITEM_SITRUS_BERRY, .moves = {MOVE_HELPING_HAND, MOVE_SIGNAL_BEAM, MOVE_SOLAR_BEAM, MOVE_MOONLIGHT}, - .level = 0, - .ppBonuses = 0, .speedEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -2831,7 +2630,7 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 1, .personality = 0xF, .nickname = _("VOLBEAT"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, }, }, @@ -2851,8 +2650,6 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .species = SPECIES_SPINDA, .heldItem = ITEM_LUM_BERRY, .moves = {MOVE_TEETER_DANCE, MOVE_DIZZY_PUNCH, MOVE_CALM_MIND, MOVE_BATON_PASS}, - .level = 0, - .ppBonuses = 0, .hpEV = 110, .defenseEV = 200, .spDefenseEV = 200, @@ -2866,15 +2663,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0xE2880098, .nickname = _("SPINDA"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_MINUN, .heldItem = ITEM_BRIGHT_POWDER, .moves = {MOVE_HELPING_HAND, MOVE_THUNDERBOLT, MOVE_AGILITY, MOVE_BATON_PASS}, - .level = 0, - .ppBonuses = 0, .speedEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -2887,15 +2682,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0x8C, .nickname = _("MINUN"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [2] = { .species = SPECIES_ILLUMISE, .heldItem = ITEM_SITRUS_BERRY, .moves = {MOVE_HELPING_HAND, MOVE_WISH, MOVE_THUNDERBOLT, MOVE_MOONLIGHT}, - .level = 0, - .ppBonuses = 0, .speedEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -2908,15 +2701,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0xF, .nickname = _("ILLUMISE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_UNOWN, .heldItem = ITEM_CHARCOAL, .moves = {MOVE_HIDDEN_POWER, MOVE_NONE, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -2929,15 +2720,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0x302, .nickname = _("UNOWN"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [4] = { .species = SPECIES_UNOWN, .heldItem = ITEM_SOFT_SAND, .moves = {MOVE_HIDDEN_POWER, MOVE_NONE, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 255, .attackEV = 255, .otId = TRAINER_HILL_OTID, @@ -2950,15 +2739,13 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0x203, .nickname = _("UNOWN"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [5] = { .species = SPECIES_UNOWN, .heldItem = ITEM_TWISTED_SPOON, .moves = {MOVE_HIDDEN_POWER, MOVE_NONE, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -2971,12 +2758,12 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { .abilityNum = 0, .personality = 0x301, .nickname = _("UNOWN"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, }, }, }, - .display = { + .map = { .metatileData = { 0x31, 0x3B, 0x3B, 0x3B, 0x39, 0x39, 0x13, 0x14, 0x15, 0x38, 0x39, 0x3A, 0x3B, 0x3B, 0x3B, 0x08, 0x69, 0x40, 0x6D, 0x41, 0x73, 0x41, 0x5E, 0x41, 0x71, 0x42, 0x45, 0x45, 0x45, 0x45, 0x45, 0x08, @@ -2996,14 +2783,14 @@ static const struct TrHillFloor sDataTagVariety_Floors[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, }, .collisionData = {0x0381, 0x1, 0x2201, 0x1, 0x8881, 0x1, 0x2223, 0x1, 0x8889, 0x1, 0x2223, 0x1, 0x8889, 0x1, 0x2223, 0xFFFF}, - .coords = {COORDS_XY(10,2), COORDS_XY(14,2)}, - .direction = TRAINER_DIRS(DIR_WEST, DIR_EAST), - .range = TRAINER_RANGE(3, 3), + .trainerCoords = {COORDS_XY(10,2), COORDS_XY(14,2)}, + .trainerDirections = TRAINER_DIRS(DIR_WEST, DIR_EAST), + .trainerRanges = TRAINER_RANGE(3, 3), } }, }; -static const struct TrHillTag sDataTagUnique = +static const struct TrainerHillChallenge sChallenge_Unique = { .numTrainers = NUM_TRAINER_HILL_TRAINERS, .unused1 = 3, @@ -3011,7 +2798,7 @@ static const struct TrHillTag sDataTagUnique = .checksum = 0x000652F3 }; -static const struct TrHillFloor sDataTagUnique_Floors[] = { +static const struct TrainerHillFloor sFloors_Unique[] = { [0] = { .trainerNum1 = 49, @@ -3034,8 +2821,6 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .species = SPECIES_SUNFLORA, .heldItem = ITEM_PERSIM_BERRY, .moves = {MOVE_PETAL_DANCE, MOVE_GRASS_WHISTLE, MOVE_LIGHT_SCREEN, MOVE_SUNNY_DAY}, - .level = 0, - .ppBonuses = 0, .hpEV = 255, .defenseEV = 155, .spDefenseEV = 100, @@ -3049,15 +2834,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 0, .personality = 0x0, .nickname = _("SUNFLORA"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_TANGELA, .heldItem = ITEM_QUICK_CLAW, .moves = {MOVE_GIGA_DRAIN, MOVE_SLEEP_POWDER, MOVE_AMNESIA, MOVE_SUNNY_DAY}, - .level = 0, - .ppBonuses = 0, .hpEV = 255, .spDefenseEV = 255, .otId = TRAINER_HILL_OTID, @@ -3070,15 +2853,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 0, .personality = 0x91, .nickname = _("TANGELA"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [2] = { .species = SPECIES_VENUSAUR, .heldItem = ITEM_LEFTOVERS, .moves = {MOVE_SOLAR_BEAM, MOVE_EARTHQUAKE, MOVE_SYNTHESIS, MOVE_SUNNY_DAY}, - .level = 0, - .ppBonuses = 0, .hpEV = 100, .attackEV = 110, .defenseEV = 100, @@ -3094,15 +2875,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 0, .personality = 0x1F, .nickname = _("VENUSAUR"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_LANTURN, .heldItem = ITEM_PERSIM_BERRY, .moves = {MOVE_SPARK, MOVE_WATER_PULSE, MOVE_CONFUSE_RAY, MOVE_RAIN_DANCE}, - .level = 0, - .ppBonuses = 0, .speedEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -3115,15 +2894,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 0, .personality = 0xF, .nickname = _("LANTURN"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [4] = { .species = SPECIES_MANECTRIC, .heldItem = ITEM_FOCUS_BAND, .moves = {MOVE_THUNDERBOLT, MOVE_HEADBUTT, MOVE_BITE, MOVE_RAIN_DANCE}, - .level = 0, - .ppBonuses = 0, .speedEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -3136,15 +2913,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 1, .personality = 0xF, .nickname = _("MANECTRIC"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [5] = { .species = SPECIES_RAIKOU, .heldItem = ITEM_BRIGHT_POWDER, .moves = {MOVE_THUNDER, MOVE_CRUNCH, MOVE_ROAR, MOVE_RAIN_DANCE}, - .level = 0, - .ppBonuses = 0, .speedEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -3157,7 +2932,7 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 0, .personality = 0xF, .nickname = _("RAIKOU"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, }, }, @@ -3177,8 +2952,6 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .species = SPECIES_RELICANTH, .heldItem = ITEM_QUICK_CLAW, .moves = {MOVE_ANCIENT_POWER, MOVE_WATER_PULSE, MOVE_MUD_SPORT, MOVE_RAIN_DANCE}, - .level = 0, - .ppBonuses = 0, .hpEV = 155, .defenseEV = 100, .spDefenseEV = 255, @@ -3192,15 +2965,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 0, .personality = 0x2F, .nickname = _("RELICANTH"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_GOLDUCK, .heldItem = ITEM_LAX_INCENSE, .moves = {MOVE_SURF, MOVE_PSYBEAM, MOVE_BRICK_BREAK, MOVE_RAIN_DANCE}, - .level = 0, - .ppBonuses = 0, .speedEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -3213,15 +2984,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 0, .personality = 0xF, .nickname = _("GOLDUCK"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [2] = { .species = SPECIES_BLASTOISE, .heldItem = ITEM_SHELL_BELL, .moves = {MOVE_HYDRO_PUMP, MOVE_BITE, MOVE_MIRROR_COAT, MOVE_RAIN_DANCE}, - .level = 0, - .ppBonuses = 0, .speedEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -3234,15 +3003,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 0, .personality = 0x28, .nickname = _("BLASTOISE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_MAGCARGO, .heldItem = ITEM_QUICK_CLAW, .moves = {MOVE_HEAT_WAVE, MOVE_ROCK_SLIDE, MOVE_PROTECT, MOVE_SUNNY_DAY}, - .level = 0, - .ppBonuses = 0, .hpEV = 255, .spDefenseEV = 255, .otId = TRAINER_HILL_OTID, @@ -3255,15 +3022,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 1, .personality = 0x93, .nickname = _("MAGCARGO"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [4] = { .species = SPECIES_RAPIDASH, .heldItem = ITEM_KINGS_ROCK, .moves = {MOVE_FIRE_BLAST, MOVE_BOUNCE, MOVE_QUICK_ATTACK, MOVE_SUNNY_DAY}, - .level = 0, - .ppBonuses = 0, .speedEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -3276,15 +3041,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 1, .personality = 0xF, .nickname = _("RAPIDASH"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [5] = { .species = SPECIES_MOLTRES, .heldItem = ITEM_BRIGHT_POWDER, .moves = {MOVE_SKY_ATTACK, MOVE_AERIAL_ACE, MOVE_ROAR, MOVE_SUNNY_DAY}, - .level = 0, - .ppBonuses = 0, .speedEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -3297,12 +3060,12 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 0, .personality = 0xF, .nickname = _("MOLTRES"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, }, }, }, - .display = { + .map = { .metatileData = { 0xF1, 0xF5, 0xFB, 0xF5, 0xE6, 0xE6, 0x1B, 0x14, 0x15, 0xF8, 0xF9, 0xFA, 0xFB, 0xFB, 0xFB, 0x08, 0xF1, 0xEB, 0xFB, 0xEB, 0xEC, 0xEC, 0xEC, 0xF9, 0xE6, 0xEE, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0x08, @@ -3322,9 +3085,9 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, }, .collisionData = {0x0381, 0x5E01, 0x50FF, 0x5083, 0x503B, 0x5FEB, 0xC02B, 0x5FEB, 0x5009, 0x57FD, 0x1005, 0x7FF5, 0x15, 0x7FF5, 0x1, 0xFFFF}, - .coords = {COORDS_XY(4,3), COORDS_XY(7,3)}, - .direction = TRAINER_DIRS(DIR_WEST, DIR_EAST), - .range = TRAINER_RANGE(2, 2), + .trainerCoords = {COORDS_XY(4,3), COORDS_XY(7,3)}, + .trainerDirections = TRAINER_DIRS(DIR_WEST, DIR_EAST), + .trainerRanges = TRAINER_RANGE(2, 2), } }, [1] = @@ -3349,8 +3112,6 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .species = SPECIES_SMEARGLE, .heldItem = ITEM_SCOPE_LENS, .moves = {MOVE_EARTHQUAKE, MOVE_SHADOW_BALL, MOVE_AERIAL_ACE, MOVE_IMPRISON}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .attackEV = 6, .speedEV = 252, @@ -3364,15 +3125,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 0, .personality = 0x8A, .nickname = _("SMEARGLE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_SMEARGLE, .heldItem = ITEM_CHESTO_BERRY, .moves = {MOVE_REST, MOVE_THUNDER_WAVE, MOVE_FLAMETHROWER, MOVE_IMPRISON}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .speedEV = 252, .spAttackEV = 6, @@ -3386,15 +3145,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 0, .personality = 0x87, .nickname = _("SMEARGLE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [2] = { .species = SPECIES_SMEARGLE, .heldItem = ITEM_QUICK_CLAW, .moves = {MOVE_TEETER_DANCE, MOVE_LOCK_ON, MOVE_SHEER_COLD, MOVE_EXPLOSION}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .attackEV = 6, .speedEV = 252, @@ -3408,15 +3165,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 0, .personality = 0xD, .nickname = _("SMEARGLE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_SMEARGLE, .heldItem = ITEM_SCOPE_LENS, .moves = {MOVE_PSYCHIC, MOVE_SURF, MOVE_THUNDERBOLT, MOVE_IMPRISON}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .speedEV = 252, .spAttackEV = 6, @@ -3430,15 +3185,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 0, .personality = 0xA, .nickname = _("SMEARGLE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [4] = { .species = SPECIES_SMEARGLE, .heldItem = ITEM_LEFTOVERS, .moves = {MOVE_TOXIC, MOVE_PROTECT, MOVE_WILL_O_WISP, MOVE_IMPRISON}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .defenseEV = 6, .speedEV = 252, @@ -3452,15 +3205,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 0, .personality = 0xA, .nickname = _("SMEARGLE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [5] = { .species = SPECIES_SMEARGLE, .heldItem = ITEM_QUICK_CLAW, .moves = {MOVE_TEETER_DANCE, MOVE_LOCK_ON, MOVE_SHEER_COLD, MOVE_DESTINY_BOND}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .defenseEV = 6, .speedEV = 252, @@ -3474,7 +3225,7 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 0, .personality = 0x8A, .nickname = _("SMEARGLE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, }, }, @@ -3494,8 +3245,6 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .species = SPECIES_STARYU, .heldItem = ITEM_LEFTOVERS, .moves = {MOVE_CAMOUFLAGE, MOVE_NONE, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .speedEV = 252, .spAttackEV = 6, @@ -3509,15 +3258,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 1, .personality = 0xA, .nickname = _("STARYU"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_MEOWTH, .heldItem = ITEM_QUICK_CLAW, .moves = {MOVE_PAY_DAY, MOVE_NONE, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .speedEV = 252, .spAttackEV = 6, @@ -3531,15 +3278,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 0, .personality = 0xD, .nickname = _("MEOWTH"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [2] = { .species = SPECIES_BLAZIKEN, .heldItem = ITEM_BRIGHT_POWDER, .moves = {MOVE_BLAZE_KICK, MOVE_NONE, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .speedEV = 252, .spDefenseEV = 6, @@ -3553,15 +3298,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 0, .personality = 0x28, .nickname = _("BLAZIKEN"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_CUBONE, .heldItem = ITEM_THICK_CLUB, .moves = {MOVE_BONEMERANG, MOVE_NONE, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .defenseEV = 6, .spDefenseEV = 252, @@ -3575,15 +3318,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 1, .personality = 0x16, .nickname = _("CUBONE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [4] = { .species = SPECIES_BEEDRILL, .heldItem = ITEM_SHELL_BELL, .moves = {MOVE_TWINEEDLE, MOVE_NONE, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .speedEV = 252, .otId = TRAINER_HILL_OTID, @@ -3596,15 +3337,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 0, .personality = 0x8A, .nickname = _("BEEDRILL"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [5] = { .species = SPECIES_RATICATE, .heldItem = ITEM_FOCUS_BAND, .moves = {MOVE_SUPER_FANG, MOVE_NONE, MOVE_NONE, MOVE_NONE}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .defenseEV = 6, .speedEV = 252, @@ -3618,12 +3357,12 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 1, .personality = 0xD, .nickname = _("RATICATE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, }, }, }, - .display = { + .map = { .metatileData = { 0x31, 0x3B, 0x3B, 0x3B, 0x39, 0x26, 0x1B, 0x1C, 0x1D, 0x25, 0x39, 0x3A, 0x3B, 0x3B, 0x3B, 0x08, 0x2D, 0x3B, 0x3B, 0x3B, 0x35, 0x2C, 0x23, 0x24, 0x23, 0x2C, 0x35, 0x3B, 0x3B, 0x3B, 0x3B, 0x08, @@ -3643,9 +3382,9 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, }, .collisionData = {0x0381, 0x7C1, 0x8AA1, 0x0209, 0x5557, 0xA281, 0x81, 0x5D6D, 0x2283, 0x89, 0xDD55, 0x20A1, 0xA81, 0x7D5D, 0x9, 0xFFFF}, - .coords = {COORDS_XY(9,6), COORDS_XY(13,6)}, - .direction = TRAINER_DIRS(DIR_WEST, DIR_EAST), - .range = TRAINER_RANGE(3, 3), + .trainerCoords = {COORDS_XY(9,6), COORDS_XY(13,6)}, + .trainerDirections = TRAINER_DIRS(DIR_WEST, DIR_EAST), + .trainerRanges = TRAINER_RANGE(3, 3), } }, [2] = @@ -3670,8 +3409,6 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .species = SPECIES_CHARMELEON, .heldItem = ITEM_CHARCOAL, .moves = {MOVE_FIRE_SPIN, MOVE_DRAGON_RAGE, MOVE_FLAMETHROWER, MOVE_SLASH}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .speedEV = 252, .spAttackEV = 6, @@ -3692,8 +3429,6 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .species = SPECIES_WARTORTLE, .heldItem = ITEM_MYSTIC_WATER, .moves = {MOVE_HYDRO_PUMP, MOVE_SKULL_BASH, MOVE_RAIN_DANCE, MOVE_PROTECT}, - .level = 0, - .ppBonuses = 0, .hpEV = 250, .defenseEV = 130, .otId = TRAINER_HILL_OTID, @@ -3713,8 +3448,6 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .species = SPECIES_IVYSAUR, .heldItem = ITEM_MIRACLE_SEED, .moves = {MOVE_SOLAR_BEAM, MOVE_SYNTHESIS, MOVE_GROWTH, MOVE_SWEET_SCENT}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .speedEV = 6, .spAttackEV = 252, @@ -3735,8 +3468,6 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .species = SPECIES_BAYLEEF, .heldItem = ITEM_MIRACLE_SEED, .moves = {MOVE_SOLAR_BEAM, MOVE_SAFEGUARD, MOVE_LIGHT_SCREEN, MOVE_BODY_SLAM}, - .level = 0, - .ppBonuses = 0, .hpEV = 250, .attackEV = 130, .spAttackEV = 130, @@ -3757,8 +3488,6 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .species = SPECIES_CROCONAW, .heldItem = ITEM_MYSTIC_WATER, .moves = {MOVE_SCARY_FACE, MOVE_SLASH, MOVE_HYDRO_PUMP, MOVE_SCREECH}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .attackEV = 252, .speedEV = 6, @@ -3779,8 +3508,6 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .species = SPECIES_QUILAVA, .heldItem = ITEM_CHARCOAL, .moves = {MOVE_QUICK_ATTACK, MOVE_FLAMETHROWER, MOVE_FLAME_WHEEL, MOVE_SWIFT}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .speedEV = 252, .spAttackEV = 252, @@ -3814,8 +3541,6 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .species = SPECIES_SMOOCHUM, .heldItem = ITEM_PETAYA_BERRY, .moves = {MOVE_ICE_BEAM, MOVE_PSYCHIC, MOVE_SWEET_KISS, MOVE_FAKE_TEARS}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .speedEV = 252, .spAttackEV = 252, @@ -3836,8 +3561,6 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .species = SPECIES_AZURILL, .heldItem = ITEM_FOCUS_BAND, .moves = {MOVE_SURF, MOVE_SING, MOVE_RAIN_DANCE, MOVE_BLIZZARD}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .speedEV = 252, .spAttackEV = 252, @@ -3858,8 +3581,6 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .species = SPECIES_ELEKID, .heldItem = ITEM_KINGS_ROCK, .moves = {MOVE_FIRE_PUNCH, MOVE_THUNDER, MOVE_ICE_PUNCH, MOVE_THUNDER_WAVE}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .speedEV = 252, .spAttackEV = 252, @@ -3880,8 +3601,6 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .species = SPECIES_CLEFFA, .heldItem = ITEM_QUICK_CLAW, .moves = {MOVE_MEGA_KICK, MOVE_SWEET_KISS, MOVE_SING, MOVE_METRONOME}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .attackEV = 252, .speedEV = 252, @@ -3902,8 +3621,6 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .species = SPECIES_WYNAUT, .heldItem = ITEM_LEFTOVERS, .moves = {MOVE_ENCORE, MOVE_COUNTER, MOVE_MIRROR_COAT, MOVE_DESTINY_BOND}, - .level = 0, - .ppBonuses = 0, .hpEV = 250, .defenseEV = 130, .spDefenseEV = 130, @@ -3924,8 +3641,6 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .species = SPECIES_MAGBY, .heldItem = ITEM_SCOPE_LENS, .moves = {MOVE_FIRE_BLAST, MOVE_CONFUSE_RAY, MOVE_THUNDER_PUNCH, MOVE_BARRIER}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .speedEV = 252, .spAttackEV = 252, @@ -3944,7 +3659,7 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { }, }, }, - .display = { + .map = { .metatileData = { 0x31, 0x3B, 0x3B, 0x3B, 0x39, 0x39, 0x13, 0x14, 0x15, 0x38, 0x39, 0x3A, 0x3B, 0x3B, 0x3B, 0x08, 0x69, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x7C, 0x46, 0x08, @@ -3964,9 +3679,9 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, }, .collisionData = {0x0381, 0x7FFB, 0x4003, 0x5FFF, 0x4003, 0x7FFB, 0x4003, 0x7EFF, 0x4443, 0x4443, 0x4443, 0x7EFF, 0x4001, 0x7FFD, 0x1, 0xFFFF}, - .coords = {COORDS_XY(6,9), COORDS_XY(8,9)}, - .direction = TRAINER_DIRS(DIR_WEST, DIR_EAST), - .range = TRAINER_RANGE(1, 1), + .trainerCoords = {COORDS_XY(6,9), COORDS_XY(8,9)}, + .trainerDirections = TRAINER_DIRS(DIR_WEST, DIR_EAST), + .trainerRanges = TRAINER_RANGE(1, 1), } }, [3] = @@ -3991,8 +3706,6 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .species = SPECIES_SUDOWOODO, .heldItem = ITEM_SITRUS_BERRY, .moves = {MOVE_ROCK_SLIDE, MOVE_BLOCK, MOVE_TOXIC, MOVE_EXPLOSION}, - .level = 0, - .ppBonuses = 0, .hpEV = 100, .attackEV = 255, .spDefenseEV = 155, @@ -4006,15 +3719,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 0, .personality = 0x80, .nickname = _("SUDOWOODO"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_SLOWKING, .heldItem = ITEM_SCOPE_LENS, .moves = {MOVE_SURF, MOVE_PSYCHIC, MOVE_BLIZZARD, MOVE_DISABLE}, - .level = 0, - .ppBonuses = 0, .hpEV = 255, .defenseEV = 255, .otId = TRAINER_HILL_OTID, @@ -4027,15 +3738,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 1, .personality = 0x8C, .nickname = _("SLOWKING"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [2] = { .species = SPECIES_ENTEI, .heldItem = ITEM_PETAYA_BERRY, .moves = {MOVE_FLAMETHROWER, MOVE_CALM_MIND, MOVE_FIRE_SPIN, MOVE_ROAR}, - .level = 0, - .ppBonuses = 0, .speedEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -4048,15 +3757,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 0, .personality = 0xF, .nickname = _("ENTEI"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_HITMONCHAN, .heldItem = ITEM_FOCUS_BAND, .moves = {MOVE_MEGA_PUNCH, MOVE_DETECT, MOVE_COUNTER, MOVE_SKY_UPPERCUT}, - .level = 0, - .ppBonuses = 0, .attackEV = 255, .speedEV = 255, .otId = TRAINER_HILL_OTID, @@ -4069,15 +3776,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 0, .personality = 0x3, .nickname = _("HITMONCHAN"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [4] = { .species = SPECIES_MANTINE, .heldItem = ITEM_LEFTOVERS, .moves = {MOVE_SURF, MOVE_CONFUSE_RAY, MOVE_ATTRACT, MOVE_AERIAL_ACE}, - .level = 0, - .ppBonuses = 0, .hpEV = 255, .defenseEV = 255, .otId = TRAINER_HILL_OTID, @@ -4090,15 +3795,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 1, .personality = 0x6, .nickname = _("MANTINE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [5] = { .species = SPECIES_ZAPDOS, .heldItem = ITEM_BRIGHT_POWDER, .moves = {MOVE_THUNDERBOLT, MOVE_DRILL_PECK, MOVE_THUNDER_WAVE, MOVE_AGILITY}, - .level = 0, - .ppBonuses = 0, .speedEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -4111,7 +3814,7 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 0, .personality = 0x18, .nickname = _("ZAPDOS"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, }, }, @@ -4131,8 +3834,6 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .species = SPECIES_HITMONLEE, .heldItem = ITEM_FOCUS_BAND, .moves = {MOVE_MEGA_KICK, MOVE_MIND_READER, MOVE_FOCUS_ENERGY, MOVE_HI_JUMP_KICK}, - .level = 0, - .ppBonuses = 0, .hpEV = 255, .attackEV = 255, .otId = TRAINER_HILL_OTID, @@ -4145,15 +3846,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 0, .personality = 0x3, .nickname = _("HITMONLEE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_PORYGON2, .heldItem = ITEM_SCOPE_LENS, .moves = {MOVE_LOCK_ON, MOVE_BLIZZARD, MOVE_CONVERSION_2, MOVE_PSYCHIC}, - .level = 0, - .ppBonuses = 0, .hpEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -4166,15 +3865,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 0, .personality = 0xF, .nickname = _("PORYGON2"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [2] = { .species = SPECIES_SUICUNE, .heldItem = ITEM_PETAYA_BERRY, .moves = {MOVE_SURF, MOVE_CALM_MIND, MOVE_MIRROR_COAT, MOVE_MIST}, - .level = 0, - .ppBonuses = 0, .speedEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -4187,15 +3884,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 0, .personality = 0xF, .nickname = _("SUICUNE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_HOUNDOOM, .heldItem = ITEM_QUICK_CLAW, .moves = {MOVE_FLAMETHROWER, MOVE_CRUNCH, MOVE_ROAR, MOVE_WILL_O_WISP}, - .level = 0, - .ppBonuses = 0, .speedEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -4208,15 +3903,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 1, .personality = 0xF, .nickname = _("HOUNDOOM"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [4] = { .species = SPECIES_STANTLER, .heldItem = ITEM_LEFTOVERS, .moves = {MOVE_CONFUSE_RAY, MOVE_SWAGGER, MOVE_PSYCH_UP, MOVE_TAKE_DOWN}, - .level = 0, - .ppBonuses = 0, .attackEV = 255, .speedEV = 255, .otId = TRAINER_HILL_OTID, @@ -4229,15 +3922,13 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 0, .personality = 0x3, .nickname = _("STANTLER"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [5] = { .species = SPECIES_ARTICUNO, .heldItem = ITEM_NEVER_MELT_ICE, .moves = {MOVE_BLIZZARD, MOVE_SHEER_COLD, MOVE_MIST, MOVE_AERIAL_ACE}, - .level = 0, - .ppBonuses = 0, .hpEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -4250,12 +3941,12 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { .abilityNum = 0, .personality = 0xF, .nickname = _("ARTICUNO"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, }, }, }, - .display = { + .map = { .metatileData = { 0xF1, 0xFB, 0xFB, 0xFB, 0xF9, 0xF9, 0x1B, 0x1C, 0x1D, 0xE5, 0xE6, 0xEE, 0xF5, 0xFB, 0xFB, 0x08, 0xED, 0xF5, 0xF5, 0xF5, 0xFB, 0xFB, 0xEC, 0xEC, 0xEC, 0xEB, 0xEC, 0xEC, 0xEC, 0xFB, 0xFB, 0x08, @@ -4275,14 +3966,14 @@ static const struct TrHillFloor sDataTagUnique_Floors[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, }, .collisionData = {0x0381, 0x3F9, 0xF041, 0x41, 0x7F5F, 0x4401, 0x4541, 0x5579, 0x5541, 0x555F, 0x5541, 0x5541, 0x557D, 0x1101, 0x1101, 0xFFFF}, - .coords = {COORDS_XY(8,2), COORDS_XY(11,5)}, - .direction = TRAINER_DIRS(DIR_WEST, DIR_NORTH), - .range = TRAINER_RANGE(3, 3), + .trainerCoords = {COORDS_XY(8,2), COORDS_XY(11,5)}, + .trainerDirections = TRAINER_DIRS(DIR_WEST, DIR_NORTH), + .trainerRanges = TRAINER_RANGE(3, 3), } }, }; -static const struct TrHillTag sDataTagExpert = +static const struct TrainerHillChallenge sChallenge_Expert = { .numTrainers = NUM_TRAINER_HILL_TRAINERS, .unused1 = 1, @@ -4290,7 +3981,7 @@ static const struct TrHillTag sDataTagExpert = .checksum = 0x00061F3F }; -static const struct TrHillFloor sDataTagExpert_Floors[] = { +static const struct TrainerHillFloor sFloors_Expert[] = { [0] = { .trainerNum1 = 57, @@ -4313,8 +4004,6 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .species = SPECIES_SNORLAX, .heldItem = ITEM_QUICK_CLAW, .moves = {MOVE_MEGA_KICK, MOVE_SHADOW_BALL, MOVE_BRICK_BREAK, MOVE_EARTHQUAKE}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .attackEV = 252, .defenseEV = 252, @@ -4328,15 +4017,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x35, .nickname = _("SNORLAX"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_MILTANK, .heldItem = ITEM_LEFTOVERS, .moves = {MOVE_DOUBLE_EDGE, MOVE_SHADOW_BALL, MOVE_ATTRACT, MOVE_MILK_DRINK}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .attackEV = 252, .speedEV = 252, @@ -4350,15 +4037,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x3, .nickname = _("MILTANK"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [2] = { .species = SPECIES_URSARING, .heldItem = ITEM_QUICK_CLAW, .moves = {MOVE_DOUBLE_EDGE, MOVE_CRUNCH, MOVE_BRICK_BREAK, MOVE_AERIAL_ACE}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .attackEV = 252, .spAttackEV = 6, @@ -4372,15 +4057,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x7F, .nickname = _("URSARING"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_SLAKING, .heldItem = ITEM_CHESTO_BERRY, .moves = {MOVE_HYPER_BEAM, MOVE_SHADOW_BALL, MOVE_BRICK_BREAK, MOVE_REST}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .attackEV = 252, .spDefenseEV = 252, @@ -4394,15 +4077,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x80, .nickname = _("SLAKING"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [4] = { .species = SPECIES_KANGASKHAN, .heldItem = ITEM_LEFTOVERS, .moves = {MOVE_MEGA_KICK, MOVE_SHADOW_BALL, MOVE_ATTRACT, MOVE_FAKE_OUT}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .attackEV = 252, .speedEV = 252, @@ -4416,15 +4097,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x3, .nickname = _("KANGASKHAN"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [5] = { .species = SPECIES_ZANGOOSE, .heldItem = ITEM_SCOPE_LENS, .moves = {MOVE_CRUSH_CLAW, MOVE_SHADOW_BALL, MOVE_BRICK_BREAK, MOVE_ROAR}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .attackEV = 252, .speedEV = 252, @@ -4438,7 +4117,7 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x80, .nickname = _("ZANGOOSE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, }, }, @@ -4458,8 +4137,6 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .species = SPECIES_SLOWKING, .heldItem = ITEM_LEFTOVERS, .moves = {MOVE_PSYCHIC, MOVE_SURF, MOVE_ICE_BEAM, MOVE_SKILL_SWAP}, - .level = 0, - .ppBonuses = 0, .hpEV = 200, .defenseEV = 110, .spAttackEV = 200, @@ -4473,15 +4150,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 1, .personality = 0xF, .nickname = _("SLOWKING"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_ESPEON, .heldItem = ITEM_LUM_BERRY, .moves = {MOVE_PSYCHIC, MOVE_BITE, MOVE_CALM_MIND, MOVE_REFLECT}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .speedEV = 252, .spAttackEV = 252, @@ -4495,15 +4170,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x28, .nickname = _("ESPEON"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [2] = { .species = SPECIES_STARMIE, .heldItem = ITEM_SHELL_BELL, .moves = {MOVE_PSYCHIC, MOVE_SURF, MOVE_THUNDERBOLT, MOVE_ICE_BEAM}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .speedEV = 252, .spAttackEV = 252, @@ -4517,15 +4190,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 1, .personality = 0xF, .nickname = _("STARMIE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_GENGAR, .heldItem = ITEM_LUM_BERRY, .moves = {MOVE_PSYCHIC, MOVE_THUNDERBOLT, MOVE_FIRE_PUNCH, MOVE_ICE_PUNCH}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .speedEV = 252, .spAttackEV = 252, @@ -4539,15 +4210,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0xF, .nickname = _("GENGAR"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [4] = { .species = SPECIES_GARDEVOIR, .heldItem = ITEM_SALAC_BERRY, .moves = {MOVE_PSYCHIC, MOVE_THUNDERBOLT, MOVE_MAGICAL_LEAF, MOVE_DESTINY_BOND}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .speedEV = 252, .spAttackEV = 252, @@ -4561,15 +4230,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0xF, .nickname = _("GARDEVOIR"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [5] = { .species = SPECIES_ALAKAZAM, .heldItem = ITEM_LUM_BERRY, .moves = {MOVE_PSYCHIC, MOVE_RECOVER, MOVE_THUNDER_WAVE, MOVE_ATTRACT}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .speedEV = 252, .spAttackEV = 252, @@ -4583,12 +4250,12 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0xF, .nickname = _("ALAKAZAM"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, }, }, }, - .display = { + .map = { .metatileData = { 0x31, 0x3B, 0x3B, 0x3B, 0x39, 0x39, 0x1B, 0x14, 0x15, 0x38, 0x39, 0x3A, 0x3B, 0x3B, 0x3B, 0x08, 0x31, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x2C, 0x39, 0x39, 0x3A, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x08, @@ -4608,9 +4275,9 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, }, .collisionData = {0x0381, 0x0201, 0x3EF9, 0x3EF9, 0x3EF9, 0x2009, 0x3019, 0x2009, 0x3019, 0x2009, 0x3019, 0x3019, 0x3C79, 0x1, 0x1, 0xFFFF}, - .coords = {COORDS_XY(4,7), COORDS_XY(10,7)}, - .direction = TRAINER_DIRS(DIR_WEST, DIR_EAST), - .range = TRAINER_RANGE(5, 5), + .trainerCoords = {COORDS_XY(4,7), COORDS_XY(10,7)}, + .trainerDirections = TRAINER_DIRS(DIR_WEST, DIR_EAST), + .trainerRanges = TRAINER_RANGE(5, 5), } }, [1] = @@ -4635,8 +4302,6 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .species = SPECIES_SWELLOW, .heldItem = ITEM_LEFTOVERS, .moves = {MOVE_AERIAL_ACE, MOVE_AGILITY, MOVE_FACADE, MOVE_ATTRACT}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .attackEV = 252, .spDefenseEV = 6, @@ -4650,15 +4315,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x3, .nickname = _("SWELLOW"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_MACHAMP, .heldItem = ITEM_LEFTOVERS, .moves = {MOVE_LOW_KICK, MOVE_ROCK_SLIDE, MOVE_FACADE, MOVE_ATTRACT}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .attackEV = 252, .spDefenseEV = 6, @@ -4672,15 +4335,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x3, .nickname = _("MACHAMP"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [2] = { .species = SPECIES_URSARING, .heldItem = ITEM_LEFTOVERS, .moves = {MOVE_PROTECT, MOVE_ROCK_SLIDE, MOVE_FACADE, MOVE_ATTRACT}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .attackEV = 252, .spDefenseEV = 6, @@ -4694,15 +4355,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x3, .nickname = _("URSARING"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_KINGLER, .heldItem = ITEM_PERSIM_BERRY, .moves = {MOVE_RETURN, MOVE_PROTECT, MOVE_CRABHAMMER, MOVE_ATTRACT}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .attackEV = 252, .spDefenseEV = 6, @@ -4716,15 +4375,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x80, .nickname = _("KINGLER"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [4] = { .species = SPECIES_TYRANITAR, .heldItem = ITEM_PERSIM_BERRY, .moves = {MOVE_ROCK_SLIDE, MOVE_CRUNCH, MOVE_EARTHQUAKE, MOVE_ATTRACT}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .attackEV = 252, .defenseEV = 6, @@ -4738,15 +4395,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x80, .nickname = _("TYRANITAR"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [5] = { .species = SPECIES_DRAGONITE, .heldItem = ITEM_PERSIM_BERRY, .moves = {MOVE_BODY_SLAM, MOVE_THUNDER_WAVE, MOVE_EARTHQUAKE, MOVE_ATTRACT}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .attackEV = 252, .spDefenseEV = 6, @@ -4760,7 +4415,7 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x80, .nickname = _("DRAGONITE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, }, }, @@ -4780,8 +4435,6 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .species = SPECIES_JOLTEON, .heldItem = ITEM_BRIGHT_POWDER, .moves = {MOVE_THUNDERBOLT, MOVE_THUNDER_WAVE, MOVE_ATTRACT, MOVE_SWAGGER}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .speedEV = 252, .spAttackEV = 252, @@ -4795,15 +4448,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0xA, .nickname = _("JOLTEON"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_ALAKAZAM, .heldItem = ITEM_KINGS_ROCK, .moves = {MOVE_PSYCHIC, MOVE_ICE_PUNCH, MOVE_ATTRACT, MOVE_SWAGGER}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .speedEV = 252, .spAttackEV = 252, @@ -4817,15 +4468,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0xA, .nickname = _("ALAKAZAM"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [2] = { .species = SPECIES_STARMIE, .heldItem = ITEM_SCOPE_LENS, .moves = {MOVE_SURF, MOVE_PSYCHIC, MOVE_CONFUSE_RAY, MOVE_SWAGGER}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .speedEV = 252, .spAttackEV = 252, @@ -4839,15 +4488,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 1, .personality = 0xA, .nickname = _("STARMIE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_DUSCLOPS, .heldItem = ITEM_LEFTOVERS, .moves = {MOVE_PURSUIT, MOVE_PROTECT, MOVE_ATTRACT, MOVE_WILL_O_WISP}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .defenseEV = 252, .spDefenseEV = 6, @@ -4861,15 +4508,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x82, .nickname = _("DUSCLOPS"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [4] = { .species = SPECIES_NINETALES, .heldItem = ITEM_WHITE_HERB, .moves = {MOVE_OVERHEAT, MOVE_CONFUSE_RAY, MOVE_WILL_O_WISP, MOVE_ATTRACT}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .speedEV = 252, .spAttackEV = 252, @@ -4883,15 +4528,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0xD2, .nickname = _("NINETALES"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [5] = { .species = SPECIES_BANETTE, .heldItem = ITEM_FOCUS_BAND, .moves = {MOVE_SHADOW_BALL, MOVE_FAINT_ATTACK, MOVE_ATTRACT, MOVE_WILL_O_WISP}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .defenseEV = 252, .spDefenseEV = 6, @@ -4905,12 +4548,12 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x85, .nickname = _("BANETTE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, }, }, }, - .display = { + .map = { .metatileData = { 0x31, 0x3B, 0x3B, 0x3B, 0x39, 0x39, 0x13, 0x14, 0x15, 0x38, 0x39, 0x3A, 0x3B, 0x3B, 0x3B, 0x08, 0x91, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x78, 0x08, @@ -4930,9 +4573,9 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, }, .collisionData = {0x0381, 0x7FFD, 0x4001, 0x5FFF, 0x4001, 0x7FFD, 0x4001, 0x5FFF, 0x4001, 0x7FFD, 0x1, 0x1, 0x1, 0x1, 0x1, 0xFFFF}, - .coords = {COORDS_XY(7,10), COORDS_XY(7,14)}, - .direction = TRAINER_DIRS(DIR_SOUTH, DIR_NORTH), - .range = TRAINER_RANGE(3, 3), + .trainerCoords = {COORDS_XY(7,10), COORDS_XY(7,14)}, + .trainerDirections = TRAINER_DIRS(DIR_SOUTH, DIR_NORTH), + .trainerRanges = TRAINER_RANGE(3, 3), } }, [2] = @@ -4957,8 +4600,6 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .species = SPECIES_WOBBUFFET, .heldItem = ITEM_LEFTOVERS, .moves = {MOVE_MIRROR_COAT, MOVE_COUNTER, MOVE_SAFEGUARD, MOVE_ENCORE}, - .level = 0, - .ppBonuses = 0, .hpEV = 250, .defenseEV = 130, .spDefenseEV = 130, @@ -4972,15 +4613,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x94, .nickname = _("WOBBUFFET"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_EXPLOUD, .heldItem = ITEM_CHESTO_BERRY, .moves = {MOVE_HYPER_VOICE, MOVE_COUNTER, MOVE_REST, MOVE_ROCK_SLIDE}, - .level = 0, - .ppBonuses = 0, .hpEV = 250, .defenseEV = 130, .spDefenseEV = 130, @@ -5001,8 +4640,6 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .species = SPECIES_CROBAT, .heldItem = ITEM_KINGS_ROCK, .moves = {MOVE_MEAN_LOOK, MOVE_CONFUSE_RAY, MOVE_AERIAL_ACE, MOVE_TOXIC}, - .level = 0, - .ppBonuses = 0, .hpEV = 250, .defenseEV = 130, .spDefenseEV = 130, @@ -5016,15 +4653,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x0, .nickname = _("CROBAT"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_DUGTRIO, .heldItem = ITEM_BRIGHT_POWDER, .moves = {MOVE_DOUBLE_TEAM, MOVE_PROTECT, MOVE_RETURN, MOVE_SLUDGE_BOMB}, - .level = 0, - .ppBonuses = 0, .hpEV = 6, .attackEV = 252, .speedEV = 252, @@ -5038,15 +4673,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 1, .personality = 0xD, .nickname = _("DUGTRIO"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [4] = { .species = SPECIES_ELECTRODE, .heldItem = ITEM_PETAYA_BERRY, .moves = {MOVE_TORMENT, MOVE_MIRROR_COAT, MOVE_THUNDERBOLT, MOVE_LIGHT_SCREEN}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .defenseEV = 252, .spAttackEV = 6, @@ -5067,8 +4700,6 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .species = SPECIES_GENGAR, .heldItem = ITEM_FOCUS_BAND, .moves = {MOVE_CONFUSE_RAY, MOVE_MEAN_LOOK, MOVE_GIGA_DRAIN, MOVE_WILL_O_WISP}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .speedEV = 252, .spDefenseEV = 6, @@ -5082,7 +4713,7 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x14, .nickname = _("GENGAR"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, }, }, @@ -5102,8 +4733,6 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .species = SPECIES_LAPRAS, .heldItem = ITEM_QUICK_CLAW, .moves = {MOVE_SURF, MOVE_ICE_BEAM, MOVE_PERISH_SONG, MOVE_SING}, - .level = 0, - .ppBonuses = 0, .hpEV = 250, .defenseEV = 130, .spDefenseEV = 130, @@ -5124,8 +4753,6 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .species = SPECIES_ABSOL, .heldItem = ITEM_FOCUS_BAND, .moves = {MOVE_PERISH_SONG, MOVE_DOUBLE_EDGE, MOVE_PROTECT, MOVE_TORMENT}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .defenseEV = 6, .speedEV = 252, @@ -5146,8 +4773,6 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .species = SPECIES_ALTARIA, .heldItem = ITEM_KINGS_ROCK, .moves = {MOVE_PERISH_SONG, MOVE_PROTECT, MOVE_DRAGON_CLAW, MOVE_FIRE_BLAST}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .spAttackEV = 6, .spDefenseEV = 252, @@ -5168,8 +4793,6 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .species = SPECIES_DEWGONG, .heldItem = ITEM_CHESTO_BERRY, .moves = {MOVE_ICE_BEAM, MOVE_SIGNAL_BEAM, MOVE_REST, MOVE_PERISH_SONG}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .speedEV = 252, .spAttackEV = 6, @@ -5190,8 +4813,6 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .species = SPECIES_POLITOED, .heldItem = ITEM_BRIGHT_POWDER, .moves = {MOVE_HYDRO_PUMP, MOVE_BLIZZARD, MOVE_MIND_READER, MOVE_PERISH_SONG}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .spAttackEV = 6, .spDefenseEV = 252, @@ -5212,8 +4833,6 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .species = SPECIES_MAROWAK, .heldItem = ITEM_QUICK_CLAW, .moves = {MOVE_PERISH_SONG, MOVE_EARTHQUAKE, MOVE_COUNTER, MOVE_PROTECT}, - .level = 0, - .ppBonuses = 0, .hpEV = 252, .speedEV = 6, .spDefenseEV = 252, @@ -5232,7 +4851,7 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { }, }, }, - .display = { + .map = { .metatileData = { 0xD1, 0xDB, 0xDB, 0xDB, 0xD9, 0xD9, 0x1B, 0x14, 0x15, 0x98, 0x99, 0x9A, 0x9B, 0x9B, 0x9B, 0x08, 0xD1, 0xDB, 0xDB, 0xDB, 0xD5, 0xD5, 0xC3, 0xF9, 0x86, 0x8E, 0x95, 0x9B, 0x9B, 0x9B, 0x9B, 0x08, @@ -5252,9 +4871,9 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { 0xD1, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xCC, 0xFB, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x08, }, .collisionData = {0x0381, 0x0201, 0xEE1, 0x1EF1, 0x3EF9, 0x3EF9, 0x7E7D, 0x783D, 0x2BD, 0x783D, 0x7E7D, 0x3E79, 0x3EF9, 0x1EF1, 0xEE1, 0x201}, - .coords = {COORDS_XY(7,6), COORDS_XY(7,10)}, - .direction = TRAINER_DIRS(DIR_SOUTH, DIR_NORTH), - .range = TRAINER_RANGE(3, 3), + .trainerCoords = {COORDS_XY(7,6), COORDS_XY(7,10)}, + .trainerDirections = TRAINER_DIRS(DIR_SOUTH, DIR_NORTH), + .trainerRanges = TRAINER_RANGE(3, 3), } }, [3] = @@ -5279,8 +4898,6 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .species = SPECIES_FORRETRESS, .heldItem = ITEM_QUICK_CLAW, .moves = {MOVE_EXPLOSION, MOVE_EARTHQUAKE, MOVE_ATTRACT, MOVE_SPIKES}, - .level = 0, - .ppBonuses = 0, .hpEV = 110, .attackEV = 200, .spDefenseEV = 200, @@ -5294,15 +4911,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x3, .nickname = _("FORRETRESS"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_ELECTRODE, .heldItem = ITEM_SALAC_BERRY, .moves = {MOVE_EXPLOSION, MOVE_THUNDERBOLT, MOVE_SWIFT, MOVE_LIGHT_SCREEN}, - .level = 0, - .ppBonuses = 0, .attackEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -5315,15 +4930,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 1, .personality = 0xC, .nickname = _("ELECTRODE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [2] = { .species = SPECIES_EXEGGUTOR, .heldItem = ITEM_SHELL_BELL, .moves = {MOVE_EXPLOSION, MOVE_HYPNOSIS, MOVE_PSYCHIC, MOVE_SOLAR_BEAM}, - .level = 0, - .ppBonuses = 0, .attackEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -5336,15 +4949,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x7F, .nickname = _("EXEGGUTOR"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_DUSCLOPS, .heldItem = ITEM_LEFTOVERS, .moves = {MOVE_IMPRISON, MOVE_PROTECT, MOVE_ICE_BEAM, MOVE_EARTHQUAKE}, - .level = 0, - .ppBonuses = 0, .hpEV = 110, .defenseEV = 200, .spDefenseEV = 200, @@ -5358,15 +4969,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x93, .nickname = _("DUSCLOPS"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [4] = { .species = SPECIES_NINETALES, .heldItem = ITEM_WHITE_HERB, .moves = {MOVE_IMPRISON, MOVE_PROTECT, MOVE_OVERHEAT, MOVE_CONFUSE_RAY}, - .level = 0, - .ppBonuses = 0, .speedEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -5379,15 +4988,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0xF, .nickname = _("NINETALES"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [5] = { .species = SPECIES_BANETTE, .heldItem = ITEM_BRIGHT_POWDER, .moves = {MOVE_IMPRISON, MOVE_PROTECT, MOVE_THUNDERBOLT, MOVE_THUNDER}, - .level = 0, - .ppBonuses = 0, .hpEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -5400,7 +5007,7 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x96, .nickname = _("BANETTE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, }, }, @@ -5420,8 +5027,6 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .species = SPECIES_SALAMENCE, .heldItem = ITEM_SHELL_BELL, .moves = {MOVE_ROCK_SLIDE, MOVE_FLAMETHROWER, MOVE_DRAGON_CLAW, MOVE_AERIAL_ACE}, - .level = 0, - .ppBonuses = 0, .attackEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -5434,15 +5039,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x95, .nickname = _("SALAMENCE"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [1] = { .species = SPECIES_GENGAR, .heldItem = ITEM_LUM_BERRY, .moves = {MOVE_PSYCHIC, MOVE_GIGA_DRAIN, MOVE_WILL_O_WISP, MOVE_DESTINY_BOND}, - .level = 0, - .ppBonuses = 0, .speedEV = 255, .spAttackEV = 255, .otId = TRAINER_HILL_OTID, @@ -5455,15 +5058,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x8C, .nickname = _("GENGAR"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [2] = { .species = SPECIES_GYARADOS, .heldItem = ITEM_BRIGHT_POWDER, .moves = {MOVE_DRAGON_DANCE, MOVE_HYPER_BEAM, MOVE_BITE, MOVE_EARTHQUAKE}, - .level = 0, - .ppBonuses = 0, .attackEV = 255, .speedEV = 255, .otId = TRAINER_HILL_OTID, @@ -5476,15 +5077,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x3, .nickname = _("GYARADOS"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [3] = { .species = SPECIES_GENGAR, .heldItem = ITEM_SALAC_BERRY, .moves = {MOVE_EXPLOSION, MOVE_MEAN_LOOK, MOVE_SHADOW_BALL, MOVE_CONFUSE_RAY}, - .level = 0, - .ppBonuses = 0, .attackEV = 255, .speedEV = 255, .otId = TRAINER_HILL_OTID, @@ -5497,15 +5096,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x3, .nickname = _("GENGAR"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [4] = { .species = SPECIES_DUSCLOPS, .heldItem = ITEM_LEFTOVERS, .moves = {MOVE_MEAN_LOOK, MOVE_CONFUSE_RAY, MOVE_WILL_O_WISP, MOVE_SHADOW_BALL}, - .level = 0, - .ppBonuses = 0, .hpEV = 110, .defenseEV = 200, .spDefenseEV = 200, @@ -5519,15 +5116,13 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x14, .nickname = _("DUSCLOPS"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, [5] = { .species = SPECIES_MISDREAVUS, .heldItem = ITEM_FOCUS_BAND, .moves = {MOVE_MEAN_LOOK, MOVE_CONFUSE_RAY, MOVE_PERISH_SONG, MOVE_SHADOW_BALL}, - .level = 0, - .ppBonuses = 0, .hpEV = 180, .defenseEV = 180, .spDefenseEV = 150, @@ -5541,12 +5136,12 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { .abilityNum = 0, .personality = 0x85, .nickname = _("MISDREAVUS"), - .friendship = 255, + .friendship = MAX_FRIENDSHIP, }, }, }, }, - .display = { + .map = { .metatileData = { 0x31, 0x3B, 0x3B, 0x3B, 0x39, 0x39, 0x13, 0x14, 0x15, 0x39, 0x39, 0x3A, 0x3B, 0x3B, 0x3B, 0x08, 0x96, 0xFB, 0xF6, 0xFD, 0xF6, 0xF6, 0xFB, 0x46, 0xFB, 0xF6, 0xF6, 0xFD, 0xF6, 0xFB, 0x9B, 0x08, @@ -5566,9 +5161,9 @@ static const struct TrHillFloor sDataTagExpert_Floors[] = { 0x96, 0xFB, 0xF6, 0xFD, 0xF6, 0xF6, 0xFB, 0x46, 0xFB, 0xF6, 0xF6, 0xFD, 0xF6, 0xFB, 0x9B, 0x08, }, .collisionData = {0x0381, 0x0101, 0x0101, 0x6C1, 0x0821, 0x16D1, 0x2829, 0x2009, 0x1, 0x2009, 0x2829, 0x16D1, 0x0821, 0x6C1, 0x0101, 0x101}, - .coords = {COORDS_XY(7,6), COORDS_XY(7,10)}, - .direction = TRAINER_DIRS(DIR_SOUTH, DIR_NORTH), - .range = TRAINER_RANGE(3, 3), + .trainerCoords = {COORDS_XY(7,6), COORDS_XY(7,10)}, + .trainerDirections = TRAINER_DIRS(DIR_SOUTH, DIR_NORTH), + .trainerRanges = TRAINER_RANGE(3, 3), } }, }; diff --git a/src/ereader_helpers.c b/src/ereader_helpers.c index c3f17f234..ac6e0e1e1 100755 --- a/src/ereader_helpers.c +++ b/src/ereader_helpers.c @@ -57,22 +57,20 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = { .speechLose = { EC_WORD_TO_HER, EC_WORD_WIN, EC_WORD_JOKING, EC_WORD_HIGHS, EC_WORD_SCARY, EC_WORD_ELLIPSIS_EXCL }, .speechAfter = { EC_WORD_IGNORANT, EC_WORD_SO, EC_WORD_TODAY, EC_WORD_NIGHTTIME, EC_WORD_YOU_RE, EC_WORD_ELLIPSIS_ELLIPSIS_ELLIPSIS }, .mons = { - [0] = NULL_BATTLE_TOWER_POKEMON, - [1] = NULL_BATTLE_TOWER_POKEMON, - [2] = NULL_BATTLE_TOWER_POKEMON, + [0] = DUMMY_HILL_MON, + [1] = DUMMY_HILL_MON, + [2] = DUMMY_HILL_MON, [3] = { .species = SPECIES_SWALOT, .heldItem = ITEM_SHELL_BELL, .moves = { MOVE_SLUDGE_BOMB, MOVE_SHADOW_BALL, MOVE_PAIN_SPLIT, MOVE_YAWN }, - .level = 0, - .ppBonuses = 0x0, .hpEV = 55, .attackEV = 255, .defenseEV = 100, .speedEV = 0, .spAttackEV = 0, .spDefenseEV = 100, - .otId = 0x10000000, + .otId = TRAINER_HILL_OTID, .hpIV = 5, .attackIV = 5, .defenseIV = 5, @@ -82,21 +80,19 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = { .abilityNum = 1, .personality = 0x80, .nickname = __("マルノーム$$$$$$"), - .friendship = 255 + .friendship = MAX_FRIENDSHIP }, [4] = { .species = SPECIES_DUSTOX, .heldItem = ITEM_BRIGHT_POWDER, .moves = { MOVE_SILVER_WIND, MOVE_SLUDGE_BOMB, MOVE_SHADOW_BALL, MOVE_GIGA_DRAIN }, - .level = 0, - .ppBonuses = 0x0, .hpEV = 0, .attackEV = 255, .defenseEV = 0, .speedEV = 0, .spAttackEV = 255, .spDefenseEV = 0, - .otId = 0x10000000, + .otId = TRAINER_HILL_OTID, .hpIV = 5, .attackIV = 5, .defenseIV = 5, @@ -106,21 +102,19 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = { .abilityNum = 0, .personality = 0x6, .nickname = __("ドクケイル$$$$$$"), - .friendship = 255 + .friendship = MAX_FRIENDSHIP }, [5] = { .species = SPECIES_RELICANTH, .heldItem = ITEM_QUICK_CLAW, .moves = { MOVE_ANCIENT_POWER, MOVE_SURF, MOVE_EARTHQUAKE, MOVE_AMNESIA }, - .level = 0, - .ppBonuses = 0x0, .hpEV = 100, .attackEV = 0, .defenseEV = 0, .speedEV = 0, .spAttackEV = 155, .spDefenseEV = 255, - .otId = 0x10000000, + .otId = TRAINER_HILL_OTID, .hpIV = 5, .attackIV = 5, .defenseIV = 5, @@ -130,7 +124,7 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = { .abilityNum = 0, .personality = 0x2f, .nickname = __("ジーランス$$$$$$"), - .friendship = 255 + .friendship = MAX_FRIENDSHIP }, } }, @@ -143,22 +137,20 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = { .speechLose = { EC_MOVE2(MINIMIZE), EC_WORD_AS_MUCH_AS, EC_EMPTY_WORD, EC_WORD_THEY_RE, EC_WORD_SAD, EC_WORD_EXCL }, .speechAfter = { EC_MOVE(BITE), EC_WORD_AS_MUCH_AS, EC_EMPTY_WORD, EC_WORD_THEY_RE, EC_WORD_ANGRY, EC_WORD_EXCL }, .mons = { - [0] = NULL_BATTLE_TOWER_POKEMON, - [1] = NULL_BATTLE_TOWER_POKEMON, - [2] = NULL_BATTLE_TOWER_POKEMON, + [0] = DUMMY_HILL_MON, + [1] = DUMMY_HILL_MON, + [2] = DUMMY_HILL_MON, [3] = { .species = SPECIES_CACTURNE, .heldItem = ITEM_QUICK_CLAW, .moves = { MOVE_GIGA_DRAIN, MOVE_FAINT_ATTACK, MOVE_THUNDER_PUNCH, MOVE_GROWTH }, - .level = 0, - .ppBonuses = 0x0, .hpEV = 55, .attackEV = 0, .defenseEV = 100, .speedEV = 0, .spAttackEV = 255, .spDefenseEV = 100, - .otId = 0x10000000, + .otId = TRAINER_HILL_OTID, .hpIV = 5, .attackIV = 5, .defenseIV = 5, @@ -168,21 +160,19 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = { .abilityNum = 0, .personality = 0x8c, .nickname = __("ノクタス$$$$$$$"), - .friendship = 255 + .friendship = MAX_FRIENDSHIP }, [4] = { .species = SPECIES_SWELLOW, .heldItem = ITEM_BRIGHT_POWDER, .moves = { MOVE_FACADE, MOVE_AERIAL_ACE, MOVE_QUICK_ATTACK, MOVE_DOUBLE_TEAM }, - .level = 0, - .ppBonuses = 0x0, .hpEV = 255, .attackEV = 255, .defenseEV = 0, .speedEV = 0, .spAttackEV = 0, .spDefenseEV = 0, - .otId = 0x10000000, + .otId = TRAINER_HILL_OTID, .hpIV = 5, .attackIV = 5, .defenseIV = 5, @@ -192,21 +182,19 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = { .abilityNum = 0, .personality = 0x80, .nickname = __("オオスãƒ�メ$$$$$$"), - .friendship = 255 + .friendship = MAX_FRIENDSHIP }, [5] = { .species = SPECIES_WHISCASH, .heldItem = ITEM_CHESTO_BERRY, .moves = { MOVE_SURF, MOVE_EARTHQUAKE, MOVE_AMNESIA, MOVE_REST }, - .level = 0, - .ppBonuses = 0x0, .hpEV = 0, .attackEV = 255, .defenseEV = 0, .speedEV = 0, .spAttackEV = 255, .spDefenseEV = 0, - .otId = 0x10000000, + .otId = TRAINER_HILL_OTID, .hpIV = 5, .attackIV = 5, .defenseIV = 5, @@ -216,7 +204,7 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = { .abilityNum = 0, .personality = 0x0, .nickname = __("ナマズン$$$$$$$"), - .friendship = 255 + .friendship = MAX_FRIENDSHIP }, } }, @@ -229,22 +217,20 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = { .speechLose = { EC_WORD_THAT, EC_WORD_ABOVE, EC_WORD_LOST, EC_WORD_STORES, EC_WORD_JOKING, EC_WORD_ELLIPSIS_ELLIPSIS_ELLIPSIS }, .speechAfter = { EC_WORD_ENTERTAINING, EC_WORD_NONE, EC_WORD_HEY_QUES, EC_WORD_ALMOST, EC_WORD_EXCL, EC_EMPTY_WORD }, .mons = { - [0] = NULL_BATTLE_TOWER_POKEMON, - [1] = NULL_BATTLE_TOWER_POKEMON, - [2] = NULL_BATTLE_TOWER_POKEMON, + [0] = DUMMY_HILL_MON, + [1] = DUMMY_HILL_MON, + [2] = DUMMY_HILL_MON, [3] = { .species = SPECIES_DELCATTY, .heldItem = ITEM_LUM_BERRY, .moves = { MOVE_SING, MOVE_BODY_SLAM, MOVE_SHADOW_BALL, MOVE_IRON_TAIL }, - .level = 0, - .ppBonuses = 0x0, .hpEV = 0, .attackEV = 255, .defenseEV = 0, .speedEV = 255, .spAttackEV = 0, .spDefenseEV = 0, - .otId = 0x10000000, + .otId = TRAINER_HILL_OTID, .hpIV = 5, .attackIV = 5, .defenseIV = 5, @@ -254,21 +240,19 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = { .abilityNum = 0, .personality = 0x3, .nickname = __("エãƒ�コロロ$$$$$$"), - .friendship = 255 + .friendship = MAX_FRIENDSHIP }, [4] = { .species = SPECIES_ROSELIA, .heldItem = ITEM_LEFTOVERS, .moves = { MOVE_GIGA_DRAIN, MOVE_GRASS_WHISTLE, MOVE_TOXIC, MOVE_LEECH_SEED }, - .level = 0, - .ppBonuses = 0x0, .hpEV = 255, .attackEV = 0, .defenseEV = 0, .speedEV = 0, .spAttackEV = 255, .spDefenseEV = 0, - .otId = 0x10000000, + .otId = TRAINER_HILL_OTID, .hpIV = 5, .attackIV = 5, .defenseIV = 5, @@ -278,21 +262,19 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = { .abilityNum = 1, .personality = 0x6, .nickname = __("ロゼリア$$$$$$$"), - .friendship = 255 + .friendship = MAX_FRIENDSHIP }, [5] = { .species = SPECIES_BEAUTIFLY, .heldItem = ITEM_BRIGHT_POWDER, .moves = { MOVE_SILVER_WIND, MOVE_AERIAL_ACE, MOVE_ATTRACT, MOVE_PSYCHIC }, - .level = 0, - .ppBonuses = 0x0, .hpEV = 100, .attackEV = 200, .defenseEV = 0, .speedEV = 0, .spAttackEV = 200, .spDefenseEV = 0, - .otId = 0x10000000, + .otId = TRAINER_HILL_OTID, .hpIV = 5, .attackIV = 5, .defenseIV = 5, @@ -302,7 +284,7 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = { .abilityNum = 0, .personality = 0x6, .nickname = __("アゲãƒ�ント$$$$$$"), - .friendship = 255 + .friendship = MAX_FRIENDSHIP }, } }, @@ -315,22 +297,20 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = { .speechLose = { EC_WORD_OUTSIDE, EC_WORD_UNCLE, EC_WORD_SURPRISE, EC_WORD_THESE, EC_WORD_HEY_QUES, EC_WORD_ELLIPSIS_EXCL }, .speechAfter = { EC_WORD_HE_S, EC_WORD_NO_1, EC_WORD_STRONG, EC_WORD_CHILDREN, EC_WORD_CAN_T, EC_WORD_EXCL_EXCL }, .mons = { - [0] = NULL_BATTLE_TOWER_POKEMON, - [1] = NULL_BATTLE_TOWER_POKEMON, - [2] = NULL_BATTLE_TOWER_POKEMON, + [0] = DUMMY_HILL_MON, + [1] = DUMMY_HILL_MON, + [2] = DUMMY_HILL_MON, [3] = { .species = SPECIES_MAWILE, .heldItem = ITEM_BRIGHT_POWDER, .moves = { MOVE_CRUNCH, MOVE_FLAMETHROWER, MOVE_THUNDER_PUNCH, MOVE_COMET_PUNCH }, - .level = 0, - .ppBonuses = 0x0, .hpEV = 0, .attackEV = 0, .defenseEV = 100, .speedEV = 0, .spAttackEV = 255, .spDefenseEV = 155, - .otId = 0x10000000, + .otId = TRAINER_HILL_OTID, .hpIV = 5, .attackIV = 5, .defenseIV = 5, @@ -340,21 +320,19 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = { .abilityNum = 1, .personality = 0x0, .nickname = __("クãƒ�ート$$$$$$$"), - .friendship = 255 + .friendship = MAX_FRIENDSHIP }, [4] = { .species = SPECIES_SHARPEDO, .heldItem = ITEM_SCOPE_LENS, .moves = { MOVE_SURF, MOVE_CRUNCH, MOVE_DOUBLE_EDGE, MOVE_EARTHQUAKE }, - .level = 0, - .ppBonuses = 0x0, .hpEV = 255, .attackEV = 0, .defenseEV = 0, .speedEV = 0, .spAttackEV = 255, .spDefenseEV = 0, - .otId = 0x10000000, + .otId = TRAINER_HILL_OTID, .hpIV = 5, .attackIV = 5, .defenseIV = 5, @@ -364,21 +342,19 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = { .abilityNum = 0, .personality = 0x96, .nickname = __("サメãƒ�ダー$$$$$$"), - .friendship = 255 + .friendship = MAX_FRIENDSHIP }, [5] = { .species = SPECIES_BANETTE, .heldItem = ITEM_LUM_BERRY, .moves = { MOVE_PSYCHIC, MOVE_SHADOW_BALL, MOVE_THUNDERBOLT, MOVE_WILL_O_WISP }, - .level = 0, - .ppBonuses = 0x0, .hpEV = 255, .attackEV = 0, .defenseEV = 0, .speedEV = 0, .spAttackEV = 255, .spDefenseEV = 0, - .otId = 0x10000000, + .otId = TRAINER_HILL_OTID, .hpIV = 5, .attackIV = 5, .defenseIV = 5, @@ -388,7 +364,7 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = { .abilityNum = 0, .personality = 0x96, .nickname = __("ジュペッタ$$$$$$"), - .friendship = 255 + .friendship = MAX_FRIENDSHIP }, } }, @@ -447,40 +423,40 @@ static bool32 ValidateTrainerHillChecksum(struct EReaderTrainerHillSet *hillSet) return TRUE; } -static bool32 TryWriteTrainerHill_Internal(struct EReaderTrainerHillSet * hillSet, struct TrHillTag * hillTag) +static bool32 TryWriteTrainerHill_Internal(struct EReaderTrainerHillSet * hillSet, struct TrainerHillChallenge * challenge) { int i; AGB_ASSERT_EX(hillSet->dummy == 0, "cereader_tool.c", 450); AGB_ASSERT_EX(hillSet->id == 0, "cereader_tool.c", 452); - memset(hillTag, 0, SECTOR_SIZE); - hillTag->numTrainers = hillSet->numTrainers; - hillTag->unused1 = GetTrainerHillUnkVal(); - hillTag->numFloors = (hillSet->numTrainers + 1) / TRAINER_HILL_TRAINERS_PER_FLOOR; + memset(challenge, 0, SECTOR_SIZE); + challenge->numTrainers = hillSet->numTrainers; + challenge->unused1 = GetTrainerHillUnkVal(); + challenge->numFloors = (hillSet->numTrainers + 1) / HILL_TRAINERS_PER_FLOOR; for (i = 0; i < hillSet->numTrainers; i++) { if (!(i & 1)) { - hillTag->floors[i / TRAINER_HILL_TRAINERS_PER_FLOOR].trainerNum1 = hillSet->trainers[i].trainerNum; - hillTag->floors[i / TRAINER_HILL_TRAINERS_PER_FLOOR].display = hillSet->trainers[i].display; - hillTag->floors[i / TRAINER_HILL_TRAINERS_PER_FLOOR].trainers[0] = hillSet->trainers[i].trainer; + challenge->floors[i / HILL_TRAINERS_PER_FLOOR].trainerNum1 = hillSet->trainers[i].trainerNum; + challenge->floors[i / HILL_TRAINERS_PER_FLOOR].map = hillSet->trainers[i].map; + challenge->floors[i / HILL_TRAINERS_PER_FLOOR].trainers[0] = hillSet->trainers[i].trainer; } else { - hillTag->floors[i / TRAINER_HILL_TRAINERS_PER_FLOOR].trainerNum2 = hillSet->trainers[i].trainerNum; - hillTag->floors[i / TRAINER_HILL_TRAINERS_PER_FLOOR].trainers[1] = hillSet->trainers[i].trainer; + challenge->floors[i / HILL_TRAINERS_PER_FLOOR].trainerNum2 = hillSet->trainers[i].trainerNum; + challenge->floors[i / HILL_TRAINERS_PER_FLOOR].trainers[1] = hillSet->trainers[i].trainer; } } if (i & 1) { - hillTag->floors[i / TRAINER_HILL_TRAINERS_PER_FLOOR].trainers[1] = sTrainerHillTrainerTemplates_JP[i / TRAINER_HILL_TRAINERS_PER_FLOOR]; + challenge->floors[i / HILL_TRAINERS_PER_FLOOR].trainers[1] = sTrainerHillTrainerTemplates_JP[i / HILL_TRAINERS_PER_FLOOR]; } - hillTag->checksum = CalcByteArraySum((u8 *)hillTag->floors, NUM_TRAINER_HILL_FLOORS * sizeof(struct TrHillFloor)); - if (TryWriteSpecialSaveSector(SECTOR_ID_TRAINER_HILL, (u8 *)hillTag) != SAVE_STATUS_OK) + challenge->checksum = CalcByteArraySum((u8 *)challenge->floors, NUM_TRAINER_HILL_FLOORS * sizeof(struct TrainerHillFloor)); + if (TryWriteSpecialSaveSector(SECTOR_ID_TRAINER_HILL, (u8 *)challenge) != SAVE_STATUS_OK) return FALSE; return TRUE; diff --git a/src/trainer_hill.c b/src/trainer_hill.c index 39c6202a0..2deacfc70 100644 --- a/src/trainer_hill.c +++ b/src/trainer_hill.c @@ -32,23 +32,21 @@ #include "constants/trainer_hill.h" #include "constants/trainer_types.h" -#define HILL_TAG_NORMAL 0 -#define HILL_TAG_VARIETY 1 -#define HILL_TAG_UNIQUE 2 -#define HILL_TAG_EXPERT 3 - #define HILL_MAX_TIME 215999 // 60 * 60 * 60 - 1 -// EWRAM -struct TrHillStruct2 +struct FloorTrainers { - u8 floorId; - struct TrHillTag tag; - struct TrHillFloor floors[NUM_TRAINER_HILL_FLOORS]; + u8 name[HILL_TRAINERS_PER_FLOOR][HILL_TRAINER_NAME_LENGTH]; + u8 facilityClass[HILL_TRAINERS_PER_FLOOR]; }; -static EWRAM_DATA struct TrHillStruct2 *sHillData = NULL; -static EWRAM_DATA struct TrHillRoomTrainers *sRoomTrainers = NULL; +static EWRAM_DATA struct { + u8 floorId; + struct TrainerHillChallenge challenge; + struct TrainerHillFloor floors[NUM_TRAINER_HILL_FLOORS]; +} *sHillData = NULL; + +static EWRAM_DATA struct FloorTrainers *sFloorTrainers = NULL; EWRAM_DATA u32 *gTrainerHillVBlankCounter = NULL; // This file's functions. @@ -69,7 +67,7 @@ static void GetGameSaved(void); static void SetGameSaved(void); static void ClearGameSaved(void); static void GetChallengeWon(void); -static void TrainerHillSetTag(void); +static void TrainerHillSetMode(void); static void SetUpDataStruct(void); static void FreeDataStruct(void); static void TrainerHillDummy(void); @@ -202,12 +200,12 @@ static const u16 *const *const sPrizeListSets[] = static const u16 sEReader_Pal[] = INCBIN_U16("graphics/trainer_hill/ereader.gbapal"); static const u8 sRecordWinColors[] = {TEXT_COLOR_TRANSPARENT, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_LIGHT_GRAY}; -static const struct TrHillTag *const sDataPerTag[] = +static const struct TrainerHillChallenge *const sChallengeData[NUM_TRAINER_HILL_MODES] = { - &sDataTagNormal, - &sDataTagVariety, - &sDataTagUnique, - &sDataTagExpert, + [HILL_MODE_NORMAL] = &sChallenge_Normal, + [HILL_MODE_VARIETY] = &sChallenge_Variety, + [HILL_MODE_UNIQUE] = &sChallenge_Unique, + [HILL_MODE_EXPERT] = &sChallenge_Expert, }; // Unused. @@ -238,15 +236,15 @@ static void (* const sHillFunctions[])(void) = [TRAINER_HILL_FUNC_SET_GAME_SAVED] = SetGameSaved, [TRAINER_HILL_FUNC_CLEAR_GAME_SAVED] = ClearGameSaved, [TRAINER_HILL_FUNC_GET_WON] = GetChallengeWon, - [TRAINER_HILL_FUNC_SET_TAG] = TrainerHillSetTag, + [TRAINER_HILL_FUNC_SET_MODE] = TrainerHillSetMode, }; -static const u8 *const sTagMatchStrings[] = +static const u8 *const sModeStrings[NUM_TRAINER_HILL_MODES] = { - gText_NormalTagMatch, - gText_VarietyTagMatch, - gText_UniqueTagMatch, - gText_ExpertTagMatch, + [HILL_MODE_NORMAL] = gText_NormalTagMatch, + [HILL_MODE_VARIETY] = gText_VarietyTagMatch, + [HILL_MODE_UNIQUE] = gText_UniqueTagMatch, + [HILL_MODE_EXPERT] = gText_ExpertTagMatch, }; static const struct ObjectEventTemplate sTrainerObjectEventTemplate = @@ -261,18 +259,17 @@ static const struct ObjectEventTemplate sTrainerObjectEventTemplate = static const u32 sNextFloorMapNum[NUM_TRAINER_HILL_FLOORS] = { - MAP_NUM(TRAINER_HILL_2F), - MAP_NUM(TRAINER_HILL_3F), - MAP_NUM(TRAINER_HILL_4F), - MAP_NUM(TRAINER_HILL_ROOF) + [TRAINER_HILL_1F - 1] = MAP_NUM(TRAINER_HILL_2F), + [TRAINER_HILL_2F - 1] = MAP_NUM(TRAINER_HILL_3F), + [TRAINER_HILL_3F - 1] = MAP_NUM(TRAINER_HILL_4F), + [TRAINER_HILL_4F - 1] = MAP_NUM(TRAINER_HILL_ROOF) }; -static const u8 sTrainerPartySlots[][PARTY_SIZE / 2] = +static const u8 sTrainerPartySlots[HILL_TRAINERS_PER_FLOOR][PARTY_SIZE / 2] = { {0, 1, 2}, {3, 4, 5} }; -// code void CallTrainerHillFunction(void) { SetUpDataStruct(); @@ -287,7 +284,7 @@ void ResetTrainerHillResults(void) gSaveBlock2Ptr->frontier.savedGame = 0; gSaveBlock2Ptr->frontier.unk_EF9 = 0; gSaveBlock1Ptr->trainerHill.bestTime = 0; - for (i = 0; i < 4; i++) + for (i = 0; i < NUM_TRAINER_HILL_MODES; i++) SetTimerValue(&gSaveBlock1Ptr->trainerHillTimes[i], HILL_MAX_TIME); } @@ -300,7 +297,7 @@ u8 GetTrainerHillOpponentClass(u16 trainerId) { u8 id = trainerId - 1; - return gFacilityClassToTrainerClass[sRoomTrainers->facilityClass[id]]; + return gFacilityClassToTrainerClass[sFloorTrainers->facilityClass[id]]; } void GetTrainerHillTrainerName(u8 *dst, u16 trainerId) @@ -309,7 +306,7 @@ void GetTrainerHillTrainerName(u8 *dst, u16 trainerId) u8 id = trainerId - 1; for (i = 0; i < HILL_TRAINER_NAME_LENGTH; i++) - dst[i] = sRoomTrainers->name[id][i]; + dst[i] = sFloorTrainers->name[id][i]; } u8 GetTrainerHillTrainerFrontSpriteId(u16 trainerId) @@ -329,15 +326,14 @@ void InitTrainerHillBattleStruct(void) s32 i, j; SetUpDataStruct(); - sRoomTrainers = AllocZeroed(sizeof(*sRoomTrainers)); + sFloorTrainers = AllocZeroed(sizeof(*sFloorTrainers)); - for (i = 0; i < 2; i++) + for (i = 0; i < HILL_TRAINERS_PER_FLOOR; i++) { for (j = 0; j < HILL_TRAINER_NAME_LENGTH; j++) - { - sRoomTrainers->name[i][j] = sHillData->floors[sHillData->floorId].trainers[i].name[j]; - } - sRoomTrainers->facilityClass[i] = sHillData->floors[sHillData->floorId].trainers[i].facilityClass; + sFloorTrainers->name[i][j] = sHillData->floors[sHillData->floorId].trainers[i].name[j]; + + sFloorTrainers->facilityClass[i] = sHillData->floors[sHillData->floorId].trainers[i].facilityClass; } SetTrainerHillVBlankCounter(&gSaveBlock1Ptr->trainerHill.timer); FreeDataStruct(); @@ -345,8 +341,7 @@ void InitTrainerHillBattleStruct(void) void FreeTrainerHillBattleStruct(void) { - if (sRoomTrainers != NULL) - FREE_AND_SET_NULL(sRoomTrainers); + TRY_FREE_AND_SET_NULL(sFloorTrainers); } static void SetUpDataStruct(void) @@ -355,15 +350,20 @@ static void SetUpDataStruct(void) { sHillData = AllocZeroed(sizeof(*sHillData)); sHillData->floorId = gMapHeader.mapLayoutId - LAYOUT_TRAINER_HILL_1F; - CpuCopy32(sDataPerTag[gSaveBlock1Ptr->trainerHill.tag], &sHillData->tag, sizeof(sHillData->tag) + 4 * sizeof(struct TrHillFloor)); + + // This copy depends on the floor data for each challenge being directly after the + // challenge header data, and for the field 'floors' in sHillData to come directly + // after the field 'challenge'. + // e.g. for HILL_MODE_NORMAL, it will copy sChallenge_Normal to sHillData->challenge and + // it will copy sFloors_Normal to sHillData->floors + CpuCopy32(sChallengeData[gSaveBlock1Ptr->trainerHill.mode], &sHillData->challenge, sizeof(sHillData->challenge) + sizeof(sHillData->floors)); TrainerHillDummy(); } } static void FreeDataStruct(void) { - if (sHillData != NULL) - FREE_AND_SET_NULL(sHillData); + TRY_FREE_AND_SET_NULL(sHillData); } void CopyTrainerHillTrainerText(u8 which, u16 trainerId) @@ -428,7 +428,7 @@ static void GiveChallengePrize(void) { u16 itemId = GetPrizeItemId(); - if (sHillData->tag.numFloors != NUM_TRAINER_HILL_FLOORS || gSaveBlock1Ptr->trainerHill.receivedPrize) + if (sHillData->challenge.numFloors != NUM_TRAINER_HILL_FLOORS || gSaveBlock1Ptr->trainerHill.receivedPrize) { gSpecialVar_Result = 2; } @@ -456,7 +456,7 @@ static void CheckFinalTime(void) else if (GetTimerValue(&gSaveBlock1Ptr->trainerHill.bestTime) > gSaveBlock1Ptr->trainerHill.timer) { SetTimerValue(&gSaveBlock1Ptr->trainerHill.bestTime, gSaveBlock1Ptr->trainerHill.timer); - gSaveBlock1Ptr->trainerHillTimes[gSaveBlock1Ptr->trainerHill.tag] = gSaveBlock1Ptr->trainerHill.bestTime; + gSaveBlock1Ptr->trainerHillTimes[gSaveBlock1Ptr->trainerHill.mode] = gSaveBlock1Ptr->trainerHill.bestTime; gSpecialVar_Result = 0; } else @@ -529,9 +529,9 @@ static void BufferChallengeTime(void) static void GetAllFloorsUsed(void) { SetUpDataStruct(); - if (sHillData->tag.numFloors != NUM_TRAINER_HILL_FLOORS) + if (sHillData->challenge.numFloors != NUM_TRAINER_HILL_FLOORS) { - ConvertIntToDecimalStringN(gStringVar1, sHillData->tag.numFloors, STR_CONV_MODE_LEFT_ALIGN, 1); + ConvertIntToDecimalStringN(gStringVar1, sHillData->challenge.numFloors, STR_CONV_MODE_LEFT_ALIGN, 1); gSpecialVar_Result = FALSE; } else @@ -592,9 +592,9 @@ void PrintOnTrainerHillRecordsWindow(void) AddTextPrinterParameterized3(0, FONT_NORMAL, x, 2, sRecordWinColors, TEXT_SKIP_DRAW, gText_TimeBoard); y = 18; - for (i = 0; i < 4; i++) + for (i = 0; i < NUM_TRAINER_HILL_MODES; i++) { - AddTextPrinterParameterized3(0, FONT_NORMAL, 0, y, sRecordWinColors, TEXT_SKIP_DRAW, sTagMatchStrings[i]); + AddTextPrinterParameterized3(0, FONT_NORMAL, 0, y, sRecordWinColors, TEXT_SKIP_DRAW, sModeStrings[i]); y += 15; total = GetTimerValue(&gSaveBlock1Ptr->trainerHillTimes[i]); minutes = total / (60 * 60); @@ -637,23 +637,23 @@ void LoadTrainerHillObjectEventTemplates(void) return; SetUpDataStruct(); - for (i = 0; i < 2; i++) + for (i = 0; i < HILL_TRAINERS_PER_FLOOR; i++) gSaveBlock2Ptr->frontier.trainerIds[i] = 0xFFFF; CpuFill32(0, gSaveBlock1Ptr->objectEventTemplates, sizeof(gSaveBlock1Ptr->objectEventTemplates)); floorId = GetFloorId(); - for (i = 0; i < 2; i++) + for (i = 0; i < HILL_TRAINERS_PER_FLOOR; i++) { u8 bits; eventTemplates[i] = sTrainerObjectEventTemplate; eventTemplates[i].localId = i + 1; eventTemplates[i].graphicsId = FacilityClassToGraphicsId(sHillData->floors[floorId].trainers[i].facilityClass); - eventTemplates[i].x = sHillData->floors[floorId].display.coords[i] & 0xF; - eventTemplates[i].y = ((sHillData->floors[floorId].display.coords[i] >> 4) & 0xF) + 5; + eventTemplates[i].x = sHillData->floors[floorId].map.trainerCoords[i] & 0xF; + eventTemplates[i].y = ((sHillData->floors[floorId].map.trainerCoords[i] >> 4) & 0xF) + 5; bits = i << 2; - eventTemplates[i].movementType = ((sHillData->floors[floorId].display.direction >> bits) & 0xF) + MOVEMENT_TYPE_FACE_UP; - eventTemplates[i].trainerRange_berryTreeId = (sHillData->floors[floorId].display.range >> bits) & 0xF; + eventTemplates[i].movementType = ((sHillData->floors[floorId].map.trainerDirections >> bits) & 0xF) + MOVEMENT_TYPE_FACE_UP; + eventTemplates[i].trainerRange_berryTreeId = (sHillData->floors[floorId].map.trainerRanges >> bits) & 0xF; eventTemplates[i].script = TrainerHill_EventScript_TrainerBattle; gSaveBlock2Ptr->frontier.trainerIds[i] = i + 1; } @@ -669,14 +669,14 @@ bool32 LoadTrainerHillFloorObjectEventScripts(void) return TRUE; } -static u16 GetMetatileForFloor(u8 floorId, u32 x, u32 y, u32 stride) // stride is always 16 +static u16 GetMetatileForFloor(u8 floorId, u32 x, u32 y, u32 floorWidth) // floorWidth is always 16 { bool8 impassable; u16 metatile; u16 elevation; - impassable = (sHillData->floors[floorId].display.collisionData[y] >> (15 - x) & 1); - metatile = sHillData->floors[floorId].display.metatileData[stride * y + x] + NUM_METATILES_IN_PRIMARY; + impassable = (sHillData->floors[floorId].map.collisionData[y] >> (15 - x) & 1); + metatile = sHillData->floors[floorId].map.metatileData[floorWidth * y + x] + NUM_METATILES_IN_PRIMARY; elevation = 3 << MAPGRID_ELEVATION_SHIFT; return ((impassable << MAPGRID_COLLISION_SHIFT) & MAPGRID_COLLISION_MASK) | elevation | (metatile & MAPGRID_METATILE_ID_MASK); @@ -684,7 +684,7 @@ static u16 GetMetatileForFloor(u8 floorId, u32 x, u32 y, u32 stride) // stride i void GenerateTrainerHillFloorLayout(u16 *mapArg) { - s32 i, j; + s32 y, x; u16 *src, *dst; u8 mapId = GetCurrentTrainerHillMapId(); @@ -705,24 +705,25 @@ void GenerateTrainerHillFloorLayout(u16 *mapArg) mapId = GetFloorId(); src = gMapHeader.mapLayout->map; gBackupMapLayout.map = mapArg; - gBackupMapLayout.width = 31; - gBackupMapLayout.height = 35; + // Dimensions include border area loaded beyond map + gBackupMapLayout.width = HILL_FLOOR_WIDTH + 15; + gBackupMapLayout.height = HILL_FLOOR_HEIGHT + 14; dst = mapArg + 224; // First 5 rows of the map (Entrance / Exit) are always the same - for (i = 0; i < 5; i++) + for (y = 0; y < HILL_FLOOR_HEIGHT_MARGIN; y++) { - for (j = 0; j < 16; j++) - dst[j] = src[j]; + for (x = 0; x < HILL_FLOOR_WIDTH; x++) + dst[x] = src[x]; dst += 31; src += 16; } // Load the 16x16 floor-specific layout - for (i = 0; i < 16; i++) + for (y = 0; y < HILL_FLOOR_HEIGHT_MAIN; y++) { - for (j = 0; j < 16; j++) - dst[j] = GetMetatileForFloor(mapId, j, i, 16); + for (x = 0; x < HILL_FLOOR_WIDTH; x++) + dst[x] = GetMetatileForFloor(mapId, x, y, HILL_FLOOR_WIDTH); dst += 31; } @@ -812,8 +813,8 @@ u16 LocalIdToHillTrainerId(u8 localId) bool8 GetHillTrainerFlag(u8 objectEventId) { - u32 floorId = GetFloorId() * 2; - u8 bitId = gObjectEvents[objectEventId].localId - 1 + floorId; + u32 trainerIndexStart = GetFloorId() * HILL_TRAINERS_PER_FLOOR; + u8 bitId = gObjectEvents[objectEventId].localId - 1 + trainerIndexStart; return gSaveBlock2Ptr->frontier.trainerFlags & gBitTable[bitId]; } @@ -821,24 +822,24 @@ bool8 GetHillTrainerFlag(u8 objectEventId) void SetHillTrainerFlag(void) { u8 i; - u8 floorId = GetFloorId() * 2; + u8 trainerIndexStart = GetFloorId() * HILL_TRAINERS_PER_FLOOR; - for (i = 0; i < 2; i++) + for (i = 0; i < HILL_TRAINERS_PER_FLOOR; i++) { if (gSaveBlock2Ptr->frontier.trainerIds[i] == gTrainerBattleOpponent_A) { - gSaveBlock2Ptr->frontier.trainerFlags |= gBitTable[floorId + i]; + gSaveBlock2Ptr->frontier.trainerFlags |= gBitTable[trainerIndexStart + i]; break; } } if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) { - for (i = 0; i < 2; i++) + for (i = 0; i < HILL_TRAINERS_PER_FLOOR; i++) { if (gSaveBlock2Ptr->frontier.trainerIds[i] == gTrainerBattleOpponent_B) { - gSaveBlock2Ptr->frontier.trainerFlags |= gBitTable[floorId + i]; + gSaveBlock2Ptr->frontier.trainerFlags |= gBitTable[trainerIndexStart + i]; break; } } @@ -861,14 +862,14 @@ static void CreateNPCTrainerHillParty(u16 trainerId, u8 firstMonId) u8 trId, level; s32 i, floorId, partySlot; - if (trainerId == 0 || trainerId > 2) + if (trainerId == 0 || trainerId > HILL_TRAINERS_PER_FLOOR) return; trId = trainerId - 1; SetUpDataStruct(); level = GetHighestLevelInPlayerParty(); floorId = GetFloorId(); - for (i = firstMonId, partySlot = 0; i < firstMonId + 3; i++, partySlot++) + for (i = firstMonId, partySlot = 0; i < firstMonId + PARTY_SIZE / 2; i++, partySlot++) { u8 id = sTrainerPartySlots[trId][partySlot]; struct Pokemon *mon = &gEnemyParty[i]; @@ -890,7 +891,7 @@ void FillHillTrainersParties(void) { ZeroEnemyPartyMons(); CreateNPCTrainerHillParty(gTrainerBattleOpponent_A, 0); - CreateNPCTrainerHillParty(gTrainerBattleOpponent_B, 3); + CreateNPCTrainerHillParty(gTrainerBattleOpponent_B, PARTY_SIZE / 2); } // This function is unused, but my best guess is @@ -935,7 +936,7 @@ u8 GetNumFloorsInTrainerHillChallenge(void) u8 floors; SetUpDataStruct(); - floors = sHillData->tag.numFloors; + floors = sHillData->challenge.numFloors; FreeDataStruct(); return floors; @@ -989,9 +990,9 @@ static void GetChallengeWon(void) gSpecialVar_Result = TRUE; } -static void TrainerHillSetTag(void) +static void TrainerHillSetMode(void) { - gSaveBlock1Ptr->trainerHill.tag = gSpecialVar_0x8005; + gSaveBlock1Ptr->trainerHill.mode = gSpecialVar_0x8005; gSaveBlock1Ptr->trainerHill.bestTime = gSaveBlock1Ptr->trainerHillTimes[gSpecialVar_0x8005]; } @@ -1030,12 +1031,12 @@ static u16 GetPrizeItemId(void) prizeListSetId = var / 256; prizeListSetId %= 2; - if (FlagGet(FLAG_SYS_GAME_CLEAR) && sHillData->tag.numTrainers == NUM_TRAINER_HILL_TRAINERS) + if (FlagGet(FLAG_SYS_GAME_CLEAR) && sHillData->challenge.numTrainers == NUM_TRAINER_HILL_TRAINERS) i = GetPrizeListId(TRUE); else i = GetPrizeListId(FALSE); - if (gSaveBlock1Ptr->trainerHill.tag == HILL_TAG_EXPERT) + if (gSaveBlock1Ptr->trainerHill.mode == HILL_MODE_EXPERT) i = (i + 1) % NUM_TRAINER_HILL_PRIZE_LISTS; prizeList = sPrizeListSets[prizeListSetId][i]; From 328b925a08c3dfc47ebd49b7b8f9db2822790e34 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Thu, 31 Mar 2022 13:11:44 -0400 Subject: [PATCH 060/130] Move trainer hill map data to bin files --- .../maps_expert/floor_0/collision.bin | Bin 0 -> 32 bytes .../maps_expert/floor_0/metatiles.bin | 1 + .../maps_expert/floor_1/collision.bin | Bin 0 -> 32 bytes .../maps_expert/floor_1/metatiles.bin | 1 + .../maps_expert/floor_2/collision.bin | 1 + .../maps_expert/floor_2/metatiles.bin | 1 + .../maps_expert/floor_3/collision.bin | Bin 0 -> 32 bytes .../maps_expert/floor_3/metatiles.bin | 1 + .../maps_jp/floor_0/collision.bin | 1 + .../maps_jp/floor_0/metatiles.bin | 1 + .../maps_jp/floor_1/collision.bin | Bin 0 -> 32 bytes .../maps_jp/floor_1/metatiles.bin | 1 + .../maps_normal/floor_0/collision.bin | 1 + .../maps_normal/floor_0/metatiles.bin | 1 + .../maps_normal/floor_1/collision.bin | 1 + .../maps_normal/floor_1/metatiles.bin | 1 + .../maps_normal/floor_2/collision.bin | Bin 0 -> 32 bytes .../maps_normal/floor_2/metatiles.bin | 1 + .../maps_normal/floor_3/collision.bin | Bin 0 -> 32 bytes .../maps_normal/floor_3/metatiles.bin | 1 + .../maps_unique/floor_0/collision.bin | Bin 0 -> 32 bytes .../maps_unique/floor_0/metatiles.bin | 1 + .../maps_unique/floor_1/collision.bin | Bin 0 -> 32 bytes .../maps_unique/floor_1/metatiles.bin | 1 + .../maps_unique/floor_2/collision.bin | Bin 0 -> 32 bytes .../maps_unique/floor_2/metatiles.bin | 1 + .../maps_unique/floor_3/collision.bin | Bin 0 -> 32 bytes .../maps_unique/floor_3/metatiles.bin | 1 + .../maps_variety/floor_0/collision.bin | Bin 0 -> 32 bytes .../maps_variety/floor_0/metatiles.bin | 1 + .../maps_variety/floor_1/collision.bin | Bin 0 -> 32 bytes .../maps_variety/floor_1/metatiles.bin | 1 + .../maps_variety/floor_2/collision.bin | Bin 0 -> 32 bytes .../maps_variety/floor_2/metatiles.bin | 1 + .../maps_variety/floor_3/collision.bin | Bin 0 -> 32 bytes .../maps_variety/floor_3/metatiles.bin | 1 + include/trainer_hill.h | 2 +- src/data/battle_frontier/trainer_hill.h | 432 ++---------------- 38 files changed, 63 insertions(+), 393 deletions(-) create mode 100755 graphics/trainer_hill/maps_expert/floor_0/collision.bin create mode 100755 graphics/trainer_hill/maps_expert/floor_0/metatiles.bin create mode 100755 graphics/trainer_hill/maps_expert/floor_1/collision.bin create mode 100755 graphics/trainer_hill/maps_expert/floor_1/metatiles.bin create mode 100755 graphics/trainer_hill/maps_expert/floor_2/collision.bin create mode 100755 graphics/trainer_hill/maps_expert/floor_2/metatiles.bin create mode 100755 graphics/trainer_hill/maps_expert/floor_3/collision.bin create mode 100755 graphics/trainer_hill/maps_expert/floor_3/metatiles.bin create mode 100755 graphics/trainer_hill/maps_jp/floor_0/collision.bin create mode 100755 graphics/trainer_hill/maps_jp/floor_0/metatiles.bin create mode 100755 graphics/trainer_hill/maps_jp/floor_1/collision.bin create mode 100755 graphics/trainer_hill/maps_jp/floor_1/metatiles.bin create mode 100755 graphics/trainer_hill/maps_normal/floor_0/collision.bin create mode 100755 graphics/trainer_hill/maps_normal/floor_0/metatiles.bin create mode 100755 graphics/trainer_hill/maps_normal/floor_1/collision.bin create mode 100755 graphics/trainer_hill/maps_normal/floor_1/metatiles.bin create mode 100755 graphics/trainer_hill/maps_normal/floor_2/collision.bin create mode 100755 graphics/trainer_hill/maps_normal/floor_2/metatiles.bin create mode 100755 graphics/trainer_hill/maps_normal/floor_3/collision.bin create mode 100755 graphics/trainer_hill/maps_normal/floor_3/metatiles.bin create mode 100755 graphics/trainer_hill/maps_unique/floor_0/collision.bin create mode 100755 graphics/trainer_hill/maps_unique/floor_0/metatiles.bin create mode 100755 graphics/trainer_hill/maps_unique/floor_1/collision.bin create mode 100755 graphics/trainer_hill/maps_unique/floor_1/metatiles.bin create mode 100755 graphics/trainer_hill/maps_unique/floor_2/collision.bin create mode 100755 graphics/trainer_hill/maps_unique/floor_2/metatiles.bin create mode 100755 graphics/trainer_hill/maps_unique/floor_3/collision.bin create mode 100755 graphics/trainer_hill/maps_unique/floor_3/metatiles.bin create mode 100755 graphics/trainer_hill/maps_variety/floor_0/collision.bin create mode 100755 graphics/trainer_hill/maps_variety/floor_0/metatiles.bin create mode 100755 graphics/trainer_hill/maps_variety/floor_1/collision.bin create mode 100755 graphics/trainer_hill/maps_variety/floor_1/metatiles.bin create mode 100755 graphics/trainer_hill/maps_variety/floor_2/collision.bin create mode 100755 graphics/trainer_hill/maps_variety/floor_2/metatiles.bin create mode 100755 graphics/trainer_hill/maps_variety/floor_3/collision.bin create mode 100755 graphics/trainer_hill/maps_variety/floor_3/metatiles.bin diff --git a/graphics/trainer_hill/maps_expert/floor_0/collision.bin b/graphics/trainer_hill/maps_expert/floor_0/collision.bin new file mode 100755 index 0000000000000000000000000000000000000000..ca6e4ca28beaf070d34dedbd697149620da6ea68 GIT binary patch literal 32 ecmZo0f}Z{gu?&-0mT0byZ`_I literal 0 HcmV?d00001 diff --git a/graphics/trainer_hill/maps_expert/floor_1/metatiles.bin b/graphics/trainer_hill/maps_expert/floor_1/metatiles.bin new file mode 100755 index 000000000..a89a14c69 --- /dev/null +++ b/graphics/trainer_hill/maps_expert/floor_1/metatiles.bin @@ -0,0 +1 @@ +1;;;9989:;;;‘FFFFFFFFFFFFFx‘F›|›››}›|›{›z›‘F}FFFFFFFFFFFF‘F›~›››}›~›³›››‘FFFFFFFFFFFFF›‘F›}›|›{›z›|›››‘F›FFFFFFFFFFFF‘F›|›}›~›››}›~›‘FFFFFFFFFFFFF³‘Ö–››–ÖÛÖ–››–Ö›Ö–››–ÖÛÛÛÖ–››–Ö–››–ÖÛÛÛÛÛÖ–››–Ö–››–ÖÛÛÛÖ–››–Ö‘Ö–››–ÖÛÖ–››–Ö› \ No newline at end of file diff --git a/graphics/trainer_hill/maps_expert/floor_2/collision.bin b/graphics/trainer_hill/maps_expert/floor_2/collision.bin new file mode 100755 index 000000000..891a7f2c1 --- /dev/null +++ b/graphics/trainer_hill/maps_expert/floor_2/collision.bin @@ -0,0 +1 @@ +�áñù>ù>}~=x½=x}~y>ù>ñá \ No newline at end of file diff --git a/graphics/trainer_hill/maps_expert/floor_2/metatiles.bin b/graphics/trainer_hill/maps_expert/floor_2/metatiles.bin new file mode 100755 index 000000000..7164f059d --- /dev/null +++ b/graphics/trainer_hill/maps_expert/floor_2/metatiles.bin @@ -0,0 +1 @@ +ÑÛÛÛÙÙ˜™š›››ÑÛÛÛÕÕÃù†Ž•››››ÑÛÛÕËËËû‹‹‹•›››ÑÛÕËËËËû‹‹‹‹•››ÑÛËËËËËû‹‹‹‹‹››ÑÕËËËËËûŒ‹‹‹‹•›ÑËËËËÌÌûûŒ‹‹‹‹›ÑÌÌÌÌûõûõû‹‹‹‹›ÑÕÕÕÕûìûìû‹‹‹‹›ÑËËËËõõûûõ‹‹‹‹›ÑÌËËËËËûû‹‹‹‹Œ›ÑÛËËËËËûõ‹‹‹‹››ÑÛÌËËËËû‹‹‹‹Œ››ÑÛÛÌËËËû‹‹‹Œ›››ÑÛÛÛÌÌËûŒŒŒ››››ÑÛÛÛÛÛÌû››››››› \ No newline at end of file diff --git a/graphics/trainer_hill/maps_expert/floor_3/collision.bin b/graphics/trainer_hill/maps_expert/floor_3/collision.bin new file mode 100755 index 0000000000000000000000000000000000000000..3d25428f1569114f61521dfb75a0b10efeaee5ba GIT binary patch literal 32 kcmZoFHg#WXcI6&M*f6*M(2iYam&WCO_n09tVcFaQ7m literal 0 HcmV?d00001 diff --git a/graphics/trainer_hill/maps_expert/floor_3/metatiles.bin b/graphics/trainer_hill/maps_expert/floor_3/metatiles.bin new file mode 100755 index 000000000..f2200b713 --- /dev/null +++ b/graphics/trainer_hill/maps_expert/floor_3/metatiles.bin @@ -0,0 +1 @@ +1;;;9999:;;;–ûöýööûFûööýöû›û›ûöûûûFûûûöû›ûöû›ûûFF›FFûû›ûöýöû›F66›66F›ûöýöûûF›FFÛFF›FûûööûF6F›ÛÖÛ›F6FûöûûF6›ÛÖÖÖÛ›6Fûû–››››ÖÖ–ÖÖÛ›››–ûûF6›ÛÖÖÖÛ›6FûûöûF6F›ÛÖÛ›F6FûööûûF›FFÛFF›Fûûöýöû›F66›66F›ûöýöû›ûûFF›FFûû›ûöû›ûöûûûFûûûöû›û–ûöýööûFûööýöû› \ No newline at end of file diff --git a/graphics/trainer_hill/maps_jp/floor_0/collision.bin b/graphics/trainer_hill/maps_jp/floor_0/collision.bin new file mode 100755 index 000000000..817f4f54c --- /dev/null +++ b/graphics/trainer_hill/maps_jp/floor_0/collision.bin @@ -0,0 +1 @@ +�ÁoAcA`ADAUAUÁÿÿÿÿÿÿÿÿÿÿÿÿÿÿ \ No newline at end of file diff --git a/graphics/trainer_hill/maps_jp/floor_0/metatiles.bin b/graphics/trainer_hill/maps_jp/floor_0/metatiles.bin new file mode 100755 index 000000000..8d1787efd --- /dev/null +++ b/graphics/trainer_hill/maps_jp/floor_0/metatiles.bin @@ -0,0 +1 @@ +155;&&%9:;;;1++;44++43????;1++;;;44;3???;;1++55555;3???;?1+444+44;,???;;1+;5;+;5;5;???;1+;+;+;+;+;???;14;+;4;+5+;;?;;1;;4;;;444?;;;? \ No newline at end of file diff --git a/graphics/trainer_hill/maps_jp/floor_1/collision.bin b/graphics/trainer_hill/maps_jp/floor_1/collision.bin new file mode 100755 index 0000000000000000000000000000000000000000..58f80b49bb1ab2c9e27f9e8c19f3cfa17b6dcdfe GIT binary patch literal 32 bcmZo?HC#Uv;AiWLNEXT<6#hZ literal 0 HcmV?d00001 diff --git a/graphics/trainer_hill/maps_jp/floor_1/metatiles.bin b/graphics/trainer_hill/maps_jp/floor_1/metatiles.bin new file mode 100755 index 000000000..951723792 --- /dev/null +++ b/graphics/trainer_hill/maps_jp/floor_1/metatiles.bin @@ -0,0 +1 @@ +1;5;9&%9:;5;1;+;;+++++;;;+;1;+;;+++++>>;+;1;+;;+++++;;;+;?;+;;+++++;>>+;1;+;;++,++;;;+;1?+;;,,;,,>>;+;1;+5555;55555+;?;,,,,,;,,,,,,;1;??;55;55555551???;++5+++++++1??;;++++++++++1;;;?,,,,,,,,,, \ No newline at end of file diff --git a/graphics/trainer_hill/maps_normal/floor_0/collision.bin b/graphics/trainer_hill/maps_normal/floor_0/collision.bin new file mode 100755 index 000000000..80213aaae --- /dev/null +++ b/graphics/trainer_hill/maps_normal/floor_0/collision.bin @@ -0,0 +1 @@ +�å?í½%„½ß!~A } ÷Aùyÿÿ \ No newline at end of file diff --git a/graphics/trainer_hill/maps_normal/floor_0/metatiles.bin b/graphics/trainer_hill/maps_normal/floor_0/metatiles.bin new file mode 100755 index 000000000..658a5ace6 --- /dev/null +++ b/graphics/trainer_hill/maps_normal/floor_0/metatiles.bin @@ -0,0 +1 @@ +1;55&&%&:;5;1;,,,+$$$$,;;,;-;;;;+;;;;5;55;3;2!0+;2!0+;,+;35;;;,5;;;+;;+;4,;2!0+20;+20,;15;;5;,;;5,;;551,20+205;+2!0,,15;;+;;+;,;5;;;1,20+20+;20+20;1555+;;+;;5+;551+,,,20+20,,;,,1+;;5;;+;;5;;;;1,20+;;,20,20;51;;;,;;;;;;;;;, \ No newline at end of file diff --git a/graphics/trainer_hill/maps_normal/floor_1/collision.bin b/graphics/trainer_hill/maps_normal/floor_1/collision.bin new file mode 100755 index 000000000..fb3f6aec0 --- /dev/null +++ b/graphics/trainer_hill/maps_normal/floor_1/collision.bin @@ -0,0 +1 @@ +�ûs @ @ëQ‹S»Q‹QëQ‹Q»QPPÿÿ \ No newline at end of file diff --git a/graphics/trainer_hill/maps_normal/floor_1/metatiles.bin b/graphics/trainer_hill/maps_normal/floor_1/metatiles.bin new file mode 100755 index 000000000..52af9cfdc --- /dev/null +++ b/graphics/trainer_hill/maps_normal/floor_1/metatiles.bin @@ -0,0 +1 @@ +ÑÕÕÕÙÙÅÆÎÕÛÕÑËÄÄÛÛÄÄÄÌÌÌËÛËÑËÛÛÛÛÛÛÛËÛËÑËÛÕÕÕÕÕßËÛËÑËÛËËËÄÄÛËÛËÑËÛËÛÛÄËËßÕÕËÛËÑËÛËÛÛÛËËÛÄÄËÛËÑËÛËÛÛÛËËÕÕßËÛËÑËÛËÛÛÛËËÄÄÛËÛËÑËÛËÛÛÛËËßÕÕËÛËÑËÛËÛÛÛÄÄÛÄÄÄÛËÑËÛË››››››ÛÕÕÕËÑÄÛËÛÛÛÛÛ›ÛËËËËÑÛÛËÛÛÛÛÛ›ÛËËËËÑÛÛÄÛÛÛÛÛ›ÛÄÄÄÄ \ No newline at end of file diff --git a/graphics/trainer_hill/maps_normal/floor_2/collision.bin b/graphics/trainer_hill/maps_normal/floor_2/collision.bin new file mode 100755 index 0000000000000000000000000000000000000000..b3ccacdd4c25fee4cf227fac1346ee02b189d8c2 GIT binary patch literal 32 acmZoeskKr|x*BLe_r>jg#t literal 0 HcmV?d00001 diff --git a/graphics/trainer_hill/maps_normal/floor_2/metatiles.bin b/graphics/trainer_hill/maps_normal/floor_2/metatiles.bin new file mode 100755 index 000000000..bf2b52c32 --- /dev/null +++ b/graphics/trainer_hill/maps_normal/floor_2/metatiles.bin @@ -0,0 +1 @@ +1555&&8&.55;icddddqqqrdddcsicssssssssssscsicssssssssssscsicCA@ABAAJBAAcsicsssssssdssscsicACKCCABB@A@csicssdsssssssscsicA@BBAABJBABcsicsssssssdssscsicABACKAAA@CAcsicssssdsssssscsicA@CABBAJBABcsidsssssssdsssdsiCCABBACAA@BABsiBsssssssssssBs \ No newline at end of file diff --git a/graphics/trainer_hill/maps_normal/floor_3/collision.bin b/graphics/trainer_hill/maps_normal/floor_3/collision.bin new file mode 100755 index 0000000000000000000000000000000000000000..f4c47254c56adb7e19d0d6ed491a13178b73c526 GIT binary patch literal 32 ncmZoUbL@H$@m!0ULkk4!I2@pp3%k8wKCK(G#-c@Lu*4B1sMhZ{|5lD4+_)( literal 0 HcmV?d00001 diff --git a/graphics/trainer_hill/maps_unique/floor_3/metatiles.bin b/graphics/trainer_hill/maps_unique/floor_3/metatiles.bin new file mode 100755 index 000000000..66840137c --- /dev/null +++ b/graphics/trainer_hill/maps_unique/floor_3/metatiles.bin @@ -0,0 +1 @@ +ñûûûùùåæîõûûíõõõûûìììëìììûûôìììûûûûûëûûûûûñõõõõõõõûëûõõõõñëìììëììûìûììììñëûûûëûõûõûûûûûñëûõûëûëûëõõõûûñëûëûëûëûëìììûûñëûëûëûëûëûõõõõñëûëûëûëûëûììììñëûëûëûëûëûûûûûñëûëûëûëûëõõõõûñìûëûìûëûìììììûñûûëûûûëûûûûûûûñûûìûûûìûûûûûûû \ No newline at end of file diff --git a/graphics/trainer_hill/maps_variety/floor_0/collision.bin b/graphics/trainer_hill/maps_variety/floor_0/collision.bin new file mode 100755 index 0000000000000000000000000000000000000000..24fc2ea1e6b203d760a554f6b02de209bdeadb1e GIT binary patch literal 32 McmZo+m literal 0 HcmV?d00001 diff --git a/graphics/trainer_hill/maps_variety/floor_1/metatiles.bin b/graphics/trainer_hill/maps_variety/floor_1/metatiles.bin new file mode 100755 index 000000000..c5a9aa5d4 --- /dev/null +++ b/graphics/trainer_hill/maps_variety/floor_1/metatiles.bin @@ -0,0 +1 @@ +1;;;9989:;;;‘›œ–@@–›–@@–›œ›œ›–@ÛÛ@–@ÛÛB–››‘–@ÛÛÛÛÛÛÛÛÛB–œ‘BÛÛÖÖÖÛÖÖÖÛÛB›–BÛÖÖÖÖÖÖÖÖÖÛB––BÛÖÖÖÖÖÖÖÖÖÛB––BÛÖÖÖÖÖÖÖÖÖÛB––BÛÛÖÖÖÖÖÖÖÛÛB–‘–BÛÛÖÖÖÖÖÛÛB–›‘›–BÛÛÖÖÖÛÛB–›œœ››–BÛÛÖÛÛB–›››–›››–AÛÛÛB–››œ–Ö–œ››–AÛB–›››–֖֜›œ›–@–›œ›–Öœ \ No newline at end of file diff --git a/graphics/trainer_hill/maps_variety/floor_2/collision.bin b/graphics/trainer_hill/maps_variety/floor_2/collision.bin new file mode 100755 index 0000000000000000000000000000000000000000..606249b2a0085c18fc9fea19f02a98713c93233a GIT binary patch literal 32 RcmZo Date: Fri, 1 Apr 2022 01:21:00 -0400 Subject: [PATCH 061/130] Document trainer hill prize selection --- src/trainer_hill.c | 60 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/src/trainer_hill.c b/src/trainer_hill.c index 2deacfc70..dad6b97ea 100644 --- a/src/trainer_hill.c +++ b/src/trainer_hill.c @@ -996,10 +996,14 @@ static void TrainerHillSetMode(void) gSaveBlock1Ptr->trainerHill.bestTime = gSaveBlock1Ptr->trainerHillTimes[gSpecialVar_0x8005]; } -static u8 GetPrizeListId(bool8 maxTrainers) +// Determines which prize list to use from the set of prize lists. +static u8 GetPrizeListId(bool8 allowTMs) { u8 prizeListId, i, modBy; + // The initial selection depends on the trainer numbers for the completed challenge. + // These don't change with the available challenge modes, so Normal/Unique will always + // have a prizeListId of 8, and Variety/Expert will have a prizeListId of 24. prizeListId = 0; for (i = 0; i < NUM_TRAINER_HILL_FLOORS; i++) { @@ -1007,8 +1011,10 @@ static u8 GetPrizeListId(bool8 maxTrainers) prizeListId ^= sHillData->floors[i].trainerNum2 & 0x1F; } - // Not possible to win TMs with fewer than 8 trainers - if (maxTrainers) + // In practice, the conditional below is always true. + // The 2nd half of the lists in both sets of lists all have a TM as the "grand prize", while the 1st half do not, + // so taking the mod of the (total / 2) ensures that a prize list without a TM will be used. + if (allowTMs) modBy = NUM_TRAINER_HILL_PRIZE_LISTS; else modBy = NUM_TRAINER_HILL_PRIZE_LISTS / 2; @@ -1021,38 +1027,64 @@ static u16 GetPrizeItemId(void) { u8 i; const u16 *prizeList; - s32 var = 0, prizeListSetId, minutes, id; + s32 trainerNumSum = 0, prizeListSetId, minutes, id; + // First determine which set of prize lists to use. The sets of lists only differ in + // what TMs they can offer as the "grand prize" for a time under 12 minutes. + // Which set of lists gets used is based on the sum of all the trainer numbers for that + // challenge. These don't change with the available challenge modes, so Normal will always + // have a prizeListSetId of 0, and Unique/Variety/Expert will have a prizeListSetId of 1. for (i = 0; i < NUM_TRAINER_HILL_FLOORS; i++) { - var += sHillData->floors[i].trainerNum1; - var += sHillData->floors[i].trainerNum2; + trainerNumSum += sHillData->floors[i].trainerNum1; + trainerNumSum += sHillData->floors[i].trainerNum2; } + prizeListSetId = trainerNumSum / 256; + prizeListSetId %= (int)ARRAY_COUNT(sPrizeListSets); - prizeListSetId = var / 256; - prizeListSetId %= 2; + // Now get which prize list to use from the set. See GetPrizeListId for details. + // The below conditional will always be true, because a Trainer Hill challenge can't be entered + // until the player has entered the Hall of Fame (FLAG_SYS_GAME_CLEAR is set) and because all + // of the available challenge modes have the full 8 trainers (NUM_TRAINER_HILL_TRAINERS). if (FlagGet(FLAG_SYS_GAME_CLEAR) && sHillData->challenge.numTrainers == NUM_TRAINER_HILL_TRAINERS) i = GetPrizeListId(TRUE); else i = GetPrizeListId(FALSE); + // 1 is added to Expert mode's prize list selection because otherwise it has the same prizes as Variety if (gSaveBlock1Ptr->trainerHill.mode == HILL_MODE_EXPERT) i = (i + 1) % NUM_TRAINER_HILL_PRIZE_LISTS; + // After the above (non-random) calculations, the following are the possible prize list selections: + // sPrizeListSets[0][8] (Normal) + // sPrizeListSets[1][4] (Variety) + // sPrizeListSets[1][8] (Unique) + // sPrizeListSets[1][5] (Expert) prizeList = sPrizeListSets[prizeListSetId][i]; + + // Which prize is given from the list depends on the time scored. + // The prize for any time after 12 minutes is the same in every list. + // The prizes for a time under 12 minutes are: + // - ITEM_TM11_SUNNY_DAY (Normal) + // - ITEM_ELIXIR (Variety) + // - ITEM_TM19_GIGA_DRAIN (Unique) + // - ITEM_TM31_BRICK_BREAK (Expert) + // As an additional note, if players were allowed to enter a Trainer Hill challenge before + // entering the Hall of Fame, there would be 1 additional prize possibility (ITEM_MAX_ETHER) + // as Normal / Unique modes would use sPrizeListSets[0][3] / sPrizeListSets[1][3] respectively. minutes = (signed)(gSaveBlock1Ptr->trainerHill.timer) / (60 * 60); if (minutes < 12) - id = 0; + id = 0; // Depends on list else if (minutes < 13) - id = 1; + id = 1; // ITEM_ETHER else if (minutes < 14) - id = 2; + id = 2; // ITEM_MAX_POTION else if (minutes < 16) - id = 3; + id = 3; // ITEM_REVIVE else if (minutes < 18) - id = 4; + id = 4; // ITEM_FLUFFY_TAIL else - id = 5; + id = 5; // ITEM_GREAT_BALL return prizeList[id]; } From e1f89c70d9c0f1d34fa5d3eb45c6baf0d7a42287 Mon Sep 17 00:00:00 2001 From: Eldred Habert Date: Sat, 2 Apr 2022 00:22:36 +0200 Subject: [PATCH 062/130] Add Arch Linux install instructions I didn't test the devkitARM install instructions, but they are pretty much transcribed from the Ubuntu/Deb ones, so that should be fine. --- INSTALL.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/INSTALL.md b/INSTALL.md index 1f1e1164b..f6434c07b 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -305,6 +305,20 @@ Then proceed to [Choosing where to store pokeemerald (Linux)](#choosing-where-to > then you will have to install devkitARM. Install all the above packages except binutils-arm-none-eabi, and follow the instructions to > [install devkitARM on Debian/Ubuntu-based distributions](#installing-devkitarm-on-debianubuntu-based-distributions). + +### Arch Linux +Run this command as root to install the necessary packages: +```bash +pacman -S base-devel arm-none-eabi-binutils git libpng +``` +Then proceed to [Choosing where to store pokeemerald (Linux)](#choosing-where-to-store-pokeemerald-linux). +
+ Note for legacy repos... + +> If the repository you plan to build has an **[older revision of the INSTALL.md](https://github.com/pret/pokeemerald/blob/571c598/INSTALL.md)**, +> then you will have to install devkitARM. Install all the above packages except binutils-arm-none-eabi, and follow the instructions to +> [install devkitARM on Arch Linux](#installing-devkitarm-on-arch-linux). +
### Other distributions _(Specific instructions for other distributions would be greatly appreciated!)_ @@ -520,6 +534,24 @@ devkitARM is now installed. devkitARM is now installed. +## Installing devkitARM on Arch Linux + +1. Follow [devkitPro's instructions](https://devkitpro.org/wiki/devkitPro_pacman#Customising_Existing_Pacman_Install) to configure `pacman` to download devkitPro packages. +2. Install `gba-dev`: run the following command as root. + + ```console + pacman -S gba-dev + ``` + This will ask for the selection of packages to install. Just press Enter to install all of them, followed by entering Y to proceed with the installation. + +3. Run the following command to set devkitPro related environment variables (alternatively, close and re-open the Terminal): + + ```bash + source /etc/profile.d/devkit-env.sh + ``` + +devkitARM is now installed. + ## Other toolchains To build using a toolchain other than devkitARM, override the `TOOLCHAIN` environment variable with the path to your toolchain, which must contain the subdirectory `bin`. From dafb5ca74ddd436008a171d908c123cbddd49983 Mon Sep 17 00:00:00 2001 From: Eduardo Quezada D'Ottone Date: Sun, 3 Apr 2022 13:03:53 -0400 Subject: [PATCH 063/130] Fixed trapping moves not reflecting the configured turn config --- src/data/text/move_descriptions.h | 36 +++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/data/text/move_descriptions.h b/src/data/text/move_descriptions.h index 4704af3fd..80c97a505 100644 --- a/src/data/text/move_descriptions.h +++ b/src/data/text/move_descriptions.h @@ -79,7 +79,11 @@ static const u8 sFlyDescription[] = _( static const u8 sBindDescription[] = _( "Binds and squeezes the foe\n" +#if B_BINDING_TURNS >= GEN_5 + "for 4 or 5 turns."); +#else "for 2 to 5 turns."); +#endif static const u8 sSlamDescription[] = _( "Slams the foe with a long\n" @@ -139,7 +143,11 @@ static const u8 sBodySlamDescription[] = _( static const u8 sWrapDescription[] = _( "Wraps and squeezes the foe\n" +#if B_BINDING_TURNS >= GEN_5 + "4 or 5 times with vines, etc."); +#else "2 to 5 times with vines, etc."); +#endif static const u8 sTakeDownDescription[] = _( "A reckless charge attack\n" @@ -331,7 +339,11 @@ static const u8 sDragonRageDescription[] = _( static const u8 sFireSpinDescription[] = _( "Traps the foe in a ring of\n" +#if B_BINDING_TURNS >= GEN_5 + "fire for 4 or 5 turns."); +#else "fire for 2 to 5 turns."); +#endif static const u8 sThunderShockDescription[] = _( "An electrical attack that\n" @@ -511,7 +523,11 @@ static const u8 sWaterfallDescription[] = _( static const u8 sClampDescription[] = _( "Traps and squeezes the\n" +#if B_BINDING_TURNS >= GEN_5 + "foe for 4 or 5 turns."); +#else "foe for 2 to 5 turns."); +#endif static const u8 sSwiftDescription[] = _( "Sprays star-shaped rays\n" @@ -999,7 +1015,11 @@ static const u8 sRockSmashDescription[] = _( static const u8 sWhirlpoolDescription[] = _( "Traps and hurts the foe in\n" +#if B_BINDING_TURNS >= GEN_5 + "a whirlpool for 4 or 5 turns."); +#else "a whirlpool for 2 to 5 turns."); +#endif static const u8 sBeatUpDescription[] = _( "Summons party Pokémon to\n" @@ -1311,7 +1331,11 @@ static const u8 sSkyUppercutDescription[] = _( static const u8 sSandTombDescription[] = _( "Traps and hurts the foe in\n" +#if B_BINDING_TURNS >= GEN_5 + "quicksand for 4 or 5 turns."); +#else "quicksand for 2 to 5 turns."); +#endif static const u8 sSheerColdDescription[] = _( "A chilling attack that\n" @@ -1815,7 +1839,11 @@ static const u8 sSpacialRendDescription[] = _( static const u8 sMagmaStormDescription[] = _( "Traps the foe in a vortex\n" +#if B_BINDING_TURNS >= GEN_5 + "of fire for 4 or 5 turns."); +#else "of fire for 2 to 5 turns."); +#endif static const u8 sDarkVoidDescription[] = _( "Drags the foe into total\n" @@ -2367,7 +2395,11 @@ static const u8 sNuzzleDescription[] = _( static const u8 sInfestationDescription[] = _( "The foe is infested and\n" +#if B_BINDING_TURNS >= GEN_5 + "attacked for 4 or 5 turns."); +#else "attacked for 2 to 5 turns."); +#endif static const u8 sPowerUpPunchDescription[] = _( "A hard punch that raises\n" @@ -2912,7 +2944,11 @@ static const u8 sSurgingStrikesDescription[] = _( static const u8 sThunderCageDescription[] = _( "Traps the foe in a cage of\n" +#if B_BINDING_TURNS >= GEN_5 + "electricity for 4 or 5 turns."); +#else "electricity for 2 to 5 turns."); +#endif static const u8 sDragonEnergyDescription[] = _( "The higher the user's HP\n" From d604d99d6e74e5bf183c79faf1bdffd99682f8f9 Mon Sep 17 00:00:00 2001 From: Eduardo Quezada D'Ottone Date: Sun, 3 Apr 2022 16:54:07 -0400 Subject: [PATCH 064/130] Adjusted description of Glacial Lance and Astral Barrage --- src/data/text/move_descriptions.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data/text/move_descriptions.h b/src/data/text/move_descriptions.h index f3b982756..942ab0fbf 100644 --- a/src/data/text/move_descriptions.h +++ b/src/data/text/move_descriptions.h @@ -2932,11 +2932,11 @@ static const u8 sThunderousKickDescription[] = _( static const u8 sGlacialLanceDescription[] = _( "Strikes by hurling a blizzard-\n" - "cloaked icicle lance at a foe."); + "cloaked icicle lance at foes."); static const u8 sAstralBarrageDescription[] = _( "Strikes by sending a frightful\n" - "amount of ghosts at a foe."); + "amount of ghosts at foes."); static const u8 sEerieSpellDescription[] = _( "Attacks with psychic power.\n" From 454068095cef3bf7bad8768d92b5aedd9ce17588 Mon Sep 17 00:00:00 2001 From: Eduardo Quezada D'Ottone Date: Mon, 4 Apr 2022 16:59:01 -0400 Subject: [PATCH 065/130] Moved Sky Drop battle string to where other battle strings are --- src/battle_message.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/battle_message.c b/src/battle_message.c index 34b258e63..b374e3760 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -427,8 +427,6 @@ static const u8 sText_ExclamationMark4[] = _("!"); static const u8 sText_ExclamationMark5[] = _("!"); static const u8 sText_Accuracy[] = _("accuracy"); static const u8 sText_Evasiveness[] = _("evasiveness"); -static const u8 sText_PkmnTookTargetHigh[] = _("{B_ATK_NAME_WITH_PREFIX} took {B_DEF_NAME_WITH_PREFIX}\ninto the air!"); -static const u8 sText_TargetTooHeavy[] = _("But the target\nwas too heavy!"); const u8 * const gStatNamesTable[NUM_BATTLE_STATS] = { @@ -733,6 +731,8 @@ static const u8 sText_PkmnAboutToBeAttackedByItsItem[] = _("{B_DEF_NAME_WITH_PRE static const u8 sText_CantEscapeBecauseOfCurrentMove[] = _("{B_DEF_NAME_WITH_PREFIX} can no longer escape\nbecause of {B_CURRENT_MOVE}!"); static const u8 sText_NeutralizingGasEnters[] = _("Neutralizing Gas filled the area!"); static const u8 sText_NeutralizingGasOver[] = _("The effects of Neutralizing\nGas wore off!"); +static const u8 sText_PkmnTookTargetHigh[] = _("{B_ATK_NAME_WITH_PREFIX} took {B_DEF_NAME_WITH_PREFIX}\ninto the air!"); +static const u8 sText_TargetTooHeavy[] = _("But the target\nwas too heavy!"); const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = { From 8a7e8e9805789b5732b974451545df0894148e78 Mon Sep 17 00:00:00 2001 From: Eduardo Quezada D'Ottone Date: Tue, 12 Apr 2022 21:13:48 -0400 Subject: [PATCH 066/130] Apply suggestions from code review --- src/battle_message.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/battle_message.c b/src/battle_message.c index 3c648d32a..039aca722 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -895,9 +895,9 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = [STRINGID_PKMNHURTBY - BATTLESTRINGS_TABLE_START] = sText_PkmnHurtBy, [STRINGID_PKMNFREEDFROM - BATTLESTRINGS_TABLE_START] = sText_PkmnFreedFrom, [STRINGID_PKMNCRASHED - BATTLESTRINGS_TABLE_START] = sText_PkmnCrashed, - [STRINGID_PKMNSHROUDEDINMIST - BATTLESTRINGS_TABLE_START] =gText_PkmnShroudedInMist, + [STRINGID_PKMNSHROUDEDINMIST - BATTLESTRINGS_TABLE_START] = gText_PkmnShroudedInMist, [STRINGID_PKMNPROTECTEDBYMIST - BATTLESTRINGS_TABLE_START] = sText_PkmnProtectedByMist, - [STRINGID_PKMNGETTINGPUMPED - BATTLESTRINGS_TABLE_START] =gText_PkmnGettingPumped, + [STRINGID_PKMNGETTINGPUMPED - BATTLESTRINGS_TABLE_START] = gText_PkmnGettingPumped, [STRINGID_PKMNHITWITHRECOIL - BATTLESTRINGS_TABLE_START] = sText_PkmnHitWithRecoil, [STRINGID_PKMNPROTECTEDITSELF2 - BATTLESTRINGS_TABLE_START] = sText_PkmnProtectedItself2, [STRINGID_PKMNBUFFETEDBYSANDSTORM - BATTLESTRINGS_TABLE_START] = sText_PkmnBuffetedBySandstorm, @@ -1007,12 +1007,12 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = [STRINGID_PKMNPREVENTSSTATLOSSWITH - BATTLESTRINGS_TABLE_START] = sText_PkmnPreventsStatLossWith, [STRINGID_PKMNHURTSWITH - BATTLESTRINGS_TABLE_START] = sText_PkmnHurtsWith, [STRINGID_PKMNTRACED - BATTLESTRINGS_TABLE_START] = sText_PkmnTraced, - [STRINGID_STATSHARPLY - BATTLESTRINGS_TABLE_START] =gText_StatSharply, - [STRINGID_STATROSE - BATTLESTRINGS_TABLE_START] =gText_StatRose, + [STRINGID_STATSHARPLY - BATTLESTRINGS_TABLE_START] = gText_StatSharply, + [STRINGID_STATROSE - BATTLESTRINGS_TABLE_START] = gText_StatRose, [STRINGID_STATHARSHLY - BATTLESTRINGS_TABLE_START] = sText_StatHarshly, [STRINGID_STATFELL - BATTLESTRINGS_TABLE_START] = sText_StatFell, [STRINGID_ATTACKERSSTATROSE - BATTLESTRINGS_TABLE_START] = sText_AttackersStatRose, - [STRINGID_DEFENDERSSTATROSE - BATTLESTRINGS_TABLE_START] =gText_DefendersStatRose, + [STRINGID_DEFENDERSSTATROSE - BATTLESTRINGS_TABLE_START] = gText_DefendersStatRose, [STRINGID_ATTACKERSSTATFELL - BATTLESTRINGS_TABLE_START] = sText_AttackersStatFell, [STRINGID_DEFENDERSSTATFELL - BATTLESTRINGS_TABLE_START] = sText_DefendersStatFell, [STRINGID_CRITICALHIT - BATTLESTRINGS_TABLE_START] = sText_CriticalHit, @@ -1102,7 +1102,7 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = [STRINGID_PKMNSITEMRESTOREDHPALITTLE - BATTLESTRINGS_TABLE_START] = sText_PkmnsItemRestoredHPALittle, [STRINGID_ITEMALLOWSONLYYMOVE - BATTLESTRINGS_TABLE_START] = sText_ItemAllowsOnlyYMove, [STRINGID_PKMNHUNGONWITHX - BATTLESTRINGS_TABLE_START] = sText_PkmnHungOnWithX, - [STRINGID_EMPTYSTRING3 - BATTLESTRINGS_TABLE_START] =gText_EmptyString3, + [STRINGID_EMPTYSTRING3 - BATTLESTRINGS_TABLE_START] = gText_EmptyString3, [STRINGID_PKMNSXPREVENTSBURNS - BATTLESTRINGS_TABLE_START] = sText_PkmnsXPreventsBurns, [STRINGID_PKMNSXBLOCKSY - BATTLESTRINGS_TABLE_START] = sText_PkmnsXBlocksY, [STRINGID_PKMNSXRESTOREDHPALITTLE2 - BATTLESTRINGS_TABLE_START] = sText_PkmnsXRestoredHPALittle2, @@ -1173,10 +1173,10 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = [STRINGID_TIEDOPPONENTBYREFEREE - BATTLESTRINGS_TABLE_START] = sText_TiedOpponentByReferee, [STRINGID_QUESTIONFORFEITMATCH - BATTLESTRINGS_TABLE_START] = sText_QuestionForfeitMatch, [STRINGID_FORFEITEDMATCH - BATTLESTRINGS_TABLE_START] = sText_ForfeitedMatch, - [STRINGID_PKMNTRANSFERREDSOMEONESPC - BATTLESTRINGS_TABLE_START] =gText_PkmnTransferredSomeonesPC, - [STRINGID_PKMNTRANSFERREDLANETTESPC - BATTLESTRINGS_TABLE_START] =gText_PkmnTransferredLanettesPC, - [STRINGID_PKMNBOXSOMEONESPCFULL - BATTLESTRINGS_TABLE_START] =gText_PkmnTransferredSomeonesPCBoxFull, - [STRINGID_PKMNBOXLANETTESPCFULL - BATTLESTRINGS_TABLE_START] =gText_PkmnTransferredLanettesPCBoxFull, + [STRINGID_PKMNTRANSFERREDSOMEONESPC - BATTLESTRINGS_TABLE_START] = gText_PkmnTransferredSomeonesPC, + [STRINGID_PKMNTRANSFERREDLANETTESPC - BATTLESTRINGS_TABLE_START] = gText_PkmnTransferredLanettesPC, + [STRINGID_PKMNBOXSOMEONESPCFULL - BATTLESTRINGS_TABLE_START] = gText_PkmnTransferredSomeonesPCBoxFull, + [STRINGID_PKMNBOXLANETTESPCFULL - BATTLESTRINGS_TABLE_START] = gText_PkmnTransferredLanettesPCBoxFull, [STRINGID_TRAINER1WINTEXT - BATTLESTRINGS_TABLE_START] = sText_Trainer1WinText, [STRINGID_TRAINER2WINTEXT - BATTLESTRINGS_TABLE_START] = sText_Trainer2WinText, [STRINGID_ENDUREDSTURDY - BATTLESTRINGS_TABLE_START] = sText_EnduredViaSturdy, From 59cff2190d44edf9e64c1d8c4cfd5931b2354aaf Mon Sep 17 00:00:00 2001 From: sbird Date: Sat, 16 Apr 2022 19:03:20 +0200 Subject: [PATCH 067/130] fix building without NDEBUG on agbcc --- ld_script.txt | 43 ++++++++++++++++++++++++++++++++++++++++--- src/libisagbprn.c | 10 +++++----- src/mystery_gift.c | 4 ++++ 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/ld_script.txt b/ld_script.txt index d68498a8b..1460c8443 100644 --- a/ld_script.txt +++ b/ld_script.txt @@ -20,7 +20,9 @@ SECTIONS { . = 0x1C000; INCLUDE "sym_ewram.ld" - + *libc.a:impure.o(.data); + *libc.a:locale.o(.data); + *libc.a:mallocr.o(.data); . = 0x40000; } @@ -462,6 +464,7 @@ SECTIONS { src/mystery_gift_server.o(.rodata); src/mystery_gift_client.o(.rodata); src/mystery_gift_scripts.o(.rodata); + src/wonder_news.o(.rodata); src/union_room_chat.o(.rodata); src/berry_crush.o(.rodata); src/berry_powder.o(.rodata); @@ -1245,9 +1248,43 @@ SECTIONS { src/librfu_sio32id.o(.rodata); *libgcc.a:_divdi3.o(.rodata); *libgcc.a:_udivdi3.o(.rodata); - *libc.a(.rodata); - *libc.a(.data); + *libc.a:memcpy.o(.rodata); + *libc.a:memset.o(.rodata); + *libc.a:strcmp.o(.rodata); + *libc.a:strcpy.o(.rodata); + *libc.a:impure.o(.rodata); + *libc.a:vsprintf.o(.rodata); + *libc.a:vfprintf.o(.rodata); + *libc.a:wsetup.o(.rodata); + *libc.a:dtoa.o(.rodata); + *libc.a:fflush.o(.rodata); + *libc.a:findfp.o(.rodata); + *libc.a:freer.o(.rodata); + *libc.a:mtrim.o(.rodata); + *libc.a:fvwrite.o(.rodata); + *libc.a:fwalk.o(.rodata); + *libc.a:locale.o(.rodata); + *libc.a:makebuf.o(.rodata); + *libc.a:mallocr.o(.rodata); + *libc.a:mbtowc_r.o(.rodata); + *libc.a:memchr.o(.rodata); + *libc.a:memmove.o(.rodata); + *libc.a:mlock.o(.rodata); + *libc.a:mprec.o(.rodata); + *libc.a:s_isinf.o(.rodata); + *libc.a:s_isnan.o(.rodata); + *libc.a:sbrkr.o(.rodata); + *libc.a:stdio.o(.rodata); + *libc.a:strlen.o(.rodata); *libc.a:syscalls.o(.rodata); + *libc.a:writer.o(.rodata); + *libc.a:callocr.o(.rodata); + *libc.a:closer.o(.rodata); + *libc.a:errno.o(.rodata); + *libc.a:fstatr.o(.rodata); + *libc.a:libcfunc.o(.rodata); + *libc.a:lseekr.o(.rodata); + *libc.a:readr.o(.rodata); src/libisagbprn.o(.rodata); } =0 diff --git a/src/libisagbprn.c b/src/libisagbprn.c index 69c6986ae..7a70cf41f 100644 --- a/src/libisagbprn.c +++ b/src/libisagbprn.c @@ -31,7 +31,7 @@ void AGBPrintFlush1Block(void); void AGBPrintInit(void) { volatile struct AGBPrintStruct *pPrint = (struct AGBPrintStruct *)AGB_PRINT_STRUCT_ADDR; - u16 *pWSCNT = ®_WAITCNT; + vu16 *pWSCNT = ®_WAITCNT; u16 *pProtect = (u16 *)AGB_PRINT_PROTECT_ADDR; u16 nOldWSCNT = *pWSCNT; *pWSCNT = WSCNT_DATA; @@ -57,7 +57,7 @@ static void AGBPutcInternal(const char cChr) void AGBPutc(const char cChr) { - u16 *pWSCNT = ®_WAITCNT; + vu16 *pWSCNT = ®_WAITCNT; u16 nOldWSCNT = *pWSCNT; volatile struct AGBPrintStruct *pPrint; *pWSCNT = WSCNT_DATA; @@ -71,7 +71,7 @@ void AGBPutc(const char cChr) void AGBPrint(const char *pBuf) { volatile struct AGBPrintStruct *pPrint = (struct AGBPrintStruct *)AGB_PRINT_STRUCT_ADDR; - u16 *pWSCNT = ®_WAITCNT; + vu16 *pWSCNT = ®_WAITCNT; u16 nOldWSCNT = *pWSCNT; *pWSCNT = WSCNT_DATA; while (*pBuf) @@ -95,9 +95,9 @@ void AGBPrintf(const char *pBuf, ...) static void AGBPrintTransferDataInternal(u32 bAllData) { LPFN_PRINT_FLUSH lpfnFuncFlush; - u16 *pIME; + vu16 *pIME; u16 nIME; - u16 *pWSCNT; + vu16 *pWSCNT; u16 nOldWSCNT; u16 *pProtect; volatile struct AGBPrintStruct *pPrint; diff --git a/src/mystery_gift.c b/src/mystery_gift.c index 1df6533d9..72fc2b377 100755 --- a/src/mystery_gift.c +++ b/src/mystery_gift.c @@ -506,9 +506,13 @@ static void IncrementCardStat(u32 statType) } if (stat == NULL) + { AGB_ASSERT(0); + } else if (++(*stat) > MAX_WONDER_CARD_STAT) + { *stat = MAX_WONDER_CARD_STAT; + } } } From 0bda107188b5623f34d95214fae1c715b757ec7f Mon Sep 17 00:00:00 2001 From: Kurausukun Date: Wed, 20 Apr 2022 01:07:10 -0400 Subject: [PATCH 068/130] don't build modern with -g by default --- INSTALL.md | 1 + Makefile | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/INSTALL.md b/INSTALL.md index f6434c07b..72f3c92f3 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -457,6 +457,7 @@ To build **pokeemerald.elf** with enhanced debug info: ```bash make DINFO=1 ``` +Note that this is only necessary for the `modern` target; the regular target has debug info enabled by default. ## devkitARM's C compiler diff --git a/Makefile b/Makefile index 6283a87fe..c36cc8e93 100644 --- a/Makefile +++ b/Makefile @@ -107,7 +107,7 @@ LIBPATH := -L ../../tools/agbcc/lib LIB := $(LIBPATH) -lgcc -lc -L../../libagbsyscall -lagbsyscall else CC1 = $(shell $(PATH_MODERNCC) --print-prog-name=cc1) -quiet -override CFLAGS += -mthumb -mthumb-interwork -O2 -mabi=apcs-gnu -mtune=arm7tdmi -march=armv4t -fno-toplevel-reorder -Wno-pointer-to-int-cast -g +override CFLAGS += -mthumb -mthumb-interwork -O2 -mabi=apcs-gnu -mtune=arm7tdmi -march=armv4t -fno-toplevel-reorder -Wno-pointer-to-int-cast ROM := $(MODERN_ROM_NAME) OBJ_DIR := $(MODERN_OBJ_DIR_NAME) LIBPATH := -L "$(dir $(shell $(PATH_MODERNCC) -mthumb -print-file-name=libgcc.a))" -L "$(dir $(shell $(PATH_MODERNCC) -mthumb -print-file-name=libnosys.a))" -L "$(dir $(shell $(PATH_MODERNCC) -mthumb -print-file-name=libc.a))" From 055c72a384aa5fc9f56970166a3595f3ba545b09 Mon Sep 17 00:00:00 2001 From: LOuroboros Date: Sat, 23 Apr 2022 04:23:27 -0300 Subject: [PATCH 069/130] Improved the special animation of Shell Side Arm --- data/battle_anim_scripts.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index ef2e1d5d5..157e638c9 100644 --- a/data/battle_anim_scripts.s +++ b/data/battle_anim_scripts.s @@ -14078,8 +14078,8 @@ Move_SHELL_SIDE_ARM_SPECIAL: @ Modified Snipe Shot, placeholder loadspritegfx ANIM_TAG_LEER createvisualtask AnimTask_BlendParticle, 5, ANIM_TAG_IMPACT_2, 0, 6, 6, RGB_MAGENTA createvisualtask AnimTask_BlendParticle, 5, ANIM_TAG_LEER, 0, 6, 6, RGB_MAGENTA - launchtemplate gLeerSpriteTemplate 0x82, 2 0x18 -12 playsewithpan SE_M_DETECT, SOUND_PAN_ATTACKER + launchtemplate gLeerSpriteTemplate 0x82, 2 0x18 -12 waitforvisualfinish delay 0x20 playsewithpan SE_M_GIGA_DRAIN, SOUND_PAN_TARGET From 487e3c46d164d579f711eb28387ecae3ea2f9577 Mon Sep 17 00:00:00 2001 From: LOuroboros Date: Sun, 24 Apr 2022 17:27:23 -0300 Subject: [PATCH 070/130] Updated trainer slide-in array --- src/battle_message.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/battle_message.c b/src/battle_message.c index 039aca722..7b2afab54 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -26,6 +26,7 @@ #include "constants/frontier_util.h" #include "constants/items.h" #include "constants/moves.h" +#include "constants/opponents.h" #include "constants/species.h" #include "constants/trainers.h" #include "constants/trainer_hill.h" @@ -3878,7 +3879,9 @@ struct TrainerSlide static const struct TrainerSlide sTrainerSlides[] = { - {0x291, sText_AarghAlmostHadIt, sText_BoxIsFull, sText_123Poof}, + // Put any trainer slide-in messages inside this array. + // Example: + // {TRAINER_WALLY_VR_2, sText_AarghAlmostHadIt, sText_BoxIsFull, sText_123Poof}, }; static u32 GetEnemyMonCount(bool32 onlyAlive) From 2b223acd876169cd8f90f8f5723f28aaaa32f373 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Tue, 26 Apr 2022 21:44:11 -0400 Subject: [PATCH 071/130] Fix math in CreateBerrySprite --- src/berry_blender.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/berry_blender.c b/src/berry_blender.c index 27ea641ce..9b74c7bab 100644 --- a/src/berry_blender.c +++ b/src/berry_blender.c @@ -1188,9 +1188,9 @@ static void SetBerrySpriteData(struct Sprite* sprite, s16 x, s16 y, s16 bounceSp #undef sXSpeed #undef sYDownSpeed -static void CreateBerrySprite(u16 a0, u8 playerId) +static void CreateBerrySprite(u16 itemId, u8 playerId) { - u8 spriteId = CreateSpinningBerrySprite(a0 + FIRST_BERRY_INDEX - 10, 0, 80, playerId & 1); + u8 spriteId = CreateSpinningBerrySprite(ITEM_TO_BERRY(itemId) - 1, 0, 80, playerId & 1); SetBerrySpriteData(&gSprites[spriteId], sBerrySpriteData[playerId][0], sBerrySpriteData[playerId][1], From af6242f2e027d62eb7cb34971adb142f7eb74fe9 Mon Sep 17 00:00:00 2001 From: BuffelSaft Date: Wed, 27 Apr 2022 21:51:10 +1200 Subject: [PATCH 072/130] Requested changes, Sticky Web edge case Fix issues found by ghoulslash, and make sure Defiant works properly with Sticky Web and Court Change. --- data/battle_scripts_1.s | 2 +- include/constants/battle_script_commands.h | 2 +- src/battle_ai_main.c | 2 +- src/battle_script_commands.c | 8 ++++++-- src/battle_util.c | 2 +- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 37eaa5b83..6574e26ab 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -7290,7 +7290,7 @@ BattleScript_DefDownSpeedUpTryDef:: setstatchanger STAT_DEF, 1, TRUE statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_BUFF_ALLOW_PTR | MOVE_EFFECT_CERTAIN, BattleScript_DefDownSpeedUpTrySpeed jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_DefDownSpeedUpTrySpeed - printfromtable gStatUpStringIds + printfromtable gStatDownStringIds waitmessage B_WAIT_TIME_LONG BattleScript_DefDownSpeedUpTrySpeed: playstatchangeanimation BS_ATTACKER, BIT_SPEED, 0 diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 2903963f4..da44714e2 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -39,7 +39,7 @@ #define sABILITY_OVERWRITE (gBattleScripting + 0x34) // abilityPopupOverwrite #define sSWITCH_CASE (gBattleScripting + 0x36) // switchCase #define sBERRY_OVERRIDE (gBattleScripting + 0x37) // overrideBerryRequirements -#define sSTICKY_WEB_STAT_DROP (gBattleScripting + 0x38) // +#define sSTICKY_WEB_STAT_DROP (gBattleScripting + 0x38) // stickyWebStatDrop // Array entries for battle communication #define MULTIUSE_STATE 0 diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 02597a0aa..16e830efe 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -566,7 +566,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) GET_MOVE_TYPE(move, moveType); // check non-user target - if (moveTarget & MOVE_TARGET_USER) + if (!(moveTarget & MOVE_TARGET_USER)) { // handle negative checks on non-user target // check powder moves diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 4d464c5d2..01944f508 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -3504,8 +3504,11 @@ void SetMoveEffect(bool32 primary, u32 certain) gBattleMons[gBattlerAttacker].status2 |= STATUS2_ESCAPE_PREVENTION; break; case MOVE_EFFECT_SCALE_SHOT: - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_DefDownSpeedUp; + if (!NoAliveMonsForEitherParty()) + { + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_DefDownSpeedUp; + } break; } } @@ -7700,6 +7703,7 @@ static bool32 CourtChangeSwapSideStatuses(void) UPDATE_COURTCHANGED_BATTLER(auroraVeilBattlerId); UPDATE_COURTCHANGED_BATTLER(tailwindBattlerId); UPDATE_COURTCHANGED_BATTLER(luckyChantBattlerId); + gBattleStruct->stickyWebUser ^= BIT_SIDE; // Track which side originally set the Sticky Web SWAP(sideTimerPlayer->stickyWebBattlerSide, sideTimerOpp->stickyWebBattlerSide, temp); diff --git a/src/battle_util.c b/src/battle_util.c index 041661cdc..c0a7f2150 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -1569,7 +1569,7 @@ void PrepareStringBattle(u16 stringId, u8 battler) && ((targetAbility == ABILITY_DEFIANT && CompareStat(gBattlerTarget, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN)) || (targetAbility == ABILITY_COMPETITIVE && CompareStat(gBattlerTarget, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN))) && gSpecialStatuses[gBattlerTarget].changedStatsBattlerId != BATTLE_PARTNER(gBattlerTarget) - // && gSpecialStatuses[gBattlerTarget].changedStatsBattlerId != gBattlerTarget) // Why was this here? Needs investigating + && ((gSpecialStatuses[gBattlerTarget].changedStatsBattlerId != gBattlerTarget) || gBattleScripting.stickyWebStatDrop == 1) && !(gBattleScripting.stickyWebStatDrop == 1 && gSideTimers[targetSide].stickyWebBattlerSide == targetSide)) // Sticky Web must have been set by the foe { gBattleScripting.stickyWebStatDrop = 0; From 746d9ea6c52c523ebd52d765fd63b112e9933912 Mon Sep 17 00:00:00 2001 From: BuffelSaft Date: Wed, 27 Apr 2022 22:23:20 +1200 Subject: [PATCH 073/130] Add AI_GetBattlerMoveTargetType() Add AI version of the function that handles move target selection, as it needs to have ability and item info that it may not have access to. --- include/battle_ai_util.h | 1 + src/battle_ai_main.c | 18 +++++++++--------- src/battle_ai_util.c | 12 +++++++++++- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 5ccf68c58..0b2afebae 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -60,6 +60,7 @@ bool32 IsAbilityOfRating(u16 ability, s8 rating); s8 GetAbilityRating(u16 ability); bool32 AI_IsAbilityOnSide(u32 battlerId, u32 ability); bool32 AI_MoveMakesContact(u32 ability, u32 holdEffect, u16 move); +u32 AI_GetBattlerMoveTargetType(u8 battlerId, u16 move); // stat stage checks bool32 AnyStatIsRaised(u8 battlerId); diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 16e830efe..192b75d74 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -550,7 +550,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) u8 atkPriority = GetMovePriority(battlerAtk, move); u16 moveEffect = gBattleMoves[move].effect; s32 moveType; - u16 moveTarget = GetBattlerMoveTargetType(battlerAtk, move); + u16 moveTarget = AI_GetBattlerMoveTargetType(battlerAtk, move); u16 accuracy = AI_GetMoveAccuracy(battlerAtk, battlerDef, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect, move); u8 effectiveness = AI_GetMoveEffectiveness(move, battlerAtk, battlerDef); bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk); @@ -2371,7 +2371,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } else { - if (GetBattlerMoveTargetType(battlerDef, instructedMove) & (MOVE_TARGET_SELECTED + if (AI_GetBattlerMoveTargetType(battlerDef, instructedMove) & (MOVE_TARGET_SELECTED | MOVE_TARGET_DEPENDS | MOVE_TARGET_RANDOM | MOVE_TARGET_BOTH @@ -2568,7 +2568,7 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // move data u8 moveType = gBattleMoves[move].type; u16 effect = gBattleMoves[move].effect; - u16 moveTarget = GetBattlerMoveTargetType(battlerAtk, move); + u16 moveTarget = AI_GetBattlerMoveTargetType(battlerAtk, move); // ally data u8 battlerAtkPartner = AI_DATA->battlerAtkPartner; u16 atkPartnerAbility = AI_DATA->atkPartnerAbility; @@ -2875,7 +2875,7 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (instructedMove != MOVE_NONE && !IS_MOVE_STATUS(instructedMove) - && (GetBattlerMoveTargetType(battlerAtkPartner, instructedMove) & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY))) // Use instruct on multi-target moves + && (AI_GetBattlerMoveTargetType(battlerAtkPartner, instructedMove) & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY))) // Use instruct on multi-target moves { RETURN_SCORE_PLUS(1); } @@ -3698,24 +3698,24 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); break; case MOVE_WIDE_GUARD: - if (predictedMove != MOVE_NONE && GetBattlerMoveTargetType(battlerDef, predictedMove) & (MOVE_TARGET_FOES_AND_ALLY | MOVE_TARGET_BOTH)) + if (predictedMove != MOVE_NONE && AI_GetBattlerMoveTargetType(battlerDef, predictedMove) & (MOVE_TARGET_FOES_AND_ALLY | MOVE_TARGET_BOTH)) { ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); } - else if (isDoubleBattle && GetBattlerMoveTargetType(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove) & MOVE_TARGET_FOES_AND_ALLY) + else if (isDoubleBattle && AI_GetBattlerMoveTargetType(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove) & MOVE_TARGET_FOES_AND_ALLY) { if (AI_DATA->atkAbility != ABILITY_TELEPATHY) ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); } break; case MOVE_CRAFTY_SHIELD: - if (predictedMove != MOVE_NONE && IS_MOVE_STATUS(predictedMove) && !(GetBattlerMoveTargetType(battlerDef, predictedMove) & MOVE_TARGET_USER)) + if (predictedMove != MOVE_NONE && IS_MOVE_STATUS(predictedMove) && !(AI_GetBattlerMoveTargetType(battlerDef, predictedMove) & MOVE_TARGET_USER)) ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); break; case MOVE_MAT_BLOCK: if (gDisableStructs[battlerAtk].isFirstTurn && predictedMove != MOVE_NONE - && !IS_MOVE_STATUS(predictedMove) && !(GetBattlerMoveTargetType(battlerDef, predictedMove) & MOVE_TARGET_USER)) + && !IS_MOVE_STATUS(predictedMove) && !(AI_GetBattlerMoveTargetType(battlerDef, predictedMove) & MOVE_TARGET_USER)) ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); break; case MOVE_KINGS_SHIELD: @@ -4160,7 +4160,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score += 10; break; case EFFECT_MAGIC_COAT: - if (IS_MOVE_STATUS(predictedMove) && GetBattlerMoveTargetType(battlerDef, predictedMove) & (MOVE_TARGET_SELECTED | MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_BOTH)) + if (IS_MOVE_STATUS(predictedMove) && AI_GetBattlerMoveTargetType(battlerDef, predictedMove) & (MOVE_TARGET_SELECTED | MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_BOTH)) score += 3; break; case EFFECT_RECYCLE: diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 4b344ecba..de4271bba 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -1251,6 +1251,16 @@ bool32 AI_WeatherHasEffect(void) return TRUE; } +u32 AI_GetBattlerMoveTargetType(u8 battlerId, u16 move) +{ + u32 target; + + if (gBattleMoves[move].effect == EFFECT_EXPANDING_FORCE && AI_IsTerrainAffected(battlerId, STATUS_FIELD_PSYCHIC_TERRAIN)) + return MOVE_TARGET_BOTH; + else + return gBattleMoves[move].target; +} + bool32 IsAromaVeilProtectedMove(u16 move) { u32 i; @@ -1919,7 +1929,7 @@ bool32 HasMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef, u8 accCheck, bool32 if (ignoreStatus && IS_MOVE_STATUS(moves[i])) continue; else if ((!IS_MOVE_STATUS(moves[i]) && gBattleMoves[moves[i]].accuracy == 0) - || GetBattlerMoveTargetType(battlerAtk, moves[i]) & (MOVE_TARGET_USER | MOVE_TARGET_OPPONENTS_FIELD)) + || AI_GetBattlerMoveTargetType(battlerAtk, moves[i]) & (MOVE_TARGET_USER | MOVE_TARGET_OPPONENTS_FIELD)) continue; if (AI_GetMoveAccuracy(battlerAtk, battlerDef, atkAbility, defAbility, atkHoldEffect, defHoldEffect, moves[i]) <= accCheck) return TRUE; From 66d8409075eb8ce3eaf53c06fa2f2a66c1449af0 Mon Sep 17 00:00:00 2001 From: LOuroboros Date: Wed, 27 Apr 2022 09:47:32 -0300 Subject: [PATCH 074/130] Update post review --- src/battle_message.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/battle_message.c b/src/battle_message.c index 7b2afab54..ee0cf63e4 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -3879,9 +3879,15 @@ struct TrainerSlide static const struct TrainerSlide sTrainerSlides[] = { - // Put any trainer slide-in messages inside this array. - // Example: - // {TRAINER_WALLY_VR_2, sText_AarghAlmostHadIt, sText_BoxIsFull, sText_123Poof}, + /* Put any trainer slide-in messages inside this array. + Example: + { + .trainerId = TRAINER_WALLY_VR_2, + .msgLastSwitchIn = sText_AarghAlmostHadIt, + .msgLastLowHp = sText_BoxIsFull, + .msgFirstDown = sText_123Poof, + }, + */ }; static u32 GetEnemyMonCount(bool32 onlyAlive) From cbf0a6704b79f9d12d92ab0d91014e7ce9efde82 Mon Sep 17 00:00:00 2001 From: BuffelSaft Date: Sun, 1 May 2022 12:54:33 +1200 Subject: [PATCH 075/130] Set Sticky Web user to Court Change user This is for Mirror Armor to track the current user of Sticky Web/the mon that caused the stat drop. --- src/battle_script_commands.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 01944f508..d6edb0ab2 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -7703,7 +7703,9 @@ static bool32 CourtChangeSwapSideStatuses(void) UPDATE_COURTCHANGED_BATTLER(auroraVeilBattlerId); UPDATE_COURTCHANGED_BATTLER(tailwindBattlerId); UPDATE_COURTCHANGED_BATTLER(luckyChantBattlerId); - gBattleStruct->stickyWebUser ^= BIT_SIDE; + + // For Mirror Armor only + gBattleStruct->stickyWebUser = gBattlerAttacker; // Track which side originally set the Sticky Web SWAP(sideTimerPlayer->stickyWebBattlerSide, sideTimerOpp->stickyWebBattlerSide, temp); From be6148d876fb15d9e9b916587982aee5e616da7c Mon Sep 17 00:00:00 2001 From: sneed Date: Mon, 2 May 2022 04:54:25 +0300 Subject: [PATCH 076/130] Add missing Heal Block functionalities --- src/battle_script_commands.c | 2 +- src/battle_util.c | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index d6edb0ab2..e20832bb5 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -7872,7 +7872,7 @@ static void Cmd_various(void) gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); return; case VARIOUS_CHECK_IF_GRASSY_TERRAIN_HEALS: - if ((gStatuses3[gActiveBattler] & (STATUS3_SEMI_INVULNERABLE)) + if ((gStatuses3[gActiveBattler] & (STATUS3_SEMI_INVULNERABLE | STATUS3_HEAL_BLOCK)) || BATTLER_MAX_HP(gActiveBattler) || !gBattleMons[gActiveBattler].hp || !(IsBattlerGrounded(gActiveBattler))) diff --git a/src/battle_util.c b/src/battle_util.c index c0a7f2150..775c8eebc 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -1689,6 +1689,7 @@ bool32 IsHealBlockPreventingMove(u32 battler, u32 move) case EFFECT_HEALING_WISH: case EFFECT_WISH: case EFFECT_DREAM_EATER: + case EFFECT_STRENGTH_SAP: return TRUE; default: return FALSE; @@ -6082,7 +6083,7 @@ bool32 HasEnoughHpToEatBerry(u32 battlerId, u32 hpFraction, u32 itemId) static u8 HealConfuseBerry(u32 battlerId, u32 itemId, u8 flavorId, bool32 end2) { - if (HasEnoughHpToEatBerry(battlerId, 2, itemId)) + if (HasEnoughHpToEatBerry(battlerId, 2, itemId) && !(gStatuses3[battlerId] & STATUS3_HEAL_BLOCK)) { PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, flavorId); @@ -6268,7 +6269,7 @@ u8 TryHandleSeed(u8 battler, u32 terrainFlag, u8 statId, u16 itemId, bool32 exec static u8 ItemHealHp(u32 battlerId, u32 itemId, bool32 end2, bool32 percentHeal) { - if (HasEnoughHpToEatBerry(battlerId, 2, itemId) + if (HasEnoughHpToEatBerry(battlerId, 2, itemId) && !(gStatuses3[battlerId] & STATUS3_HEAL_BLOCK) && !(gBattleScripting.overrideBerryRequirements && gBattleMons[battlerId].hp == gBattleMons[battlerId].maxHP)) { if (percentHeal) @@ -6707,7 +6708,8 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn) break; case HOLD_EFFECT_LEFTOVERS: LEFTOVERS: - if (gBattleMons[battlerId].hp < gBattleMons[battlerId].maxHP && !moveTurn) + if (gBattleMons[battlerId].hp < gBattleMons[battlerId].maxHP && !moveTurn + && !(gStatuses3[battlerId] & STATUS3_HEAL_BLOCK)) { gBattleMoveDamage = gBattleMons[battlerId].maxHP / 16; if (gBattleMoveDamage == 0) @@ -7137,7 +7139,8 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn) if (gSpecialStatuses[gBattlerAttacker].damagedMons // Need to have done damage && gBattlerAttacker != gBattlerTarget && gBattleMons[gBattlerAttacker].hp != gBattleMons[gBattlerAttacker].maxHP - && gBattleMons[gBattlerAttacker].hp != 0) + && gBattleMons[gBattlerAttacker].hp != 0 + && !(gStatuses3[battlerId] & STATUS3_HEAL_BLOCK)) { gLastUsedItem = atkItem; gPotentialItemEffectBattler = gBattlerAttacker; From b17d1f7816bde54b64c306968a1c6fdc0d42da85 Mon Sep 17 00:00:00 2001 From: sneed Date: Mon, 2 May 2022 17:56:09 +0300 Subject: [PATCH 077/130] Add generation specific interactions --- data/battle_scripts_1.s | 4 ++++ include/constants/battle_config.h | 2 ++ src/battle_util.c | 32 +++++++++++++++++++++++++------ 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 6574e26ab..a58dc1339 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -1272,6 +1272,7 @@ BattleScript_StrengthSapTryHp: attackanimation waitanimation BattleScript_StrengthSapHp: + jumpifstatus3 BS_ATTACKER, STATUS3_HEAL_BLOCK, BattleScript_MoveEnd jumpiffullhp BS_ATTACKER, BattleScript_MoveEnd manipulatedamage DMG_BIG_ROOT healthbarupdate BS_ATTACKER @@ -3103,6 +3104,7 @@ BattleScript_EffectAbsorb:: waitmessage B_WAIT_TIME_LONG resultmessage waitmessage B_WAIT_TIME_LONG + jumpifstatus3 BS_ATTACKER, STATUS3_HEAL_BLOCK, BattleScript_AbsorbHealBlock setdrainedhp manipulatedamage DMG_BIG_ROOT orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_IGNORE_DISGUISE @@ -3122,6 +3124,7 @@ BattleScript_AbsorbUpdateHp:: waitmessage B_WAIT_TIME_LONG BattleScript_AbsorbTryFainting:: tryfaintmon BS_ATTACKER +BattleScript_AbsorbHealBlock:: tryfaintmon BS_TARGET goto BattleScript_MoveEnd @@ -3228,6 +3231,7 @@ BattleScript_DreamEaterWorked: waitmessage B_WAIT_TIME_LONG resultmessage waitmessage B_WAIT_TIME_LONG + jumpifstatus3 BS_ATTACKER, STATUS3_HEAL_BLOCK, BattleScript_DreamEaterTryFaintEnd setdrainedhp manipulatedamage DMG_BIG_ROOT orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE diff --git a/include/constants/battle_config.h b/include/constants/battle_config.h index a3ef7cc94..29395dc80 100644 --- a/include/constants/battle_config.h +++ b/include/constants/battle_config.h @@ -170,6 +170,8 @@ #define B_BRICK_BREAK GEN_7 // In Gen4+, you can destroy your own side's screens. In Gen 5+, screens are not removed if the target is immune. #define B_WISH_HP_SOURCE GEN_7 // In Gen5+, Wish heals half of the user's max HP instead of the target's. #define B_RAMPAGE_CANCELLING GEN_7 // In Gen5+, a failed Thrash, etc, will cancel except on its last turn. +#define B_HEAL_BLOCKING GEN_7 // In Gen5+, Heal Block prevents healing by Black Sludge, Leftovers, Shell Bell. Affected Pokémon will not consume held HP-restoring Berries or Berry Juice. + // Draining abilities will not heal but will prevent damage. In Gen6+, Heal Block prevents the use of most HP-draining moves. // Ability settings #define B_EXPANDED_ABILITY_NAMES TRUE // If TRUE, ability names are increased from 12 characters to 16 characters. diff --git a/src/battle_util.c b/src/battle_util.c index 775c8eebc..1aa917f82 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -1680,7 +1680,11 @@ bool32 IsHealBlockPreventingMove(u32 battler, u32 move) switch (gBattleMoves[move].effect) { +#if B_HEAL_BLOCKING >= GEN_6 case EFFECT_ABSORB: + case EFFECT_STRENGTH_SAP: + case EFFECT_DREAM_EATER: +#endif case EFFECT_MORNING_SUN: case EFFECT_MOONLIGHT: case EFFECT_RESTORE_HP: @@ -1688,8 +1692,6 @@ bool32 IsHealBlockPreventingMove(u32 battler, u32 move) case EFFECT_ROOST: case EFFECT_HEALING_WISH: case EFFECT_WISH: - case EFFECT_DREAM_EATER: - case EFFECT_STRENGTH_SAP: return TRUE; default: return FALSE; @@ -4908,7 +4910,11 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move if (effect == 1) // Drain Hp ability. { +#if B_HEAL_BLOCKING >= GEN_5 if (BATTLER_MAX_HP(battler) || gStatuses3[battler] & STATUS3_HEAL_BLOCK) +#else + if (BATTLER_MAX_HP(battler)) +#endif { if ((gProtectStructs[gBattlerAttacker].notFirstStrike)) gBattlescriptCurrInstr = BattleScript_MonMadeMoveUseless; @@ -6083,7 +6089,11 @@ bool32 HasEnoughHpToEatBerry(u32 battlerId, u32 hpFraction, u32 itemId) static u8 HealConfuseBerry(u32 battlerId, u32 itemId, u8 flavorId, bool32 end2) { +#if B_HEAL_BLOCKING >= GEN_5 if (HasEnoughHpToEatBerry(battlerId, 2, itemId) && !(gStatuses3[battlerId] & STATUS3_HEAL_BLOCK)) +#else + if (HasEnoughHpToEatBerry(battlerId, 2, itemId)) +#endif { PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, flavorId); @@ -6269,7 +6279,11 @@ u8 TryHandleSeed(u8 battler, u32 terrainFlag, u8 statId, u16 itemId, bool32 exec static u8 ItemHealHp(u32 battlerId, u32 itemId, bool32 end2, bool32 percentHeal) { +#if B_HEAL_BLOCKING >= GEN_5 if (HasEnoughHpToEatBerry(battlerId, 2, itemId) && !(gStatuses3[battlerId] & STATUS3_HEAL_BLOCK) +#else + if (HasEnoughHpToEatBerry(battlerId, 2, itemId) +#endif && !(gBattleScripting.overrideBerryRequirements && gBattleMons[battlerId].hp == gBattleMons[battlerId].maxHP)) { if (percentHeal) @@ -6708,8 +6722,11 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn) break; case HOLD_EFFECT_LEFTOVERS: LEFTOVERS: - if (gBattleMons[battlerId].hp < gBattleMons[battlerId].maxHP && !moveTurn - && !(gStatuses3[battlerId] & STATUS3_HEAL_BLOCK)) +#if B_HEAL_BLOCKING >= GEN_5 + if (gBattleMons[battlerId].hp < gBattleMons[battlerId].maxHP && !moveTurn && !(gStatuses3[battlerId] & STATUS3_HEAL_BLOCK)) +#else + if (gBattleMons[battlerId].hp < gBattleMons[battlerId].maxHP && !moveTurn) +#endif { gBattleMoveDamage = gBattleMons[battlerId].maxHP / 16; if (gBattleMoveDamage == 0) @@ -7139,8 +7156,11 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn) if (gSpecialStatuses[gBattlerAttacker].damagedMons // Need to have done damage && gBattlerAttacker != gBattlerTarget && gBattleMons[gBattlerAttacker].hp != gBattleMons[gBattlerAttacker].maxHP - && gBattleMons[gBattlerAttacker].hp != 0 - && !(gStatuses3[battlerId] & STATUS3_HEAL_BLOCK)) +#if B_HEAL_BLOCKING >= GEN_5 + && gBattleMons[gBattlerAttacker].hp != 0 && !(gStatuses3[battlerId] & STATUS3_HEAL_BLOCK)) +#else + && gBattleMons[gBattlerAttacker].hp != 0) +#endif { gLastUsedItem = atkItem; gPotentialItemEffectBattler = gBattlerAttacker; From 60d7d8f97e044f8c69a52daa72ef30ed6c1aa119 Mon Sep 17 00:00:00 2001 From: sneed Date: Tue, 3 May 2022 03:38:44 +0300 Subject: [PATCH 078/130] Initial Commit --- data/battle_scripts_1.s | 45 +++++++++++++++++++++++++ include/constants/battle_move_effects.h | 3 +- src/battle_script_commands.c | 2 +- src/data/battle_moves.h | 2 +- 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 6574e26ab..61fbf91aa 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -410,6 +410,51 @@ gBattleScriptsForMoveEffects:: .4byte BattleScript_EffectHit @ EFFECT_RISING_VOLTAGE .4byte BattleScript_EffectHit @ EFFECT_BEAK_BLAST .4byte BattleScript_EffectCourtChange @ EFFECT_COURT_CHANGE + .4byte BattleScript_EffectSteelBeam @ EFFECT_STEEL_BEAM + +BattleScript_EffectSteelBeam:: + attackcanceler + attackstring + ppreduce + accuracycheck BattleScript_SteelBeamMiss, ACC_CURR_MOVE + critcalc + damagecalc + adjustdamage + attackanimation + waitanimation + effectivenesssound + hitanimation BS_TARGET + waitstate + healthbarupdate BS_TARGET + datahpupdate BS_TARGET + critmessage + waitmessage B_WAIT_TIME_LONG + resultmessage + waitmessage B_WAIT_TIME_LONG + seteffectwithchance + jumpifability BS_ATTACKER, ABILITY_MAGIC_GUARD, BattleScript_SteelBeamAfterSelfDamage + call BattleScript_SteelBeamSelfDamage +BattleScript_SteelBeamAfterSelfDamage:: + waitstate + tryfaintmon BS_ATTACKER + tryfaintmon BS_TARGET + goto BattleScript_MoveEnd +BattleScript_SteelBeamMiss:: + pause B_WAIT_TIME_SHORT + effectivenesssound + resultmessage + waitmessage B_WAIT_TIME_LONG + jumpifability BS_ATTACKER, ABILITY_MAGIC_GUARD, BattleScript_MoveEnd + bichalfword gMoveResultFlags, MOVE_RESULT_MISSED + call BattleScript_SteelBeamSelfDamage + orhalfword gMoveResultFlags, MOVE_RESULT_MISSED + goto BattleScript_SteelBeamAfterSelfDamage + +BattleScript_SteelBeamSelfDamage:: + dmg_1_2_attackerhp + healthbarupdate BS_ATTACKER + datahpupdate BS_ATTACKER + return BattleScript_EffectCourtChange:: attackcanceler diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index 3cc3d72b3..c3460bcfe 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -393,7 +393,8 @@ #define EFFECT_RISING_VOLTAGE 387 #define EFFECT_BEAK_BLAST 388 #define EFFECT_COURT_CHANGE 389 +#define EFFECT_STEEL_BEAM 390 -#define NUM_BATTLE_MOVE_EFFECTS 390 +#define NUM_BATTLE_MOVE_EFFECTS 391 #endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index d6edb0ab2..072130b8b 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -9882,7 +9882,7 @@ static void Cmd_manipulatedamage(void) gBattleMoveDamage = GetDrainedBigRootHp(gBattlerAttacker, gBattleMoveDamage); break; case DMG_1_2_ATTACKER_HP: - gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 2; + gBattleMoveDamage = (gBattleMons[gBattlerAttacker].maxHP + 1) / 2; // Half of Max HP Rounded UP break; case DMG_RECOIL_FROM_IMMUNE: gBattleMoveDamage = gBattleMons[gBattlerTarget].maxHP / 2; diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index 1f90abf03..2035acff7 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -11221,7 +11221,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_STEEL_BEAM] = { - .effect = EFFECT_RECOIL_50, + .effect = EFFECT_STEEL_BEAM, .power = 140, .type = TYPE_STEEL, .accuracy = 95, From 865b771db7ad3ad31b427ad45ce537e8f4ba4bd4 Mon Sep 17 00:00:00 2001 From: sneed Date: Thu, 5 May 2022 00:57:19 +0300 Subject: [PATCH 079/130] initial commit --- include/constants/battle_config.h | 2 +- src/battle_util.c | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/include/constants/battle_config.h b/include/constants/battle_config.h index a3ef7cc94..a8d6ebdf7 100644 --- a/include/constants/battle_config.h +++ b/include/constants/battle_config.h @@ -181,7 +181,7 @@ #define B_FLASH_FIRE_FROZEN GEN_7 // In Gen5+, Flash Fire can trigger even when frozen, when it couldn't before. #define B_SYNCHRONIZE_NATURE GEN_8 // In Gen8, if a Pokémon with Synchronize is leading the party, it's 100% guaranteed that wild Pokémon will have the same ability, as opposed to 50% previously. #define B_SYNCHRONIZE_TOXIC GEN_8 // In Gen5+, if a Pokémon with Synchronize is badly poisoned, the opponent will also become badly poisoned. Previously, the opponent would become regular poisoned. -#define B_UPDATED_INTIMIDATE GEN_8 // In Gen8, Intimidate doesn't work on opponents with the Inner Focus, Scrappy, Own Tempo or Oblivious abilities. +#define B_UPDATED_INTIMIDATE GEN_8 // In Gen8, Intimidate doesn't work on opponents with the Inner Focus, Scrappy, Own Tempo or Oblivious abilities. It also activates Rattled. // Item settings #define B_HP_BERRIES GEN_7 // In Gen4+, berries which restore hp activate immediately after HP drops to half. In Gen3, the effect occurs at the end of the turn. diff --git a/src/battle_util.c b/src/battle_util.c index c0a7f2150..c18e4f113 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -1581,6 +1581,16 @@ void PrepareStringBattle(u16 stringId, u8 battler) else SET_STATCHANGER(STAT_SPATK, 2, FALSE); } +#if B_UPDATED_INTIMIDATE >= GEN_8 + else if (stringId == STRINGID_PKMNCUTSATTACKWITH && targetAbility == ABILITY_RATTLED + && CompareStat(gBattlerTarget, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN)) + { + gBattlerAbility = gBattlerTarget; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_DefiantActivates; + SET_STATCHANGER(STAT_SPEED, 1, FALSE); + } +#endif gActiveBattler = battler; BtlController_EmitPrintString(BUFFER_A, stringId); From 6c23eb431de0f3f6538d49c1e8a98fe835feedb4 Mon Sep 17 00:00:00 2001 From: sneed Date: Thu, 5 May 2022 13:56:59 +0300 Subject: [PATCH 080/130] Heal Pulse and Pollen Puff --- data/battle_scripts_1.s | 2 ++ src/battle_util.c | 1 + 2 files changed, 3 insertions(+) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index a58dc1339..132a8ea35 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -2410,6 +2410,8 @@ BattleScript_EffectHealPulse: attackcanceler attackstring ppreduce + jumpifstatus3 BS_ATTACKER, STATUS3_HEAL_BLOCK, BattleScript_MoveUsedHealBlockPrevents @ stops pollen puff + jumpifstatus3 BS_TARGET, STATUS3_HEAL_BLOCK, BattleScript_MoveUsedHealBlockPrevents accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON jumpifsubstituteblocks BattleScript_ButItFailed tryhealpulse BS_TARGET, BattleScript_AlreadyAtFullHp diff --git a/src/battle_util.c b/src/battle_util.c index 1aa917f82..6569c6a1b 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -1692,6 +1692,7 @@ bool32 IsHealBlockPreventingMove(u32 battler, u32 move) case EFFECT_ROOST: case EFFECT_HEALING_WISH: case EFFECT_WISH: + case EFFECT_HEAL_PULSE: return TRUE; default: return FALSE; From 6235970722ad9eab298deaf3b66580f9a78dd2d9 Mon Sep 17 00:00:00 2001 From: AgustinGDLV Date: Thu, 5 May 2022 11:41:27 -0700 Subject: [PATCH 081/130] added special battle evo changes --- include/constants/pokemon.h | 2 ++ src/battle_main.c | 37 +++++++++++++++++++++++++++++++++--- src/battle_script_commands.c | 7 +++++++ src/pokemon.c | 13 +++++++++++++ 4 files changed, 56 insertions(+), 3 deletions(-) diff --git a/include/constants/pokemon.h b/include/constants/pokemon.h index c375bbdd1..a7f0e3e4e 100644 --- a/include/constants/pokemon.h +++ b/include/constants/pokemon.h @@ -379,6 +379,7 @@ #define EVO_SPECIFIC_MAP 32 // Pokémon levels up on specified map #define EVO_LEVEL_NATURE_AMPED 33 // Pokémon reaches the specified level, it has a Hardy, Brave, Adamant, Naughty, Docile, Impish, Lax, Hasty, Jolly, Naive, Rash, Sassy, or Quirky nature. #define EVO_LEVEL_NATURE_LOW_KEY 34 // Pokémon reaches the specified level, it has a Lonely, Bold, Relaxed, Timid, Serious, Modest, Mild, Quiet, Bashful, Calm, Gentle, or Careful nature. +#define EVO_CRITICAL_HITS 35 // Pokémon performs specified number of critical hits in one battle #define EVOS_PER_MON 10 @@ -387,6 +388,7 @@ #define EVO_MODE_TRADE 1 #define EVO_MODE_ITEM_USE 2 #define EVO_MODE_ITEM_CHECK 3 // If an Everstone is being held, still want to show that the stone *could* be used on that Pokémon to evolve +#define EVO_MODE_BATTLE_SPECIAL 4 #define NUM_MALE_LINK_FACILITY_CLASSES 8 #define NUM_FEMALE_LINK_FACILITY_CLASSES 8 diff --git a/src/battle_main.c b/src/battle_main.c index 479cafae6..ca59ff86e 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -115,6 +115,7 @@ static void HandleEndTurn_MonFled(void); static void HandleEndTurn_FinishBattle(void); static void SpriteCB_UnusedBattleInit(struct Sprite* sprite); static void SpriteCB_UnusedBattleInit_Main(struct Sprite *sprite); +static void TrySpecialEvolution(void); EWRAM_DATA u16 gBattle_BG0_X = 0; EWRAM_DATA u16 gBattle_BG0_Y = 0; @@ -237,6 +238,8 @@ EWRAM_DATA bool8 gHasFetchedBall = FALSE; EWRAM_DATA u8 gLastUsedBall = 0; EWRAM_DATA u16 gLastThrownBall = 0; EWRAM_DATA bool8 gSwapDamageCategory = FALSE; // Photon Geyser, Shell Side Arm, Light That Burns the Sky +EWRAM_DATA u8 gPartyCriticalHits[PARTY_SIZE] = {0}; +EWRAM_DATA static u8 sTriedEvolving = 0; void (*gPreBattleCallback1)(void); void (*gBattleMainFunc)(void); @@ -2999,6 +3002,7 @@ static void BattleStartClearSetData(void) gBattleStruct->usedHeldItems[i][0] = 0; gBattleStruct->usedHeldItems[i][1] = 0; gBattleStruct->itemStolen[i].originalItem = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM); + gPartyCriticalHits[i] = 0; } gSwapDamageCategory = FALSE; // Photon Geyser, Shell Side Arm, Light That Burns the Sky @@ -5154,9 +5158,16 @@ static void FreeResetData_ReturnToOvOrDoEvolutions(void) gIsFishingEncounter = FALSE; gIsSurfingEncounter = FALSE; ResetSpriteData(); - if (gLeveledUpInBattle && (gBattleOutcome == B_OUTCOME_WON || gBattleOutcome == B_OUTCOME_CAUGHT)) + if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK + | BATTLE_TYPE_RECORDED_LINK + | BATTLE_TYPE_FIRST_BATTLE + | BATTLE_TYPE_SAFARI + | BATTLE_TYPE_FRONTIER + | BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_WALLY_TUTORIAL)) + && (gBattleOutcome == B_OUTCOME_WON || gBattleOutcome == B_OUTCOME_CAUGHT)) { - gBattleMainFunc = TryEvolvePokemon; + gBattleMainFunc = TrySpecialEvolution; } else { @@ -5174,6 +5185,26 @@ static void FreeResetData_ReturnToOvOrDoEvolutions(void) } } +static void TrySpecialEvolution(void) // Attempts to perform non-level related battle evolutions (not the script command). +{ + s32 i; + + for (i = 0; i < PARTY_SIZE; i++) + { + u16 species = GetEvolutionTargetSpecies(&gPlayerParty[i], EVO_MODE_BATTLE_SPECIAL, i, SPECIES_NONE); + if (species != SPECIES_NONE && !(sTriedEvolving & gBitTable[i])) + { + sTriedEvolving |= gBitTable[i]; + FreeAllWindowBuffers(); + gBattleMainFunc = WaitForEvoSceneToFinish; + EvolutionScene(&gPlayerParty[i], species, TRUE, i); + return; + } + } + sTriedEvolving = 0; + gBattleMainFunc = TryEvolvePokemon; +} + static void TryEvolvePokemon(void) { s32 i; @@ -5208,7 +5239,7 @@ static void TryEvolvePokemon(void) static void WaitForEvoSceneToFinish(void) { if (gMain.callback2 == BattleMainCB2) - gBattleMainFunc = TryEvolvePokemon; + gBattleMainFunc = TrySpecialEvolution; } static void ReturnFromBattleToOverworld(void) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index d6edb0ab2..4ae67d1a2 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1914,6 +1914,7 @@ s8 GetInverseCritChance(u8 battlerAtk, u8 battlerDef, u32 move) static void Cmd_critcalc(void) { + u16 partySlot; s32 critChance = CalcCritChanceStage(gBattlerAttacker, gBattlerTarget, gCurrentMove, TRUE); gPotentialItemEffectBattler = gBattlerAttacker; @@ -1928,6 +1929,12 @@ static void Cmd_critcalc(void) else gIsCriticalHit = FALSE; + // Counter for EVO_CRITICAL_HITS. + partySlot = gBattlerPartyIndexes[gBattlerAttacker]; + if (gIsCriticalHit && GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER + && !(gBattleTypeFlags & BATTLE_TYPE_MULTI && GetBattlerPosition(gBattlerAttacker) == B_POSITION_PLAYER_LEFT)) + gPartyCriticalHits[partySlot]++; + gBattlescriptCurrInstr++; } diff --git a/src/pokemon.c b/src/pokemon.c index 71176d2eb..ff2dcbe51 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -5394,6 +5394,19 @@ u16 GetEvolutionTargetSpecies(struct Pokemon *mon, u8 mode, u16 evolutionItem) } } break; + // Battle evolution without leveling; party slot is being passed into the evolutionItem arg. + case EVO_MODE_BATTLE_SPECIAL: + for (i = 0; i < EVOS_PER_MON; i++) + { + switch (gEvolutionTable[species][i].method) + { + case EVO_CRITICAL_HITS: + if (gPartyCriticalHits[evolutionItem] >= gEvolutionTable[species][i].param) + targetSpecies = gEvolutionTable[species][i].targetSpecies; + break; + } + } + break; } return targetSpecies; From e343c73cd8cd3ad16bd045f9cf8b48b00f05f638 Mon Sep 17 00:00:00 2001 From: AgustinGDLV Date: Thu, 5 May 2022 15:17:31 -0700 Subject: [PATCH 082/130] fixed compile error + small tweaks --- src/battle_main.c | 6 +++++- src/pokemon.c | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/battle_main.c b/src/battle_main.c index ca59ff86e..ee6166062 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -5191,7 +5191,11 @@ static void TrySpecialEvolution(void) // Attempts to perform non-level related b for (i = 0; i < PARTY_SIZE; i++) { - u16 species = GetEvolutionTargetSpecies(&gPlayerParty[i], EVO_MODE_BATTLE_SPECIAL, i, SPECIES_NONE); + #ifndef POKEMON_EXPANSION + u16 species = GetEvolutionTargetSpecies(&gPlayerParty[i], EVO_MODE_BATTLE_SPECIAL, i); + #else + u16 species = GetEvolutionTargetSpecies(&gPlayerParty[i], EVO_MODE_BATTLE_SPECIAL, i, SPECIES_NONE); + #endif if (species != SPECIES_NONE && !(sTriedEvolving & gBitTable[i])) { sTriedEvolving |= gBitTable[i]; diff --git a/src/pokemon.c b/src/pokemon.c index ff2dcbe51..fe2bcf9dd 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -5394,6 +5394,7 @@ u16 GetEvolutionTargetSpecies(struct Pokemon *mon, u8 mode, u16 evolutionItem) } } break; + #ifdef BATTLE_ENGINE // Battle evolution without leveling; party slot is being passed into the evolutionItem arg. case EVO_MODE_BATTLE_SPECIAL: for (i = 0; i < EVOS_PER_MON; i++) @@ -5407,6 +5408,7 @@ u16 GetEvolutionTargetSpecies(struct Pokemon *mon, u8 mode, u16 evolutionItem) } } break; + #endif } return targetSpecies; From e730d64945b95aba49eaf924ef29c553abd2e433 Mon Sep 17 00:00:00 2001 From: AgustinGDLV Date: Thu, 5 May 2022 15:54:33 -0700 Subject: [PATCH 083/130] corrections --- include/battle.h | 1 + src/pokemon.c | 15 --------------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/include/battle.h b/include/battle.h index 4068454bf..fde4162c7 100644 --- a/include/battle.h +++ b/include/battle.h @@ -932,5 +932,6 @@ extern bool8 gHasFetchedBall; extern u8 gLastUsedBall; extern u16 gLastThrownBall; extern bool8 gSwapDamageCategory; // Photon Geyser, Shell Side Arm, Light That Burns the Sky +extern u8 gPartyCriticalHits[PARTY_SIZE]; #endif // GUARD_BATTLE_H diff --git a/src/pokemon.c b/src/pokemon.c index fe2bcf9dd..71176d2eb 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -5394,21 +5394,6 @@ u16 GetEvolutionTargetSpecies(struct Pokemon *mon, u8 mode, u16 evolutionItem) } } break; - #ifdef BATTLE_ENGINE - // Battle evolution without leveling; party slot is being passed into the evolutionItem arg. - case EVO_MODE_BATTLE_SPECIAL: - for (i = 0; i < EVOS_PER_MON; i++) - { - switch (gEvolutionTable[species][i].method) - { - case EVO_CRITICAL_HITS: - if (gPartyCriticalHits[evolutionItem] >= gEvolutionTable[species][i].param) - targetSpecies = gEvolutionTable[species][i].targetSpecies; - break; - } - } - break; - #endif } return targetSpecies; From 07b42d62ef9db2d01b45b2312c53d5351b4453cc Mon Sep 17 00:00:00 2001 From: AgustinGDLV Date: Thu, 5 May 2022 20:46:45 -0700 Subject: [PATCH 084/130] fixed shed shell --- src/battle_main.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/battle_main.c b/src/battle_main.c index 479cafae6..3edbea48b 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -4020,10 +4020,18 @@ static void HandleTurnActionSelectionState(void) { BtlController_EmitChoosePokemon(BUFFER_A, PARTY_ACTION_CANT_SWITCH, PARTY_SIZE, ABILITY_NONE, gBattleStruct->battlerPartyOrders[gActiveBattler]); } + #ifdef ITEM_EXPANSION + else if ((i = IsAbilityPreventingEscape(gActiveBattler) + && ItemId_GetHoldEffect(gBattleMons[gActiveBattler].item) != HOLD_EFFECT_SHED_SHELL)) + { + BtlController_EmitChoosePokemon(BUFFER_A, ((i - 1) << 4) | PARTY_ACTION_ABILITY_PREVENTS, PARTY_SIZE, gBattleMons[i - 1].ability, gBattleStruct->battlerPartyOrders[gActiveBattler]); + } + #else else if ((i = IsAbilityPreventingEscape(gActiveBattler))) { BtlController_EmitChoosePokemon(BUFFER_A, ((i - 1) << 4) | PARTY_ACTION_ABILITY_PREVENTS, PARTY_SIZE, gBattleMons[i - 1].ability, gBattleStruct->battlerPartyOrders[gActiveBattler]); } + #endif else { if (gActiveBattler == 2 && gChosenActionByBattler[0] == B_ACTION_SWITCH) From aff1d3949f23d253cd3a3692d2f49a5f8489784c Mon Sep 17 00:00:00 2001 From: AgustinGDLV Date: Thu, 5 May 2022 21:58:16 -0700 Subject: [PATCH 085/130] fixed spotlight function --- src/battle_message.c | 2 +- src/battle_script_commands.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/battle_message.c b/src/battle_message.c index 3e2d9abd9..8cf9a508b 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -220,7 +220,7 @@ static const u8 sText_PkmnForesawAttack[] = _("{B_ATK_NAME_WITH_PREFIX} foresaw\ static const u8 sText_PkmnTookAttack[] = _("{B_DEF_NAME_WITH_PREFIX} took the\n{B_BUFF1} attack!"); static const u8 sText_PkmnChoseXAsDestiny[] = _("{B_ATK_NAME_WITH_PREFIX} chose\n{B_CURRENT_MOVE} as its destiny!"); static const u8 sText_PkmnAttack[] = _("{B_BUFF1}'s attack!"); -static const u8 sText_PkmnCenterAttention[] = _("{B_ATK_NAME_WITH_PREFIX} became the\ncenter of attention!"); +static const u8 sText_PkmnCenterAttention[] = _("{B_DEF_NAME_WITH_PREFIX} became the\ncenter of attention!"); static const u8 sText_PkmnChargingPower[] = _("{B_ATK_NAME_WITH_PREFIX} began\ncharging power!"); static const u8 sText_NaturePowerTurnedInto[] = _("NATURE POWER turned into\n{B_CURRENT_MOVE}!"); static const u8 sText_PkmnStatusNormal[] = _("{B_ATK_NAME_WITH_PREFIX}'s status\nreturned to normal!"); diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index d6edb0ab2..227d2f573 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -12397,9 +12397,9 @@ static void Cmd_jumpifattackandspecialattackcannotfall(void) // memento static void Cmd_setforcedtarget(void) // follow me { - gSideTimers[GetBattlerSide(gBattlerAttacker)].followmeTimer = 1; - gSideTimers[GetBattlerSide(gBattlerAttacker)].followmeTarget = gBattlerAttacker; - gSideTimers[GetBattlerSide(gBattlerAttacker)].followmePowder = TestMoveFlags(gCurrentMove, FLAG_POWDER); + gSideTimers[GetBattlerSide(gBattlerTarget)].followmeTimer = 1; + gSideTimers[GetBattlerSide(gBattlerTarget)].followmeTarget = gBattlerTarget; + gSideTimers[GetBattlerSide(gBattlerTarget)].followmePowder = TestMoveFlags(gCurrentMove, FLAG_POWDER); gBattlescriptCurrInstr++; } From 74cc8c5ecb18962204f3ff1a42c8e9cc7f998b60 Mon Sep 17 00:00:00 2001 From: AgustinGDLV Date: Thu, 5 May 2022 22:37:28 -0700 Subject: [PATCH 086/130] fixed bolt beak switch-in boost --- src/battle_util.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/battle_util.c b/src/battle_util.c index c0a7f2150..55602cdc1 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -8119,7 +8119,8 @@ static u16 CalcMoveBasePower(u16 move, u8 battlerAtk, u8 battlerDef) basePower *= 2; break; case EFFECT_BOLT_BEAK: - if (GetBattlerTurnOrderNum(battlerAtk) < GetBattlerTurnOrderNum(battlerDef)) + if (GetBattlerTurnOrderNum(battlerAtk) < GetBattlerTurnOrderNum(battlerDef) + || gDisableStructs[battlerDef].isFirstTurn == 2) basePower *= 2; break; case EFFECT_ROUND: From 382cd41d12c22ef7e4ea1dfddb0be5263f0b0ac0 Mon Sep 17 00:00:00 2001 From: AgustinGDLV Date: Thu, 5 May 2022 22:49:46 -0700 Subject: [PATCH 087/130] realized hold effect is defined already --- src/battle_main.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/battle_main.c b/src/battle_main.c index 3edbea48b..4adca1987 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -4020,18 +4020,11 @@ static void HandleTurnActionSelectionState(void) { BtlController_EmitChoosePokemon(BUFFER_A, PARTY_ACTION_CANT_SWITCH, PARTY_SIZE, ABILITY_NONE, gBattleStruct->battlerPartyOrders[gActiveBattler]); } - #ifdef ITEM_EXPANSION else if ((i = IsAbilityPreventingEscape(gActiveBattler) && ItemId_GetHoldEffect(gBattleMons[gActiveBattler].item) != HOLD_EFFECT_SHED_SHELL)) { BtlController_EmitChoosePokemon(BUFFER_A, ((i - 1) << 4) | PARTY_ACTION_ABILITY_PREVENTS, PARTY_SIZE, gBattleMons[i - 1].ability, gBattleStruct->battlerPartyOrders[gActiveBattler]); } - #else - else if ((i = IsAbilityPreventingEscape(gActiveBattler))) - { - BtlController_EmitChoosePokemon(BUFFER_A, ((i - 1) << 4) | PARTY_ACTION_ABILITY_PREVENTS, PARTY_SIZE, gBattleMons[i - 1].ability, gBattleStruct->battlerPartyOrders[gActiveBattler]); - } - #endif else { if (gActiveBattler == 2 && gChosenActionByBattler[0] == B_ACTION_SWITCH) From ef7cd3cdfecad531ec57230e6876db4cff68e7b6 Mon Sep 17 00:00:00 2001 From: sneed Date: Fri, 6 May 2022 11:15:24 +0300 Subject: [PATCH 088/130] BattleScript_DefiantActivates rename --- data/battle_scripts_1.s | 2 +- include/battle_scripts.h | 2 +- src/battle_util.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 6574e26ab..0dc88eb43 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -7925,7 +7925,7 @@ BattleScript_DrizzleActivates:: call BattleScript_WeatherFormChanges end3 -BattleScript_DefiantActivates:: +BattleScript_AbilityRaisesDefenderStat:: pause B_WAIT_TIME_SHORT call BattleScript_AbilityPopUp statbuffchange 0, NULL diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 740d27148..5fd70159b 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -308,7 +308,7 @@ extern const u8 BattleScript_MistySurgeActivates[]; extern const u8 BattleScript_ElectricSurgeActivates[]; extern const u8 BattleScript_SpectralThiefSteal[]; extern const u8 BattleScript_StatUpMsg[]; -extern const u8 BattleScript_DefiantActivates[]; +extern const u8 BattleScript_AbilityRaisesDefenderStat[]; extern const u8 BattleScript_PowderMoveNoEffect[]; extern const u8 BattleScript_GrassyTerrainHeals[]; extern const u8 BattleScript_VCreateStatLoss[]; diff --git a/src/battle_util.c b/src/battle_util.c index c18e4f113..a5542e225 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -1575,7 +1575,7 @@ void PrepareStringBattle(u16 stringId, u8 battler) gBattleScripting.stickyWebStatDrop = 0; gBattlerAbility = gBattlerTarget; BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_DefiantActivates; + gBattlescriptCurrInstr = BattleScript_AbilityRaisesDefenderStat; if (targetAbility == ABILITY_DEFIANT) SET_STATCHANGER(STAT_ATK, 2, FALSE); else @@ -1587,7 +1587,7 @@ void PrepareStringBattle(u16 stringId, u8 battler) { gBattlerAbility = gBattlerTarget; BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_DefiantActivates; + gBattlescriptCurrInstr = BattleScript_AbilityRaisesDefenderStat; SET_STATCHANGER(STAT_SPEED, 1, FALSE); } #endif From 07579bd42bbf5087274af3504af9da3d92df558d Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Sat, 7 May 2022 09:56:32 -0400 Subject: [PATCH 089/130] prevent ally pollen puff selection under heal block. add some ai checks for heal block --- include/battle_util.h | 1 + src/battle_ai_main.c | 8 ++++++++ src/battle_controller_opponent.c | 11 ++++++++--- src/battle_controller_player.c | 6 ++++-- src/battle_util.c | 9 +++++++++ 5 files changed, 30 insertions(+), 5 deletions(-) diff --git a/include/battle_util.h b/include/battle_util.h index d2d7ac29f..dee85ef7f 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -171,6 +171,7 @@ void TryToApplyMimicry(u8 battlerId, bool8 various); void TryToRevertMimicry(void); void RestoreBattlerOriginalTypes(u8 battlerId); u32 GetBattlerMoveTargetType(u8 battlerId, u16 move); +bool32 CanTargetBattler(u8 battlerAtk, u8 battlerDef, u16 move); // Ability checks bool32 IsRolePlayBannedAbilityAtk(u16 ability); bool32 IsRolePlayBannedAbility(u16 ability); diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 192b75d74..5c7d577c0 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -438,6 +438,9 @@ static u8 ChooseMoveOrAction_Doubles(void) { if (gBattleMons[sBattler_AI].moves[j] != 0) { + if (!CanTargetBattler(sBattler_AI, i, gBattleMons[sBattler_AI].moves[j])) + continue; + if (mostViableMovesScores[0] == AI_THINKING_STRUCT->score[j]) { mostViableMovesScores[mostViableMovesNo] = AI_THINKING_STRUCT->score[j]; @@ -2296,6 +2299,8 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_HIT_ENEMY_HEAL_ALLY: // pollen puff if (IsTargetingPartner(battlerAtk, battlerDef)) { + if (gStatuses3[battlerDef] & STATUS3_HEAL_BLOCK) + return 0; if (AtMaxHp(battlerDef)) score -= 10; else if (gBattleMons[battlerDef].hp > gBattleMons[battlerDef].maxHP / 2) @@ -4902,6 +4907,9 @@ static s16 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) || (moveType == TYPE_ELECTRIC && AI_DATA->atkPartnerAbility == ABILITY_VOLT_ABSORB) || (moveType == TYPE_WATER && (AI_DATA->atkPartnerAbility == ABILITY_DRY_SKIN || AI_DATA->atkPartnerAbility == ABILITY_WATER_ABSORB))) { + if (gStatuses3[battlerDef] & STATUS3_HEAL_BLOCK) + return 0; + if (CanTargetFaintAi(FOE(battlerAtk), AI_DATA->battlerAtkPartner) || (CanTargetFaintAi(BATTLE_PARTNER(FOE(battlerAtk)), AI_DATA->battlerAtkPartner))) score--; diff --git a/src/battle_controller_opponent.c b/src/battle_controller_opponent.c index 69e0de5af..35e774341 100644 --- a/src/battle_controller_opponent.c +++ b/src/battle_controller_opponent.c @@ -1605,6 +1605,7 @@ static void OpponentHandleChooseMove(void) else // Wild pokemon - use random move { u16 move; + u8 target; do { chosenMoveId = Random() & 3; @@ -1615,6 +1616,10 @@ static void OpponentHandleChooseMove(void) BtlController_EmitTwoReturnValues(BUFFER_B, 10, (chosenMoveId) | (gActiveBattler << 8)); else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) { + do { + target = GetBattlerAtPosition(Random() & 2); + } while (!CanTargetBattler(gActiveBattler, target, move)); + #if B_WILD_NATURAL_ENEMIES == TRUE // Don't bother to loop through table if the move can't attack ally if (!(gBattleMoves[move].target & MOVE_TARGET_BOTH)) @@ -1641,14 +1646,14 @@ static void OpponentHandleChooseMove(void) break; } } - if (isPartnerEnemy) + if (isPartnerEnemy && CanTargetBattler(gActiveBattler, target, move)) BtlController_EmitTwoReturnValues(BUFFER_B, 10, (chosenMoveId) | (GetBattlerAtPosition(BATTLE_PARTNER(gActiveBattler)) << 8)); else - BtlController_EmitTwoReturnValues(BUFFER_B, 10, (chosenMoveId) | (GetBattlerAtPosition(Random() & 2) << 8)); + BtlController_EmitTwoReturnValues(BUFFER_B, 10, (chosenMoveId) | (target << 8)); } else #endif - BtlController_EmitTwoReturnValues(BUFFER_B, 10, (chosenMoveId) | (GetBattlerAtPosition(Random() & 2) << 8)); + BtlController_EmitTwoReturnValues(BUFFER_B, 10, (chosenMoveId) | (target << 8)); } else BtlController_EmitTwoReturnValues(BUFFER_B, 10, (chosenMoveId) | (GetBattlerAtPosition(B_POSITION_PLAYER_LEFT) << 8)); diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index bd6b3a023..0e01eb549 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -436,7 +436,8 @@ static void HandleInputChooseTarget(void) break; } - if (gAbsentBattlerFlags & gBitTable[gMultiUsePlayerCursor]) + if (gAbsentBattlerFlags & gBitTable[gMultiUsePlayerCursor] + || !CanTargetBattler(gActiveBattler, gMultiUsePlayerCursor, move)) i = 0; } while (i == 0); } @@ -485,7 +486,8 @@ static void HandleInputChooseTarget(void) break; } - if (gAbsentBattlerFlags & gBitTable[gMultiUsePlayerCursor]) + if (gAbsentBattlerFlags & gBitTable[gMultiUsePlayerCursor] + || !CanTargetBattler(gActiveBattler, gMultiUsePlayerCursor, move)) i = 0; } while (i == 0); } diff --git a/src/battle_util.c b/src/battle_util.c index 68c675c54..d17c9ce99 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -10099,3 +10099,12 @@ u32 GetBattlerMoveTargetType(u8 battlerId, u16 move) else return gBattleMoves[move].target; } + +bool32 CanTargetBattler(u8 battlerAtk, u8 battlerDef, u16 move) +{ + if (gBattleMoves[move].effect == EFFECT_HIT_ENEMY_HEAL_ALLY + && GetBattlerSide(battlerAtk) == GetBattlerSide(battlerDef) + && gStatuses3[battlerDef] & STATUS3_HEAL_BLOCK) + return FALSE; + return TRUE; +} From 89816b62bad6fd4ba2f7626f11f3abc826be74f8 Mon Sep 17 00:00:00 2001 From: Eduardo Quezada D'Ottone Date: Sat, 7 May 2022 10:38:16 -0400 Subject: [PATCH 090/130] Added Sheer Cold accuracy change to ShouldTryOHKO --- src/battle_ai_util.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index de4271bba..8ed6e0490 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -1499,6 +1499,10 @@ bool32 ShouldTryOHKO(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbilit else // test the odds { u16 odds = accuracy + (gBattleMons[battlerAtk].level - gBattleMons[battlerDef].level); + #if B_SHEER_COLD_ACC >= GEN_7 + if (gCurrentMove == MOVE_SHEER_COLD && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_ICE)) + odds -= 10; + #endif if (Random() % 100 + 1 < odds && gBattleMons[battlerAtk].level >= gBattleMons[battlerDef].level) return TRUE; } From 096fe3c11d5e4d830d89b6d6892b0ae477d3b01b Mon Sep 17 00:00:00 2001 From: Eduardo Quezada D'Ottone Date: Sat, 7 May 2022 10:56:31 -0400 Subject: [PATCH 091/130] Removed unecessary B_LEEK_ALWAYS_CRIT config --- include/constants/battle_config.h | 3 +-- src/battle_script_commands.c | 6 +----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/include/constants/battle_config.h b/include/constants/battle_config.h index 047d7c1a6..fa181fb65 100644 --- a/include/constants/battle_config.h +++ b/include/constants/battle_config.h @@ -99,7 +99,7 @@ #endif // Calculation settings -#define B_CRIT_CHANCE GEN_7 // Chances of a critical hit landing. See CalcCritChanceStage. +#define B_CRIT_CHANCE GEN_7 // Chances of a critical hit landing. See CalcCritChanceStage. Gen6+ chances guarantee that Farfetch'd and Sirfetch'd always get critical hits while holding a Leek and using high-crit ratio moves. #define B_CRIT_MULTIPLIER GEN_7 // In Gen6+, critical hits multiply damage by 1.5 instead of 2. #define B_PARALYSIS_SPEED GEN_7 // In Gen7+, Speed is decreased by 50% instead of 75%. #define B_CONFUSION_SELF_DMG_CHANCE GEN_7 // In Gen7+, confusion has a 33.3% of self-damage, instead of 50%. @@ -209,7 +209,6 @@ #define B_HEAVY_BALL_MODIFIER GEN_7 // In Gen7+, Heavy Ball's ranges change. See Cmd_handleballthrow. #define B_DREAM_BALL_MODIFIER GEN_8 // In Gen8, Dream Ball's catch multiplier is x4 when the target is asleep or has the ability Comatose. #define B_SERENE_GRACE_BOOST GEN_7 // In Gen5+, Serene Grace boosts the added flinch chance of King's Rock and Razor Fang. -#define B_LEEK_ALWAYS_CRIT GEN_7 // In Gen6+, if a Farfetch'd or Sirfetch'd holding a Leek use a move with increased Critical Hit ratio, it will always result in a Critical Hit. // Flag settings // To use the following features in scripting, replace the 0s with the flag ID you're assigning it to. diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 1d9009e6e..d0431c25e 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1878,11 +1878,7 @@ s32 CalcCritChanceStage(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recordAbi else if (gStatuses3[battlerAtk] & STATUS3_LASER_FOCUS || gBattleMoves[move].effect == EFFECT_ALWAYS_CRIT || (abilityAtk == ABILITY_MERCILESS && gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY) - || move == MOVE_SURGING_STRIKES - #if B_LEEK_ALWAYS_CRIT >= GEN_6 - || ((gBattleMoves[gCurrentMove].flags & FLAG_HIGH_CRIT) && BENEFITS_FROM_LEEK(battlerAtk, holdEffectAtk)) - #endif - ) + || move == MOVE_SURGING_STRIKES) { critChance = -2; } From 5456a87b83a7a86655c7a757a8bd6f1a8535da75 Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Sat, 7 May 2022 11:27:32 -0400 Subject: [PATCH 092/130] fix pollen puff heal blocked battler in CanTargetBattler --- src/battle_util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/battle_util.c b/src/battle_util.c index d17c9ce99..f1a5bd883 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -10104,7 +10104,7 @@ bool32 CanTargetBattler(u8 battlerAtk, u8 battlerDef, u16 move) { if (gBattleMoves[move].effect == EFFECT_HIT_ENEMY_HEAL_ALLY && GetBattlerSide(battlerAtk) == GetBattlerSide(battlerDef) - && gStatuses3[battlerDef] & STATUS3_HEAL_BLOCK) - return FALSE; + && gStatuses3[battlerAtk] & STATUS3_HEAL_BLOCK) + return FALSE; // Pokémon affected by Heal Block cannot target allies with Pollen Puff return TRUE; } From 017f44f5ac2ec86cc5d9182bfa6cedd02d8da489 Mon Sep 17 00:00:00 2001 From: AgustinGDLV <103095241+AgustinGDLV@users.noreply.github.com> Date: Sat, 7 May 2022 09:35:00 -0700 Subject: [PATCH 093/130] Apply suggestions from code review Co-authored-by: Eduardo Quezada D'Ottone --- include/constants/pokemon.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/include/constants/pokemon.h b/include/constants/pokemon.h index a7f0e3e4e..b1aea3334 100644 --- a/include/constants/pokemon.h +++ b/include/constants/pokemon.h @@ -380,15 +380,20 @@ #define EVO_LEVEL_NATURE_AMPED 33 // Pokémon reaches the specified level, it has a Hardy, Brave, Adamant, Naughty, Docile, Impish, Lax, Hasty, Jolly, Naive, Rash, Sassy, or Quirky nature. #define EVO_LEVEL_NATURE_LOW_KEY 34 // Pokémon reaches the specified level, it has a Lonely, Bold, Relaxed, Timid, Serious, Modest, Mild, Quiet, Bashful, Calm, Gentle, or Careful nature. #define EVO_CRITICAL_HITS 35 // Pokémon performs specified number of critical hits in one battle +#define EVO_SCRIPT_TRIGGER_DMG 36 // Pokémon has specified HP below max, then player interacts trigger +#define EVO_DARK_SCROLL 37 // interacts with Scroll of Darkness +#define EVO_WATER_SCROLL 38 // interacts with Scroll of Waters #define EVOS_PER_MON 10 // Evolution 'modes,' for GetEvolutionTargetSpecies #define EVO_MODE_NORMAL 0 -#define EVO_MODE_TRADE 1 -#define EVO_MODE_ITEM_USE 2 -#define EVO_MODE_ITEM_CHECK 3 // If an Everstone is being held, still want to show that the stone *could* be used on that Pokémon to evolve -#define EVO_MODE_BATTLE_SPECIAL 4 +#define EVO_MODE_NORMAL 0 +#define EVO_MODE_TRADE 1 +#define EVO_MODE_ITEM_USE 2 +#define EVO_MODE_ITEM_CHECK 3 // If an Everstone is being held, still want to show that the stone *could* be used on that Pokémon to evolve +#define EVO_MODE_BATTLE_SPECIAL 4 +#define EVO_MODE_OVERWORLD_SPECIAL 5 #define NUM_MALE_LINK_FACILITY_CLASSES 8 #define NUM_FEMALE_LINK_FACILITY_CLASSES 8 From 4c8770fdc2a308ae2ac4155c931eb8c0559d732e Mon Sep 17 00:00:00 2001 From: sneed Date: Sat, 7 May 2022 21:57:50 +0300 Subject: [PATCH 094/130] Update battle_util.c --- src/battle_util.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/battle_util.c b/src/battle_util.c index 30df20f4f..114235f73 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -6098,12 +6098,18 @@ bool32 HasEnoughHpToEatBerry(u32 battlerId, u32 hpFraction, u32 itemId) return FALSE; } +#if defined(ITEM_EXPANSION) && B_CONFUSE_BERRIES_HEAL >= GEN_7 + #define CONFUSE_BERRY_HP_FRACTION 4 +#else + #define CONFUSE_BERRY_HP_FRACTION 2 +#endif + static u8 HealConfuseBerry(u32 battlerId, u32 itemId, u8 flavorId, bool32 end2) { #if B_HEAL_BLOCKING >= GEN_5 - if (HasEnoughHpToEatBerry(battlerId, 2, itemId) && !(gStatuses3[battlerId] & STATUS3_HEAL_BLOCK)) + if (HasEnoughHpToEatBerry(battlerId, CONFUSE_BERRY_HP_FRACTION, itemId) && !(gStatuses3[battlerId] & STATUS3_HEAL_BLOCK)) #else - if (HasEnoughHpToEatBerry(battlerId, 2, itemId)) + if (HasEnoughHpToEatBerry(battlerId, CONFUSE_BERRY_HP_FRACTION, itemId)) #endif { PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, flavorId); @@ -6140,6 +6146,8 @@ static u8 HealConfuseBerry(u32 battlerId, u32 itemId, u8 flavorId, bool32 end2) return 0; } +#undef CONFUSE_BERRY_HP_FRACTION + static u8 StatRaiseBerry(u32 battlerId, u32 itemId, u32 statId, bool32 end2) { if (CompareStat(battlerId, statId, MAX_STAT_STAGE, CMP_LESS_THAN) && HasEnoughHpToEatBerry(battlerId, GetBattlerHoldEffectParam(battlerId), itemId)) From c6b529ed50ec42f0d3e9f1e7eecef84bcb80b46f Mon Sep 17 00:00:00 2001 From: sneed Date: Sat, 7 May 2022 22:09:08 +0300 Subject: [PATCH 095/130] add missing constant --- include/constants/battle_config.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/constants/battle_config.h b/include/constants/battle_config.h index fa181fb65..86d6582ba 100644 --- a/include/constants/battle_config.h +++ b/include/constants/battle_config.h @@ -194,6 +194,7 @@ // Item settings #define B_HP_BERRIES GEN_7 // In Gen4+, berries which restore hp activate immediately after HP drops to half. In Gen3, the effect occurs at the end of the turn. #define B_BERRIES_INSTANT GEN_7 // In Gen4+, most berries activate on battle start/switch-in if applicable. In Gen3, they only activate either at the move end or turn end. +#define B_CONFUSE_BERRIES_HEAL GEN_8 // Before Gen7, Figy and similar berries restore 1/8th of HP and trigger at half HP. In Gen7 they restore half HP, triggering at 25% HP. In Gen8 they heal 1/3rd of HP. #define B_X_ITEMS_BUFF GEN_7 // In Gen7+, the X Items raise a stat by 2 stages instead of 1. #define B_MENTAL_HERB GEN_5 // In Gen5+, the Mental Herb cures Infatuation, Taunt, Encore, Torment, Heal Block, and Disable #define B_TRAINERS_KNOCK_OFF_ITEMS TRUE // If TRUE, trainers can steal/swap your items (non-berries are restored after battle). In vanilla games trainers cannot steal items. From f83875cf0f06c28507f58b07477c67f6b327e786 Mon Sep 17 00:00:00 2001 From: sneed Date: Sat, 7 May 2022 23:34:38 +0300 Subject: [PATCH 096/130] remove item expansion check --- include/constants/battle_config.h | 1 + src/battle_util.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/constants/battle_config.h b/include/constants/battle_config.h index 86d6582ba..baecae018 100644 --- a/include/constants/battle_config.h +++ b/include/constants/battle_config.h @@ -195,6 +195,7 @@ #define B_HP_BERRIES GEN_7 // In Gen4+, berries which restore hp activate immediately after HP drops to half. In Gen3, the effect occurs at the end of the turn. #define B_BERRIES_INSTANT GEN_7 // In Gen4+, most berries activate on battle start/switch-in if applicable. In Gen3, they only activate either at the move end or turn end. #define B_CONFUSE_BERRIES_HEAL GEN_8 // Before Gen7, Figy and similar berries restore 1/8th of HP and trigger at half HP. In Gen7 they restore half HP, triggering at 25% HP. In Gen8 they heal 1/3rd of HP. + // Requires using Item Expansion or manually editing the holdEffectParam of Figy, Wiki, Mago, Aguav and Iapapa berries. #define B_X_ITEMS_BUFF GEN_7 // In Gen7+, the X Items raise a stat by 2 stages instead of 1. #define B_MENTAL_HERB GEN_5 // In Gen5+, the Mental Herb cures Infatuation, Taunt, Encore, Torment, Heal Block, and Disable #define B_TRAINERS_KNOCK_OFF_ITEMS TRUE // If TRUE, trainers can steal/swap your items (non-berries are restored after battle). In vanilla games trainers cannot steal items. diff --git a/src/battle_util.c b/src/battle_util.c index 114235f73..9681afbe2 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -6098,7 +6098,7 @@ bool32 HasEnoughHpToEatBerry(u32 battlerId, u32 hpFraction, u32 itemId) return FALSE; } -#if defined(ITEM_EXPANSION) && B_CONFUSE_BERRIES_HEAL >= GEN_7 +#if B_CONFUSE_BERRIES_HEAL >= GEN_7 #define CONFUSE_BERRY_HP_FRACTION 4 #else #define CONFUSE_BERRY_HP_FRACTION 2 From 07b0ce973766c16d9109ce4326c480e2f2b55e0a Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Sun, 8 May 2022 17:57:30 -0400 Subject: [PATCH 097/130] add inner focus ability popup msg --- data/battle_scripts_1.s | 7 +++++++ include/battle_scripts.h | 1 + src/battle_script_commands.c | 12 +++++++++++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 89d2292cc..354dde4f0 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -8498,6 +8498,13 @@ BattleScript_ObliviousPreventsAttraction:: waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd +BattleScript_FlinchPrevention:: + pause B_WAIT_TIME_SHORT + call BattleScript_AbilityPopUp + printstring STRINGID_PKMNSXPREVENTSFLINCHING + waitmessage B_WAIT_TIME_LONG + goto BattleScript_MoveEnd + BattleScript_OwnTempoPrevents:: pause B_WAIT_TIME_SHORT call BattleScript_AbilityPopUp diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 5fd70159b..4134a87dc 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -169,6 +169,7 @@ extern const u8 BattleScript_BRNPrevention[]; extern const u8 BattleScript_PRLZPrevention[]; extern const u8 BattleScript_PSNPrevention[]; extern const u8 BattleScript_ObliviousPreventsAttraction[]; +extern const u8 BattleScript_FlinchPrevention[]; extern const u8 BattleScript_OwnTempoPrevents[]; extern const u8 BattleScript_SoundproofProtected[]; extern const u8 BattleScript_AbilityNoSpecificStatLoss[]; diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index ef8c5a764..f64b57d66 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -2941,7 +2941,17 @@ void SetMoveEffect(bool32 primary, u32 certain) case MOVE_EFFECT_FLINCH: if (battlerAbility == ABILITY_INNER_FOCUS) { - gBattlescriptCurrInstr++; + if (primary == TRUE || certain == MOVE_EFFECT_CERTAIN) + { + gLastUsedAbility = ABILITY_INNER_FOCUS; + gBattlerAbility = gEffectBattler; + RecordAbilityBattle(gEffectBattler, ABILITY_INNER_FOCUS); + gBattlescriptCurrInstr = BattleScript_FlinchPrevention; + } + else + { + gBattlescriptCurrInstr++; + } } else { From 277f4a37511495a567b2f671e9b0ac64eb69db70 Mon Sep 17 00:00:00 2001 From: AgustinGDLV <103095241+AgustinGDLV@users.noreply.github.com> Date: Sun, 8 May 2022 21:23:06 -0700 Subject: [PATCH 098/130] niceties Co-authored-by: Eduardo Quezada D'Ottone --- src/battle_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/battle_main.c b/src/battle_main.c index ee6166062..fbe132eae 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -5194,7 +5194,7 @@ static void TrySpecialEvolution(void) // Attempts to perform non-level related b #ifndef POKEMON_EXPANSION u16 species = GetEvolutionTargetSpecies(&gPlayerParty[i], EVO_MODE_BATTLE_SPECIAL, i); #else - u16 species = GetEvolutionTargetSpecies(&gPlayerParty[i], EVO_MODE_BATTLE_SPECIAL, i, SPECIES_NONE); + u16 species = GetEvolutionTargetSpecies(&gPlayerParty[i], EVO_MODE_BATTLE_SPECIAL, i, NULL); #endif if (species != SPECIES_NONE && !(sTriedEvolving & gBitTable[i])) { From 9bb5db2275e42ace6bb34b384659e4f8136505c5 Mon Sep 17 00:00:00 2001 From: AgustinGDLV Date: Sun, 8 May 2022 21:23:51 -0700 Subject: [PATCH 099/130] removed duplicate define --- include/constants/pokemon.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/constants/pokemon.h b/include/constants/pokemon.h index b1aea3334..13db5644e 100644 --- a/include/constants/pokemon.h +++ b/include/constants/pokemon.h @@ -387,7 +387,6 @@ #define EVOS_PER_MON 10 // Evolution 'modes,' for GetEvolutionTargetSpecies -#define EVO_MODE_NORMAL 0 #define EVO_MODE_NORMAL 0 #define EVO_MODE_TRADE 1 #define EVO_MODE_ITEM_USE 2 From 709f583390f2889eba2f3ccd0df3a820c6b7fbeb Mon Sep 17 00:00:00 2001 From: sneed Date: Tue, 10 May 2022 02:58:24 +0300 Subject: [PATCH 100/130] Initial commit --- include/constants/battle_config.h | 1 + src/battle_main.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/include/constants/battle_config.h b/include/constants/battle_config.h index baecae018..d968dbd2f 100644 --- a/include/constants/battle_config.h +++ b/include/constants/battle_config.h @@ -252,6 +252,7 @@ // Other settings #define B_DOUBLE_WILD_CHANCE 0 // % chance of encountering two Pokémon in a Wild Encounter. #define B_MULTI_BATTLE_WHITEOUT GEN_8 // In Gen4+, multi battles end when the Player and also their Partner don't have any more Pokémon to fight. +#define B_EVOLUTION_AFTER_WHITEOUT TRUE // If set to TRUE, Pokemon that qualify for evolution after battle will evolve even if the player loses. #define B_WILD_NATURAL_ENEMIES TRUE // If set to TRUE, certain wild mon species will attack other species when partnered in double wild battles (eg. Zangoose vs Seviper) // Animation Settings diff --git a/src/battle_main.c b/src/battle_main.c index c376b227e..b2b205cbe 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -5174,7 +5174,11 @@ static void FreeResetData_ReturnToOvOrDoEvolutions(void) | BATTLE_TYPE_FRONTIER | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_WALLY_TUTORIAL)) +#if !B_EVOLUTION_AFTER_WHITEOUT && (gBattleOutcome == B_OUTCOME_WON || gBattleOutcome == B_OUTCOME_CAUGHT)) +#else + ) +#endif { gBattleMainFunc = TrySpecialEvolution; } From bceccf54747f36aaba7a81637285af553e79943a Mon Sep 17 00:00:00 2001 From: sneed Date: Tue, 10 May 2022 08:17:31 +0300 Subject: [PATCH 101/130] changes --- include/constants/battle_config.h | 2 +- src/battle_main.c | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/include/constants/battle_config.h b/include/constants/battle_config.h index d968dbd2f..74ac9e129 100644 --- a/include/constants/battle_config.h +++ b/include/constants/battle_config.h @@ -252,7 +252,7 @@ // Other settings #define B_DOUBLE_WILD_CHANCE 0 // % chance of encountering two Pokémon in a Wild Encounter. #define B_MULTI_BATTLE_WHITEOUT GEN_8 // In Gen4+, multi battles end when the Player and also their Partner don't have any more Pokémon to fight. -#define B_EVOLUTION_AFTER_WHITEOUT TRUE // If set to TRUE, Pokemon that qualify for evolution after battle will evolve even if the player loses. +#define B_EVOLUTION_AFTER_WHITEOUT GEN_6 // In Gen6+, Pokemon that qualify for evolution after battle will evolve even if the player loses. #define B_WILD_NATURAL_ENEMIES TRUE // If set to TRUE, certain wild mon species will attack other species when partnered in double wild battles (eg. Zangoose vs Seviper) // Animation Settings diff --git a/src/battle_main.c b/src/battle_main.c index b2b205cbe..bf2853a7b 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -5174,11 +5174,7 @@ static void FreeResetData_ReturnToOvOrDoEvolutions(void) | BATTLE_TYPE_FRONTIER | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_WALLY_TUTORIAL)) -#if !B_EVOLUTION_AFTER_WHITEOUT - && (gBattleOutcome == B_OUTCOME_WON || gBattleOutcome == B_OUTCOME_CAUGHT)) -#else - ) -#endif + && (B_EVOLUTION_AFTER_WHITEOUT >= GEN_6 || gBattleOutcome == B_OUTCOME_WON || gBattleOutcome == B_OUTCOME_CAUGHT)) { gBattleMainFunc = TrySpecialEvolution; } From 1c13335d16f610d2c3881effb7eddf3fefd5d894 Mon Sep 17 00:00:00 2001 From: Kurausukun Date: Thu, 12 May 2022 22:05:44 -0400 Subject: [PATCH 102/130] Update INSTALL.md --- INSTALL.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index 72f3c92f3..42d8a75ec 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -451,14 +451,6 @@ Replace `` with the number that the `nproc` command returned. `nproc` is not available on macOS. The alternative is `sysctl -n hw.ncpu` ([relevant Stack Overflow thread](https://stackoverflow.com/questions/1715580)). -## Debug info - -To build **pokeemerald.elf** with enhanced debug info: -```bash -make DINFO=1 -``` -Note that this is only necessary for the `modern` target; the regular target has debug info enabled by default. - ## devkitARM's C compiler This project supports the `arm-none-eabi-gcc` compiler included with devkitARM. If devkitARM (a.k.a. gba-dev) has already been installed as part of the platform-specific instructions, simply run: @@ -535,7 +527,7 @@ devkitARM is now installed. devkitARM is now installed. -## Installing devkitARM on Arch Linux +### Installing devkitARM on Arch Linux 1. Follow [devkitPro's instructions](https://devkitpro.org/wiki/devkitPro_pacman#Customising_Existing_Pacman_Install) to configure `pacman` to download devkitPro packages. 2. Install `gba-dev`: run the following command as root. @@ -553,7 +545,7 @@ devkitARM is now installed. devkitARM is now installed. -## Other toolchains +### Other toolchains To build using a toolchain other than devkitARM, override the `TOOLCHAIN` environment variable with the path to your toolchain, which must contain the subdirectory `bin`. ```bash @@ -565,6 +557,14 @@ make TOOLCHAIN="/usr/local/arm-none-eabi" ``` To compile the `modern` target with this toolchain, the subdirectories `lib`, `include`, and `arm-none-eabi` must also be present. +### Building with debug info under a modern toolchain + +To build **pokeemerald.elf** with debug symbols under a modern toolchain: +```bash +make DINFO=1 +``` +Note that this is not necessary for a non-modern build since those are built with debug symbols by default. + # Useful additional tools * [porymap](https://github.com/huderlem/porymap) for viewing and editing maps From 7d224197c05fb319c03d2bcbed3ed36d6f246fd8 Mon Sep 17 00:00:00 2001 From: Kurausukun Date: Thu, 12 May 2022 22:33:17 -0400 Subject: [PATCH 103/130] Update INSTALL.md --- INSTALL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/INSTALL.md b/INSTALL.md index 42d8a75ec..7f1d47879 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -561,7 +561,7 @@ To compile the `modern` target with this toolchain, the subdirectories `lib`, `i To build **pokeemerald.elf** with debug symbols under a modern toolchain: ```bash -make DINFO=1 +make modern DINFO=1 ``` Note that this is not necessary for a non-modern build since those are built with debug symbols by default. From 577791a6bc203e0ce5c8e564b88d9c7a5040f4cc Mon Sep 17 00:00:00 2001 From: LOuroboros Date: Fri, 13 May 2022 10:52:09 -0300 Subject: [PATCH 104/130] Moved order of defined header files in include/global.h --- include/global.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/global.h b/include/global.h index ddd77ac9b..e1d19cdec 100644 --- a/include/global.h +++ b/include/global.h @@ -14,8 +14,8 @@ #include "constants/maps.h" #include "constants/pokemon.h" #include "constants/easy_chat.h" -#include "constants/expansion_branches.h" #include "constants/trainer_hill.h" +#include "constants/expansion_branches.h" // Prevent cross-jump optimization. #define BLOCK_CROSS_JUMP asm(""); From b5d98ec93eb1582bc4627de4b65458c9e67b6477 Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Fri, 13 May 2022 20:05:52 -0400 Subject: [PATCH 105/130] prevent overwriting wild mon held items --- src/pokemon.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pokemon.c b/src/pokemon.c index 71176d2eb..65aad6196 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -6459,6 +6459,9 @@ void SetWildMonHeldItem(void) for (i = 0; i < count; i++) { + if (GetMonData(&gEnemyParty[i], MON_DATA_HELD_ITEM) != ITEM_NONE) + continue; // prevent ovewriting previously set item + rnd = Random() % 100; species = GetMonData(&gEnemyParty[i], MON_DATA_SPECIES, 0); if (gMapHeader.mapLayoutId == LAYOUT_ALTERING_CAVE) From 7dd6988b2b525e3a2ed7f2191725889f3b777012 Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Fri, 13 May 2022 20:32:03 -0400 Subject: [PATCH 106/130] fix args to GetMonData --- src/pokemon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pokemon.c b/src/pokemon.c index 65aad6196..26f12dca2 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -6459,7 +6459,7 @@ void SetWildMonHeldItem(void) for (i = 0; i < count; i++) { - if (GetMonData(&gEnemyParty[i], MON_DATA_HELD_ITEM) != ITEM_NONE) + if (GetMonData(&gEnemyParty[i], MON_DATA_HELD_ITEM, NULL) != ITEM_NONE) continue; // prevent ovewriting previously set item rnd = Random() % 100; From 0424e37252f048f3047fb5d6ff5ae690c21a892d Mon Sep 17 00:00:00 2001 From: sneed Date: Thu, 19 May 2022 14:20:34 +0300 Subject: [PATCH 107/130] Fix cherrim + castform interaction --- src/battle_gfx_sfx_util.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/battle_gfx_sfx_util.c b/src/battle_gfx_sfx_util.c index 9dbfa7771..aeed8ab81 100644 --- a/src/battle_gfx_sfx_util.c +++ b/src/battle_gfx_sfx_util.c @@ -914,6 +914,8 @@ void HandleSpeciesGfxDataChange(u8 battlerAtk, u8 battlerDef, bool8 castform, bo { StartSpriteAnim(&gSprites[gBattlerSpriteIds[battlerAtk]], gBattleSpritesDataPtr->animationData->animArg); paletteOffset = 0x100 + battlerAtk * 16; + lzPaletteData = GetMonSpritePalFromSpeciesAndPersonality(targetSpecies, otId, personalityValue); + LZDecompressWram(lzPaletteData, gBattleStruct->castformPalette[CASTFORM_NORMAL]); LoadPalette(gBattleStruct->castformPalette[gBattleSpritesDataPtr->animationData->animArg], paletteOffset, 32); gBattleMonForms[battlerAtk] = gBattleSpritesDataPtr->animationData->animArg; if (gBattleSpritesDataPtr->battlerData[battlerAtk].transformSpecies != SPECIES_NONE) From 928d3c5a2855a0c85d7b3a6b87e8feeecf58b9ee Mon Sep 17 00:00:00 2001 From: sneed Date: Thu, 19 May 2022 15:08:03 +0300 Subject: [PATCH 108/130] change form on weather fade --- data/battle_scripts_1.s | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 354dde4f0..a9c15040d 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -6511,9 +6511,11 @@ BattleScript_LearnMoveReturn:: BattleScript_RainContinuesOrEnds:: printfromtable gRainContinuesStringIds waitmessage B_WAIT_TIME_LONG - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_RAIN_STOPPED, BattleScript_RainContinuesOrEndsEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_RAIN_STOPPED, BattleScript_RainEnds playanimation BS_ATTACKER, B_ANIM_RAIN_CONTINUES -BattleScript_RainContinuesOrEndsEnd:: + end2 +BattleScript_RainEnds:: + call BattleScript_WeatherFormChanges end2 BattleScript_DamagingWeatherContinues:: @@ -6552,6 +6554,7 @@ BattleScript_DamagingWeatherContinuesEnd:: BattleScript_SandStormHailEnds:: printfromtable gSandStormHailEndStringIds waitmessage B_WAIT_TIME_LONG + call BattleScript_WeatherFormChanges end2 BattleScript_SunlightContinues:: @@ -6563,6 +6566,7 @@ BattleScript_SunlightContinues:: BattleScript_SunlightFaded:: printstring STRINGID_SUNLIGHTFADED waitmessage B_WAIT_TIME_LONG + call BattleScript_WeatherFormChanges end2 BattleScript_OverworldWeatherStarts:: From 881e7e70ec7c14d27d30180e73981397975ef25c Mon Sep 17 00:00:00 2001 From: sneed Date: Thu, 19 May 2022 15:22:28 +0300 Subject: [PATCH 109/130] Generalize usage of castformPalette https://github.com/pret/pokeemerald/pull/1663 --- src/battle_gfx_sfx_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/battle_gfx_sfx_util.c b/src/battle_gfx_sfx_util.c index aeed8ab81..2d441c7eb 100644 --- a/src/battle_gfx_sfx_util.c +++ b/src/battle_gfx_sfx_util.c @@ -915,7 +915,7 @@ void HandleSpeciesGfxDataChange(u8 battlerAtk, u8 battlerDef, bool8 castform, bo StartSpriteAnim(&gSprites[gBattlerSpriteIds[battlerAtk]], gBattleSpritesDataPtr->animationData->animArg); paletteOffset = 0x100 + battlerAtk * 16; lzPaletteData = GetMonSpritePalFromSpeciesAndPersonality(targetSpecies, otId, personalityValue); - LZDecompressWram(lzPaletteData, gBattleStruct->castformPalette[CASTFORM_NORMAL]); + LZDecompressWram(lzPaletteData, gBattleStruct->castformPalette); LoadPalette(gBattleStruct->castformPalette[gBattleSpritesDataPtr->animationData->animArg], paletteOffset, 32); gBattleMonForms[battlerAtk] = gBattleSpritesDataPtr->animationData->animArg; if (gBattleSpritesDataPtr->battlerData[battlerAtk].transformSpecies != SPECIES_NONE) From d8d31b79722cb2543d99b8c200970c46e431fa34 Mon Sep 17 00:00:00 2001 From: sneed Date: Fri, 20 May 2022 04:57:32 +0300 Subject: [PATCH 110/130] disable last used ball in bpike --- src/battle_interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/battle_interface.c b/src/battle_interface.c index 6d98d794d..e0d3b7d61 100644 --- a/src/battle_interface.c +++ b/src/battle_interface.c @@ -3309,7 +3309,7 @@ bool32 CanThrowLastUsedBall(void) #else if (!CanThrowBall()) return FALSE; - if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + if (gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FRONTIER)) return FALSE; if (!CheckBagHasItem(gLastThrownBall, 1)) return FALSE; From 307d5d93c4bbf2d1f6a624761a53ceae8d8d32b5 Mon Sep 17 00:00:00 2001 From: hamish Date: Mon, 23 May 2022 08:53:08 -0400 Subject: [PATCH 111/130] add potlergeist animation --- data/battle_anim_scripts.s | 37 +++++++++++++- .../battle_anims/sprites/new/poltergeist.pal | 19 +++++++ include/constants/battle_anim.h | 1 + include/graphics.h | 1 + src/battle_anim_ghost.c | 49 ++++++++++++++++++- src/battle_script_commands.c | 1 + src/data/battle_anim.h | 2 + src/graphics.c | 2 + 8 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 graphics/battle_anims/sprites/new/poltergeist.pal diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index d76aff05a..f1ef78fe0 100644 --- a/data/battle_anim_scripts.s +++ b/data/battle_anim_scripts.s @@ -14193,7 +14193,42 @@ Move_LASH_OUT:: end @to do: Move_POLTERGEIST:: - end @to do: + loadspritegfx ANIM_TAG_EYE_SPARKLE + loadspritegfx ANIM_TAG_WHITE_SHADOW @Destiny Bond + loadspritegfx ANIM_TAG_QUICK_GUARD_HAND @Black Colour + loadspritegfx ANIM_TAG_IMPACT + loadspritegfx ANIM_TAG_POLTERGEIST + fadetobg BG_NIGHTMARE + waitbgfadein + createsprite gSimplePaletteBlendSpriteTemplate, ANIM_ATTACKER, 2, 2, 0, 0, 16, RGB_BLACK + waitforvisualfinish + createsprite gEyeSparkleSpriteTemplate, ANIM_ATTACKER, 0, -16, -8 + createsprite gEyeSparkleSpriteTemplate, ANIM_ATTACKER, 0, 16, -8 + playsewithpan SE_M_DETECT, SOUND_PAN_ATTACKER + waitforvisualfinish + createsprite gSimplePaletteBlendSpriteTemplate, ANIM_ATTACKER, 2, 2, 0, 16, 0, RGB_BLACK + playsewithpan SE_M_FAINT_ATTACK, SOUND_PAN_ATTACKER + delay 0x1 + launchtask AnimTask_DestinyBondWhiteShadow 0x5 0x2 0x0 0x24 + delay 0x30 + playsewithpan SE_M_SAND_ATTACK, SOUND_PAN_TARGET + createvisualtask AnimTask_PoltergeistItem, 2 + waitforvisualfinish + setalpha 12, 8 + launchtemplate gBasicHitSplatSpriteTemplate 0x2 0x4 0x0 0x0 0x1 0x1 + launchtask AnimTask_ShakeMon 0x5 0x5 0x1 0x0 0x5 0x5 0x1 + launchtemplate gComplexPaletteBlendSpriteTemplate 0x2 0x7 0x7 0x5 0x1 0x0 0xa 0x0 0x0 + playsewithpan SE_M_VITAL_THROW2, SOUND_PAN_TARGET + waitforvisualfinish + launchtask AnimTask_NightmareClone 0x2 0x0 + launchtask AnimTask_ShakeMon 0x2 0x5 0x1 0x3 0x0 0x28 0x1 + playsewithpan SE_M_NIGHTMARE, SOUND_PAN_TARGET + waitforvisualfinish + restorebg + waitbgfadein + clearmonbg 0x3 + blendoff + end Move_CORROSIVE_GAS:: end @to do: diff --git a/graphics/battle_anims/sprites/new/poltergeist.pal b/graphics/battle_anims/sprites/new/poltergeist.pal new file mode 100644 index 000000000..699ab1ffa --- /dev/null +++ b/graphics/battle_anims/sprites/new/poltergeist.pal @@ -0,0 +1,19 @@ +JASC-PAL +0100 +16 +0 0 0 +246 246 246 +246 246 246 +213 197 230 +213 197 230 +180 148 213 +180 148 213 +180 148 213 +148 98 197 +115 65 164 +82 32 131 +82 32 131 +82 32 131 +0 0 0 +0 0 0 +0 0 0 diff --git a/include/constants/battle_anim.h b/include/constants/battle_anim.h index bddb727fd..52f46e46d 100644 --- a/include/constants/battle_anim.h +++ b/include/constants/battle_anim.h @@ -395,6 +395,7 @@ #define ANIM_TAG_OMEGA_SYMBOL (ANIM_SPRITES_START + 383) #define ANIM_TAG_PRIMAL_PARTICLES (ANIM_SPRITES_START + 384) #define ANIM_TAG_STEEL_BEAM (ANIM_SPRITES_START + 385) +#define ANIM_TAG_POLTERGEIST (ANIM_SPRITES_START + 386) // battlers #define ANIM_ATTACKER 0 diff --git a/include/graphics.h b/include/graphics.h index 1e2a0f4d8..10e10a1c7 100644 --- a/include/graphics.h +++ b/include/graphics.h @@ -4906,6 +4906,7 @@ extern const u32 gBattleAnimSpriteGfx_StonePillar[]; extern const u32 gBattleAnimSpritePal_StonePillar[]; extern const u32 gBattleAnimSpriteGfx_StraightBeam[]; extern const u32 gBattleAnimSpritePal_StraightBeam[]; +extern const u32 gBattleAnimSpritePal_Poltergeist[]; extern const u32 gBattleAnimSpriteGfx_SubstituteBack[]; extern const u32 gBattleAnimSpriteGfx_SubstituteFront[]; extern const u32 gBattleAnimSpritePal_SubstituteFront[]; diff --git a/src/battle_anim_ghost.c b/src/battle_anim_ghost.c index d9cbc919c..5ced0567b 100644 --- a/src/battle_anim_ghost.c +++ b/src/battle_anim_ghost.c @@ -2,6 +2,7 @@ #include "battle.h" #include "battle_anim.h" #include "gpu_regs.h" +#include "item_icon.h" #include "palette.h" #include "constants/rgb.h" #include "scanline_effect.h" @@ -39,6 +40,7 @@ static void AnimGhostStatusSprite_Step(struct Sprite *); static void AnimGrudgeFlame(struct Sprite *); static void AnimMonMoveCircular(struct Sprite *); static void AnimMonMoveCircular_Step(struct Sprite *); +static void AnimPoltergeistItem(struct Sprite *); static const union AffineAnimCmd sAffineAnim_ConfuseRayBallBounce[] = { @@ -270,6 +272,17 @@ const struct SpriteTemplate gFlashCannonBallMovementTemplate = .callback = AnimShadowBall }; +const struct SpriteTemplate gPoltergeistEffectTemplate = +{ + .tileTag = ANIM_TAG_POLTERGEIST, + .paletteTag = ANIM_TAG_POLTERGEIST, + .oam = &gOamData_AffineNormal_ObjNormal_32x32, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gAffineAnims_ShadowBall, + .callback = AnimPoltergeistItem, +}; + static void AnimConfuseRayBallBounce(struct Sprite *sprite) { InitSpritePosToAnimAttacker(sprite, TRUE); @@ -870,7 +883,8 @@ void AnimTask_DestinyBondWhiteShadow(u8 taskId) && battler != (gBattleAnimAttacker ^ 2) && IsBattlerSpriteVisible(battler)) { - if (gAnimMoveIndex == MOVE_DARK_VOID) + if (gAnimMoveIndex == MOVE_DARK_VOID + || gAnimMoveIndex == MOVE_POLTERGEIST) spriteId = CreateSprite(&gDarkVoidBlackHoleTemplate, baseX, baseY, 55); //dark void else spriteId = CreateSprite(&gDestinyBondWhiteShadowSpriteTemplate, baseX, baseY, 55); //destiny bond @@ -1395,3 +1409,36 @@ static void AnimMonMoveCircular_Step(struct Sprite *sprite) sprite->callback = DestroySpriteAndMatrix; } } + +void AnimTask_PoltergeistItem(u8 taskId) +{ + struct Task *task = &gTasks[taskId]; + u8 x = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X); + u8 y = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y) + (GetBattlerSpriteCoordAttr(gBattleAnimTarget, BATTLER_COORD_ATTR_HEIGHT) / 2); + + task->data[0] = AddItemIconSprite(ANIM_TAG_ITEM_BAG, ANIM_TAG_ITEM_BAG, gLastUsedItem); + gSprites[task->data[0]].x = x + 4; + gSprites[task->data[0]].y = y + 4; + gSprites[task->data[0]].data[0] = x + 4; + gSprites[task->data[0]].data[1] = y + 4; + gSprites[task->data[0]].callback = AnimPoltergeistItem; + + task->data[1] = CreateSprite(&gPoltergeistEffectTemplate, x, y, 1); + gSprites[task->data[1]].data[0] = x; + gSprites[task->data[1]].data[1] = y; + + gAnimVisualTaskCount += 2; + + DestroyAnimVisualTask(taskId); +} + +static void AnimPoltergeistItem(struct Sprite *sprite) +{ + sprite->data[2] += 4; + + sprite->x = sprite->data[0] + Sin(sprite->data[2], 24); + sprite->y = sprite->data[1] + (Cos(sprite->data[2], 24) - 24); + + if (sprite->data[2] == 256) + DestroyAnimSprite(sprite); +} diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 15915c71a..6892e1766 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -9448,6 +9448,7 @@ static void Cmd_various(void) else { PREPARE_ITEM_BUFFER(gBattleTextBuff1, gBattleMons[gActiveBattler].item); + gLastUsedItem = gBattleMons[gActiveBattler].item; gBattlescriptCurrInstr += 7; } return; diff --git a/src/data/battle_anim.h b/src/data/battle_anim.h index 5483b8f3b..62f3802a5 100644 --- a/src/data/battle_anim.h +++ b/src/data/battle_anim.h @@ -1451,6 +1451,7 @@ const struct CompressedSpriteSheet gBattleAnimPicTable[] = {gBattleAnimSpriteGfx_OmegaSymbol, 0x0200, ANIM_TAG_OMEGA_SYMBOL}, {gBattleAnimSpriteGfx_PrimalParticles, 0x0180, ANIM_TAG_PRIMAL_PARTICLES}, {gBattleAnimSpriteGfx_Orbs, 0x0180, ANIM_TAG_STEEL_BEAM}, + {gBattleAnimSpriteGfx_AuraSphere, 0x200, ANIM_TAG_POLTERGEIST}, }; const struct CompressedSpritePalette gBattleAnimPaletteTable[] = @@ -1902,6 +1903,7 @@ const struct CompressedSpritePalette gBattleAnimPaletteTable[] = {gBattleAnimSpritePal_OmegaSymbol, ANIM_TAG_OMEGA_SYMBOL}, {gBattleAnimSpritePal_PrimalParticles, ANIM_TAG_PRIMAL_PARTICLES}, {gBattleAnimSpritePal_SteelBeam, ANIM_TAG_STEEL_BEAM}, + {gBattleAnimSpritePal_Poltergeist, ANIM_TAG_POLTERGEIST}, }; const struct BattleAnimBackground gBattleAnimBackgroundTable[] = diff --git a/src/graphics.c b/src/graphics.c index b735d20b1..6aae37a9f 100644 --- a/src/graphics.c +++ b/src/graphics.c @@ -269,6 +269,8 @@ const u32 gBattleAnimSpritePal_Steamroller[] = INCBIN_U32("graphics/battle_anims const u32 gBattleAnimSpriteGfx_StonePillar[] = INCBIN_U32("graphics/battle_anims/sprites/new/stone_pillar.4bpp.lz"); const u32 gBattleAnimSpritePal_StonePillar[] = INCBIN_U32("graphics/battle_anims/sprites/new/stone_pillar.gbapal.lz"); +const u32 gBattleAnimSpritePal_Poltergeist[] = INCBIN_U32("graphics/battle_anims/sprites/new/poltergeist.gbapal.lz"); + const u32 gBattleAnimSpriteGfx_StraightBeam[] = INCBIN_U32("graphics/battle_anims/sprites/new/straight_beam.4bpp.lz"); const u32 gBattleAnimSpritePal_StraightBeam[] = INCBIN_U32("graphics/battle_anims/sprites/new/straight_beam.gbapal.lz"); From 2e855b204a42f5845520aca1936021390c44fd94 Mon Sep 17 00:00:00 2001 From: sneed Date: Sun, 29 May 2022 04:41:59 +0300 Subject: [PATCH 112/130] ai accounts for a third type --- include/battle_ai_util.h | 2 +- include/constants/battle_ai.h | 2 ++ src/battle_ai_main.c | 37 +++++++++++------------------------ src/battle_ai_util.c | 11 ++++++++--- 4 files changed, 22 insertions(+), 30 deletions(-) diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 0b2afebae..4f0f68b33 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -85,7 +85,7 @@ s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef); u8 GetMoveDamageResult(u16 move); u32 GetCurrDamageHpPercent(u8 battlerAtk, u8 battlerDef); u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef); -u8 AI_GetMoveEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef); +u32 AI_GetMoveEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef); u16 *GetMovesArray(u32 battler); bool32 IsConfusionMoveEffect(u16 moveEffect); bool32 HasMove(u32 battlerId, u32 move); diff --git a/include/constants/battle_ai.h b/include/constants/battle_ai.h index 7d38d6dba..67f5c11b8 100644 --- a/include/constants/battle_ai.h +++ b/include/constants/battle_ai.h @@ -15,11 +15,13 @@ #define AI_TYPE_MOVE 4 // type effectiveness +#define AI_EFFECTIVENESS_x8 320 #define AI_EFFECTIVENESS_x4 160 #define AI_EFFECTIVENESS_x2 80 #define AI_EFFECTIVENESS_x1 40 #define AI_EFFECTIVENESS_x0_5 20 #define AI_EFFECTIVENESS_x0_25 10 +#define AI_EFFECTIVENESS_x0_125 5 #define AI_EFFECTIVENESS_x0 0 // ai weather diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 5c7d577c0..c4ad06ee5 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -555,7 +555,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) s32 moveType; u16 moveTarget = AI_GetBattlerMoveTargetType(battlerAtk, move); u16 accuracy = AI_GetMoveAccuracy(battlerAtk, battlerDef, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect, move); - u8 effectiveness = AI_GetMoveEffectiveness(move, battlerAtk, battlerDef); + u32 effectiveness = AI_GetMoveEffectiveness(move, battlerAtk, battlerDef); bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk); u32 i; u16 predictedMove = gLastMoves[battlerDef]; // TODO better move prediction @@ -600,6 +600,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case AI_EFFECTIVENESS_x0: RETURN_SCORE_MINUS(20); break; + case AI_EFFECTIVENESS_x0_125: case AI_EFFECTIVENESS_x0_25: RETURN_SCORE_MINUS(10); break; @@ -642,7 +643,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) RETURN_SCORE_MINUS(20); break; case ABILITY_WONDER_GUARD: - if (effectiveness != AI_EFFECTIVENESS_x2 && effectiveness != AI_EFFECTIVENESS_x4) + if (effectiveness < AI_EFFECTIVENESS_x2) return 0; break; case ABILITY_SAP_SIPPER: @@ -2524,33 +2525,17 @@ static s16 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) switch (AI_GetMoveEffectiveness(move, battlerAtk, battlerDef)) { + case AI_EFFECTIVENESS_x8: + score += 8; + break; case AI_EFFECTIVENESS_x4: - if (WEATHER_HAS_EFFECT - && gBattleWeather & B_WEATHER_STRONG_WINDS - && IS_BATTLER_OF_TYPE(battlerDef, TYPE_FLYING)) - { - if (AI_RandLessThan(176)) //Consider it supereffective instead of hypereffective. - score += 2; - else - score++; - } - else - score += 4; + score += 4; break; case AI_EFFECTIVENESS_x2: - if (WEATHER_HAS_EFFECT - && gBattleWeather & B_WEATHER_STRONG_WINDS - && IS_BATTLER_OF_TYPE(battlerDef, TYPE_FLYING)) - { - break; // Don't increase score, consider it neutral. - } + if (AI_RandLessThan(176)) + score += 2; else - { - if (AI_RandLessThan(176)) - score += 2; - else - score++; - } + score++; break; } } @@ -2962,7 +2947,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { // move data u16 moveEffect = gBattleMoves[move].effect; - u8 effectiveness = AI_GetMoveEffectiveness(move, battlerAtk, battlerDef); + u32 effectiveness = AI_GetMoveEffectiveness(move, battlerAtk, battlerDef); u8 atkPriority = GetMovePriority(battlerAtk, move); u16 predictedMove = gLastMoves[battlerDef]; //for now bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk); diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 8ed6e0490..59acbe0b7 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -950,10 +950,9 @@ u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef) return typeEffectiveness; } -u8 AI_GetMoveEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef) +u32 AI_GetMoveEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef) { - u8 damageVar; - u32 effectivenessMultiplier; + u32 damageVar, effectivenessMultiplier; gMoveResultFlags = 0; gCurrentMove = move; @@ -965,6 +964,9 @@ u8 AI_GetMoveEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef) default: damageVar = AI_EFFECTIVENESS_x0; break; + case UQ_4_12(0.125): + damageVar = AI_EFFECTIVENESS_x0_125; + break; case UQ_4_12(0.25): damageVar = AI_EFFECTIVENESS_x0_25; break; @@ -980,6 +982,9 @@ u8 AI_GetMoveEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef) case UQ_4_12(4.0): damageVar = AI_EFFECTIVENESS_x4; break; + case UQ_4_12(8.0): + damageVar = AI_EFFECTIVENESS_x8; + break; } return damageVar; From 86b436782aa756a2d9ffe14fdf1ca908178e1b9b Mon Sep 17 00:00:00 2001 From: sneed Date: Wed, 1 Jun 2022 22:01:50 +0300 Subject: [PATCH 113/130] trap move related code cleanup --- include/constants/battle.h | 3 +++ src/battle_message.c | 2 +- src/battle_script_commands.c | 8 +++----- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/include/constants/battle.h b/include/constants/battle.h index d651dab18..bcfb34c45 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -475,4 +475,7 @@ // For the second argument of GetMoveTarget, when no target override is needed #define NO_TARGET_OVERRIDE 0 +// Makes sure gWrappedStringIds and sTrappingMoves have the same size +#define TRAPPING_MOVES_COUNT 9 + #endif // GUARD_CONSTANTS_BATTLE_H diff --git a/src/battle_message.c b/src/battle_message.c index 8cf9a508b..34d020188 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -1562,7 +1562,7 @@ const u16 gFirstTurnOfTwoStringIds[] = }; // Index copied from move's index in sTrappingMoves -const u16 gWrappedStringIds[] = +const u16 gWrappedStringIds[TRAPPING_MOVES_COUNT] = { STRINGID_PKMNSQUEEZEDBYBIND, // MOVE_BIND STRINGID_PKMNWRAPPEDBY, // MOVE_WRAP diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 15915c71a..4abaf5adb 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -279,9 +279,9 @@ static const s32 sExperienceScalingFactors[] = 159767, }; -static const u16 sTrappingMoves[] = +static const u16 sTrappingMoves[TRAPPING_MOVES_COUNT] = { - MOVE_BIND, MOVE_WRAP, MOVE_FIRE_SPIN, MOVE_CLAMP, MOVE_WHIRLPOOL, MOVE_SAND_TOMB, MOVE_MAGMA_STORM, MOVE_INFESTATION, MOVE_SNAP_TRAP, 0xFFFF + MOVE_BIND, MOVE_WRAP, MOVE_FIRE_SPIN, MOVE_CLAMP, MOVE_WHIRLPOOL, MOVE_SAND_TOMB, MOVE_MAGMA_STORM, MOVE_INFESTATION, MOVE_SNAP_TRAP, }; #define STAT_CHANGE_WORKED 0 @@ -3037,10 +3037,8 @@ void SetMoveEffect(bool32 primary, u32 certain) BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleScripting.moveEffect]; - for (gBattleCommunication[MULTISTRING_CHOOSER] = 0; ; gBattleCommunication[MULTISTRING_CHOOSER]++) + for (gBattleCommunication[MULTISTRING_CHOOSER] = 0; gBattleCommunication[MULTISTRING_CHOOSER] < TRAPPING_MOVES_COUNT; gBattleCommunication[MULTISTRING_CHOOSER]++) { - if (gBattleCommunication[MULTISTRING_CHOOSER] > ARRAY_COUNT(sTrappingMoves) - 1) - break; if (sTrappingMoves[gBattleCommunication[MULTISTRING_CHOOSER]] == gCurrentMove) break; } From 5934acbdc5c3584c71cde625a9d0117dd1505b4c Mon Sep 17 00:00:00 2001 From: sneed Date: Wed, 1 Jun 2022 22:21:32 +0300 Subject: [PATCH 114/130] IS_BATTLER_OF_TYPE ignores 3rd type if mystery --- include/battle.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/battle.h b/include/battle.h index ea556c012..dd16ecbb0 100644 --- a/include/battle.h +++ b/include/battle.h @@ -633,7 +633,7 @@ struct BattleStruct #define TARGET_TURN_DAMAGED ((gSpecialStatuses[gBattlerTarget].physicalDmg != 0 || gSpecialStatuses[gBattlerTarget].specialDmg != 0)) #define BATTLER_DAMAGED(battlerId) ((gSpecialStatuses[battlerId].physicalDmg != 0 || gSpecialStatuses[battlerId].specialDmg != 0)) -#define IS_BATTLER_OF_TYPE(battlerId, type)((gBattleMons[battlerId].type1 == type || gBattleMons[battlerId].type2 == type || gBattleMons[battlerId].type3 == type)) +#define IS_BATTLER_OF_TYPE(battlerId, type)((gBattleMons[battlerId].type1 == type || gBattleMons[battlerId].type2 == type || (gBattleMons[battlerId].type3 != TYPE_MYSTERY && gBattleMons[battlerId].type3 == type))) #define SET_BATTLER_TYPE(battlerId, type) \ { \ gBattleMons[battlerId].type1 = type; \ From e1c57e4071c19cadd69c57420adfc97838b7cf3f Mon Sep 17 00:00:00 2001 From: sneed Date: Wed, 1 Jun 2022 22:45:50 +0300 Subject: [PATCH 115/130] move_none does not benefit from stab --- src/battle_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/battle_util.c b/src/battle_util.c index d0ff7c5be..b060a15ce 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -8941,7 +8941,7 @@ static u32 CalcFinalDmg(u32 dmg, u16 move, u8 battlerAtk, u8 battlerDef, u8 move } // check stab - if (IS_BATTLER_OF_TYPE(battlerAtk, moveType) && move != MOVE_STRUGGLE) + if (IS_BATTLER_OF_TYPE(battlerAtk, moveType) && move != MOVE_STRUGGLE && move != MOVE_NONE) { if (abilityAtk == ABILITY_ADAPTABILITY) MulModifier(&finalModifier, UQ_4_12(2.0)); From c60de5055d70a21328babc47f3cf1510fa46ac84 Mon Sep 17 00:00:00 2001 From: Sneed69 Date: Fri, 3 Jun 2022 17:24:57 +0300 Subject: [PATCH 116/130] remove IsMoveWithoutAnimation --- include/battle_gfx_sfx_util.h | 1 - src/battle_controller_link_opponent.c | 13 +++---------- src/battle_controller_link_partner.c | 13 +++---------- src/battle_controller_opponent.c | 11 ++--------- src/battle_controller_player.c | 13 +++---------- src/battle_controller_player_partner.c | 11 ++--------- src/battle_controller_recorded_opponent.c | 11 ++--------- src/battle_controller_recorded_player.c | 11 ++--------- src/battle_controller_wally.c | 12 ++---------- src/battle_gfx_sfx_util.c | 9 --------- 10 files changed, 19 insertions(+), 86 deletions(-) diff --git a/include/battle_gfx_sfx_util.h b/include/battle_gfx_sfx_util.h index 35e63aa75..e716fd9df 100644 --- a/include/battle_gfx_sfx_util.h +++ b/include/battle_gfx_sfx_util.h @@ -9,7 +9,6 @@ void SpriteCB_TrainerSlideIn(struct Sprite *sprite); void InitAndLaunchChosenStatusAnimation(bool8 isStatus2, u32 status); bool8 TryHandleLaunchBattleTableAnimation(u8 activeBattlerId, u8 attacker, u8 target, u8 tableId, u16 argument); void InitAndLaunchSpecialAnimation(u8 activeBattlerId, u8 attacker, u8 target, u8 tableId); -bool8 IsMoveWithoutAnimation(u16 moveId, u8 animationTurn); bool8 IsBattleSEPlaying(u8 battlerId); void BattleLoadOpponentMonSpriteGfx(struct Pokemon *mon, u8 battlerId); void BattleLoadPlayerMonSpriteGfx(struct Pokemon *mon, u8 battlerId); diff --git a/src/battle_controller_link_opponent.c b/src/battle_controller_link_opponent.c index 12276df7b..2ef3077d7 100644 --- a/src/battle_controller_link_opponent.c +++ b/src/battle_controller_link_opponent.c @@ -1399,16 +1399,9 @@ static void LinkOpponentHandleMoveAnimation(void) gWeatherMoveAnim = gBattleResources->bufferA[gActiveBattler][12] | (gBattleResources->bufferA[gActiveBattler][13] << 8); gAnimDisableStructPtr = (struct DisableStruct *)&gBattleResources->bufferA[gActiveBattler][16]; gTransformedPersonalities[gActiveBattler] = gAnimDisableStructPtr->transformedMonPersonality; - if (IsMoveWithoutAnimation(move, gAnimMoveTurn)) // always returns FALSE - { - LinkOpponentBufferExecCompleted(); - } - else - { - gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0; - gBattlerControllerFuncs[gActiveBattler] = LinkOpponentDoMoveAnimation; - BattleTv_SetDataBasedOnMove(move, gWeatherMoveAnim, gAnimDisableStructPtr); - } + gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0; + gBattlerControllerFuncs[gActiveBattler] = LinkOpponentDoMoveAnimation; + BattleTv_SetDataBasedOnMove(move, gWeatherMoveAnim, gAnimDisableStructPtr); } } diff --git a/src/battle_controller_link_partner.c b/src/battle_controller_link_partner.c index 278f5a192..1dadd9a44 100644 --- a/src/battle_controller_link_partner.c +++ b/src/battle_controller_link_partner.c @@ -1231,16 +1231,9 @@ static void LinkPartnerHandleMoveAnimation(void) gWeatherMoveAnim = gBattleResources->bufferA[gActiveBattler][12] | (gBattleResources->bufferA[gActiveBattler][13] << 8); gAnimDisableStructPtr = (struct DisableStruct *)&gBattleResources->bufferA[gActiveBattler][16]; gTransformedPersonalities[gActiveBattler] = gAnimDisableStructPtr->transformedMonPersonality; - if (IsMoveWithoutAnimation(move, gAnimMoveTurn)) // always returns FALSE - { - LinkPartnerBufferExecCompleted(); - } - else - { - gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0; - gBattlerControllerFuncs[gActiveBattler] = LinkPartnerDoMoveAnimation; - BattleTv_SetDataBasedOnMove(move, gWeatherMoveAnim, gAnimDisableStructPtr); - } + gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0; + gBattlerControllerFuncs[gActiveBattler] = LinkPartnerDoMoveAnimation; + BattleTv_SetDataBasedOnMove(move, gWeatherMoveAnim, gAnimDisableStructPtr); } } diff --git a/src/battle_controller_opponent.c b/src/battle_controller_opponent.c index 35e774341..f3b8352bb 100644 --- a/src/battle_controller_opponent.c +++ b/src/battle_controller_opponent.c @@ -1461,15 +1461,8 @@ static void OpponentHandleMoveAnimation(void) gWeatherMoveAnim = gBattleResources->bufferA[gActiveBattler][12] | (gBattleResources->bufferA[gActiveBattler][13] << 8); gAnimDisableStructPtr = (struct DisableStruct *)&gBattleResources->bufferA[gActiveBattler][16]; gTransformedPersonalities[gActiveBattler] = gAnimDisableStructPtr->transformedMonPersonality; - if (IsMoveWithoutAnimation(move, gAnimMoveTurn)) // always returns FALSE - { - OpponentBufferExecCompleted(); - } - else - { - gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0; - gBattlerControllerFuncs[gActiveBattler] = OpponentDoMoveAnimation; - } + gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0; + gBattlerControllerFuncs[gActiveBattler] = OpponentDoMoveAnimation; } } diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index 0e01eb549..9db7020bd 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -2662,16 +2662,9 @@ static void PlayerHandleMoveAnimation(void) gWeatherMoveAnim = gBattleResources->bufferA[gActiveBattler][12] | (gBattleResources->bufferA[gActiveBattler][13] << 8); gAnimDisableStructPtr = (struct DisableStruct *)&gBattleResources->bufferA[gActiveBattler][16]; gTransformedPersonalities[gActiveBattler] = gAnimDisableStructPtr->transformedMonPersonality; - if (IsMoveWithoutAnimation(move, gAnimMoveTurn)) // Always returns FALSE. - { - PlayerBufferExecCompleted(); - } - else - { - gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0; - gBattlerControllerFuncs[gActiveBattler] = PlayerDoMoveAnimation; - BattleTv_SetDataBasedOnMove(move, gWeatherMoveAnim, gAnimDisableStructPtr); - } + gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0; + gBattlerControllerFuncs[gActiveBattler] = PlayerDoMoveAnimation; + BattleTv_SetDataBasedOnMove(move, gWeatherMoveAnim, gAnimDisableStructPtr); } } diff --git a/src/battle_controller_player_partner.c b/src/battle_controller_player_partner.c index 0b7a95406..984a647f8 100644 --- a/src/battle_controller_player_partner.c +++ b/src/battle_controller_player_partner.c @@ -1428,15 +1428,8 @@ static void PlayerPartnerHandleMoveAnimation(void) gWeatherMoveAnim = gBattleResources->bufferA[gActiveBattler][12] | (gBattleResources->bufferA[gActiveBattler][13] << 8); gAnimDisableStructPtr = (struct DisableStruct *)&gBattleResources->bufferA[gActiveBattler][16]; gTransformedPersonalities[gActiveBattler] = gAnimDisableStructPtr->transformedMonPersonality; - if (IsMoveWithoutAnimation(move, gAnimMoveTurn)) // always returns FALSE - { - PlayerPartnerBufferExecCompleted(); - } - else - { - gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0; - gBattlerControllerFuncs[gActiveBattler] = PlayerPartnerDoMoveAnimation; - } + gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0; + gBattlerControllerFuncs[gActiveBattler] = PlayerPartnerDoMoveAnimation; } } diff --git a/src/battle_controller_recorded_opponent.c b/src/battle_controller_recorded_opponent.c index 69bffb45c..8968617ca 100644 --- a/src/battle_controller_recorded_opponent.c +++ b/src/battle_controller_recorded_opponent.c @@ -1327,15 +1327,8 @@ static void RecordedOpponentHandleMoveAnimation(void) gWeatherMoveAnim = gBattleResources->bufferA[gActiveBattler][12] | (gBattleResources->bufferA[gActiveBattler][13] << 8); gAnimDisableStructPtr = (struct DisableStruct *)&gBattleResources->bufferA[gActiveBattler][16]; gTransformedPersonalities[gActiveBattler] = gAnimDisableStructPtr->transformedMonPersonality; - if (IsMoveWithoutAnimation(move, gAnimMoveTurn)) // always returns FALSE - { - RecordedOpponentBufferExecCompleted(); - } - else - { - gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0; - gBattlerControllerFuncs[gActiveBattler] = RecordedOpponentDoMoveAnimation; - } + gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0; + gBattlerControllerFuncs[gActiveBattler] = RecordedOpponentDoMoveAnimation; } } diff --git a/src/battle_controller_recorded_player.c b/src/battle_controller_recorded_player.c index f81b24620..157bcf942 100644 --- a/src/battle_controller_recorded_player.c +++ b/src/battle_controller_recorded_player.c @@ -1331,15 +1331,8 @@ static void RecordedPlayerHandleMoveAnimation(void) gWeatherMoveAnim = gBattleResources->bufferA[gActiveBattler][12] | (gBattleResources->bufferA[gActiveBattler][13] << 8); gAnimDisableStructPtr = (struct DisableStruct *)&gBattleResources->bufferA[gActiveBattler][16]; gTransformedPersonalities[gActiveBattler] = gAnimDisableStructPtr->transformedMonPersonality; - if (IsMoveWithoutAnimation(move, gAnimMoveTurn)) // always returns FALSE - { - RecordedPlayerBufferExecCompleted(); - } - else - { - gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0; - gBattlerControllerFuncs[gActiveBattler] = RecordedPlayerDoMoveAnimation; - } + gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0; + gBattlerControllerFuncs[gActiveBattler] = RecordedPlayerDoMoveAnimation; } } diff --git a/src/battle_controller_wally.c b/src/battle_controller_wally.c index 076187297..5cd282b5b 100644 --- a/src/battle_controller_wally.c +++ b/src/battle_controller_wally.c @@ -1114,16 +1114,8 @@ static void WallyHandleMoveAnimation(void) gWeatherMoveAnim = gBattleResources->bufferA[gActiveBattler][12] | (gBattleResources->bufferA[gActiveBattler][13] << 8); gAnimDisableStructPtr = (struct DisableStruct *)&gBattleResources->bufferA[gActiveBattler][16]; gTransformedPersonalities[gActiveBattler] = gAnimDisableStructPtr->transformedMonPersonality; - if (IsMoveWithoutAnimation(move, gAnimMoveTurn)) // always returns FALSE - { - WallyBufferExecCompleted(); - } - else - { - gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0; - gBattlerControllerFuncs[gActiveBattler] = WallyDoMoveAnimation; - } - + gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0; + gBattlerControllerFuncs[gActiveBattler] = WallyDoMoveAnimation; } static void WallyDoMoveAnimation(void) diff --git a/src/battle_gfx_sfx_util.c b/src/battle_gfx_sfx_util.c index 2d441c7eb..df5fa69ac 100644 --- a/src/battle_gfx_sfx_util.c +++ b/src/battle_gfx_sfx_util.c @@ -526,15 +526,6 @@ static void Task_ClearBitWhenSpecialAnimDone(u8 taskId) #undef tBattlerId -// Great function to include newly added moves that don't have animation yet. -bool8 IsMoveWithoutAnimation(u16 moveId, u8 animationTurn) -{ - if (moveId >= (MOVES_COUNT - 1)) - return TRUE; - else - return FALSE; -} - // Check if SE has finished or 30 calls, whichever comes first bool8 IsBattleSEPlaying(u8 battlerId) { From f419fc3ae77acf136c7e3c1367b4e8bbb2f3779b Mon Sep 17 00:00:00 2001 From: sneed Date: Sat, 4 Jun 2022 18:36:18 +0300 Subject: [PATCH 117/130] fix terrain move softlock --- data/battle_scripts_1.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index a9c15040d..5ffe483b5 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -2390,7 +2390,7 @@ BattleScript_EffectPsychicTerrain: waitanimation printfromtable gTerrainStringIds waitmessage B_WAIT_TIME_LONG - playanimation BS_SCRIPTING, B_ANIM_RESTORE_BG + playanimation BS_ATTACKER, B_ANIM_RESTORE_BG call BattleScript_TerrainSeedLoop jumpifabilitypresent ABILITY_MIMICRY, BattleScript_ApplyMimicry goto BattleScript_MoveEnd From bf1025ac16620c9e148af609b7266d569f5d0836 Mon Sep 17 00:00:00 2001 From: sneed Date: Sun, 5 Jun 2022 05:09:06 +0300 Subject: [PATCH 118/130] Update battle_util.c --- src/battle_util.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/battle_util.c b/src/battle_util.c index d0ff7c5be..ebd7917d4 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -1696,6 +1696,7 @@ bool32 IsHealBlockPreventingMove(u32 battler, u32 move) case EFFECT_DREAM_EATER: #endif case EFFECT_MORNING_SUN: + case EFFECT_SYNTHESIS: case EFFECT_MOONLIGHT: case EFFECT_RESTORE_HP: case EFFECT_REST: From 1d19c0dc9fc44e1c3e3d51969daa82b3f6377790 Mon Sep 17 00:00:00 2001 From: sneed Date: Sun, 5 Jun 2022 16:38:37 +0300 Subject: [PATCH 119/130] Update battle_util.c --- src/battle_util.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/battle_util.c b/src/battle_util.c index ebd7917d4..3504c0a52 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -1704,6 +1704,7 @@ bool32 IsHealBlockPreventingMove(u32 battler, u32 move) case EFFECT_HEALING_WISH: case EFFECT_WISH: case EFFECT_HEAL_PULSE: + case EFFECT_JUNGLE_HEALING: return TRUE; default: return FALSE; From b33a8b0cb430d1636d7416a8a42a2753316c5fa9 Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Sun, 5 Jun 2022 11:09:04 -0400 Subject: [PATCH 120/130] move ai score calc to STATE_TURN_START_RECORD so AI can consider move selection for item use --- include/battle.h | 2 + include/battle_ai_main.h | 2 +- include/battle_ai_util.h | 3 +- include/constants/battle.h | 2 + src/battle_ai_main.c | 165 ++++++++++++++----------- src/battle_ai_switch_items.c | 68 ++++++++-- src/battle_ai_util.c | 33 +++-- src/battle_controller_opponent.c | 7 +- src/battle_controller_player_partner.c | 4 +- src/battle_main.c | 5 + 10 files changed, 187 insertions(+), 104 deletions(-) diff --git a/include/battle.h b/include/battle.h index 5d0b0596d..bcf018d0f 100644 --- a/include/battle.h +++ b/include/battle.h @@ -584,6 +584,8 @@ struct BattleStruct bool8 spriteIgnore0Hp; struct Illusion illusion[MAX_BATTLERS_COUNT]; s8 aiFinalScore[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // AI, target, moves to make debugging easier + u8 aiMoveOrAction[MAX_BATTLERS_COUNT]; + u8 aiChosenTarget[MAX_BATTLERS_COUNT]; u8 soulheartBattlerId; u8 friskedBattler; // Frisk needs to identify 2 battlers in double battles. bool8 friskedAbility; // If identifies two mons, show the ability pop-up only once. diff --git a/include/battle_ai_main.h b/include/battle_ai_main.h index 185281749..fcb31a9b2 100644 --- a/include/battle_ai_main.h +++ b/include/battle_ai_main.h @@ -19,7 +19,7 @@ return score; \ } - +u8 ComputeBattleAiScores(u8 battler); void BattleAI_SetupItems(void); void BattleAI_SetupFlags(void); void BattleAI_SetupAIData(u8 defaultScoreMoves); diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 7cc42e74a..437c475f7 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -20,6 +20,7 @@ void ClearBattlerItemEffectHistory(u8 battlerId); void SaveBattlerData(u8 battlerId); void SetBattlerData(u8 battlerId); void RestoreBattlerData(u8 battlerId); +u16 GetAIChosenMove(u8 battlerId); bool32 WillAIStrikeFirst(void); u32 GetTotalBaseStat(u32 species); @@ -27,7 +28,7 @@ bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler); bool32 AtMaxHp(u8 battler); u32 GetHealthPercentage(u8 battler); bool32 IsBattlerTrapped(u8 battler, bool8 switching); -u8 AI_WhoStrikesFirst(u8 battlerAI, u8 battler2); +u8 AI_WhoStrikesFirst(u8 battlerAI, u8 battler2, u16 consideredMove); bool32 CanTargetFaintAi(u8 battlerDef, u8 battlerAtk); bool32 CanMoveFaintBattler(u16 move, u8 battlerDef, u8 battlerAtk, u8 nHits); bool32 CanTargetFaintAiWithMod(u8 battlerDef, u8 battlerAtk, s32 hpMod, s32 dmgMod); diff --git a/include/constants/battle.h b/include/constants/battle.h index d651dab18..71252ae34 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -81,6 +81,8 @@ #define WILD_DOUBLE_BATTLE ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_TRAINER)))) #define BATTLE_TWO_VS_ONE_OPPONENT ((gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gTrainerBattleOpponent_B == 0xFFFF)) +#define BATTLE_TYPE_HAS_AI (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FIRST_BATTLE | BATTLE_TYPE_SAFARI | BATTLE_TYPE_ROAMER) + // Battle Outcome defines #define B_OUTCOME_WON 1 diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 6601862ed..dc3bd6b26 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -174,11 +174,12 @@ void BattleAI_SetupFlags(void) AI_THINKING_STRUCT->aiFlags |= AI_FLAG_DOUBLE_BATTLE; // Act smart in doubles and don't attack your partner. } +// sBattler_AI set in ComputeBattleAiScores void BattleAI_SetupAIData(u8 defaultScoreMoves) { s32 i, move, dmg; u8 moveLimitations; - + // Clear AI data but preserve the flags. u32 flags = AI_THINKING_STRUCT->aiFlags; memset(AI_THINKING_STRUCT, 0, sizeof(struct AI_ThinkingStruct)); @@ -204,8 +205,9 @@ void BattleAI_SetupAIData(u8 defaultScoreMoves) AI_THINKING_STRUCT->score[i] = 0; } - sBattler_AI = gActiveBattler; + //sBattler_AI = gActiveBattler; gBattlerTarget = SetRandomTarget(sBattler_AI); + gBattleStruct->aiChosenTarget[sBattler_AI] = gBattlerTarget; } u8 BattleAI_ChooseMoveOrAction(void) @@ -226,53 +228,73 @@ u8 BattleAI_ChooseMoveOrAction(void) return ret; } +// damages/other info computed in GetAIDataAndCalcDmg +u8 ComputeBattleAiScores(u8 battler) +{ + sBattler_AI = battler; + BattleAI_SetupAIData(0xF); + return BattleAI_ChooseMoveOrAction(); +} + +static void SetBattlerAiData(u8 battlerId) +{ + AI_DATA->abilities[battlerId] = AI_GetAbility(battlerId); + AI_DATA->items[battlerId] = gBattleMons[battlerId].item; + AI_DATA->holdEffects[battlerId] = AI_GetHoldEffect(battlerId); + AI_DATA->holdEffectParams[battlerId] = GetBattlerHoldEffectParam(battlerId); + AI_DATA->predictedMoves[battlerId] = gLastMoves[battlerId]; + AI_DATA->hpPercents[battlerId] = GetHealthPercentage(battlerId); + AI_DATA->moveLimitations[battlerId] = CheckMoveLimitations(battlerId, 0, 0xFF); +} + void GetAiLogicData(void) { u32 battlerAtk, battlerDef, i, move; u8 effectiveness; s32 dmg; + memset(AI_DATA, 0, sizeof(struct AiLogicData)); + if (!(gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FIRST_BATTLE | BATTLE_TYPE_SAFARI | BATTLE_TYPE_ROAMER) && !IsWildMonSmart())) return; - memset(AI_DATA, 0, sizeof(struct AiLogicData)); - for (battlerAtk = 0; battlerAtk < MAX_BATTLERS_COUNT; battlerAtk++) + // get/assume all battler data + for (i = 0; i < gBattlersCount; i++) { - if (IsBattlerAlive(battlerAtk)) { - AI_DATA->abilities[battlerAtk] = AI_GetAbility(battlerAtk); - AI_DATA->items[battlerAtk] = gBattleMons[battlerAtk].item; - AI_DATA->holdEffects[battlerAtk] = AI_GetHoldEffect(battlerAtk); - AI_DATA->holdEffectParams[battlerAtk] = GetBattlerHoldEffectParam(battlerAtk); - AI_DATA->predictedMoves[battlerAtk] = gLastMoves[battlerAtk]; - AI_DATA->hpPercents[battlerAtk] = GetHealthPercentage(battlerAtk); - AI_DATA->moveLimitations[battlerAtk] = CheckMoveLimitations(battlerAtk, 0, MOVE_LIMITATIONS_ALL); + if (IsBattlerAlive(i)) { + SetBattlerAiData(i); + } + } + + // simulate AI damage + for (battlerAtk = 0; battlerAtk < gBattlersCount; battlerAtk++) + { + if (!IsBattlerAlive(battlerAtk) + || !IsBattlerAIControlled(battlerAtk)) { + continue; + } + for (battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) + { + if (battlerAtk == battlerDef) + continue; - // Simulate dmg for all AI moves against all other targets - for (battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) + RecordKnownMove(battlerDef, gLastMoves[battlerDef]); + for (i = 0; i < MAX_MON_MOVES; i++) { - if (battlerAtk == battlerDef) - continue; + dmg = 0; + effectiveness = AI_EFFECTIVENESS_x0; + move = gBattleMons[battlerAtk].moves[i]; - RecordKnownMove(battlerDef, gLastMoves[battlerDef]); - for (i = 0; i < MAX_MON_MOVES; i++) - { - dmg = 0; - effectiveness = AI_EFFECTIVENESS_x0; - move = gBattleMons[battlerAtk].moves[i]; - if (move != 0 - && move != 0xFFFF - && gBattleMoves[move].power != 0 - && !(AI_DATA->moveLimitations[battlerAtk] & gBitTable[i])) - { - dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness); - if (dmg == 0) - dmg = 1; - } - - AI_DATA->simulatedDmg[battlerAtk][battlerDef][i] = dmg; - AI_DATA->effectiveness[battlerAtk][battlerDef][i] = effectiveness; + if (move != 0 + && move != 0xFFFF + //&& gBattleMoves[move].power != 0 /* we want to get effectiveness of status moves */ + && !(AI_DATA->moveLimitations[battlerAtk] & gBitTable[i])) { + dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness); } + + AI_DATA->simulatedDmg[battlerAtk][battlerDef][i] = dmg; + AI_DATA->effectiveness[battlerAtk][battlerDef][i] = effectiveness; } } } @@ -495,6 +517,7 @@ static u8 ChooseMoveOrAction_Doubles(void) } gBattlerTarget = mostViableTargetsArray[Random() % mostViableTargetsNo]; + gBattleStruct->aiChosenTarget[sBattler_AI] = gBattlerTarget; return actionOrMoveIndex[gBattlerTarget]; } @@ -556,7 +579,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) u16 moveEffect = gBattleMoves[move].effect; s32 moveType; u16 moveTarget = AI_GetBattlerMoveTargetType(battlerAtk, move); - u16 accuracy = AI_GetMoveAccuracy(battlerAtk, battlerDef, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect, move); + u16 accuracy = AI_GetMoveAccuracy(battlerAtk, battlerDef, move); u8 effectiveness = AI_DATA->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex]; bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk); u32 i; @@ -593,7 +616,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } // check off screen - if (IsSemiInvulnerable(battlerDef, move) && moveEffect != EFFECT_SEMI_INVULNERABLE && AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) + if (IsSemiInvulnerable(battlerDef, move) && moveEffect != EFFECT_SEMI_INVULNERABLE && AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) RETURN_SCORE_MINUS(20); // if target off screen and we go first, don't use move // check if negates type @@ -1292,7 +1315,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) && (B_MENTAL_HERB >= GEN_5 && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB) && !PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) { - if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) // Attacker should go first + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) // Attacker should go first { if (gLastMoves[battlerDef] == MOVE_NONE || gLastMoves[battlerDef] == 0xFFFF) score -= 10; // no anticipated move to disable @@ -1312,7 +1335,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) && (B_MENTAL_HERB >= GEN_5 && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB) && !DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) { - if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) // Attacker should go first + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) // Attacker should go first { if (gLastMoves[battlerDef] == MOVE_NONE || gLastMoves[battlerDef] == 0xFFFF) score -= 10; // no anticipated move to encore @@ -1755,7 +1778,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_SPITE: case EFFECT_MIMIC: - if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) // Attacker should go first + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) // Attacker should go first { if (gLastMoves[battlerDef] == MOVE_NONE || gLastMoves[battlerDef] == 0xFFFF) @@ -1912,7 +1935,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (isDoubleBattle) { if (IsHazardMoveEffect(gBattleMoves[AI_DATA->partnerMove].effect) // partner is going to set up hazards - && AI_WhoStrikesFirst(BATTLE_PARTNER(battlerAtk), battlerAtk) == AI_IS_FASTER) // partner is going to set up before the potential Defog + && AI_WhoStrikesFirst(BATTLE_PARTNER(battlerAtk), battlerAtk, AI_DATA->partnerMove) == AI_IS_FASTER) // partner is going to set up before the potential Defog { score -= 10; break; // Don't use Defog if partner is going to set up hazards @@ -1950,7 +1973,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_SEMI_INVULNERABLE: if (predictedMove != MOVE_NONE - && AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER + && AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER && gBattleMoves[predictedMove].effect == EFFECT_SEMI_INVULNERABLE) score -= 10; // Don't Fly/dig/etc if opponent is going to fly/dig/etc after you @@ -2131,7 +2154,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_ME_FIRST: if (predictedMove != MOVE_NONE) { - if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER) + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER) score -= 10; // Target is predicted to go first, Me First will fail else return AI_CheckBadMove(battlerAtk, battlerDef, predictedMove, score); @@ -2320,7 +2343,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_ELECTRIFY: - if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER //|| GetMoveTypeSpecial(battlerDef, predictedMove) == TYPE_ELECTRIC // Move will already be electric type || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) score -= 10; @@ -2349,7 +2372,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_INSTRUCT: { u16 instructedMove; - if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER) + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER) instructedMove = predictedMove; else instructedMove = gLastMoves[battlerDef]; @@ -2389,21 +2412,21 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_QUASH: if (!isDoubleBattle - || AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER + || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_AFTER_YOU: if (!IsTargetingPartner(battlerAtk, battlerDef) || !isDoubleBattle - || AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER + || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_SUCKER_PUNCH: if (predictedMove != MOVE_NONE) { - if (IS_MOVE_STATUS(predictedMove) || AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER) // Opponent going first + if (IS_MOVE_STATUS(predictedMove) || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER) // Opponent going first score -= 10; } break; @@ -2455,7 +2478,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score--; // don't want to move last break; case EFFECT_FLAIL: - if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER // Opponent should go first + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER // Opponent should go first || AI_DATA->hpPercents[battlerAtk] > 50) score -= 4; break; @@ -2604,7 +2627,7 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // Ally decided to use Frost Breath on us. we must have Anger Point as our ability if (AI_DATA->abilities[battlerAtk] == ABILITY_ANGER_POINT) { - if (AI_WhoStrikesFirst(battlerAtk, battlerAtkPartner) == AI_IS_SLOWER) // Partner moving first + if (AI_WhoStrikesFirst(battlerAtk, battlerAtkPartner, move) == AI_IS_SLOWER) // Partner moving first { // discourage raising our attack since it's about to be maxed out if (IsAttackBoostMoveEffect(effect)) @@ -2871,7 +2894,7 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_INSTRUCT: { u16 instructedMove; - if (AI_WhoStrikesFirst(battlerAtk, battlerAtkPartner) == AI_IS_FASTER) + if (AI_WhoStrikesFirst(battlerAtk, battlerAtkPartner, move) == AI_IS_FASTER) instructedMove = AI_DATA->partnerMove; else instructedMove = gLastMoves[battlerAtkPartner]; @@ -2885,8 +2908,8 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_AFTER_YOU: - if (AI_WhoStrikesFirst(battlerAtkPartner, FOE(battlerAtkPartner) == AI_IS_SLOWER) // Opponent mon 1 goes before partner - || AI_WhoStrikesFirst(battlerAtkPartner, BATTLE_PARTNER(FOE(battlerAtkPartner)) == AI_IS_SLOWER)) // Opponent mon 2 goes before partner + if (AI_WhoStrikesFirst(battlerAtkPartner, FOE(battlerAtkPartner), AI_DATA->partnerMove) == AI_IS_SLOWER // Opponent mon 1 goes before partner + || AI_WhoStrikesFirst(battlerAtkPartner, BATTLE_PARTNER(FOE(battlerAtkPartner)), AI_DATA->partnerMove) == AI_IS_SLOWER) // Opponent mon 2 goes before partner { if (gBattleMoves[AI_DATA->partnerMove].effect == EFFECT_COUNTER || gBattleMoves[AI_DATA->partnerMove].effect == EFFECT_MIRROR_COAT) break; // These moves need to go last @@ -2913,7 +2936,7 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_MAGNITUDE: if (!IsBattlerGrounded(battlerAtkPartner) || (IsBattlerGrounded(battlerAtkPartner) - && AI_WhoStrikesFirst(battlerAtk, battlerAtkPartner) == AI_IS_SLOWER + && AI_WhoStrikesFirst(battlerAtk, battlerAtkPartner, move) == AI_IS_SLOWER && IsUngroundingEffect(gBattleMoves[AI_DATA->partnerMove].effect))) score += 2; else if (IS_BATTLER_OF_TYPE(battlerAtkPartner, TYPE_FIRE) @@ -2986,7 +3009,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // check already dead if (!IsBattlerIncapacitated(battlerDef, AI_DATA->abilities[battlerDef]) && CanTargetFaintAi(battlerAtk, battlerDef) - && AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER) // Opponent should go first + && AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER) // Opponent should go first { if (atkPriority > 0) score++; @@ -3034,7 +3057,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case ABILITY_GRIM_NEIGH: case ABILITY_AS_ONE_ICE_RIDER: case ABILITY_AS_ONE_SHADOW_RIDER: - if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) // Attacker should go first + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) // Attacker should go first { if (CanIndexMoveFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) score += 8; // prioritize killing target for stat boost @@ -3481,7 +3504,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score++; break; case EFFECT_MIMIC: - if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) { if (gLastMoves[battlerDef] != MOVE_NONE && gLastMoves[battlerDef] != 0xFFFF) return AI_CheckViability(battlerAtk, battlerDef, gLastMoves[battlerDef], score); @@ -3540,7 +3563,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (gDisableStructs[battlerDef].disableTimer == 0 && (B_MENTAL_HERB >= GEN_5 && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB)) // mental herb { - if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) // AI goes first + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) // AI goes first { if (gLastMoves[battlerDef] != MOVE_NONE && gLastMoves[battlerDef] != 0xFFFF) @@ -3594,7 +3617,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score += 3; break; case EFFECT_DESTINY_BOND: - if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER && CanTargetFaintAi(battlerDef, battlerAtk)) + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER && CanTargetFaintAi(battlerDef, battlerAtk)) score += 3; break; case EFFECT_SPITE: @@ -3703,7 +3726,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); } - else if (isDoubleBattle && AI_GetBattlerMoveTargetType(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove) & MOVE_TARGET_FOES_AND_ALLY) + else if (isDoubleBattle && AI_GetBattlerMoveTargetType(BATTLE_PARTNER(battlerAtk), AI_DATA->partnerMove) & MOVE_TARGET_FOES_AND_ALLY) { if (AI_DATA->abilities[battlerAtk] != ABILITY_TELEPATHY) ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score); @@ -3842,7 +3865,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) && AI_DATA->abilities[battlerAtk] != ABILITY_CONTRARY && CanIndexMoveFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) { - if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) // Attacker goes first + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) // Attacker goes first score += 9; else score += 3; @@ -3887,7 +3910,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score++; if (predictedMove != MOVE_NONE && !isDoubleBattle) { - if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) // Attacker goes first + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) // Attacker goes first { if (gBattleMoves[predictedMove].effect == EFFECT_EXPLOSION || gBattleMoves[predictedMove].effect == EFFECT_PROTECT) @@ -3954,7 +3977,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_ATTRACT: if (!isDoubleBattle && BattlerWillFaintFromSecondaryDamage(battlerDef, AI_DATA->abilities[battlerDef]) - && AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER) // Target goes first + && AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER) // Target goes first break; // Don't use if the attract won't have a change to activate if (gBattleMons[battlerDef].status1 & STATUS1_ANY @@ -3999,7 +4022,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (isDoubleBattle) { if (IsHazardMoveEffect(gBattleMoves[AI_DATA->partnerMove].effect) // Partner is going to set up hazards - && AI_WhoStrikesFirst(battlerAtk, BATTLE_PARTNER(battlerAtk)) == AI_IS_SLOWER) // Partner going first + && AI_WhoStrikesFirst(battlerAtk, BATTLE_PARTNER(battlerAtk), move) == AI_IS_SLOWER) // Partner going first break; // Don't use Defog if partner is going to set up hazards } @@ -4488,13 +4511,13 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score++; break; case EFFECT_THROAT_CHOP: - if (predictedMove != MOVE_NONE && TestMoveFlags(predictedMove, FLAG_SOUND) && AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) + if (predictedMove != MOVE_NONE && TestMoveFlags(predictedMove, FLAG_SOUND) && AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) score += 3; // Ai goes first and predicts the target will use a sound move else if (TestMoveFlagsInMoveset(battlerDef, FLAG_SOUND)) score += 3; break; case EFFECT_HEAL_BLOCK: - if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER && predictedMove != MOVE_NONE && IsHealingMoveEffect(gBattleMoves[predictedMove].effect)) + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER && predictedMove != MOVE_NONE && IsHealingMoveEffect(gBattleMoves[predictedMove].effect)) score += 3; // Try to cancel healing move else if (HasHealingEffect(battlerDef) || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_LEFTOVERS || (AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_BLACK_SLUDGE && IS_BATTLER_OF_TYPE(battlerDef, TYPE_POISON))) @@ -4530,7 +4553,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_QUASH: if (isDoubleBattle - && AI_WhoStrikesFirst(BATTLE_PARTNER(battlerAtk), battlerDef) == AI_IS_SLOWER) // Attacker partner wouldn't go before target + && AI_WhoStrikesFirst(BATTLE_PARTNER(battlerAtk), battlerDef, AI_DATA->partnerMove) == AI_IS_SLOWER) // Attacker partner wouldn't go before target score++; break; case EFFECT_TAILWIND: @@ -4552,7 +4575,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (IsBattlerGrounded(battlerAtk) && HasDamagingMoveOfType(battlerDef, TYPE_ELECTRIC) && !(AI_GetTypeEffectiveness(MOVE_EARTHQUAKE, battlerDef, battlerAtk) == AI_EFFECTIVENESS_x0)) // Doesn't resist ground move { - if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) // Attacker goes first + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) // Attacker goes first { if (gBattleMoves[predictedMove].type == TYPE_GROUND) score += 3; // Cause the enemy's move to fail @@ -4567,7 +4590,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_CAMOUFLAGE: - if (predictedMove != MOVE_NONE && AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER // Attacker goes first + if (predictedMove != MOVE_NONE && AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER // Attacker goes first && !IS_MOVE_STATUS(move) && AI_GetTypeEffectiveness(predictedMove, battlerDef, battlerAtk) != AI_EFFECTIVENESS_x0) score++; break; @@ -4610,7 +4633,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_FLAIL: - if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) // Ai goes first + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) // Ai goes first { if (AI_DATA->hpPercents[battlerAtk] < 20) score++; @@ -4652,7 +4675,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score += 2; break; case EFFECT_ENDEAVOR: - if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER) // Opponent faster + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER) // Opponent faster { if (AI_DATA->hpPercents[battlerAtk] < 40) score++; @@ -4683,7 +4706,7 @@ static s16 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) return score; if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_SMART_SWITCHING - && AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER + && AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER && CanTargetFaintAi(battlerDef, battlerAtk) && GetMovePriority(battlerAtk, move) == 0) { diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index 9136d667c..7963d8b86 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -18,6 +18,8 @@ static bool8 HasSuperEffectiveMoveAgainstOpponents(bool8 noRng); static bool8 FindMonWithFlagsAndSuperEffective(u16 flags, u8 moduloPercent); static bool8 ShouldUseItem(void); +static bool32 AI_ShouldHeal(u32 healAmount); +static bool32 AI_OpponentCanFaintAiWithMod(u32 healAmount); void GetAIPartyIndexes(u32 battlerId, s32 *firstId, s32 *lastId) { @@ -788,6 +790,25 @@ static u8 GetAI_ItemType(u16 itemId, const u8 *itemEffect) return AI_ITEM_NOT_RECOGNIZABLE; } +static bool32 AiExpectsToFaintPlayer(void) +{ + bool32 canFaintPlayer; + u32 i; + u8 target = gBattleStruct->aiChosenTarget[gActiveBattler]; + + if (gBattleStruct->aiMoveOrAction[gActiveBattler] > 3) + return FALSE; // AI not planning to use move + + if (GetBattlerSide(target) != GetBattlerSide(gActiveBattler) + && CanIndexMoveFaintTarget(gActiveBattler, target, gBattleStruct->aiMoveOrAction[gActiveBattler], 0) + && AI_WhoStrikesFirst(gActiveBattler, target, GetAIChosenMove(gActiveBattler)) == AI_IS_FASTER) { + // We expect to faint the target and move first -> dont use an item + return TRUE; + } + + return FALSE; +} + static bool8 ShouldUseItem(void) { struct Pokemon *party; @@ -802,6 +823,9 @@ static bool8 ShouldUseItem(void) if (gStatuses3[gActiveBattler] & STATUS3_EMBARGO) return FALSE; + + if (AiExpectsToFaintPlayer()) + return FALSE; if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER) party = gPlayerParty; @@ -843,21 +867,10 @@ static bool8 ShouldUseItem(void) switch (*(gBattleStruct->AI_itemType + gActiveBattler / 2)) { case AI_ITEM_FULL_RESTORE: - if (gBattleMons[gActiveBattler].hp >= gBattleMons[gActiveBattler].maxHP / 4) - break; - if (gBattleMons[gActiveBattler].hp == 0) - break; - shouldUse = TRUE; + shouldUse = AI_ShouldHeal(0); break; case AI_ITEM_HEAL_HP: - paramOffset = GetItemEffectParamOffset(item, 4, 4); - if (paramOffset == 0) - break; - if (gBattleMons[gActiveBattler].hp == 0) - break; - if (gBattleMons[gActiveBattler].hp < gBattleMons[gActiveBattler].maxHP / 4 - || gBattleMons[gActiveBattler].maxHP - gBattleMons[gActiveBattler].hp > itemEffects[paramOffset]) - shouldUse = TRUE; + shouldUse = AI_ShouldHeal(itemEffects[GetItemEffectParamOffset(item, 4, 4)]); break; case AI_ITEM_CURE_CONDITION: *(gBattleStruct->AI_itemFlags + gActiveBattler / 2) = 0; @@ -948,3 +961,32 @@ static bool8 ShouldUseItem(void) return FALSE; } + +static bool32 AI_ShouldHeal(u32 healAmount) +{ + bool32 shouldHeal = FALSE; + + if (gBattleMons[gActiveBattler].hp < gBattleMons[gActiveBattler].maxHP / 4 + || gBattleMons[gActiveBattler].hp == 0 + || (healAmount != 0 && gBattleMons[gActiveBattler].maxHP - gBattleMons[gActiveBattler].hp > healAmount)) { + // We have low enough HP to consider healing + shouldHeal = !AI_OpponentCanFaintAiWithMod(healAmount); // if target can kill us even after we heal, why bother + } + + return shouldHeal; +} + +static bool32 AI_OpponentCanFaintAiWithMod(u32 healAmount) +{ + u32 i; + // Check special cases to NOT heal + for (i = 0; i < gBattlersCount; i++) { + if (GetBattlerSide(i) == B_SIDE_PLAYER) { + if (CanTargetFaintAiWithMod(i, gActiveBattler, healAmount, 0)) { + // Target is expected to faint us + return TRUE; + } + } + } + return FALSE; +} diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 3a43fd702..a5cbc92b0 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -440,9 +440,14 @@ static const u16 sOtherMoveCallingMoves[] = }; // Functions +u16 GetAIChosenMove(u8 battlerId) +{ + return (gBattleMons[battlerId].moves[gBattleStruct->aiMoveOrAction[battlerId]]); +} + bool32 WillAIStrikeFirst(void) { - return (AI_WhoStrikesFirst(sBattler_AI, gBattlerTarget) == AI_IS_FASTER); + return (AI_WhoStrikesFirst(sBattler_AI, gBattlerTarget, AI_THINKING_STRUCT->moveConsidered) == AI_IS_FASTER); } bool32 AI_RandLessThan(u8 val) @@ -638,7 +643,7 @@ bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler) u32 move = gBattleResources->battleHistory->usedMoves[opposingBattler][i]; if (gBattleMoves[move].effect == EFFECT_PROTECT && move != MOVE_ENDURE) return TRUE; - if (gBattleMoves[move].effect == EFFECT_SEMI_INVULNERABLE && AI_WhoStrikesFirst(battlerAI, opposingBattler) == AI_IS_SLOWER) + if (gBattleMoves[move].effect == EFFECT_SEMI_INVULNERABLE && AI_WhoStrikesFirst(battlerAI, opposingBattler, GetAIChosenMove(battlerAI)) == AI_IS_SLOWER) return TRUE; } return FALSE; @@ -987,23 +992,25 @@ static u8 AI_GetEffectiveness(u16 multiplier) * AI_IS_FASTER: is user(ai) faster * AI_IS_SLOWER: is target faster */ -u8 AI_WhoStrikesFirst(u8 battlerAI, u8 battler2) +u8 AI_WhoStrikesFirst(u8 battlerAI, u8 battler2, u16 moveConsidered) { u32 fasterAI = 0, fasterPlayer = 0, i; s8 prioAI = 0; s8 prioPlayer = 0; + s8 prioBattler2 = 0; + u16 *battler2Moves = GetMovesArray(battler2); // Check move priorities first. - prioAI = GetMovePriority(battlerAI, AI_THINKING_STRUCT->moveConsidered); + prioAI = GetMovePriority(battlerAI, moveConsidered); for (i = 0; i < MAX_MON_MOVES; i++) { - if (gBattleMons[battler2].moves[i] == 0 || gBattleMons[battler2].moves[i] == 0xFFFF) + if (battler2Moves[i] == 0 || battler2Moves[i] == 0xFFFF) continue; - prioPlayer = GetMovePriority(battler2, gBattleMons[battler2].moves[i]); - if (prioAI > prioPlayer) + prioBattler2 = GetMovePriority(battler2, battler2Moves[i]); + if (prioAI > prioBattler2) fasterAI++; - else if (prioPlayer > prioAI) + else if (prioBattler2 > prioAI) fasterPlayer++; } @@ -1017,6 +1024,8 @@ u8 AI_WhoStrikesFirst(u8 battlerAI, u8 battler2) } else { + if (prioAI > prioBattler2) + return AI_IS_FASTER; // if we didn't know any of battler 2's moves to compare priorities, assume they don't have a prio+ move // Priorities are the same(at least comparing to moves the AI is aware of), decide by speed. if (GetWhoStrikesFirst(battlerAI, battler2, TRUE) == 0) return AI_IS_FASTER; @@ -2422,7 +2431,7 @@ bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 mo /*if (IsPredictedToSwitch(battlerDef, battlerAtk) && !hasStatBoost) return PIVOT; // Try pivoting so you can switch to a better matchup to counter your new opponent*/ - if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) // Attacker goes first + if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) // Attacker goes first { if (!CanAIFaintTarget(battlerAtk, battlerDef, 0)) // Can't KO foe otherwise { @@ -2782,7 +2791,7 @@ u32 ShouldTryToFlinch(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbili { if (defAbility == ABILITY_INNER_FOCUS || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) - || AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER) // Opponent goes first + || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER) // Opponent goes first { return 0; // don't try to flinch } @@ -2906,7 +2915,7 @@ bool32 ShouldUseRecoilMove(u8 battlerAtk, u8 battlerDef, u32 recoilDmg, u8 moveI bool32 ShouldAbsorb(u8 battlerAtk, u8 battlerDef, u16 move, s32 damage) { - if (move == 0xFFFF || AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) + if (move == 0xFFFF || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) { // using item or user goes first u8 healPercent = (gBattleMoves[move].argument == 0) ? 50 : gBattleMoves[move].argument; @@ -2933,7 +2942,7 @@ bool32 ShouldAbsorb(u8 battlerAtk, u8 battlerDef, u16 move, s32 damage) bool32 ShouldRecover(u8 battlerAtk, u8 battlerDef, u16 move, u8 healPercent) { - if (move == 0xFFFF || AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) + if (move == 0xFFFF || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) { // using item or user going first s32 damage = AI_DATA->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex]; diff --git a/src/battle_controller_opponent.c b/src/battle_controller_opponent.c index f3b8352bb..9c262405b 100644 --- a/src/battle_controller_opponent.c +++ b/src/battle_controller_opponent.c @@ -1535,7 +1535,7 @@ static void OpponentHandlePrintSelectionString(void) static void OpponentHandleChooseAction(void) { - AI_TrySwitchOrUseItem(); // TODO consider move choice first + AI_TrySwitchOrUseItem(); OpponentBufferExecCompleted(); } @@ -1559,9 +1559,8 @@ static void OpponentHandleChooseMove(void) if (gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FIRST_BATTLE | BATTLE_TYPE_SAFARI | BATTLE_TYPE_ROAMER) || IsWildMonSmart()) { - BattleAI_SetupAIData(0xF); - chosenMoveId = BattleAI_ChooseMoveOrAction(); - + chosenMoveId = gBattleStruct->aiMoveOrAction[gActiveBattler]; + gBattlerTarget = gBattleStruct->aiChosenTarget[gActiveBattler]; switch (chosenMoveId) { case AI_CHOICE_WATCH: diff --git a/src/battle_controller_player_partner.c b/src/battle_controller_player_partner.c index 984a647f8..4e41651de 100644 --- a/src/battle_controller_player_partner.c +++ b/src/battle_controller_player_partner.c @@ -1515,8 +1515,8 @@ static void PlayerPartnerHandleChooseMove(void) u8 chosenMoveId; struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct*)(&gBattleResources->bufferA[gActiveBattler][4]); - BattleAI_SetupAIData(0xF); - chosenMoveId = BattleAI_ChooseMoveOrAction(); + chosenMoveId = gBattleStruct->aiMoveOrAction[gActiveBattler]; + gBattlerTarget = gBattleStruct->aiChosenTarget[gActiveBattler]; if (gBattleMoves[moveInfo->moves[chosenMoveId]].target & (MOVE_TARGET_USER | MOVE_TARGET_USER_OR_SELECTED)) gBattlerTarget = gActiveBattler; diff --git a/src/battle_main.c b/src/battle_main.c index 5bf5043e1..cb38f3bdf 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -3918,6 +3918,11 @@ static void HandleTurnActionSelectionState(void) case STATE_TURN_START_RECORD: // Recorded battle related action on start of every turn. RecordedBattle_CopyBattlerMoves(); gBattleCommunication[gActiveBattler] = STATE_BEFORE_ACTION_CHOSEN; + + // Do AI score computations here so we can use them in AI_TrySwitchOrUseItem + if ((gBattleTypeFlags & BATTLE_TYPE_HAS_AI || IsWildMonSmart()) && IsBattlerAIControlled(gActiveBattler)) { + gBattleStruct->aiMoveOrAction[gActiveBattler] = ComputeBattleAiScores(gActiveBattler); + } break; case STATE_BEFORE_ACTION_CHOSEN: // Choose an action. *(gBattleStruct->monToSwitchIntoId + gActiveBattler) = PARTY_SIZE; From 407047ace7bcfbf73119dd0b80cf890a23725604 Mon Sep 17 00:00:00 2001 From: sneed Date: Fri, 10 Jun 2022 22:31:53 +0300 Subject: [PATCH 121/130] ground x2 vs flying if inverse battle --- src/battle_util.c | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/battle_util.c b/src/battle_util.c index ebd7917d4..e521ef00d 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -7770,33 +7770,35 @@ bool32 IsBattlerProtected(u8 battlerId, u16 move) return FALSE; } - -bool32 IsBattlerGrounded(u8 battlerId) +// Only called directly when calculating damage type effectiveness +static bool32 IsBattlerGrounded2(u8 battlerId, bool32 considerInverse) { if (GetBattlerHoldEffect(battlerId, TRUE) == HOLD_EFFECT_IRON_BALL) return TRUE; - else if (gFieldStatuses & STATUS_FIELD_GRAVITY) + if (gFieldStatuses & STATUS_FIELD_GRAVITY) return TRUE; #if B_ROOTED_GROUNDING >= GEN_4 - else if (gStatuses3[battlerId] & STATUS3_ROOTED) + if (gStatuses3[battlerId] & STATUS3_ROOTED) return TRUE; #endif - else if (gStatuses3[battlerId] & STATUS3_SMACKED_DOWN) + if (gStatuses3[battlerId] & STATUS3_SMACKED_DOWN) return TRUE; + if (gStatuses3[battlerId] & STATUS3_TELEKINESIS) + return FALSE; + if (gStatuses3[battlerId] & STATUS3_MAGNET_RISE) + return FALSE; + if (GetBattlerHoldEffect(battlerId, TRUE) == HOLD_EFFECT_AIR_BALLOON) + return FALSE; + if (GetBattlerAbility(battlerId) == ABILITY_LEVITATE) + return FALSE; + if (IS_BATTLER_OF_TYPE(battlerId, TYPE_FLYING) && (!considerInverse || !FlagGet(B_FLAG_INVERSE_BATTLE))) + return FALSE; + return TRUE; +} - else if (gStatuses3[battlerId] & STATUS3_TELEKINESIS) - return FALSE; - else if (gStatuses3[battlerId] & STATUS3_MAGNET_RISE) - return FALSE; - else if (GetBattlerHoldEffect(battlerId, TRUE) == HOLD_EFFECT_AIR_BALLOON) - return FALSE; - else if (GetBattlerAbility(battlerId) == ABILITY_LEVITATE) - return FALSE; - else if (IS_BATTLER_OF_TYPE(battlerId, TYPE_FLYING)) - return FALSE; - - else - return TRUE; +bool32 IsBattlerGrounded(u8 battlerId) +{ + IsBattlerGrounded2(battlerId, FALSE); } bool32 IsBattlerAlive(u8 battlerId) @@ -9172,7 +9174,7 @@ static u16 CalcTypeEffectivenessMultiplierInternal(u16 move, u8 moveType, u8 bat && gBattleMons[battlerDef].type3 != gBattleMons[battlerDef].type1) MulByTypeEffectiveness(&modifier, move, moveType, battlerDef, gBattleMons[battlerDef].type3, battlerAtk, recordAbilities); - if (moveType == TYPE_GROUND && !IsBattlerGrounded(battlerDef) && !(gBattleMoves[move].flags & FLAG_DMG_UNGROUNDED_IGNORE_TYPE_IF_FLYING)) + if (moveType == TYPE_GROUND && !IsBattlerGrounded2(battlerDef, TRUE) && !(gBattleMoves[move].flags & FLAG_DMG_UNGROUNDED_IGNORE_TYPE_IF_FLYING)) { modifier = UQ_4_12(0.0); if (recordAbilities && defAbility == ABILITY_LEVITATE) From f43d54af8935fddc511d90aac46eecc1f2ec3abe Mon Sep 17 00:00:00 2001 From: sneed Date: Sat, 18 Jun 2022 19:00:33 +0300 Subject: [PATCH 122/130] AI chooses most resistant mon --- src/battle_ai_switch_items.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index 9136d667c..0d394c3b8 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -602,39 +602,39 @@ static u32 GetBestMonBatonPass(struct Pokemon *party, int firstId, int lastId, u return PARTY_SIZE; } -static u32 GestBestMonOffensive(struct Pokemon *party, int firstId, int lastId, u8 invalidMons, u32 opposingBattler) +static u32 GestBestMonTypeMatchup(struct Pokemon *party, int firstId, int lastId, u8 invalidMons, u32 opposingBattler) { int i, bits = 0; while (bits != 0x3F) // All mons were checked. { - int bestDmg = 0; + u32 bestResist = UQ_4_12(1.0); int bestMonId = PARTY_SIZE; - // Find the mon whose type is the most suitable offensively. + // Find the mon whose type is the most suitable defensively. for (i = firstId; i < lastId; i++) { if (!(gBitTable[i] & invalidMons) && !(gBitTable[i] & bits)) { u16 species = GetMonData(&party[i], MON_DATA_SPECIES); - u32 typeDmg = UQ_4_12(1.0); + u32 typeEffectiveness = UQ_4_12(1.0); - u8 atkType1 = gBaseStats[species].type1; - u8 atkType2 = gBaseStats[species].type2; - u8 defType1 = gBattleMons[opposingBattler].type1; - u8 defType2 = gBattleMons[opposingBattler].type2; + u8 atkType1 = gBattleMons[opposingBattler].type1; + u8 atkType2 = gBattleMons[opposingBattler].type2; + u8 defType1 = gBaseStats[species].type1; + u8 defType2 = gBaseStats[species].type2; - typeDmg *= GetTypeModifier(atkType1, defType1); + typeEffectiveness *= GetTypeModifier(atkType1, defType1); if (atkType2 != atkType1) - typeDmg *= GetTypeModifier(atkType2, defType1); + typeEffectiveness *= GetTypeModifier(atkType2, defType1); if (defType2 != defType1) { - typeDmg *= GetTypeModifier(atkType1, defType2); + typeEffectiveness *= GetTypeModifier(atkType1, defType2); if (atkType2 != atkType1) - typeDmg *= GetTypeModifier(atkType2, defType2); + typeEffectiveness *= GetTypeModifier(atkType2, defType2); } - if (bestDmg < typeDmg) + if (typeEffectiveness < bestResist) { - bestDmg = typeDmg; + bestResist = typeEffectiveness; bestMonId = i; } } @@ -698,7 +698,6 @@ static u32 GetBestMonDmg(struct Pokemon *party, int firstId, int lastId, u8 inva u8 GetMostSuitableMonToSwitchInto(void) { u32 opposingBattler = 0; - u32 bestDmg = 0; u32 bestMonId = 0; u8 battlerIn1 = 0, battlerIn2 = 0; s32 firstId = 0; @@ -757,7 +756,7 @@ u8 GetMostSuitableMonToSwitchInto(void) if (bestMonId != PARTY_SIZE) return bestMonId; - bestMonId = GestBestMonOffensive(party, firstId, lastId, invalidMons, opposingBattler); + bestMonId = GestBestMonTypeMatchup(party, firstId, lastId, invalidMons, opposingBattler); if (bestMonId != PARTY_SIZE) return bestMonId; From 5e7df653bd2658d6b55c28d00f180eea744caa2d Mon Sep 17 00:00:00 2001 From: sneed Date: Sat, 18 Jun 2022 19:18:01 +0300 Subject: [PATCH 123/130] no gest --- src/battle_ai_switch_items.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index 0d394c3b8..42f6c7fc9 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -602,7 +602,7 @@ static u32 GetBestMonBatonPass(struct Pokemon *party, int firstId, int lastId, u return PARTY_SIZE; } -static u32 GestBestMonTypeMatchup(struct Pokemon *party, int firstId, int lastId, u8 invalidMons, u32 opposingBattler) +static u32 GetBestMonTypeMatchup(struct Pokemon *party, int firstId, int lastId, u8 invalidMons, u32 opposingBattler) { int i, bits = 0; @@ -756,7 +756,7 @@ u8 GetMostSuitableMonToSwitchInto(void) if (bestMonId != PARTY_SIZE) return bestMonId; - bestMonId = GestBestMonTypeMatchup(party, firstId, lastId, invalidMons, opposingBattler); + bestMonId = GetBestMonTypeMatchup(party, firstId, lastId, invalidMons, opposingBattler); if (bestMonId != PARTY_SIZE) return bestMonId; From c1af41834041817e78eea735d17e09fdcd1246e5 Mon Sep 17 00:00:00 2001 From: sneed Date: Fri, 1 Jul 2022 17:52:46 +0300 Subject: [PATCH 124/130] define B_MSG_WRAPPED_ constants --- include/constants/battle.h | 3 --- include/constants/battle_string_ids.h | 12 ++++++++++++ src/battle_message.c | 18 +++++++++--------- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/include/constants/battle.h b/include/constants/battle.h index bcfb34c45..d651dab18 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -475,7 +475,4 @@ // For the second argument of GetMoveTarget, when no target override is needed #define NO_TARGET_OVERRIDE 0 -// Makes sure gWrappedStringIds and sTrappingMoves have the same size -#define TRAPPING_MOVES_COUNT 9 - #endif // GUARD_CONSTANTS_BATTLE_H diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index 4eff91c85..2017d7085 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -872,4 +872,16 @@ #define B_MSG_TERRAINPREVENTS_ELECTRIC 1 #define B_MSG_TERRAINPREVENTS_PSYCHIC 2 +// gWrappedStringIds +#define B_MSG_WRAPPED_BIND 0 +#define B_MSG_WRAPPED_WRAP 1 +#define B_MSG_WRAPPED_FIRE_SPIN 2 +#define B_MSG_WRAPPED_CLAMP 3 +#define B_MSG_WRAPPED_WHIRLPOOL 4 +#define B_MSG_WRAPPED_SAND_TOMB 5 +#define B_MSG_WRAPPED_MAGMA_STORM 6 +#define B_MSG_WRAPPED_INFESTATION 7 +#define B_MSG_WRAPPED_SNAP_TRAP 8 +#define TRAPPING_MOVES_COUNT 9 + #endif // GUARD_CONSTANTS_BATTLE_STRING_IDS_H diff --git a/src/battle_message.c b/src/battle_message.c index 34d020188..f9e625224 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -1564,15 +1564,15 @@ const u16 gFirstTurnOfTwoStringIds[] = // Index copied from move's index in sTrappingMoves const u16 gWrappedStringIds[TRAPPING_MOVES_COUNT] = { - STRINGID_PKMNSQUEEZEDBYBIND, // MOVE_BIND - STRINGID_PKMNWRAPPEDBY, // MOVE_WRAP - STRINGID_PKMNTRAPPEDINVORTEX, // MOVE_FIRE_SPIN - STRINGID_PKMNCLAMPED, // MOVE_CLAMP - STRINGID_PKMNTRAPPEDINVORTEX, // MOVE_WHIRLPOOL - STRINGID_PKMNTRAPPEDBYSANDTOMB, // MOVE_SAND_TOMB - STRINGID_TRAPPEDBYSWIRLINGMAGMA, // MOVE_MAGMA_STORM - STRINGID_INFESTATION, // MOVE_INFESTATION - STRINGID_PKMNINSNAPTRAP, // MOVE_SNAPTRAP + [B_MSG_WRAPPED_BIND] = STRINGID_PKMNSQUEEZEDBYBIND, // MOVE_BIND + [B_MSG_WRAPPED_WRAP] = STRINGID_PKMNWRAPPEDBY, // MOVE_WRAP + [B_MSG_WRAPPED_FIRE_SPIN] = STRINGID_PKMNTRAPPEDINVORTEX, // MOVE_FIRE_SPIN + [B_MSG_WRAPPED_CLAMP] = STRINGID_PKMNCLAMPED, // MOVE_CLAMP + [B_MSG_WRAPPED_WHIRLPOOL] = STRINGID_PKMNTRAPPEDINVORTEX, // MOVE_WHIRLPOOL + [B_MSG_WRAPPED_SAND_TOMB] = STRINGID_PKMNTRAPPEDBYSANDTOMB, // MOVE_SAND_TOMB + [B_MSG_WRAPPED_MAGMA_STORM] = STRINGID_TRAPPEDBYSWIRLINGMAGMA, // MOVE_MAGMA_STORM + [B_MSG_WRAPPED_INFESTATION] = STRINGID_INFESTATION, // MOVE_INFESTATION + [B_MSG_WRAPPED_SNAP_TRAP] = STRINGID_PKMNINSNAPTRAP, // MOVE_SNAP_TRAP }; const u16 gMistUsedStringIds[] = From fac6f21ed007c09dc09f2174874e690651a09c7d Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Sun, 3 Jul 2022 16:28:34 -0400 Subject: [PATCH 125/130] AI_EFFECTIVENESS_xY are enums --- include/constants/battle_ai.h | 14 +++++++------- src/battle_ai_main.c | 1 + 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/include/constants/battle_ai.h b/include/constants/battle_ai.h index 67f5c11b8..d48827683 100644 --- a/include/constants/battle_ai.h +++ b/include/constants/battle_ai.h @@ -15,13 +15,13 @@ #define AI_TYPE_MOVE 4 // type effectiveness -#define AI_EFFECTIVENESS_x8 320 -#define AI_EFFECTIVENESS_x4 160 -#define AI_EFFECTIVENESS_x2 80 -#define AI_EFFECTIVENESS_x1 40 -#define AI_EFFECTIVENESS_x0_5 20 -#define AI_EFFECTIVENESS_x0_25 10 -#define AI_EFFECTIVENESS_x0_125 5 +#define AI_EFFECTIVENESS_x8 7 +#define AI_EFFECTIVENESS_x4 6 +#define AI_EFFECTIVENESS_x2 5 +#define AI_EFFECTIVENESS_x1 4 +#define AI_EFFECTIVENESS_x0_5 3 +#define AI_EFFECTIVENESS_x0_25 2 +#define AI_EFFECTIVENESS_x0_125 1 #define AI_EFFECTIVENESS_x0 0 // ai weather diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 9840c4827..7350c9b03 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -274,6 +274,7 @@ void GetAiLogicData(void) || !IsBattlerAIControlled(battlerAtk)) { continue; } + for (battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) { if (battlerAtk == battlerDef) From f0edbeb0b037c7493e827a7061cdffa42397c5dd Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Sun, 3 Jul 2022 16:31:00 -0400 Subject: [PATCH 126/130] minor format fix --- src/battle_ai_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 7350c9b03..11b672bca 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -179,7 +179,7 @@ void BattleAI_SetupAIData(u8 defaultScoreMoves) { s32 i, move, dmg; u8 moveLimitations; - + // Clear AI data but preserve the flags. u32 flags = AI_THINKING_STRUCT->aiFlags; memset(AI_THINKING_STRUCT, 0, sizeof(struct AI_ThinkingStruct)); From 57e110aa6a2c2a2702f149c1fb307e598b5fb8cc Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Sun, 3 Jul 2022 17:20:39 -0400 Subject: [PATCH 127/130] fix AI_GetEffectiveness declaration --- src/battle_ai_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index a00b53de3..9b7c4bdbb 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -20,7 +20,7 @@ #include "constants/moves.h" #include "constants/items.h" -static u8 AI_GetEffectiveness(u16 multiplier); +static u32 AI_GetEffectiveness(u16 multiplier); // Const Data static const s8 sAiAbilityRatings[ABILITIES_COUNT] = From 3f739a8f3b0390ad0a11f67451925b9e15663a4e Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Sun, 3 Jul 2022 17:23:59 -0400 Subject: [PATCH 128/130] AI_CalcDamage returns 0 for status moves --- src/battle_ai_util.c | 100 ++++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 45 deletions(-) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 9b7c4bdbb..d04f9d7ee 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -736,53 +736,63 @@ s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef, u8 *typeEffectiveness) SetTypeBeforeUsingMove(move, battlerAtk); GET_MOVE_TYPE(move, moveType); - critChance = GetInverseCritChance(battlerAtk, battlerDef, move); - normalDmg = CalculateMoveDamageAndEffectiveness(move, battlerAtk, battlerDef, moveType, &effectivenessMultiplier); - critDmg = CalculateMoveDamage(move, battlerAtk, battlerDef, moveType, 0, TRUE, FALSE, FALSE); - - if(critChance == -1) - dmg = normalDmg; - else - dmg = (critDmg + normalDmg * (critChance - 1)) / critChance; - - // Handle dynamic move damage - switch (gBattleMoves[move].effect) + if (gBattleMoves[move].power) { - case EFFECT_LEVEL_DAMAGE: - case EFFECT_PSYWAVE: - dmg = gBattleMons[battlerAtk].level * (AI_DATA->abilities[battlerAtk] == ABILITY_PARENTAL_BOND ? 2 : 1); - break; - case EFFECT_DRAGON_RAGE: - dmg = 40 * (AI_DATA->abilities[battlerAtk] == ABILITY_PARENTAL_BOND ? 2 : 1); - break; - case EFFECT_SONICBOOM: - dmg = 20 * (AI_DATA->abilities[battlerAtk] == ABILITY_PARENTAL_BOND ? 2 : 1); - break; - case EFFECT_MULTI_HIT: - dmg *= (AI_DATA->abilities[battlerAtk] == ABILITY_SKILL_LINK ? 5 : 3); - break; - case EFFECT_TRIPLE_KICK: - dmg *= (AI_DATA->abilities[battlerAtk] == ABILITY_SKILL_LINK ? 6 : 5); - break; - case EFFECT_ENDEAVOR: - // If target has less HP than user, Endeavor does no damage - dmg = max(0, gBattleMons[battlerDef].hp - gBattleMons[battlerAtk].hp); - break; - case EFFECT_SUPER_FANG: - dmg = (AI_DATA->abilities[battlerAtk] == ABILITY_PARENTAL_BOND - ? max(2, gBattleMons[battlerDef].hp * 3 / 4) - : max(1, gBattleMons[battlerDef].hp / 2)); - break; - case EFFECT_FINAL_GAMBIT: - dmg = gBattleMons[battlerAtk].hp; - break; - } + critChance = GetInverseCritChance(battlerAtk, battlerDef, move); + normalDmg = CalculateMoveDamageAndEffectiveness(move, battlerAtk, battlerDef, moveType, &effectivenessMultiplier); + critDmg = CalculateMoveDamage(move, battlerAtk, battlerDef, moveType, 0, TRUE, FALSE, FALSE); - // Handle other multi-strike moves - if (gBattleMoves[move].flags & FLAG_TWO_STRIKES) - dmg *= 2; - else if (move == MOVE_SURGING_STRIKES || (move == MOVE_WATER_SHURIKEN && gBattleMons[battlerAtk].species == SPECIES_GRENINJA_ASH)) - dmg *= 3; + if (critChance == -1) + dmg = normalDmg; + else + dmg = (critDmg + normalDmg * (critChance - 1)) / critChance; + + // Handle dynamic move damage + switch (gBattleMoves[move].effect) + { + case EFFECT_LEVEL_DAMAGE: + case EFFECT_PSYWAVE: + dmg = gBattleMons[battlerAtk].level * (AI_DATA->abilities[battlerAtk] == ABILITY_PARENTAL_BOND ? 2 : 1); + break; + case EFFECT_DRAGON_RAGE: + dmg = 40 * (AI_DATA->abilities[battlerAtk] == ABILITY_PARENTAL_BOND ? 2 : 1); + break; + case EFFECT_SONICBOOM: + dmg = 20 * (AI_DATA->abilities[battlerAtk] == ABILITY_PARENTAL_BOND ? 2 : 1); + break; + case EFFECT_MULTI_HIT: + dmg *= (AI_DATA->abilities[battlerAtk] == ABILITY_SKILL_LINK ? 5 : 3); + break; + case EFFECT_TRIPLE_KICK: + dmg *= (AI_DATA->abilities[battlerAtk] == ABILITY_SKILL_LINK ? 6 : 5); + break; + case EFFECT_ENDEAVOR: + // If target has less HP than user, Endeavor does no damage + dmg = max(0, gBattleMons[battlerDef].hp - gBattleMons[battlerAtk].hp); + break; + case EFFECT_SUPER_FANG: + dmg = (AI_DATA->abilities[battlerAtk] == ABILITY_PARENTAL_BOND + ? max(2, gBattleMons[battlerDef].hp * 3 / 4) + : max(1, gBattleMons[battlerDef].hp / 2)); + break; + case EFFECT_FINAL_GAMBIT: + dmg = gBattleMons[battlerAtk].hp; + break; + } + + // Handle other multi-strike moves + if (gBattleMoves[move].flags & FLAG_TWO_STRIKES) + dmg *= 2; + else if (move == MOVE_SURGING_STRIKES || (move == MOVE_WATER_SHURIKEN && gBattleMons[battlerAtk].species == SPECIES_GRENINJA_ASH)) + dmg *= 3; + + if (dmg == 0) + dmg = 1; + } + else + { + dmg = 0; + } RestoreBattlerData(battlerAtk); RestoreBattlerData(battlerDef); From cec7e30ef10d7ba24c34f5c0969363fee2420d00 Mon Sep 17 00:00:00 2001 From: LOuroboros Date: Fri, 15 Jul 2022 01:51:36 -0300 Subject: [PATCH 129/130] Update battle_moves.h --- src/data/battle_moves.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index 2035acff7..2027d797c 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -7850,7 +7850,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = .secondaryEffectChance = 0, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_KINGS_ROCK_AFFECTED, + .flags = FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_KINGS_ROCK_AFFECTED | FLAG_SOUND, .split = SPLIT_SPECIAL, }, From 0651cc9fe46c474e5f65fd88ccc9e9c6e2626672 Mon Sep 17 00:00:00 2001 From: LOuroboros Date: Sat, 16 Jul 2022 05:09:32 -0300 Subject: [PATCH 130/130] Updated Cmd_handleballthrow --- src/battle_script_commands.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 309c6f36b..07e6b8735 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -13586,7 +13586,7 @@ static void Cmd_handleballthrow(void) else catchRate = gBaseStats[gBattleMons[gBattlerTarget].species].catchRate; - #ifdef POKEMON_EXPANSION + #if defined POKEMON_EXPANSION && defined ITEM_EXPANSION if (gBaseStats[gBattleMons[gBattlerTarget].species].flags & FLAG_ULTRA_BEAST) { if (gLastUsedItem == ITEM_BEAST_BALL) @@ -13764,7 +13764,7 @@ static void Cmd_handleballthrow(void) #endif } - #ifdef POKEMON_EXPANSION + #if defined POKEMON_EXPANSION && defined ITEM_EXPANSION } #endif