Skip to content

Commit

Permalink
Merge branch 'mystery-encounters-main' of https://github.com/Innocent…
Browse files Browse the repository at this point in the history
…GameDev/PokeRogue-Events into netlify-beta

pull latest changes
  • Loading branch information
ImperialSympathizer committed Sep 9, 2024
2 parents 6d2c57f + 08e023e commit f952a28
Show file tree
Hide file tree
Showing 213 changed files with 2,620 additions and 1,943 deletions.
49 changes: 27 additions & 22 deletions create-test-boilerplate.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,54 +20,58 @@ const type = args[0]; // "move" or "ability"
let fileName = args[1]; // The file name

if (!type || !fileName) {
console.error('Please provide both a type ("move", "ability", or "item") and a file name.');
process.exit(1);
console.error('Please provide a type ("move", "ability", or "item") and a file name.');
process.exit(1);
}

// Convert fileName from to snake_case if camelCase is given
fileName = fileName.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase();
// Convert fileName from kebab-case or camelCase to snake_case
fileName = fileName
.replace(/-+/g, '_') // Convert kebab-case (dashes) to underscores
.replace(/([a-z])([A-Z])/g, '$1_$2') // Convert camelCase to snake_case
.toLowerCase(); // Ensure all lowercase

// Format the description for the test case
const formattedName = fileName
.replace(/_/g, ' ')
.replace(/\b\w/g, char => char.toUpperCase());
.replace(/_/g, ' ')
.replace(/\b\w/g, char => char.toUpperCase());

// Determine the directory based on the type
let dir;
let description;
if (type === 'move') {
dir = path.join(__dirname, 'src', 'test', 'moves');
description = `Moves - ${formattedName}`;
dir = path.join(__dirname, 'src', 'test', 'moves');
description = `Moves - ${formattedName}`;
} else if (type === 'ability') {
dir = path.join(__dirname, 'src', 'test', 'abilities');
description = `Abilities - ${formattedName}`;
dir = path.join(__dirname, 'src', 'test', 'abilities');
description = `Abilities - ${formattedName}`;
} else if (type === "item") {
dir = path.join(__dirname, 'src', 'test', 'items');
description = `Items - ${formattedName}`;
dir = path.join(__dirname, 'src', 'test', 'items');
description = `Items - ${formattedName}`;
} else {
console.error('Invalid type. Please use "move", "ability", or "item".');
process.exit(1);
console.error('Invalid type. Please use "move", "ability", or "item".');
process.exit(1);
}

// Ensure the directory exists
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
fs.mkdirSync(dir, { recursive: true });
}

// Create the file with the given name
const filePath = path.join(dir, `${fileName}.test.ts`);

if (fs.existsSync(filePath)) {
console.error(`File "${fileName}.test.ts" already exists.`);
process.exit(1);
console.error(`File "${fileName}.test.ts" already exists.`);
process.exit(1);
}

// Define the content template
const content = `import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, it } from "vitest";
import { afterEach, beforeAll, beforeEach, describe, it, expect } from "vitest";
describe("${description}", () => {
let phaserGame: Phaser.Game;
Expand All @@ -87,14 +91,15 @@ describe("${description}", () => {
beforeEach(() => {
game = new GameManager(phaserGame);
game.override
.moveset([Moves.SPLASH])
.battleType("single")
.enemyAbility(Abilities.BALL_FETCH)
.enemyMoveset(SPLASH_ONLY);
.enemyMoveset(Moves.SPLASH);
});
it("test case", async () => {
// await game.classicMode.startBattle();
// game.move.select();
// await game.classicMode.startBattle([Species.MAGIKARP]);
// game.move.select(Moves.SPLASH);
}, TIMEOUT);
});
`;
Expand Down
Binary file removed public/images/ui/legacy/summary_moves_effect_de.png
Binary file not shown.
Binary file removed public/images/ui/legacy/summary_moves_effect_es.png
Binary file not shown.
Binary file removed public/images/ui/legacy/summary_moves_effect_fr.png
Binary file not shown.
Binary file removed public/images/ui/legacy/summary_moves_effect_it.png
Binary file not shown.
Binary file removed public/images/ui/legacy/summary_moves_effect_pt-BR.png
Binary file not shown.
Binary file removed public/images/ui/legacy/summary_moves_effect_zh-CN.png
Binary file not shown.
36 changes: 24 additions & 12 deletions src/battle-scene.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ import { ToggleDoublePositionPhase } from "./phases/toggle-double-position-phase
import { TurnInitPhase } from "./phases/turn-init-phase";
import { ShopCursorTarget } from "./enums/shop-cursor-target";
import MysteryEncounter from "./data/mystery-encounters/mystery-encounter";
import { allMysteryEncounters, ANTI_VARIANCE_WEIGHT_MODIFIER, AVERAGE_ENCOUNTERS_PER_RUN_TARGET, BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT, mysteryEncountersByBiome, WEIGHT_INCREMENT_ON_SPAWN_MISS } from "./data/mystery-encounters/mystery-encounters";
import { allMysteryEncounters, ANTI_VARIANCE_WEIGHT_MODIFIER, AVERAGE_ENCOUNTERS_PER_RUN_TARGET, BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT, MYSTERY_ENCOUNTER_SPAWN_MAX_WEIGHT, mysteryEncountersByBiome, WEIGHT_INCREMENT_ON_SPAWN_MISS } from "./data/mystery-encounters/mystery-encounters";
import { MysteryEncounterSaveData } from "#app/data/mystery-encounters/mystery-encounter-save-data";
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
Expand Down Expand Up @@ -256,7 +256,7 @@ export default class BattleScene extends SceneBase {
public money: integer;
public pokemonInfoContainer: PokemonInfoContainer;
private party: PlayerPokemon[];
public mysteryEncounterSaveData: MysteryEncounterSaveData = new MysteryEncounterSaveData(null);
public mysteryEncounterSaveData: MysteryEncounterSaveData = new MysteryEncounterSaveData();
public lastMysteryEncounter?: MysteryEncounter;
/** Combined Biome and Wave count text */
private biomeWaveText: Phaser.GameObjects.Text;
Expand Down Expand Up @@ -411,7 +411,6 @@ export default class BattleScene extends SceneBase {

this.fieldUI = fieldUI;

// @ts-ignore
const transition = this.make.rexTransitionImagePack({
x: 0,
y: 0,
Expand Down Expand Up @@ -897,6 +896,12 @@ export default class BattleScene extends SceneBase {
return pokemon;
}

/**
* Removes a PlayerPokemon from the party, and clears modifiers for that Pokemon's id
* Useful for MEs/Challenges that remove Pokemon from the player party temporarily or permanently
* @param pokemon
* @param destroy - Default true. If true, will destroy the Pokemon object after removing
*/
removePokemonFromPlayerParty(pokemon: PlayerPokemon, destroy: boolean = true) {
if (!pokemon) {
return;
Expand Down Expand Up @@ -1113,7 +1118,7 @@ export default class BattleScene extends SceneBase {
}
}

newBattle(waveIndex?: integer, battleType?: BattleType, trainerData?: TrainerData, double?: boolean, mysteryEncounter?: MysteryEncounter): Battle | null {
newBattle(waveIndex?: integer, battleType?: BattleType, trainerData?: TrainerData, double?: boolean, mysteryEncounterType?: MysteryEncounterType): Battle | null {
const _startingWave = Overrides.STARTING_WAVE_OVERRIDE || startingWave;
const newWaveIndex = waveIndex || ((this.currentBattle?.waveIndex || (_startingWave - 1)) + 1);
let newDouble: boolean | undefined;
Expand Down Expand Up @@ -1165,10 +1170,10 @@ export default class BattleScene extends SceneBase {

// Check for mystery encounter
// Can only occur in place of a standard (non-boss) wild battle, waves 10-180
const highestMysteryEncounterWave = 180;
const lowestMysteryEncounterWave = 10;
const highestMysteryEncounterWave = this.gameMode.maxMysteryEncounterWave;
const lowestMysteryEncounterWave = this.gameMode.minMysteryEncounterWave;
if (this.gameMode.hasMysteryEncounters && newBattleType === BattleType.WILD && !this.gameMode.isBoss(newWaveIndex) && newWaveIndex < highestMysteryEncounterWave && newWaveIndex > lowestMysteryEncounterWave) {
const roll = Utils.randSeedInt(256);
const roll = Utils.randSeedInt(MYSTERY_ENCOUNTER_SPAWN_MAX_WEIGHT);

// Base spawn weight is BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT/256, and increases by WEIGHT_INCREMENT_ON_SPAWN_MISS/256 for each missed attempt at spawning an encounter on a valid floor
const sessionEncounterRate = this.mysteryEncounterSaveData.encounterSpawnChance;
Expand Down Expand Up @@ -1236,7 +1241,7 @@ export default class BattleScene extends SceneBase {
// Disable double battle on mystery encounters (it may be re-enabled as part of encounter)
this.currentBattle.double = false;
this.executeWithSeedOffset(() => {
this.currentBattle.mysteryEncounter = this.getMysteryEncounter(mysteryEncounter);
this.currentBattle.mysteryEncounter = this.getMysteryEncounter(mysteryEncounterType);
}, this.currentBattle.waveIndex << 4);
}

Expand All @@ -1248,7 +1253,7 @@ export default class BattleScene extends SceneBase {
const isEndlessFifthWave = this.gameMode.hasShortBiomes && (lastBattle.waveIndex % 5) === 0;
const isWaveIndexMultipleOfFiftyMinusOne = (lastBattle.waveIndex % 50) === 49;
const isNewBiome = isWaveIndexMultipleOfTen || isEndlessFifthWave || (isEndlessOrDaily && isWaveIndexMultipleOfFiftyMinusOne);
const resetArenaState = isNewBiome || this.currentBattle.battleType === BattleType.TRAINER || this.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER || this.currentBattle.battleSpec === BattleSpec.FINAL_BOSS;
const resetArenaState = isNewBiome || [BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(this.currentBattle.battleType) || this.currentBattle.battleSpec === BattleSpec.FINAL_BOSS;
this.getEnemyParty().forEach(enemyPokemon => enemyPokemon.destroy());
this.trySpreadPokerus();
if (!isNewBiome && (newWaveIndex % 10) === 5) {
Expand Down Expand Up @@ -2920,6 +2925,13 @@ export default class BattleScene extends SceneBase {
this.shiftPhase();
}

/**
* Updates Exp and level values for Player's party, adding new level up phases as required
* @param expValue - raw value of exp to split among participants, OR the base multiplier to use with waveIndex
* @param pokemonDefeated - If true, will increment Macho Brace stacks and give the party Pokemon friendship increases
* @param useWaveIndexMultiplier - Default false. If true, will multiply expValue by a scaling waveIndex multiplier. Not needed if expValue is already scaled by level/wave
* @param pokemonParticipantIds - Participants. If none are defined, no exp will be given. To spread evenly among the party, should pass all ids of party members.
*/
applyPartyExp(expValue: number, pokemonDefeated: boolean, useWaveIndexMultiplier?: boolean, pokemonParticipantIds?: Set<number>): void {
const participantIds = pokemonParticipantIds ?? this.currentBattle.playerParticipantIds;
const party = this.getParty();
Expand Down Expand Up @@ -3016,16 +3028,16 @@ export default class BattleScene extends SceneBase {

/**
* Loads or generates a mystery encounter
* @param override - used to load session encounter when restarting game, etc.
* @param encounterType - used to load session encounter when restarting game, etc.
* @returns
*/
getMysteryEncounter(override: MysteryEncounter | undefined): MysteryEncounter {
getMysteryEncounter(encounterType?: MysteryEncounterType): MysteryEncounter {
// Loading override or session encounter
let encounter: MysteryEncounter | null;
if (!isNullOrUndefined(Overrides.MYSTERY_ENCOUNTER_OVERRIDE) && allMysteryEncounters.hasOwnProperty(Overrides.MYSTERY_ENCOUNTER_OVERRIDE!)) {
encounter = allMysteryEncounters[Overrides.MYSTERY_ENCOUNTER_OVERRIDE!];
} else {
encounter = override?.encounterType && override.encounterType >= 0 ? allMysteryEncounters[override.encounterType] : null;
encounter = !isNullOrUndefined(encounterType) ? allMysteryEncounters[encounterType!] : null;
}

// Check for queued encounters first
Expand Down
54 changes: 44 additions & 10 deletions src/data/ability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1595,8 +1595,8 @@ export class PostAttackAbAttr extends AbAttr {
private attackCondition: PokemonAttackCondition;

/** The default attackCondition requires that the selected move is a damaging move */
constructor(attackCondition: PokemonAttackCondition = (user, target, move) => (move.category !== MoveCategory.STATUS)) {
super();
constructor(attackCondition: PokemonAttackCondition = (user, target, move) => (move.category !== MoveCategory.STATUS), showAbility: boolean = true) {
super(showAbility);

this.attackCondition = attackCondition;
}
Expand Down Expand Up @@ -1624,6 +1624,40 @@ export class PostAttackAbAttr extends AbAttr {
}
}

/**
* Ability attribute for Gorilla Tactics
* @extends PostAttackAbAttr
*/
export class GorillaTacticsAbAttr extends PostAttackAbAttr {
constructor() {
super((user, target, move) => true, false);
}

/**
*
* @param {Pokemon} pokemon the {@linkcode Pokemon} with this ability
* @param passive n/a
* @param simulated whether the ability is being simulated
* @param defender n/a
* @param move n/a
* @param hitResult n/a
* @param args n/a
* @returns `true` if the ability is applied
*/
applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean | Promise<boolean> {
if (simulated) {
return simulated;
}

if (pokemon.getTag(BattlerTagType.GORILLA_TACTICS)) {
return false;
}

pokemon.addTag(BattlerTagType.GORILLA_TACTICS);
return true;
}
}

export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr {
private stealCondition: PokemonAttackCondition | null;

Expand Down Expand Up @@ -3923,7 +3957,7 @@ export class PostBattleLootAbAttr extends PostBattleAbAttr {
}

export class PostFaintAbAttr extends AbAttr {
applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker?: Pokemon, move?: Move, hitResult?: HitResult, ...args: any[]): boolean {
return false;
}
}
Expand Down Expand Up @@ -3974,7 +4008,7 @@ export class PostFaintClearWeatherAbAttr extends PostFaintAbAttr {
* @param args N/A
* @returns {boolean} Returns true if the weather clears, otherwise false.
*/
applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker?: Pokemon, move?: Move, hitResult?: HitResult, ...args: any[]): boolean {
const weatherType = pokemon.scene.arena.weather?.weatherType;
let turnOffWeather = false;

Expand Down Expand Up @@ -4022,8 +4056,8 @@ export class PostFaintContactDamageAbAttr extends PostFaintAbAttr {
this.damageRatio = damageRatio;
}

applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
if (move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) {
applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker?: Pokemon, move?: Move, hitResult?: HitResult, ...args: any[]): boolean {
if (move !== undefined && attacker !== undefined && move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) { //If the mon didn't die to indirect damage
const cancelled = new Utils.BooleanHolder(false);
pokemon.scene.getField(true).map(p => applyAbAttrs(FieldPreventExplosiveMovesAbAttr, p, cancelled, simulated));
if (cancelled.value || attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) {
Expand Down Expand Up @@ -4052,8 +4086,8 @@ export class PostFaintHPDamageAbAttr extends PostFaintAbAttr {
super ();
}

applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
if (!simulated) {
applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker?: Pokemon, move?: Move, hitResult?: HitResult, ...args: any[]): boolean {
if (move !== undefined && attacker !== undefined && !simulated) { //If the mon didn't die to indirect damage
const damage = pokemon.turnData.attacksReceived[0].damage;
attacker.damageAndUpdate((damage), HitResult.OTHER);
attacker.turnData.damageTaken += damage;
Expand Down Expand Up @@ -4711,7 +4745,7 @@ export function applyPostBattleAbAttrs(attrType: Constructor<PostBattleAbAttr>,
}

export function applyPostFaintAbAttrs(attrType: Constructor<PostFaintAbAttr>,
pokemon: Pokemon, attacker: Pokemon, move: Move, hitResult: HitResult, simulated: boolean = false, ...args: any[]): Promise<void> {
pokemon: Pokemon, attacker?: Pokemon, move?: Move, hitResult?: HitResult, simulated: boolean = false, ...args: any[]): Promise<void> {
return applyAbAttrsInternal<PostFaintAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostFaint(pokemon, passive, simulated, attacker, move, hitResult, args), args, false, simulated);
}

Expand Down Expand Up @@ -5597,7 +5631,7 @@ export function initAbilities() {
.bypassFaint()
.partial(),
new Ability(Abilities.GORILLA_TACTICS, 8)
.unimplemented(),
.attr(GorillaTacticsAbAttr),
new Ability(Abilities.NEUTRALIZING_GAS, 8)
.attr(SuppressFieldAbilitiesAbAttr)
.attr(UncopiableAbilityAbAttr)
Expand Down
Loading

0 comments on commit f952a28

Please sign in to comment.