Overhaul random logic and implement battle seed

pull/14/head
Flashfyre 2024-01-02 21:31:59 -05:00
parent 6558de01c4
commit e05bf78481
9 changed files with 121 additions and 96 deletions

View File

@ -260,7 +260,7 @@ export abstract class FieldPhase extends BattlePhase {
const aSpeed = a?.getBattleStat(Stat.SPD) || 0;
const bSpeed = b?.getBattleStat(Stat.SPD) || 0;
return aSpeed < bSpeed ? 1 : aSpeed > bSpeed ? -1 : !Utils.randInt(2) ? -1 : 1;
return aSpeed < bSpeed ? 1 : aSpeed > bSpeed ? -1 : !this.scene.currentBattle.randSeedInt(2) ? -1 : 1;
});
const speedReversed = new Utils.BooleanHolder(false);
@ -1692,7 +1692,7 @@ export class MovePhase extends BattlePhase {
switch (this.pokemon.status.effect) {
case StatusEffect.PARALYSIS:
if (Utils.randInt(4) === 0) {
if (!this.pokemon.randSeedInt(4)) {
activated = true;
this.cancelled = true;
}
@ -1704,7 +1704,7 @@ export class MovePhase extends BattlePhase {
this.cancelled = activated;
break;
case StatusEffect.FREEZE:
healed = Utils.randInt(5) === 0;
healed = !this.pokemon.randSeedInt(5);
activated = !healed;
this.cancelled = activated;
break;
@ -1919,7 +1919,7 @@ export class MoveEffectPhase extends PokemonPhase {
applyAbAttrs(IgnoreOpponentStatChangesAbAttr, target, null, userAccuracyLevel);
applyAbAttrs(IgnoreOpponentStatChangesAbAttr, this.getUserPokemon(), null, targetEvasionLevel);
this.scene.applyModifiers(TempBattleStatBoosterModifier, this.player, TempBattleStat.ACC, userAccuracyLevel);
const rand = Utils.randInt(100, 1);
const rand = this.getUserPokemon().randSeedInt(100, 1);
let accuracyMultiplier = 1;
if (userAccuracyLevel.value !== targetEvasionLevel.value) {
accuracyMultiplier = userAccuracyLevel.value > targetEvasionLevel.value
@ -2020,9 +2020,8 @@ export class StatChangePhase extends PokemonPhase {
constructor(scene: BattleScene, battlerIndex: BattlerIndex, selfTarget: boolean, stats: BattleStat[], levels: integer) {
super(scene, battlerIndex);
const allStats = Utils.getEnumValues(BattleStat);
this.selfTarget = selfTarget;
this.stats = stats.map(s => s !== BattleStat.RAND ? s : allStats[Utils.randInt(BattleStat.SPD + 1)]);
this.stats = stats;
this.levels = levels;
}
@ -2032,7 +2031,8 @@ export class StatChangePhase extends PokemonPhase {
if (pokemon.isFainted())
return this.end();
const filteredStats = this.stats.filter(stat => {
const allStats = Utils.getEnumValues(BattleStat);
const filteredStats = this.stats.map(s => s !== BattleStat.RAND ? s : allStats[pokemon.randSeedInt(BattleStat.SPD + 1)]).filter(stat => {
const cancelled = new Utils.BooleanHolder(false);
if (!this.selfTarget && this.levels < 0)
@ -3046,7 +3046,7 @@ export class AttemptCapturePhase extends PokemonPhase {
shakeCounter.stop();
this.failCatch(shakeCount);
} else if (shakeCount++ < 3) {
if (Utils.randInt(65536) < y)
if (pokemon.randSeedInt(65536) < y)
this.scene.playSound('pb_move');
else {
shakeCounter.stop();
@ -3190,7 +3190,7 @@ export class AttemptRunPhase extends PokemonPhase {
const escapeChance = new Utils.IntegerHolder((((playerPokemon.getStat(Stat.SPD) * 128) / enemySpeed) + (30 * this.scene.currentBattle.escapeAttempts++)) % 256);
applyAbAttrs(RunSuccessAbAttr, playerPokemon, null, escapeChance);
if (Utils.randInt(256) < escapeChance.value) {
if (playerPokemon.randSeedInt(256) < escapeChance.value) {
this.scene.playSound('flee');
this.scene.queueMessage('You got away safely!', null, true, 500);

View File

@ -48,6 +48,8 @@ export default class Battle {
public playerParticipantIds: Set<integer> = new Set<integer>();
public escapeAttempts: integer = 0;
public lastMove: Moves;
public battleSeed: string;
private battleSeedState: string;
constructor(waveIndex: integer, battleType: BattleType, trainer: Trainer, double: boolean) {
this.waveIndex = waveIndex;
@ -61,6 +63,8 @@ export default class Battle {
this.double = double;
this.turn = 0;
this.started = false;
this.battleSeed = Utils.randomString(16, true);
this.battleSeedState = null;
}
private getLevelForWave(): integer {
@ -86,6 +90,7 @@ export default class Battle {
incrementTurn(scene: BattleScene): void {
this.turn++;
this.turnCommands = Object.fromEntries(Utils.getEnumValues(BattlerIndex).map(bt => [ bt, null ]));
this.battleSeedState = null;
}
addParticipant(playerPokemon: PlayerPokemon): void {
@ -120,6 +125,19 @@ export default class Battle {
return null;
}
randSeedInt(range: integer, min: integer = 0): integer {
let ret: integer;
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) ]);
ret = Utils.randSeedInt(range, min);
this.battleSeedState = Phaser.Math.RND.state();
Phaser.Math.RND.state(state);
return ret;
}
}
export class FixedBattle extends Battle {

View File

@ -347,8 +347,8 @@ export class PostDefendContactApplyStatusEffectAbAttr extends PostDefendAbAttr {
}
applyPostDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean {
if (move.getMove().checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && Utils.randInt(100) < this.chance && !pokemon.status) {
const effect = this.effects.length === 1 ? this.effects[0] : this.effects[Utils.randInt(this.effects.length)];
if (move.getMove().checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && pokemon.randSeedInt(100) < this.chance && !pokemon.status) {
const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)];
pokemon.scene.unshiftPhase(new ObtainStatusEffectPhase(pokemon.scene, attacker.getBattlerIndex(), effect));
}
@ -370,7 +370,7 @@ export class PostDefendContactApplyTagChanceAbAttr extends PostDefendAbAttr {
}
applyPostDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean {
if (move.getMove().checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && Utils.randInt(100) < this.chance)
if (move.getMove().checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && pokemon.randSeedInt(100) < this.chance)
return attacker.addTag(this.tagType, this.turnCount, move.moveId, pokemon.id);
return false;
@ -490,7 +490,7 @@ export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr {
if (hitResult < HitResult.NO_EFFECT && (!this.condition || this.condition(pokemon, defender, move.getMove()))) {
const heldItems = this.getTargetHeldItems(defender).filter(i => i.getTransferrable(false));
if (heldItems.length) {
const stolenItem = heldItems[Utils.randInt(heldItems.length)];
const stolenItem = heldItems[pokemon.randSeedInt(heldItems.length)];
pokemon.scene.tryTransferHeldItemModifier(stolenItem, pokemon, false, false).then(success => {
if (success)
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` stole\n${defender.name}'s ${stolenItem.type.name}!`));
@ -523,7 +523,7 @@ export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr {
if (hitResult < HitResult.NO_EFFECT && (!this.condition || this.condition(pokemon, attacker, move.getMove()))) {
const heldItems = this.getTargetHeldItems(attacker).filter(i => i.getTransferrable(false));
if (heldItems.length) {
const stolenItem = heldItems[Utils.randInt(heldItems.length)];
const stolenItem = heldItems[pokemon.randSeedInt(heldItems.length)];
pokemon.scene.tryTransferHeldItemModifier(stolenItem, pokemon, false, false).then(success => {
if (success)
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` stole\n${attacker.name}'s ${stolenItem.type.name}!`));

View File

@ -202,10 +202,10 @@ export class ConfusedTag extends BattlerTag {
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ' is\nconfused!'));
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), undefined, CommonAnim.CONFUSION));
if (Utils.randInt(2)) {
if (pokemon.randSeedInt(2)) {
const atk = pokemon.getBattleStat(Stat.ATK);
const def = pokemon.getBattleStat(Stat.DEF);
const damage = Math.ceil(((((2 * pokemon.level / 5 + 2) * 40 * atk / def) / 50) + 2) * (Utils.randInt(15, 85) / 100));
const damage = Math.ceil(((((2 * pokemon.level / 5 + 2) * 40 * atk / def) / 50) + 2) * (pokemon.randSeedInt(15, 85) / 100));
pokemon.scene.queueMessage('It hurt itself in its\nconfusion!');
pokemon.scene.unshiftPhase(new DamagePhase(pokemon.scene, pokemon.getBattlerIndex()));
pokemon.damage(damage);
@ -250,7 +250,7 @@ export class InfatuatedTag extends BattlerTag {
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` is in love\nwith ${pokemon.scene.getPokemonById(this.sourceId).name}!`));
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), undefined, CommonAnim.ATTRACT));
if (Utils.randInt(2)) {
if (pokemon.randSeedInt(2)) {
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ' is\nimmobilized by love!'));
(pokemon.scene.getCurrentPhase() as MovePhase).cancel();
}
@ -347,7 +347,7 @@ export class FrenzyTag extends BattlerTag {
onRemove(pokemon: Pokemon): void {
super.onRemove(pokemon);
pokemon.addTag(BattlerTagType.CONFUSED, Utils.randIntRange(1, 4) + 1);
pokemon.addTag(BattlerTagType.CONFUSED, pokemon.randSeedIntRange(2, 4));
}
}

View File

@ -1409,7 +1409,7 @@ export class RandomLevelDamageAttr extends FixedDamageAttr {
}
getDamage(user: Pokemon, target: Pokemon, move: Move): number {
return Math.max(Math.floor(user.level * (Utils.randIntRange(50, 150) * 0.01)), 1);
return Math.max(Math.floor(user.level * (user.randSeedIntRange(50, 150) * 0.01)), 1);
}
}
@ -1584,7 +1584,7 @@ export class MultiHitAttr extends MoveAttr {
switch (this.multiHitType) {
case MultiHitType._2_TO_5:
{
const rand = Utils.randInt(16);
const rand = user.randSeedInt(16);
const hitValue = new Utils.IntegerHolder(rand);
applyAbAttrs(MaxMultiHitAbAttr, user, null, hitValue);
if (hitValue.value >= 10)
@ -1609,7 +1609,7 @@ export class MultiHitAttr extends MoveAttr {
break;
case MultiHitType._1_TO_10:
{
const rand = Utils.randInt(90);
const rand = user.randSeedInt(90);
const hitValue = new Utils.IntegerHolder(rand);
applyAbAttrs(MaxMultiHitAbAttr, user, null, hitValue);
if (hitValue.value >= 81)
@ -1658,7 +1658,7 @@ export class StatusEffectAttr extends MoveEffectAttr {
}
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const statusCheck = move.chance < 0 || move.chance === 100 || Utils.randInt(100) < move.chance;
const statusCheck = move.chance < 0 || move.chance === 100 || user.randSeedInt(100) < move.chance;
if (statusCheck) {
const pokemon = this.selfTarget ? user : target;
if (pokemon.status) {
@ -1689,7 +1689,7 @@ export class StealHeldItemAttr extends MoveEffectAttr {
return new Promise<boolean>(resolve => {
const heldItems = this.getTargetHeldItems(target).filter(i => i.getTransferrable(false));
if (heldItems.length) {
const stolenItem = heldItems[Utils.randInt(heldItems.length)];
const stolenItem = heldItems[user.randSeedInt(heldItems.length)];
user.scene.tryTransferHeldItemModifier(stolenItem, user, false, false).then(success => {
if (success)
user.scene.queueMessage(getPokemonMessage(user, ` stole\n${target.name}'s ${stolenItem.type.name}!`));
@ -1933,7 +1933,7 @@ export class StatChangeAttr extends MoveEffectAttr {
if (!super.apply(user, target, move, args) || (this.condition && !this.condition(user, target, move)))
return false;
if (move.chance < 0 || move.chance === 100 || Utils.randInt(100) < move.chance) {
if (move.chance < 0 || move.chance === 100 || user.randSeedInt(100) < move.chance) {
const levels = this.getLevels(user);
user.scene.unshiftPhase(new StatChangePhase(user.scene, (this.selfTarget ? user : target).getBattlerIndex(), this.selfTarget, this.stats, levels));
return true;
@ -2321,7 +2321,7 @@ export class FrenzyAttr extends MoveEffectAttr {
if (!user.getMoveQueue().length) {
if (!user.getTag(BattlerTagType.FRENZY)) {
const turnCount = Utils.randIntRange(3, 4);
const turnCount = user.randSeedIntRange(2, 3);
new Array(turnCount).fill(null).map(() => user.getMoveQueue().push({ move: move.id, targets: [ target.getBattlerIndex() ], ignorePP: true }));
user.addTag(BattlerTagType.FRENZY, 1, move.id, user.id);
} else {
@ -2345,14 +2345,16 @@ export const frenzyMissFunc: UserMoveCondition = (user: Pokemon, move: Move) =>
export class AddBattlerTagAttr extends MoveEffectAttr {
public tagType: BattlerTagType;
public turnCount: integer;
public turnCountMin: integer;
public turnCountMax: integer;
private failOnOverlap: boolean;
constructor(tagType: BattlerTagType, selfTarget?: boolean, turnCount?: integer, failOnOverlap?: boolean) {
constructor(tagType: BattlerTagType, selfTarget: boolean = false, failOnOverlap: boolean = false, turnCountMin: integer = 0, turnCountMax?: integer) {
super(selfTarget);
this.tagType = tagType;
this.turnCount = turnCount;
this.turnCountMin = turnCountMin;
this.turnCountMax = turnCountMax !== undefined ? turnCountMax : turnCountMin;
this.failOnOverlap = !!failOnOverlap;
}
@ -2361,8 +2363,8 @@ export class AddBattlerTagAttr extends MoveEffectAttr {
return false;
const chance = this.getTagChance(user, target, move);
if (chance < 0 || chance === 100 || Utils.randInt(100) < chance) {
(this.selfTarget ? user : target).addTag(this.tagType, this.turnCount, move.id, user.id);
if (chance < 0 || chance === 100 || user.randSeedInt(100) < chance) {
(this.selfTarget ? user : target).addTag(this.tagType, user.randSeedInt(this.turnCountMax - this.turnCountMin, this.turnCountMin), move.id, user.id);
return true;
}
@ -2454,13 +2456,13 @@ export class FlinchAttr extends AddBattlerTagAttr {
export class ConfuseAttr extends AddBattlerTagAttr {
constructor(selfTarget?: boolean) {
super(BattlerTagType.CONFUSED, selfTarget, Utils.randIntRange(1, 4) + 1);
super(BattlerTagType.CONFUSED, selfTarget, false, 2, 5);
}
}
export class TrapAttr extends AddBattlerTagAttr {
constructor(tagType: BattlerTagType) {
super(tagType, false, Utils.randIntRange(2, 5) + 1);
super(tagType, false, false, 3, 6);
}
}
@ -2472,12 +2474,12 @@ export class ProtectAttr extends AddBattlerTagAttr {
getCondition(): MoveCondition {
return ((user, target, move): boolean => {
let timesUsed = 0;
const moveHistory = user.getLastXMoves(-1);
const moveHistory = user.getLastXMoves();
let turnMove: TurnMove;
while (moveHistory.length && (turnMove = moveHistory.shift()).move === move.id && turnMove.result === MoveResult.SUCCESS)
timesUsed++;
if (timesUsed)
return !Utils.randInt(Math.pow(2, timesUsed));
return !user.randSeedInt(Math.pow(2, timesUsed));
return true;
});
}
@ -2485,7 +2487,7 @@ export class ProtectAttr extends AddBattlerTagAttr {
export class IgnoreAccuracyAttr extends AddBattlerTagAttr {
constructor() {
super(BattlerTagType.IGNORE_ACCURACY, true, 1);
super(BattlerTagType.IGNORE_ACCURACY, true, false, 1);
}
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
@ -2500,14 +2502,14 @@ export class IgnoreAccuracyAttr extends AddBattlerTagAttr {
export class FaintCountdownAttr extends AddBattlerTagAttr {
constructor() {
super(BattlerTagType.PERISH_SONG, false, 4, true);
super(BattlerTagType.PERISH_SONG, false, true, 4);
}
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
if (!super.apply(user, target, move, args))
return false;
user.scene.queueMessage(getPokemonMessage(target, `\nwill faint in ${this.turnCount - 1} turns.`));
user.scene.queueMessage(getPokemonMessage(target, `\nwill faint in ${this.turnCountMin - 1} turns.`));
return true;
}
@ -2548,7 +2550,7 @@ export class AddArenaTagAttr extends MoveEffectAttr {
if (!super.apply(user, target, move, args))
return false;
if (move.chance < 0 || move.chance === 100 || Utils.randInt(100) < move.chance) {
if (move.chance < 0 || move.chance === 100 || user.randSeedInt(100) < move.chance) {
user.scene.arena.addTag(this.tagType, this.turnCount, move.id, user.id);
return true;
}
@ -2689,7 +2691,7 @@ export class RandomMovesetMoveAttr extends OverrideMoveEffectAttr {
const moveset = (!this.enemyMoveset ? user : target).getMoveset();
const moves = moveset.filter(m => !m.getMove().hasFlag(MoveFlags.IGNORE_VIRTUAL));
if (moves.length) {
const move = moves[Utils.randInt(moves.length)];
const move = moves[user.randSeedInt(moves.length)];
const moveIndex = moveset.findIndex(m => m.moveId === move.moveId);
const moveTargets = getMoveTargets(user, move.moveId);
if (!moveTargets.targets.length)
@ -2698,7 +2700,7 @@ export class RandomMovesetMoveAttr extends OverrideMoveEffectAttr {
? moveTargets.targets
: moveTargets.targets.indexOf(target.getBattlerIndex()) > -1
? [ target.getBattlerIndex() ]
: [ moveTargets.targets[Utils.randInt(moveTargets.targets.length)] ];
: [ moveTargets.targets[user.randSeedInt(moveTargets.targets.length)] ];
user.getMoveQueue().push({ move: move.moveId, targets: targets, ignorePP: this.enemyMoveset });
user.scene.unshiftPhase(new MovePhase(user.scene, user, targets, moveset[moveIndex], true));
return true;
@ -2712,7 +2714,7 @@ export class RandomMoveAttr extends OverrideMoveEffectAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise<boolean> {
return new Promise(resolve => {
const moveIds = Utils.getEnumValues(Moves).filter(m => !allMoves[m].hasFlag(MoveFlags.IGNORE_VIRTUAL));
const moveId = moveIds[Utils.randInt(moveIds.length)];
const moveId = moveIds[user.randSeedInt(moveIds.length)];
const moveTargets = getMoveTargets(user, moveId);
if (!moveTargets.targets.length) {
@ -2723,7 +2725,7 @@ export class RandomMoveAttr extends OverrideMoveEffectAttr {
? moveTargets.targets
: moveTargets.targets.indexOf(target.getBattlerIndex()) > -1
? [ target.getBattlerIndex() ]
: [ moveTargets.targets[Utils.randInt(moveTargets.targets.length)] ];
: [ moveTargets.targets[user.randSeedInt(moveTargets.targets.length)] ];
user.getMoveQueue().push({ move: moveId, targets: targets, ignorePP: true });
user.scene.unshiftPhase(new MovePhase(user.scene, user, targets, new PokemonMove(moveId, 0, 0, true), true));
initMoveAnim(moveId).then(() => {
@ -2760,7 +2762,7 @@ export class CopyMoveAttr extends OverrideMoveEffectAttr {
? moveTargets.targets
: moveTargets.targets.indexOf(target.getBattlerIndex()) > -1
? [ target.getBattlerIndex() ]
: [ moveTargets.targets[Utils.randInt(moveTargets.targets.length)] ];
: [ moveTargets.targets[user.randSeedInt(moveTargets.targets.length)] ];
user.getMoveQueue().push({ move: lastMove, targets: targets, ignorePP: true });
user.scene.unshiftPhase(new MovePhase(user.scene, user as PlayerPokemon, targets, new PokemonMove(lastMove, 0, 0, true), true));
@ -2945,7 +2947,7 @@ export function getMoveTargets(user: Pokemon, move: Moves): MoveTargetSet {
multiple = moveTarget !== MoveTarget.NEAR_ENEMY;
break;
case MoveTarget.RANDOM_NEAR_ENEMY:
set = [ opponents[Utils.randInt(opponents.length)] ];
set = [ opponents[user.randSeedInt(opponents.length)] ];
break;
case MoveTarget.ATTACKER:
return { targets: [ -1 as BattlerIndex ], multiple: false };
@ -3250,7 +3252,7 @@ export function initMoves() {
new StatusMove(Moves.REFLECT, "Reflect (N)", Type.PSYCHIC, -1, 20, 74, "A wondrous wall of light is put up to reduce damage from physical attacks for five turns.", -1, 0, 1)
.target(MoveTarget.USER_SIDE),
new SelfStatusMove(Moves.FOCUS_ENERGY, "Focus Energy", Type.NORMAL, -1, 30, -1, "The user takes a deep breath and focuses so that critical hits land more easily.", -1, 0, 1)
.attr(AddBattlerTagAttr, BattlerTagType.CRIT_BOOST, true, undefined, true),
.attr(AddBattlerTagAttr, BattlerTagType.CRIT_BOOST, true, true),
new AttackMove(Moves.BIDE, "Bide (N)", Type.NORMAL, MoveCategory.PHYSICAL, -1, -1, 10, -1, "The user endures attacks for two turns, then strikes back to cause double the damage taken.", -1, 1, 1)
.ignoresVirtual()
.target(MoveTarget.USER),
@ -3397,7 +3399,7 @@ export function initMoves() {
new AttackMove(Moves.THIEF, "Thief", Type.DARK, MoveCategory.PHYSICAL, 60, 100, 25, 18, "The user attacks and steals the target's held item simultaneously. The user can't steal anything if it already holds an item.", -1, 0, 2)
.attr(StealHeldItemAttr),
new StatusMove(Moves.SPIDER_WEB, "Spider Web", Type.BUG, -1, 10, -1, "The user ensnares the target with thin, gooey silk so it can't flee from battle.", -1, 0, 2)
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, 1, true),
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, true, 1),
new StatusMove(Moves.MIND_READER, "Mind Reader", Type.NORMAL, -1, 5, -1, "The user senses the target's movements with its mind to ensure its next attack does not miss the target.", -1, 0, 2)
.attr(IgnoreAccuracyAttr),
new StatusMove(Moves.NIGHTMARE, "Nightmare", Type.GHOST, 100, 15, -1, "A sleeping target sees a nightmare that inflicts some damage every turn.", -1, 0, 2)
@ -3501,7 +3503,7 @@ export function initMoves() {
new AttackMove(Moves.STEEL_WING, "Steel Wing", Type.STEEL, MoveCategory.PHYSICAL, 70, 90, 25, -1, "The target is hit with wings of steel. This may also raise the user's Defense stat.", 10, 0, 2)
.attr(StatChangeAttr, BattleStat.DEF, 1, true),
new StatusMove(Moves.MEAN_LOOK, "Mean Look", Type.NORMAL, -1, 5, -1, "The user pins the target with a dark, arresting look. The target becomes unable to flee.", -1, 0, 2)
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, 1, true),
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, true, 1),
new StatusMove(Moves.ATTRACT, "Attract", Type.NORMAL, 100, 15, -1, "If it is the opposite gender of the user, the target becomes infatuated and less likely to attack.", -1, 0, 2)
.attr(AddBattlerTagAttr, BattlerTagType.INFATUATED)
.condition((user, target, move) => user.isOppositeGender(target)),
@ -3538,7 +3540,7 @@ export function initMoves() {
.attr(ForceSwitchOutAttr, true, true)
.hidesUser(),
new StatusMove(Moves.ENCORE, "Encore", Type.NORMAL, 100, 5, 122, "The user compels the target to keep using the move it encored for three turns.", -1, 0, 2)
.attr(AddBattlerTagAttr, BattlerTagType.ENCORE, false, undefined, true)
.attr(AddBattlerTagAttr, BattlerTagType.ENCORE, false, true)
.condition((user, target, move) => new EncoreTag(move.id, user.id).canAdd(target)),
new AttackMove(Moves.PURSUIT, "Pursuit (N)", Type.DARK, MoveCategory.PHYSICAL, 40, 100, 20, -1, "The power of this attack move is doubled if it's used on a target that's switching out of battle.", -1, 0, 2),
new AttackMove(Moves.RAPID_SPIN, "Rapid Spin", Type.NORMAL, MoveCategory.PHYSICAL, 50, 100, 40, -1, "A spin attack that can also eliminate such moves as Bind, Wrap, and Leech Seed. This also raises the user's Speed stat.", 100, 0, 2)
@ -3642,7 +3644,7 @@ export function initMoves() {
.attr(RandomMovesetMoveAttr, true)
.ignoresVirtual(),
new SelfStatusMove(Moves.INGRAIN, "Ingrain", Type.GRASS, -1, 20, -1, "The user lays roots that restore its HP on every turn. Because it's rooted, it can't switch out.", -1, 0, 3)
.attr(AddBattlerTagAttr, BattlerTagType.INGRAIN, true, undefined, true),
.attr(AddBattlerTagAttr, BattlerTagType.INGRAIN, true, true),
new AttackMove(Moves.SUPERPOWER, "Superpower", Type.FIGHTING, MoveCategory.PHYSICAL, 120, 100, 5, -1, "The user attacks the target with great power. However, this also lowers the user's Attack and Defense stats.", 100, 0, 3)
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF ], -1, true),
new SelfStatusMove(Moves.MAGIC_COAT, "Magic Coat (N)", Type.PSYCHIC, -1, 15, -1, "Moves like Leech Seed and moves that inflict status conditions are blocked by a barrier and reflected back to the user of those moves.", -1, 4, 3),
@ -3650,7 +3652,7 @@ export function initMoves() {
new AttackMove(Moves.REVENGE, "Revenge (N)", Type.FIGHTING, MoveCategory.PHYSICAL, 60, 100, 10, -1, "This attack move's power is doubled if the user has been hurt by the opponent in the same turn.", -1, -4, 3),
new AttackMove(Moves.BRICK_BREAK, "Brick Break (N)", Type.FIGHTING, MoveCategory.PHYSICAL, 75, 100, 15, 58, "The user attacks with a swift chop. It can also break barriers, such as Light Screen and Reflect.", -1, 0, 3),
new StatusMove(Moves.YAWN, "Yawn", Type.NORMAL, -1, 10, -1, "The user lets loose a huge yawn that lulls the target into falling asleep on the next turn.", -1, 0, 3)
.attr(AddBattlerTagAttr, BattlerTagType.DROWSY, false, undefined, true)
.attr(AddBattlerTagAttr, BattlerTagType.DROWSY, false, true)
.condition((user, target, move) => !target.status),
new AttackMove(Moves.KNOCK_OFF, "Knock Off (N)", Type.DARK, MoveCategory.PHYSICAL, 65, 100, 20, -1, "The user slaps down the target's held item, and that item can't be used in that battle. The move does more damage if the target has a held item.", -1, 0, 3),
new AttackMove(Moves.ENDEAVOR, "Endeavor", Type.NORMAL, MoveCategory.PHYSICAL, -1, 100, 5, -1, "This attack move cuts down the target's HP to equal the user's HP.", -1, 0, 3)
@ -3782,7 +3784,7 @@ export function initMoves() {
new SelfStatusMove(Moves.IRON_DEFENSE, "Iron Defense", Type.STEEL, -1, 15, 104, "The user hardens its body's surface like iron, sharply raising its Defense stat.", -1, 0, 3)
.attr(StatChangeAttr, BattleStat.DEF, 2, true),
new StatusMove(Moves.BLOCK, "Block", Type.NORMAL, -1, 5, -1, "The user blocks the target's way with arms spread wide to prevent escape.", -1, 0, 3)
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, 1, true),
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, true, 1),
new StatusMove(Moves.HOWL, "Howl", Type.NORMAL, -1, 40, -1, "The user howls loudly to raise the spirit of itself and allies. This raises their Attack stats.", -1, 0, 3)
.attr(StatChangeAttr, BattleStat.ATK, 1, true)
.soundBased()
@ -3833,7 +3835,7 @@ export function initMoves() {
.attr(StatChangeAttr, BattleStat.SPATK, -2, true),
new SelfStatusMove(Moves.ROOST, "Roost", Type.FLYING, -1, 10, -1, "The user lands and rests its body. This move restores the user's HP by up to half of its max HP.", -1, 0, 4)
.attr(HealAttr, 0.5)
.attr(AddBattlerTagAttr, BattlerTagType.IGNORE_FLYING, true, 1),
.attr(AddBattlerTagAttr, BattlerTagType.IGNORE_FLYING, true, false, 1),
new StatusMove(Moves.GRAVITY, "Gravity", Type.PSYCHIC, -1, 5, -1, "This move enables Flying-type Pokémon or Pokémon with the Levitate Ability to be hit by Ground-type moves. Moves that involve flying can't be used.", -1, 0, 4)
.attr(AddArenaTagAttr, ArenaTagType.GRAVITY, 5)
.target(MoveTarget.BOTH_SIDES),
@ -3884,7 +3886,7 @@ export function initMoves() {
new SelfStatusMove(Moves.POWER_TRICK, "Power Trick (N)", Type.PSYCHIC, -1, 10, -1, "The user employs its psychic power to switch its Attack stat with its Defense stat.", -1, 0, 4),
new StatusMove(Moves.GASTRO_ACID, "Gastro Acid (N)", Type.POISON, 100, 10, -1, "The user hurls up its stomach acids on the target. The fluid eliminates the effect of the target's Ability.", -1, 0, 4),
new StatusMove(Moves.LUCKY_CHANT, "Lucky Chant (N)", Type.NORMAL, -1, 30, -1, "The user chants an incantation toward the sky, preventing opposing Pokémon from landing critical hits for five turns.", -1, 0, 4)
.attr(AddBattlerTagAttr, BattlerTagType.NO_CRIT, false, 5)
.attr(AddBattlerTagAttr, BattlerTagType.NO_CRIT, false, false, 5)
.target(MoveTarget.USER_SIDE),
new StatusMove(Moves.ME_FIRST, "Me First (N)", Type.NORMAL, -1, 20, -1, "The user cuts ahead of the target to copy and use the target's intended move with greater power. This move fails if it isn't used first.", -1, 0, 4)
.ignoresVirtual()
@ -3904,7 +3906,7 @@ export function initMoves() {
.target(MoveTarget.ENEMY_SIDE),
new StatusMove(Moves.HEART_SWAP, "Heart Swap (N)", Type.PSYCHIC, -1, 10, -1, "The user employs its psychic power to switch stat changes with the target.", -1, 0, 4),
new SelfStatusMove(Moves.AQUA_RING, "Aqua Ring", Type.WATER, -1, 20, -1, "The user envelops itself in a veil made of water. It regains some HP every turn.", -1, 0, 4)
.attr(AddBattlerTagAttr, BattlerTagType.AQUA_RING, true, undefined, true),
.attr(AddBattlerTagAttr, BattlerTagType.AQUA_RING, true, true),
new SelfStatusMove(Moves.MAGNET_RISE, "Magnet Rise (N)", Type.ELECTRIC, -1, 10, -1, "The user levitates using electrically generated magnetism for five turns.", -1, 0, 4),
new AttackMove(Moves.FLARE_BLITZ, "Flare Blitz", Type.FIRE, MoveCategory.PHYSICAL, 120, 100, 15, 165, "The user cloaks itself in fire and charges the target. This also damages the user quite a lot. This attack may leave the target with a burn.", 10, 0, 4)
.attr(RecoilAttr)
@ -4110,7 +4112,7 @@ export function initMoves() {
.ignoresProtect()
.target(MoveTarget.BOTH_SIDES),
new AttackMove(Moves.SMACK_DOWN, "Smack Down", Type.ROCK, MoveCategory.PHYSICAL, 50, 100, 15, -1, "The user throws a stone or similar projectile to attack the target. A flying Pokémon will fall to the ground when it's hit.", 100, 0, 5)
.attr(AddBattlerTagAttr, BattlerTagType.IGNORE_FLYING, false, 5)
.attr(AddBattlerTagAttr, BattlerTagType.IGNORE_FLYING, false, false, 5)
.makesContact(false),
new AttackMove(Moves.STORM_THROW, "Storm Throw", Type.FIGHTING, MoveCategory.PHYSICAL, 60, 100, 10, -1, "The user strikes the target with a fierce blow. This attack always results in a critical hit.", -1, 0, 5)
.attr(CritOnlyAttr),
@ -4402,10 +4404,10 @@ export function initMoves() {
new AttackMove(Moves.OBLIVION_WING, "Oblivion Wing", Type.FLYING, MoveCategory.SPECIAL, 80, 100, 10, -1, "The user absorbs its target's HP. The user's HP is restored by over half of the damage taken by the target.", -1, 0, 6)
.attr(HitHealAttr, 0.75),
new AttackMove(Moves.THOUSAND_ARROWS, "Thousand Arrows", Type.GROUND, MoveCategory.PHYSICAL, 90, 100, 10, -1, "This move also hits opposing Pokémon that are in the air. Those Pokémon are knocked down to the ground.", 100, 0, 6)
.attr(AddBattlerTagAttr, BattlerTagType.IGNORE_FLYING, false, 5)
.attr(AddBattlerTagAttr, BattlerTagType.IGNORE_FLYING, false, false, 5)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.THOUSAND_WAVES, "Thousand Waves", Type.GROUND, MoveCategory.PHYSICAL, 90, 100, 10, -1, "The user attacks with a wave that crawls along the ground. Those it hits can't flee from battle.", -1, 0, 6)
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, 1, true)
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, true, 1)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.LANDS_WRATH, "Land's Wrath", Type.GROUND, MoveCategory.PHYSICAL, 90, 100, 10, -1, "The user gathers the energy of the land and focuses that power on opposing Pokémon to damage them.", -1, 0, 6)
.target(MoveTarget.ALL_NEAR_ENEMIES),
@ -4608,7 +4610,7 @@ export function initMoves() {
new SelfStatusMove(Moves.STUFF_CHEEKS, "Stuff Cheeks (N)", Type.NORMAL, -1, 10, -1, "The user eats its held Berry, then sharply raises its Defense stat.", 100, 0, 8),
new SelfStatusMove(Moves.NO_RETREAT, "No Retreat", Type.FIGHTING, -1, 5, -1, "This move raises all the user's stats but prevents the user from switching out or fleeing.", 100, 0, 8)
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 1, true)
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, true, 1, true),
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, true, true, 1),
new StatusMove(Moves.TAR_SHOT, "Tar Shot (N)", Type.ROCK, 100, 15, -1, "The user pours sticky tar over the target, lowering the target's Speed stat. The target becomes weaker to Fire-type moves.", 100, 0, 8),
new StatusMove(Moves.MAGIC_POWDER, "Magic Powder (N)", Type.PSYCHIC, 100, 20, -1, "The user scatters a cloud of magic powder that changes the target to Psychic type.", -1, 0, 8)
.powderMove(),
@ -4617,7 +4619,7 @@ export function initMoves() {
new StatusMove(Moves.TEATIME, "Teatime (N)", Type.NORMAL, -1, 10, -1, "The user has teatime with all the Pokémon in the battle. Each Pokémon eats its held Berry.", -1, 0, 8)
.target(MoveTarget.ALL),
new StatusMove(Moves.OCTOLOCK, "Octolock (P)", Type.FIGHTING, 100, 15, -1, "The user locks the target in and prevents it from fleeing. This move also lowers the target's Defense and Sp. Def every turn.", -1, 0, 8)
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, 1, true),
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, true, 1),
new AttackMove(Moves.BOLT_BEAK, "Bolt Beak (N)", Type.ELECTRIC, MoveCategory.PHYSICAL, 85, 100, 10, -1, "The user stabs the target with its electrified beak. If the user attacks before the target, the power of this move is doubled.", -1, 0, 8),
new AttackMove(Moves.FISHIOUS_REND, "Fishious Rend (N)", Type.WATER, MoveCategory.PHYSICAL, 85, 100, 10, -1, "The user rends the target with its hard gills. If the user attacks before the target, the power of this move is doubled.", -1, 0, 8)
.bitingMove(),
@ -4965,7 +4967,7 @@ export function initMoves() {
new AttackMove(Moves.HARD_PRESS, "Hard Press", Type.STEEL, MoveCategory.PHYSICAL, 100, 100, 5, -1, "The target is crushed with an arm, a claw, or the like to inflict damage. The more HP the target has left, the greater the move's power.", -1, 0, 9)
.attr(OpponentHighHpPowerAttr),
new StatusMove(Moves.DRAGON_CHEER, "Dragon Cheer (P)", Type.DRAGON, -1, 15, -1, "The user raises its allies' morale with a draconic cry so that their future attacks have a heightened chance of landing critical hits. This rouses Dragon types more.", 100, 0, 9)
.attr(AddBattlerTagAttr, BattlerTagType.CRIT_BOOST, false, undefined, true)
.attr(AddBattlerTagAttr, BattlerTagType.CRIT_BOOST, false, true)
.target(MoveTarget.NEAR_ALLY),
new AttackMove(Moves.ALLURING_VOICE, "Alluring Voice (N)", Type.FAIRY, MoveCategory.SPECIAL, 80, 100, 10, -1, "The user attacks the target using its angelic voice. This also confuses the target if its stats have been boosted during the turn.", -1, 0, 9),
new AttackMove(Moves.TEMPER_FLARE, "Temper Flare (N)", Type.FIRE, MoveCategory.PHYSICAL, 75, 100, 10, -1, "Spurred by desperation, the user attacks the target. This move's power is doubled if the user's previous move failed.", -1, 0, 9),

View File

@ -16,13 +16,9 @@ export class Status {
public turnCount: integer;
public cureTurn: integer;
constructor(effect: StatusEffect, turnCount?: integer, cureTurn?: integer) {
constructor(effect: StatusEffect, turnCount: integer = 0, cureTurn?: integer) {
this.effect = effect;
this.turnCount = turnCount === undefined ? 0 : turnCount;
if (cureTurn === undefined) {
if (effect === StatusEffect.SLEEP)
this.cureTurn = Utils.randInt(3, 2);
} else
this.cureTurn = cureTurn;
}

View File

@ -565,7 +565,7 @@ export class SurviveDamageModifier extends PokemonHeldItemModifier {
const pokemon = args[0] as Pokemon;
const surviveDamage = args[1] as Utils.BooleanHolder;
if (!surviveDamage.value && Utils.randInt(10) < this.getStackCount()) {
if (!surviveDamage.value && pokemon.randSeedInt(10) < this.getStackCount()) {
surviveDamage.value = true;
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` hung on\nusing its ${this.type.name}!`));
@ -598,9 +598,10 @@ export class FlinchChanceModifier extends PokemonHeldItemModifier {
}
apply(args: any[]): boolean {
const pokemon = args[0] as Pokemon;
const flinched = args[1] as Utils.BooleanHolder;
if (!flinched.value && Utils.randInt(10) < this.getStackCount()) {
if (!flinched.value && pokemon.randSeedInt(10) < this.getStackCount()) {
flinched.value = true;
return true;
}
@ -741,7 +742,7 @@ export class BerryModifier extends PokemonHeldItemModifier {
}
const preserve = new Utils.BooleanHolder(false);
pokemon.scene.applyModifiers(PreserveBerryModifier, pokemon.isPlayer(), preserve);
pokemon.scene.applyModifiers(PreserveBerryModifier, pokemon.isPlayer(), pokemon, preserve);
getBerryEffectFunc(this.berryType)(pokemon);
if (!preserve.value)
@ -769,12 +770,12 @@ export class PreserveBerryModifier extends PersistentModifier {
}
shouldApply(args: any[]): boolean {
return super.shouldApply(args) && args[0] instanceof Utils.BooleanHolder;
return super.shouldApply(args) && args[0] instanceof Pokemon && args[1] instanceof Utils.BooleanHolder;
}
apply(args: any[]): boolean {
if (!(args[0] as Utils.BooleanHolder).value)
(args[0] as Utils.BooleanHolder).value = Utils.randInt(this.getMaxStackCount(null)) < this.getStackCount();
if (!(args[1] as Utils.BooleanHolder).value)
(args[1] as Utils.BooleanHolder).value = (args[0] as Pokemon).randSeedInt(this.getMaxStackCount(null)) < this.getStackCount();
return true;
}
@ -1396,7 +1397,7 @@ export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier {
if (!opponents.length)
return false;
const targetPokemon = opponents[Utils.randInt(opponents.length)];
const targetPokemon = opponents[pokemon.randSeedInt(opponents.length)];
const transferredItemCount = this.getTransferredItemCount();
if (!transferredItemCount)
@ -1413,7 +1414,7 @@ export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier {
for (let i = 0; i < transferredItemCount; i++) {
if (!itemModifiers.length)
break;
const randItemIndex = Utils.randInt(itemModifiers.length);
const randItemIndex = pokemon.randSeedInt(itemModifiers.length);
const randItem = itemModifiers[randItemIndex];
heldItemTransferPromises.push(pokemon.scene.tryTransferHeldItemModifier(randItem, pokemon, false, false, true).then(success => {
if (success) {

View File

@ -132,7 +132,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.fusionShiny = dataSource.fusionShiny;
this.fusionGender = dataSource.fusionGender;
} else {
this.id = Utils.randSeedInt(4294967295);
this.id = Utils.randSeedInt(4294967296);
this.ivs = ivs || [
Utils.binToDec(Utils.decToBin(this.id).substring(0, 5)),
Utils.binToDec(Utils.decToBin(this.id).substring(5, 10)),
@ -956,7 +956,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (source.getTag(BattlerTagType.CRIT_BOOST))
critLevel.value += 2;
const critChance = Math.ceil(16 / Math.pow(2, critLevel.value));
isCritical = !source.getTag(BattlerTagType.NO_CRIT) && !(this.getAbility().hasAttr(BlockCritAbAttr)) && (critChance === 1 || !Utils.randInt(critChance));
isCritical = !source.getTag(BattlerTagType.NO_CRIT) && !(this.getAbility().hasAttr(BlockCritAbAttr)) && (critChance === 1 || !this.scene.currentBattle.randSeedInt(critChance));
}
const sourceAtk = source.getBattleStat(isPhysical ? Stat.ATK : Stat.SPATK, this);
const targetDef = this.getBattleStat(isPhysical ? Stat.DEF : Stat.SPDEF, source);
@ -968,7 +968,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
applyAbAttrs(StabBoostAbAttr, source, null, stabMultiplier);
if (!isTypeImmune) {
damage.value = Math.ceil(((((2 * source.level / 5 + 2) * power.value * sourceAtk / targetDef) / 50) + 2) * stabMultiplier.value * typeMultiplier.value * weatherTypeMultiplier * ((Utils.randInt(15) + 85) / 100)) * criticalMultiplier;
damage.value = Math.ceil(((((2 * source.level / 5 + 2) * power.value * sourceAtk / targetDef) / 50) + 2) * stabMultiplier.value * typeMultiplier.value * weatherTypeMultiplier * ((this.scene.currentBattle.randSeedInt(15) + 85) / 100)) * criticalMultiplier;
if (isPhysical && source.status && source.status.effect === StatusEffect.BURN)
damage.value = Math.floor(damage.value / 2);
move.getAttrs(HitsTagAttr).map(hta => hta as HitsTagAttr).filter(hta => hta.doubleDamage).forEach(hta => {
@ -1087,14 +1087,14 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return this.species.speciesId === Species.ETERNATUS && this.formIndex === 1;
}
addTag(tagType: BattlerTagType, turnCount?: integer, sourceMove?: Moves, sourceId?: integer): boolean {
addTag(tagType: BattlerTagType, turnCount: integer = 0, sourceMove?: Moves, sourceId?: integer): boolean {
const existingTag = this.getTag(tagType);
if (existingTag) {
existingTag.onOverlap(this);
return false;
}
const newTag = getBattlerTag(tagType, turnCount || 0, sourceMove, sourceId);
const newTag = getBattlerTag(tagType, turnCount, sourceMove, sourceId);
const cancelled = new Utils.BooleanHolder(false);
applyPreApplyBattlerTagAbAttrs(PreApplyBattlerTagAbAttr, this, newTag, cancelled);
@ -1387,10 +1387,14 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (cancelled.value)
return false;
if (effect === StatusEffect.SLEEP)
this.setFrameRate(4);
let cureTurn: integer;
this.status = new Status(effect);
if (effect === StatusEffect.SLEEP) {
cureTurn = this.randSeedIntRange(2, 4);
this.setFrameRate(4);
}
this.status = new Status(effect, 0, cureTurn);
return true;
}
@ -1693,6 +1697,16 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
fusionCanvas.remove();
}
randSeedInt(range: integer, min: integer = 0): integer {
return this.scene.currentBattle
? this.scene.currentBattle.randSeedInt(range, min)
: Utils.randSeedInt(range, min);
}
randSeedIntRange(min: integer, max: integer): integer {
return this.randSeedInt((max - min) + 1, min);
}
destroy(): void {
this.battleInfo.destroy();
super.destroy();
@ -1958,7 +1972,7 @@ export class EnemyPokemon extends Pokemon {
}
switch (this.aiType) {
case AiType.RANDOM:
const moveId = movePool[Utils.randInt(movePool.length)].moveId;
const moveId = movePool[this.scene.currentBattle.randSeedInt(movePool.length)].moveId;
return { move: moveId, targets: this.getNextTargets(moveId) };
case AiType.SMART_RANDOM:
case AiType.SMART:
@ -1990,7 +2004,7 @@ export class EnemyPokemon extends Pokemon {
});
let r = 0;
if (this.aiType === AiType.SMART_RANDOM) {
while (r < sortedMovePool.length - 1 && Utils.randInt(8) >= 5)
while (r < sortedMovePool.length - 1 && this.scene.currentBattle.randSeedInt(8) >= 5)
r++;
}
console.log(movePool.map(m => m.getName()), moveScores, r, sortedMovePool.map(m => m.getName()));
@ -2043,7 +2057,7 @@ export class EnemyPokemon extends Pokemon {
return total;
}, 0);
const randValue = Utils.randInt(totalWeight);
const randValue = this.scene.currentBattle.randSeedInt(totalWeight);
let targetIndex: integer;
thresholds.every((t, i) => {

View File

@ -2,12 +2,12 @@ export function toReadableString(str: string): string {
return str.replace(/\_/g, ' ').split(' ').map(s => `${s.slice(0, 1)}${s.slice(1).toLowerCase()}`).join(' ');
}
export function randomString(length: integer) {
export function randomString(length: integer, seeded: boolean = false) {
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
for (let i = 0; i < length; i++) {
const randomIndex = Math.floor(Math.random() * characters.length);
const randomIndex = seeded ? randSeedInt(characters.length) : Math.floor(Math.random() * characters.length);
result += characters[randomIndex];
}
@ -56,17 +56,13 @@ export function padInt(value: integer, length: integer, padWith?: string): strin
return valueStr;
}
export function randInt(range: integer, min?: integer): integer {
if (!min)
min = 0;
export function randInt(range: integer, min: integer = 0): integer {
if (range === 1)
return min;
return Math.floor(Math.random() * range) + min;
}
export function randSeedInt(range: integer, min?: integer): integer {
if (!min)
min = 0;
export function randSeedInt(range: integer, min: integer = 0): integer {
if (range === 1)
return min;
return Phaser.Math.RND.integerInRange(min, (range - 1) + min);
@ -162,9 +158,7 @@ export function apiFetch(path: string): Promise<Response> {
});
}
export function apiPost(path: string, data?: any, contentType?: string): Promise<Response> {
if (!contentType)
contentType = 'application/json';
export function apiPost(path: string, data?: any, contentType: string = 'application/json'): Promise<Response> {
return new Promise((resolve, reject) => {
const headers = {
'Accept': contentType,