From 9088c0bdb55da1383af758c214f2c97bcbc42733 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Fri, 27 Jul 2018 23:40:10 +0200 Subject: [PATCH] Introduce battle config; Snow Warning Done. --- data/battle_scripts_1.s | 8 +++++ include/battle_scripts.h | 1 + include/battle_util.h | 1 + include/constants/battle.h | 12 +++++-- include/constants/battle_config.h | 14 ++++++++ src/battle_debug.c | 2 +- src/battle_script_commands.c | 37 ++++++++++---------- src/battle_util.c | 58 +++++++++++++++++++++++++------ 8 files changed, 101 insertions(+), 32 deletions(-) create mode 100644 include/constants/battle_config.h diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 0ae1c4e013..2589811252 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -4609,6 +4609,14 @@ BattleScript_DroughtActivates:: call BattleScript_WeatherFormChanges end3 +BattleScript_SnowWarningActivates:: + pause 0x20 + printstring STRINGID_SNOWWARNINGHAIL + waitstate + playanimation BS_BATTLER_0, B_ANIM_HAIL_CONTINUES, NULL + call BattleScript_WeatherFormChanges + end3 + BattleScript_BadDreamsActivates:: setbyte gBattlerTarget, 0 BattleScript_BadDreamsLoop: diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 5850fca067..e26eb5278f 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -322,5 +322,6 @@ extern const u8 BattleScript_CursedBodyActivates[]; extern const u8 BattleScript_MummyActivates[]; extern const u8 BattleScript_WeakArmorActivates[]; extern const u8 BattleScript_FellStingerRaisesStat[]; +extern const u8 BattleScript_SnowWarningActivates[]; #endif // GUARD_BATTLE_SCRIPTS_H diff --git a/include/battle_util.h b/include/battle_util.h index fa3120c006..e25fbb5425 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -64,6 +64,7 @@ void TryClearRageStatuses(void); u8 AtkCanceller_UnableToUseMove(void); bool8 HasNoMonsToSwitch(u8 battlerId, u8 r1, u8 r2); u8 CastformDataTypeChange(u8 battlerId); +bool32 TryChangeBattleWeather(u8 battler, u32 weatherEnumId, bool32 viaAbility); u8 AbilityBattleEffects(u8 caseID, u8 battlerId, u8 ability, u8 special, u16 moveArg); void BattleScriptExecute(const u8* BS_ptr); void BattleScriptPushCursorAndCallback(const u8* BS_ptr); diff --git a/include/constants/battle.h b/include/constants/battle.h index f1dee674ec..55aeb349f6 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -240,10 +240,18 @@ #define WEATHER_SUN_TEMPORARY (1 << 5) #define WEATHER_SUN_PERMANENT (1 << 6) #define WEATHER_SUN_ANY (WEATHER_SUN_TEMPORARY | WEATHER_SUN_PERMANENT) -#define WEATHER_HAIL (1 << 7) -#define WEATHER_HAIL_ANY (WEATHER_HAIL) +#define WEATHER_HAIL_TEMPORARY (1 << 7) +#define WEATHER_HAIL_PERMANENT (1 << 8) +#define WEATHER_HAIL_ANY (WEATHER_HAIL_TEMPORARY | WEATHER_HAIL_PERMANENT) #define WEATHER_ANY (WEATHER_RAIN_ANY | WEATHER_SANDSTORM_ANY | WEATHER_SUN_ANY | WEATHER_HAIL_ANY) +// Battle Weather as enum +#define ENUM_WEATHER_NONE 0 +#define ENUM_WEATHER_RAIN 1 +#define ENUM_WEATHER_SUN 2 +#define ENUM_WEATHER_SANDSTORM 3 +#define ENUM_WEATHER_HAIL 4 + // Move Effects #define MOVE_EFFECT_SLEEP 0x1 #define MOVE_EFFECT_POISON 0x2 diff --git a/include/constants/battle_config.h b/include/constants/battle_config.h new file mode 100644 index 0000000000..4fab97fd71 --- /dev/null +++ b/include/constants/battle_config.h @@ -0,0 +1,14 @@ +#ifndef GUARD_CONSTANTS_BATTLE_CONFIG_H +#define GUARD_CONSTANTS_BATTLE_CONFIG_H + +#define GEN_3 0 +#define GEN_4 1 +#define GEN_5 2 +#define GEN_6 3 +#define GEN_7 4 + +#define B_CRIT_CHANCE GEN_6 // Chances of a critical hit landing. See atk04_critcalc. +#define B_FELL_STINGER_STAT_RAISE GEN_6 // Gen6 Atk+2, Gen7 Atk+3. +#define B_ABILITY_WEATHER GEN_6 // Up to gen5 - weather induced by abilities such as Drought or Drizzle lasted till the battle's end or weather change by a move. From Gen6 onwards, weather caused by abilities lasts the same amount of turns as induced from a move. + +#endif // GUARD_CONSTANTS_BATTLE_CONFIG_H diff --git a/src/battle_debug.c b/src/battle_debug.c index d625cdd70a..a6aa4c9eb5 100644 --- a/src/battle_debug.c +++ b/src/battle_debug.c @@ -1162,7 +1162,7 @@ static void SetUpModifyArrows(struct BattleDebugMenu *data) { case LIST_ITEM_ABILITY: data->modifyArrows.minValue = 0; - data->modifyArrows.maxValue = ABILITIES_COUNT_GEN5 - 1; + data->modifyArrows.maxValue = ABILITIES_COUNT_GEN6 - 1; data->modifyArrows.maxDigits = 3; data->modifyArrows.modifiedValPtr = &gBattleMons[data->battlerId].ability; data->modifyArrows.typeOfVal = VAL_U8; diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index addaa14060..139ffcd6e2 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -42,6 +42,7 @@ #include "battle_setup.h" #include "overworld.h" #include "party_menu.h" +#include "constants/battle_config.h" extern u16 gBattle_BG1_X; extern u16 gBattle_BG1_Y; @@ -1342,9 +1343,13 @@ s32 CalcCritChanceStage(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recordAbi } // The chance is 1/N for each stage. -static const u8 sCriticalHitChanceGen3[] = {16, 8, 4, 3, 2}; // Gens 2,3,4,5 -static const u8 sCriticalHitChanceGen6[] = {16, 8, 2, 1, 1}; -static const u8 sCriticalHitChanceGen7[] = {24, 8, 2, 1, 1}; +#if B_CRIT_CHANCE == GEN_7 + static const u8 sCriticalHitChance[] = {24, 8, 2, 1, 1}; +#elif B_CRIT_CHANCE == GEN_6 + static const u8 sCriticalHitChance[] = {16, 8, 2, 1, 1}; +#else + static const u8 sCriticalHitChance[] = {16, 8, 4, 3, 2}; // Gens 2,3,4,5 +#endif // B_CRIT_CHANCE static void atk04_critcalc(void) { @@ -1357,7 +1362,7 @@ static void atk04_critcalc(void) gIsCriticalHit = FALSE; else if (critChance == -2) gIsCriticalHit = TRUE; - else if (Random() % sCriticalHitChanceGen3[critChance] == 0) + else if (Random() % sCriticalHitChance[critChance] == 0) gIsCriticalHit = TRUE; else gIsCriticalHit = FALSE; @@ -6390,7 +6395,7 @@ static void atk76_various(void) && HasAttackerFaintedTarget() && !IsBattleLostForPlayer() && !IsBattleWonForPlayer() - && gBattleMons[gBattlerAttacker].statStages[STAT_ATK] != 0xC) + && gBattleMons[gBattlerAttacker].statStages[STAT_ATK] != 12) { gBattleMons[gBattlerAttacker].statStages[STAT_ATK]++; SET_STATCHANGER(STAT_ATK, 1, FALSE); @@ -6405,10 +6410,12 @@ static void atk76_various(void) && HasAttackerFaintedTarget() && !IsBattleLostForPlayer() && !IsBattleWonForPlayer() - && gBattleMons[gBattlerAttacker].statStages[STAT_ATK] != 0xC) + && gBattleMons[gBattlerAttacker].statStages[STAT_ATK] != 12) { - if (gBattleMons[gBattlerAttacker].statStages[STAT_ATK] >= 0xB) + if (gBattleMons[gBattlerAttacker].statStages[STAT_ATK] >= 11) SET_STATCHANGER(STAT_ATK, 1, FALSE); + else if (gBattleMons[gBattlerAttacker].statStages[STAT_ATK] <= 9 && B_FELL_STINGER_STAT_RAISE == GEN_7) + SET_STATCHANGER(STAT_ATK, 3, FALSE); else SET_STATCHANGER(STAT_ATK, 2, FALSE); @@ -6601,16 +6608,14 @@ static void atk7C_trymirrormove(void) static void atk7D_setrain(void) { - if (gBattleWeather & WEATHER_RAIN_ANY) + if (!TryChangeBattleWeather(gBattlerAttacker, ENUM_WEATHER_RAIN, FALSE)) { gMoveResultFlags |= MOVE_RESULT_MISSED; gBattleCommunication[MULTISTRING_CHOOSER] = 2; } else { - gBattleWeather = WEATHER_RAIN_TEMPORARY; gBattleCommunication[MULTISTRING_CHOOSER] = 0; - gWishFutureKnock.weatherDuration = 5; } gBattlescriptCurrInstr++; } @@ -7478,16 +7483,14 @@ static void atk94_damagetohalftargethp(void) // super fang static void atk95_setsandstorm(void) { - if (gBattleWeather & WEATHER_SANDSTORM_ANY) + if (!TryChangeBattleWeather(gBattlerAttacker, ENUM_WEATHER_SANDSTORM, FALSE)) { gMoveResultFlags |= MOVE_RESULT_MISSED; gBattleCommunication[MULTISTRING_CHOOSER] = 2; } else { - gBattleWeather = WEATHER_SANDSTORM_TEMPORARY; gBattleCommunication[MULTISTRING_CHOOSER] = 3; - gWishFutureKnock.weatherDuration = 5; } gBattlescriptCurrInstr++; } @@ -8645,16 +8648,14 @@ static void atkBA_jumpifnopursuitswitchdmg(void) static void atkBB_setsunny(void) { - if (gBattleWeather & WEATHER_SUN_ANY) + if (!TryChangeBattleWeather(gBattlerAttacker, ENUM_WEATHER_SUN, FALSE)) { gMoveResultFlags |= MOVE_RESULT_MISSED; gBattleCommunication[MULTISTRING_CHOOSER] = 2; } else { - gBattleWeather = WEATHER_SUN_TEMPORARY; gBattleCommunication[MULTISTRING_CHOOSER] = 4; - gWishFutureKnock.weatherDuration = 5; } gBattlescriptCurrInstr++; @@ -8911,16 +8912,14 @@ static void atkC7_setminimize(void) static void atkC8_sethail(void) { - if (gBattleWeather & WEATHER_HAIL_ANY) + if (!TryChangeBattleWeather(gBattlerAttacker, ENUM_WEATHER_HAIL, FALSE)) { gMoveResultFlags |= MOVE_RESULT_MISSED; gBattleCommunication[MULTISTRING_CHOOSER] = 2; } else { - gBattleWeather = WEATHER_HAIL; gBattleCommunication[MULTISTRING_CHOOSER] = 5; - gWishFutureKnock.weatherDuration = 5; } gBattlescriptCurrInstr++; diff --git a/src/battle_util.c b/src/battle_util.c index c4dacd71d1..fd4f6028c1 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -24,6 +24,7 @@ #include "link.h" #include "berry.h" #include "pokedex.h" +#include "constants/battle_config.h" extern u8 weather_get_current(void); @@ -1070,9 +1071,9 @@ u8 DoFieldEndTurnEffects(void) case ENDTURN_HAIL: if (gBattleWeather & WEATHER_HAIL_ANY) { - if (--gWishFutureKnock.weatherDuration == 0) + if (!(gBattleWeather & WEATHER_HAIL_PERMANENT) && --gWishFutureKnock.weatherDuration == 0) { - gBattleWeather &= ~WEATHER_HAIL; + gBattleWeather &= ~WEATHER_HAIL_TEMPORARY; gBattlescriptCurrInstr = BattleScript_SandStormHailEnds; } else @@ -2311,7 +2312,39 @@ u8 CastformDataTypeChange(u8 battler) return formChange; } -// The largest function in the game, but even it could not save itself from decompiling. +static const u16 sWeatherFlagsInfo[][3] = +{ + [ENUM_WEATHER_RAIN] = {WEATHER_RAIN_TEMPORARY, WEATHER_RAIN_PERMANENT, HOLD_EFFECT_DAMP_ROCK}, + [ENUM_WEATHER_SUN] = {WEATHER_SUN_TEMPORARY, WEATHER_SUN_PERMANENT, HOLD_EFFECT_HEAT_ROCK}, + [ENUM_WEATHER_SANDSTORM] = {WEATHER_SANDSTORM_TEMPORARY, WEATHER_SANDSTORM_PERMANENT, HOLD_EFFECT_SMOOTH_ROCK}, + [ENUM_WEATHER_HAIL] = {WEATHER_HAIL_TEMPORARY, WEATHER_HAIL_PERMANENT, HOLD_EFFECT_ICY_ROCK}, +}; + +bool32 TryChangeBattleWeather(u8 battler, u32 weatherEnumId, bool32 viaAbility) +{ + if (viaAbility && B_ABILITY_WEATHER <= GEN_5 + && !(gBattleWeather & sWeatherFlagsInfo[weatherEnumId][1])) + { + gBattleWeather = (sWeatherFlagsInfo[weatherEnumId][0] | sWeatherFlagsInfo[weatherEnumId][1]); + return TRUE; + } + else if (B_ABILITY_WEATHER > GEN_5 + && !(gBattleWeather & (sWeatherFlagsInfo[weatherEnumId][0] | sWeatherFlagsInfo[weatherEnumId][1]))) + { + gBattleWeather = (sWeatherFlagsInfo[weatherEnumId][0]); + if (GetBattlerHoldEffect(battler, TRUE) == sWeatherFlagsInfo[weatherEnumId][2]) + gWishFutureKnock.weatherDuration = 8; + else + gWishFutureKnock.weatherDuration = 5; + + return TRUE; + } + else + { + return FALSE; + } +} + u8 AbilityBattleEffects(u8 caseID, u8 battler, u8 ability, u8 special, u16 moveArg) { u8 effect = 0; @@ -2477,32 +2510,37 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u8 ability, u8 special, u16 moveA } break; case ABILITY_DRIZZLE: - if (!(gBattleWeather & WEATHER_RAIN_PERMANENT)) + if (TryChangeBattleWeather(battler, ENUM_WEATHER_RAIN, TRUE)) { - gBattleWeather = (WEATHER_RAIN_PERMANENT | WEATHER_RAIN_TEMPORARY); BattleScriptPushCursorAndCallback(BattleScript_DrizzleActivates); gBattleScripting.battler = battler; effect++; } break; case ABILITY_SAND_STREAM: - if (!(gBattleWeather & WEATHER_SANDSTORM_PERMANENT)) + if (TryChangeBattleWeather(battler, ENUM_WEATHER_SANDSTORM, TRUE)) { - gBattleWeather = (WEATHER_SANDSTORM_PERMANENT | WEATHER_SANDSTORM_TEMPORARY); - BattleScriptPushCursorAndCallback(BattleScript_SandstreamActivates); + BattleScriptPushCursorAndCallback(BattleScript_DrizzleActivates); gBattleScripting.battler = battler; effect++; } break; case ABILITY_DROUGHT: - if (!(gBattleWeather & WEATHER_SUN_PERMANENT)) + if (TryChangeBattleWeather(battler, ENUM_WEATHER_SUN, TRUE)) { - gBattleWeather = (WEATHER_SUN_PERMANENT | WEATHER_SUN_TEMPORARY); BattleScriptPushCursorAndCallback(BattleScript_DroughtActivates); gBattleScripting.battler = battler; effect++; } break; + case ABILITY_SNOW_WARNING: + if (TryChangeBattleWeather(battler, ENUM_WEATHER_HAIL, TRUE)) + { + BattleScriptPushCursorAndCallback(BattleScript_SnowWarningActivates); + gBattleScripting.battler = battler; + effect++; + } + break; case ABILITY_INTIMIDATE: if (!(gSpecialStatuses[battler].intimidatedMon)) {