mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-07-06 16:32:16 +02:00
Merge branch 'main' of github.com:Greenlamp2/pokerogue into test_instance
This commit is contained in:
commit
bea0e216ab
@ -2356,7 +2356,7 @@ export class IncreasePpAbAttr extends AbAttr { }
|
||||
|
||||
export class ForceSwitchOutImmunityAbAttr extends AbAttr {
|
||||
apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` can't be switched out!`))
|
||||
cancelled.value = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -327,11 +327,13 @@ export default class Move implements Localizable {
|
||||
}
|
||||
|
||||
getFailedText(user: Pokemon, target: Pokemon, move: Move, cancelled: Utils.BooleanHolder): string | null {
|
||||
let failedText = null;
|
||||
for (let attr of this.attrs)
|
||||
failedText = attr.getFailedText(user, target, move, cancelled);
|
||||
for (let attr of this.attrs) {
|
||||
let failedText = attr.getFailedText(user, target, move, cancelled);
|
||||
if (failedText !== null)
|
||||
return failedText;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer {
|
||||
let score = 0;
|
||||
@ -445,7 +447,9 @@ export abstract class MoveAttr {
|
||||
export enum MoveEffectTrigger {
|
||||
PRE_APPLY,
|
||||
POST_APPLY,
|
||||
HIT
|
||||
HIT,
|
||||
/** Triggers one time after all target effects have applied */
|
||||
POST_TARGET,
|
||||
}
|
||||
|
||||
export class MoveEffectAttr extends MoveAttr {
|
||||
@ -738,19 +742,33 @@ export class SacrificialAttr extends MoveEffectAttr {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attribute used for moves which cut the user's Max HP in half.
|
||||
* Triggers using POST_TARGET.
|
||||
*/
|
||||
export class HalfSacrificialAttr extends MoveEffectAttr {
|
||||
constructor() {
|
||||
super(true, MoveEffectTrigger.PRE_APPLY);
|
||||
super(true, MoveEffectTrigger.POST_TARGET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cut's the user's Max HP in half and displays the appropriate recoil message
|
||||
* @param user Pokemon that used the move
|
||||
* @param target N/A
|
||||
* @param move Move with this attribute
|
||||
* @param args N/A
|
||||
* @returns true if the function succeeds
|
||||
*/
|
||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||
if (!super.apply(user, target, move, args))
|
||||
return false;
|
||||
|
||||
const cancelled = new Utils.BooleanHolder(false);
|
||||
// Check to see if the Pokemon has an ability that blocks non-direct damage
|
||||
applyAbAttrs(BlockNonDirectDamageAbAttr, user, cancelled);
|
||||
if (!cancelled.value){
|
||||
user.damageAndUpdate(Math.ceil(user.getMaxHp()/2), HitResult.OTHER, false, true, true);
|
||||
user.scene.queueMessage(getPokemonMessage(user, ' cut its own HP to power up its move!')); // Queue recoil message
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -2703,26 +2721,19 @@ export class AddBattlerTagAttr extends MoveEffectAttr {
|
||||
export class CurseAttr extends MoveEffectAttr {
|
||||
|
||||
apply(user: Pokemon, target: Pokemon, move:Move, args: any[]): boolean {
|
||||
// Determine the correct target based on the user's type
|
||||
if (!user.getTypes(true).includes(Type.GHOST)) {
|
||||
// For non-Ghost types, target the user itself
|
||||
target = user;
|
||||
}
|
||||
|
||||
if (user.getTypes(true).includes(Type.GHOST)) {
|
||||
if (target.getTag(BattlerTagType.CURSED)) {
|
||||
user.scene.queueMessage('But it failed!');
|
||||
return false;
|
||||
}
|
||||
let curseRecoilDamage = Math.floor(user.getMaxHp() / 2);
|
||||
let curseRecoilDamage = Math.max(1, Math.floor(user.getMaxHp() / 2));
|
||||
user.damageAndUpdate(curseRecoilDamage, HitResult.OTHER, false, true, true);
|
||||
user.scene.queueMessage(getPokemonMessage(user, ` cut its own HP\nand laid a curse on the ${target.name}!`));
|
||||
target.addTag(BattlerTagType.CURSED, 0, move.id, user.id);
|
||||
return true;
|
||||
} else {
|
||||
target = user;
|
||||
user.scene.unshiftPhase(new StatChangePhase(user.scene, user.getBattlerIndex(), this.selfTarget, [BattleStat.ATK, BattleStat.DEF], 1));
|
||||
user.scene.unshiftPhase(new StatChangePhase(user.scene, user.getBattlerIndex(), this.selfTarget, [BattleStat.SPD], -1));
|
||||
user.scene.unshiftPhase(new StatChangePhase(user.scene, user.getBattlerIndex(), true, [BattleStat.ATK, BattleStat.DEF], 1));
|
||||
user.scene.unshiftPhase(new StatChangePhase(user.scene, user.getBattlerIndex(), true, [BattleStat.SPD], -1));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -2977,7 +2988,7 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
|
||||
return new Promise(resolve => {
|
||||
|
||||
// Check if the move category is not STATUS or if the switch out condition is not met
|
||||
if (!this.getCondition()(user, target, move)) {
|
||||
if (!this.getSwitchOutCondition()(user, target, move)) {
|
||||
//Apply effects before switch out i.e. poison point, flame body, etc
|
||||
applyPostDefendAbAttrs(PostDefendContactApplyStatusEffectAbAttr, target, user, new PokemonMove(move.id), null);
|
||||
return resolve(false);
|
||||
@ -3035,8 +3046,9 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
|
||||
}
|
||||
|
||||
getFailedText(user: Pokemon, target: Pokemon, move: Move, cancelled: Utils.BooleanHolder): string | null {
|
||||
applyAbAttrs(ForceSwitchOutImmunityAbAttr, target, cancelled);
|
||||
return null;
|
||||
const blockedByAbility = new Utils.BooleanHolder(false);
|
||||
applyAbAttrs(ForceSwitchOutImmunityAbAttr, target, blockedByAbility);
|
||||
return blockedByAbility.value ? getPokemonMessage(target, ` can't be switched out!`) : null;
|
||||
}
|
||||
|
||||
getSwitchOutCondition(): MoveConditionFunc {
|
||||
@ -3809,6 +3821,9 @@ const failOnMaxCondition: MoveConditionFunc = (user, target, move) => !target.is
|
||||
const failIfDampCondition: MoveConditionFunc = (user, target, move) => {
|
||||
const cancelled = new Utils.BooleanHolder(false);
|
||||
user.scene.getField(true).map(p=>applyAbAttrs(FieldPreventExplosiveMovesAbAttr, p, cancelled));
|
||||
// Queue a message if an ability prevented usage of the move
|
||||
if (cancelled.value)
|
||||
user.scene.queueMessage(getPokemonMessage(user, ` cannot use ${move.name}!`));
|
||||
return !cancelled.value;
|
||||
}
|
||||
|
||||
@ -4402,10 +4417,8 @@ export function initMoves() {
|
||||
.condition((user, target, move) => user.status?.effect === StatusEffect.SLEEP)
|
||||
.soundBased(),
|
||||
new StatusMove(Moves.CURSE, Type.GHOST, -1, 10, -1, 0, 2)
|
||||
.attr(StatChangeAttr, BattleStat.SPD, -1, true)
|
||||
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF ], 1, true)
|
||||
.target(MoveTarget.USER)
|
||||
.partial(),
|
||||
.attr(CurseAttr)
|
||||
.ignoresProtect(true),
|
||||
new AttackMove(Moves.FLAIL, Type.NORMAL, MoveCategory.PHYSICAL, -1, 100, 15, -1, 0, 2)
|
||||
.attr(LowHpPowerAttr),
|
||||
new StatusMove(Moves.CONVERSION_2, Type.NORMAL, -1, 30, -1, 0, 2)
|
||||
@ -6249,8 +6262,7 @@ export function initMoves() {
|
||||
.partial(),
|
||||
new SelfStatusMove(Moves.TAKE_HEART, Type.PSYCHIC, -1, 10, -1, 0, 8)
|
||||
.attr(StatChangeAttr, [ BattleStat.SPATK, BattleStat.SPDEF ], 1, true)
|
||||
.attr(HealStatusEffectAttr, true, StatusEffect.PARALYSIS, StatusEffect.POISON, StatusEffect.TOXIC, StatusEffect.BURN)
|
||||
.condition((user, target, move) => user.status && (user.status.effect === StatusEffect.PARALYSIS || user.status.effect === StatusEffect.POISON || user.status.effect === StatusEffect.TOXIC || user.status.effect === StatusEffect.BURN)),
|
||||
.attr(HealStatusEffectAttr, true, StatusEffect.PARALYSIS, StatusEffect.POISON, StatusEffect.TOXIC, StatusEffect.BURN, StatusEffect.SLEEP),
|
||||
/* Unused
|
||||
new AttackMove(Moves.G_MAX_WILDFIRE, Type.FIRE, MoveCategory.PHYSICAL, 10, -1, 10, -1, 0, 8)
|
||||
.target(MoveTarget.ALL_NEAR_ENEMIES)
|
||||
|
@ -54,6 +54,10 @@ export class InputsController {
|
||||
|
||||
init(): void {
|
||||
this.events = new Phaser.Events.EventEmitter();
|
||||
// Handle the game losing focus
|
||||
this.scene.game.events.on(Phaser.Core.Events.BLUR, () => {
|
||||
this.loseFocus()
|
||||
})
|
||||
|
||||
if (typeof this.scene.input.gamepad !== 'undefined') {
|
||||
this.scene.input.gamepad.on('connected', function (thisGamepad) {
|
||||
@ -78,10 +82,14 @@ export class InputsController {
|
||||
this.setupKeyboardControls();
|
||||
}
|
||||
|
||||
loseFocus(): void {
|
||||
this.deactivatePressedKey();
|
||||
}
|
||||
|
||||
update(): void {
|
||||
for (const b of Utils.getEnumValues(Button)) {
|
||||
if (!this.interactions.hasOwnProperty(b)) continue;
|
||||
if (this.repeatInputDurationJustPassed(b)) {
|
||||
if (this.repeatInputDurationJustPassed(b) && this.interactions[b].isPressed) {
|
||||
this.events.emit('input_down', {
|
||||
controller_type: 'repeated',
|
||||
button: b,
|
||||
@ -166,8 +174,8 @@ export class InputsController {
|
||||
[Button.LEFT]: [keyCodes.LEFT, keyCodes.A],
|
||||
[Button.RIGHT]: [keyCodes.RIGHT, keyCodes.D],
|
||||
[Button.SUBMIT]: [keyCodes.ENTER],
|
||||
[Button.ACTION]: [keyCodes.SPACE, this.scene.abSwapped ? keyCodes.X : keyCodes.Z],
|
||||
[Button.CANCEL]: [keyCodes.BACKSPACE, this.scene.abSwapped ? keyCodes.Z : keyCodes.X],
|
||||
[Button.ACTION]: [keyCodes.SPACE, keyCodes.Z],
|
||||
[Button.CANCEL]: [keyCodes.BACKSPACE, keyCodes.X],
|
||||
[Button.MENU]: [keyCodes.ESC, keyCodes.M],
|
||||
[Button.STATS]: [keyCodes.SHIFT, keyCodes.C],
|
||||
[Button.CYCLE_SHINY]: [keyCodes.R],
|
||||
@ -248,11 +256,22 @@ export class InputsController {
|
||||
if (!this.interactions.hasOwnProperty(button)) return;
|
||||
this.buttonLock = button;
|
||||
this.interactions[button].pressTime = this.time.now;
|
||||
this.interactions[button].isPressed = true;
|
||||
}
|
||||
|
||||
delLastProcessedMovementTime(button: Button): void {
|
||||
if (!this.interactions.hasOwnProperty(button)) return;
|
||||
this.buttonLock = null;
|
||||
this.interactions[button].pressTime = null;
|
||||
this.interactions[button].isPressed = false;
|
||||
}
|
||||
|
||||
deactivatePressedKey(): void {
|
||||
this.buttonLock = null;
|
||||
for (const b of Utils.getEnumValues(Button)) {
|
||||
if (!this.interactions.hasOwnProperty(b)) return;
|
||||
this.interactions[b].pressTime = null;
|
||||
this.interactions[b].isPressed = false;
|
||||
}
|
||||
}
|
||||
}
|
@ -2278,7 +2278,7 @@ export class MovePhase extends BattlePhase {
|
||||
|
||||
// Assume conditions affecting targets only apply to moves with a single target
|
||||
let success = this.move.getMove().applyConditions(this.pokemon, targets[0], this.move.getMove());
|
||||
let cancelled = new Utils.BooleanHolder(true);
|
||||
let cancelled = new Utils.BooleanHolder(false);
|
||||
let failedText = this.move.getMove().getFailedText(this.pokemon, targets[0], this.move.getMove(), cancelled);
|
||||
if (success && this.scene.arena.isMoveWeatherCancelled(this.move.getMove()))
|
||||
success = false;
|
||||
@ -2494,6 +2494,9 @@ export class MoveEffectPhase extends PokemonPhase {
|
||||
});
|
||||
}));
|
||||
}
|
||||
// Trigger effect which should only apply one time after all targeted effects have already applied
|
||||
applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && (attr as MoveEffectAttr).trigger === MoveEffectTrigger.POST_TARGET,
|
||||
user, null, this.move.getMove())
|
||||
Promise.allSettled(applyAttrs).then(() => this.end());
|
||||
});
|
||||
});
|
||||
|
@ -358,8 +358,11 @@ export class GameData {
|
||||
this.starterData = systemData.starterData;
|
||||
}
|
||||
|
||||
if (systemData.gameStats)
|
||||
if (systemData.gameStats) {
|
||||
if (systemData.gameStats.legendaryPokemonCaught !== undefined && systemData.gameStats.subLegendaryPokemonCaught === undefined)
|
||||
this.fixLegendaryStats(systemData);
|
||||
this.gameStats = systemData.gameStats;
|
||||
}
|
||||
|
||||
if (systemData.unlocks) {
|
||||
for (let key of Object.keys(systemData.unlocks)) {
|
||||
@ -1005,7 +1008,9 @@ export class GameData {
|
||||
if (incrementCount) {
|
||||
dexEntry.seenCount++;
|
||||
this.gameStats.pokemonSeen++;
|
||||
if (!trainer && pokemon.species.subLegendary || pokemon.species.legendary)
|
||||
if (!trainer && pokemon.species.subLegendary)
|
||||
this.gameStats.subLegendaryPokemonSeen++;
|
||||
else if (!trainer && pokemon.species.legendary)
|
||||
this.gameStats.legendaryPokemonSeen++;
|
||||
else if (!trainer && pokemon.species.mythical)
|
||||
this.gameStats.mythicalPokemonSeen++;
|
||||
@ -1043,7 +1048,9 @@ export class GameData {
|
||||
if (!fromEgg) {
|
||||
dexEntry.caughtCount++;
|
||||
this.gameStats.pokemonCaught++;
|
||||
if (pokemon.species.subLegendary || pokemon.species.legendary)
|
||||
if (pokemon.species.subLegendary)
|
||||
this.gameStats.subLegendaryPokemonCaught++;
|
||||
else if (pokemon.species.legendary)
|
||||
this.gameStats.legendaryPokemonCaught++;
|
||||
else if (pokemon.species.mythical)
|
||||
this.gameStats.mythicalPokemonCaught++;
|
||||
@ -1052,7 +1059,9 @@ export class GameData {
|
||||
} else {
|
||||
dexEntry.hatchedCount++;
|
||||
this.gameStats.pokemonHatched++;
|
||||
if (pokemon.species.subLegendary || pokemon.species.legendary)
|
||||
if (pokemon.species.subLegendary)
|
||||
this.gameStats.subLegendaryPokemonHatched++;
|
||||
else if (pokemon.species.legendary)
|
||||
this.gameStats.legendaryPokemonHatched++;
|
||||
else if (pokemon.species.mythical)
|
||||
this.gameStats.mythicalPokemonHatched++;
|
||||
@ -1311,4 +1320,22 @@ export class GameData {
|
||||
for (let starterId of defaultStarterSpecies)
|
||||
systemData.starterData[starterId].abilityAttr |= AbilityAttr.ABILITY_1;
|
||||
}
|
||||
|
||||
fixLegendaryStats(systemData: SystemSaveData): void {
|
||||
systemData.gameStats.subLegendaryPokemonSeen = 0;
|
||||
systemData.gameStats.subLegendaryPokemonCaught = 0;
|
||||
systemData.gameStats.subLegendaryPokemonHatched = 0;
|
||||
allSpecies.filter(s => s.subLegendary).forEach(s => {
|
||||
const dexEntry = systemData.dexData[s.speciesId];
|
||||
systemData.gameStats.subLegendaryPokemonSeen += dexEntry.seenCount;
|
||||
systemData.gameStats.legendaryPokemonSeen = Math.max(systemData.gameStats.legendaryPokemonSeen - dexEntry.seenCount, 0);
|
||||
systemData.gameStats.subLegendaryPokemonCaught += dexEntry.caughtCount;
|
||||
systemData.gameStats.legendaryPokemonCaught = Math.max(systemData.gameStats.legendaryPokemonCaught - dexEntry.caughtCount, 0);
|
||||
systemData.gameStats.subLegendaryPokemonHatched += dexEntry.hatchedCount;
|
||||
systemData.gameStats.legendaryPokemonHatched = Math.max(systemData.gameStats.legendaryPokemonHatched - dexEntry.hatchedCount, 0);
|
||||
});
|
||||
systemData.gameStats.subLegendaryPokemonSeen = Math.max(systemData.gameStats.subLegendaryPokemonSeen, systemData.gameStats.subLegendaryPokemonCaught);
|
||||
systemData.gameStats.legendaryPokemonSeen = Math.max(systemData.gameStats.legendaryPokemonSeen, systemData.gameStats.legendaryPokemonCaught);
|
||||
systemData.gameStats.mythicalPokemonSeen = Math.max(systemData.gameStats.mythicalPokemonSeen, systemData.gameStats.mythicalPokemonCaught);
|
||||
}
|
||||
}
|
@ -18,6 +18,9 @@ export class GameStats {
|
||||
public pokemonDefeated: integer;
|
||||
public pokemonCaught: integer;
|
||||
public pokemonHatched: integer;
|
||||
public subLegendaryPokemonSeen: integer;
|
||||
public subLegendaryPokemonCaught: integer;
|
||||
public subLegendaryPokemonHatched: integer;
|
||||
public legendaryPokemonSeen: integer;
|
||||
public legendaryPokemonCaught: integer;
|
||||
public legendaryPokemonHatched: integer;
|
||||
@ -52,6 +55,10 @@ export class GameStats {
|
||||
this.pokemonDefeated = source?.pokemonDefeated || 0;
|
||||
this.pokemonCaught = source?.pokemonCaught || 0;
|
||||
this.pokemonHatched = source?.pokemonHatched || 0;
|
||||
// Currently handled by migration
|
||||
this.subLegendaryPokemonSeen = source?.subLegendaryPokemonSeen;
|
||||
this.subLegendaryPokemonCaught = source?.subLegendaryPokemonCaught;
|
||||
this.subLegendaryPokemonHatched = source?.subLegendaryPokemonHatched;
|
||||
this.legendaryPokemonSeen = source?.legendaryPokemonSeen || 0;
|
||||
this.legendaryPokemonCaught = source?.legendaryPokemonCaught || 0;
|
||||
this.legendaryPokemonHatched = source?.legendaryPokemonHatched || 0;
|
||||
|
@ -64,13 +64,16 @@ const displayStats: DisplayStats = {
|
||||
pokemonDefeated: 'Pokémon Defeated',
|
||||
pokemonCaught: 'Pokémon Caught',
|
||||
pokemonHatched: 'Eggs Hatched',
|
||||
legendaryPokemonSeen: 'Legendary Encounters?',
|
||||
legendaryPokemonCaught: 'Legendaries Caught?',
|
||||
legendaryPokemonHatched: 'Legendaries Hatched?',
|
||||
mythicalPokemonSeen: 'Mythical Encounters?',
|
||||
subLegendaryPokemonSeen: 'Sub-Legends Seen?',
|
||||
subLegendaryPokemonCaught: 'Sub-Legends Caught?',
|
||||
subLegendaryPokemonHatched: 'Sub-Legends Hatched?',
|
||||
legendaryPokemonSeen: 'Legends Seen?',
|
||||
legendaryPokemonCaught: 'Legends Caught?',
|
||||
legendaryPokemonHatched: 'Legends Hatched?',
|
||||
mythicalPokemonSeen: 'Mythicals Seen?',
|
||||
mythicalPokemonCaught: 'Mythicals Caught?',
|
||||
mythicalPokemonHatched: 'Mythicals Hatched?',
|
||||
shinyPokemonSeen: 'Shiny Encounters?',
|
||||
shinyPokemonSeen: 'Shinies Seen?',
|
||||
shinyPokemonCaught: 'Shinies Caught?',
|
||||
shinyPokemonHatched: 'Shinies Hatched?',
|
||||
pokemonFused: 'Pokémon Fused?',
|
||||
|
@ -226,7 +226,7 @@ export const apiUrl = isLocal ? serverUrl : 'api';
|
||||
|
||||
export function setCookie(cName: string, cValue: string): void {
|
||||
const expiration = new Date();
|
||||
expiration.setTime(new Date().getTime() + 3600000 * 24 * 7);
|
||||
expiration.setTime(new Date().getTime() + 3600000 * 24 * 30 * 3/*7*/);
|
||||
document.cookie = `${cName}=${cValue};SameSite=Strict;path=/;expires=${expiration.toUTCString()}`;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user