final mechanical changes

This commit is contained in:
Prof-Holon
2026-04-12 13:41:42 +01:00
parent 601247df5f
commit 16ca832d90
9 changed files with 258 additions and 58 deletions

View File

@@ -452,6 +452,7 @@ BattleScript_DreamEaterWorked:
waitmessage B_WAIT_TIME_LONG
resultmessage
waitmessage B_WAIT_TIME_LONG
jumpifability BS_TARGET, ABILITY_LIQUID_OOZE, BattleScript_AbsorbLiquidOoze
negativedamage
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE
healthbarupdate BS_ATTACKER
@@ -3992,6 +3993,8 @@ BattleScript_IntimidateActivationAnimLoop::
jumpifability BS_TARGET, ABILITY_CLEAR_BODY, BattleScript_IntimidateAbilityFail
jumpifability BS_TARGET, ABILITY_HYPER_CUTTER, BattleScript_IntimidateAbilityFail
jumpifability BS_TARGET, ABILITY_WHITE_SMOKE, BattleScript_IntimidateAbilityFail
jumpifability BS_TARGET, ABILITY_OBLIVIOUS, BattleScript_IntimidateAbilityFail
jumpifability BS_TARGET, ABILITY_INNER_FOCUS, BattleScript_IntimidateAbilityFail
statbuffchange STAT_CHANGE_ALLOW_PTR | STAT_CHANGE_NOT_PROTECT_AFFECTED, BattleScript_IntimidateFail
jumpifbyte CMP_GREATER_THAN, cMULTISTRING_CHOOSER, 1, BattleScript_IntimidateFail
setgraphicalstatchangevalues
@@ -4037,9 +4040,9 @@ BattleScript_TookAttack::
BattleScript_SturdyPreventsOHKO::
pause B_WAIT_TIME_SHORT
printstring STRINGID_PKMNPROTECTEDBY
pause B_WAIT_TIME_LONG
goto BattleScript_MoveEnd
printstring STRINGID_STURDY
pause B_WAIT_TIME_SHORT
return
BattleScript_DampStopsExplosion::
pause B_WAIT_TIME_SHORT
@@ -4402,3 +4405,10 @@ BattleScript_DampCuresStatus::
updatestatusicon BS_ATTACKER
end3
BattleScript_TruantHeal::
printstring STRINGID_TRUANTRESTOREDHP
waitmessage B_WAIT_TIME_LONG
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE
healthbarupdate BS_ATTACKER
datahpupdate BS_ATTACKER
end3

View File

@@ -450,6 +450,7 @@ struct BattleStruct
u8 wishPerishSongState;
u8 wishPerishSongBattlerId;
u8 lastAttackerToFaintOpponent;
u8 pickupUsed[MAX_BATTLERS_COUNT];
// align 4
union {
struct LinkBattlerHeader linkBattlerHeader;

View File

@@ -392,12 +392,20 @@
//add boosting abilities tooltip
#define STRINGID_OVERGROWBOOSTED 389
#define STRINGID_BLAZINGBOOSTED 390
#define STRINGID_BLAZEBOOSTED 390
#define STRINGID_TORRENTBOOSTED 391
#define STRINGID_SWARMBOOSTED 392
#define STRINGID_EARLYBIRDBOOSTED 393
#define STRINGID_ILLUMINATEBOOSTED 394
#define BATTLESTRINGS_COUNT 394
//add sturdy
#define STRINGID_STURDY 395
//add truant
#define STRINGID_TRUANTRESTOREDHP 396
#define BATTLESTRINGS_COUNT 397
// This is the string id that gBattleStringsTable starts with.
// String ids before this (e.g. STRINGID_INTROMSG) are not in the table,

View File

@@ -3197,16 +3197,18 @@ static void HandleTurnActionSelectionState(void)
break;
case B_ACTION_SWITCH:
*(gBattleStruct->battlerPartyIndexes + gActiveBattler) = gBattlerPartyIndexes[gActiveBattler];
if (gBattleMons[gActiveBattler].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION) || gStatuses3[gActiveBattler] & STATUS3_ROOTED)
if (gBattleMons[gActiveBattler].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION) || gStatuses3[gActiveBattler] & STATUS3_ROOTED
&& gBattleMons[gActiveBattler].ability != ABILITY_RUN_AWAY)) //added
{
BtlController_EmitChoosePokemon(BUFFER_A, PARTY_ACTION_CANT_SWITCH, 6, ABILITY_NONE, gBattleStruct->battlerPartyOrders[gActiveBattler]);
}
else if ((i = ABILITY_ON_OPPOSING_FIELD(gActiveBattler, ABILITY_SHADOW_TAG))
|| ((i = ABILITY_ON_OPPOSING_FIELD(gActiveBattler, ABILITY_ARENA_TRAP))
else if (gBattleMons[gActiveBattler].ability != ABILITY_RUN_AWAY // ADD
&& ((i = ABILITY_ON_OPPOSING_FIELD(gActiveBattler, ABILITY_SHADOW_TAG))
|| ((i = ABILITY_ON_OPPOSING_FIELD(gActiveBattler, ABILITY_ARENA_TRAP))
&& !IS_BATTLER_OF_TYPE(gActiveBattler, TYPE_FLYING)
&& gBattleMons[gActiveBattler].ability != ABILITY_LEVITATE)
|| ((i = AbilityBattleEffects(ABILITYEFFECT_CHECK_FIELD_EXCEPT_BATTLER, gActiveBattler, ABILITY_MAGNET_PULL, 0, 0))
&& IS_BATTLER_OF_TYPE(gActiveBattler, TYPE_STEEL)))
|| ((i = AbilityBattleEffects(ABILITYEFFECT_CHECK_FIELD_EXCEPT_BATTLER, gActiveBattler, ABILITY_MAGNET_PULL, 0, 0))
&& IS_BATTLER_OF_TYPE(gActiveBattler, TYPE_ELECTRIC || TYPE_ROCK)))
{
BtlController_EmitChoosePokemon(BUFFER_A, ((i - 1) << 4) | PARTY_ACTION_ABILITY_PREVENTS, 6, gLastUsedAbility, gBattleStruct->battlerPartyOrders[gActiveBattler]);
}
@@ -3427,6 +3429,22 @@ u8 GetWhoStrikesFirst(u8 battler1, u8 battler2, bool8 ignoreChosenMoves)
speedMultiplierBattler1 = (gBattleMons[battler1].ability == ABILITY_AIR_LOCK) ? 2 : 1;
speedMultiplierBattler2 = (gBattleMons[battler2].ability == ABILITY_AIR_LOCK) ? 2 : 1;
}
// add vital spirit speed boost for both battlers
if ((gBattleMons[battler1].ability == ABILITY_VITAL_SPIRIT && battler1->status1)
speedMultiplierBattler1 = 2;
if ((gBattleMons[battler2].ability == ABILITY_VITAL_SPIRIT && battler2->status1)
speedMultiplierBattler2 = 2;
// add speed doubling if Minus/Plus ally
if ((gBattleMons[battler1].ability == ABILITY_PLUS && ABILITY_ON_FIELD2(ABILITY_MINUS))
speedMultiplierBattler1 = 2;
if ((gBattleMons[battler2].ability == ABILITY_PLUS && ABILITY_ON_FIELD2(ABILITY_MINUS))
speedMultiplierBattler2 = 2;
if ((gBattleMons[battler1].ability == ABILITY_MINUS && ABILITY_ON_FIELD2(ABILITY_PLUS))
speedMultiplierBattler1 = 2;
if ((gBattleMons[battler2].ability == ABILITY_MINUS && ABILITY_ON_FIELD2(ABILITY_PLUS))
speedMultiplierBattler2 = 2;
else
{
speedMultiplierBattler1 = 1;
@@ -4331,7 +4349,8 @@ static void HandleAction_Run(void)
}
else
{
if (gBattleMons[gBattlerAttacker].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION))
if (gBattleMons[gBattlerAttacker].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION)
&& gBattleMons[gBattlerAttacker].ability != ABILITY_RUN_AWAY)) //added
{
gBattleCommunication[MULTISTRING_CHOOSER] = 4;
gBattlescriptCurrInstr = BattleScript_PrintFailedToRunString;

View File

@@ -428,20 +428,25 @@ static const u8 sText_ExclamationMark3[] = _("!");
static const u8 sText_ExclamationMark4[] = _("!");
static const u8 sText_ExclamationMark5[] = _("!");
static const u8 sText_Overgrow_Boosted[] = _("{B_ATK_NAME_WITH_PREFIX}'s Overgrow\nboosted its Grass moves!");
static const u8 sText_Blaze_Boosted[] = _("{B_ATK_NAME_WITH_PREFIX}'s Blaze\nboosted its Fire moves!");
static const u8 sText_Torrent_Boosted[] = _("{B_ATK_NAME_WITH_PREFIX}'s Torrent\nboosted its Water moves!");
static const u8 sText_Swarm_Boosted[] = _("{B_ATK_NAME_WITH_PREFIX}'s Swarm\nboosted its Bug moves!");
static const u8 sText_Early_Bird_Boosted[] = _("{B_ATK_NAME_WITH_PREFIX}'s Early Bird\nboosted its Flying moves!");
static const u8 sText_OvergrowBoosted[] = _("{B_ATK_NAME_WITH_PREFIX}'s Overgrow\nboosted its Grass moves!");
static const u8 sText_BlazeBoosted[] = _("{B_ATK_NAME_WITH_PREFIX}'s Blaze\nboosted its Fire moves!");
static const u8 sText_TorrentBoosted[] = _("{B_ATK_NAME_WITH_PREFIX}'s Torrent\nboosted its Water moves!");
static const u8 sText_SwarmBoosted[] = _("{B_ATK_NAME_WITH_PREFIX}'s Swarm\nboosted its Bug moves!");
static const u8 sText_EarlyBirdBoosted[] = _("{B_ATK_NAME_WITH_PREFIX}'s Early Bird\nboosted its Flying moves!");
static const u8 sText_IlluminateBoosted[] = _("{B_ATK_NAME_WITH_PREFIX}'s Illuminate\nboosted its Electric moves!");
const u16 gLowHpAbilityBoostStringIds[] = {
STRINGID_OVERGROWBOOSTED, // 0
STRINGID_BLAZEBOOSTED, // 1
STRINGID_TORRENTBOOSTED, // 2
STRINGID_SWARMBOOSTED, // 3
STRINGID_EARLYBIRDBOOSTED, // 4
STRINGID_EARLYBIRDBOOSTED, // 4
STRINGID_ILLUMINATEBOOSTED, // 5
};
static const u8 sText_Sturdy[] = _("{B_ATK_NAME_WITH_PREFIX}'s Sturdy\nallowed it to endure the hit!");
static const u8 sText_Truant[] = _("{B_ATK_NAME_WITH_PREFIX} is loafing around and recovered HP!");
static const u8 sText_HP2[] = _("HP");
static const u8 sText_Attack2[] = _("ATTACK");
static const u8 sText_Defense2[] = _("DEFENSE");
@@ -906,7 +911,15 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT - BATTLESTRINGS_TABLE_ST
[STRINGID_TRAINER1MON1COMEBACK - BATTLESTRINGS_TABLE_START] = sText_Trainer1RecallPkmn1,
[STRINGID_TRAINER1WINTEXT - BATTLESTRINGS_TABLE_START] = sText_Trainer1WinText,
[STRINGID_TRAINER1MON2COMEBACK - BATTLESTRINGS_TABLE_START] = sText_Trainer1RecallPkmn2,
[STRINGID_TRAINER1MON1AND2COMEBACK - BATTLESTRINGS_TABLE_START] = sText_Trainer1RecallBoth
[STRINGID_TRAINER1MON1AND2COMEBACK - BATTLESTRINGS_TABLE_START] = sText_Trainer1RecallBoth,
[STRINGID_STURDY - BATTLESTRINGS_TABLE_START] = sText_Sturdy,
[STRINGID_TRUANTRESTOREDHP - BATTLESTRINGS_TABLE_START] = sText_Truant,
[STRINGID_OVERGROWBOOSTED - BATTLESTRINGS_TABLE_START] = sText_OvergrowBoosted,
[STRINGID_BLAZEBOOSTED - BATTLESTRINGS_TABLE_START] = sText_BlazeBoosted,
[STRINGID_TORRENTBOOSTED- BATTLESTRINGS_TABLE_START] = sText_TorrentBoosted,
[STRINGID_SWARMBOOSTED - BATTLESTRINGS_TABLE_START] = sText_SwarmBoosted,,
[STRINGID_EARLYBIRDBOOSTED - BATTLESTRINGS_TABLE_START] = sText_EarlyBirdBoosted,
[STRINGID_ILLUMINATEBOOSTED - BATTLESTRINGS_TABLE_START] = sText_IlluminateBoosted
};
const u16 gMissStringIds[] =

View File

@@ -1064,7 +1064,17 @@ static void Cmd_accuracycheck(void)
else
{
u8 acc = gBattleMons[gBattlerAttacker].statStages[STAT_ACC];
buff = acc + DEFAULT_STAT_STAGE - gBattleMons[gBattlerTarget].statStages[STAT_EVASION];
if (gBattleMons[gBattlerAttacker].ability == ABILITY_KEEN_EYE)
{
u8 targetEvasion = gBattleMons[gBattlerTarget].statStages[STAT_EVASION];
if (targetEvasion > DEFAULT_STAT_STAGE)
targetEvasion = DEFAULT_STAT_STAGE; // cap at neutral, drops still apply
buff = acc + DEFAULT_STAT_STAGE - targetEvasion;
}
else
{
buff = acc + DEFAULT_STAT_STAGE - gBattleMons[gBattlerTarget].statStages[STAT_EVASION];
}
}
if (buff < MIN_STAT_STAGE)
@@ -1102,7 +1112,7 @@ static void Cmd_accuracycheck(void)
gPotentialItemEffectBattler = gBattlerTarget;
if (holdEffect == HOLD_EFFECT_EVASION_UP)
if (holdEffect == HOLD_EFFECT_EVASION_UP && gBattleMons[gBattlerAttacker].ability != ABILITY_KEEN_EYE)
calc = (calc * (100 - param)) / 100;
// final calculation
@@ -1212,6 +1222,15 @@ static void Cmd_critcalc(void)
+ 2 * (holdEffect == HOLD_EFFECT_LUCKY_PUNCH && gBattleMons[gBattlerAttacker].species == SPECIES_CHANSEY)
+ 2 * (holdEffect == HOLD_EFFECT_STICK && gBattleMons[gBattlerAttacker].species == SPECIES_FARFETCHD);
// ADD: high crit moves guarantee at least stage 4
if ((gBattleMoves[gCurrentMove].effect == EFFECT_HIGH_CRITICAL
|| gBattleMoves[gCurrentMove].effect == EFFECT_SKY_ATTACK
|| gBattleMoves[gCurrentMove].effect == EFFECT_BLAZE_KICK
|| gBattleMoves[gCurrentMove].effect == EFFECT_POISON_TAIL)
&& critChance < ARRAY_COUNT(sCriticalHitChance) - 1)
critChance = ARRAY_COUNT(sCriticalHitChance) - 1;
// END ADD
if (critChance >= ARRAY_COUNT(sCriticalHitChance))
critChance = ARRAY_COUNT(sCriticalHitChance) - 1;
@@ -1222,9 +1241,9 @@ static void Cmd_critcalc(void)
gen1Denominator = gen3Denominator;
else
{
gen1Denominator = (68 * sCriticalHitChance[critChance]) / baseSpeed; // allows it to also scale based on crit stage, anything higher than 80 is better
if (gen1Denominator < 2)
gen1Denominator = 2;
gen1Denominator = (sCriticalHitChance[critChance] * 680) / (13 * baseSpeed); // (1/stage) * (1.3 * speed / 68) inverted
if (gen1Denominator < 1) // ADD: floor at 1 — effectively guaranteed crit
gen1Denominator = 1;
}
effectiveDenominator = (gen1Denominator < gen3Denominator) ? gen1Denominator : gen3Denominator;
// END ADD
@@ -1232,7 +1251,7 @@ static void Cmd_critcalc(void)
if ((gBattleMons[gBattlerTarget].ability != ABILITY_BATTLE_ARMOR && gBattleMons[gBattlerTarget].ability != ABILITY_SHELL_ARMOR)
&& !(gStatuses3[gBattlerAttacker] & STATUS3_CANT_SCORE_A_CRIT)
&& !(gBattleTypeFlags & BATTLE_TYPE_OLD_MAN_TUTORIAL)
&& !(Random() % effectiveDenominator)
&& ((Random() & 0xFF) < (256 / effectiveDenominator))
&& (!(gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE) || BtlCtrl_OakOldMan_TestState2Flag(1))
&& !(gBattleTypeFlags & BATTLE_TYPE_POKEDUDE))
gCritMultiplier = 2;
@@ -1336,6 +1355,24 @@ static void Cmd_typecalc(void)
gBattleCommunication[MISS_TYPE] = B_MSG_GROUND_MISS;
RecordAbilityBattle(gBattlerTarget, gLastUsedAbility);
}
else if (gBattleMons[gBattlerTarget].ability == ABILITY_IMMUNITY && moveType == TYPE_POISON)
{
gLastUsedAbility = gBattleMons[gBattlerTarget].ability;
gMoveResultFlags |= (MOVE_RESULT_MISSED | MOVE_RESULT_DOESNT_AFFECT_FOE);
gLastLandedMoves[gBattlerTarget] = 0;
gLastHitByType[gBattlerTarget] = 0;
gBattleCommunication[MISS_TYPE] = B_MSG_GROUND_MISS;
RecordAbilityBattle(gBattlerTarget, gLastUsedAbility);
}
else if (gBattleMons[gBattlerTarget].ability == ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC)
{
gLastUsedAbility = gBattleMons[gBattlerTarget].ability;
gMoveResultFlags |= (MOVE_RESULT_MISSED | MOVE_RESULT_DOESNT_AFFECT_FOE);
gLastLandedMoves[gBattlerTarget] = 0;
gLastHitByType[gBattlerTarget] = 0;
gBattleCommunication[MISS_TYPE] = B_MSG_GROUND_MISS;
RecordAbilityBattle(gBattlerTarget, gLastUsedAbility);
}
else
{
while (TYPE_EFFECT_ATK_TYPE(i) != TYPE_ENDTABLE)
@@ -2525,7 +2562,10 @@ void SetMoveEffect(bool8 primary, u8 certain)
}
else
{
gBattleMons[gEffectBattler].status2 |= STATUS2_WRAPPED_TURN((Random() & 2) + 3); // 2-5 turns
if (gBattleMons[gEffectBattler].ability == ABILITY_SUCTION_CUPS)
gBattleMons[gEffectBattler].status2 |= STATUS2_WRAPPED_TURN((Random() & 1) + 4); // 4-5 turns
else
gBattleMons[gEffectBattler].status2 |= STATUS2_WRAPPED_TURN((Random() & 3) + 2); // 2-5 turns
*(gBattleStruct->wrappedMove + gEffectBattler * 2 + 0) = gCurrentMove;
*(gBattleStruct->wrappedMove + gEffectBattler * 2 + 1) = gCurrentMove >> 8;
@@ -4313,6 +4353,21 @@ static void Cmd_moveend(void)
gBattleScripting.moveendState++;
break;
case MOVEEND_UPDATE_LAST_MOVES:
// ADD: cancel wrap and attacker lock-in if trapping move missed
if (gMoveResultFlags & MOVE_RESULT_MISSED)
{
for (i = 0; i < gBattlersCount; i++)
{
if ((gBattleMons[i].status2 & STATUS2_WRAPPED)
&& *(gBattleStruct->wrappedBy + i) == gBattlerAttacker)
{
gBattleMons[i].status2 &= ~STATUS2_WRAPPED;
CancelMultiTurnMoves(gBattlerAttacker);
break;
}
}
}
// END ADD
if (gHitMarker & HITMARKER_SWAP_ATTACKER_TARGET)
{
gActiveBattler = gBattlerAttacker;
@@ -5729,6 +5784,15 @@ static void Cmd_removeitem(void)
*usedHeldItem = gBattleMons[gActiveBattler].item;
gBattleMons[gActiveBattler].item = ITEM_NONE;
// Pickup effect: restore consumed item once per battle
if (gBattleMons[gActiveBattler].ability == ABILITY_PICKUP
&& !gBattleStruct->pickupUsed[gActiveBattler]
&& *usedHeldItem != ITEM_NONE)
{
gBattleMons[gActiveBattler].item = *usedHeldItem;
gBattleStruct->pickupUsed[gActiveBattler] = TRUE;
}
BtlController_EmitSetMonData(BUFFER_A, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[gActiveBattler].item), &gBattleMons[gActiveBattler].item);
MarkBattlerForControllerExec(gActiveBattler);
@@ -7203,9 +7267,12 @@ static void Cmd_tryKO(void)
gSpecialStatuses[gBattlerTarget].focusBanded = 1;
}
if (gBattleMons[gBattlerTarget].ability == ABILITY_STURDY)
if (gBattleMons[gBattlerTarget].ability == ABILITY_STURDY
&& gBattleMons[gBattlerTarget].hp == gBattleMons[gBattlerTarget].maxHP
&& gBattleMoveDamage >= gBattleMons[gBattlerTarget].hp
&& !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT))
{
gMoveResultFlags |= MOVE_RESULT_MISSED;
gBattleMoveDamage = gBattleMons[gBattlerTarget].hp - 1;
gLastUsedAbility = ABILITY_STURDY;
gBattlescriptCurrInstr = BattleScript_SturdyPreventsOHKO;
RecordAbilityBattle(gBattlerTarget, ABILITY_STURDY);

View File

@@ -817,7 +817,7 @@ u8 DoBattlerEndTurnEffects(void)
}
else
{
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 8;
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 16;
}
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
@@ -1309,7 +1309,7 @@ u8 AtkCanceller_UnableToUseMove(void)
else
{
u8 toSub;
if (gBattleMons[gBattlerAttacker].ability == ABILITY_EARLY_BIRD)
if (gBattleMons[gBattlerAttacker].ability == ABILITY_LIMBER) // changed old Early Bird effect to Limber
toSub = 2;
else
toSub = 1;
@@ -1373,6 +1373,16 @@ u8 AtkCanceller_UnableToUseMove(void)
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_LOAFING;
gBattlescriptCurrInstr = BattleScript_MoveUsedLoafingAround;
gMoveResultFlags |= MOVE_RESULT_MISSED;
// ADD: heal 1/16 max HP on loafing turns
if (gBattleMons[gBattlerAttacker].maxHP > gBattleMons[gBattlerAttacker].hp)
{
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 16;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
gBattleMoveDamage *= -1;
gBattleScripting.battler = gBattlerAttacker;
BattleScriptPushCursorAndCallback(BattleScript_TruantHeal);
}
effect = 1;
}
gBattleStruct->atkCancellerTracker++;
@@ -1902,6 +1912,19 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u8 ability, u8 special, u16 moveA
effect++;
}
break;
case ABILITY_TRUANT:
if ((gBattleMons[battler].status1 & STATUS1_SLEEP)
&& gBattleMons[battler].maxHP > gBattleMons[battler].hp)
{
gBattleMoveDamage = gBattleMons[battler].maxHP / 16;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
gBattleMoveDamage *= -1;
gBattleScripting.battler = gActiveBattler = battler;
BattleScriptPushCursorAndCallback(BattleScript_TruantHeal);
effect++;
}
break;
case ABILITY_SHED_SKIN:
if ((gBattleMons[battler].status1 & STATUS1_ANY) && (Random() % 3) == 0)
{
@@ -1982,24 +2005,8 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u8 ability, u8 special, u16 moveA
effect = 1;
}
}
// ADD: Inner Focus blocks priority moves
else if (gLastUsedAbility == ABILITY_INNER_FOCUS)
{
for (i = 0; sPrioMoves[i] != PRIO_MOVES_END; i++)
{
if (sPrioMoves[i] == move)
break;
}
if (sPrioMoves[i] != PRIO_MOVES_END)
{
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)
gHitMarker |= HITMARKER_NO_PPDEDUCT;
gBattlescriptCurrInstr = BattleScript_SoundproofProtected;
effect = 1;
}
}
// ADD: Oblivious blocks taunt/redirect moves
else if (gLastUsedAbility == ABILITY_OBLIVIOUS)
// ADD: Oblivious and Inner Focus blocks taunt/redirect moves
else if (gLastUsedAbility == ABILITY_OBLIVIOUS || gLastUsedAbility == ABILITY_INNER_FOCUS)
{
for (i = 0; sTauntMoves[i] != TAUNT_MOVES_END; i++)
{
@@ -2068,7 +2075,19 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u8 ability, u8 special, u16 moveA
}
}
break;
case ABILITY_LIGHTNING_ROD:
if (moveType == TYPE_ELECTRIC)
{
gLastUsedAbility = ABILITY_LIGHTNING_ROD;
RecordAbilityBattle(battler, ABILITY_LIGHTNING_ROD);
// Apply permanent Charge boost until switch
gStatuses3[battler] |= STATUS3_CHARGED_UP;
gBattlescriptCurrInstr = BattleScript_MoveHPDrain; // reuse generic ability popup
effect = 2; // cancels the hit (immunity)
}
break;
}
if (effect == 1)
{
@@ -2239,7 +2258,6 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u8 ability, u8 special, u16 moveA
}
break;
case ABILITY_INSOMNIA:
case ABILITY_VITAL_SPIRIT:
if (gBattleMons[battler].status1 & STATUS1_SLEEP)
{
gBattleMons[battler].status2 &= ~STATUS2_NIGHTMARE;

View File

@@ -3365,7 +3365,7 @@ const struct SpeciesInfo gSpeciesInfo[] =
.friendship = 70,
.growthRate = GROWTH_MEDIUM_FAST,
.eggGroups = {EGG_GROUP_MONSTER, EGG_GROUP_MONSTER},
.abilities = {ABILITY_INSOMNIA, ABILITY_NONE},
.abilities = {ABILITY_INSOMNIA, ABILITY_PICKUP},
.safariZoneFleeRate = 125,
.bodyColor = BODY_COLOR_BROWN,
.noFlip = FALSE,
@@ -3713,7 +3713,7 @@ const struct SpeciesInfo gSpeciesInfo[] =
.friendship = 70,
.growthRate = GROWTH_SLOW,
.eggGroups = {EGG_GROUP_BUG, EGG_GROUP_BUG},
.abilities = {ABILITY_HYPER_CUTTER, ABILITY_NONE},
.abilities = {ABILITY_HYPER_CUTTER, ABILITY_GUTS},
.safariZoneFleeRate = 125,
.bodyColor = BODY_COLOR_BROWN,
.noFlip = FALSE,
@@ -5308,7 +5308,7 @@ const struct SpeciesInfo gSpeciesInfo[] =
.friendship = 70,
.growthRate = GROWTH_MEDIUM_SLOW,
.eggGroups = {EGG_GROUP_GRASS, EGG_GROUP_GRASS},
.abilities = {ABILITY_CHLOROPHYLL, ABILITY_NONE},
.abilities = {ABILITY_CHLOROPHYLL, ABILITY_FLASH_FIRE},
.safariZoneFleeRate = 0,
.bodyColor = BODY_COLOR_GREEN,
.noFlip = FALSE,

View File

@@ -2412,6 +2412,36 @@ static bool8 IsMoveInList(u16 move, const u16 *list)
return FALSE;
}
bool32 HasOtherElectricType(u8 battler)
{
u8 i;
for (i = 0; i < gBattlersCount; i++)
{
if (i != battler
&& gBattleMons[i].hp != 0
&& (gBattleMons[i].type1 == TYPE_ELECTRIC || gBattleMons[i].type2 == TYPE_ELECTRIC))
return TRUE;
}
return FALSE;
}
bool32 HasOtherRockType(u8 battler)
{
u8 i;
for (i = 0; i < gBattlersCount; i++)
{
if (i != battler
&& gBattleMons[i].hp != 0
&& (gBattleMons[i].type1 == TYPE_ROCK || gBattleMons[i].type2 == TYPE_ROCK))
return TRUE;
}
return FALSE;
}
s32 CalculateBaseDamage(struct BattlePokemon *attacker, struct BattlePokemon *defender, u32 move, u16 sideStatus, u16 powerOverride, u8 typeOverride, u8 battlerIdAtk, u8 battlerIdDef)
{
u32 i;
@@ -2509,14 +2539,21 @@ s32 CalculateBaseDamage(struct BattlePokemon *attacker, struct BattlePokemon *de
defense *= 2;
if (attackerHoldEffect == HOLD_EFFECT_THICK_CLUB && (attacker->species == SPECIES_CUBONE || attacker->species == SPECIES_MAROWAK))
attack *= 2;
// Apply effects of abilities
if (defender->ability == ABILITY_THICK_FAT && (type == TYPE_FIRE || type == TYPE_ICE))
spAttack /= 2;
if (defender->ability == ABILITY_MAGMA_ARMOR && (type == TYPE_FIRE || type == TYPE_GROUND))
gBattleMovePower = (50 * gBattleMovePower) / 100;
if (attacker->ability == ABILITY_HUSTLE)
&& (gBattleMoves[move].flags & FLAG_MAKES_CONTACT)) // boost only for contact moves
gBattleMovePower = (150 * gBattleMovePower) / 100; // alternatively boost both attack and SpAttack but this is neater
if (attacker->ability == ABILITY_PLUS && ABILITY_ON_FIELD2(ABILITY_MINUS))
if (attacker->ability == ABILITY_PLUS && HasOtherRockType(gBattlerAttacker))
spAttack = (150 * spAttack) / 100;
if (attacker->ability == ABILITY_MINUS && ABILITY_ON_FIELD2(ABILITY_PLUS))
if (attacker->ability == ABILITY_MINUS && HasOtherElectricType(gBattlerAttacker))
spAttack = (150 * spAttack) / 100;
if (defender->ability == ABILITY_PLUS && HasOtherRockType(gBattlerAttacker))
spAttack = (150 * spAttack) / 100;
if (defender->ability == ABILITY_MINUS && HasOtherElectricType(gBattlerAttacker))
spAttack = (150 * spAttack) / 100;
if (attacker->ability == ABILITY_GUTS && attacker->status1)
attack = (150 * attack) / 100;
@@ -2562,7 +2599,14 @@ s32 CalculateBaseDamage(struct BattlePokemon *attacker, struct BattlePokemon *de
damage = attack;
}
else
{
// ADD: Pressure on defender ignores attacker's Attack boosts
if (defender->ability == ABILITY_PRESSURE
&& attacker->statStages[STAT_ATK] > DEFAULT_STAT_STAGE)
damage = attack;
else
APPLY_STAT_MOD(damage, attacker, attack, STAT_ATK)
}
damage = damage * gBattleMovePower;
damage *= (2 * attacker->level / 5 + 2);
@@ -2576,7 +2620,14 @@ s32 CalculateBaseDamage(struct BattlePokemon *attacker, struct BattlePokemon *de
damageHelper = defense;
}
else
APPLY_STAT_MOD(damageHelper, defender, defense, STAT_DEF)
{
// ADD: Pressure on attacker ignores foe Defense boosts
if (attacker->ability == ABILITY_PRESSURE
&& defender->statStages[STAT_DEF] > DEFAULT_STAT_STAGE)
damageHelper = defense;
else
APPLY_STAT_MOD(damageHelper, defender, defense, STAT_DEF)
}
damage = damage / damageHelper;
damage /= 50;
@@ -2617,8 +2668,14 @@ s32 CalculateBaseDamage(struct BattlePokemon *attacker, struct BattlePokemon *de
damage = spAttack;
}
else
APPLY_STAT_MOD(damage, attacker, spAttack, STAT_SPATK)
{
// ADD: Pressure on defender ignores attacker's SpAtk boosts
if (defender->ability == ABILITY_PRESSURE
&& attacker->statStages[STAT_SPATK] > DEFAULT_STAT_STAGE)
damage = spAttack;
else
APPLY_STAT_MOD(damage, attacker, spAttack, STAT_SPATK)
}
damage = damage * gBattleMovePower;
damage *= (2 * attacker->level / 5 + 2);
@@ -2631,7 +2688,14 @@ s32 CalculateBaseDamage(struct BattlePokemon *attacker, struct BattlePokemon *de
damageHelper = spDefense;
}
else
APPLY_STAT_MOD(damageHelper, defender, spDefense, STAT_SPDEF)
{
// ADD: Pressure ignores SpDef boosts
if (attacker->ability == ABILITY_PRESSURE
&& defender->statStages[STAT_SPATK] > DEFAULT_STAT_STAGE)
damageHelper = spDefense;
else
APPLY_STAT_MOD(damageHelper, defender, spDefense, STAT_SPDEF)
}
damage = (damage / damageHelper);
damage /= 50;