New crit calculator.

This commit is contained in:
DizzyEggg 2018-07-23 21:36:05 +02:00
parent 56120e35d4
commit 6570324432
8 changed files with 100 additions and 26 deletions

View File

@ -117,7 +117,7 @@ gBattleScriptsForMoveEffects:: @ 82D86A8
.4byte BattleScript_EffectSpite .4byte BattleScript_EffectSpite
.4byte BattleScript_EffectFalseSwipe .4byte BattleScript_EffectFalseSwipe
.4byte BattleScript_EffectHealBell .4byte BattleScript_EffectHealBell
.4byte BattleScript_EffectPlaceholder103 .4byte BattleScript_EffectAlwaysCrit
.4byte BattleScript_EffectTripleKick .4byte BattleScript_EffectTripleKick
.4byte BattleScript_EffectThief .4byte BattleScript_EffectThief
.4byte BattleScript_EffectMeanLook .4byte BattleScript_EffectMeanLook
@ -488,7 +488,7 @@ BattleScript_EffectEvasionDownHit:
BattleScript_EffectVitalThrow: BattleScript_EffectVitalThrow:
BattleScript_EffectUnused60: BattleScript_EffectUnused60:
BattleScript_EffectFalseSwipe: BattleScript_EffectFalseSwipe:
BattleScript_EffectPlaceholder103: BattleScript_EffectAlwaysCrit:
BattleScript_EffectUnused6e: BattleScript_EffectUnused6e:
BattleScript_EffectPursuit: BattleScript_EffectPursuit:
BattleScript_EffectUnused8d: BattleScript_EffectUnused8d:

View File

@ -178,6 +178,7 @@ struct DisableStruct
u8 magnetRiseTimer; u8 magnetRiseTimer;
u8 telekinesisTimer; u8 telekinesisTimer;
u8 healBlockTimer; u8 healBlockTimer;
u8 laserFocusTimer;
}; };
struct ProtectStruct struct ProtectStruct

View File

@ -4,6 +4,7 @@
#define WINDOW_CLEAR 0x1 #define WINDOW_CLEAR 0x1
#define WINDOW_x80 0x80 #define WINDOW_x80 0x80
s32 CalcCritChanceStage(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recordAbility);
u8 GetBattlerTurnOrderNum(u8 battlerId); u8 GetBattlerTurnOrderNum(u8 battlerId);
void SetMoveEffect(bool8 primary, u8 certain); void SetMoveEffect(bool8 primary, u8 certain);
void BattleDestroyYesNoCursorAt(u8 cursorPosition); void BattleDestroyYesNoCursorAt(u8 cursorPosition);

View File

@ -156,6 +156,7 @@
#define STATUS3_MAGNET_RISE 0x4000000 #define STATUS3_MAGNET_RISE 0x4000000
#define STATUS3_HEAL_BLOCK 0x8000000 #define STATUS3_HEAL_BLOCK 0x8000000
#define STATUS3_AQUA_RING 0x10000000 #define STATUS3_AQUA_RING 0x10000000
#define STATUS3_LASER_FOCUS 0x20000000
#define STATUS3_SEMI_INVULNERABLE (STATUS3_UNDERGROUND | STATUS3_ON_AIR | STATUS3_UNDERWATER) #define STATUS3_SEMI_INVULNERABLE (STATUS3_UNDERGROUND | STATUS3_ON_AIR | STATUS3_UNDERWATER)
// Not really sure what a "hitmarker" is. // Not really sure what a "hitmarker" is.

View File

@ -104,7 +104,7 @@
#define EFFECT_SPITE 100 #define EFFECT_SPITE 100
#define EFFECT_FALSE_SWIPE 101 #define EFFECT_FALSE_SWIPE 101
#define EFFECT_HEAL_BELL 102 #define EFFECT_HEAL_BELL 102
#define EFFECT_PLACEHOLDER_103 103 #define EFFECT_ALWAYS_CRIT 103
#define EFFECT_TRIPLE_KICK 104 #define EFFECT_TRIPLE_KICK 104
#define EFFECT_THIEF 105 #define EFFECT_THIEF 105
#define EFFECT_MEAN_LOOK 106 #define EFFECT_MEAN_LOOK 106

View File

@ -727,6 +727,40 @@ static void RestoreBattlerData(u8 battlerId)
} }
} }
static bool32 AI_GetIfCrit(u32 move, u8 battlerAtk, u8 battlerDef)
{
bool32 isCrit;
switch (CalcCritChanceStage(battlerAtk, battlerDef, move, FALSE))
{
case -1:
case 0:
default:
isCrit = FALSE;
break;
case 1:
if (gBattleMoves[move].flags & FLAG_HIGH_CRIT && (Random() % 5 == 0))
isCrit = TRUE;
else
isCrit = FALSE;
break;
case 2:
if (gBattleMoves[move].flags & FLAG_HIGH_CRIT && (Random() % 2 == 0))
isCrit = TRUE;
else if (!(gBattleMoves[move].flags & FLAG_HIGH_CRIT) && (Random() % 4) == 0)
isCrit = TRUE;
else
isCrit = FALSE;
break;
case 3:
case 4:
isCrit = TRUE;
break;
}
return isCrit;
}
s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef) s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef)
{ {
s32 dmg; s32 dmg;
@ -737,7 +771,7 @@ s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef)
SetBattlerData(battlerAtk); SetBattlerData(battlerAtk);
SetBattlerData(battlerDef); SetBattlerData(battlerDef);
dmg = CalculateMoveDamage(move, battlerAtk, battlerDef, gBattleMoves[move].type, 0, FALSE, FALSE); dmg = CalculateMoveDamage(move, battlerAtk, battlerDef, gBattleMoves[move].type, 0, AI_GetIfCrit(move, battlerAtk, battlerDef), FALSE);
RestoreBattlerData(battlerAtk); RestoreBattlerData(battlerAtk);
RestoreBattlerData(battlerDef); RestoreBattlerData(battlerDef);

View File

@ -627,9 +627,6 @@ static const struct StatFractions sAccuracyStageRatios[] =
{ 3, 1}, // +6 { 3, 1}, // +6
}; };
// The chance is 1/N for each stage.
static const u16 sCriticalHitChance[] = {16, 8, 4, 3, 2};
static const u32 sStatusFlagsForMoveEffects[] = static const u32 sStatusFlagsForMoveEffects[] =
{ {
0x00000000, 0x00000000,
@ -1298,33 +1295,62 @@ static void atk03_ppreduce(void)
gBattlescriptCurrInstr++; gBattlescriptCurrInstr++;
} }
static void atk04_critcalc(void) s32 CalcCritChanceStage(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recordAbility)
{ {
u8 holdEffect; s32 critChance = 0;
u16 item, critChance; u32 abilityAtk = GetBattlerAbility(gBattlerAttacker);
u32 abilityDef = GetBattlerAbility(gBattlerTarget);
item = gBattleMons[gBattlerAttacker].item; if (gSideStatuses[battlerDef] & SIDE_STATUS_LUCKY_CHANT
|| gStatuses3[gBattlerAttacker] & STATUS3_CANT_SCORE_A_CRIT)
if (item == ITEM_ENIGMA_BERRY) {
holdEffect = gEnigmaBerries[gBattlerAttacker].holdEffect; critChance = -1;
}
else if (abilityDef == ABILITY_BATTLE_ARMOR || abilityDef == ABILITY_SHELL_ARMOR)
{
if (recordAbility)
RecordAbilityBattle(battlerDef, abilityDef);
critChance = -1;
}
else if (gStatuses3[battlerAtk] & STATUS3_LASER_FOCUS
|| gBattleMoves[move].effect == EFFECT_ALWAYS_CRIT
|| (abilityAtk == ABILITY_MERCILESS && gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY))
{
critChance = 4;
}
else else
holdEffect = ItemId_GetHoldEffect(item); {
u32 holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE);
gPotentialItemEffectBattler = gBattlerAttacker; critChance = 2 * ((gBattleMons[gBattlerAttacker].status2 & STATUS2_FOCUS_ENERGY) != 0)
+ ((gBattleMoves[gCurrentMove].flags & FLAG_HIGH_CRIT) != 0)
critChance = 2 * ((gBattleMons[gBattlerAttacker].status2 & STATUS2_FOCUS_ENERGY) != 0) + (holdEffectAtk == HOLD_EFFECT_SCOPE_LENS)
+ ((gBattleMoves[gCurrentMove].flags & FLAG_HIGH_CRIT) != 0) + 2 * (holdEffectAtk == HOLD_EFFECT_LUCKY_PUNCH && gBattleMons[gBattlerAttacker].species == SPECIES_CHANSEY)
+ (holdEffect == HOLD_EFFECT_SCOPE_LENS) + 2 * (holdEffectAtk == HOLD_EFFECT_STICK && gBattleMons[gBattlerAttacker].species == SPECIES_FARFETCHD)
+ 2 * (holdEffect == HOLD_EFFECT_LUCKY_PUNCH && gBattleMons[gBattlerAttacker].species == SPECIES_CHANSEY) + (abilityAtk == ABILITY_SUPER_LUCK);
+ 2 * (holdEffect == HOLD_EFFECT_STICK && gBattleMons[gBattlerAttacker].species == SPECIES_FARFETCHD); }
if (critChance > 4) if (critChance > 4)
critChance = 4; critChance = 4;
if ((gBattleMons[gBattlerTarget].ability != ABILITY_BATTLE_ARMOR && gBattleMons[gBattlerTarget].ability != ABILITY_SHELL_ARMOR) return critChance;
&& !(gStatuses3[gBattlerAttacker] & STATUS3_CANT_SCORE_A_CRIT) }
&& !(gBattleTypeFlags & (BATTLE_TYPE_WALLY_TUTORIAL | BATTLE_TYPE_FIRST_BATTLE))
&& !(Random() % sCriticalHitChance[critChance])) // 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};
static void atk04_critcalc(void)
{
s32 critChance = CalcCritChanceStage(gBattlerAttacker, gBattlerTarget, gCurrentMove, TRUE);
gPotentialItemEffectBattler = gBattlerAttacker;
if (gBattleTypeFlags & (BATTLE_TYPE_WALLY_TUTORIAL | BATTLE_TYPE_FIRST_BATTLE))
gIsCriticalHit = FALSE;
else if (critChance == -1)
gIsCriticalHit = FALSE;
else if (Random() % sCriticalHitChanceGen3[critChance] == 0)
gIsCriticalHit = TRUE; gIsCriticalHit = TRUE;
else else
gIsCriticalHit = FALSE; gIsCriticalHit = FALSE;

View File

@ -1209,6 +1209,7 @@ enum
ENDTURN_EMBARGO, ENDTURN_EMBARGO,
ENDTURN_LOCK_ON, ENDTURN_LOCK_ON,
ENDTURN_CHARGE, ENDTURN_CHARGE,
ENDTURN_LASER_FOCUS,
ENDTURN_TAUNT, ENDTURN_TAUNT,
ENDTURN_YAWN, ENDTURN_YAWN,
ENDTURN_ITEMS2, ENDTURN_ITEMS2,
@ -1581,6 +1582,16 @@ u8 DoBattlerEndTurnEffects(void)
} }
gBattleStruct->turnEffectsTracker++; gBattleStruct->turnEffectsTracker++;
break; break;
case ENDTURN_LASER_FOCUS:
if (gStatuses3[gActiveBattler] & STATUS3_LASER_FOCUS)
{
if (gDisableStructs[gActiveBattler].laserFocusTimer != 0)
gDisableStructs[gActiveBattler].laserFocusTimer--;
if (gDisableStructs[gActiveBattler].laserFocusTimer == 0)
gStatuses3[gActiveBattler] &= ~(STATUS3_LASER_FOCUS);
}
gBattleStruct->turnEffectsTracker++;
break;
case ENDTURN_EMBARGO: case ENDTURN_EMBARGO:
if (gStatuses3[gActiveBattler] & STATUS3_EMBARGO) if (gStatuses3[gActiveBattler] & STATUS3_EMBARGO)
{ {