mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-07-06 16:32:16 +02:00
Fix off-by-one error in some random number calls
This commit is contained in:
parent
e39ebb68f2
commit
1fb6656c22
@ -851,7 +851,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
overrideModifiers(this, false);
|
overrideModifiers(this, false);
|
||||||
overrideHeldItems(this, pokemon, false);
|
overrideHeldItems(this, pokemon, false);
|
||||||
if (boss && !dataSource) {
|
if (boss && !dataSource) {
|
||||||
const secondaryIvs = Utils.getIvsFromId(Utils.randSeedInt(4294967295));
|
const secondaryIvs = Utils.getIvsFromId(Utils.randSeedInt(4294967296));
|
||||||
|
|
||||||
for (let s = 0; s < pokemon.ivs.length; s++) {
|
for (let s = 0; s < pokemon.ivs.length; s++) {
|
||||||
pokemon.ivs[s] = Math.round(Phaser.Math.Linear(Math.min(pokemon.ivs[s], secondaryIvs[s]), Math.max(pokemon.ivs[s], secondaryIvs[s]), 0.75));
|
pokemon.ivs[s] = Math.round(Phaser.Math.Linear(Math.min(pokemon.ivs[s], secondaryIvs[s]), Math.max(pokemon.ivs[s], secondaryIvs[s]), 0.75));
|
||||||
@ -957,6 +957,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
this.offsetGym = this.gameMode.isClassic && this.getGeneratedOffsetGym();
|
this.offsetGym = this.gameMode.isClassic && this.getGeneratedOffsetGym();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// What is the purpose of this function? Why not just use Battle.randSeedInt() directly?
|
||||||
randBattleSeedInt(range: integer, min: integer = 0): integer {
|
randBattleSeedInt(range: integer, min: integer = 0): integer {
|
||||||
return this.currentBattle?.randSeedInt(this, range, min);
|
return this.currentBattle?.randSeedInt(this, range, min);
|
||||||
}
|
}
|
||||||
@ -1107,7 +1108,8 @@ export default class BattleScene extends SceneBase {
|
|||||||
doubleTrainer = false;
|
doubleTrainer = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
newTrainer = trainerData !== undefined ? trainerData.toTrainer(this) : new Trainer(this, trainerType, doubleTrainer ? TrainerVariant.DOUBLE : Utils.randSeedInt(2) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT);
|
const variant = doubleTrainer ? TrainerVariant.DOUBLE : (Utils.randSeedInt(2) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT);
|
||||||
|
newTrainer = trainerData !== undefined ? trainerData.toTrainer(this) : new Trainer(this, trainerType, variant);
|
||||||
this.field.add(newTrainer);
|
this.field.add(newTrainer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2550,7 +2552,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
if (mods.length < 1) {
|
if (mods.length < 1) {
|
||||||
return mods;
|
return mods;
|
||||||
}
|
}
|
||||||
const rand = Math.floor(Utils.randSeedInt(mods.length));
|
const rand = Math.floor(Utils.randSeedInt(mods.length)); // Why is there a floor() call around a number that can only be an integer?
|
||||||
return [mods[rand], ...shuffleModifiers(mods.filter((_, i) => i !== rand))];
|
return [mods[rand], ...shuffleModifiers(mods.filter((_, i) => i !== rand))];
|
||||||
};
|
};
|
||||||
modifiers = shuffleModifiers(modifiers);
|
modifiers = shuffleModifiers(modifiers);
|
||||||
|
@ -2452,7 +2452,7 @@ export class ConfusionOnStatusEffectAbAttr extends PostAttackAbAttr {
|
|||||||
*/
|
*/
|
||||||
applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
|
applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
|
||||||
if (this.effects.indexOf(args[0]) > -1 && !defender.isFainted()) {
|
if (this.effects.indexOf(args[0]) > -1 && !defender.isFainted()) {
|
||||||
return defender.addTag(BattlerTagType.CONFUSED, pokemon.randSeedInt(3,2), move.id, defender.id);
|
return defender.addTag(BattlerTagType.CONFUSED, pokemon.randSeedIntRange(2, 5), move.id, defender.id);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -347,7 +347,7 @@ export class ConfusedTag extends BattlerTag {
|
|||||||
if (pokemon.randSeedInt(3) === 0) {
|
if (pokemon.randSeedInt(3) === 0) {
|
||||||
const atk = pokemon.getBattleStat(Stat.ATK);
|
const atk = pokemon.getBattleStat(Stat.ATK);
|
||||||
const def = pokemon.getBattleStat(Stat.DEF);
|
const def = pokemon.getBattleStat(Stat.DEF);
|
||||||
const damage = Math.ceil(((((2 * pokemon.level / 5 + 2) * 40 * atk / def) / 50) + 2) * (pokemon.randSeedInt(15, 85) / 100));
|
const damage = Math.ceil(((((2 * pokemon.level / 5 + 2) * 40 * atk / def) / 50) + 2) * (pokemon.randSeedIntRange(85, 100) / 100));
|
||||||
pokemon.scene.queueMessage(i18next.t("battlerTags:confusedLapseHurtItself"));
|
pokemon.scene.queueMessage(i18next.t("battlerTags:confusedLapseHurtItself"));
|
||||||
pokemon.damageAndUpdate(damage);
|
pokemon.damageAndUpdate(damage);
|
||||||
pokemon.battleData.hitCount++;
|
pokemon.battleData.hitCount++;
|
||||||
|
@ -4334,7 +4334,7 @@ export class AddBattlerTagAttr extends MoveEffectAttr {
|
|||||||
|
|
||||||
const moveChance = this.getMoveChance(user, target, move, this.selfTarget, true);
|
const moveChance = this.getMoveChance(user, target, move, this.selfTarget, true);
|
||||||
if (moveChance < 0 || moveChance === 100 || user.randSeedInt(100) < moveChance) {
|
if (moveChance < 0 || moveChance === 100 || user.randSeedInt(100) < moveChance) {
|
||||||
return (this.selfTarget ? user : target).addTag(this.tagType, user.randSeedInt(this.turnCountMax - this.turnCountMin, this.turnCountMin), move.id, user.id);
|
return (this.selfTarget ? user : target).addTag(this.tagType, user.randSeedIntRange(this.turnCountMin, this.turnCountMax), move.id, user.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -1573,7 +1573,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.fusionSpecies = this.scene.randomSpecies(this.scene.currentBattle?.waveIndex || 0, this.level, false, filter, true);
|
this.fusionSpecies = this.scene.randomSpecies(this.scene.currentBattle?.waveIndex || 0, this.level, false, filter, true);
|
||||||
this.fusionAbilityIndex = (this.fusionSpecies.abilityHidden && hasHiddenAbility ? this.fusionSpecies.ability2 ? 2 : 1 : this.fusionSpecies.ability2 ? randAbilityIndex : 0);
|
this.fusionAbilityIndex = (this.fusionSpecies.abilityHidden && hasHiddenAbility ? 2 : this.fusionSpecies.ability2 !== this.fusionSpecies.ability1 ? randAbilityIndex : 0);
|
||||||
this.fusionShiny = this.shiny;
|
this.fusionShiny = this.shiny;
|
||||||
this.fusionVariant = this.variant;
|
this.fusionVariant = this.variant;
|
||||||
|
|
||||||
@ -2081,7 +2081,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
|
|
||||||
if (!isTypeImmune) {
|
if (!isTypeImmune) {
|
||||||
const levelMultiplier = (2 * source.level / 5 + 2);
|
const levelMultiplier = (2 * source.level / 5 + 2);
|
||||||
const randomMultiplier = ((this.scene.randBattleSeedInt(16) + 85) / 100);
|
const randomMultiplier = (this.randSeedIntRange(85, 100) / 100);
|
||||||
damage.value = Math.ceil((((levelMultiplier * power * sourceAtk.value / targetDef.value) / 50) + 2)
|
damage.value = Math.ceil((((levelMultiplier * power * sourceAtk.value / targetDef.value) / 50) + 2)
|
||||||
* stabMultiplier.value
|
* stabMultiplier.value
|
||||||
* typeMultiplier.value
|
* typeMultiplier.value
|
||||||
|
@ -379,16 +379,16 @@ export class MoveEffectPhase extends PokemonPhase {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const moveAccuracy = this.move.getMove().calculateBattleAccuracy(user!, target); // TODO: is the bang correct here?
|
const moveAccuracy = this.move.getMove().calculateBattleAccuracy(user, target);
|
||||||
|
|
||||||
if (moveAccuracy === -1) {
|
if (moveAccuracy === -1) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const accuracyMultiplier = user.getAccuracyMultiplier(target, this.move.getMove());
|
const accuracyMultiplier = user.getAccuracyMultiplier(target, this.move.getMove());
|
||||||
const rand = user.randSeedInt(100, 1);
|
const rand = user.randSeedInt(100);
|
||||||
|
|
||||||
return rand <= moveAccuracy * (accuracyMultiplier!); // TODO: is this bang correct?
|
return rand < (moveAccuracy * accuracyMultiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the {@linkcode Pokemon} using this phase's invoked move */
|
/** Returns the {@linkcode Pokemon} using this phase's invoked move */
|
||||||
|
56
src/rng.md
Normal file
56
src/rng.md
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
`src/field/pokemon.ts -> Pokemon`
|
||||||
|
```ts
|
||||||
|
// This calls either `BattleScene:randBattleSeedInt()` in `src/battle-scene.ts` which calls `Battle:randSeedInt()` in `src/battle.ts` which calls `randSeedInt()` in `src/utils.ts`
|
||||||
|
// or it directly calls `randSeedInt()` in `src/utils.ts`
|
||||||
|
randSeedInt(range: integer, min: integer = 0): integer {
|
||||||
|
return this.scene.currentBattle
|
||||||
|
? this.scene.randBattleSeedInt(range, min)
|
||||||
|
: Utils.randSeedInt(range, min);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`src/battle-scene.ts -> BattleScene`
|
||||||
|
```ts
|
||||||
|
// This calls `Battle:randSeedInt()` in `src/battle.ts` which calls `randSeedInt()` in `src/utils.ts`
|
||||||
|
randBattleSeedInt(range: integer, min: integer = 0): integer {
|
||||||
|
return this.currentBattle?.randSeedInt(this, range, min);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`src/battle.ts -> Battle`
|
||||||
|
```ts
|
||||||
|
// This calls `randSeedInt()` in `src/utils.ts`
|
||||||
|
randSeedInt(scene: BattleScene, range: integer, min: integer = 0): integer {
|
||||||
|
if (range <= 1) {
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
const tempRngCounter = scene.rngCounter;
|
||||||
|
const tempSeedOverride = scene.rngSeedOverride;
|
||||||
|
const state = Phaser.Math.RND.state();
|
||||||
|
if (this.battleSeedState) {
|
||||||
|
Phaser.Math.RND.state(this.battleSeedState);
|
||||||
|
} else {
|
||||||
|
Phaser.Math.RND.sow([ Utils.shiftCharCodes(this.battleSeed, this.turn << 6) ]);
|
||||||
|
console.log("Battle Seed:", this.battleSeed);
|
||||||
|
}
|
||||||
|
scene.rngCounter = this.rngCounter++;
|
||||||
|
scene.rngSeedOverride = this.battleSeed;
|
||||||
|
const ret = Utils.randSeedInt(range, min);
|
||||||
|
this.battleSeedState = Phaser.Math.RND.state();
|
||||||
|
Phaser.Math.RND.state(state);
|
||||||
|
scene.rngCounter = tempRngCounter;
|
||||||
|
scene.rngSeedOverride = tempSeedOverride;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`src/utils.ts`
|
||||||
|
```ts
|
||||||
|
// This is the eventual endpoint of every other RSI function
|
||||||
|
export function randSeedInt(range: integer, min: integer = 0): integer {
|
||||||
|
if (range <= 1) {
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
return Phaser.Math.RND.integerInRange(min, (range - 1) + min);
|
||||||
|
}
|
||||||
|
```
|
@ -82,6 +82,7 @@ export function randInt(range: integer, min: integer = 0): integer {
|
|||||||
return Math.floor(Math.random() * range) + min;
|
return Math.floor(Math.random() * range) + min;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Is this only seeded if called via `Battle:randSeedInt()`?
|
||||||
export function randSeedInt(range: integer, min: integer = 0): integer {
|
export function randSeedInt(range: integer, min: integer = 0): integer {
|
||||||
if (range <= 1) {
|
if (range <= 1) {
|
||||||
return min;
|
return min;
|
||||||
|
Loading…
Reference in New Issue
Block a user