More changes

This commit is contained in:
Wlowscha 2025-05-11 23:11:32 +02:00
parent 8613dadad9
commit 560b6fd369
No known key found for this signature in database
GPG Key ID: 3C8F1AD330565D04
7 changed files with 279 additions and 99 deletions

View File

@ -1,18 +1,18 @@
import { allHeldItems } from "#app/modifier/held-items"; import { allHeldItems } from "#app/modifier/held-items";
import type { HeldItemType } from "#app/modifier/held-items"; import type { HeldItems } from "#app/modifier/held-items";
export class PokemonItemManager { export class PokemonItemManager {
private heldItems: [HeldItemType, number][]; private heldItems: [HeldItems, number][];
constructor() { constructor() {
this.heldItems = []; this.heldItems = [];
} }
getHeldItems(): [HeldItemType, number][] { getHeldItems(): [HeldItems, number][] {
return this.heldItems; return this.heldItems;
} }
addHeldItem(itemType: HeldItemType, stack: number) { addHeldItem(itemType: HeldItems, stack: number) {
const maxStack = allHeldItems[itemType].getMaxStackCount(); const maxStack = allHeldItems[itemType].getMaxStackCount();
const existing = this.heldItems.find(([type]) => type === itemType); const existing = this.heldItems.find(([type]) => type === itemType);

View File

@ -21,6 +21,7 @@ import { initVouchers } from "#app/system/voucher";
import { Biome } from "#enums/biome"; import { Biome } from "#enums/biome";
import { initMysteryEncounters } from "#app/data/mystery-encounters/mystery-encounters"; import { initMysteryEncounters } from "#app/data/mystery-encounters/mystery-encounters";
import { timedEventManager } from "./global-event-manager"; import { timedEventManager } from "./global-event-manager";
import { initHeldItems } from "./modifier/held-items";
export class LoadingScene extends SceneBase { export class LoadingScene extends SceneBase {
public static readonly KEY = "loading"; public static readonly KEY = "loading";
@ -375,6 +376,7 @@ export class LoadingScene extends SceneBase {
initSpecies(); initSpecies();
initMoves(); initMoves();
initAbilities(); initAbilities();
initHeldItems();
initChallenges(); initChallenges();
initMysteryEncounters(); initMysteryEncounters();
} }

View File

@ -0,0 +1,69 @@
/**
import { PlayerPokemon } from "#app/field/pokemon";
import { randSeedInt } from "#app/utils/common";
import { HeldItemCategories, HeldItems } from "./held-items";
import { ModifierTier } from "./modifier-tier";
interface HeldItemPool {
[tier: string]: [HeldItems | HeldItemCategories, number][];
}
const dailyStarterHeldItemPool: HeldItemPool = {
[ModifierTier.COMMON]: [
[HeldItemCategories.BASE_STAT_BOOSTER, 1],
[HeldItemCategories.BERRY, 3],
],
[ModifierTier.GREAT]: [
[HeldItemCategories.ATTACK_TYPE_BOOSTER, 5],
],
[ModifierTier.ULTRA]: [
[HeldItems.REVIVER_SEED, 4],
[HeldItems.SOOTHE_BELL, 1],
[HeldItems.SOUL_DEW, 1],
[HeldItems.GOLDEN_PUNCH, 1],
],
[ModifierTier.ROGUE]: [
[HeldItems.GRIP_CLAW, 5],
[HeldItems.BATON, 2],
[HeldItems.FOCUS_BAND, 5],
[HeldItems.QUICK_CLAW, 3],
[HeldItems.KINGS_ROCK, 3],
],
[ModifierTier.MASTER]: [
[HeldItems.LEFTOVERS, 1],
[HeldItems.SHELL_BELL, 1],
],
};
export function getDailyRunStarterModifiers(party: PlayerPokemon[]): HeldItems[] {
const ret: HeldItems[] = [];
for (const p of party) {
for (let m = 0; m < 3; m++) {
const tierValue = randSeedInt(64);
let tier: ModifierTier;
if (tierValue > 25) {
tier = ModifierTier.COMMON;
} else if (tierValue > 12) {
tier = ModifierTier.GREAT;
} else if (tierValue > 4) {
tier = ModifierTier.ULTRA;
} else if (tierValue) {
tier = ModifierTier.ROGUE;
} else {
tier = ModifierTier.MASTER;
}
const modifier = getNewModifierTypeOption(party, ModifierPoolType.DAILY_STARTER, tier)?.type?.newModifier(
p,
);
ret.push(modifier);
}
}
return ret;
}
*/

View File

@ -5,35 +5,58 @@ import type { NumberHolder } from "#app/utils/common";
import { PokemonType } from "#enums/pokemon-type"; import { PokemonType } from "#enums/pokemon-type";
import i18next from "i18next"; import i18next from "i18next";
export enum HeldItemType { export const HeldItems = {
NONE, NONE: 0x0000,
SITRUS_BERRY = 1, SITRUS_BERRY: 0x0101,
LEPPA_BERRY, LEPPA_BERRY: 0x0102,
SILK_SCARF = 101, SILK_SCARF: 0x0201,
BLACK_BELT, BLACK_BELT: 0x0202,
SHARP_BEAK, SHARP_BEAK: 0x0203,
POISON_BARB, POISON_BARB: 0x0204,
SOFT_SAND, SOFT_SAND: 0x0205,
HARD_STONE, HARD_STONE: 0x0206,
SILVER_POWDER, SILVER_POWDER: 0x0207,
SPELL_TAG, SPELL_TAG: 0x0208,
METAL_COAT, METAL_COAT: 0x0209,
CHARCOAL, CHARCOAL: 0x020a,
MYSTIC_WATER, MYSTIC_WATER: 0x020b,
MIRACLE_SEED, MIRACLE_SEED: 0x020c,
MAGNET, MAGNET: 0x020d,
TWISTED_SPOON, TWISTED_SPOON: 0x020e,
NEVER_MELT_ICE, NEVER_MELT_ICE: 0x020f,
DRAGON_FANG, DRAGON_FANG: 0x0210,
BLACK_GLASSES, BLACK_GLASSES: 0x0211,
FAIRY_FEATHER, FAIRY_FEATHER: 0x0212,
}
REVIVER_SEED: 0x0301,
SOOTHE_BELL: 0x0302,
SOUL_DEW: 0x0303,
GOLDEN_PUNCH: 0x0304,
GRIP_CLAW: 0x0305,
BATON: 0x0306,
FOCUS_BAND: 0x0307,
QUICK_CLAW: 0x0308,
KINGS_ROCK: 0x0309,
LEFTOVERS: 0x030a,
SHELL_BELL: 0x030b,
};
export type HeldItems = (typeof HeldItems)[keyof typeof HeldItems];
export const HeldItemCategories = {
NONE: 0x0000,
BERRY: 0x0100,
ATTACK_TYPE_BOOSTER: 0x0200,
BASE_STAT_BOOSTER: 0x0400,
};
export type HeldItemCategories = (typeof HeldItemCategories)[keyof typeof HeldItemCategories];
export class HeldItem implements Localizable { export class HeldItem implements Localizable {
// public pokemonId: number; // public pokemonId: number;
public type: HeldItemType; public type: HeldItems;
public maxStackCount: number; public maxStackCount: number;
public isTransferable = true; public isTransferable = true;
public isStealable = true; public isStealable = true;
@ -43,7 +66,7 @@ export class HeldItem implements Localizable {
public description = ""; public description = "";
public icon = ""; public icon = "";
constructor(type: HeldItemType, maxStackCount = 1) { constructor(type: HeldItems, maxStackCount = 1) {
this.type = type; this.type = type;
this.maxStackCount = maxStackCount; this.maxStackCount = maxStackCount;
@ -125,36 +148,36 @@ export class HeldItem implements Localizable {
} }
} }
interface AttackTypeToHeldItemTypeMap { interface AttackTypeToHeldItemMap {
[key: number]: HeldItemType; [key: number]: HeldItems;
} }
export const attackTypeToHeldItemTypeMap: AttackTypeToHeldItemTypeMap = { export const attackTypeToHeldItem: AttackTypeToHeldItemMap = {
[PokemonType.NORMAL]: HeldItemType.SILK_SCARF, [PokemonType.NORMAL]: HeldItems.SILK_SCARF,
[PokemonType.FIGHTING]: HeldItemType.BLACK_BELT, [PokemonType.FIGHTING]: HeldItems.BLACK_BELT,
[PokemonType.FLYING]: HeldItemType.SHARP_BEAK, [PokemonType.FLYING]: HeldItems.SHARP_BEAK,
[PokemonType.POISON]: HeldItemType.POISON_BARB, [PokemonType.POISON]: HeldItems.POISON_BARB,
[PokemonType.GROUND]: HeldItemType.SOFT_SAND, [PokemonType.GROUND]: HeldItems.SOFT_SAND,
[PokemonType.ROCK]: HeldItemType.HARD_STONE, [PokemonType.ROCK]: HeldItems.HARD_STONE,
[PokemonType.BUG]: HeldItemType.SILVER_POWDER, [PokemonType.BUG]: HeldItems.SILVER_POWDER,
[PokemonType.GHOST]: HeldItemType.SPELL_TAG, [PokemonType.GHOST]: HeldItems.SPELL_TAG,
[PokemonType.STEEL]: HeldItemType.METAL_COAT, [PokemonType.STEEL]: HeldItems.METAL_COAT,
[PokemonType.FIRE]: HeldItemType.CHARCOAL, [PokemonType.FIRE]: HeldItems.CHARCOAL,
[PokemonType.WATER]: HeldItemType.MYSTIC_WATER, [PokemonType.WATER]: HeldItems.MYSTIC_WATER,
[PokemonType.GRASS]: HeldItemType.MIRACLE_SEED, [PokemonType.GRASS]: HeldItems.MIRACLE_SEED,
[PokemonType.ELECTRIC]: HeldItemType.MAGNET, [PokemonType.ELECTRIC]: HeldItems.MAGNET,
[PokemonType.PSYCHIC]: HeldItemType.TWISTED_SPOON, [PokemonType.PSYCHIC]: HeldItems.TWISTED_SPOON,
[PokemonType.ICE]: HeldItemType.NEVER_MELT_ICE, [PokemonType.ICE]: HeldItems.NEVER_MELT_ICE,
[PokemonType.DRAGON]: HeldItemType.DRAGON_FANG, [PokemonType.DRAGON]: HeldItems.DRAGON_FANG,
[PokemonType.DARK]: HeldItemType.BLACK_GLASSES, [PokemonType.DARK]: HeldItems.BLACK_GLASSES,
[PokemonType.FAIRY]: HeldItemType.FAIRY_FEATHER, [PokemonType.FAIRY]: HeldItems.FAIRY_FEATHER,
}; };
export class AttackTypeBoosterHeldItem extends HeldItem { export class AttackTypeBoosterHeldItem extends HeldItem {
public moveType: PokemonType; public moveType: PokemonType;
public powerBoost: number; public powerBoost: number;
constructor(type: HeldItemType, maxStackCount = 1, moveType: PokemonType, powerBoost: number) { constructor(type: HeldItems, maxStackCount = 1, moveType: PokemonType, powerBoost: number) {
super(type, maxStackCount); super(type, maxStackCount);
this.moveType = moveType; this.moveType = moveType;
this.powerBoost = powerBoost; this.powerBoost = powerBoost;
@ -162,7 +185,7 @@ export class AttackTypeBoosterHeldItem extends HeldItem {
} }
getName(): string { getName(): string {
return i18next.t(`modifierType:AttackTypeBoosterItem.${HeldItemType[this.type]?.toLowerCase()}`); return i18next.t(`modifierType:AttackTypeBoosterItem.${HeldItems[this.type]?.toLowerCase()}`);
} }
getDescription(): string { getDescription(): string {
@ -172,7 +195,7 @@ export class AttackTypeBoosterHeldItem extends HeldItem {
} }
getIcon(): string { getIcon(): string {
return `${HeldItemType[this.type]?.toLowerCase()}`; return `${HeldItems[this.type]?.toLowerCase()}`;
} }
apply(stackCount: number, moveType: PokemonType, movePower: NumberHolder): void { apply(stackCount: number, moveType: PokemonType, movePower: NumberHolder): void {
@ -192,17 +215,12 @@ export function applyAttackTypeBoosterHeldItem(pokemon: Pokemon, moveType: Pokem
} }
} }
type HeldItemMap = { export const allHeldItems = {};
[key in HeldItemType]: HeldItem;
};
export const allHeldItems = {} as HeldItemMap;
export function initHeldItems() { export function initHeldItems() {
// SILK_SCARF, BLACK_BELT, etc... // SILK_SCARF, BLACK_BELT, etc...
for (const [typeKey, heldItemType] of Object.entries(attackTypeToHeldItemTypeMap)) { for (const [typeKey, heldItemType] of Object.entries(attackTypeToHeldItem)) {
const pokemonType = Number(typeKey) as PokemonType; const pokemonType = Number(typeKey) as PokemonType;
allHeldItems[heldItemType] = new AttackTypeBoosterHeldItem(heldItemType, 99, pokemonType, 0.2); allHeldItems[heldItemType] = new AttackTypeBoosterHeldItem(heldItemType, 99, pokemonType, 0.2);
} }
} }

View File

@ -128,8 +128,8 @@ import { getStatKey, Stat, TEMP_BATTLE_STATS } from "#enums/stat";
import { StatusEffect } from "#enums/status-effect"; import { StatusEffect } from "#enums/status-effect";
import i18next from "i18next"; import i18next from "i18next";
import { timedEventManager } from "#app/global-event-manager"; import { timedEventManager } from "#app/global-event-manager";
import type { HeldItemType } from "./held-items"; import type { HeldItems } from "./held-items";
import { allHeldItems, attackTypeToHeldItemTypeMap } from "./held-items"; import { allHeldItems, attackTypeToHeldItem } from "./held-items";
const outputModifierData = false; const outputModifierData = false;
const useMaxWeightForOutput = false; const useMaxWeightForOutput = false;
@ -812,10 +812,10 @@ export class AttackTypeBoosterModifierType
{ {
public moveType: PokemonType; public moveType: PokemonType;
public boostPercent: number; public boostPercent: number;
public heldItemId: HeldItemType; public heldItemId: HeldItems;
constructor(moveType: PokemonType, boostPercent: number) { constructor(moveType: PokemonType, boostPercent: number) {
const heldItemId = attackTypeToHeldItemTypeMap[moveType]; const heldItemId = attackTypeToHeldItem[moveType];
super( super(
"", "",
allHeldItems[heldItemId].getIcon(), allHeldItems[heldItemId].getIcon(),

View File

@ -0,0 +1,120 @@
import { AttackMove } from "#app/data/moves/move";
import type Pokemon from "#app/field/pokemon";
import { PokemonType } from "#enums/pokemon-type";
import { attackTypeToHeldItem } from "./held-items";
import { HeldItemReward, type Reward } from "./reward";
function getRandomWeightedSelection<T>(weights: Map<T, number>): T | null {
const totalWeight = Array.from(weights.values()).reduce((sum, weight) => sum + weight, 0);
if (totalWeight === 0) {
return null;
}
const randInt = Math.floor(Math.random() * totalWeight);
let accumulatedWeight = 0;
for (const [item, weight] of weights.entries()) {
accumulatedWeight += weight;
if (randInt < accumulatedWeight) {
return item;
}
}
return null;
}
export class RewardGenerator<T extends number> {
options: T[];
tempWeights: Map<T, number>;
constructor(options: T[]) {
this.options = options;
this.tempWeights = new Map(this.options.map(option => [option, 1]));
}
generate(party: Pokemon[], overrideWeightFunction?: Function) {
const weights = overrideWeightFunction ? overrideWeightFunction(party) : this.weightFunction(party);
for (const [option, tempWeight] of this.tempWeights.entries()) {
if (tempWeight === 0 && weights.has(option)) {
weights.set(option, 0);
}
}
const value: T | null = getRandomWeightedSelection(weights);
if (value) {
this.tempWeights.set(value, 0);
return this.generateReward(value);
}
return null;
}
weightFunction(_party: Pokemon[]): Map<T, number> {
const defaultWeightMap = new Map<T, number>();
this.options.forEach(option => {
defaultWeightMap.set(option, 1);
});
return defaultWeightMap;
}
generateReward(_value: T): Reward | null {
return null;
}
}
export class AttackTypeBoosterHeldItemRewardGenerator extends RewardGenerator<PokemonType> {
constructor() {
//TODO: we can also construct this, but then have to handle options being null
const options = [
PokemonType.NORMAL,
PokemonType.FIGHTING,
PokemonType.FLYING,
PokemonType.POISON,
PokemonType.GROUND,
PokemonType.ROCK,
PokemonType.BUG,
PokemonType.GHOST,
PokemonType.STEEL,
PokemonType.FIRE,
PokemonType.WATER,
PokemonType.GRASS,
PokemonType.ELECTRIC,
PokemonType.PSYCHIC,
PokemonType.ICE,
PokemonType.DRAGON,
PokemonType.DARK,
PokemonType.FAIRY,
];
super(options);
}
weightFunction(party: Pokemon[]): Map<PokemonType, number> {
const attackMoveTypes = party.flatMap(p =>
p
.getMoveset()
.map(m => m.getMove())
.filter(m => m instanceof AttackMove)
.map(m => m.type),
);
const attackMoveTypeWeights = new Map<PokemonType, number>();
for (const type of attackMoveTypes) {
const currentWeight = attackMoveTypeWeights.get(type) ?? 0;
if (currentWeight < 3) {
attackMoveTypeWeights.set(type, currentWeight + 1);
}
}
return attackMoveTypeWeights;
}
generateReward(value: PokemonType) {
return new HeldItemReward(attackTypeToHeldItem[value]);
}
}

View File

@ -2,7 +2,7 @@
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import type { PokeballType } from "#enums/pokeball"; import type { PokeballType } from "#enums/pokeball";
import i18next from "i18next"; import i18next from "i18next";
import { allHeldItems, type HeldItem } from "./held-items"; import { allHeldItems, type HeldItems } from "./held-items";
import { getPokeballCatchMultiplier, getPokeballName, MAX_PER_TYPE_POKEBALLS } from "#app/data/pokeball"; import { getPokeballCatchMultiplier, getPokeballName, MAX_PER_TYPE_POKEBALLS } from "#app/data/pokeball";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
@ -77,8 +77,9 @@ export class PartySelectReward extends Reward {
} }
export class HeldItemReward extends PartySelectReward { export class HeldItemReward extends PartySelectReward {
private itemId; private itemId: HeldItems;
constructor(itemId: HeldItem) {
constructor(itemId: HeldItems) {
super(); super();
this.itemId = itemId; this.itemId = itemId;
} }
@ -103,38 +104,14 @@ export class HeldItemReward extends PartySelectReward {
export class RewardGenerator {
options: number[];
optionWeights: number[];
constructor(options: number[]) {
this.options = options;
}
}
export class PokeballRewardGenerator extends RewardGenerator{
constructor(
options: PokeballType[],
condition?: (party: Pokemon[], option: number) => boolean,
getOptionWeight?: (party: Pokemon[], option: number) => number,
) {
super(options);
this.isAvailable = isAvailable;
this.getOptionWeight = getOptionWeight;
}
isAvailable(): boolean {
}
optionWeights() {
}
}
@ -162,12 +139,6 @@ export class RewardManager {
this.rewardPool = rewardPool; this.rewardPool = rewardPool;
} }
} }
* */
*/