mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-14 03:19:28 +02:00
Add tracking for friendship ribbon
This commit is contained in:
parent
c1085dcc34
commit
92d8c5289b
@ -1,4 +1,4 @@
|
||||
import type { RibbonData } from "#system/ribbon-data";
|
||||
import type { RibbonData } from "#system/ribbons/ribbon-data";
|
||||
|
||||
export interface DexData {
|
||||
[key: number]: DexEntry;
|
||||
|
@ -101,3 +101,9 @@ export const ANTI_VARIANCE_WEIGHT_MODIFIER = 15;
|
||||
* Default: `10000` (0.01%)
|
||||
*/
|
||||
export const FAKE_TITLE_LOGO_CHANCE = 10000;
|
||||
|
||||
/**
|
||||
* The ceiling on friendshp amount that can be reached through the use of rare candies.
|
||||
* Using rare candies will never increase friendship beyond this value.
|
||||
*/
|
||||
export const RARE_CANDY_FRIENDSHIP_CAP = 200;
|
||||
|
@ -20,7 +20,7 @@ import { Trainer } from "#field/trainer";
|
||||
import type { ModifierTypeOption } from "#modifiers/modifier-type";
|
||||
import { PokemonMove } from "#moves/pokemon-move";
|
||||
import type { DexAttrProps, GameData } from "#system/game-data";
|
||||
import { RibbonData, type RibbonFlag } from "#system/ribbon-data";
|
||||
import { RibbonData, type RibbonFlag } from "#system/ribbons/ribbon-data";
|
||||
import { type BooleanHolder, isBetween, type NumberHolder, randSeedItem } from "#utils/common";
|
||||
import { deepCopy } from "#utils/data";
|
||||
import { getPokemonSpecies, getPokemonSpeciesForm } from "#utils/pokemon-utils";
|
||||
|
@ -1,7 +1,7 @@
|
||||
import type { Ability, PreAttackModifyDamageAbAttrParams } from "#abilities/ability";
|
||||
import { applyAbAttrs, applyOnGainAbAttrs, applyOnLoseAbAttrs } from "#abilities/apply-ab-attrs";
|
||||
import type { AnySound, BattleScene } from "#app/battle-scene";
|
||||
import { PLAYER_PARTY_MAX_SIZE } from "#app/constants";
|
||||
import { PLAYER_PARTY_MAX_SIZE, RARE_CANDY_FRIENDSHIP_CAP } from "#app/constants";
|
||||
import { timedEventManager } from "#app/global-event-manager";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { getPokemonNameWithAffix } from "#app/messages";
|
||||
@ -138,6 +138,8 @@ import { populateVariantColors, variantColorCache, variantData } from "#sprites/
|
||||
import { achvs } from "#system/achv";
|
||||
import type { StarterDataEntry, StarterMoveset } from "#system/game-data";
|
||||
import type { PokemonData } from "#system/pokemon-data";
|
||||
import { RibbonData } from "#system/ribbons/ribbon-data";
|
||||
import { awardRibbonsToSpeciesLine } from "#system/ribbons/ribbon-methods";
|
||||
import type { AbAttrMap, AbAttrString, TypeMultiplierAbAttrParams } from "#types/ability-types";
|
||||
import type { DamageCalculationResult, DamageResult } from "#types/damage-result";
|
||||
import type { IllusionData } from "#types/illusion-data";
|
||||
@ -5821,45 +5823,59 @@ export class PlayerPokemon extends Pokemon {
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
addFriendship(friendship: number): void {
|
||||
if (friendship > 0) {
|
||||
const starterSpeciesId = this.species.getRootSpeciesId();
|
||||
const fusionStarterSpeciesId = this.isFusion() && this.fusionSpecies ? this.fusionSpecies.getRootSpeciesId() : 0;
|
||||
const starterData = [
|
||||
globalScene.gameData.starterData[starterSpeciesId],
|
||||
fusionStarterSpeciesId ? globalScene.gameData.starterData[fusionStarterSpeciesId] : null,
|
||||
].filter(d => !!d);
|
||||
const amount = new NumberHolder(friendship);
|
||||
globalScene.applyModifier(PokemonFriendshipBoosterModifier, true, this, amount);
|
||||
const candyFriendshipMultiplier = globalScene.gameMode.isClassic
|
||||
? timedEventManager.getClassicFriendshipMultiplier()
|
||||
: 1;
|
||||
const fusionReduction = fusionStarterSpeciesId
|
||||
? timedEventManager.areFusionsBoosted()
|
||||
? 1.5 // Divide candy gain for fusions by 1.5 during events
|
||||
: 2 // 2 for fusions outside events
|
||||
: 1; // 1 for non-fused mons
|
||||
const starterAmount = new NumberHolder(Math.floor((amount.value * candyFriendshipMultiplier) / fusionReduction));
|
||||
|
||||
// Add friendship to this PlayerPokemon
|
||||
this.friendship = Math.min(this.friendship + amount.value, 255);
|
||||
if (this.friendship === 255) {
|
||||
globalScene.validateAchv(achvs.MAX_FRIENDSHIP);
|
||||
}
|
||||
// Add to candy progress for this mon's starter species and its fused species (if it has one)
|
||||
starterData.forEach((sd: StarterDataEntry, i: number) => {
|
||||
const speciesId = !i ? starterSpeciesId : (fusionStarterSpeciesId as SpeciesId);
|
||||
sd.friendship = (sd.friendship || 0) + starterAmount.value;
|
||||
if (sd.friendship >= getStarterValueFriendshipCap(speciesStarterCosts[speciesId])) {
|
||||
globalScene.gameData.addStarterCandy(getPokemonSpecies(speciesId), 1);
|
||||
sd.friendship = 0;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Lose friendship upon fainting
|
||||
/**
|
||||
* Add friendship to this Pokemon
|
||||
*
|
||||
* @remarks
|
||||
* This adds friendship to the pokemon's friendship stat (used for evolution, return, etc.) and candy progress.
|
||||
* For fusions, candy progress for each species in the fusion is halved.
|
||||
*
|
||||
* @param friendship - The amount of friendship to add. Negative values will reduce friendship, though not below 0.
|
||||
* @param capped - If true, don't allow the friendship gain to exceed 200. Used to cap friendship gains from rare candies.
|
||||
*/
|
||||
addFriendship(friendship: number, capped = false): void {
|
||||
// Short-circuit friendship loss, which doesn't impact candy friendship
|
||||
if (friendship <= 0) {
|
||||
this.friendship = Math.max(this.friendship + friendship, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
const starterSpeciesId = this.species.getRootSpeciesId();
|
||||
const fusionStarterSpeciesId = this.isFusion() && this.fusionSpecies ? this.fusionSpecies.getRootSpeciesId() : 0;
|
||||
const starterGameData = globalScene.gameData.starterData;
|
||||
const starterData: [StarterDataEntry, SpeciesId][] = [[starterGameData[starterSpeciesId], starterSpeciesId]];
|
||||
if (fusionStarterSpeciesId) {
|
||||
starterData.push([starterGameData[fusionStarterSpeciesId], fusionStarterSpeciesId]);
|
||||
}
|
||||
const amount = new NumberHolder(friendship);
|
||||
globalScene.applyModifier(PokemonFriendshipBoosterModifier, true, this, amount);
|
||||
friendship = amount.value;
|
||||
|
||||
const newFriendship = this.friendship + friendship;
|
||||
// If capped is true, only adjust friendship if the new friendship is less than or equal to 200.
|
||||
if (!capped || newFriendship <= RARE_CANDY_FRIENDSHIP_CAP) {
|
||||
this.friendship = Math.min(newFriendship, 255);
|
||||
if (newFriendship >= 255) {
|
||||
globalScene.validateAchv(achvs.MAX_FRIENDSHIP);
|
||||
awardRibbonsToSpeciesLine(this.species.speciesId, RibbonData.FRIENDSHIP);
|
||||
}
|
||||
}
|
||||
|
||||
let candyFriendshipMultiplier = globalScene.gameMode.isClassic
|
||||
? timedEventManager.getClassicFriendshipMultiplier()
|
||||
: 1;
|
||||
if (fusionStarterSpeciesId) {
|
||||
candyFriendshipMultiplier /= timedEventManager.areFusionsBoosted() ? 1.5 : 2;
|
||||
}
|
||||
const candyFriendshipAmount = Math.floor(friendship * candyFriendshipMultiplier);
|
||||
// Add to candy progress for this mon's starter species and its fused species (if it has one)
|
||||
starterData.forEach(([sd, id]: [StarterDataEntry, SpeciesId]) => {
|
||||
sd.friendship = (sd.friendship || 0) + candyFriendshipAmount;
|
||||
if (sd.friendship >= getStarterValueFriendshipCap(speciesStarterCosts[id])) {
|
||||
globalScene.gameData.addStarterCandy(getPokemonSpecies(id), 1);
|
||||
sd.friendship = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getPossibleEvolution(evolution: SpeciesFormEvolution | null): Promise<Pokemon> {
|
||||
|
@ -2304,7 +2304,7 @@ export class PokemonLevelIncrementModifier extends ConsumablePokemonModifier {
|
||||
playerPokemon.levelExp = 0;
|
||||
}
|
||||
|
||||
playerPokemon.addFriendship(FRIENDSHIP_GAIN_FROM_RARE_CANDY);
|
||||
playerPokemon.addFriendship(FRIENDSHIP_GAIN_FROM_RARE_CANDY, true);
|
||||
|
||||
globalScene.phaseManager.unshiftNew(
|
||||
"LevelUpPhase",
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { pokerogueApi } from "#api/pokerogue-api";
|
||||
import { clientSessionId } from "#app/account";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { pokemonEvolutions, pokemonPrevolutions } from "#balance/pokemon-evolutions";
|
||||
import { pokemonEvolutions } from "#balance/pokemon-evolutions";
|
||||
import { modifierTypes } from "#data/data-lists";
|
||||
import { getCharVariantFromDialogue } from "#data/dialogue";
|
||||
import type { PokemonSpecies } from "#data/pokemon-species";
|
||||
@ -19,11 +19,12 @@ import { ChallengeData } from "#system/challenge-data";
|
||||
import type { SessionSaveData } from "#system/game-data";
|
||||
import { ModifierData as PersistentModifierData } from "#system/modifier-data";
|
||||
import { PokemonData } from "#system/pokemon-data";
|
||||
import { RibbonData, type RibbonFlag } from "#system/ribbon-data";
|
||||
import { RibbonData, type RibbonFlag } from "#system/ribbons/ribbon-data";
|
||||
import { awardRibbonsToSpeciesLine } from "#system/ribbons/ribbon-methods";
|
||||
import { TrainerData } from "#system/trainer-data";
|
||||
import { trainerConfigs } from "#trainers/trainer-config";
|
||||
import { checkSpeciesValidForChallenge, isNuzlockeChallenge } from "#utils/challenge-utils";
|
||||
import { isLocal, isLocalServerConnected, isNullOrUndefined } from "#utils/common";
|
||||
import { isLocal, isLocalServerConnected } from "#utils/common";
|
||||
import { getPokemonSpecies } from "#utils/pokemon-utils";
|
||||
import i18next from "i18next";
|
||||
|
||||
@ -134,25 +135,15 @@ export class GameOverPhase extends BattlePhase {
|
||||
// Award ribbons to all Pokémon in the player's party that are considered valid
|
||||
// for the current game mode and challenges.
|
||||
for (const pokemon of globalScene.getPlayerParty()) {
|
||||
const species = pokemon.species;
|
||||
if (
|
||||
checkSpeciesValidForChallenge(
|
||||
pokemon.species,
|
||||
globalScene.gameData.getSpeciesDexAttrProps(pokemon.species, pokemon.getDexAttr()),
|
||||
species,
|
||||
globalScene.gameData.getSpeciesDexAttrProps(species, pokemon.getDexAttr()),
|
||||
false,
|
||||
)
|
||||
) {
|
||||
const speciesId = pokemon.species.speciesId;
|
||||
const dexData = globalScene.gameData.dexData;
|
||||
dexData[speciesId].ribbons.award(ribbonFlags as RibbonFlag);
|
||||
|
||||
// Mark all pre-evolutions of the Pokémon with the same ribbon flags.
|
||||
for (
|
||||
let prevoId = pokemonPrevolutions[speciesId];
|
||||
!isNullOrUndefined(prevoId);
|
||||
prevoId = pokemonPrevolutions[prevoId]
|
||||
) {
|
||||
dexData[speciesId].ribbons.award(ribbonFlags as RibbonFlag);
|
||||
}
|
||||
awardRibbonsToSpeciesLine(species.speciesId, ribbonFlags as RibbonFlag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ import { EggData } from "#system/egg-data";
|
||||
import { GameStats } from "#system/game-stats";
|
||||
import { ModifierData as PersistentModifierData } from "#system/modifier-data";
|
||||
import { PokemonData } from "#system/pokemon-data";
|
||||
import { RibbonData } from "#system/ribbon-data";
|
||||
import { RibbonData } from "#system/ribbons/ribbon-data";
|
||||
import { resetSettings, SettingKeys, setSetting } from "#system/settings";
|
||||
import { SettingGamepad, setSettingGamepad, settingGamepadDefaults } from "#system/settings-gamepad";
|
||||
import type { SettingKeyboard } from "#system/settings-keyboard";
|
||||
|
@ -55,11 +55,11 @@ export class RibbonData {
|
||||
public static readonly MONO_GEN = 0x40000 as RibbonFlag;
|
||||
|
||||
/** Flag for winning classic */
|
||||
public static readonly CLASSIC = 0x80000;
|
||||
public static readonly CLASSIC = 0x80000 as RibbonFlag;
|
||||
/** Flag for winning the nuzzlocke challenge */
|
||||
public static readonly NUZLOCKE = 0x80000;
|
||||
public static readonly NUZLOCKE = 0x80000 as RibbonFlag;
|
||||
/** Flag for reaching max friendship */
|
||||
public static readonly FRIENDSHIP = 0x100000;
|
||||
public static readonly FRIENDSHIP = 0x100000 as RibbonFlag;
|
||||
//#endregion Ribbons
|
||||
|
||||
constructor(value: number) {
|
20
src/system/ribbons/ribbon-methods.ts
Normal file
20
src/system/ribbons/ribbon-methods.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { pokemonPrevolutions } from "#balance/pokemon-evolutions";
|
||||
import type { SpeciesId } from "#enums/species-id";
|
||||
import type { RibbonFlag } from "#system/ribbons/ribbon-data";
|
||||
import { isNullOrUndefined } from "#utils/common";
|
||||
|
||||
/**
|
||||
* Award one or more ribbons to a species and its pre-evolutions
|
||||
*
|
||||
* @param id - The ID of the species to award ribbons to
|
||||
* @param ribbons The ribbon(s) to award (use bitwise OR to combine multiple)
|
||||
*/
|
||||
export function awardRibbonsToSpeciesLine(id: SpeciesId, ribbons: RibbonFlag): void {
|
||||
const dexData = globalScene.gameData.dexData;
|
||||
dexData[id].ribbons.award(ribbons);
|
||||
// Mark all pre-evolutions of the Pokémon with the same ribbon flags.
|
||||
for (let prevoId = pokemonPrevolutions[id]; !isNullOrUndefined(prevoId); prevoId = pokemonPrevolutions[prevoId]) {
|
||||
dexData[id].ribbons.award(ribbons);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user