mirror of
https://github.com/smogon/pokemon-showdown.git
synced 2026-04-28 11:46:55 -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') {
|
if (effect?.effectType !== 'Move') {
|
||||||
return;
|
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');
|
this.add('-activate', source, 'ability: Battle Bond');
|
||||||
source.formeChange('Greninja-Ash', this.effect, true);
|
source.formeChange('Greninja-Ash', this.effect, true);
|
||||||
}
|
}
|
||||||
|
|
@ -3154,19 +3154,14 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
|
||||||
onStart(pokemon) {
|
onStart(pokemon) {
|
||||||
let activated = false;
|
let activated = false;
|
||||||
for (const sideCondition of ['reflect', 'lightscreen', 'auroraveil']) {
|
for (const sideCondition of ['reflect', 'lightscreen', 'auroraveil']) {
|
||||||
if (pokemon.side.getSideCondition(sideCondition)) {
|
for (const side of [pokemon.side, ...pokemon.side.foeSidesWithConditions()]) {
|
||||||
if (!activated) {
|
if (side.getSideCondition(sideCondition)) {
|
||||||
this.add('-activate', pokemon, 'ability: Screen Cleaner');
|
if (!activated) {
|
||||||
activated = true;
|
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,
|
inherit: true,
|
||||||
onUpdate(pokemon) {
|
onUpdate(pokemon) {
|
||||||
if (!pokemon.isStarted) return;
|
if (!pokemon.isStarted) return;
|
||||||
const target = pokemon.side.foe.randomAlly();
|
const target = pokemon.side.randomFoe();
|
||||||
if (!target || target.fainted) return;
|
if (!target || target.fainted) return;
|
||||||
const ability = target.getAbility();
|
const ability = target.getAbility();
|
||||||
const bannedAbilities = ['forecast', 'multitype', 'trace'];
|
const bannedAbilities = ['forecast', 'multitype', 'trace'];
|
||||||
|
|
|
||||||
|
|
@ -454,7 +454,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
|
||||||
inherit: true,
|
inherit: true,
|
||||||
onUpdate(pokemon) {
|
onUpdate(pokemon) {
|
||||||
if (!pokemon.isStarted) return;
|
if (!pokemon.isStarted) return;
|
||||||
const target = pokemon.side.foe.randomAlly();
|
const target = pokemon.side.randomFoe();
|
||||||
if (!target || target.fainted) return;
|
if (!target || target.fainted) return;
|
||||||
const ability = target.getAbility();
|
const ability = target.getAbility();
|
||||||
const bannedAbilities = ['forecast', 'multitype', 'trace'];
|
const bannedAbilities = ['forecast', 'multitype', 'trace'];
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
|
||||||
frisk: {
|
frisk: {
|
||||||
inherit: true,
|
inherit: true,
|
||||||
onStart(pokemon) {
|
onStart(pokemon) {
|
||||||
const target = pokemon.side.foe.randomAlly();
|
const target = pokemon.side.randomFoe();
|
||||||
if (target?.item) {
|
if (target?.item) {
|
||||||
this.add('-item', target, target.getItem().name, '[from] ability: Frisk', '[of] ' + pokemon);
|
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');
|
this.add('-sidestart', targetSide, 'Fire Pledge');
|
||||||
},
|
},
|
||||||
onEnd(targetSide) {
|
onEnd(targetSide) {
|
||||||
for (const pokemon of targetSide.activeTeam()) {
|
for (const pokemon of targetSide.allies()) {
|
||||||
if (pokemon && !pokemon.hasType('Fire')) {
|
if (!pokemon.hasType('Fire')) this.damage(pokemon.baseMaxhp / 8, pokemon);
|
||||||
this.damage(pokemon.baseMaxhp / 8, pokemon);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.add('-sideend', targetSide, 'Fire Pledge');
|
this.add('-sideend', targetSide, 'Fire Pledge');
|
||||||
},
|
},
|
||||||
onResidualOrder: 5,
|
onResidualOrder: 5,
|
||||||
onResidualSubOrder: 1,
|
onResidualSubOrder: 1,
|
||||||
onResidual(side) {
|
onResidual(side) {
|
||||||
for (const pokemon of side.activeTeam()) {
|
for (const pokemon of side.allies()) {
|
||||||
if (pokemon && !pokemon.hasType('Fire')) {
|
if (!pokemon.hasType('Fire')) this.damage(pokemon.baseMaxhp / 8, pokemon);
|
||||||
this.damage(pokemon.baseMaxhp / 8, pokemon);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -5944,15 +5940,10 @@ export const Moves: {[moveid: string]: MoveData} = {
|
||||||
priority: 0,
|
priority: 0,
|
||||||
flags: {snatch: 1, authentic: 1},
|
flags: {snatch: 1, authentic: 1},
|
||||||
onHitSide(side, source, move) {
|
onHitSide(side, source, move) {
|
||||||
const targets = [];
|
const targets = side.allies().filter(target => (
|
||||||
for (const pokemon of side.activeTeam()) {
|
target.hasAbility(['plus', 'minus']) &&
|
||||||
if (
|
(!target.volatiles['maxguard'] || this.runEvent('TryHit', target, source, move))
|
||||||
pokemon.hasAbility(['plus', 'minus']) &&
|
));
|
||||||
(!pokemon.volatiles['maxguard'] || this.runEvent('TryHit', pokemon, source, move))
|
|
||||||
) {
|
|
||||||
targets.push(pokemon);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!targets.length) return false;
|
if (!targets.length) return false;
|
||||||
let didSomething = false;
|
let didSomething = false;
|
||||||
for (const target of targets) {
|
for (const target of targets) {
|
||||||
|
|
@ -6187,13 +6178,13 @@ export const Moves: {[moveid: string]: MoveData} = {
|
||||||
onResidualOrder: 5,
|
onResidualOrder: 5,
|
||||||
onResidualSubOrder: 1.1,
|
onResidualSubOrder: 1.1,
|
||||||
onResidual(targetSide) {
|
onResidual(targetSide) {
|
||||||
for (const pokemon of targetSide.activeTeam()) {
|
for (const target of targetSide.allies()) {
|
||||||
if (!pokemon.hasType('Water')) this.damage(pokemon.baseMaxhp / 6, pokemon);
|
if (!target.hasType('Water')) this.damage(target.baseMaxhp / 6, target);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onEnd(targetSide) {
|
onEnd(targetSide) {
|
||||||
for (const pokemon of targetSide.activeTeam()) {
|
for (const target of targetSide.allies()) {
|
||||||
if (!pokemon.hasType('Water')) this.damage(pokemon.baseMaxhp / 6, pokemon);
|
if (!target.hasType('Water')) this.damage(target.baseMaxhp / 6, target);
|
||||||
}
|
}
|
||||||
this.add('-sideend', targetSide, 'G-Max Cannonade');
|
this.add('-sideend', targetSide, 'G-Max Cannonade');
|
||||||
},
|
},
|
||||||
|
|
@ -6839,13 +6830,13 @@ export const Moves: {[moveid: string]: MoveData} = {
|
||||||
onResidualOrder: 5,
|
onResidualOrder: 5,
|
||||||
onResidualSubOrder: 1.1,
|
onResidualSubOrder: 1.1,
|
||||||
onResidual(targetSide) {
|
onResidual(targetSide) {
|
||||||
for (const pokemon of targetSide.activeTeam()) {
|
for (const target of targetSide.allies()) {
|
||||||
if (!pokemon.hasType('Grass')) this.damage(pokemon.baseMaxhp / 6, pokemon);
|
if (!target.hasType('Grass')) this.damage(target.baseMaxhp / 6, target);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onEnd(targetSide) {
|
onEnd(targetSide) {
|
||||||
for (const pokemon of targetSide.activeTeam()) {
|
for (const target of targetSide.allies()) {
|
||||||
if (!pokemon.hasType('Grass')) this.damage(pokemon.baseMaxhp / 6, pokemon);
|
if (!target.hasType('Grass')) this.damage(target.baseMaxhp / 6, target);
|
||||||
}
|
}
|
||||||
this.add('-sideend', targetSide, 'G-Max Vine Lash');
|
this.add('-sideend', targetSide, 'G-Max Vine Lash');
|
||||||
},
|
},
|
||||||
|
|
@ -6879,13 +6870,13 @@ export const Moves: {[moveid: string]: MoveData} = {
|
||||||
onResidualOrder: 5,
|
onResidualOrder: 5,
|
||||||
onResidualSubOrder: 1.1,
|
onResidualSubOrder: 1.1,
|
||||||
onResidual(targetSide) {
|
onResidual(targetSide) {
|
||||||
for (const pokemon of targetSide.activeTeam()) {
|
for (const target of targetSide.allies()) {
|
||||||
if (!pokemon.hasType('Rock')) this.damage(pokemon.baseMaxhp / 6, pokemon);
|
if (!target.hasType('Rock')) this.damage(target.baseMaxhp / 6, target);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onEnd(targetSide) {
|
onEnd(targetSide) {
|
||||||
for (const pokemon of targetSide.activeTeam()) {
|
for (const target of targetSide.allies()) {
|
||||||
if (!pokemon.hasType('Rock')) this.damage(pokemon.baseMaxhp / 6, pokemon);
|
if (!target.hasType('Rock')) this.damage(target.baseMaxhp / 6, target);
|
||||||
}
|
}
|
||||||
this.add('-sideend', targetSide, 'G-Max Volcalith');
|
this.add('-sideend', targetSide, 'G-Max Volcalith');
|
||||||
},
|
},
|
||||||
|
|
@ -6942,13 +6933,13 @@ export const Moves: {[moveid: string]: MoveData} = {
|
||||||
onResidualOrder: 5,
|
onResidualOrder: 5,
|
||||||
onResidualSubOrder: 1.1,
|
onResidualSubOrder: 1.1,
|
||||||
onResidual(targetSide) {
|
onResidual(targetSide) {
|
||||||
for (const pokemon of targetSide.activeTeam()) {
|
for (const target of targetSide.allies()) {
|
||||||
if (!pokemon.hasType('Fire')) this.damage(pokemon.baseMaxhp / 6, pokemon);
|
if (!target.hasType('Fire')) this.damage(target.baseMaxhp / 6, target);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onEnd(targetSide) {
|
onEnd(targetSide) {
|
||||||
for (const pokemon of targetSide.activeTeam()) {
|
for (const target of targetSide.allies()) {
|
||||||
if (!pokemon.hasType('Fire')) this.damage(pokemon.baseMaxhp / 6, pokemon);
|
if (!target.hasType('Fire')) this.damage(target.baseMaxhp / 6, target);
|
||||||
}
|
}
|
||||||
this.add('-sideend', targetSide, 'G-Max Wildfire');
|
this.add('-sideend', targetSide, 'G-Max Wildfire');
|
||||||
},
|
},
|
||||||
|
|
@ -10106,16 +10097,12 @@ export const Moves: {[moveid: string]: MoveData} = {
|
||||||
priority: 0,
|
priority: 0,
|
||||||
flags: {snatch: 1, distance: 1, authentic: 1},
|
flags: {snatch: 1, distance: 1, authentic: 1},
|
||||||
onHitSide(side, source, move) {
|
onHitSide(side, source, move) {
|
||||||
const targets = [];
|
const targets = side.allies().filter(ally => (
|
||||||
for (const pokemon of side.activeTeam()) {
|
ally.hasAbility(['plus', 'minus']) &&
|
||||||
if (
|
(!ally.volatiles['maxguard'] || this.runEvent('TryHit', ally, source, move))
|
||||||
pokemon.hasAbility(['plus', 'minus']) &&
|
));
|
||||||
(!pokemon.volatiles['maxguard'] || this.runEvent('TryHit', pokemon, source, move))
|
|
||||||
) {
|
|
||||||
targets.push(pokemon);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!targets.length) return false;
|
if (!targets.length) return false;
|
||||||
|
|
||||||
let didSomething = false;
|
let didSomething = false;
|
||||||
for (const target of targets) {
|
for (const target of targets) {
|
||||||
didSomething = this.boost({def: 1, spd: 1}, target, source, move, false, true) || didSomething;
|
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.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.
|
// 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();
|
const actives = this.getAllActive();
|
||||||
if (actives.length > 1 && !actives[0].isAdjacent(actives[1])) {
|
if (actives.length > 1 && !actives[0].isAdjacent(actives[1])) {
|
||||||
|
|
@ -1594,7 +1594,7 @@ export class Battle {
|
||||||
}
|
}
|
||||||
if (!target?.hp) return 0;
|
if (!target?.hp) return 0;
|
||||||
if (!target.isActive) return false;
|
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});
|
boost = this.runEvent('Boost', target, source, effect, {...boost});
|
||||||
let success = null;
|
let success = null;
|
||||||
let boosted = isSecondary;
|
let boosted = isSecondary;
|
||||||
|
|
@ -2062,7 +2062,7 @@ export class Battle {
|
||||||
return foeActives[frontPosition];
|
return foeActives[frontPosition];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pokemon.side.foe.randomAlly() || pokemon.side.foe.active[0];
|
return pokemon.side.randomFoe() || pokemon.side.foe.active[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
checkFainted() {
|
checkFainted() {
|
||||||
|
|
|
||||||
21
sim/side.ts
21
sim/side.ts
|
|
@ -204,12 +204,27 @@ export class Side {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
randomAlly() {
|
randomFoe() {
|
||||||
const actives = this.allies();
|
const actives = this.foes();
|
||||||
if (!actives.length) return null;
|
if (!actives.length) return null;
|
||||||
return this.battle.sample(actives);
|
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() {
|
allies() {
|
||||||
// called during the first switch-in, so `active` can still contain nulls at this point
|
// called during the first switch-in, so `active` can still contain nulls at this point
|
||||||
return this.activeTeam().filter(ally => ally && !ally.fainted);
|
return this.activeTeam().filter(ally => ally && !ally.fainted);
|
||||||
|
|
@ -217,7 +232,7 @@ export class Side {
|
||||||
foes() {
|
foes() {
|
||||||
if (this.battle.gameType === 'free-for-all') {
|
if (this.battle.gameType === 'free-for-all') {
|
||||||
return this.battle.sides.map(side => side.active[0])
|
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();
|
return this.foe.allies();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user