Overhaul modifiers and add temp stat boosts

pull/1/head
Flashfyre 2023-04-18 22:09:37 -04:00
parent 59155b7c18
commit d2d2f956ef
18 changed files with 1878 additions and 1526 deletions

View File

@ -17,17 +17,12 @@
- Critical capture
- Save data
- Pokedex
- Battle info
- Owned icon
- Status effect indicator
- Modifiers
- PP Up
- Type enhancers
- Various mainline game items for various enhancements
- Items that cause effects on hit (?)
- Capture rate booster
- Balancing
- Modifiers
- Biome pools
- Custom art
- Battle bases and backgrounds

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 330 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 B

View File

@ -5,18 +5,18 @@ import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, ConditionalMoveA
import { Mode } from './ui/ui';
import { Command } from "./ui/command-ui-handler";
import { Stat } from "./pokemon-stat";
import { ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, HitHealModifier } from "./modifier";
import { ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, HitHealModifier, TempBattleStatBoosterModifier } from "./modifier";
import PartyUiHandler, { PartyOption, PartyUiMode } from "./ui/party-ui-handler";
import { doPokeballBounceAnim, getPokeballAtlasKey, getPokeballCatchMultiplier, getPokeballTintColor, PokeballType } from "./pokeball";
import { CommonAnim, CommonBattleAnim, MoveAnim, initMoveAnim, loadMoveAnimAssets } from "./battle-anims";
import { StatusEffect, getStatusEffectActivationText, getStatusEffectHealText, getStatusEffectObtainText, getStatusEffectOverlapText } from "./status-effect";
import { StatusEffect, getStatusEffectActivationText, getStatusEffectCatchRateMultiplier, getStatusEffectHealText, getStatusEffectObtainText, getStatusEffectOverlapText } from "./status-effect";
import { SummaryUiMode } from "./ui/summary-ui-handler";
import EvolutionSceneHandler from "./ui/evolution-scene-handler";
import { EvolutionPhase } from "./evolution-phase";
import { BattlePhase } from "./battle-phase";
import { BattleStat, getBattleStatLevelChangeDescription, getBattleStatName } from "./battle-stat";
import { Biome, biomeLinks } from "./biome";
import { ModifierTypeOption, PokemonModifierType, PokemonMoveModifierType, getModifierTypeOptionsForWave, regenerateModifierPoolThresholds } from "./modifier-type";
import { ModifierTypeOption, PokemonModifierType, PokemonMoveModifierType, TempBattleStat, getModifierTypeOptionsForWave, regenerateModifierPoolThresholds } from "./modifier-type";
import SoundFade from "phaser3-rex-plugins/plugins/soundfade";
import { BattleTagLapseType, BattleTagType, HideSpriteTag as HiddenTag } from "./battle-tag";
import { getPokemonMessage } from "./messages";
@ -103,6 +103,7 @@ export class EncounterPhase extends BattlePhase {
end() {
if (this.scene.getEnemyPokemon().shiny)
this.scene.unshiftPhase(new ShinySparklePhase(this.scene, false));
// TODO: Remove
//this.scene.unshiftPhase(new SelectModifierPhase(this.scene));
@ -531,6 +532,8 @@ export class TurnEndPhase extends BattlePhase {
}
start() {
super.start();
const playerPokemon = this.scene.getPlayerPokemon();
const enemyPokemon = this.scene.getEnemyPokemon();
@ -548,6 +551,24 @@ export class TurnEndPhase extends BattlePhase {
}
}
export class BattleEndPhase extends BattlePhase {
constructor(scene: BattleScene) {
super(scene);
}
start() {
super.start();
const tempBattleStatBoosterModifiers = this.scene.getModifiers(TempBattleStatBoosterModifier) as TempBattleStatBoosterModifier[];
for (let m of tempBattleStatBoosterModifiers) {
if (!m.lapse())
this.scene.removeModifier(m);
}
this.scene.updateModifiers().then(() => this.end());
}
}
export abstract class PokemonPhase extends BattlePhase {
protected player: boolean;
@ -805,14 +826,16 @@ abstract class MoveEffectPhase extends PokemonPhase {
}
if (this.move.getMove().category !== MoveCategory.STATUS) {
const userAccuracyLevel = this.getUserPokemon().summonData.battleStats[BattleStat.ACC];
const targetEvasionLevel = this.getTargetPokemon().summonData.battleStats[BattleStat.EVA];
const userAccuracyLevel = new Utils.IntegerHolder(this.getUserPokemon().summonData.battleStats[BattleStat.ACC]);
const targetEvasionLevel = new Utils.IntegerHolder(this.getTargetPokemon().summonData.battleStats[BattleStat.EVA]);
if (this.getUserPokemon().isPlayer())
this.scene.applyModifiers(TempBattleStatBoosterModifier, TempBattleStat.ACC, userAccuracyLevel);
const rand = Utils.randInt(100, 1);
let accuracyMultiplier = 1;
if (userAccuracyLevel !== targetEvasionLevel) {
accuracyMultiplier = userAccuracyLevel > targetEvasionLevel
? (3 + Math.min(userAccuracyLevel - targetEvasionLevel, 6)) / 3
: 3 / (3 + Math.min(targetEvasionLevel - userAccuracyLevel, 6));
if (userAccuracyLevel.value !== targetEvasionLevel.value) {
accuracyMultiplier = userAccuracyLevel.value > targetEvasionLevel.value
? (3 + Math.min(userAccuracyLevel.value - targetEvasionLevel.value, 6)) / 3
: 3 / (3 + Math.min(targetEvasionLevel.value - userAccuracyLevel.value, 6));
}
return rand <= this.move.getMove().accuracy * accuracyMultiplier;
}
@ -1172,7 +1195,7 @@ export class VictoryPhase extends PokemonPhase {
const participantIds = this.scene.currentBattle.playerParticipantIds;
const party = this.scene.getParty();
const expShareModifier = this.scene.getModifier(ExpShareModifier) as ExpShareModifier;
const expShareModifier = this.scene.findModifier(m => m instanceof ExpShareModifier) as ExpShareModifier;
const expValue = this.scene.getEnemyPokemon().getExpValue();
for (let pm = 0; pm < party.length; pm++) {
const pokemon = party[pm];
@ -1192,6 +1215,8 @@ export class VictoryPhase extends PokemonPhase {
this.scene.unshiftPhase(new ExpPhase(this.scene, pm, expValue * expMultiplier));
}
}
this.scene.pushPhase(new BattleEndPhase(this.scene));
this.scene.pushPhase(new SelectModifierPhase(this.scene));
this.scene.newBattle();
@ -1434,7 +1459,7 @@ export class AttemptCapturePhase extends BattlePhase {
const _2h = 2 * pokemon.hp;
const catchRate = pokemon.species.catchRate;
const pokeballMultiplier = getPokeballCatchMultiplier(this.pokeballType);
const statusMultiplier = 1;
const statusMultiplier = pokemon.status ? getStatusEffectCatchRateMultiplier(pokemon.status.effect) : 1;
const x = Math.round((((_3m - _2h) * catchRate * pokeballMultiplier) / _3m) * statusMultiplier);
const y = Math.round(65536 / Math.sqrt(Math.sqrt(255 / x)));

View File

@ -645,8 +645,18 @@ export default class BattleScene extends Phaser.Scene {
});
}
getModifier(modifierType: { new(...args: any[]): Modifier }): Modifier {
return this.modifiers.find(m => m instanceof modifierType);
removeModifier(modifier: PersistentModifier): boolean {
const modifierIndex = this.modifiers.indexOf(modifier);
if (modifierIndex > -1) {
this.modifiers.splice(modifierIndex, 1);
return true;
}
return false;
}
getModifiers(modifierType: { new(...args: any[]): Modifier }): Modifier[] {
return this.modifiers.filter(m => m instanceof modifierType);
}
findModifier(modifierFilter: ModifierPredicate): Modifier {

View File

@ -1,3 +1,4 @@
import { BattleStat, getBattleStatName } from './battle-stat';
import * as Modifiers from './modifier';
import { AttackMove, Moves, allMoves } from './move';
import { PokeballType, getPokeballName } from './pokeball';
@ -25,13 +26,15 @@ export class ModifierType {
public name: string;
public description: string;
public iconImage: string;
public group: string;
public tier: ModifierTier;
private newModifierFunc: NewModifierFunc;
constructor(name: string, description: string, newModifierFunc: NewModifierFunc, iconImage?: string) {
constructor(name: string, description: string, newModifierFunc: NewModifierFunc, iconImage?: string, group?: string,) {
this.name = name;
this.description = description;
this.iconImage = iconImage || name?.replace(/[ \-]/g, '_')?.toLowerCase();
this.group = group || '';
this.newModifierFunc = newModifierFunc;
}
@ -46,15 +49,15 @@ export class ModifierType {
class AddPokeballModifierType extends ModifierType {
constructor(pokeballType: PokeballType, count: integer, iconImage?: string) {
super(`${count}x ${getPokeballName(pokeballType)}`, `Receive ${getPokeballName(pokeballType)} x${count}`, (_type, _args) => new Modifiers.AddPokeballModifier(this, pokeballType, count), iconImage);
super(`${count}x ${getPokeballName(pokeballType)}`, `Receive ${getPokeballName(pokeballType)} x${count}`, (_type, _args) => new Modifiers.AddPokeballModifier(this, pokeballType, count), iconImage, 'pb');
}
}
export class PokemonModifierType extends ModifierType {
public selectFilter: PokemonSelectFilter;
constructor(name: string, description: string, newModifierFunc: NewModifierFunc, selectFilter?: PokemonSelectFilter, iconImage?: string) {
super(name, description, newModifierFunc, iconImage);
constructor(name: string, description: string, newModifierFunc: NewModifierFunc, selectFilter?: PokemonSelectFilter, iconImage?: string, group?: string) {
super(name, description, newModifierFunc, iconImage, group);
this.selectFilter = selectFilter;
}
@ -64,14 +67,14 @@ export class PokemonHpRestoreModifierType extends PokemonModifierType {
protected restorePoints: integer;
protected percent: boolean;
constructor(name: string, restorePoints: integer, percent?: boolean, newModifierFunc?: NewModifierFunc, selectFilter?: PokemonSelectFilter, iconImage?: string) {
constructor(name: string, restorePoints: integer, percent?: boolean, newModifierFunc?: NewModifierFunc, selectFilter?: PokemonSelectFilter, iconImage?: string, group?: string) {
super(name, `Restore ${restorePoints}${percent ? '%' : ''} HP for one POKéMON`,
newModifierFunc || ((_type, args) => new Modifiers.PokemonHpRestoreModifier(this, (args[0] as PlayerPokemon).id, this.restorePoints, this.percent, false)),
selectFilter || ((pokemon: PlayerPokemon) => {
if (!pokemon.hp || pokemon.hp >= pokemon.getMaxHp())
return PartyUiHandler.NoEffectMessage;
return null;
}), iconImage);
}), iconImage, group || 'potion');
this.restorePoints = restorePoints;
this.percent = !!percent;
@ -85,7 +88,7 @@ export class PokemonReviveModifierType extends PokemonHpRestoreModifierType {
if (pokemon.hp)
return PartyUiHandler.NoEffectMessage;
return null;
}), iconImage);
}), iconImage, 'revive');
this.description = `Revive one POKéMON and restore ${restorePercent}% HP`;
this.selectFilter = (pokemon: PlayerPokemon) => {
@ -99,8 +102,9 @@ export class PokemonReviveModifierType extends PokemonHpRestoreModifierType {
export abstract class PokemonMoveModifierType extends PokemonModifierType {
public moveSelectFilter: PokemonMoveSelectFilter;
constructor(name: string, description: string, newModifierFunc: NewModifierFunc, selectFilter?: PokemonSelectFilter, moveSelectFilter?: PokemonMoveSelectFilter, iconImage?: string) {
super(name, description, newModifierFunc, selectFilter, iconImage);
constructor(name: string, description: string, newModifierFunc: NewModifierFunc, selectFilter?: PokemonSelectFilter, moveSelectFilter?: PokemonMoveSelectFilter,
iconImage?: string, group?: string) {
super(name, description, newModifierFunc, selectFilter, iconImage, group);
this.moveSelectFilter = moveSelectFilter;
}
@ -117,7 +121,7 @@ export class PokemonPpRestoreModifierType extends PokemonMoveModifierType {
if (!pokemonMove.ppUsed)
return PartyUiHandler.NoEffectMessage;
return null;
}, iconImage);
}, iconImage, 'ether');
this.restorePoints = this.restorePoints;
}
@ -132,12 +136,60 @@ export class PokemonAllMovePpRestoreModifierType extends PokemonModifierType {
if (!pokemon.moveset.filter(m => m.ppUsed).length)
return PartyUiHandler.NoEffectMessage;
return null;
}, iconImage);
}, iconImage, 'elixir');
this.restorePoints = this.restorePoints;
}
}
export enum TempBattleStat {
ATK,
DEF,
SPATK,
SPDEF,
SPD,
ACC,
CRIT
}
function getTempBattleStatName(tempBattleStat: TempBattleStat) {
if (tempBattleStat === TempBattleStat.CRIT)
return 'critical-hit ratio';
return getBattleStatName(tempBattleStat as integer as BattleStat);
}
function getTempBattleStatBoosterItemName(tempBattleStat: TempBattleStat) {
switch (tempBattleStat) {
case TempBattleStat.ATK:
return 'X Attack';
case TempBattleStat.DEF:
return 'X Defense';
case TempBattleStat.SPATK:
return 'X Sp. Atk';
case TempBattleStat.SPDEF:
return 'X Sp. Def';
case TempBattleStat.SPD:
return 'X Speed';
case TempBattleStat.ACC:
return 'X Accuracy';
case TempBattleStat.CRIT:
return 'Dire Hit';
}
}
export class TempBattleStatBoosterModifierType extends ModifierType {
public tempBattleStat: TempBattleStat;
constructor(tempBattleStat: TempBattleStat) {
super(Utils.toPokemonUpperCase(getTempBattleStatBoosterItemName(tempBattleStat)),
`Increases the ${getTempBattleStatName(tempBattleStat)} of all party members by 1 stage for 5 battles`,
(_type, _args) => new Modifiers.TempBattleStatBoosterModifier(this, this.tempBattleStat),
getTempBattleStatBoosterItemName(tempBattleStat).replace(/\./g, '').replace(/[ ]/g, '_').toLowerCase());
this.tempBattleStat = tempBattleStat;
}
}
function getAttackTypeBoosterItemName(type: Type) {
switch (type) {
case Type.NORMAL:
@ -184,7 +236,7 @@ export class AttackTypeBoosterModifierType extends PokemonModifierType {
public boostPercent: integer;
constructor(moveType: Type, boostPercent: integer) {
super(getAttackTypeBoosterItemName(moveType), `Inceases the power of a POKéMON's ${Type[moveType]}-type moves by 20%`,
super(Utils.toPokemonUpperCase(getAttackTypeBoosterItemName(moveType)), `Inceases the power of a POKéMON's ${Type[moveType]}-type moves by 20%`,
(_type, args) => new Modifiers.AttackTypeBoosterModifier(this, (args[0] as PlayerPokemon).id, moveType, boostPercent),
null, `${getAttackTypeBoosterItemName(moveType).replace(/[ \-]/g, '_').toLowerCase()}`);
@ -200,6 +252,23 @@ export class PokemonLevelIncrementModifierType extends PokemonModifierType {
}
}
function getBaseStatBoosterItemName(stat: Stat) {
switch (stat) {
case Stat.HP:
return 'HP-UP';
case Stat.ATK:
return 'PROTEIN';
case Stat.DEF:
return 'IRON';
case Stat.SPATK:
return 'CALCIUM';
case Stat.SPDEF:
return 'ZINC';
case Stat.SPD:
return 'CARBOS';
}
}
export class PokemonBaseStatBoosterModifierType extends PokemonModifierType {
private stat: Stat;
@ -237,7 +306,7 @@ export class TmModifierType extends PokemonModifierType {
if (pokemon.compatibleTms.indexOf(moveId) === -1 || pokemon.moveset.filter(m => m?.moveId === moveId).length)
return PartyUiHandler.NoEffectMessage;
return null;
}, `tm_${Type[allMoves[moveId - 1].type].toLowerCase()}`);
}, `tm_${Type[allMoves[moveId - 1].type].toLowerCase()}`, 'tm');
this.moveId = moveId;
}
@ -297,10 +366,8 @@ class ModifierTypeGenerator extends ModifierType {
generateType(party: PlayerPokemon[]) {
const ret = this.genTypeFunc(party);
if (ret) {
console.log(ret);
if (ret)
ret.setTier(this.tier);
}
return ret;
}
}
@ -374,25 +441,43 @@ class WeightedModifierType {
}
}
class WeightedModifierTypeGroup {
public modifierTypes: WeightedModifierType[];
constructor(...modifierTypes: WeightedModifierType[]) {
this.modifierTypes = modifierTypes;
}
setTier(tier: ModifierTier) {
for (let modifierType of this.modifierTypes)
modifierType.setTier(tier);
}
}
const modifierPool = {
[ModifierTier.COMMON]: [
new WeightedModifierType(new AddPokeballModifierType(PokeballType.POKEBALL, 5, 'pb'), 2),
new WeightedModifierType(new AddPokeballModifierType(PokeballType.POKEBALL, 5, 'pb'), 6),
new WeightedModifierType(new PokemonLevelIncrementModifierType('RARE CANDY'), 2),
new WeightedModifierType(new PokemonHpRestoreModifierType('POTION', 20), (party: PlayerPokemon[]) => {
const thresholdPartyMemberCount = party.filter(p => p.getInverseHp() >= 10 || p.getHpRatio() <= 0.875).length;
return thresholdPartyMemberCount;
return thresholdPartyMemberCount * 3;
}),
new WeightedModifierType(new PokemonHpRestoreModifierType('SUPER POTION', 50), (party: PlayerPokemon[]) => {
const thresholdPartyMemberCount = party.filter(p => p.getInverseHp() >= 25 || p.getHpRatio() <= 0.75).length;
return Math.ceil(thresholdPartyMemberCount / 3);
}),
new WeightedModifierType(new PokemonPpRestoreModifierType('ETHER', 10), (party: PlayerPokemon[]) => {
const thresholdPartyMemberCount = party.filter(p => p.moveset.filter(m => m.ppUsed >= 5).length).length;
return thresholdPartyMemberCount;
}),
new WeightedModifierType(new PokemonPpRestoreModifierType('ETHER', 10), (party: PlayerPokemon[]) => {
const thresholdPartyMemberCount = party.filter(p => p.hp && p.moveset.filter(m => (m.getMove().pp - m.ppUsed) <= 5).length).length;
return thresholdPartyMemberCount * 3;
}),
new WeightedModifierType(new PokemonPpRestoreModifierType('MAX ETHER', -1), (party: PlayerPokemon[]) => {
const thresholdPartyMemberCount = party.filter(p => p.moveset.filter(m => m.ppUsed > 10).length).length;
return Math.ceil(thresholdPartyMemberCount / 3);
})
const thresholdPartyMemberCount = party.filter(p => p.hp && p.moveset.filter(m => (m.getMove().pp - m.ppUsed) <= 5).length).length;
return thresholdPartyMemberCount;
}),
new WeightedModifierType(new ModifierTypeGenerator((party: PlayerPokemon[]) => {
const randTempBattleStat = Utils.randInt(7) as TempBattleStat;
return new TempBattleStatBoosterModifierType(randTempBattleStat);
}), 4)
].map(m => { m.setTier(ModifierTier.COMMON); return m; }),
[ModifierTier.GREAT]: [
new WeightedModifierType(new AddPokeballModifierType(PokeballType.GREAT_BALL, 5, 'gb'), 12),
@ -416,11 +501,11 @@ const modifierPool = {
return Math.ceil(thresholdPartyMemberCount / 1.5);
}),
new WeightedModifierType(new PokemonAllMovePpRestoreModifierType('ELIXIR', 10), (party: PlayerPokemon[]) => {
const thresholdPartyMemberCount = party.filter(p => p.moveset.filter(m => m.ppUsed >= 5).length).length;
const thresholdPartyMemberCount = party.filter(p => p.hp && p.moveset.filter(m => (m.getMove().pp - m.ppUsed) <= 5).length).length;
return thresholdPartyMemberCount * 2;
}),
new WeightedModifierType(new PokemonAllMovePpRestoreModifierType('MAX ELIXIR', -1), (party: PlayerPokemon[]) => {
const thresholdPartyMemberCount = party.filter(p => p.moveset.filter(m => m.ppUsed > 10).length).length;
const thresholdPartyMemberCount = party.filter(p => p.hp && p.moveset.filter(m => (m.getMove().pp - m.ppUsed) <= 5).length).length;
return Math.ceil(thresholdPartyMemberCount / 1.5);
}),
new WeightedModifierType(new ModifierTypeGenerator((party: PlayerPokemon[]) => {
@ -429,13 +514,11 @@ const modifierPool = {
const randTmIndex = Utils.randInt(uniqueCompatibleTms.length);
return new TmModifierType(uniqueCompatibleTms[randTmIndex]);
}), 4),
new WeightedModifierType(new PokemonLevelIncrementModifierType('RARE CANDY'), 4),
new WeightedModifierType(new PokemonBaseStatBoosterModifierType('HP-UP', Stat.HP), 1),
new WeightedModifierType(new PokemonBaseStatBoosterModifierType('PROTEIN', Stat.ATK), 1),
new WeightedModifierType(new PokemonBaseStatBoosterModifierType('IRON', Stat.DEF), 1),
new WeightedModifierType(new PokemonBaseStatBoosterModifierType('CALCIUM', Stat.SPATK), 1),
new WeightedModifierType(new PokemonBaseStatBoosterModifierType('ZINC', Stat.SPDEF), 1),
new WeightedModifierType(new PokemonBaseStatBoosterModifierType('CARBOS', Stat.SPD), 1)
new WeightedModifierType(new ModifierType('EXP. SHARE', 'All POKéMON in your party gain an additional 10% of a battle\'s EXP. Points', (type, _args) => new Modifiers.ExpShareModifier(type), 'exp_share'), 2),
new WeightedModifierType(new ModifierTypeGenerator((party: PlayerPokemon[]) => {
const randStat = Utils.randInt(6) as Stat;
return new PokemonBaseStatBoosterModifierType(getBaseStatBoosterItemName(randStat), randStat);
}), 4)
].map(m => { m.setTier(ModifierTier.GREAT); return m; }),
[ModifierTier.ULTRA]: [
new WeightedModifierType(new AddPokeballModifierType(PokeballType.ULTRA_BALL, 5, 'ub'), 8),
@ -444,9 +527,8 @@ const modifierPool = {
new ModifierType('OVAL CHARM', 'For every X (no. of party members) items in a POKéMON\'s held item stack, give one to each other party member',
(type, _args) => new Modifiers.PartyShareModifier(type), 'oval_charm'),
new ModifierType('HEALING CHARM', 'Doubles the effectiveness of HP restoring moves and items (excludes revives)', (type, _args) => new Modifiers.HealingBoosterModifier(type, 2), 'healing_charm'),
new WeightedModifierType(new PokemonModifierType('SHELL BELL', 'Heals 1/8 of a POKéMON\'s dealt damage', (type, args) => new Modifiers.HitHealModifier(type, (args[0] as PlayerPokemon).id)), 8),
new WeightedModifierType(new ExpBoosterModifierType('LUCKY EGG', 25), 4),
new WeightedModifierType(new ModifierType('EXP. SHARE', 'All POKéMON in your party gain an additional 10% of a battle\'s EXP. Points', (type, _args) => new Modifiers.ExpShareModifier(type), 'exp_share'), 3)
new WeightedModifierType(new PokemonModifierType('SHELL BELL', 'Heals 1/8 of a POKéMON\'s dealt damage', (type, args) => new Modifiers.HitHealModifier(type, (args[0] as PlayerPokemon).id)), 2),
new WeightedModifierType(new ExpBoosterModifierType('LUCKY EGG', 25), 4)
].map(m => { m.setTier(ModifierTier.ULTRA); return m; }),
[ModifierTier.MASTER]: [
new AddPokeballModifierType(PokeballType.MASTER_BALL, 1, 'mb'),
@ -486,13 +568,21 @@ export function regenerateModifierPoolThresholds(party: PlayerPokemon[]) {
}, 0);
return [ t, Object.fromEntries(thresholds) ]
})));
console.log(modifierPoolThresholds)
}
export function getModifierTypeOptionsForWave(waveIndex: integer, count: integer, party: PlayerPokemon[]): ModifierTypeOption[] {
if (waveIndex % 10 === 0)
return modifierPool[ModifierTier.LUXURY].map(m => new ModifierTypeOption(m, false));
return new Array(count).fill(0).map(() => getNewModifierTypeOption(party));
const options: ModifierTypeOption[] = [];
const retryCount = Math.min(count * 5, 50);
new Array(count).fill(0).map(() => {
let candidate = getNewModifierTypeOption(party);
let r = 0;
while (options.length && ++r < retryCount && options.filter(o => o.type.name === candidate.type.name || o.type.group === candidate.type.group).length)
candidate = getNewModifierTypeOption(party, candidate.type.tier, candidate.upgraded);
options.push(candidate);
});
return options;
}
function getNewModifierTypeOption(party: PlayerPokemon[], tier?: ModifierTier, upgrade?: boolean): ModifierTypeOption {

View File

@ -131,7 +131,7 @@ export abstract class PersistentModifier extends Modifier {
const maxStrokeColor = '#984038';
if (virtual) {
const virtualText = addTextObject(scene, 1 * 11 + 16, 12, `+${this.virtualStackCount.toString()}`, TextStyle.PARTY, { fontSize: '66px', color: !isStackMax ? '#40c8f8' : maxColor });
const virtualText = addTextObject(scene, 27, 12, `+${this.virtualStackCount.toString()}`, TextStyle.PARTY, { fontSize: '66px', color: !isStackMax ? '#40c8f8' : maxColor });
virtualText.setShadow(0, 0, null);
virtualText.setStroke(!isStackMax ? '#006090' : maxStrokeColor, 16)
virtualText.setOrigin(1, 0);
@ -181,6 +181,50 @@ export class AddPokeballModifier extends ConsumableModifier {
}
}
export class TempBattleStatBoosterModifier extends PersistentModifier {
private tempBattleStat: ModifierTypes.TempBattleStat;
private battlesLeft: integer;
constructor(type: ModifierTypes.TempBattleStatBoosterModifierType, tempBattleStat: ModifierTypes.TempBattleStat) {
super(type);
this.tempBattleStat = tempBattleStat;
this.battlesLeft = 5;
}
clone(): TempBattleStatBoosterModifier {
return new TempBattleStatBoosterModifier(this.type as ModifierTypes.TempBattleStatBoosterModifierType, this.tempBattleStat);
}
apply(args: any[]): boolean {
const tempBattleStat = args[0] as ModifierTypes.TempBattleStat;
if (tempBattleStat === this.tempBattleStat) {
const statLevel = args[1] as Utils.IntegerHolder;
statLevel.value = Math.min(statLevel.value + 1, 6);
return true;
}
return false;
}
lapse(): boolean {
return !!--this.battlesLeft;
}
getIcon(scene: BattleScene): Phaser.GameObjects.Container {
const container = super.getIcon(scene);
const battleCountText = addTextObject(scene, 27, 0, this.battlesLeft.toString(), TextStyle.PARTY, { fontSize: '66px', color: '#f89890' });
battleCountText.setShadow(0, 0, null);
battleCountText.setStroke('#984038', 16)
battleCountText.setOrigin(1, 0);
container.add(battleCountText);
return container;
}
}
export abstract class PokemonHeldItemModifier extends PersistentModifier {
public pokemonId: integer;
@ -387,7 +431,6 @@ export class PokemonPpRestoreModifier extends ConsumablePokemonMoveModifier {
apply(args: any[]): boolean {
const pokemon = args[0] as Pokemon;
const move = pokemon.moveset[this.moveIndex];
console.log(move.ppUsed, this.restorePoints, this.restorePoints >= -1 ? Math.max(move.ppUsed - this.restorePoints, 0) : 0);
move.ppUsed = this.restorePoints >= -1 ? Math.max(move.ppUsed - this.restorePoints, 0) : 0;
return true;

View File

@ -1,7 +1,7 @@
import { ChargeAnim, MoveChargeAnim, initMoveAnim, loadMoveAnimAssets } from "./battle-anims";
import { DamagePhase, EnemyMovePhase, MessagePhase, ObtainStatusEffectPhase, PlayerMovePhase, PokemonHealPhase, StatChangePhase } from "./battle-phases";
import { BattleStat } from "./battle-stat";
import { BattleTagType, ProtectedTag } from "./battle-tag";
import { BattleTagType } from "./battle-tag";
import { getPokemonMessage } from "./messages";
import Pokemon, { EnemyPokemon, MoveResult, PlayerPokemon, PokemonMove, TurnMove } from "./pokemon";
import { StatusEffect } from "./status-effect";
@ -684,8 +684,7 @@ export class MoveHitEffectAttr extends MoveAttr {
export class HighCritAttr extends MoveAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const critChance = args[0] as Utils.IntegerHolder;
critChance.value /= 2;
(args[0] as Utils.IntegerHolder).value++;
return true;
}

View File

@ -8,7 +8,7 @@ import * as Utils from './utils';
import { Type, getTypeDamageMultiplier } from './type';
import { getLevelTotalExp } from './exp';
import { Stat } from './pokemon-stat';
import { AttackTypeBoosterModifier, PokemonBaseStatModifier as PokemonBaseStatBoosterModifier, ShinyRateBoosterModifier } from './modifier';
import { AttackTypeBoosterModifier, PokemonBaseStatModifier as PokemonBaseStatBoosterModifier, ShinyRateBoosterModifier, TempBattleStatBoosterModifier } from './modifier';
import { PokeballType } from './pokeball';
import { Gender } from './gender';
import { initMoveAnim, loadMoveAnimAssets } from './battle-anims';
@ -20,6 +20,7 @@ import { BattleStat } from './battle-stat';
import { BattleTag, BattleTagLapseType, BattleTagType, getBattleTag } from './battle-tag';
import { Species } from './species';
import { WeatherType } from './weather';
import { TempBattleStat } from './modifier-type';
export default abstract class Pokemon extends Phaser.GameObjects.Container {
public id: integer;
@ -263,8 +264,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
getBattleStat(stat: Stat): integer {
if (stat === Stat.HP)
return this.stats[Stat.HP];
const statLevel = this.summonData.battleStats[(stat - 1) as BattleStat];
let ret = this.stats[stat] * (Math.max(2, 2 + statLevel) / Math.max(2, 2 - statLevel));
const battleStat = (stat - 1) as BattleStat;
const statLevel = new Utils.IntegerHolder(this.summonData.battleStats[battleStat]);
if (this.isPlayer())
this.scene.applyModifiers(TempBattleStatBoosterModifier, battleStat as integer as TempBattleStat, statLevel);
let ret = this.stats[stat] * (Math.max(2, 2 + statLevel.value) / Math.max(2, 2 - statLevel.value));
if (stat === Stat.SPDEF && this.scene.arena.weather?.weatherType === WeatherType.SANDSTORM)
ret *= 1.5;
if (this.status && this.status.effect === StatusEffect.PARALYSIS)
@ -461,9 +465,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const weatherTypeMultiplier = this.scene.arena.getAttackTypeMultiplier(move.type);
applyMoveAttrs(VariablePowerAttr, source, this, move, power);
this.scene.applyModifiers(AttackTypeBoosterModifier, source, power);
const critChance = new Utils.IntegerHolder(16);
applyMoveAttrs(HighCritAttr, source, this, move, critChance);
let isCritical = Utils.randInt(critChance.value) === 0;
const critLevel = new Utils.IntegerHolder(0);
applyMoveAttrs(HighCritAttr, source, this, move, critLevel);
if (source.isPlayer())
this.scene.applyModifiers(TempBattleStatBoosterModifier, TempBattleStat.CRIT, critLevel);
const critChance = Math.ceil(16 / Math.pow(2, critLevel.value));
let isCritical = critChance === 1 || !Utils.randInt(critChance);
const sourceAtk = source.getBattleStat(isPhysical ? Stat.ATK : Stat.SPATK);
const targetDef = this.getBattleStat(isPhysical ? Stat.DEF : Stat.SPDEF);
const stabMultiplier = source.species.type1 === move.type || (source.species.type2 !== null && source.species.type2 === move.type) ? 1.5 : 1;

View File

@ -103,4 +103,19 @@ export function getStatusEffectHealText(statusEffect: StatusEffect) {
}
return '';
}
export function getStatusEffectCatchRateMultiplier(statusEffect: StatusEffect) {
switch (statusEffect) {
case StatusEffect.POISON:
case StatusEffect.TOXIC:
case StatusEffect.PARALYSIS:
case StatusEffect.BURN:
return 1.5;
case StatusEffect.SLEEP:
case StatusEffect.FREEZE:
return 2.5;
}
return 1;
}