Prevent Fusing Status Errors (#465)

pull/471/head^2
Benjamin Odom 2024-05-04 20:37:31 -05:00 committed by GitHub
parent d170aeeab6
commit 68eca464f7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 88 additions and 6 deletions

View File

@ -3,7 +3,7 @@
"short_name": "PokéRogue", "short_name": "PokéRogue",
"description": "A Pokémon fangame heavily inspired by the roguelite genre. Battle endlessly while gathering stacking items, exploring many different biomes, and reaching Pokémon stats you never thought possible.", "description": "A Pokémon fangame heavily inspired by the roguelite genre. Battle endlessly while gathering stacking items, exploring many different biomes, and reaching Pokémon stats you never thought possible.",
"scope": "/", "scope": "/",
"start_url": "https://pokerogue.net", "start_url": "/",
"display": "fullscreen", "display": "fullscreen",
"background_color": "#8c8c8c", "background_color": "#8c8c8c",
"theme_color": "#8c8c8c", "theme_color": "#8c8c8c",

View File

@ -135,3 +135,43 @@ export function getStatusEffectCatchRateMultiplier(statusEffect: StatusEffect):
return 1; return 1;
} }
/**
* Returns a random non-volatile StatusEffect
*/
export function generateRandomStatusEffect(): StatusEffect {
return Utils.randIntRange(1, 6);
}
/**
* Returns a random non-volatile StatusEffect between the two provided
* @param statusEffectA The first StatusEffect
* @param statusEffectA The second StatusEffect
*/
export function getRandomStatusEffect(statusEffectA: StatusEffect, statusEffectB: StatusEffect): StatusEffect {
if (statusEffectA === StatusEffect.NONE || statusEffectA === StatusEffect.FAINT) {
return statusEffectB;
}
if (statusEffectB === StatusEffect.NONE || statusEffectB === StatusEffect.FAINT) {
return statusEffectA;
}
return Utils.randIntRange(0, 2) ? statusEffectA : statusEffectB;
}
/**
* Returns a random non-volatile StatusEffect between the two provided
* @param statusA The first Status
* @param statusB The second Status
*/
export function getRandomStatus(statusA: Status, statusB: Status): Status {
if (statusA === undefined || statusA.effect === StatusEffect.NONE || statusA.effect === StatusEffect.FAINT) {
return statusB;
}
if (statusB === undefined || statusB.effect === StatusEffect.NONE || statusB.effect === StatusEffect.FAINT) {
return statusA;
}
return Utils.randIntRange(0, 2) ? statusA : statusB;
}

View File

@ -14,7 +14,7 @@ import { AttackTypeBoosterModifier, DamageMoneyRewardModifier, EnemyDamageBooste
import { PokeballType } from '../data/pokeball'; import { PokeballType } from '../data/pokeball';
import { Gender } from '../data/gender'; import { Gender } from '../data/gender';
import { initMoveAnim, loadMoveAnimAssets } from '../data/battle-anims'; import { initMoveAnim, loadMoveAnimAssets } from '../data/battle-anims';
import { Status, StatusEffect } from '../data/status-effect'; import { Status, StatusEffect, getRandomStatus } from '../data/status-effect';
import { pokemonEvolutions, pokemonPrevolutions, SpeciesFormEvolution, SpeciesEvolutionCondition, FusionSpeciesFormEvolution } from '../data/pokemon-evolutions'; import { pokemonEvolutions, pokemonPrevolutions, SpeciesFormEvolution, SpeciesEvolutionCondition, FusionSpeciesFormEvolution } from '../data/pokemon-evolutions';
import { reverseCompatibleTms, tmSpecies } from '../data/tms'; import { reverseCompatibleTms, tmSpecies } from '../data/tms';
import { DamagePhase, FaintPhase, LearnMovePhase, ObtainStatusEffectPhase, StatChangePhase, SwitchSummonPhase } from '../phases'; import { DamagePhase, FaintPhase, LearnMovePhase, ObtainStatusEffectPhase, StatChangePhase, SwitchSummonPhase } from '../phases';
@ -2542,6 +2542,10 @@ export class PlayerPokemon extends Pokemon {
this.generateCompatibleTms(); this.generateCompatibleTms();
} }
/**
* Returns a Promise to fuse two PlayerPokemon together
* @param pokemon The PlayerPokemon to fuse to this one
*/
fuse(pokemon: PlayerPokemon): Promise<void> { fuse(pokemon: PlayerPokemon): Promise<void> {
return new Promise(resolve => { return new Promise(resolve => {
this.fusionSpecies = pokemon.species; this.fusionSpecies = pokemon.species;
@ -2555,8 +2559,25 @@ export class PlayerPokemon extends Pokemon {
this.scene.validateAchv(achvs.SPLICE); this.scene.validateAchv(achvs.SPLICE);
this.scene.gameData.gameStats.pokemonFused++; this.scene.gameData.gameStats.pokemonFused++;
// Store the average HP% that each Pokemon has
const newHpPercent = ((pokemon.hp / pokemon.stats[Stat.HP]) + (this.hp / this.stats[Stat.HP])) / 2;
this.generateName(); this.generateName();
this.calculateStats(); this.calculateStats();
// Set this Pokemon's HP to the average % of both fusion components
this.hp = Math.round(this.stats[Stat.HP] * newHpPercent);
if (!this.isFainted()) {
// If this Pokemon hasn't fainted, make sure the HP wasn't set over the new maximum
this.hp = Math.min(this.hp, this.stats[Stat.HP]);
this.status = getRandomStatus(this.status, pokemon.status); // Get a random valid status between the two
}
else if (!pokemon.isFainted()) {
// If this Pokemon fainted but the other hasn't, make sure the HP wasn't set to zero
this.hp = Math.max(this.hp, 1);
this.status = pokemon.status; // Inherit the other Pokemon's status
}
this.generateCompatibleTms(); this.generateCompatibleTms();
this.updateInfo(true); this.updateInfo(true);
const fusedPartyMemberIndex = this.scene.getParty().indexOf(pokemon); const fusedPartyMemberIndex = this.scene.getParty().indexOf(pokemon);

View File

@ -1179,14 +1179,25 @@ export class SummonPhase extends PartyMemberPokemonPhase {
this.preSummon(); this.preSummon();
} }
/**
* Sends out a Pokemon before the battle begins and shows the appropriate messages
*/
preSummon(): void { preSummon(): void {
const partyMember = this.getPokemon(); const partyMember = this.getPokemon();
// If the Pokemon about to be sent out is fainted, switch to the first non-fainted Pokemon
if (partyMember.isFainted()) { if (partyMember.isFainted()) {
console.warn("The Pokemon about to be sent out is fainted. Attempting to resolve...");
const party = this.getParty(); const party = this.getParty();
const nonFaintedIndex = party.slice(this.partyMemberIndex).findIndex(p => !p.isFainted()) + this.partyMemberIndex;
const nonFaintedPartyMember = party[nonFaintedIndex]; const nonFaintedIndex = party.findIndex(x => !x.isFainted()); // Find the first non-fainted Pokemon index
party[nonFaintedIndex] = partyMember; if (nonFaintedIndex === -1) {
party[this.partyMemberIndex] = nonFaintedPartyMember; console.error("Party Details:\n", party);
throw new Error("All available Pokemon were fainted!");
}
// Swaps the fainted Pokemon and the first non-fainted Pokemon in the party
[party[this.partyMemberIndex], party[nonFaintedIndex]] = [party[nonFaintedIndex], party[this.partyMemberIndex]];
console.warn("Swapped %s %O with %s %O", partyMember?.name, partyMember, party[0]?.name, party[0]);
} }
if (this.player) { if (this.player) {

View File

@ -62,6 +62,11 @@ export function padInt(value: integer, length: integer, padWith?: string): strin
return valueStr; return valueStr;
} }
/**
* Returns a random integer between min and min + range
* @param range The amount of possible numbers
* @param min The starting number
*/
export function randInt(range: integer, min: integer = 0): integer { export function randInt(range: integer, min: integer = 0): integer {
if (range === 1) if (range === 1)
return min; return min;
@ -74,6 +79,11 @@ export function randSeedInt(range: integer, min: integer = 0): integer {
return Phaser.Math.RND.integerInRange(min, (range - 1) + min); return Phaser.Math.RND.integerInRange(min, (range - 1) + min);
} }
/**
* Returns a random integer between min and max (non-inclusive)
* @param min The lowest number
* @param max The highest number
*/
export function randIntRange(min: integer, max: integer): integer { export function randIntRange(min: integer, max: integer): integer {
return randInt(max - min, min); return randInt(max - min, min);
} }