mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-25 16:59:27 +02:00
RNG Logging extension
Copied over every file that uses any RNG function, adding more logging and hopefully fixing RNG discrepancies
This commit is contained in:
parent
f0ec8b4a87
commit
dfcc5c9e87
@ -850,9 +850,9 @@ export default class BattleScene extends SceneBase {
|
||||
return activeOnly ? this.infoToggles.filter(t => t?.isActive()) : this.infoToggles;
|
||||
}
|
||||
|
||||
getPokemonById(pokemonId: integer): Pokemon | undefined {
|
||||
getPokemonById(pokemonId: integer): Pokemon | null {
|
||||
const findInParty = (party: Pokemon[]) => party.find(p => p.id === pokemonId);
|
||||
return (findInParty(this.getParty()) || findInParty(this.getEnemyParty())) || undefined;
|
||||
return (findInParty(this.getParty()) || findInParty(this.getEnemyParty())) ?? null;
|
||||
}
|
||||
|
||||
addPlayerPokemon(species: PokemonSpecies, level: integer, abilityIndex?: integer, formIndex?: integer, gender?: Gender, shiny?: boolean, variant?: Variant, ivs?: integer[], nature?: Nature, dataSource?: Pokemon | PokemonData, postProcess?: (playerPokemon: PlayerPokemon) => void): PlayerPokemon {
|
||||
@ -879,7 +879,7 @@ export default class BattleScene extends SceneBase {
|
||||
overrideModifiers(this, false);
|
||||
overrideHeldItems(this, pokemon, false);
|
||||
if (boss && !dataSource) {
|
||||
const secondaryIvs = Utils.getIvsFromId(Utils.randSeedInt(4294967296));
|
||||
const secondaryIvs = Utils.getIvsFromId(Utils.randSeedInt(4294967296, undefined, "IVs"));
|
||||
|
||||
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));
|
||||
@ -1196,12 +1196,12 @@ export default class BattleScene extends SceneBase {
|
||||
this.setScoreText(txt.join(" / "))
|
||||
}
|
||||
|
||||
newBattle(waveIndex?: integer, battleType?: BattleType, trainerData?: TrainerData, double?: boolean): Battle {
|
||||
newBattle(waveIndex?: integer, battleType?: BattleType, trainerData?: TrainerData, double?: boolean): Battle | null {
|
||||
const _startingWave = Overrides.STARTING_WAVE_OVERRIDE || startingWave;
|
||||
const newWaveIndex = waveIndex || ((this.currentBattle?.waveIndex || (_startingWave - 1)) + 1);
|
||||
var newDouble;
|
||||
var newBattleType;
|
||||
var newTrainer;
|
||||
let newDouble: boolean | undefined;
|
||||
let newBattleType: BattleType;
|
||||
let newTrainer: Trainer | undefined;
|
||||
|
||||
let battleConfig: FixedBattleConfig | null = null;
|
||||
|
||||
@ -1237,13 +1237,13 @@ export default class BattleScene extends SceneBase {
|
||||
const doubleChance = new Utils.IntegerHolder(newWaveIndex % 10 === 0 ? 32 : 8);
|
||||
this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance);
|
||||
playerField.forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, false, doubleChance));
|
||||
doubleTrainer = !Utils.randSeedInt(doubleChance.value);
|
||||
doubleTrainer = !Utils.randSeedInt(doubleChance.value, undefined, "Double battle roll");
|
||||
// Add a check that special trainers can't be double except for tate and liza - they should use the normal double chance
|
||||
if (trainerConfigs[trainerType].trainerTypeDouble && ![ TrainerType.TATE, TrainerType.LIZA ].includes(trainerType)) {
|
||||
doubleTrainer = false;
|
||||
}
|
||||
}
|
||||
const variant = doubleTrainer ? TrainerVariant.DOUBLE : (Utils.randSeedInt(2) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT);
|
||||
const variant = doubleTrainer ? TrainerVariant.DOUBLE : (Utils.randSeedInt(2, undefined, "Trainer gender") ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT);
|
||||
newTrainer = trainerData !== undefined ? trainerData.toTrainer(this) : new Trainer(this, trainerType, variant);
|
||||
this.field.add(newTrainer);
|
||||
}
|
||||
@ -1254,9 +1254,9 @@ export default class BattleScene extends SceneBase {
|
||||
const doubleChance = new Utils.IntegerHolder(newWaveIndex % 10 === 0 ? 32 : 8);
|
||||
this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance);
|
||||
playerField.forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, false, doubleChance));
|
||||
newDouble = !Utils.randSeedInt(doubleChance.value);
|
||||
newDouble = !Utils.randSeedInt(doubleChance.value, undefined, "Double battle roll");
|
||||
} else if (newBattleType === BattleType.TRAINER) {
|
||||
newDouble = newTrainer.variant === TrainerVariant.DOUBLE;
|
||||
newDouble = newTrainer?.variant === TrainerVariant.DOUBLE;
|
||||
}
|
||||
} else if (!battleConfig) {
|
||||
newDouble = !!double;
|
||||
@ -1408,19 +1408,19 @@ export default class BattleScene extends SceneBase {
|
||||
case Species.TATSUGIRI:
|
||||
case Species.GIMMIGHOUL:
|
||||
case Species.PALDEA_TAUROS:
|
||||
return Utils.randSeedInt(species.forms.length);
|
||||
return Utils.randSeedInt(species.forms.length, undefined, "General form selection");
|
||||
case Species.PIKACHU:
|
||||
return Utils.randSeedInt(8);
|
||||
return Utils.randSeedInt(8, undefined, "Pikachu form selection");
|
||||
case Species.EEVEE:
|
||||
return Utils.randSeedInt(2);
|
||||
return Utils.randSeedInt(2, undefined, "Eevee form selection");
|
||||
case Species.GRENINJA:
|
||||
return Utils.randSeedInt(2);
|
||||
return Utils.randSeedInt(2, undefined, "Greninja form selection");
|
||||
case Species.ZYGARDE:
|
||||
return Utils.randSeedInt(3);
|
||||
return Utils.randSeedInt(3, undefined, "Zygarde form selection");
|
||||
case Species.MINIOR:
|
||||
return Utils.randSeedInt(6);
|
||||
return Utils.randSeedInt(6, undefined, "Minior color selection");
|
||||
case Species.ALCREMIE:
|
||||
return Utils.randSeedInt(9);
|
||||
return Utils.randSeedInt(9, undefined, "Alcremie form selection");
|
||||
case Species.MEOWSTIC:
|
||||
case Species.INDEEDEE:
|
||||
case Species.BASCULEGION:
|
||||
@ -1440,7 +1440,7 @@ export default class BattleScene extends SceneBase {
|
||||
case Species.WORMADAM:
|
||||
case Species.ROTOM:
|
||||
case Species.LYCANROC:
|
||||
return Utils.randSeedInt(species.forms.length);
|
||||
return Utils.randSeedInt(species.forms.length, undefined, "Non-area-specific form selection");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -1451,7 +1451,7 @@ export default class BattleScene extends SceneBase {
|
||||
private getGeneratedOffsetGym(): boolean {
|
||||
let ret = false;
|
||||
this.executeWithSeedOffset(() => {
|
||||
ret = !Utils.randSeedInt(2);
|
||||
ret = !Utils.randSeedInt(2, undefined, "Random gym offset");
|
||||
}, 0, this.seed.toString());
|
||||
return ret;
|
||||
}
|
||||
@ -1459,7 +1459,7 @@ export default class BattleScene extends SceneBase {
|
||||
private getGeneratedWaveCycleOffset(): integer {
|
||||
let ret = 0;
|
||||
this.executeWithSeedOffset(() => {
|
||||
ret = Utils.randSeedInt(8) * 5;
|
||||
ret = Utils.randSeedInt(8, undefined, "Random day/night cycle offset 5 x") * 5;
|
||||
}, 0, this.seed.toString());
|
||||
return ret;
|
||||
}
|
||||
@ -1481,7 +1481,7 @@ export default class BattleScene extends SceneBase {
|
||||
isBoss = true;
|
||||
} else {
|
||||
this.executeWithSeedOffset(() => {
|
||||
isBoss = waveIndex % 10 === 0 || (this.gameMode.hasRandomBosses && Utils.randSeedInt(100) < Math.min(Math.max(Math.ceil((waveIndex - 250) / 50), 0) * 2, 30));
|
||||
isBoss = waveIndex % 10 === 0 || (this.gameMode.hasRandomBosses && Utils.randSeedInt(100, undefined, "Boss HP segments") < Math.min(Math.max(Math.ceil((waveIndex - 250) / 50), 0) * 2, 30));
|
||||
}, waveIndex << 2);
|
||||
}
|
||||
if (!isBoss) {
|
||||
@ -1819,7 +1819,7 @@ export default class BattleScene extends SceneBase {
|
||||
}
|
||||
return s;
|
||||
}))] : allSpecies.filter(s => s.isCatchable());
|
||||
return filteredSpecies[Utils.randSeedInt(filteredSpecies.length)];
|
||||
return filteredSpecies[Utils.randSeedInt(filteredSpecies.length, undefined, "Random Species")];
|
||||
}
|
||||
|
||||
generateRandomBiome(waveIndex: integer): Biome {
|
||||
@ -1835,7 +1835,7 @@ export default class BattleScene extends SceneBase {
|
||||
biomeThresholds.push(totalWeight);
|
||||
}
|
||||
|
||||
const randInt = Utils.randSeedInt(totalWeight);
|
||||
const randInt = Utils.randSeedInt(totalWeight, undefined, "Random biome");
|
||||
|
||||
for (const biome of biomes) {
|
||||
if (randInt < biomeThresholds[biome]) {
|
||||
@ -1843,7 +1843,7 @@ export default class BattleScene extends SceneBase {
|
||||
}
|
||||
}
|
||||
|
||||
return biomes[Utils.randSeedInt(biomes.length)];
|
||||
return biomes[Utils.randSeedInt(biomes.length, undefined, "Random biome (initial roll failed)")];
|
||||
}
|
||||
|
||||
isBgmPlaying(): boolean {
|
||||
@ -2665,7 +2665,7 @@ export default class BattleScene extends SceneBase {
|
||||
pokemonModifierChance = Math.ceil(pokemonModifierChance * this.currentBattle.trainer.getPartyMemberModifierChanceMultiplier(i)); // eslint-disable-line
|
||||
let count = 0;
|
||||
for (let c = 0; c < chances; c++) {
|
||||
if (!Utils.randSeedInt(modifierChance)) {
|
||||
if (!Utils.randSeedInt(modifierChance, undefined, "Modifier roll")) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
@ -2790,7 +2790,7 @@ export default class BattleScene extends SceneBase {
|
||||
if (mods.length < 1) {
|
||||
return mods;
|
||||
}
|
||||
const rand = Utils.randSeedInt(mods.length);
|
||||
const rand = Utils.randSeedInt(mods.length, undefined, "Apply shuffled modifiers");
|
||||
return [mods[rand], ...shuffleModifiers(mods.filter((_, i) => i !== rand))];
|
||||
};
|
||||
modifiers = shuffleModifiers(modifiers);
|
||||
|
@ -387,7 +387,7 @@ export default class Battle {
|
||||
* @param min The minimum integer to pick, default `0`
|
||||
* @returns A random integer between {@linkcode min} and ({@linkcode min} + {@linkcode range} - 1)
|
||||
*/
|
||||
randSeedInt(scene: BattleScene, range: number, min: number = 0, reason: string = "Unlabeled randSeedInt"): number {
|
||||
randSeedInt(scene: BattleScene, range: number, min: number = 0, reason?: string): number {
|
||||
if (range <= 1) {
|
||||
return min;
|
||||
}
|
||||
@ -402,8 +402,7 @@ export default class Battle {
|
||||
}
|
||||
scene.rngCounter = this.rngCounter++;
|
||||
scene.rngSeedOverride = this.battleSeed;
|
||||
const ret = Utils.randSeedInt(range, min);
|
||||
console.log("[RNG] " + reason, ret)
|
||||
const ret = Utils.randSeedInt(range, min, reason);
|
||||
this.battleSeedState = Phaser.Math.RND.state();
|
||||
Phaser.Math.RND.state(state);
|
||||
//scene.setScoreText("RNG: " + tempRngCounter + " (Last sim: " + this.rngCounter + ")")
|
||||
@ -474,7 +473,7 @@ function getRandomTrainerFunc(trainerPool: (TrainerType | TrainerType[])[], rand
|
||||
scene.executeWithSeedOffset(() => {
|
||||
for (const trainerPoolEntry of trainerPool) {
|
||||
const trainerType = Array.isArray(trainerPoolEntry)
|
||||
? Utils.randSeedItem(trainerPoolEntry)
|
||||
? Utils.randSeedItem(trainerPoolEntry, "Random trainer helper function")
|
||||
: trainerPoolEntry;
|
||||
trainerTypes.push(trainerType);
|
||||
}
|
||||
@ -482,7 +481,7 @@ function getRandomTrainerFunc(trainerPool: (TrainerType | TrainerType[])[], rand
|
||||
|
||||
let trainerGender = TrainerVariant.DEFAULT;
|
||||
if (randomGender) {
|
||||
trainerGender = (Utils.randInt(2) === 0) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT;
|
||||
trainerGender = (Utils.randInt(2, undefined, "Random trainer helper function") === 0) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT;
|
||||
}
|
||||
|
||||
/* 1/3 chance for evil team grunts to be double battles */
|
||||
@ -490,7 +489,7 @@ function getRandomTrainerFunc(trainerPool: (TrainerType | TrainerType[])[], rand
|
||||
const isEvilTeamGrunt = evilTeamGrunts.includes(trainerTypes[rand]);
|
||||
|
||||
if (trainerConfigs[trainerTypes[rand]].hasDouble && isEvilTeamGrunt) {
|
||||
return new Trainer(scene, trainerTypes[rand], (Utils.randInt(3) === 0) ? TrainerVariant.DOUBLE : trainerGender);
|
||||
return new Trainer(scene, trainerTypes[rand], (Utils.randInt(3, undefined, "Evil grunt selection") === 0) ? TrainerVariant.DOUBLE : trainerGender);
|
||||
}
|
||||
|
||||
return new Trainer(scene, trainerTypes[rand], trainerGender);
|
||||
@ -511,7 +510,7 @@ export interface FixedBattleConfigs {
|
||||
*/
|
||||
export const classicFixedBattles: FixedBattleConfigs = {
|
||||
[5]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.YOUNGSTER, Utils.randSeedInt(2) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)),
|
||||
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.YOUNGSTER, Utils.randSeedInt(2, undefined, "Youngster gender") ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)),
|
||||
[8]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
||||
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)),
|
||||
[25]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
||||
|
@ -859,7 +859,7 @@ export class PostDefendContactApplyStatusEffectAbAttr extends PostDefendAbAttr {
|
||||
|
||||
applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
|
||||
if (move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && !attacker.status && (this.chance === -1 || pokemon.randSeedInt(100, undefined, "Random chance to apply effect after something makes contact") < this.chance)) {
|
||||
const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length, undefined, "Selecting an effect to apply")];
|
||||
const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length, undefined, "Choosing status to apply")];
|
||||
if (simulated) {
|
||||
return attacker.canSetStatus(effect, true, false, pokemon);
|
||||
} else {
|
||||
@ -1674,7 +1674,7 @@ export class PostAttackApplyStatusEffectAbAttr extends PostAttackAbAttr {
|
||||
applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
|
||||
/**Status inflicted by abilities post attacking are also considered additional effects.*/
|
||||
if (!attacker.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr) && !simulated && pokemon !== attacker && (!this.contactRequired || move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) && pokemon.randSeedInt(100, undefined, "Chance to apply status after attacking") < this.chance && !pokemon.status) {
|
||||
const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length, undefined, "Selecting a status to apply")];
|
||||
const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length, undefined, "Choosing effect to apply")];
|
||||
return attacker.trySetStatus(effect, true, pokemon);
|
||||
}
|
||||
|
||||
@ -1727,7 +1727,7 @@ export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr {
|
||||
if (!simulated && hitResult < HitResult.NO_EFFECT && (!this.condition || this.condition(pokemon, attacker, move))) {
|
||||
const heldItems = this.getTargetHeldItems(attacker).filter(i => i.isTransferrable);
|
||||
if (heldItems.length) {
|
||||
const stolenItem = heldItems[pokemon.randSeedInt(heldItems.length, undefined, "Choosing an item to steal")];
|
||||
const stolenItem = heldItems[pokemon.randSeedInt(heldItems.length, undefined, "Choosing item to steal (guaranteed steal)")];
|
||||
pokemon.scene.tryTransferHeldItemModifier(stolenItem, pokemon, false).then(success => {
|
||||
if (success) {
|
||||
pokemon.scene.queueMessage(i18next.t("abilityTriggers:postDefendStealHeldItem", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), attackerName: attacker.name, stolenItemType: stolenItem.type.name }));
|
||||
@ -2222,7 +2222,7 @@ export class PostSummonCopyAbilityAbAttr extends PostSummonAbAttr {
|
||||
|
||||
let target: Pokemon;
|
||||
if (targets.length > 1) {
|
||||
pokemon.scene.executeWithSeedOffset(() => target = Utils.randSeedItem(targets), pokemon.scene.currentBattle.waveIndex);
|
||||
pokemon.scene.executeWithSeedOffset(() => target = Utils.randSeedItem(targets, "Target to copy ability from"), pokemon.scene.currentBattle.waveIndex);
|
||||
} else {
|
||||
target = targets[0];
|
||||
}
|
||||
@ -2343,7 +2343,7 @@ export class PostSummonTransformAbAttr extends PostSummonAbAttr {
|
||||
|
||||
let target: Pokemon;
|
||||
if (targets.length > 1) {
|
||||
pokemon.scene.executeWithSeedOffset(() => target = Utils.randSeedItem(targets), pokemon.scene.currentBattle.waveIndex);
|
||||
pokemon.scene.executeWithSeedOffset(() => target = Utils.randSeedItem(targets, "Target to transform into"), pokemon.scene.currentBattle.waveIndex);
|
||||
} else {
|
||||
target = targets[0];
|
||||
}
|
||||
@ -2642,7 +2642,7 @@ export class ConfusionOnStatusEffectAbAttr extends PostAttackAbAttr {
|
||||
if (simulated) {
|
||||
return defender.canAddTag(BattlerTagType.CONFUSED);
|
||||
} else {
|
||||
return defender.addTag(BattlerTagType.CONFUSED, pokemon.randSeedIntRange(2, 5, "Duration of Confusion effect"), move.id, defender.id);
|
||||
return defender.addTag(BattlerTagType.CONFUSED, pokemon.randSeedIntRange(2, 5, "Chance to apply effect after attacking"), move.id, defender.id);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@ -3413,7 +3413,7 @@ export class PostTurnLootAbAttr extends PostTurnAbAttr {
|
||||
return true;
|
||||
}
|
||||
|
||||
const randomIdx = Utils.randSeedInt(berriesEaten.length);
|
||||
const randomIdx = Utils.randSeedInt(berriesEaten.length, undefined, "Randomly select a berry to regenerate");
|
||||
const chosenBerryType = berriesEaten[randomIdx];
|
||||
const chosenBerry = new BerryModifierType(chosenBerryType);
|
||||
berriesEaten.splice(randomIdx); // Remove berry from memory
|
||||
@ -3466,12 +3466,12 @@ export class MoodyAbAttr extends PostTurnAbAttr {
|
||||
|
||||
if (!simulated) {
|
||||
if (canRaise.length > 0) {
|
||||
const raisedStat = canRaise[pokemon.randSeedInt(canRaise.length)];
|
||||
const raisedStat = canRaise[pokemon.randSeedInt(canRaise.length, undefined, "Choosing a random raisable stat to increase")];
|
||||
canLower = canRaise.filter(s => s !== raisedStat);
|
||||
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ raisedStat ], 2));
|
||||
}
|
||||
if (canLower.length > 0) {
|
||||
const loweredStat = canLower[pokemon.randSeedInt(canLower.length)];
|
||||
const loweredStat = canLower[pokemon.randSeedInt(canLower.length, undefined, "Choosing a random lowerable stat to decrease")];
|
||||
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ loweredStat ], -1));
|
||||
}
|
||||
}
|
||||
@ -3909,7 +3909,7 @@ export class PostBattleLootAbAttr extends PostBattleAbAttr {
|
||||
applyPostBattle(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean {
|
||||
const postBattleLoot = pokemon.scene.currentBattle.postBattleLoot;
|
||||
if (!simulated && postBattleLoot.length) {
|
||||
const randItem = Utils.randSeedItem(postBattleLoot);
|
||||
const randItem = Utils.randSeedItem(postBattleLoot, "Randomly selecting item to Pickup");
|
||||
//@ts-ignore - TODO see below
|
||||
if (pokemon.scene.tryTransferHeldItemModifier(randItem, pokemon, true, 1, true)) { // TODO: fix. This is a promise!?
|
||||
postBattleLoot.splice(postBattleLoot.indexOf(randItem), 1);
|
||||
@ -5032,7 +5032,7 @@ export function initAbilities() {
|
||||
.bypassFaint()
|
||||
.ignorable(),
|
||||
new Ability(Abilities.SHED_SKIN, 3)
|
||||
.conditionalAttr(pokemon => !Utils.randSeedInt(3), PostTurnResetStatusAbAttr),
|
||||
.conditionalAttr(pokemon => !Utils.randSeedInt(3, undefined, "Random chance to activate Shed Skin"), PostTurnResetStatusAbAttr),
|
||||
new Ability(Abilities.GUTS, 3)
|
||||
.attr(BypassBurnDamageReductionAbAttr)
|
||||
.conditionalAttr(pokemon => !!pokemon.status || pokemon.hasAbility(Abilities.COMATOSE), StatMultiplierAbAttr, Stat.ATK, 1.5),
|
||||
@ -5247,7 +5247,7 @@ export function initAbilities() {
|
||||
.attr(PostDefendMoveDisableAbAttr, 30)
|
||||
.bypassFaint(),
|
||||
new Ability(Abilities.HEALER, 5)
|
||||
.conditionalAttr(pokemon => pokemon.getAlly() && Utils.randSeedInt(10) < 3, PostTurnResetStatusAbAttr, true),
|
||||
.conditionalAttr(pokemon => pokemon.getAlly() && Utils.randSeedInt(10, undefined, "Random chance to apply Healer") < 3, PostTurnResetStatusAbAttr, true),
|
||||
new Ability(Abilities.FRIEND_GUARD, 5)
|
||||
.ignorable()
|
||||
.unimplemented(),
|
||||
|
@ -483,7 +483,7 @@ export class ConfusedTag extends BattlerTag {
|
||||
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), undefined, CommonAnim.CONFUSION));
|
||||
|
||||
// 1/3 chance of hitting self with a 40 base power move
|
||||
if (pokemon.randSeedInt(3, undefined, "Self-hit confusion roll") === 0) {
|
||||
if (pokemon.randSeedInt(3, undefined, "Confusion chance") === 0) {
|
||||
const atk = pokemon.getEffectiveStat(Stat.ATK);
|
||||
const def = pokemon.getEffectiveStat(Stat.DEF);
|
||||
const damage = Utils.toDmgValue(((((2 * pokemon.level / 5 + 2) * 40 * atk / def) / 50) + 2) * (pokemon.randSeedIntRange(85, 100, "Damage roll for Confusion") / 100));
|
||||
|
@ -114,7 +114,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
|
||||
if (pokemon.battleData) {
|
||||
pokemon.battleData.berriesEaten.push(berryType);
|
||||
}
|
||||
const randStat = Utils.randSeedInt(Stat.SPD, Stat.ATK);
|
||||
const randStat = Utils.randSeedInt(Stat.SPD, Stat.ATK, "Randomly selecting a stat to raise");
|
||||
const stages = new Utils.NumberHolder(2);
|
||||
applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, stages);
|
||||
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ randStat ], stages.value));
|
||||
|
@ -7666,7 +7666,7 @@ export function initBiomes() {
|
||||
if (biome === Biome.END) {
|
||||
const biomeList = Object.keys(Biome).filter(key => !isNaN(Number(key)));
|
||||
biomeList.pop(); // Removes Biome.END from the list
|
||||
const randIndex = Utils.randInt(biomeList.length, 1); // Will never be Biome.TOWN
|
||||
const randIndex = Utils.randInt(biomeList.length, 1, "Traversing biomes"); // Will never be Biome.TOWN
|
||||
biome = Biome[biomeList[randIndex]];
|
||||
}
|
||||
const linkedBiomes: (Biome | [ Biome, integer ])[] = Array.isArray(biomeLinks[biome])
|
||||
|
@ -49,7 +49,7 @@ export function getDailyRunStarters(scene: BattleScene, seed: string): Starter[]
|
||||
const costSpecies = Object.keys(speciesStarters)
|
||||
.map(s => parseInt(s) as Species)
|
||||
.filter(s => speciesStarters[s] === cost);
|
||||
const randPkmSpecies = getPokemonSpecies(Utils.randSeedItem(costSpecies));
|
||||
const randPkmSpecies = getPokemonSpecies(Utils.randSeedItem(costSpecies, "Daily starters"));
|
||||
const starterSpecies = getPokemonSpecies(randPkmSpecies.getTrainerSpeciesForLevel(startingLevel, true, PartyMemberStrength.STRONGER));
|
||||
starters.push(getDailyRunStarter(scene, starterSpecies, startingLevel));
|
||||
}
|
||||
|
@ -151,7 +151,7 @@ export class Egg {
|
||||
this.checkForPityTierOverrides(eggOptions.scene!); // TODO: is this bang correct?
|
||||
}
|
||||
|
||||
this._id = eggOptions?.id ?? Utils.randInt(EGG_SEED, EGG_SEED * this._tier);
|
||||
this._id = eggOptions?.id ?? Utils.randInt(EGG_SEED, EGG_SEED * this._tier, "eg");
|
||||
|
||||
this._sourceType = eggOptions?.sourceType ?? undefined;
|
||||
this._hatchWaves = eggOptions?.hatchWaves ?? this.getEggTierDefaultHatchWaves();
|
||||
@ -223,14 +223,14 @@ export class Egg {
|
||||
let pokemonSpecies = getPokemonSpecies(this._species);
|
||||
// Special condition to have Phione eggs also have a chance of generating Manaphy
|
||||
if (this._species === Species.PHIONE) {
|
||||
pokemonSpecies = getPokemonSpecies(Utils.randSeedInt(MANAPHY_EGG_MANAPHY_RATE) ? Species.PHIONE : Species.MANAPHY);
|
||||
pokemonSpecies = getPokemonSpecies(Utils.randSeedInt(MANAPHY_EGG_MANAPHY_RATE, undefined, "Chance of Manaphy Egg not scamming you") ? Species.PHIONE : Species.MANAPHY);
|
||||
}
|
||||
|
||||
// Sets the hidden ability if a hidden ability exists and
|
||||
// the override is set or the egg hits the chance
|
||||
let abilityIndex: number | undefined = undefined;
|
||||
const sameSpeciesEggHACheck = (this._sourceType === EggSourceType.SAME_SPECIES_EGG && !Utils.randSeedInt(SAME_SPECIES_EGG_HA_RATE));
|
||||
const gachaEggHACheck = (!(this._sourceType === EggSourceType.SAME_SPECIES_EGG) && !Utils.randSeedInt(GACHA_EGG_HA_RATE));
|
||||
const sameSpeciesEggHACheck = (this._sourceType === EggSourceType.SAME_SPECIES_EGG && !Utils.randSeedInt(SAME_SPECIES_EGG_HA_RATE, undefined, "Hidden Ability chance (Candy egg)"));
|
||||
const gachaEggHACheck = (!(this._sourceType === EggSourceType.SAME_SPECIES_EGG) && !Utils.randSeedInt(GACHA_EGG_HA_RATE, undefined, "Hidden Ability chance (Gacha)"));
|
||||
if (pokemonSpecies.abilityHidden && (this._overrideHiddenAbility || sameSpeciesEggHACheck || gachaEggHACheck)) {
|
||||
abilityIndex = 2;
|
||||
}
|
||||
@ -240,7 +240,7 @@ export class Egg {
|
||||
ret.shiny = this._isShiny;
|
||||
ret.variant = this._variantTier;
|
||||
|
||||
const secondaryIvs = Utils.getIvsFromId(Utils.randSeedInt(4294967295));
|
||||
const secondaryIvs = Utils.getIvsFromId(Utils.randSeedInt(4294967295, undefined, "Egg IVs"));
|
||||
|
||||
for (let s = 0; s < ret.ivs.length; s++) {
|
||||
ret.ivs[s] = Math.max(ret.ivs[s], secondaryIvs[s]);
|
||||
|
@ -1980,6 +1980,13 @@ export class StatusEffectAttr extends MoveEffectAttr {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (user !== target && target.scene.arena.getTagOnSide(ArenaTagType.SAFEGUARD, target.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY)) {
|
||||
if (move.category === MoveCategory.STATUS) {
|
||||
user.scene.queueMessage(i18next.t("moveTriggers:safeguard", { targetName: getPokemonNameWithAffix(target)}));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if ((!pokemon.status || (pokemon.status.effect === this.effect && moveChance < 0))
|
||||
&& pokemon.trySetStatus(this.effect, true, user, this.cureTurn)) {
|
||||
applyPostAttackAbAttrs(ConfusionOnStatusEffectAbAttr, user, target, move, null, false, this.effect);
|
||||
@ -2004,7 +2011,7 @@ export class MultiStatusEffectAttr extends StatusEffectAttr {
|
||||
}
|
||||
|
||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||
this.effect = Utils.randSeedItem(this.effects);
|
||||
this.effect = Utils.randSeedItem(this.effects, "Selecting status effect to apply");
|
||||
const result = super.apply(user, target, move, args);
|
||||
return result;
|
||||
}
|
||||
@ -2080,6 +2087,7 @@ export class StealHeldItemChanceAttr extends MoveEffectAttr {
|
||||
}
|
||||
//*/
|
||||
|
||||
console.log("realInRange direct call @ StealHeldItemChanceAttr: " + rand)
|
||||
if (rand >= this.chance) {
|
||||
return resolve(false);
|
||||
}
|
||||
@ -2632,7 +2640,7 @@ export class StatStageChangeAttr extends MoveEffectAttr {
|
||||
}
|
||||
|
||||
const moveChance = this.getMoveChance(user, target, move, this.selfTarget, true);
|
||||
if (moveChance < 0 || moveChance === 100 || user.randSeedInt(100, undefined, "Chance to apply status condition") < moveChance) {
|
||||
if (moveChance < 0 || moveChance === 100 || user.randSeedInt(100, undefined, "Random chance to raise stat") < moveChance) {
|
||||
const stages = this.getLevels(user);
|
||||
user.scene.unshiftPhase(new StatStageChangePhase(user.scene, (this.selfTarget ? user : target).getBattlerIndex(), this.selfTarget, this.stats, stages, this.showMessage));
|
||||
return true;
|
||||
@ -2718,7 +2726,7 @@ export class AcupressureStatStageChangeAttr extends MoveEffectAttr {
|
||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean | Promise<boolean> {
|
||||
const randStats = BATTLE_STATS.filter(s => target.getStatStage(s) < 6);
|
||||
if (randStats.length > 0) {
|
||||
const boostStat = [randStats[user.randSeedInt(randStats.length)]];
|
||||
const boostStat = [randStats[user.randSeedInt(randStats.length, undefined, "Choosing stat to raise")]];
|
||||
user.scene.unshiftPhase(new StatStageChangePhase(user.scene, target.getBattlerIndex(), this.selfTarget, boostStat, 2));
|
||||
return true;
|
||||
}
|
||||
@ -3051,7 +3059,7 @@ export class BeatUpAttr extends VariablePowerAttr {
|
||||
const doublePowerChanceMessageFunc = (user: Pokemon, target: Pokemon, move: Move) => {
|
||||
let message: string = "";
|
||||
user.scene.executeWithSeedOffset(() => {
|
||||
const rand = Utils.randSeedInt(100);
|
||||
const rand = Utils.randSeedInt(100, undefined, "Doubled power chance (applying message)");
|
||||
if (rand < move.chance) {
|
||||
message = i18next.t("moveTriggers:goingAllOutForAttack", {pokemonName: getPokemonNameWithAffix(user)});
|
||||
}
|
||||
@ -3062,7 +3070,7 @@ const doublePowerChanceMessageFunc = (user: Pokemon, target: Pokemon, move: Move
|
||||
export class DoublePowerChanceAttr extends VariablePowerAttr {
|
||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||
let rand: integer;
|
||||
user.scene.executeWithSeedOffset(() => rand = Utils.randSeedInt(100), user.scene.currentBattle.turn << 6, user.scene.waveSeed);
|
||||
user.scene.executeWithSeedOffset(() => rand = Utils.randSeedInt(100, undefined, "Doubled power chance (applying move)"), user.scene.currentBattle.turn << 6, user.scene.waveSeed);
|
||||
if (rand! < move.chance) {
|
||||
const power = args[0] as Utils.NumberHolder;
|
||||
power.value *= 2;
|
||||
@ -3323,7 +3331,7 @@ const magnitudeMessageFunc = (user: Pokemon, target: Pokemon, move: Move) => {
|
||||
user.scene.executeWithSeedOffset(() => {
|
||||
const magnitudeThresholds = [ 5, 15, 35, 65, 75, 95 ];
|
||||
|
||||
const rand = Utils.randSeedInt(100);
|
||||
const rand = Utils.randSeedInt(100, undefined, "Magnitude selection (message)");
|
||||
|
||||
let m = 0;
|
||||
for (; m < magnitudeThresholds.length; m++) {
|
||||
@ -3346,7 +3354,7 @@ export class MagnitudePowerAttr extends VariablePowerAttr {
|
||||
|
||||
let rand: integer;
|
||||
|
||||
user.scene.executeWithSeedOffset(() => rand = Utils.randSeedInt(100), user.scene.currentBattle.turn << 6, user.scene.waveSeed);
|
||||
user.scene.executeWithSeedOffset(() => rand = Utils.randSeedInt(100, undefined, "Magnitude selection (move)"), user.scene.currentBattle.turn << 6, user.scene.waveSeed);
|
||||
|
||||
let m = 0;
|
||||
for (; m < magnitudeThresholds.length; m++) {
|
||||
@ -3471,7 +3479,7 @@ export class PresentPowerAttr extends VariablePowerAttr {
|
||||
*/
|
||||
const firstHit = (user.turnData.hitCount === user.turnData.hitsLeft);
|
||||
|
||||
const powerSeed = Utils.randSeedInt(firstHit ? 100 : 80);
|
||||
const powerSeed = Utils.randSeedInt(firstHit ? 100 : 80, undefined, "Present healing chance");
|
||||
if (powerSeed <= 40) {
|
||||
(args[0] as Utils.NumberHolder).value = 40;
|
||||
} else if (40 < powerSeed && powerSeed <= 70) {
|
||||
@ -3919,7 +3927,7 @@ export class ShellSideArmCategoryAttr extends VariableMoveCategoryAttr {
|
||||
} else if (atkRatio === specialRatio && args[1] == "SIM") {
|
||||
category.value = MoveCategory.PHYSICAL;
|
||||
return true;
|
||||
} else if (atkRatio === specialRatio && user.randSeedInt(2, undefined, "Randomly selecting an attack type for Shell Side Arm") === 0) {
|
||||
} else if (atkRatio === specialRatio && user.randSeedInt(2, undefined, "Random category for Shell Side Arm") === 0) {
|
||||
category.value = MoveCategory.PHYSICAL;
|
||||
return true;
|
||||
}
|
||||
@ -4394,7 +4402,7 @@ export class FrenzyAttr extends MoveEffectAttr {
|
||||
}
|
||||
|
||||
if (!user.getTag(BattlerTagType.FRENZY) && !user.getMoveQueue().length) {
|
||||
const turnCount = user.randSeedIntRange(1, 2, "Frenzy targeting");
|
||||
const turnCount = user.randSeedIntRange(1, 2, "Frenzy duration");
|
||||
new Array(turnCount).fill(null).map(() => user.getMoveQueue().push({ move: move.id, targets: [ target.getBattlerIndex() ], ignorePP: true }));
|
||||
user.addTag(BattlerTagType.FRENZY, turnCount, move.id, user.id);
|
||||
} else {
|
||||
@ -4446,8 +4454,8 @@ export class AddBattlerTagAttr extends MoveEffectAttr {
|
||||
}
|
||||
|
||||
const moveChance = this.getMoveChance(user, target, move, this.selfTarget, true);
|
||||
if (moveChance < 0 || moveChance === 100 || user.randSeedInt(100, undefined, "Chance to apply battler tag") < moveChance) {
|
||||
return (this.selfTarget ? user : target).addTag(this.tagType, user.randSeedIntRange(this.turnCountMin, this.turnCountMax, "Duration of effect"), move.id, user.id);
|
||||
if (moveChance < 0 || moveChance === 100 || user.randSeedInt(100, undefined, "Chance to add Battler Tag") < moveChance) {
|
||||
return (this.selfTarget ? user : target).addTag(this.tagType, user.randSeedIntRange(this.turnCountMin, this.turnCountMax, "Battler Tag duration"), move.id, user.id);
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -4572,7 +4580,7 @@ export class JawLockAttr extends AddBattlerTagAttr {
|
||||
}
|
||||
|
||||
const moveChance = this.getMoveChance(user, target, move, this.selfTarget);
|
||||
if (moveChance < 0 || moveChance === 100 || user.randSeedInt(100) < moveChance) {
|
||||
if (moveChance < 0 || moveChance === 100 || user.randSeedInt(100, undefined, "Chance to apply Trap tag (Jaw Lock)") < moveChance) {
|
||||
/**
|
||||
* Add the tag to both the user and the target.
|
||||
* The target's tag source is considered to be the user and vice versa
|
||||
@ -4666,6 +4674,17 @@ export class ConfuseAttr extends AddBattlerTagAttr {
|
||||
constructor(selfTarget?: boolean) {
|
||||
super(BattlerTagType.CONFUSED, selfTarget, false, 2, 5);
|
||||
}
|
||||
|
||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||
if (!this.selfTarget && target.scene.arena.getTagOnSide(ArenaTagType.SAFEGUARD, target.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY)) {
|
||||
if (move.category === MoveCategory.STATUS) {
|
||||
user.scene.queueMessage(i18next.t("moveTriggers:safeguard", { targetName: getPokemonNameWithAffix(target)}));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return super.apply(user, target, move, args);
|
||||
}
|
||||
}
|
||||
|
||||
export class RechargeAttr extends AddBattlerTagAttr {
|
||||
@ -4699,7 +4718,7 @@ export class ProtectAttr extends AddBattlerTagAttr {
|
||||
timesUsed++;
|
||||
}
|
||||
if (timesUsed) {
|
||||
return !user.randSeedInt(Math.pow(3, timesUsed), undefined, "Chance for Protect-like move to fail");
|
||||
return !user.randSeedInt(Math.pow(3, timesUsed), undefined, "Chance for Protection move to succeed");
|
||||
}
|
||||
return true;
|
||||
});
|
||||
@ -4855,7 +4874,7 @@ export class AddArenaTrapTagHitAttr extends AddArenaTagAttr {
|
||||
const moveChance = this.getMoveChance(user, target, move, this.selfTarget, true);
|
||||
const side = (this.selfSideTarget ? user : target).isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
|
||||
const tag = user.scene.arena.getTagOnSide(this.tagType, side) as ArenaTrapTag;
|
||||
if ((moveChance < 0 || moveChance === 100 || user.randSeedInt(100, undefined, "Chance to apply trap") < moveChance) && user.getLastXMoves(1)[0].result === MoveResult.SUCCESS) {
|
||||
if ((moveChance < 0 || moveChance === 100 || user.randSeedInt(100, undefined, "Chance to add arena tag on hit") < moveChance) && user.getLastXMoves(1)[0].result === MoveResult.SUCCESS) {
|
||||
user.scene.arena.addTag(this.tagType, 0, move.id, user.id, side);
|
||||
if (!tag) {
|
||||
return true;
|
||||
@ -5009,7 +5028,7 @@ export class RevivalBlessingAttr extends MoveEffectAttr {
|
||||
&& user.scene.getEnemyParty().findIndex(p => p.isFainted() && !p.isBoss()) > -1) {
|
||||
// Selects a random fainted pokemon
|
||||
const faintedPokemon = user.scene.getEnemyParty().filter(p => p.isFainted() && !p.isBoss());
|
||||
const pokemon = faintedPokemon[user.randSeedInt(faintedPokemon.length, undefined, "Randomly selecting a Pokemon to revive")];
|
||||
const pokemon = faintedPokemon[user.randSeedInt(faintedPokemon.length, undefined, "Choosing Pokemon to revive")];
|
||||
const slotIndex = user.scene.getEnemyParty().findIndex(p => pokemon.id === p.id);
|
||||
pokemon.resetStatus();
|
||||
pokemon.heal(Math.min(Utils.toDmgValue(0.5 * pokemon.getMaxHp()), pokemon.getMaxHp()));
|
||||
@ -5319,7 +5338,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[user.randSeedInt(moves.length, undefined, "Randomly selecting a known move")];
|
||||
const move = moves[user.randSeedInt(moves.length, undefined, "Choosing random move from moveset")];
|
||||
const moveIndex = moveset.findIndex(m => m?.moveId === move?.moveId);
|
||||
const moveTargets = getMoveTargets(user, move?.moveId!); // TODO: is this bang correct?
|
||||
if (!moveTargets.targets.length) {
|
||||
@ -6373,7 +6392,7 @@ export class ResistLastMoveTypeAttr extends MoveEffectAttr {
|
||||
if (!validTypes.length) {
|
||||
return false;
|
||||
}
|
||||
const type = validTypes[user.randSeedInt(validTypes.length, undefined, "Randomly selecting a type for Conversion2 that resists Type." + Utils.getEnumKeys(Type)[moveData.type])];
|
||||
const type = validTypes[user.randSeedInt(validTypes.length, undefined, "Choosing type to transform into (Conversion2)")];
|
||||
user.summonData.types = [ type ];
|
||||
user.scene.queueMessage(i18next.t("battle:transformedIntoType", {pokemonName: getPokemonNameWithAffix(user), type: Utils.toReadableString(Type[type])}));
|
||||
user.updateInfo();
|
||||
@ -7126,7 +7145,7 @@ export function initMoves() {
|
||||
.attr(FriendshipPowerAttr, true),
|
||||
new StatusMove(Moves.SAFEGUARD, Type.NORMAL, -1, 25, -1, 0, 2)
|
||||
.target(MoveTarget.USER_SIDE)
|
||||
.unimplemented(),
|
||||
.attr(AddArenaTagAttr, ArenaTagType.SAFEGUARD, 5, true, true),
|
||||
new StatusMove(Moves.PAIN_SPLIT, Type.NORMAL, -1, 20, -1, 0, 2)
|
||||
.attr(HpSplitAttr)
|
||||
.condition(failOnBossCondition),
|
||||
@ -7315,7 +7334,7 @@ export function initMoves() {
|
||||
.attr(RemoveScreensAttr),
|
||||
new StatusMove(Moves.YAWN, Type.NORMAL, -1, 10, -1, 0, 3)
|
||||
.attr(AddBattlerTagAttr, BattlerTagType.DROWSY, false, true)
|
||||
.condition((user, target, move) => !target.status),
|
||||
.condition((user, target, move) => !target.status && !target.scene.arena.getTagOnSide(ArenaTagType.SAFEGUARD, target.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY)),
|
||||
new AttackMove(Moves.KNOCK_OFF, Type.DARK, MoveCategory.PHYSICAL, 65, 100, 20, -1, 0, 3)
|
||||
.attr(MovePowerMultiplierAttr, (user, target, move) => target.getHeldItems().filter(i => i.isTransferrable).length > 0 ? 1.5 : 1)
|
||||
.attr(RemoveHeldItemAttr, false),
|
||||
@ -8866,8 +8885,8 @@ export function initMoves() {
|
||||
new AttackMove(Moves.SKITTER_SMACK, Type.BUG, MoveCategory.PHYSICAL, 70, 90, 10, 100, 0, 8)
|
||||
.attr(StatStageChangeAttr, [ Stat.SPATK ], -1),
|
||||
new AttackMove(Moves.BURNING_JEALOUSY, Type.FIRE, MoveCategory.SPECIAL, 70, 100, 5, 100, 0, 8)
|
||||
.target(MoveTarget.ALL_NEAR_ENEMIES)
|
||||
.partial(),
|
||||
.attr(StatusIfBoostedAttr, StatusEffect.BURN)
|
||||
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
||||
new AttackMove(Moves.LASH_OUT, Type.DARK, MoveCategory.PHYSICAL, 75, 100, 5, -1, 0, 8)
|
||||
.attr(MovePowerMultiplierAttr, (user, _target, _move) => user.turnData.statStagesDecreased ? 2 : 1),
|
||||
new AttackMove(Moves.POLTERGEIST, Type.GHOST, MoveCategory.PHYSICAL, 110, 90, 5, -1, 0, 8)
|
||||
@ -9316,12 +9335,11 @@ export function initMoves() {
|
||||
new AttackMove(Moves.HARD_PRESS, Type.STEEL, MoveCategory.PHYSICAL, -1, 100, 10, -1, 0, 9)
|
||||
.attr(OpponentHighHpPowerAttr, 100),
|
||||
new StatusMove(Moves.DRAGON_CHEER, Type.DRAGON, -1, 15, -1, 0, 9)
|
||||
.attr(AddBattlerTagAttr, BattlerTagType.CRIT_BOOST, false, true)
|
||||
.target(MoveTarget.NEAR_ALLY)
|
||||
.partial(),
|
||||
.attr(AddBattlerTagAttr, BattlerTagType.DRAGON_CHEER, false, true)
|
||||
.target(MoveTarget.NEAR_ALLY),
|
||||
new AttackMove(Moves.ALLURING_VOICE, Type.FAIRY, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 9)
|
||||
.soundBased()
|
||||
.partial(),
|
||||
.attr(AddBattlerTagIfBoostedAttr, BattlerTagType.CONFUSED)
|
||||
.soundBased(),
|
||||
new AttackMove(Moves.TEMPER_FLARE, Type.FIRE, MoveCategory.PHYSICAL, 75, 100, 10, -1, 0, 9)
|
||||
.attr(MovePowerMultiplierAttr, (user, target, move) => user.getLastXMoves(2)[1]?.result === MoveResult.MISS || user.getLastXMoves(2)[1]?.result === MoveResult.FAIL ? 2 : 1),
|
||||
new AttackMove(Moves.SUPERCELL_SLAM, Type.ELECTRIC, MoveCategory.PHYSICAL, 100, 95, 15, -1, 0, 9)
|
||||
|
@ -1157,7 +1157,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
||||
[Species.TANDEMAUS]: [
|
||||
new SpeciesFormEvolution(Species.MAUSHOLD, "", "three", 25, null, new SpeciesEvolutionCondition(p => {
|
||||
let ret = false;
|
||||
p.scene.executeWithSeedOffset(() => ret = !Utils.randSeedInt(4), p.id);
|
||||
p.scene.executeWithSeedOffset(() => ret = !Utils.randSeedInt(4, undefined, "Tandemaus form selection"), p.id);
|
||||
return ret;
|
||||
})),
|
||||
new SpeciesEvolution(Species.MAUSHOLD, 25, null, null)
|
||||
@ -1325,7 +1325,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
||||
new SpeciesFormEvolution(Species.DUDUNSPARCE, "", "three-segment", 32, null, new SpeciesEvolutionCondition(p => {
|
||||
let ret = false;
|
||||
if (p.moveset.filter(m => m?.moveId === Moves.HYPER_DRILL).length > 0) {
|
||||
p.scene.executeWithSeedOffset(() => ret = !Utils.randSeedInt(4), p.id);
|
||||
p.scene.executeWithSeedOffset(() => ret = !Utils.randSeedInt(4, undefined, "Dudunsparce form selection"), p.id);
|
||||
}
|
||||
return ret;
|
||||
}), SpeciesWildEvolutionDelay.LONG),
|
||||
|
@ -761,7 +761,7 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali
|
||||
return this.speciesId;
|
||||
}
|
||||
|
||||
const randValue = evolutionPool.size === 1 ? 0 : Utils.randSeedInt(totalWeight);
|
||||
const randValue = evolutionPool.size === 1 ? 0 : Utils.randSeedInt(totalWeight, undefined, "Random levelled species");
|
||||
|
||||
for (const weight of evolutionPool.keys()) {
|
||||
if (randValue < weight) {
|
||||
@ -3340,7 +3340,7 @@ export function getPokerusStarters(scene: BattleScene): PokemonSpecies[] {
|
||||
date.setUTCHours(0, 0, 0, 0);
|
||||
scene.executeWithSeedOffset(() => {
|
||||
while (pokerusStarters.length < starterCount) {
|
||||
const randomSpeciesId = parseInt(Utils.randSeedItem(Object.keys(speciesStarters)), 10);
|
||||
const randomSpeciesId = parseInt(Utils.randSeedItem(Object.keys(speciesStarters), "Get Pokerus starters"), 10);
|
||||
const species = getPokemonSpecies(randomSpeciesId);
|
||||
if (!pokerusStarters.includes(species)) {
|
||||
pokerusStarters.push(species);
|
||||
|
@ -994,7 +994,7 @@ function getGymLeaderPartyTemplate(scene: BattleScene) {
|
||||
|
||||
function getRandomPartyMemberFunc(speciesPool: Species[], trainerSlot: TrainerSlot = TrainerSlot.TRAINER, ignoreEvolution: boolean = false, postProcess?: (enemyPokemon: EnemyPokemon) => void): PartyMemberFunc {
|
||||
return (scene: BattleScene, level: integer, strength: PartyMemberStrength) => {
|
||||
let species = Utils.randSeedItem(speciesPool);
|
||||
let species = Utils.randSeedItem(speciesPool, "Get random party member");
|
||||
if (!ignoreEvolution) {
|
||||
species = getPokemonSpecies(species).getTrainerSpeciesForLevel(level, true, strength, scene.currentBattle.waveIndex);
|
||||
}
|
||||
@ -1015,9 +1015,9 @@ function getRandomTeraModifiers(party: EnemyPokemon[], count: integer, types?: T
|
||||
const ret: PersistentModifier[] = [];
|
||||
const partyMemberIndexes = new Array(party.length).fill(null).map((_, i) => i);
|
||||
for (let t = 0; t < Math.min(count, party.length); t++) {
|
||||
const randomIndex = Utils.randSeedItem(partyMemberIndexes);
|
||||
const randomIndex = Utils.randSeedItem(partyMemberIndexes, "Get random tera modifiers");
|
||||
partyMemberIndexes.splice(partyMemberIndexes.indexOf(randomIndex), 1);
|
||||
ret.push(modifierTypes.TERA_SHARD().generateType([], [Utils.randSeedItem(types ? types : party[randomIndex].getTypes())])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(party[randomIndex]) as PersistentModifier); // TODO: is the bang correct?
|
||||
ret.push(modifierTypes.TERA_SHARD().generateType([], [Utils.randSeedItem(types ? types : party[randomIndex].getTypes(), "Selecting Tera Type")])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(party[randomIndex]) as PersistentModifier); // TODO: is the bang correct?
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@ -1868,7 +1868,7 @@ export const trainerConfigs: TrainerConfigs = {
|
||||
p.setBoss(true, 2);
|
||||
p.generateAndPopulateMoveset();
|
||||
p.pokeball = PokeballType.MASTER_BALL;
|
||||
p.formIndex = Utils.randSeedInt(5);
|
||||
p.formIndex = Utils.randSeedInt(5, undefined, "Random form for Genesect");
|
||||
}))
|
||||
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.BASCULEGION, Species.JELLICENT ], TrainerSlot.TRAINER, true, p => {
|
||||
p.generateAndPopulateMoveset();
|
||||
|
@ -378,7 +378,7 @@ export function getRandomWeatherType(arena: any /* Importing from arena causes a
|
||||
let totalWeight = 0;
|
||||
weatherPool.forEach(w => totalWeight += w.weight);
|
||||
|
||||
const rand = Utils.randSeedInt(totalWeight);
|
||||
const rand = Utils.randSeedInt(totalWeight, undefined, "Weather selection");
|
||||
let w = 0;
|
||||
for (const weather of weatherPool) {
|
||||
w += weather.weight;
|
||||
|
@ -90,7 +90,7 @@ export class Arena {
|
||||
if (typeof luckValue !== "undefined") {
|
||||
luckModifier = luckValue * (isBoss ? 0.5 : 2);
|
||||
}
|
||||
const tierValue = Utils.randSeedInt(randVal - luckModifier);
|
||||
const tierValue = Utils.randSeedInt(randVal - luckModifier, undefined, "Selecting rarity tier for encounter");
|
||||
let tier = !isBoss
|
||||
? tierValue >= 156 ? BiomePoolTier.COMMON : tierValue >= 32 ? BiomePoolTier.UNCOMMON : tierValue >= 6 ? BiomePoolTier.RARE : tierValue >= 1 ? BiomePoolTier.SUPER_RARE : BiomePoolTier.ULTRA_RARE
|
||||
: tierValue >= 20 ? BiomePoolTier.BOSS : tierValue >= 6 ? BiomePoolTier.BOSS_RARE : tierValue >= 1 ? BiomePoolTier.BOSS_SUPER_RARE : BiomePoolTier.BOSS_ULTRA_RARE;
|
||||
@ -118,7 +118,7 @@ export class Arena {
|
||||
if (!tierPool.length) {
|
||||
ret = this.scene.randomSpecies(waveIndex, level);
|
||||
} else {
|
||||
const entry = tierPool[Utils.randSeedInt(tierPool.length)];
|
||||
const entry = tierPool[Utils.randSeedInt(tierPool.length, undefined, "Selecting rarity tier but for real this time")];
|
||||
let species: Species;
|
||||
if (typeof entry === "number") {
|
||||
species = entry as Species;
|
||||
@ -129,7 +129,7 @@ export class Arena {
|
||||
if (level >= levelThreshold) {
|
||||
const speciesIds = entry[levelThreshold];
|
||||
if (speciesIds.length > 1) {
|
||||
species = speciesIds[Utils.randSeedInt(speciesIds.length)];
|
||||
species = speciesIds[Utils.randSeedInt(speciesIds.length, undefined, "Randomly selecting encounter species")];
|
||||
} else {
|
||||
species = speciesIds[0];
|
||||
}
|
||||
@ -175,7 +175,7 @@ export class Arena {
|
||||
const isBoss = !!this.trainerPool[BiomePoolTier.BOSS].length
|
||||
&& this.scene.gameMode.isTrainerBoss(waveIndex, this.biomeType, this.scene.offsetGym);
|
||||
console.log(isBoss, this.trainerPool);
|
||||
const tierValue = Utils.randSeedInt(!isBoss ? 512 : 64);
|
||||
const tierValue = Utils.randSeedInt(!isBoss ? 512 : 64, undefined, "Selecting random trainer");
|
||||
let tier = !isBoss
|
||||
? tierValue >= 156 ? BiomePoolTier.COMMON : tierValue >= 32 ? BiomePoolTier.UNCOMMON : tierValue >= 6 ? BiomePoolTier.RARE : tierValue >= 1 ? BiomePoolTier.SUPER_RARE : BiomePoolTier.ULTRA_RARE
|
||||
: tierValue >= 20 ? BiomePoolTier.BOSS : tierValue >= 6 ? BiomePoolTier.BOSS_RARE : tierValue >= 1 ? BiomePoolTier.BOSS_SUPER_RARE : BiomePoolTier.BOSS_ULTRA_RARE;
|
||||
@ -185,7 +185,7 @@ export class Arena {
|
||||
tier--;
|
||||
}
|
||||
const tierPool = this.trainerPool[tier] || [];
|
||||
return !tierPool.length ? TrainerType.BREEDER : tierPool[Utils.randSeedInt(tierPool.length)];
|
||||
return !tierPool.length ? TrainerType.BREEDER : tierPool[Utils.randSeedInt(tierPool.length, undefined, "Selecting trainer type")];
|
||||
}
|
||||
|
||||
getSpeciesFormIndex(species: PokemonSpecies): integer {
|
||||
@ -303,7 +303,7 @@ export class Arena {
|
||||
|
||||
/**
|
||||
* Sets weather to the override specified in overrides.ts
|
||||
* @param weather new {@linkcode WeatherType} to set
|
||||
* @param weather new weather to set of type WeatherType
|
||||
* @returns true to force trySetWeather to return true
|
||||
*/
|
||||
trySetWeatherOverride(weather: WeatherType): boolean {
|
||||
@ -315,8 +315,8 @@ export class Arena {
|
||||
|
||||
/**
|
||||
* Attempts to set a new weather to the battle
|
||||
* @param weather {@linkcode WeatherType} new {@linkcode WeatherType} to set
|
||||
* @param hasPokemonSource boolean if the new weather is from a pokemon
|
||||
* @param weather new weather to set of type WeatherType
|
||||
* @param hasPokemonSource is the new weather from a pokemon
|
||||
* @returns true if new weather set, false if no weather provided or attempting to set the same weather as currently in use
|
||||
*/
|
||||
trySetWeather(weather: WeatherType, hasPokemonSource: boolean): boolean {
|
||||
@ -587,12 +587,6 @@ export class Arena {
|
||||
this.ignoreAbilities = ignoreAbilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies each `ArenaTag` in this Arena, based on which side (self, enemy, or both) is passed in as a parameter
|
||||
* @param tagType Either an {@linkcode ArenaTagType} string, or an actual {@linkcode ArenaTag} class to filter which ones to apply
|
||||
* @param side {@linkcode ArenaTagSide} which side's arena tags to apply
|
||||
* @param args array of parameters that the called upon tags may need
|
||||
*/
|
||||
applyTagsForSide(tagType: ArenaTagType | Constructor<ArenaTag>, side: ArenaTagSide, ...args: unknown[]): void {
|
||||
let tags = typeof tagType === "string"
|
||||
? this.tags.filter(t => t.tagType === tagType)
|
||||
@ -603,28 +597,11 @@ export class Arena {
|
||||
tags.forEach(t => t.apply(this, args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the specified tag to both sides (ie: both user and trainer's tag that match the Tag specified)
|
||||
* by calling {@linkcode applyTagsForSide()}
|
||||
* @param tagType Either an {@linkcode ArenaTagType} string, or an actual {@linkcode ArenaTag} class to filter which ones to apply
|
||||
* @param args array of parameters that the called upon tags may need
|
||||
*/
|
||||
applyTags(tagType: ArenaTagType | Constructor<ArenaTag>, ...args: unknown[]): void {
|
||||
this.applyTagsForSide(tagType, ArenaTagSide.BOTH, ...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new tag to the arena
|
||||
* @param tagType {@linkcode ArenaTagType} the tag being added
|
||||
* @param turnCount How many turns the tag lasts
|
||||
* @param sourceMove {@linkcode Moves} the move the tag came from, or `undefined` if not from a move
|
||||
* @param sourceId The ID of the pokemon in play the tag came from (see {@linkcode BattleScene.getPokemonById})
|
||||
* @param side {@linkcode ArenaTagSide} which side(s) the tag applies to
|
||||
* @param quiet If a message should be queued on screen to announce the tag being added
|
||||
* @param targetIndex The {@linkcode BattlerIndex} of the target pokemon
|
||||
* @returns `false` if there already exists a tag of this type in the Arena
|
||||
*/
|
||||
addTag(tagType: ArenaTagType, turnCount: number, sourceMove: Moves | undefined, sourceId: number, side: ArenaTagSide = ArenaTagSide.BOTH, quiet: boolean = false, targetIndex?: BattlerIndex): boolean {
|
||||
addTag(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves | undefined, sourceId: integer, side: ArenaTagSide = ArenaTagSide.BOTH, quiet: boolean = false, targetIndex?: BattlerIndex): boolean {
|
||||
const existingTag = this.getTagOnSide(tagType, side);
|
||||
if (existingTag) {
|
||||
existingTag.onOverlap(this);
|
||||
@ -637,7 +614,6 @@ export class Arena {
|
||||
return false;
|
||||
}
|
||||
|
||||
// creates a new tag object
|
||||
const newTag = getArenaTag(tagType, turnCount || 0, sourceMove, sourceId, targetIndex, side);
|
||||
if (newTag) {
|
||||
this.tags.push(newTag);
|
||||
@ -651,11 +627,6 @@ export class Arena {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to get a tag from the Arena via {@linkcode getTagOnSide} that applies to both sides
|
||||
* @param tagType The {@linkcode ArenaTagType} or {@linkcode ArenaTag} to get
|
||||
* @returns either the {@linkcode ArenaTag}, or `undefined` if it isn't there
|
||||
*/
|
||||
getTag(tagType: ArenaTagType | Constructor<ArenaTag>): ArenaTag | undefined {
|
||||
return this.getTagOnSide(tagType, ArenaTagSide.BOTH);
|
||||
}
|
||||
@ -664,35 +635,16 @@ export class Arena {
|
||||
return !!this.getTag(tagType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to get a tag from the Arena from a specific side (the tag passed in has to either apply to both sides, or the specific side only)
|
||||
*
|
||||
* eg: `MIST` only applies to the user's side, while `MUD_SPORT` applies to both user and enemy side
|
||||
* @param tagType The {@linkcode ArenaTagType} or {@linkcode ArenaTag} to get
|
||||
* @param side The {@linkcode ArenaTagSide} to look at
|
||||
* @returns either the {@linkcode ArenaTag}, or `undefined` if it isn't there
|
||||
*/
|
||||
getTagOnSide(tagType: ArenaTagType | Constructor<ArenaTag>, side: ArenaTagSide): ArenaTag | undefined {
|
||||
return typeof(tagType) === "string"
|
||||
? this.tags.find(t => t.tagType === tagType && (side === ArenaTagSide.BOTH || t.side === ArenaTagSide.BOTH || t.side === side))
|
||||
: this.tags.find(t => t instanceof tagType && (side === ArenaTagSide.BOTH || t.side === ArenaTagSide.BOTH || t.side === side));
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses {@linkcode findTagsOnSide} to filter (using the parameter function) for specific tags that apply to both sides
|
||||
* @param tagPredicate a function mapping {@linkcode ArenaTag}s to `boolean`s
|
||||
* @returns array of {@linkcode ArenaTag}s from which the Arena's tags return true and apply to both sides
|
||||
*/
|
||||
findTags(tagPredicate: (t: ArenaTag) => boolean): ArenaTag[] {
|
||||
return this.findTagsOnSide(tagPredicate, ArenaTagSide.BOTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns specific tags from the arena that pass the `tagPredicate` function passed in as a parameter, and apply to the given side
|
||||
* @param tagPredicate a function mapping {@linkcode ArenaTag}s to `boolean`s
|
||||
* @param side The {@linkcode ArenaTagSide} to look at
|
||||
* @returns array of {@linkcode ArenaTag}s from which the Arena's tags return `true` and apply to the given side
|
||||
*/
|
||||
findTagsOnSide(tagPredicate: (t: ArenaTag) => boolean, side: ArenaTagSide): ArenaTag[] {
|
||||
return this.tags.filter(t => tagPredicate(t) && (side === ArenaTagSide.BOTH || t.side === ArenaTagSide.BOTH || t.side === side));
|
||||
}
|
||||
@ -922,7 +874,7 @@ export class ArenaBase extends Phaser.GameObjects.Container {
|
||||
if (!this.player) {
|
||||
(this.scene as BattleScene).executeWithSeedOffset(() => {
|
||||
this.propValue = propValue === undefined
|
||||
? hasProps ? Utils.randSeedInt(8) : 0
|
||||
? hasProps ? Utils.randSeedInt(8, undefined, "Selecting biome prop(?)") : 0
|
||||
: propValue;
|
||||
this.props.forEach((prop, p) => {
|
||||
const propKey = `${biomeKey}_b${hasProps ? `_${p + 1}` : ""}`;
|
||||
|
@ -31,7 +31,7 @@ export default class PokemonSpriteSparkleHandler {
|
||||
const parent = (pokemon || s).parentContainer;
|
||||
const texture = s.texture;
|
||||
const [ width, height ] = [ texture.source[0].width, texture.source[0].height ];
|
||||
const [ pixelX, pixelY ] = [ Utils.randInt(width), Utils.randInt(height) ];
|
||||
const [ pixelX, pixelY ] = [ Utils.randInt(width, undefined, "Pixel X"), Utils.randInt(height, undefined, "Pixel Y") ];
|
||||
const ratioX = s.width / width;
|
||||
const ratioY = s.height / height;
|
||||
const pixel = texture.manager.getPixel(pixelX, pixelY, texture.key, "__BASE");
|
||||
|
@ -156,8 +156,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
this.abilityIndex = abilityIndex; // Use the provided ability index if it is defined
|
||||
} else {
|
||||
// If abilityIndex is not provided, determine it based on species and hidden ability
|
||||
const hasHiddenAbility = !Utils.randSeedInt(hiddenAbilityChance.value);
|
||||
const randAbilityIndex = Utils.randSeedInt(2);
|
||||
const hasHiddenAbility = !Utils.randSeedInt(hiddenAbilityChance.value, undefined, "Hidden Ability chance");
|
||||
const randAbilityIndex = Utils.randSeedInt(2, undefined, "Selecting ability index");
|
||||
if (species.abilityHidden && hasHiddenAbility) {
|
||||
// If the species has a hidden ability and the hidden ability is present
|
||||
this.abilityIndex = 2;
|
||||
@ -210,7 +210,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
this.fusionLuck = dataSource.fusionLuck;
|
||||
this.usedTMs = dataSource.usedTMs ?? [];
|
||||
} else {
|
||||
this.id = Utils.randSeedInt(4294967296);
|
||||
this.id = Utils.randSeedInt(4294967296, undefined, "Generating a Pokemon ID to create Pokemon's IVs");
|
||||
this.ivs = ivs || Utils.getIvsFromId(this.id);
|
||||
|
||||
if (this.gender === undefined) {
|
||||
@ -923,7 +923,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
if (naturePool === undefined) {
|
||||
naturePool = Utils.getEnumValues(Nature);
|
||||
}
|
||||
const nature = naturePool[Utils.randSeedInt(naturePool.length)];
|
||||
const nature = naturePool[Utils.randSeedInt(naturePool.length, undefined, "Random nature")];
|
||||
this.setNature(nature);
|
||||
}
|
||||
|
||||
@ -1451,26 +1451,22 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
}
|
||||
|
||||
let multiplier = types.map(defType => {
|
||||
const multiplier = new Utils.NumberHolder(getTypeDamageMultiplier(moveType, defType));
|
||||
applyChallenges(this.scene.gameMode, ChallengeType.TYPE_EFFECTIVENESS, multiplier);
|
||||
if (source) {
|
||||
const ignoreImmunity = new Utils.BooleanHolder(false);
|
||||
if (source.isActive(true) && source.hasAbilityWithAttr(IgnoreTypeImmunityAbAttr)) {
|
||||
applyAbAttrs(IgnoreTypeImmunityAbAttr, source, ignoreImmunity, simulated, moveType, defType);
|
||||
}
|
||||
if (ignoreImmunity.value) {
|
||||
if (multiplier.value === 0) {
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
const exposedTags = this.findTags(tag => tag instanceof ExposedTag) as ExposedTag[];
|
||||
if (exposedTags.some(t => t.ignoreImmunity(defType, moveType))) {
|
||||
if (multiplier.value === 0) {
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
const multiplier = new Utils.NumberHolder(getTypeDamageMultiplier(moveType, defType));
|
||||
applyChallenges(this.scene.gameMode, ChallengeType.TYPE_EFFECTIVENESS, multiplier);
|
||||
return multiplier.value;
|
||||
}).reduce((acc, cur) => acc * cur, 1) as TypeDamageMultiplier;
|
||||
|
||||
@ -1717,7 +1713,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
if (!this.shiny || (!variantData.hasOwnProperty(variantDataIndex) && !variantData.hasOwnProperty(this.species.speciesId))) {
|
||||
return 0;
|
||||
}
|
||||
const rand = Utils.randSeedInt(10);
|
||||
const rand = Utils.randSeedInt(10, undefined, "Random variant selection");
|
||||
if (rand >= 4) {
|
||||
return 0; // 6/10
|
||||
} else if (rand >= 1) {
|
||||
@ -1733,8 +1729,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
this.scene.applyModifiers(HiddenAbilityRateBoosterModifier, true, hiddenAbilityChance);
|
||||
}
|
||||
|
||||
const hasHiddenAbility = !Utils.randSeedInt(hiddenAbilityChance.value);
|
||||
const randAbilityIndex = Utils.randSeedInt(2);
|
||||
const hasHiddenAbility = !Utils.randSeedInt(hiddenAbilityChance.value, undefined, "Whether the Pokemon has its HA or not");
|
||||
const randAbilityIndex = Utils.randSeedInt(2, undefined, "Ability slot (if no HA)");
|
||||
|
||||
const filter = !forStarter ? this.species.getCompatibleFusionSpeciesFilter()
|
||||
: species => {
|
||||
@ -1907,7 +1903,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
|
||||
if (stabMovePool.length) {
|
||||
const totalWeight = stabMovePool.reduce((v, m) => v + m[1], 0);
|
||||
let rand = Utils.randSeedInt(totalWeight);
|
||||
let rand = Utils.randSeedInt(totalWeight, undefined, "Selecting a STAB move to include");
|
||||
let index = 0;
|
||||
while (rand > stabMovePool[index][1]) {
|
||||
rand -= stabMovePool[index++][1];
|
||||
@ -1918,7 +1914,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
const attackMovePool = baseWeights.filter(m => allMoves[m[0]].category !== MoveCategory.STATUS);
|
||||
if (attackMovePool.length) {
|
||||
const totalWeight = attackMovePool.reduce((v, m) => v + m[1], 0);
|
||||
let rand = Utils.randSeedInt(totalWeight);
|
||||
let rand = Utils.randSeedInt(totalWeight, undefined, "Selecting a damage dealing move to include");
|
||||
let index = 0;
|
||||
while (rand > attackMovePool[index][1]) {
|
||||
rand -= attackMovePool[index++][1];
|
||||
@ -1937,7 +1933,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
movePool = baseWeights.filter(m => !this.moveset.some(mo => m[0] === mo?.moveId));
|
||||
}
|
||||
const totalWeight = movePool.reduce((v, m) => v + m[1], 0);
|
||||
let rand = Utils.randSeedInt(totalWeight);
|
||||
let rand = Utils.randSeedInt(totalWeight, undefined, "Selecting moves");
|
||||
let index = 0;
|
||||
while (rand > movePool[index][1]) {
|
||||
rand -= movePool[index++][1];
|
||||
@ -3646,7 +3642,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
* @param min The minimum integer to pick, default `0`
|
||||
* @returns A random integer between {@linkcode min} and ({@linkcode min} + {@linkcode range} - 1)
|
||||
*/
|
||||
randSeedInt(range: integer, min: integer = 0, reason: string = "Pokémon randSeedInt"): integer {
|
||||
randSeedInt(range: integer, min: integer = 0, reason?: string): integer {
|
||||
return this.scene.currentBattle
|
||||
? this.scene.randBattleSeedInt(range, min, reason)
|
||||
: Utils.randSeedInt(range, min, reason);
|
||||
@ -3658,7 +3654,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
* @param max The maximum integer to generate
|
||||
* @returns a random integer between {@linkcode min} and {@linkcode max} inclusive
|
||||
*/
|
||||
randSeedIntRange(min: integer, max: integer, reason: string = "Pokémon randSeedInt"): integer {
|
||||
randSeedIntRange(min: integer, max: integer, reason?: string): integer {
|
||||
return this.randSeedInt((max - min) + 1, min, reason);
|
||||
}
|
||||
|
||||
@ -4269,6 +4265,7 @@ export class EnemyPokemon extends Pokemon {
|
||||
* @returns this Pokemon's next move in the format {move, moveTargets}
|
||||
*/
|
||||
getNextMove(): QueuedMove {
|
||||
console.log("Starting getNextMove() for " + this.name)
|
||||
// If this Pokemon has a move already queued, return it.
|
||||
const queuedMove = this.getMoveQueue().length
|
||||
? this.getMoveset().find(m => m?.moveId === this.getMoveQueue()[0].move)
|
||||
@ -4281,9 +4278,11 @@ export class EnemyPokemon extends Pokemon {
|
||||
this.flyout.setText(i)
|
||||
}
|
||||
}
|
||||
console.log(" Move was already selected")
|
||||
return { move: queuedMove.moveId, targets: this.getMoveQueue()[0].targets, ignorePP: this.getMoveQueue()[0].ignorePP };
|
||||
} else {
|
||||
this.getMoveQueue().shift();
|
||||
console.log(" Selected move cannot be used")
|
||||
return this.getNextMove();
|
||||
}
|
||||
}
|
||||
@ -4295,7 +4294,8 @@ export class EnemyPokemon extends Pokemon {
|
||||
// If there's only 1 move in the move pool, use it.
|
||||
if (movePool.length === 1) {
|
||||
this.flyout.setText(this.getMoveset().indexOf(movePool[0]))
|
||||
return { move: movePool[0]!.moveId, targets: this.getNextTargets(movePool[0]!.moveId) };
|
||||
console.log(" Only one move to select")
|
||||
return { move: movePool[0]!.moveId, targets: this.getNextTargets(movePool[0]!.moveId) }; // TODO: are the bangs correct?
|
||||
}
|
||||
// If a move is forced because of Encore, use it.
|
||||
const encoreTag = this.getTag(EncoreTag) as EncoreTag;
|
||||
@ -4303,6 +4303,7 @@ export class EnemyPokemon extends Pokemon {
|
||||
const encoreMove = movePool.find(m => m?.moveId === encoreTag.moveId);
|
||||
if (encoreMove) {
|
||||
this.flyout.setText(this.getMoveset().indexOf(encoreMove))
|
||||
console.log(" Locked into Encore")
|
||||
return { move: encoreMove.moveId, targets: this.getNextTargets(encoreMove.moveId) };
|
||||
}
|
||||
}
|
||||
@ -4311,6 +4312,7 @@ export class EnemyPokemon extends Pokemon {
|
||||
var i = this.scene.randBattleSeedInt(movePool.length, undefined, "Move selection roll (RANDOM)")
|
||||
const moveId = movePool[i]!.moveId;
|
||||
this.flyout.setText(i)
|
||||
case AiType.RANDOM: // No enemy should spawn with this AI type in-game
|
||||
return { move: moveId, targets: this.getNextTargets(moveId) };
|
||||
case AiType.SMART_RANDOM:
|
||||
case AiType.SMART:
|
||||
@ -4392,22 +4394,25 @@ export class EnemyPokemon extends Pokemon {
|
||||
});
|
||||
let r = 0;
|
||||
if (this.aiType === AiType.SMART_RANDOM) {
|
||||
while (r < sortedMovePool.length - 1 && this.scene.randBattleSeedInt(8, undefined, "Move selection roll (SMART_RANDOM)") >= 5) {
|
||||
// Has a 5/8 chance to select the best move, and a 3/8 chance to advance to the next best move (and repeat this roll)
|
||||
while (r < sortedMovePool.length - 1 && this.scene.randBattleSeedInt(8, undefined, "Smart-Random AI Move Selection") >= 5) {
|
||||
r++;
|
||||
}
|
||||
} else if (this.aiType === AiType.SMART) {
|
||||
// The chance to advance to the next best move increases when the compared moves' scores are closer to each other.
|
||||
while (r < sortedMovePool.length - 1 && (moveScores[movePool.indexOf(sortedMovePool[r + 1])] / moveScores[movePool.indexOf(sortedMovePool[r])]) >= 0
|
||||
&& this.scene.randBattleSeedInt(100, undefined, "Move selection roll (SMART)") < Math.round((moveScores[movePool.indexOf(sortedMovePool[r + 1])] / moveScores[movePool.indexOf(sortedMovePool[r])]) * 50)) {
|
||||
&& this.scene.randBattleSeedInt(100, undefined, "Smart AI Move Selection") < Math.round((moveScores[movePool.indexOf(sortedMovePool[r + 1])] / moveScores[movePool.indexOf(sortedMovePool[r])]) * 50)) {
|
||||
r++;
|
||||
}
|
||||
}
|
||||
console.log(movePool.map(m => m!.getName()), moveScores, r, sortedMovePool.map(m => m!.getName()));
|
||||
this.flyout.setText(movePool.indexOf(sortedMovePool[r]))
|
||||
console.log(" Selected " + sortedMovePool[r]!.getName())
|
||||
return { move: sortedMovePool[r]!.moveId, targets: moveTargets[sortedMovePool[r]!.moveId] };
|
||||
}
|
||||
}
|
||||
this.flyout.setText()
|
||||
console.log(" Selected Struggle")
|
||||
return { move: Moves.STRUGGLE, targets: this.getNextTargets(Moves.STRUGGLE) };
|
||||
}
|
||||
|
||||
@ -4417,10 +4422,12 @@ export class EnemyPokemon extends Pokemon {
|
||||
* @returns The indexes of the Pokemon the given move would target
|
||||
*/
|
||||
getNextTargets(moveId: Moves): BattlerIndex[] {
|
||||
console.log("Starting getNextTargets() for " + this.name + " with move " + Utils.getEnumKeys(Moves)[moveId])
|
||||
const moveTargets = getMoveTargets(this, moveId);
|
||||
const targets = this.scene.getField(true).filter(p => moveTargets.targets.indexOf(p.getBattlerIndex()) > -1);
|
||||
// If the move is multi-target, return all targets' indexes
|
||||
if (moveTargets.multiple) {
|
||||
console.log(" Multi-target move")
|
||||
return targets.map(p => p.getBattlerIndex());
|
||||
}
|
||||
|
||||
@ -4444,9 +4451,10 @@ export class EnemyPokemon extends Pokemon {
|
||||
// Set target to BattlerIndex.ATTACKER when using a counter move
|
||||
// This is the same as when the player does so
|
||||
if (move.hasAttr(CounterDamageAttr)) {
|
||||
console.log(" Counter move")
|
||||
return [BattlerIndex.ATTACKER];
|
||||
}
|
||||
|
||||
console.log(" No targets available")
|
||||
return [];
|
||||
}
|
||||
|
||||
@ -4480,7 +4488,7 @@ export class EnemyPokemon extends Pokemon {
|
||||
* then select the first target whose cumulative weight (with all previous targets' weights)
|
||||
* is greater than that random number.
|
||||
*/
|
||||
const randValue = this.scene.randBattleSeedInt(totalWeight, undefined, "Random target selection");
|
||||
const randValue = this.scene.randBattleSeedInt(totalWeight, undefined, "Random move target");
|
||||
let targetIndex: integer = 0;
|
||||
|
||||
thresholds.every((t, i) => {
|
||||
@ -4491,6 +4499,8 @@ export class EnemyPokemon extends Pokemon {
|
||||
targetIndex = i;
|
||||
return false;
|
||||
});
|
||||
console.log("Target selection thresholds", thresholds)
|
||||
console.log(" Randomly selected position " + sortedBenefitScores[targetIndex][0] + " as target")
|
||||
|
||||
return [ sortedBenefitScores[targetIndex][0] ];
|
||||
}
|
||||
@ -4600,7 +4610,7 @@ export class EnemyPokemon extends Pokemon {
|
||||
}
|
||||
|
||||
// Pick a random stat from the leftover stats to increase its stages
|
||||
const randInt = Utils.randSeedInt(totalWeight);
|
||||
const randInt = Utils.randSeedInt(totalWeight, undefined, "Random stat to raise from breaking a segment");
|
||||
for (const i in statThresholds) {
|
||||
if (randInt < statThresholds[i]) {
|
||||
boostedStat = leftoverStats[i];
|
||||
|
@ -45,7 +45,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
||||
this.config.partyTemplates.length - 1);
|
||||
if (trainerNamePools.hasOwnProperty(trainerType)) {
|
||||
const namePool = trainerNamePools[trainerType];
|
||||
this.name = name || Utils.randSeedItem(Array.isArray(namePool[0]) ? namePool[variant === TrainerVariant.FEMALE ? 1 : 0] : namePool);
|
||||
this.name = name || Utils.randSeedItem(Array.isArray(namePool[0]) ? namePool[variant === TrainerVariant.FEMALE ? 1 : 0] : namePool, "Trainer name 1");
|
||||
if (variant === TrainerVariant.DOUBLE) {
|
||||
if (this.config.doubleOnly) {
|
||||
if (partnerName) {
|
||||
@ -54,7 +54,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
||||
[this.name, this.partnerName] = this.name.split(" & ");
|
||||
}
|
||||
} else {
|
||||
this.partnerName = partnerName || Utils.randSeedItem(Array.isArray(namePool[0]) ? namePool[1] : namePool);
|
||||
this.partnerName = partnerName || Utils.randSeedItem(Array.isArray(namePool[0]) ? namePool[1] : namePool, "Trainer name 2");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -487,7 +487,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
||||
|
||||
let species: PokemonSpecies;
|
||||
if (this.config.speciesPools) {
|
||||
const tierValue = Utils.randSeedInt(512);
|
||||
const tierValue = Utils.randSeedInt(512, undefined, "Randomly selecting species for trainer party");
|
||||
let tier = tierValue >= 156 ? TrainerPoolTier.COMMON : tierValue >= 32 ? TrainerPoolTier.UNCOMMON : tierValue >= 6 ? TrainerPoolTier.RARE : tierValue >= 1 ? TrainerPoolTier.SUPER_RARE : TrainerPoolTier.ULTRA_RARE;
|
||||
console.log(TrainerPoolTier[tier]);
|
||||
while (!this.config.speciesPools.hasOwnProperty(tier) || !this.config.speciesPools[tier].length) {
|
||||
@ -495,7 +495,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
||||
tier--;
|
||||
}
|
||||
const tierPool = this.config.speciesPools[tier];
|
||||
species = getPokemonSpecies(Utils.randSeedItem(tierPool));
|
||||
species = getPokemonSpecies(Utils.randSeedItem(tierPool, "Random party member species"));
|
||||
} else {
|
||||
species = this.scene.randomSpecies(battle.waveIndex, level, false, this.config.speciesFilter);
|
||||
}
|
||||
@ -587,7 +587,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
||||
|
||||
if (maxScorePartyMemberIndexes.length > 1) {
|
||||
let rand: integer;
|
||||
this.scene.executeWithSeedOffset(() => rand = Utils.randSeedInt(maxScorePartyMemberIndexes.length), this.scene.currentBattle.turn << 2);
|
||||
this.scene.executeWithSeedOffset(() => rand = Utils.randSeedInt(maxScorePartyMemberIndexes.length, undefined, "Randomly selecting who to send out next"), this.scene.currentBattle.turn << 2);
|
||||
return maxScorePartyMemberIndexes[rand!];
|
||||
}
|
||||
|
||||
|
@ -161,7 +161,7 @@ export class GameMode implements GameModeConfig {
|
||||
} else if (w < waveIndex) {
|
||||
arena.scene.executeWithSeedOffset(() => {
|
||||
const waveTrainerChance = arena.getTrainerChance();
|
||||
if (!Utils.randSeedInt(waveTrainerChance)) {
|
||||
if (!Utils.randSeedInt(waveTrainerChance, undefined, "Random chance of wave being a Trainer Battle")) {
|
||||
allowTrainerBattle = false;
|
||||
}
|
||||
}, w);
|
||||
@ -171,7 +171,7 @@ export class GameMode implements GameModeConfig {
|
||||
}
|
||||
}
|
||||
}
|
||||
return Boolean(allowTrainerBattle && trainerChance && !Utils.randSeedInt(trainerChance));
|
||||
return Boolean(allowTrainerBattle && trainerChance && !Utils.randSeedInt(trainerChance, undefined, "Random chance of wave being a Trainer Battle"));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -189,7 +189,7 @@ export class GameMode implements GameModeConfig {
|
||||
if (this.isDaily && this.isWaveFinal(waveIndex)) {
|
||||
const allFinalBossSpecies = allSpecies.filter(s => (s.subLegendary || s.legendary || s.mythical)
|
||||
&& s.baseTotal >= 600 && s.speciesId !== Species.ETERNATUS && s.speciesId !== Species.ARCEUS);
|
||||
return Utils.randSeedItem(allFinalBossSpecies);
|
||||
return Utils.randSeedItem(allFinalBossSpecies, "Final Boss override");
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -1063,7 +1063,7 @@ class AttackTypeBoosterModifierTypeGenerator extends ModifierTypeGenerator {
|
||||
|
||||
let type: Type;
|
||||
|
||||
const randInt = Utils.randSeedInt(totalWeight);
|
||||
const randInt = Utils.randSeedInt(totalWeight, undefined, "Generating a move type booster");
|
||||
let weight = 0;
|
||||
|
||||
var fullweights: integer[] = []
|
||||
@ -1104,7 +1104,7 @@ class BaseStatBoosterModifierTypeGenerator extends ModifierTypeGenerator {
|
||||
if (pregenArgs) {
|
||||
return new BaseStatBoosterModifierType(pregenArgs[0]);
|
||||
}
|
||||
const randStat: PermanentStat = Utils.randSeedInt(Stat.SPD + 1);
|
||||
const randStat: PermanentStat = Utils.randSeedInt(Stat.SPD + 1, undefined, "Randomly generating a Vitamin");
|
||||
return new BaseStatBoosterModifierType(randStat);
|
||||
});
|
||||
}
|
||||
@ -1125,7 +1125,7 @@ class TempStatStageBoosterModifierTypeGenerator extends ModifierTypeGenerator {
|
||||
if (pregenArgs && (pregenArgs.length === 1) && TEMP_BATTLE_STATS.includes(pregenArgs[0])) {
|
||||
return new TempStatStageBoosterModifierType(pregenArgs[0]);
|
||||
}
|
||||
const randStat: TempBattleStat = Utils.randSeedInt(Stat.ACC, Stat.ATK);
|
||||
const randStat: TempBattleStat = Utils.randSeedInt(Stat.ACC, Stat.ATK, "Randomly choosing an X item");
|
||||
return new TempStatStageBoosterModifierType(randStat);
|
||||
});
|
||||
}
|
||||
@ -1190,7 +1190,7 @@ class SpeciesStatBoosterModifierTypeGenerator extends ModifierTypeGenerator {
|
||||
}
|
||||
|
||||
if (totalWeight !== 0) {
|
||||
const randInt = Utils.randSeedInt(totalWeight, 1);
|
||||
const randInt = Utils.randSeedInt(totalWeight, 1, "Randomly choosing a species booster");
|
||||
let weight = 0;
|
||||
|
||||
var fullweights: integer[] = []
|
||||
@ -1232,9 +1232,9 @@ class TmModifierTypeGenerator extends ModifierTypeGenerator {
|
||||
if (!tierUniqueCompatibleTms.length) {
|
||||
return null;
|
||||
}
|
||||
const randTmIndex = Utils.randSeedInt(tierUniqueCompatibleTms.length);
|
||||
//console.log(tierUniqueCompatibleTms.map((v, i) => i == randTmIndex ? `> ${Utils.getEnumKeys(Moves)[v].toUpperCase() + Utils.getEnumKeys(Moves)[v].substring(1).toLowerCase()} <` : `${Utils.getEnumKeys(Moves)[v].toUpperCase() + Utils.getEnumKeys(Moves)[v].substring(1).toLowerCase()}`))
|
||||
return new TmModifierType(tierUniqueCompatibleTms[randTmIndex], tier);
|
||||
const randTmIndex = Utils.randSeedInt(tierUniqueCompatibleTms.length, undefined, "Choosing a TM to give");
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1263,9 +1263,7 @@ class EvolutionItemModifierTypeGenerator extends ModifierTypeGenerator {
|
||||
return null;
|
||||
}
|
||||
|
||||
const idx = Utils.randSeedInt(evolutionItemPool.length)
|
||||
// console.log(evolutionItemPool.map((v, i) => i == idx ? `> ${Utils.getEnumKeys(EvolutionItem)[v!]} <` : Utils.getEnumKeys(EvolutionItem)[v!]))
|
||||
return new EvolutionItemModifierType(evolutionItemPool[idx]!); // TODO: is the bang correct?
|
||||
return new EvolutionItemModifierType(evolutionItemPool[Utils.randSeedInt(evolutionItemPool.length, undefined, "Choosing an evolution item")]!); // TODO: is the bang correct?
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1321,9 +1319,7 @@ class FormChangeItemModifierTypeGenerator extends ModifierTypeGenerator {
|
||||
return null;
|
||||
}
|
||||
|
||||
const idx = Utils.randSeedInt(formChangeItemPool.length)
|
||||
// console.log(formChangeItemPool.map((v, i) => i == idx ? `> ${Utils.getEnumKeys(FormChangeItem)[v!]} <` : Utils.getEnumKeys(FormChangeItem)[v!]))
|
||||
return new FormChangeItemModifierType(formChangeItemPool[idx]!);
|
||||
return new FormChangeItemModifierType(formChangeItemPool[Utils.randSeedInt(formChangeItemPool.length, undefined, "Choosing a form change item")]);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1584,7 +1580,7 @@ export const modifierTypes = {
|
||||
if (pregenArgs && (pregenArgs.length === 1) && (pregenArgs[0] in Nature)) {
|
||||
return new PokemonNatureChangeModifierType(pregenArgs[0] as Nature);
|
||||
}
|
||||
return new PokemonNatureChangeModifierType(Utils.randSeedInt(Utils.getEnumValues(Nature).length) as Nature);
|
||||
return new PokemonNatureChangeModifierType(Utils.randSeedInt(Utils.getEnumValues(Nature).length, undefined, "Choosing a Mint") as Nature);
|
||||
}),
|
||||
|
||||
TERA_SHARD: () => new ModifierTypeGenerator((party: Pokemon[], pregenArgs?: any[]) => {
|
||||
@ -1595,11 +1591,11 @@ export const modifierTypes = {
|
||||
return null;
|
||||
}
|
||||
let type: Type;
|
||||
if (!Utils.randSeedInt(3)) {
|
||||
if (!Utils.randSeedInt(3, undefined, "Choosing whether to give a type from your party")) {
|
||||
const partyMemberTypes = party.map(p => p.getTypes(false, false, true)).flat();
|
||||
type = Utils.randSeedItem(partyMemberTypes);
|
||||
type = Utils.randSeedItem(partyMemberTypes, "Choosing a Tera Shard type to give");
|
||||
} else {
|
||||
type = Utils.randSeedInt(64) ? Utils.randSeedInt(18) as Type : Type.STELLAR;
|
||||
type = Utils.randSeedInt(64, undefined, "Choosing whether to give a Stellar Shard") ? Utils.randSeedInt(18, undefined, "Choosing a type (man I have no patience)") as Type : Type.STELLAR;
|
||||
}
|
||||
return new TerastallizeModifierType(type);
|
||||
}),
|
||||
@ -1610,7 +1606,7 @@ export const modifierTypes = {
|
||||
}
|
||||
const berryTypes = Utils.getEnumValues(BerryType);
|
||||
let randBerryType: BerryType;
|
||||
const rand = Utils.randSeedInt(12);
|
||||
const rand = Utils.randSeedInt(12, undefined, "Choosing a Berry");
|
||||
if (rand < 2) {
|
||||
randBerryType = BerryType.SITRUS;
|
||||
} else if (rand < 4) {
|
||||
@ -1618,7 +1614,7 @@ export const modifierTypes = {
|
||||
} else if (rand < 6) {
|
||||
randBerryType = BerryType.LEPPA;
|
||||
} else {
|
||||
randBerryType = berryTypes[Utils.randSeedInt(berryTypes.length - 3) + 2];
|
||||
randBerryType = berryTypes[Utils.randSeedInt(berryTypes.length - 3, undefined, "Choosing a berry") + 2];
|
||||
}
|
||||
return new BerryModifierType(randBerryType);
|
||||
}),
|
||||
@ -2720,7 +2716,7 @@ export function getDailyRunStarterModifiers(party: PlayerPokemon[], scene?: Batt
|
||||
const ret: Modifiers.PokemonHeldItemModifier[] = [];
|
||||
for (const p of party) {
|
||||
for (let m = 0; m < 3; m++) {
|
||||
const tierValue = Utils.randSeedInt(64);
|
||||
const tierValue = Utils.randSeedInt(64, undefined, "Choosing modifier tier for daily items");
|
||||
|
||||
let tier: ModifierTier;
|
||||
if (tierValue > 25) {
|
||||
@ -2808,7 +2804,7 @@ function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType,
|
||||
Phaser.Math.RND.state(state)
|
||||
}
|
||||
}
|
||||
const tierValue = Utils.randSeedInt(1024);
|
||||
const tierValue = Utils.randSeedInt(1024, undefined, "Choosing a modifier tier");
|
||||
if (!upgradeCount) {
|
||||
upgradeCount = 0;
|
||||
}
|
||||
@ -2822,7 +2818,7 @@ function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType,
|
||||
const upgradeOdds = Math.floor(128 / ((partyLuckValue + 4) / 4));
|
||||
let upgraded = false;
|
||||
do {
|
||||
upgraded = Utils.randSeedInt(upgradeOdds) < 4;
|
||||
upgraded = Utils.randSeedInt(upgradeOdds, undefined, "Upgrade chance") < 4;
|
||||
if (upgraded) {
|
||||
upgradeCount++;
|
||||
}
|
||||
@ -2880,7 +2876,7 @@ function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType,
|
||||
}
|
||||
const upgradeOdds = Math.floor(32 / ((partyShinyCount + 2) / 2));
|
||||
while (modifierPool.hasOwnProperty(tier + upgradeCount + 1) && modifierPool[tier + upgradeCount + 1].length) {
|
||||
if (!Utils.randSeedInt(upgradeOdds)) {
|
||||
if (!Utils.randSeedInt(upgradeOdds, undefined, "Upgrade chance 2")) {
|
||||
upgradeCount++;
|
||||
} else {
|
||||
break;
|
||||
@ -2907,9 +2903,9 @@ function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType,
|
||||
//console.log("Ignored items for this tier", ignoredPoolIndexes[tier].map((v, i) => [ignoredPoolNames[i], v]).flat())
|
||||
}
|
||||
}
|
||||
let modifierType: ModifierType = (pool[tier][index]).modifierType;
|
||||
let modifierType: ModifierType | null = (pool[tier][index]).modifierType;
|
||||
if (modifierType instanceof ModifierTypeGenerator) {
|
||||
modifierType = (modifierType as ModifierTypeGenerator).generateType(party)!;
|
||||
modifierType = (modifierType as ModifierTypeGenerator).generateType(party);
|
||||
if (modifierType === null) {
|
||||
if (player) {
|
||||
if (!shutUpBro) console.log(ModifierTier[tier], upgradeCount);
|
||||
|
@ -796,7 +796,7 @@ export class TerastallizeModifier extends LapsingPokemonHeldItemModifier {
|
||||
/**
|
||||
* Modifier used for held items, specifically vitamins like Carbos, Hp Up, etc., that
|
||||
* increase the value of a given {@linkcode PermanentStat}.
|
||||
* @extends PokemonHeldItemModifier
|
||||
* @extends LapsingPersistentModifier
|
||||
* @see {@linkcode apply}
|
||||
*/
|
||||
export class BaseStatModifier extends PokemonHeldItemModifier {
|
||||
@ -1494,7 +1494,7 @@ export class PreserveBerryModifier extends PersistentModifier {
|
||||
|
||||
apply(args: any[]): boolean {
|
||||
if (!(args[1] as Utils.BooleanHolder).value) {
|
||||
(args[1] as Utils.BooleanHolder).value = (args[0] as Pokemon).randSeedInt(10, undefined, "Chance to save a berry") < this.getStackCount() * 3;
|
||||
(args[1] as Utils.BooleanHolder).value = (args[0] as Pokemon).randSeedInt(10, undefined, "Chance to preserve berry") < this.getStackCount() * 3;
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -2428,7 +2428,7 @@ export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier {
|
||||
return false;
|
||||
}
|
||||
|
||||
const targetPokemon = opponents[pokemon.randSeedInt(opponents.length, undefined, "Chance to steal/transfer an item")];
|
||||
const targetPokemon = opponents[pokemon.randSeedInt(opponents.length, undefined, "Chance to steal item")];
|
||||
|
||||
const transferredItemCount = this.getTransferredItemCount();
|
||||
if (!transferredItemCount) {
|
||||
|
@ -124,7 +124,7 @@ export class AttemptCapturePhase extends PokemonPhase {
|
||||
shakeCounter.stop();
|
||||
this.failCatch(shakeCount);
|
||||
} else if (shakeCount++ < 3) {
|
||||
if (pokeballMultiplier === -1 || this.roll(y) < y) {
|
||||
if (pokeballMultiplier === -1 || pokemon.randSeedInt(65536, undefined, "Capture roll") < y) {
|
||||
this.scene.playSound("se/pb_move");
|
||||
} else {
|
||||
shakeCounter.stop();
|
||||
|
@ -29,7 +29,7 @@ export class AttemptRunPhase extends PokemonPhase {
|
||||
|
||||
applyAbAttrs(RunSuccessAbAttr, playerPokemon, null, false, escapeChance);
|
||||
|
||||
if (playerPokemon.randSeedInt(100, undefined, "Run attempt") < escapeChance.value) {
|
||||
if (playerPokemon.randSeedInt(100, undefined, "Run away chance") < escapeChance.value) {
|
||||
this.scene.playSound("se/flee");
|
||||
LoggerTools.logShop(this.scene, this.scene.currentBattle.waveIndex, "Fled")
|
||||
this.scene.queueMessage(i18next.t("battle:runAwaySuccess"), null, true, 500);
|
||||
|
@ -391,7 +391,7 @@ export class EggHatchPhase extends Phase {
|
||||
repeat: intensity,
|
||||
duration: Utils.getFrameMs(1),
|
||||
onRepeat: () => {
|
||||
this.doSprayParticle(Utils.randInt(8), offsetY || 0);
|
||||
this.doSprayParticle(Utils.randInt(8, undefined, "%HIDE"), offsetY || 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -410,8 +410,8 @@ export class EggHatchPhase extends Phase {
|
||||
|
||||
let f = 0;
|
||||
let yOffset = 0;
|
||||
const speed = 3 - Utils.randInt(8);
|
||||
const amp = 24 + Utils.randInt(32);
|
||||
const speed = 3 - Utils.randInt(8, undefined, "%HIDE");
|
||||
const amp = 24 + Utils.randInt(32, undefined, "%HIDE");
|
||||
|
||||
const particleTimer = this.scene.tweens.addCounter({
|
||||
repeat: -1,
|
||||
|
@ -309,7 +309,7 @@ export class EncounterPhase extends BattlePhase {
|
||||
doSummon();
|
||||
} else {
|
||||
let message: string;
|
||||
this.scene.executeWithSeedOffset(() => message = Utils.randSeedItem(encounterMessages), this.scene.currentBattle.waveIndex);
|
||||
this.scene.executeWithSeedOffset(() => message = Utils.randSeedItem(encounterMessages, "Encounter message"), this.scene.currentBattle.waveIndex);
|
||||
message = message!; // tell TS compiler it's defined now
|
||||
const showDialogueAndSummon = () => {
|
||||
this.scene.ui.showDialogue(message, trainer?.getName(TrainerSlot.NONE, true), null, () => {
|
||||
|
@ -251,7 +251,7 @@ export class MovePhase extends BattlePhase {
|
||||
|
||||
switch (this.pokemon.status.effect) {
|
||||
case StatusEffect.PARALYSIS:
|
||||
if (!this.pokemon.randSeedInt(4, undefined, "Paralysis chance")) {
|
||||
if (!this.pokemon.randSeedInt(4, undefined, "Chance to be immobilized by Paralysis")) {
|
||||
activated = true;
|
||||
this.cancelled = true;
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ export class SelectBiomePhase extends BattlePhase {
|
||||
let biomes: Biome[] = [];
|
||||
this.scene.executeWithSeedOffset(() => {
|
||||
biomes = (biomeLinks[currentBiome] as (Biome | [Biome, integer])[])
|
||||
.filter(b => !Array.isArray(b) || !Utils.randSeedInt(b[1]))
|
||||
.filter(b => !Array.isArray(b) || !Utils.randSeedInt(b[1], undefined, "Choosing next biome"))
|
||||
.map(b => !Array.isArray(b) ? b : b[0]);
|
||||
}, this.scene.currentBattle.waveIndex);
|
||||
if (biomes.length > 1 && this.scene.findModifier(m => m instanceof MapModifier)) {
|
||||
@ -48,7 +48,7 @@ export class SelectBiomePhase extends BattlePhase {
|
||||
biomeChoices = (!Array.isArray(biomeLinks[currentBiome])
|
||||
? [biomeLinks[currentBiome] as Biome]
|
||||
: biomeLinks[currentBiome] as (Biome | [Biome, integer])[])
|
||||
.filter((b, i) => !Array.isArray(b) || !Utils.randSeedInt(b[1]))
|
||||
.filter((b, i) => !Array.isArray(b) || !Utils.randSeedInt(b[1], undefined, "Choosing next biome for map"))
|
||||
.map(b => Array.isArray(b) ? b[0] : b);
|
||||
}, this.scene.currentBattle.waveIndex);
|
||||
const biomeSelectItems = biomeChoices.map(b => {
|
||||
@ -67,7 +67,7 @@ export class SelectBiomePhase extends BattlePhase {
|
||||
delay: 1000
|
||||
});
|
||||
} else {
|
||||
setNextBiome(biomes[Utils.randSeedInt(biomes.length)]);
|
||||
setNextBiome(biomes[Utils.randSeedInt(biomes.length, undefined, "Choosing biome randomly")]);
|
||||
}
|
||||
} else if (biomeLinks.hasOwnProperty(currentBiome)) {
|
||||
setNextBiome(biomeLinks[currentBiome] as Biome);
|
||||
|
@ -38,7 +38,7 @@ export class TrainerVictoryPhase extends BattlePhase {
|
||||
this.scene.ui.showText(i18next.t("battle:trainerDefeated", { trainerName: this.scene.currentBattle.trainer?.getName(TrainerSlot.NONE, true) }), null, () => {
|
||||
const victoryMessages = this.scene.currentBattle.trainer?.getVictoryMessages()!; // TODO: is this bang correct?
|
||||
let message: string;
|
||||
this.scene.executeWithSeedOffset(() => message = Utils.randSeedItem(victoryMessages), this.scene.currentBattle.waveIndex);
|
||||
this.scene.executeWithSeedOffset(() => message = Utils.randSeedItem(victoryMessages, "Victory message"), this.scene.currentBattle.waveIndex);
|
||||
message = message!; // tell TS compiler it's defined now
|
||||
|
||||
const showMessage = () => {
|
||||
|
@ -31,8 +31,8 @@ import { Variant } from "#app/data/variant";
|
||||
import {setSettingGamepad, SettingGamepad, settingGamepadDefaults} from "./settings/settings-gamepad";
|
||||
import {setSettingKeyboard, SettingKeyboard} from "#app/system/settings/settings-keyboard";
|
||||
import { TerrainChangedEvent, WeatherChangedEvent } from "#app/events/arena";
|
||||
import * as Modifier from "../modifier/modifier";
|
||||
import { StatusEffect } from "#app/data/status-effect";
|
||||
import { EnemyAttackStatusEffectChanceModifier } from "../modifier/modifier";
|
||||
import ChallengeData from "./challenge-data";
|
||||
import { Device } from "#enums/devices";
|
||||
import { GameDataType } from "#enums/game-data-type";
|
||||
@ -327,8 +327,8 @@ export class GameData {
|
||||
this.loadSettings();
|
||||
this.loadGamepadSettings();
|
||||
this.loadMappingConfigs();
|
||||
this.trainerId = Utils.randInt(65536);
|
||||
this.secretId = Utils.randInt(65536);
|
||||
this.trainerId = Utils.randInt(65536, undefined, "Trainer ID");
|
||||
this.secretId = Utils.randInt(65536, undefined, "Secret ID");
|
||||
this.starterData = {};
|
||||
this.gameStats = new GameStats();
|
||||
this.runHistory = {};
|
||||
@ -1085,8 +1085,10 @@ export class GameData {
|
||||
// TODO
|
||||
//scene.arena.tags = sessionData.arena.tags;
|
||||
|
||||
const modifiersModule = await import("../modifier/modifier");
|
||||
|
||||
for (const modifierData of sessionData.modifiers) {
|
||||
const modifier = modifierData.toModifier(scene, Modifier[modifierData.className]);
|
||||
const modifier = modifierData.toModifier(scene, modifiersModule[modifierData.className]);
|
||||
if (modifier) {
|
||||
scene.addModifier(modifier, true);
|
||||
}
|
||||
@ -1095,7 +1097,7 @@ export class GameData {
|
||||
scene.updateModifiers(true);
|
||||
|
||||
for (const enemyModifierData of sessionData.enemyModifiers) {
|
||||
const modifier = enemyModifierData.toModifier(scene, Modifier[enemyModifierData.className]);
|
||||
const modifier = enemyModifierData.toModifier(scene, modifiersModule[enemyModifierData.className]);
|
||||
if (modifier) {
|
||||
scene.addEnemyModifier(modifier, true);
|
||||
}
|
||||
@ -1251,7 +1253,7 @@ export class GameData {
|
||||
if (md?.className === "ExpBalanceModifier") { // Temporarily limit EXP Balance until it gets reworked
|
||||
md.stackCount = Math.min(md.stackCount, 4);
|
||||
}
|
||||
if (md instanceof Modifier.EnemyAttackStatusEffectChanceModifier && md.effect === StatusEffect.FREEZE || md.effect === StatusEffect.SLEEP) {
|
||||
if (md instanceof EnemyAttackStatusEffectChanceModifier && md.effect === StatusEffect.FREEZE || md.effect === StatusEffect.SLEEP) {
|
||||
continue;
|
||||
}
|
||||
ret.push(new PersistentModifierData(md, player));
|
||||
@ -1507,7 +1509,7 @@ export class GameData {
|
||||
this.scene.executeWithSeedOffset(() => {
|
||||
const neutralNatures = [ Nature.HARDY, Nature.DOCILE, Nature.SERIOUS, Nature.BASHFUL, Nature.QUIRKY ];
|
||||
for (let s = 0; s < defaultStarterSpecies.length; s++) {
|
||||
defaultStarterNatures.push(Utils.randSeedItem(neutralNatures));
|
||||
defaultStarterNatures.push(Utils.randSeedItem(neutralNatures, "Random neutral nature"));
|
||||
}
|
||||
}, 0, "default");
|
||||
|
||||
@ -1862,7 +1864,7 @@ export class GameData {
|
||||
entry.hatchedCount = 0;
|
||||
}
|
||||
if (!entry.hasOwnProperty("natureAttr") || (entry.caughtAttr && !entry.natureAttr)) {
|
||||
entry.natureAttr = this.defaultDexData?.[k].natureAttr || (1 << Utils.randInt(25, 1));
|
||||
entry.natureAttr = this.defaultDexData?.[k].natureAttr || (1 << Utils.randInt(25, 1, "Random bit shift"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1073,7 +1073,7 @@ export default class PartyUiHandler extends MessageUiHandler {
|
||||
}
|
||||
|
||||
getReleaseMessage(pokemonName: string): string {
|
||||
const rand = Utils.randInt(128);
|
||||
const rand = Utils.randInt(128, undefined, "Random release message");
|
||||
if (rand < 20) {
|
||||
return i18next.t("partyUiHandler:goodbye", { pokemonName: pokemonName });
|
||||
} else if (rand < 40) {
|
||||
|
@ -85,7 +85,7 @@ export default class TitleUiHandler extends OptionSelectUiHandler {
|
||||
const ret = super.show(args);
|
||||
|
||||
if (ret) {
|
||||
this.splashMessage = Utils.randItem(getSplashMessages());
|
||||
this.splashMessage = Utils.randItem(getSplashMessages(), "Splash Message selection");
|
||||
this.splashMessageText.setText(this.splashMessage.replace("{COUNT}", "?"));
|
||||
|
||||
const ui = this.getUi();
|
||||
|
20
src/utils.ts
20
src/utils.ts
@ -13,7 +13,7 @@ export function randomString(length: integer, seeded: boolean = false) {
|
||||
let result = "";
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
const randomIndex = seeded ? randSeedInt(characters.length) : Math.floor(Math.random() * characters.length);
|
||||
const randomIndex = seeded ? randSeedInt(characters.length, undefined, "%HIDE") : Math.floor(Math.random() * characters.length);
|
||||
result += characters[randomIndex];
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ export function rangemap(value: integer, min: integer, max: integer, outMin: int
|
||||
return ((value - min) / (max - min)) * (outMax - outMin) + outMin
|
||||
}
|
||||
|
||||
export function randGauss(stdev: number, mean: number = 0): number {
|
||||
export function randGauss(stdev: number, mean: number = 0, reason?: string): number {
|
||||
if (!stdev) {
|
||||
return 0;
|
||||
}
|
||||
@ -54,7 +54,7 @@ export function randGauss(stdev: number, mean: number = 0): number {
|
||||
return z * stdev + mean;
|
||||
}
|
||||
|
||||
export function randSeedGauss(stdev: number, mean: number = 0): number {
|
||||
export function randSeedGauss(stdev: number, mean: number = 0, reason?: string): number {
|
||||
if (!stdev) {
|
||||
return 0;
|
||||
}
|
||||
@ -85,7 +85,9 @@ export function randInt(range: integer, min: integer = 0, reason?: string): inte
|
||||
return min;
|
||||
}
|
||||
let V = Math.floor(Math.random() * range) + min;
|
||||
//console.log(reason ? reason : "randInt", V)
|
||||
if (reason != "%HIDE") {
|
||||
console.log("[unseeded] " + (reason ? reason : "randInt"), V)
|
||||
}
|
||||
return V;
|
||||
}
|
||||
|
||||
@ -100,7 +102,13 @@ export function randSeedInt(range: integer, min: integer = 0, reason?: string):
|
||||
return min;
|
||||
}
|
||||
let V = Phaser.Math.RND.integerInRange(min, (range - 1) + min);
|
||||
//console.log(reason ? reason : "randSeedInt", V)
|
||||
if (reason != "%HIDE") {
|
||||
if (reason) {
|
||||
console.log(reason, V)
|
||||
} else {
|
||||
console.error("unlabeled randSeedInt", V)
|
||||
}
|
||||
}
|
||||
return V;
|
||||
}
|
||||
|
||||
@ -122,7 +130,7 @@ export function randItem<T>(items: T[], reason?: string): T {
|
||||
export function randSeedItem<T>(items: T[], reason?: string): T {
|
||||
function rpick() {
|
||||
let V = Phaser.Math.RND.pick(items)
|
||||
//console.log(reason ? reason : "randSeedItem")
|
||||
console.log(reason ? reason : "randSeedItem")
|
||||
return V;
|
||||
}
|
||||
return items.length === 1
|
||||
|
Loading…
Reference in New Issue
Block a user