mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-12-26 11:44:17 +01:00
RNG_HITS and RNG_LOADED_DICE
This commit is contained in:
parent
b406a9c1bd
commit
fc321965a9
@ -60,8 +60,10 @@ enum RandomTag
|
||||
RNG_FLAME_BODY,
|
||||
RNG_FORCE_RANDOM_SWITCH,
|
||||
RNG_FROZEN,
|
||||
RNG_HITS,
|
||||
RNG_HOLD_EFFECT_FLINCH,
|
||||
RNG_INFATUATION,
|
||||
RNG_LOADED_DICE,
|
||||
RNG_METRONOME,
|
||||
RNG_PARALYSIS,
|
||||
RNG_POISON_POINT,
|
||||
|
@ -12206,30 +12206,14 @@ static void Cmd_setmultihitcounter(void)
|
||||
}
|
||||
else
|
||||
{
|
||||
#if B_MULTI_HIT_CHANCE >= GEN_5
|
||||
// Based on Gen 5's odds
|
||||
// 35% for 2 hits
|
||||
// 35% for 3 hits
|
||||
// 15% for 4 hits
|
||||
// 15% for 5 hits
|
||||
gMultiHitCounter = Random() % 100;
|
||||
if (gMultiHitCounter < 35)
|
||||
gMultiHitCounter = 2;
|
||||
else if (gMultiHitCounter < 35 + 35)
|
||||
gMultiHitCounter = 3;
|
||||
else if (gMultiHitCounter < 35 + 35 + 15)
|
||||
gMultiHitCounter = 4;
|
||||
else
|
||||
gMultiHitCounter = 5;
|
||||
#else
|
||||
// 2 and 3 hits: 37.5%
|
||||
// 4 and 5 hits: 12.5%
|
||||
gMultiHitCounter = Random() % 4;
|
||||
if (gMultiHitCounter > 1)
|
||||
gMultiHitCounter = (Random() % 4) + 2;
|
||||
else
|
||||
gMultiHitCounter += 2;
|
||||
#endif
|
||||
// WARNING: These seem to be unused, see SetRandomMultiHitCounter.
|
||||
#if B_MULTI_HIT_CHANCE >= GEN_5
|
||||
// 35%: 2 hits, 35%: 3 hits, 15% 4 hits, 15% 5 hits.
|
||||
gMultiHitCounter = RandomWeighted(RNG_HITS, 0, 0, 7, 7, 3, 3);
|
||||
#else
|
||||
// 37.5%: 2 hits, 37.5%: 3 hits, 12.5% 4 hits, 12.5% 5 hits.
|
||||
gMultiHitCounter = RandomWeighted(RNG_HITS, 0, 0, 3, 3, 1, 1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10899,35 +10899,19 @@ bool32 CanTargetBattler(u8 battlerAtk, u8 battlerDef, u16 move)
|
||||
|
||||
static void SetRandomMultiHitCounter()
|
||||
{
|
||||
#if (B_MULTI_HIT_CHANCE >= GEN_5)
|
||||
// Based on Gen 5's odds
|
||||
// 35% for 2 hits
|
||||
// 35% for 3 hits
|
||||
// 15% for 4 hits
|
||||
// 15% for 5 hits
|
||||
gMultiHitCounter = Random() % 100;
|
||||
if (gMultiHitCounter < 35)
|
||||
gMultiHitCounter = 2;
|
||||
else if (gMultiHitCounter < 35 + 35)
|
||||
gMultiHitCounter = 3;
|
||||
else if (gMultiHitCounter < 35 + 35 + 15)
|
||||
gMultiHitCounter = 4;
|
||||
else
|
||||
gMultiHitCounter = 5;
|
||||
#else
|
||||
// 2 and 3 hits: 37.5%
|
||||
// 4 and 5 hits: 12.5%
|
||||
gMultiHitCounter = Random() % 4;
|
||||
if (gMultiHitCounter > 1)
|
||||
gMultiHitCounter = (Random() % 4) + 2;
|
||||
else
|
||||
gMultiHitCounter += 2;
|
||||
#endif
|
||||
|
||||
if (gMultiHitCounter < 4 && GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_LOADED_DICE)
|
||||
if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_LOADED_DICE)
|
||||
{
|
||||
// If roll 4 or 5 Loaded Dice doesn't do anything. Otherwise it rolls the number of hits as 5 minus a random integer from 0 to 1 inclusive.
|
||||
gMultiHitCounter = 5 - (Random() & 1);
|
||||
gMultiHitCounter = RandomUniform(RNG_LOADED_DICE, 4, 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if B_MULTI_HIT_CHANCE >= GEN_5
|
||||
// 35%: 2 hits, 35%: 3 hits, 15% 4 hits, 15% 5 hits.
|
||||
gMultiHitCounter = RandomWeighted(RNG_HITS, 0, 0, 7, 7, 3, 3);
|
||||
#else
|
||||
// 37.5%: 2 hits, 37.5%: 3 hits, 12.5% 4 hits, 12.5% 5 hits.
|
||||
gMultiHitCounter = RandomWeighted(RNG_HITS, 0, 0, 3, 3, 1, 1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,6 +56,6 @@ SINGLE_BATTLE_TEST("Metronome's called multi-hit move hits multiple times")
|
||||
MESSAGE("Wobbuffet used Rock Blast!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ROCK_BLAST, player);
|
||||
HP_BAR(opponent);
|
||||
MESSAGE("Hit 2 time(s)!");
|
||||
MESSAGE("Hit 5 time(s)!");
|
||||
}
|
||||
}
|
||||
|
@ -9,8 +9,8 @@ ASSUMPTIONS
|
||||
SINGLE_BATTLE_TEST("Mirror Move copies the last used move by the target")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) {Speed(2);}
|
||||
OPPONENT(SPECIES_WOBBUFFET) {Speed(5);}
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_TACKLE); MOVE(player, MOVE_MIRROR_MOVE); }
|
||||
} SCENE {
|
||||
@ -26,10 +26,10 @@ SINGLE_BATTLE_TEST("Mirror Move copies the last used move by the target")
|
||||
SINGLE_BATTLE_TEST("Mirror Move fails if no move was used before")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) {Speed(5);}
|
||||
OPPONENT(SPECIES_WOBBUFFET) {Speed(2);}
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_TACKLE); MOVE(player, MOVE_MIRROR_MOVE); }
|
||||
TURN { MOVE(player, MOVE_MIRROR_MOVE); MOVE(opponent, MOVE_TACKLE); }
|
||||
} SCENE {
|
||||
MESSAGE("Wobbuffet used Mirror Move!");
|
||||
MESSAGE("The Mirror Move failed!");
|
||||
@ -44,8 +44,8 @@ SINGLE_BATTLE_TEST("Mirror Move's called powder move fails against Grass Types")
|
||||
ASSUME(gBattleMoves[MOVE_STUN_SPORE].flags & FLAG_POWDER);
|
||||
ASSUME(gSpeciesInfo[SPECIES_ODDISH].types[0] == TYPE_GRASS);
|
||||
ASSUME(gBattleMoves[MOVE_STUN_SPORE].effect == EFFECT_PARALYZE);
|
||||
PLAYER(SPECIES_ODDISH) {Speed(5);}
|
||||
OPPONENT(SPECIES_WOBBUFFET) {Speed(2);}
|
||||
PLAYER(SPECIES_ODDISH);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_STUN_SPORE); MOVE(opponent, MOVE_MIRROR_MOVE); }
|
||||
} SCENE {
|
||||
@ -59,19 +59,18 @@ SINGLE_BATTLE_TEST("Mirror Move's called powder move fails against Grass Types")
|
||||
}
|
||||
}
|
||||
|
||||
// It hits first 2 times, then 5 times with the default rng seed.
|
||||
SINGLE_BATTLE_TEST("Mirror Move's called multi-hit move hits multiple times")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gBattleMoves[MOVE_BULLET_SEED].effect == EFFECT_MULTI_HIT);
|
||||
PLAYER(SPECIES_WOBBUFFET) {Speed(5);}
|
||||
OPPONENT(SPECIES_WOBBUFFET) {Speed(2);}
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_BULLET_SEED); MOVE(opponent, MOVE_MIRROR_MOVE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
|
||||
HP_BAR(opponent);
|
||||
MESSAGE("Hit 2 time(s)!");
|
||||
MESSAGE("Hit 5 time(s)!");
|
||||
MESSAGE("Foe Wobbuffet used Mirror Move!");
|
||||
MESSAGE("Foe Wobbuffet used Bullet Seed!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, opponent);
|
||||
|
@ -368,52 +368,40 @@ u32 RandomUniformExcept(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32
|
||||
PrintTestName();
|
||||
}
|
||||
STATE->trialRatio = Q_4_12(1) / STATE->trials;
|
||||
return STATE->runTrial + lo;
|
||||
|
||||
while (reject(STATE->runTrial + lo + STATE->rngTrialOffset))
|
||||
{
|
||||
if (STATE->runTrial + lo + STATE->rngTrialOffset > hi)
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, "RandomUniformExcept called with inconsistent reject");
|
||||
STATE->rngTrialOffset++;
|
||||
}
|
||||
|
||||
return STATE->runTrial + lo + STATE->rngTrialOffset;
|
||||
}
|
||||
|
||||
default_ = hi;
|
||||
while (reject(default_))
|
||||
{
|
||||
if (default_ == lo)
|
||||
Test_ExitWithResult(TEST_RESULT_INVALID, "RandomUniformExcept rejected all values");
|
||||
default_--;
|
||||
}
|
||||
return default_;
|
||||
}
|
||||
|
||||
u32 RandomWeightedArray(enum RandomTag tag, u32 sum, u32 n, const u8 *weights)
|
||||
{
|
||||
const struct BattlerTurn *turn = NULL;
|
||||
u32 default_ = n-1;
|
||||
|
||||
if (sum == 0)
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, "RandomWeightedArray called with zero sum");
|
||||
|
||||
if (gCurrentTurnActionNumber < gBattlersCount)
|
||||
{
|
||||
u32 battlerId = gBattlerByTurnOrder[gCurrentTurnActionNumber];
|
||||
turn = &DATA.battleRecordTurns[gBattleResults.battleTurnCounter][battlerId];
|
||||
}
|
||||
|
||||
if (turn && turn->rng.tag == tag)
|
||||
{
|
||||
default_ = turn->rng.value;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (tag)
|
||||
{
|
||||
case RNG_ACCURACY:
|
||||
ASSUME(n == 2);
|
||||
if (turn && turn->hit)
|
||||
return turn->hit - 1;
|
||||
default_ = TRUE;
|
||||
break;
|
||||
|
||||
case RNG_CRITICAL_HIT:
|
||||
ASSUME(n == 2);
|
||||
if (turn && turn->criticalHit)
|
||||
return turn->criticalHit - 1;
|
||||
default_ = FALSE;
|
||||
break;
|
||||
|
||||
case RNG_SECONDARY_EFFECT:
|
||||
ASSUME(n == 2);
|
||||
if (turn && turn->secondaryEffect)
|
||||
return turn->secondaryEffect - 1;
|
||||
default_ = TRUE;
|
||||
break;
|
||||
}
|
||||
if (turn && turn->rng.tag == tag)
|
||||
return turn->rng.value;
|
||||
}
|
||||
|
||||
if (tag == STATE->rngTag)
|
||||
@ -432,7 +420,38 @@ u32 RandomWeightedArray(enum RandomTag tag, u32 sum, u32 n, const u8 *weights)
|
||||
return STATE->runTrial;
|
||||
}
|
||||
|
||||
return default_;
|
||||
switch (tag)
|
||||
{
|
||||
case RNG_ACCURACY:
|
||||
ASSUME(n == 2);
|
||||
if (turn && turn->hit)
|
||||
return turn->hit - 1;
|
||||
else
|
||||
return TRUE;
|
||||
|
||||
case RNG_CRITICAL_HIT:
|
||||
ASSUME(n == 2);
|
||||
if (turn && turn->criticalHit)
|
||||
return turn->criticalHit - 1;
|
||||
else
|
||||
return FALSE;
|
||||
|
||||
case RNG_SECONDARY_EFFECT:
|
||||
ASSUME(n == 2);
|
||||
if (turn && turn->secondaryEffect)
|
||||
return turn->secondaryEffect - 1;
|
||||
else
|
||||
return TRUE;
|
||||
|
||||
default:
|
||||
while (weights[n-1] == 0)
|
||||
{
|
||||
if (n == 1)
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, "RandomWeightedArray called with all zero weights");
|
||||
n--;
|
||||
}
|
||||
return n-1;
|
||||
}
|
||||
}
|
||||
|
||||
const void *RandomElementArray(enum RandomTag tag, const void *array, size_t size, size_t count)
|
||||
|
Loading…
Reference in New Issue
Block a user