This commit is contained in:
NightKev 2024-09-19 03:18:47 -07:00 committed by GitHub
commit 5a43a906cf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 655 additions and 309 deletions

File diff suppressed because it is too large Load Diff

View File

@ -5,4 +5,8 @@ export enum Challenges {
LOWER_STARTER_POINTS,
FRESH_START,
INVERSE_BATTLE,
NO_AUTO_HEAL,
HARDCORE,
NO_LEGENDS,
LIMITED_CATCH,
}

View File

@ -33,5 +33,29 @@
"desc": "Type matchups are reversed and no type is immune to any other type.\nDisables other challenges' achievements.",
"value.0": "Off",
"value.1": "On"
},
"noAutoHeal": {
"name": "No Free Heal",
"desc": "Disables the free automatic healing which normally occurs after every 10th wave.",
"value.0": "Off",
"value.1": "On"
},
"hardcore": {
"name": "Hardcore",
"desc": "You can no longer revive Pokemon that have fainted.",
"value.0": "Off",
"value.1": "On"
},
"noLegends": {
"name": "No Starter Legends",
"desc": "You can't choose any legendary, sub-legendary or mythical Pokemon as a starter.",
"value.0": "Off",
"value.1": "On"
},
"limitedCatch": {
"name": "Limited Catch",
"desc": "You can only add the first Pokemon of a biome to your current party.",
"value.0": "Off",
"value.1": "On"
}
}

View File

@ -1,32 +1,34 @@
import * as Modifiers from "./modifier";
import { MoneyMultiplierModifier } from "./modifier";
import { allMoves, AttackMove, selfStatLowerMoves } from "../data/move";
import { getPokeballCatchMultiplier, getPokeballName, MAX_PER_TYPE_POKEBALLS, PokeballType } from "../data/pokeball";
import Pokemon, { EnemyPokemon, PlayerPokemon, PokemonMove } from "../field/pokemon";
import { EvolutionItem, pokemonEvolutions } from "../data/pokemon-evolutions";
import { tmPoolTiers, tmSpecies } from "../data/tms";
import { Type } from "../data/type";
import PartyUiHandler, { PokemonMoveSelectFilter, PokemonSelectFilter } from "../ui/party-ui-handler";
import * as Utils from "../utils";
import { getBerryEffectDescription, getBerryName } from "../data/berry";
import { Unlockables } from "../system/unlockables";
import { getStatusEffectDescriptor, StatusEffect } from "../data/status-effect";
import { SpeciesFormKey } from "../data/pokemon-species";
import BattleScene from "../battle-scene";
import { getVoucherTypeIcon, getVoucherTypeName, VoucherType } from "../system/voucher";
import { FormChangeItem, pokemonFormChanges, SpeciesFormChangeCondition, SpeciesFormChangeItemTrigger } from "../data/pokemon-forms";
import { ModifierTier } from "./modifier-tier";
import BattleScene from "#app/battle-scene";
import { getBerryEffectDescription, getBerryName } from "#app/data/berry";
import { applyChallenges, ChallengeType } from "#app/data/challenge";
import { allMoves, AttackMove, selfStatLowerMoves } from "#app/data/move";
import { getNatureName, getNatureStatMultiplier, Nature } from "#app/data/nature";
import i18next from "i18next";
import { getModifierTierTextTint } from "#app/ui/text";
import { getPokeballCatchMultiplier, getPokeballName, MAX_PER_TYPE_POKEBALLS, PokeballType } from "#app/data/pokeball";
import { EvolutionItem, pokemonEvolutions } from "#app/data/pokemon-evolutions";
import { FormChangeItem, pokemonFormChanges, SpeciesFormChangeCondition, SpeciesFormChangeItemTrigger } from "#app/data/pokemon-forms";
import { SpeciesFormKey } from "#app/data/pokemon-species";
import { getStatusEffectDescriptor, StatusEffect } from "#app/data/status-effect";
import { tmPoolTiers, tmSpecies } from "#app/data/tms";
import { Type } from "#app/data/type";
import { getStatKey, PermanentStat, Stat, TEMP_BATTLE_STATS, TempBattleStat } from "#app/enums/stat";
import Pokemon, { EnemyPokemon, PlayerPokemon, PokemonMove } from "#app/field/pokemon";
import { GameMode } from "#app/game-mode";
import { getPokemonNameWithAffix } from "#app/messages";
import Overrides from "#app/overrides";
import { Unlockables } from "#app/system/unlockables";
import { getVoucherTypeIcon, getVoucherTypeName, VoucherType } from "#app/system/voucher";
import PartyUiHandler, { PokemonMoveSelectFilter, PokemonSelectFilter } from "#app/ui/party-ui-handler";
import { getModifierTierTextTint } from "#app/ui/text";
import * as Utils from "#app/utils";
import { Abilities } from "#enums/abilities";
import { BattlerTagType } from "#enums/battler-tag-type";
import { BerryType } from "#enums/berry-type";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import { getPokemonNameWithAffix } from "#app/messages";
import { PermanentStat, TEMP_BATTLE_STATS, TempBattleStat, Stat, getStatKey } from "#app/enums/stat";
import i18next from "i18next";
import * as Modifiers from "./modifier";
import { MoneyMultiplierModifier } from "./modifier";
import { ModifierTier } from "./modifier-tier";
const outputModifierData = false;
const useMaxWeightForOutput = false;
@ -2139,8 +2141,12 @@ function getModifierTypeOptionWithRetry(existingOptions: ModifierTypeOption[], r
allowLuckUpgrades = allowLuckUpgrades ?? true;
let candidate = getNewModifierTypeOption(party, ModifierPoolType.PLAYER, tier, undefined, 0, allowLuckUpgrades);
let r = 0;
while (existingOptions.length && ++r < retryCount && existingOptions.filter(o => o.type.name === candidate?.type.name || o.type.group === candidate?.type.group).length) {
let isValidForChallenge = new Utils.BooleanHolder(true);
applyChallenges(party[0].scene.gameMode, ChallengeType.RANDOM_ITEM_BLACKLIST, candidate!, isValidForChallenge);
while (existingOptions.length && ++r < retryCount && existingOptions.filter(o => o.type.name === candidate?.type.name || o.type.group === candidate?.type.group).length || !isValidForChallenge.value) {
candidate = getNewModifierTypeOption(party, ModifierPoolType.PLAYER, candidate?.type.tier ?? tier, candidate?.upgradeCount, 0, allowLuckUpgrades);
isValidForChallenge = new Utils.BooleanHolder(true);
applyChallenges(party[0].scene.gameMode, ChallengeType.RANDOM_ITEM_BLACKLIST, candidate!, isValidForChallenge);
}
return candidate!;
}
@ -2170,7 +2176,7 @@ export function overridePlayerModifierTypeOptions(options: ModifierTypeOption[],
}
}
export function getPlayerShopModifierTypeOptionsForWave(waveIndex: integer, baseCost: integer): ModifierTypeOption[] {
export function getPlayerShopModifierTypeOptionsForWave(waveIndex: integer, baseCost: integer, gameMode: GameMode): ModifierTypeOption[] {
if (!(waveIndex % 10)) {
return [];
}
@ -2204,7 +2210,11 @@ export function getPlayerShopModifierTypeOptionsForWave(waveIndex: integer, base
new ModifierTypeOption(modifierTypes.SACRED_ASH(), 0, baseCost * 10)
]
];
return options.slice(0, Math.ceil(Math.max(waveIndex + 10, 0) / 30)).flat();
return options.slice(0, Math.ceil(Math.max(waveIndex + 10, 0) / 30)).flat().filter(x => {
const isValidForChallenge = new Utils.BooleanHolder(true);
applyChallenges(gameMode, ChallengeType.SHOP_ITEM_BLACKLIST, x, isValidForChallenge);
return isValidForChallenge.value;
});
}
export function getEnemyBuffModifierForWave(tier: ModifierTier, enemyModifiers: Modifiers.PersistentModifier[], scene: BattleScene): Modifiers.EnemyPersistentModifier {

View File

@ -1,21 +1,23 @@
import BattleScene from "#app/battle-scene";
import { BattlerIndex } from "#app/battle";
import { getPokeballCatchMultiplier, getPokeballAtlasKey, getPokeballTintColor, doPokeballBounceAnim } from "#app/data/pokeball";
import BattleScene from "#app/battle-scene";
import { SubstituteTag } from "#app/data/battler-tags";
import { ChallengeType, applyChallenges } from "#app/data/challenge";
import { doPokeballBounceAnim, getPokeballAtlasKey, getPokeballCatchMultiplier, getPokeballTintColor } from "#app/data/pokeball";
import { getStatusEffectCatchRateMultiplier } from "#app/data/status-effect";
import { PokeballType } from "#app/enums/pokeball";
import { StatusEffect } from "#app/enums/status-effect";
import { addPokeballOpenParticles, addPokeballCaptureStars } from "#app/field/anims";
import { addPokeballCaptureStars, addPokeballOpenParticles } from "#app/field/anims";
import { EnemyPokemon } from "#app/field/pokemon";
import { getPokemonNameWithAffix } from "#app/messages";
import { PokemonHeldItemModifier } from "#app/modifier/modifier";
import { achvs } from "#app/system/achv";
import { PartyUiMode, PartyOption } from "#app/ui/party-ui-handler";
import { PartyOption, PartyUiMode } from "#app/ui/party-ui-handler";
import { SummaryUiMode } from "#app/ui/summary-ui-handler";
import { Mode } from "#app/ui/ui";
import { BooleanHolder } from "#app/utils";
import i18next from "i18next";
import { PokemonPhase } from "./pokemon-phase";
import { VictoryPhase } from "./victory-phase";
import { SubstituteTag } from "#app/data/battler-tags";
export class AttemptCapturePhase extends PokemonPhase {
private pokeballType: PokeballType;
@ -249,6 +251,13 @@ export class AttemptCapturePhase extends PokemonPhase {
});
};
Promise.all([pokemon.hideInfo(), this.scene.gameData.setPokemonCaught(pokemon)]).then(() => {
const challengeCanAddToParty = new BooleanHolder(true);
applyChallenges(this.scene.gameMode, ChallengeType.ADD_POKEMON_TO_PARTY, pokemon, this.scene.currentBattle.waveIndex, challengeCanAddToParty);
if (!challengeCanAddToParty.value) {
removePokemon();
end();
return;
}
if (this.scene.getParty().length === 6) {
const promptRelease = () => {
this.scene.ui.showText(i18next.t("battle:partyFull", { pokemonName: pokemon.getNameToRender() }), null, () => {

View File

@ -1,7 +1,8 @@
import { BattleType, TurnCommand } from "#app/battle";
import BattleScene from "#app/battle-scene";
import { TurnCommand, BattleType } from "#app/battle";
import { TrappedTag, EncoreTag } from "#app/data/battler-tags";
import { MoveTargetSet, getMoveTargets } from "#app/data/move";
import { EncoreTag, TrappedTag } from "#app/data/battler-tags";
import { applyChallenges, ChallengeType } from "#app/data/challenge";
import { getMoveTargets, MoveTargetSet } from "#app/data/move";
import { speciesStarters } from "#app/data/pokemon-species";
import { Abilities } from "#app/enums/abilities";
import { BattlerTagType } from "#app/enums/battler-tag-type";
@ -12,10 +13,11 @@ import { FieldPosition, PlayerPokemon } from "#app/field/pokemon";
import { getPokemonNameWithAffix } from "#app/messages";
import { Command } from "#app/ui/command-ui-handler";
import { Mode } from "#app/ui/ui";
import { BooleanHolder } from "#app/utils";
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
import i18next from "i18next";
import { FieldPhase } from "./field-phase";
import { SelectTargetPhase } from "./select-target-phase";
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
export class CommandPhase extends FieldPhase {
protected fieldIndex: integer;
@ -84,6 +86,18 @@ export class CommandPhase extends FieldPhase {
switch (command) {
case Command.FIGHT:
// Check if move can be used in challenge
const isValidForChallenge = new BooleanHolder(true);
applyChallenges(this.scene.gameMode, ChallengeType.MOVE_BLACKLIST, playerPokemon.getMoveset()[cursor]!, isValidForChallenge);
if (!isValidForChallenge.value) {
const moveName = playerPokemon.getMoveset()[cursor]?.getName();
this.scene.ui.setMode(Mode.MESSAGE);
this.scene.ui.showText(i18next.t("challenges:illegalMove", { moveName: moveName }), null, () => {
this.scene.ui.clearText();
this.scene.ui.setMode(Mode.FIGHT, this.fieldIndex);
}, null, true);
break;
}
let useStruggle = false;
if (cursor === -1 ||
playerPokemon.trySelectMove(cursor, args[0] as boolean) ||

View File

@ -1,5 +1,7 @@
import BattleScene from "#app/battle-scene";
import * as Utils from "#app/utils";
import { applyChallenges, ChallengeType } from "#app/data/challenge";
import { SelectModifierPhase } from "#app/phases/select-modifier-phase";
import { BooleanHolder, fixedInt } from "#app/utils";
import { BattlePhase } from "./battle-phase";
export class PartyHealPhase extends BattlePhase {
@ -14,21 +16,36 @@ export class PartyHealPhase extends BattlePhase {
start() {
super.start();
const isHealPhaseActive = new BooleanHolder(true);
applyChallenges(this.scene.gameMode, ChallengeType.NO_HEAL_PHASE, isHealPhaseActive);
if (!isHealPhaseActive.value) {
this.scene.unshiftPhase(new SelectModifierPhase(this.scene));
this.end();
return;
}
const bgmPlaying = this.scene.isBgmPlaying();
if (bgmPlaying) {
this.scene.fadeOutBgm(1000, false);
}
const canBeRevived = new BooleanHolder(true);
this.scene.ui.fadeOut(1000).then(() => {
for (const pokemon of this.scene.getParty()) {
pokemon.hp = pokemon.getMaxHp();
pokemon.resetStatus();
for (const move of pokemon.moveset) {
move!.ppUsed = 0; // TODO: is this bang correct?
applyChallenges(this.scene.gameMode, ChallengeType.PREVENT_REVIVE, pokemon, canBeRevived);
if (canBeRevived.value || !pokemon.isFainted()) {
pokemon.hp = pokemon.getMaxHp();
pokemon.resetStatus();
for (const move of pokemon.moveset) {
if (move) {
move.ppUsed = 0;
}
}
pokemon.updateInfo(true);
}
pokemon.updateInfo(true);
}
const healSong = this.scene.playSoundWithoutBgm("heal");
this.scene.time.delayedCall(Utils.fixedInt(healSong.totalDuration * 1000), () => {
this.scene.time.delayedCall(fixedInt(healSong.totalDuration * 1000), () => {
healSong.destroy();
if (this.resumeBgm && bgmPlaying) {
this.scene.playBgm();

View File

@ -1,16 +1,15 @@
import BattleScene from "#app/battle-scene";
import { ModifierTier } from "#app/modifier/modifier-tier";
import { regenerateModifierPoolThresholds, ModifierTypeOption, ModifierType, getPlayerShopModifierTypeOptionsForWave, PokemonModifierType, FusePokemonModifierType, PokemonMoveModifierType, TmModifierType, RememberMoveModifierType, PokemonPpRestoreModifierType, PokemonPpUpModifierType, ModifierPoolType, getPlayerModifierTypeOptions } from "#app/modifier/modifier-type";
import { ExtraModifierModifier, Modifier, PokemonHeldItemModifier } from "#app/modifier/modifier";
import ModifierSelectUiHandler, { SHOP_OPTIONS_ROW_LIMIT } from "#app/ui/modifier-select-ui-handler";
import PartyUiHandler, { PartyUiMode, PartyOption } from "#app/ui/party-ui-handler";
import { Mode } from "#app/ui/ui";
import i18next from "i18next";
import * as Utils from "#app/utils";
import { BattlePhase } from "./battle-phase";
import { ModifierTier } from "#app/modifier/modifier-tier";
import { CustomModifierSettings, FusePokemonModifierType, ModifierPoolType, ModifierType, ModifierTypeOption, PokemonModifierType, PokemonMoveModifierType, PokemonPpRestoreModifierType, PokemonPpUpModifierType, RememberMoveModifierType, TmModifierType, getPlayerModifierTypeOptions, getPlayerShopModifierTypeOptionsForWave, regenerateModifierPoolThresholds } from "#app/modifier/modifier-type";
import Overrides from "#app/overrides";
import { CustomModifierSettings } from "#app/modifier/modifier-type";
import ModifierSelectUiHandler, { SHOP_OPTIONS_ROW_LIMIT } from "#app/ui/modifier-select-ui-handler";
import PartyUiHandler, { PartyOption, PartyUiMode } from "#app/ui/party-ui-handler";
import { Mode } from "#app/ui/ui";
import * as Utils from "#app/utils";
import { isNullOrUndefined } from "#app/utils";
import i18next from "i18next";
import { BattlePhase } from "./battle-phase";
export class SelectModifierPhase extends BattlePhase {
private rerollCount: integer;
@ -128,7 +127,7 @@ export class SelectModifierPhase extends BattlePhase {
}
break;
default:
const shopOptions = getPlayerShopModifierTypeOptionsForWave(this.scene.currentBattle.waveIndex, this.scene.getWaveMoneyAmount(1));
const shopOptions = getPlayerShopModifierTypeOptionsForWave(this.scene.currentBattle.waveIndex, this.scene.getWaveMoneyAmount(1), this.scene.gameMode);
const shopOption = shopOptions[rowCursor > 2 || shopOptions.length <= SHOP_OPTIONS_ROW_LIMIT ? cursor : cursor + SHOP_OPTIONS_ROW_LIMIT];
if (shopOption.type) {
modifierType = shopOption.type;

View File

@ -1,20 +1,20 @@
import BattleScene from "../battle-scene";
import { getPlayerShopModifierTypeOptionsForWave, ModifierTypeOption, TmModifierType } from "../modifier/modifier-type";
import { getPokeballAtlasKey, PokeballType } from "../data/pokeball";
import { addTextObject, getTextStyleOptions, getModifierTierTextTint, getTextColor, TextStyle } from "./text";
import AwaitableUiHandler from "./awaitable-ui-handler";
import { Mode } from "./ui";
import { LockModifierTiersModifier, PokemonHeldItemModifier, HealShopCostModifier } from "../modifier/modifier";
import { handleTutorial, Tutorial } from "../tutorial";
import { Button } from "#enums/buttons";
import MoveInfoOverlay from "./move-info-overlay";
import { allMoves } from "../data/move";
import * as Utils from "./../utils";
import BattleScene from "#app/battle-scene";
import { applyChallenges, ChallengeType } from "#app/data/challenge";
import { allMoves } from "#app/data/move";
import { getPokeballAtlasKey, PokeballType } from "#app/data/pokeball";
import { HealShopCostModifier, LockModifierTiersModifier, PokemonHeldItemModifier } from "#app/modifier/modifier";
import { getPlayerShopModifierTypeOptionsForWave, ModifierTypeOption, TmModifierType } from "#app/modifier/modifier-type";
import Overrides from "#app/overrides";
import { handleTutorial, Tutorial } from "#app/tutorial";
import { BooleanHolder, formatMoney, NumberHolder } from "#app/utils";
import { Button } from "#enums/buttons";
import { ShopCursorTarget } from "#enums/shop-cursor-target";
import i18next from "i18next";
import { ShopCursorTarget } from "#app/enums/shop-cursor-target";
import { IntegerHolder } from "./../utils";
import Phaser from "phaser";
import AwaitableUiHandler from "./awaitable-ui-handler";
import MoveInfoOverlay from "./move-info-overlay";
import { addTextObject, getModifierTierTextTint, getTextColor, getTextStyleOptions, TextStyle } from "./text";
import { Mode } from "./ui";
export const SHOP_OPTIONS_ROW_LIMIT = 6;
@ -186,11 +186,18 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
const typeOptions = args[1] as ModifierTypeOption[];
const removeHealShop = this.scene.gameMode.hasNoShop;
const baseShopCost = new IntegerHolder(this.scene.getWaveMoneyAmount(1));
const baseShopCost = new NumberHolder(this.scene.getWaveMoneyAmount(1));
this.scene.applyModifier(HealShopCostModifier, true, baseShopCost);
const shopTypeOptions = !removeHealShop
? getPlayerShopModifierTypeOptionsForWave(this.scene.currentBattle.waveIndex, baseShopCost.value)
? getPlayerShopModifierTypeOptionsForWave(this.scene.currentBattle.waveIndex, baseShopCost.value, this.scene.gameMode).filter(shopItem => {
const isValidForChallenge = new BooleanHolder(true);
applyChallenges(this.scene.gameMode, ChallengeType.SHOP_ITEM_BLACKLIST, shopItem, isValidForChallenge);
return isValidForChallenge.value;
})
: [];
const optionsYOffset = shopTypeOptions.length >= SHOP_OPTIONS_ROW_LIMIT ? -8 : -24;
for (let m = 0; m < typeOptions.length; m++) {
@ -554,7 +561,7 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
}
const canReroll = this.scene.money >= this.rerollCost;
const formattedMoney = Utils.formatMoney(this.scene.moneyFormat, this.rerollCost);
const formattedMoney = formatMoney(this.scene.moneyFormat, this.rerollCost);
this.rerollCostText.setText(i18next.t("modifierSelectUiHandler:rerollCost", { formattedMoney }));
this.rerollCostText.setColor(this.getTextColor(canReroll ? TextStyle.MONEY : TextStyle.PARTY_RED));
@ -819,7 +826,7 @@ class ModifierOption extends Phaser.GameObjects.Container {
const cost = Overrides.WAIVE_ROLL_FEE_OVERRIDE ? 0 : this.modifierTypeOption.cost;
const textStyle = cost <= scene.money ? TextStyle.MONEY : TextStyle.PARTY_RED;
const formattedMoney = Utils.formatMoney(scene.moneyFormat, cost);
const formattedMoney = formatMoney(scene.moneyFormat, cost);
this.itemCostText.setText(i18next.t("modifierSelectUiHandler:itemCost", { formattedMoney }));
this.itemCostText.setColor(getTextColor(textStyle, false, scene.uiTheme));