mirror of
https://github.com/smogon/pokemon-showdown.git
synced 2026-03-21 17:25:10 -05:00
Implement randomFoe and foePokemonLeft
This commit is contained in:
parent
e5d52bb33c
commit
f6ec932e8d
|
|
@ -276,7 +276,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
|
|||
if (effect?.effectType !== 'Move') {
|
||||
return;
|
||||
}
|
||||
if (source.species.id === 'greninja' && source.hp && !source.transformed && source.side.foe.pokemonLeft) {
|
||||
if (source.species.id === 'greninja' && source.hp && !source.transformed && source.side.foePokemonLeft()) {
|
||||
this.add('-activate', source, 'ability: Battle Bond');
|
||||
source.formeChange('Greninja-Ash', this.effect, true);
|
||||
}
|
||||
|
|
@ -3154,19 +3154,14 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
|
|||
onStart(pokemon) {
|
||||
let activated = false;
|
||||
for (const sideCondition of ['reflect', 'lightscreen', 'auroraveil']) {
|
||||
if (pokemon.side.getSideCondition(sideCondition)) {
|
||||
if (!activated) {
|
||||
this.add('-activate', pokemon, 'ability: Screen Cleaner');
|
||||
activated = true;
|
||||
for (const side of [pokemon.side, ...pokemon.side.foeSidesWithConditions()]) {
|
||||
if (side.getSideCondition(sideCondition)) {
|
||||
if (!activated) {
|
||||
this.add('-activate', pokemon, 'ability: Screen Cleaner');
|
||||
activated = true;
|
||||
}
|
||||
side.removeSideCondition(sideCondition);
|
||||
}
|
||||
pokemon.side.removeSideCondition(sideCondition);
|
||||
}
|
||||
if (pokemon.side.foe.getSideCondition(sideCondition)) {
|
||||
if (!activated) {
|
||||
this.add('-activate', pokemon, 'ability: Screen Cleaner');
|
||||
activated = true;
|
||||
}
|
||||
pokemon.side.foe.removeSideCondition(sideCondition);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
|
|||
inherit: true,
|
||||
onUpdate(pokemon) {
|
||||
if (!pokemon.isStarted) return;
|
||||
const target = pokemon.side.foe.randomAlly();
|
||||
const target = pokemon.side.randomFoe();
|
||||
if (!target || target.fainted) return;
|
||||
const ability = target.getAbility();
|
||||
const bannedAbilities = ['forecast', 'multitype', 'trace'];
|
||||
|
|
|
|||
|
|
@ -454,7 +454,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
|
|||
inherit: true,
|
||||
onUpdate(pokemon) {
|
||||
if (!pokemon.isStarted) return;
|
||||
const target = pokemon.side.foe.randomAlly();
|
||||
const target = pokemon.side.randomFoe();
|
||||
if (!target || target.fainted) return;
|
||||
const ability = target.getAbility();
|
||||
const bannedAbilities = ['forecast', 'multitype', 'trace'];
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
|
|||
frisk: {
|
||||
inherit: true,
|
||||
onStart(pokemon) {
|
||||
const target = pokemon.side.foe.randomAlly();
|
||||
const target = pokemon.side.randomFoe();
|
||||
if (target?.item) {
|
||||
this.add('-item', target, target.getItem().name, '[from] ability: Frisk', '[of] ' + pokemon);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4877,20 +4877,16 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|||
this.add('-sidestart', targetSide, 'Fire Pledge');
|
||||
},
|
||||
onEnd(targetSide) {
|
||||
for (const pokemon of targetSide.activeTeam()) {
|
||||
if (pokemon && !pokemon.hasType('Fire')) {
|
||||
this.damage(pokemon.baseMaxhp / 8, pokemon);
|
||||
}
|
||||
for (const pokemon of targetSide.allies()) {
|
||||
if (!pokemon.hasType('Fire')) this.damage(pokemon.baseMaxhp / 8, pokemon);
|
||||
}
|
||||
this.add('-sideend', targetSide, 'Fire Pledge');
|
||||
},
|
||||
onResidualOrder: 5,
|
||||
onResidualSubOrder: 1,
|
||||
onResidual(side) {
|
||||
for (const pokemon of side.activeTeam()) {
|
||||
if (pokemon && !pokemon.hasType('Fire')) {
|
||||
this.damage(pokemon.baseMaxhp / 8, pokemon);
|
||||
}
|
||||
for (const pokemon of side.allies()) {
|
||||
if (!pokemon.hasType('Fire')) this.damage(pokemon.baseMaxhp / 8, pokemon);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
@ -5944,15 +5940,10 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|||
priority: 0,
|
||||
flags: {snatch: 1, authentic: 1},
|
||||
onHitSide(side, source, move) {
|
||||
const targets = [];
|
||||
for (const pokemon of side.activeTeam()) {
|
||||
if (
|
||||
pokemon.hasAbility(['plus', 'minus']) &&
|
||||
(!pokemon.volatiles['maxguard'] || this.runEvent('TryHit', pokemon, source, move))
|
||||
) {
|
||||
targets.push(pokemon);
|
||||
}
|
||||
}
|
||||
const targets = side.allies().filter(target => (
|
||||
target.hasAbility(['plus', 'minus']) &&
|
||||
(!target.volatiles['maxguard'] || this.runEvent('TryHit', target, source, move))
|
||||
));
|
||||
if (!targets.length) return false;
|
||||
let didSomething = false;
|
||||
for (const target of targets) {
|
||||
|
|
@ -6187,13 +6178,13 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|||
onResidualOrder: 5,
|
||||
onResidualSubOrder: 1.1,
|
||||
onResidual(targetSide) {
|
||||
for (const pokemon of targetSide.activeTeam()) {
|
||||
if (!pokemon.hasType('Water')) this.damage(pokemon.baseMaxhp / 6, pokemon);
|
||||
for (const target of targetSide.allies()) {
|
||||
if (!target.hasType('Water')) this.damage(target.baseMaxhp / 6, target);
|
||||
}
|
||||
},
|
||||
onEnd(targetSide) {
|
||||
for (const pokemon of targetSide.activeTeam()) {
|
||||
if (!pokemon.hasType('Water')) this.damage(pokemon.baseMaxhp / 6, pokemon);
|
||||
for (const target of targetSide.allies()) {
|
||||
if (!target.hasType('Water')) this.damage(target.baseMaxhp / 6, target);
|
||||
}
|
||||
this.add('-sideend', targetSide, 'G-Max Cannonade');
|
||||
},
|
||||
|
|
@ -6839,13 +6830,13 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|||
onResidualOrder: 5,
|
||||
onResidualSubOrder: 1.1,
|
||||
onResidual(targetSide) {
|
||||
for (const pokemon of targetSide.activeTeam()) {
|
||||
if (!pokemon.hasType('Grass')) this.damage(pokemon.baseMaxhp / 6, pokemon);
|
||||
for (const target of targetSide.allies()) {
|
||||
if (!target.hasType('Grass')) this.damage(target.baseMaxhp / 6, target);
|
||||
}
|
||||
},
|
||||
onEnd(targetSide) {
|
||||
for (const pokemon of targetSide.activeTeam()) {
|
||||
if (!pokemon.hasType('Grass')) this.damage(pokemon.baseMaxhp / 6, pokemon);
|
||||
for (const target of targetSide.allies()) {
|
||||
if (!target.hasType('Grass')) this.damage(target.baseMaxhp / 6, target);
|
||||
}
|
||||
this.add('-sideend', targetSide, 'G-Max Vine Lash');
|
||||
},
|
||||
|
|
@ -6879,13 +6870,13 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|||
onResidualOrder: 5,
|
||||
onResidualSubOrder: 1.1,
|
||||
onResidual(targetSide) {
|
||||
for (const pokemon of targetSide.activeTeam()) {
|
||||
if (!pokemon.hasType('Rock')) this.damage(pokemon.baseMaxhp / 6, pokemon);
|
||||
for (const target of targetSide.allies()) {
|
||||
if (!target.hasType('Rock')) this.damage(target.baseMaxhp / 6, target);
|
||||
}
|
||||
},
|
||||
onEnd(targetSide) {
|
||||
for (const pokemon of targetSide.activeTeam()) {
|
||||
if (!pokemon.hasType('Rock')) this.damage(pokemon.baseMaxhp / 6, pokemon);
|
||||
for (const target of targetSide.allies()) {
|
||||
if (!target.hasType('Rock')) this.damage(target.baseMaxhp / 6, target);
|
||||
}
|
||||
this.add('-sideend', targetSide, 'G-Max Volcalith');
|
||||
},
|
||||
|
|
@ -6942,13 +6933,13 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|||
onResidualOrder: 5,
|
||||
onResidualSubOrder: 1.1,
|
||||
onResidual(targetSide) {
|
||||
for (const pokemon of targetSide.activeTeam()) {
|
||||
if (!pokemon.hasType('Fire')) this.damage(pokemon.baseMaxhp / 6, pokemon);
|
||||
for (const target of targetSide.allies()) {
|
||||
if (!target.hasType('Fire')) this.damage(target.baseMaxhp / 6, target);
|
||||
}
|
||||
},
|
||||
onEnd(targetSide) {
|
||||
for (const pokemon of targetSide.activeTeam()) {
|
||||
if (!pokemon.hasType('Fire')) this.damage(pokemon.baseMaxhp / 6, pokemon);
|
||||
for (const target of targetSide.allies()) {
|
||||
if (!target.hasType('Fire')) this.damage(target.baseMaxhp / 6, target);
|
||||
}
|
||||
this.add('-sideend', targetSide, 'G-Max Wildfire');
|
||||
},
|
||||
|
|
@ -10106,16 +10097,12 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|||
priority: 0,
|
||||
flags: {snatch: 1, distance: 1, authentic: 1},
|
||||
onHitSide(side, source, move) {
|
||||
const targets = [];
|
||||
for (const pokemon of side.activeTeam()) {
|
||||
if (
|
||||
pokemon.hasAbility(['plus', 'minus']) &&
|
||||
(!pokemon.volatiles['maxguard'] || this.runEvent('TryHit', pokemon, source, move))
|
||||
) {
|
||||
targets.push(pokemon);
|
||||
}
|
||||
}
|
||||
const targets = side.allies().filter(ally => (
|
||||
ally.hasAbility(['plus', 'minus']) &&
|
||||
(!ally.volatiles['maxguard'] || this.runEvent('TryHit', ally, source, move))
|
||||
));
|
||||
if (!targets.length) return false;
|
||||
|
||||
let didSomething = false;
|
||||
for (const target of targets) {
|
||||
didSomething = this.boost({def: 1, spd: 1}, target, source, move, false, true) || didSomething;
|
||||
|
|
|
|||
|
|
@ -1414,7 +1414,7 @@ export class Battle {
|
|||
|
||||
if (this.maybeTriggerEndlessBattleClause(trappedBySide, stalenessBySide)) return;
|
||||
|
||||
if (this.gameType === 'triples' && !this.sides.filter(side => side.pokemonLeft > 1).length) {
|
||||
if (this.gameType === 'triples' && this.sides.every(side => side.pokemonLeft === 1)) {
|
||||
// If both sides have one Pokemon left in triples and they are not adjacent, they are both moved to the center.
|
||||
const actives = this.getAllActive();
|
||||
if (actives.length > 1 && !actives[0].isAdjacent(actives[1])) {
|
||||
|
|
@ -1594,7 +1594,7 @@ export class Battle {
|
|||
}
|
||||
if (!target?.hp) return 0;
|
||||
if (!target.isActive) return false;
|
||||
if (this.gen > 5 && !target.side.foe.pokemonLeft) return false;
|
||||
if (this.gen > 5 && !target.side.foePokemonLeft()) return false;
|
||||
boost = this.runEvent('Boost', target, source, effect, {...boost});
|
||||
let success = null;
|
||||
let boosted = isSecondary;
|
||||
|
|
@ -2062,7 +2062,7 @@ export class Battle {
|
|||
return foeActives[frontPosition];
|
||||
}
|
||||
}
|
||||
return pokemon.side.foe.randomAlly() || pokemon.side.foe.active[0];
|
||||
return pokemon.side.randomFoe() || pokemon.side.foe.active[0];
|
||||
}
|
||||
|
||||
checkFainted() {
|
||||
|
|
|
|||
21
sim/side.ts
21
sim/side.ts
|
|
@ -204,12 +204,27 @@ export class Side {
|
|||
return data;
|
||||
}
|
||||
|
||||
randomAlly() {
|
||||
const actives = this.allies();
|
||||
randomFoe() {
|
||||
const actives = this.foes();
|
||||
if (!actives.length) return null;
|
||||
return this.battle.sample(actives);
|
||||
}
|
||||
|
||||
/** Intended as a way to iterate through all foe side conditions - do not use for anything else. */
|
||||
foeSidesWithConditions() {
|
||||
if (this.battle.gameType === 'multi') return this.battle.sides.filter(side => side !== this);
|
||||
|
||||
return [this.foe];
|
||||
}
|
||||
foePokemonLeft() {
|
||||
if (this.battle.gameType === 'multi') {
|
||||
return this.battle.sides.filter(side => side !== this).map(side => side.pokemonLeft).reduce((a, b) => a + b);
|
||||
}
|
||||
|
||||
if (this.foe.allySide) return this.foe.pokemonLeft + this.foe.allySide.pokemonLeft;
|
||||
|
||||
return this.foe.pokemonLeft;
|
||||
}
|
||||
allies() {
|
||||
// called during the first switch-in, so `active` can still contain nulls at this point
|
||||
return this.activeTeam().filter(ally => ally && !ally.fainted);
|
||||
|
|
@ -217,7 +232,7 @@ export class Side {
|
|||
foes() {
|
||||
if (this.battle.gameType === 'free-for-all') {
|
||||
return this.battle.sides.map(side => side.active[0])
|
||||
.filter(pokemon => pokemon.side !== this && pokemon && !pokemon.fainted);
|
||||
.filter(pokemon => pokemon && pokemon.side !== this && !pokemon.fainted);
|
||||
}
|
||||
return this.foe.allies();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user