type hints

This commit is contained in:
Yentis 2024-05-18 00:28:56 +02:00
parent 5dd017fa30
commit aa91ae4c49
7 changed files with 167 additions and 16 deletions

View File

@ -119,6 +119,7 @@ export default class BattleScene extends SceneBase {
public fusionPaletteSwaps: boolean = true; public fusionPaletteSwaps: boolean = true;
public enableTouchControls: boolean = false; public enableTouchControls: boolean = false;
public enableVibration: boolean = false; public enableVibration: boolean = false;
public typeHints: integer = 0;
public abSwapped: boolean = false; public abSwapped: boolean = false;
public disableMenu: boolean = false; public disableMenu: boolean = false;

View File

@ -943,6 +943,22 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return !this.isOfType(Type.FLYING, true) && !this.hasAbility(Abilities.LEVITATE); return !this.isOfType(Type.FLYING, true) && !this.hasAbility(Abilities.LEVITATE);
} }
isStabMove(move: Move): boolean {
if (move.category === MoveCategory.STATUS) return false;
const type = move.type;
const types = this.getTypes();
const teraType = this.getTeraType();
const matchesSourceType = types[0] === type || (types.length > 1 && types[1] === type);
return (teraType === Type.UNKNOWN && matchesSourceType) || (teraType !== Type.UNKNOWN && teraType === type);
}
getMoveEffectiveness(source: Pokemon, move: PokemonMove): TypeDamageMultiplier | undefined {
if (move.getMove().category === MoveCategory.STATUS) return undefined;
return this.getAttackMoveEffectiveness(source, move);
}
getAttackMoveEffectiveness(source: Pokemon, move: PokemonMove): TypeDamageMultiplier { getAttackMoveEffectiveness(source: Pokemon, move: PokemonMove): TypeDamageMultiplier {
const typeless = !!move.getMove().getAttrs(TypelessAttr).length; const typeless = !!move.getMove().getAttrs(TypelessAttr).length;
const typeMultiplier = new Utils.NumberHolder(this.getAttackTypeEffectiveness(move.getMove().type, source)); const typeMultiplier = new Utils.NumberHolder(this.getAttackTypeEffectiveness(move.getMove().type, source));
@ -1096,11 +1112,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
let shinyThreshold = new Utils.IntegerHolder(32); let shinyThreshold = new Utils.IntegerHolder(32);
if (thresholdOverride === undefined) { if (thresholdOverride === undefined) {
if (!this.hasTrainer()) { if (!this.hasTrainer())
if (new Date() < new Date('2024-05-21'))
shinyThreshold.value *= 3;
this.scene.applyModifiers(ShinyRateBoosterModifier, true, shinyThreshold); this.scene.applyModifiers(ShinyRateBoosterModifier, true, shinyThreshold);
}
} else } else
shinyThreshold.value = thresholdOverride; shinyThreshold.value = thresholdOverride;
@ -1376,6 +1389,57 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return this.battleInfo.updateInfo(this, instant); return this.battleInfo.updateInfo(this, instant);
} }
updateNameColor() {
const nameColor = this.getNameColor();
if (nameColor === undefined) return;
this.battleInfo.updateNameColor(nameColor);
}
getNameColor(): string | undefined {
const typeHints = this.scene.typeHints;
if (typeHints === 0) return undefined;
const opponents = this.getOpponents();
const opponentMoveEffectivenessList = opponents.map((opponent) => {
return opponent.getMoveset().map((move) => {
return this.getMoveEffectiveness(opponent, move);
});
}).flat().filter((effectiveness) => effectiveness !== undefined);
const moveEffectivenessList = opponents.map((opponent) => {
return this.getMoveset().map((move) => {
return opponent.getMoveEffectiveness(this, move);
});
}).flat().filter((effectiveness) => effectiveness !== undefined);
const fullHints = typeHints === 2;
if (fullHints && opponentMoveEffectivenessList.some((effectiveness) => effectiveness === 8)) {
return 'darkred';
} else if (fullHints && opponentMoveEffectivenessList.some((effectiveness) => effectiveness === 4)) {
return 'red';
} else if (fullHints && opponentMoveEffectivenessList.some((effectiveness) => effectiveness === 2)) {
return 'crimson';
} else if (moveEffectivenessList.some((effectiveness) => effectiveness === 8)) {
return 'darkgreen';
} else if (moveEffectivenessList.some((effectiveness) => effectiveness === 4)) {
return 'green';
} else if (moveEffectivenessList.some((effectiveness) => effectiveness === 2)) {
return 'lightgreen';
} else if (fullHints && opponentMoveEffectivenessList.every((effectiveness) => effectiveness === 0)) {
return 'yellow';
} else if (fullHints && opponentMoveEffectivenessList.every((effectiveness) => effectiveness === 0.125)) {
return 'darkblue';
} else if (fullHints && opponentMoveEffectivenessList.every((effectiveness) => effectiveness === 0.25)) {
return 'blue';
} else if (fullHints && opponentMoveEffectivenessList.every((effectiveness) => effectiveness === 0.5)) {
return 'lightblue';
}
return 'white';
}
toggleStats(visible: boolean): void { toggleStats(visible: boolean): void {
this.battleInfo.toggleStats(visible); this.battleInfo.toggleStats(visible);
} }
@ -1526,11 +1590,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const isTypeImmune = (typeMultiplier.value * arenaAttackTypeMultiplier.value) === 0; const isTypeImmune = (typeMultiplier.value * arenaAttackTypeMultiplier.value) === 0;
const sourceTypes = source.getTypes(); const sourceTypes = source.getTypes();
const matchesSourceType = sourceTypes[0] === type || (sourceTypes.length > 1 && sourceTypes[1] === type); const matchesSourceType = sourceTypes[0] === type || (sourceTypes.length > 1 && sourceTypes[1] === type);
let stabMultiplier = new Utils.NumberHolder(1); let stabMultiplier = new Utils.NumberHolder(1);
if (sourceTeraType === Type.UNKNOWN && matchesSourceType) if (source.isStabMove(move)) {
stabMultiplier.value += 0.5;
else if (sourceTeraType !== Type.UNKNOWN && sourceTeraType === type)
stabMultiplier.value += 0.5; stabMultiplier.value += 0.5;
}
applyAbAttrs(StabBoostAbAttr, source, null, stabMultiplier); applyAbAttrs(StabBoostAbAttr, source, null, stabMultiplier);

View File

@ -1572,6 +1572,10 @@ export class CheckSwitchPhase extends BattlePhase {
super.start(); super.start();
const pokemon = this.scene.getPlayerField()[this.fieldIndex]; const pokemon = this.scene.getPlayerField()[this.fieldIndex];
this.scene.getParty().forEach((pokemon) => {
pokemon.updateNameColor();
});
if (this.scene.field.getAll().indexOf(pokemon) === -1) { if (this.scene.field.getAll().indexOf(pokemon) === -1) {
this.scene.unshiftPhase(new SummonMissingPhase(this.scene, this.fieldIndex)); this.scene.unshiftPhase(new SummonMissingPhase(this.scene, this.fieldIndex));
@ -1651,6 +1655,10 @@ export class TurnInitPhase extends FieldPhase {
} }
}); });
this.scene.getParty().forEach((pokemon) => {
pokemon.updateNameColor();
});
this.scene.pushPhase(new TurnStartPhase(this.scene)); this.scene.pushPhase(new TurnStartPhase(this.scene));
this.end(); this.end();

View File

@ -28,7 +28,8 @@ export enum Setting {
Gamepad_Support = "GAMEPAD_SUPPORT", Gamepad_Support = "GAMEPAD_SUPPORT",
Swap_A_and_B = "SWAP_A_B", // Swaps which gamepad button handles ACTION and CANCEL Swap_A_and_B = "SWAP_A_B", // Swaps which gamepad button handles ACTION and CANCEL
Touch_Controls = "TOUCH_CONTROLS", Touch_Controls = "TOUCH_CONTROLS",
Vibration = "VIBRATION" Vibration = "VIBRATION",
Type_Hints = "TYPE_HINTS"
} }
export interface SettingOptions { export interface SettingOptions {
@ -61,7 +62,8 @@ export const settingOptions: SettingOptions = {
[Setting.Gamepad_Support]: ['Auto', 'Disabled'], [Setting.Gamepad_Support]: ['Auto', 'Disabled'],
[Setting.Swap_A_and_B]: ['Enabled', 'Disabled'], [Setting.Swap_A_and_B]: ['Enabled', 'Disabled'],
[Setting.Touch_Controls]: ['Auto', 'Disabled'], [Setting.Touch_Controls]: ['Auto', 'Disabled'],
[Setting.Vibration]: ['Auto', 'Disabled'] [Setting.Vibration]: ['Auto', 'Disabled'],
[Setting.Type_Hints]: ['Off', 'Partial', 'Full']
}; };
export const settingDefaults: SettingDefaults = { export const settingDefaults: SettingDefaults = {
@ -86,7 +88,8 @@ export const settingDefaults: SettingDefaults = {
[Setting.Gamepad_Support]: 0, [Setting.Gamepad_Support]: 0,
[Setting.Swap_A_and_B]: 1, // Set to 'Disabled' by default [Setting.Swap_A_and_B]: 1, // Set to 'Disabled' by default
[Setting.Touch_Controls]: 0, [Setting.Touch_Controls]: 0,
[Setting.Vibration]: 0 [Setting.Vibration]: 0,
[Setting.Type_Hints]: 0,
}; };
export const reloadSettings: Setting[] = [Setting.UI_Theme, Setting.Language, Setting.Sprite_Set]; export const reloadSettings: Setting[] = [Setting.UI_Theme, Setting.Language, Setting.Sprite_Set];
@ -171,6 +174,9 @@ export function setSetting(scene: BattleScene, setting: Setting, value: integer)
case Setting.Vibration: case Setting.Vibration:
scene.enableVibration = settingOptions[setting][value] !== 'Disabled' && hasTouchscreen(); scene.enableVibration = settingOptions[setting][value] !== 'Disabled' && hasTouchscreen();
break; break;
case Setting.Type_Hints:
scene.typeHints = value;
break;
case Setting.Language: case Setting.Language:
if (value) { if (value) {
if (scene.ui) { if (scene.ui) {

View File

@ -551,6 +551,10 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
this.lastName = pokemon.name; this.lastName = pokemon.name;
} }
updateNameColor(color: string) {
this.nameText.setColor(color);
}
updatePokemonExp(pokemon: Pokemon, instant?: boolean, levelDurationMultiplier: number = 1): Promise<void> { updatePokemonExp(pokemon: Pokemon, instant?: boolean, levelDurationMultiplier: number = 1): Promise<void> {
return new Promise(resolve => { return new Promise(resolve => {
const levelUp = this.lastLevel < pokemon.level; const levelUp = this.lastLevel < pokemon.level;

View File

@ -1,6 +1,6 @@
import BattleScene from "../battle-scene"; import BattleScene from "../battle-scene";
import { addTextObject, TextStyle } from "./text"; import { addTextObject, TextStyle } from "./text";
import { Type } from "../data/type"; import { Type, TypeDamageMultiplier } from "../data/type";
import { Command } from "./command-ui-handler"; import { Command } from "./command-ui-handler";
import { Mode } from "./ui"; import { Mode } from "./ui";
import UiHandler from "./ui-handler"; import UiHandler from "./ui-handler";
@ -9,6 +9,7 @@ import { CommandPhase } from "../phases";
import { MoveCategory } from "#app/data/move.js"; import { MoveCategory } from "#app/data/move.js";
import i18next from '../plugins/i18n'; import i18next from '../plugins/i18n';
import {Button} from "../enums/buttons"; import {Button} from "../enums/buttons";
import Pokemon, { PokemonMove } from "#app/field/pokemon.js";
export default class FightUiHandler extends UiHandler { export default class FightUiHandler extends UiHandler {
private movesContainer: Phaser.GameObjects.Container; private movesContainer: Phaser.GameObjects.Container;
@ -189,15 +190,79 @@ export default class FightUiHandler extends UiHandler {
} }
displayMoves() { displayMoves() {
const moveset = (this.scene.getCurrentPhase() as CommandPhase).getPokemon().getMoveset(); const pokemon = (this.scene.getCurrentPhase() as CommandPhase).getPokemon();
for (let m = 0; m < 4; m++) { const moveset = pokemon.getMoveset();
const moveText = addTextObject(this.scene, m % 2 === 0 ? 0 : 100, m < 2 ? 0 : 16, '-', TextStyle.WINDOW);
if (m < moveset.length) for (let moveIndex = 0; moveIndex < 4; moveIndex++) {
moveText.setText(moveset[m].getName()); const moveText = addTextObject(this.scene, moveIndex % 2 === 0 ? 0 : 100, moveIndex < 2 ? 0 : 16, '-', TextStyle.WINDOW);
if (moveIndex < moveset.length) {
const pokemonMove = moveset[moveIndex];
moveText.setText(pokemonMove.getName());
if (this.scene.typeHints > 0) {
this.setTypeHints(pokemon, pokemonMove, moveText);
}
}
this.movesContainer.add(moveText); this.movesContainer.add(moveText);
} }
} }
private setTypeHints(pokemon: Pokemon, pokemonMove: PokemonMove, moveText: Phaser.GameObjects.Text) {
const opponents = pokemon.getOpponents();
if (opponents.length < 1) return;
const move = pokemonMove.getMove();
const moveEffectivenessList = opponents.map((opponent) => opponent.getMoveEffectiveness(pokemon, pokemonMove));
let text = moveText.text;
const effectivenessTextList = moveEffectivenessList.map((effectiveness) => this.getMoveEffectivenessText(effectiveness));
if (effectivenessTextList.every((text) => text === effectivenessTextList[0])) {
if (moveEffectivenessList[0] !== 1) {
text += effectivenessTextList[0];
}
} else {
moveEffectivenessList.forEach((effectiveness) => {
text += this.getMoveEffectivenessText(effectiveness);
});
}
moveText.setText(text);
const stab = pokemon.isStabMove(move);
if (stab) moveText.setFontStyle('bold');
const moveColors = moveEffectivenessList.sort((a, b) => b - a).map((effectiveness) => this.getMoveColor(effectiveness));
moveText.setColor(moveColors[0]);
}
private getMoveEffectivenessText(moveEffectiveness?: TypeDamageMultiplier): string {
if (moveEffectiveness === undefined) return '';
return ` ${moveEffectiveness}x`;
}
private getMoveColor(moveEffectiveness?: TypeDamageMultiplier): string {
switch (moveEffectiveness) {
case 0:
return 'black';
case 0.125:
return 'darkred';
case 0.25:
return 'red';
case 0.5:
return 'crimson';
case 2:
return 'lightgreen';
case 4:
return 'green';
case 8:
return 'darkgreen';
}
return 'white';
}
clear() { clear() {
super.clear(); super.clear();
this.clearMoves(); this.clearMoves();

View File

@ -870,6 +870,9 @@ class PartySlot extends Phaser.GameObjects.Container {
slotName.setPositionRelative(slotBg, this.slotIndex >= battlerCount ? 21 : 24, this.slotIndex >= battlerCount ? 2 : 10); slotName.setPositionRelative(slotBg, this.slotIndex >= battlerCount ? 21 : 24, this.slotIndex >= battlerCount ? 2 : 10);
slotName.setOrigin(0, 0); slotName.setOrigin(0, 0);
const color = this.pokemon.getNameColor();
if (color !== undefined) slotName.setColor(color);
const slotLevelLabel = this.scene.add.image(0, 0, 'party_slot_overlay_lv'); const slotLevelLabel = this.scene.add.image(0, 0, 'party_slot_overlay_lv');
slotLevelLabel.setPositionRelative(slotName, 8, 12); slotLevelLabel.setPositionRelative(slotName, 8, 12);
slotLevelLabel.setOrigin(0, 0); slotLevelLabel.setOrigin(0, 0);