feat: implemented move effectiveness color

This commit is contained in:
Paul 2024-04-26 23:40:23 +02:00
parent ad87727517
commit 49e6126c51
9 changed files with 193 additions and 36 deletions

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "pokemon-rogue-battle",
"version": "1.0.1",
"version": "1.0.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "pokemon-rogue-battle",
"version": "1.0.1",
"version": "1.0.3",
"dependencies": {
"@material/material-color-utilities": "^0.2.7",
"crypto-js": "^4.2.0",

View File

@ -122,6 +122,7 @@ export default class BattleScene extends SceneBase {
public bgmVolume: number = 1;
public seVolume: number = 1;
public gameSpeed: integer = 1;
public showEffectiveness: boolean = false;
public damageNumbersMode: integer = 0;
public showLevelUpStats: boolean = true;
public enableTutorials: boolean = import.meta.env.VITE_BYPASS_TUTORIAL === "1";
@ -172,6 +173,8 @@ export default class BattleScene extends SceneBase {
public pokeballCounts: PokeballCounts;
public money: integer;
public pokemonInfoContainer: PokemonInfoContainer;
public selectedTarget: Pokemon;
public newEncounter: boolean = true;
private party: PlayerPokemon[];
private waveCountText: Phaser.GameObjects.Text;
private moneyText: Phaser.GameObjects.Text;
@ -1423,7 +1426,8 @@ export default class BattleScene extends SceneBase {
if (this.ui?.getMode() === Mode.SETTINGS)
(this.ui.getHandler() as SettingsUiHandler).show([]);
}
} else
}
else
return;
if (inputSuccess && this.enableVibration && typeof navigator.vibrate !== 'undefined')
navigator.vibrate(vibrationLength || 10);

View File

@ -696,7 +696,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const ret = !ignoreOverride && this.summonData?.moveset
? this.summonData.moveset
: this.moveset;
if (MOVE_OVERRIDE && this.isPlayer())
this.moveset[0] = new PokemonMove(MOVE_OVERRIDE, Math.min(this.moveset[0].ppUsed, allMoves[MOVE_OVERRIDE].pp));
else if (OPP_MOVE_OVERRIDE && !this.isPlayer())

View File

@ -666,7 +666,6 @@ export class EncounterPhase extends BattlePhase {
constructor(scene: BattleScene, loaded?: boolean) {
super(scene);
this.loaded = !!loaded;
}
@ -674,6 +673,7 @@ export class EncounterPhase extends BattlePhase {
super.start();
this.scene.initSession();
this.scene.newEncounter = true;
const loadEnemyAssets = [];
@ -1680,8 +1680,10 @@ export class CommandPhase extends FieldPhase {
console.log(moveTargets, playerPokemon.name);
if (moveTargets.targets.length <= 1 || moveTargets.multiple)
turnCommand.move.targets = moveTargets.targets;
else
else{
this.scene.ui.clearText();
this.scene.unshiftPhase(new SelectTargetPhase(this.scene, this.fieldIndex));
}
this.scene.currentBattle.turnCommands[this.fieldIndex] = turnCommand;
success = true;
} else if (cursor < playerPokemon.getMoveset().length) {
@ -1906,12 +1908,14 @@ export class SelectTargetPhase extends PokemonPhase {
const turnCommand = this.scene.currentBattle.turnCommands[this.fieldIndex];
const move = turnCommand.move?.move;
this.scene.ui.setMode(Mode.TARGET_SELECT, this.fieldIndex, move, (cursor: integer) => {
turnCommand.targets = [ cursor ];
this.scene.ui.setMode(Mode.MESSAGE);
if (cursor === -1) {
this.scene.currentBattle.turnCommands[this.fieldIndex] = null;
this.scene.unshiftPhase(new CommandPhase(this.scene, this.fieldIndex));
} else
turnCommand.targets = [ cursor ];
this.scene.newEncounter=false;
if (turnCommand.command === Command.BALL && this.fieldIndex)
this.scene.currentBattle.turnCommands[this.fieldIndex - 1].skip = true;
this.end();
@ -3210,6 +3214,7 @@ export class VictoryPhase extends PokemonPhase {
const multipleParticipantExpBonusModifier = this.scene.findModifier(m => m instanceof MultipleParticipantExpBonusModifier) as MultipleParticipantExpBonusModifier;
const expPartyMembers = party.filter(p => p.hp && p.level < this.scene.getMaxExpLevel());
const partyMemberExp = [];
this.scene.selectedTarget=null;
if (participantIds.size) {
let expValue = this.getPokemon().getExpValue();

View File

@ -12,6 +12,7 @@ export enum Setting {
BGM_Volume = "BGM_VOLUME",
SE_Volume = "SE_VOLUME",
Language = "LANGUAGE",
Move_Effectiveness = "MOVE_EFFECTIVENESS",
Damage_Numbers = "DAMAGE_NUMBERS",
UI_Theme = "UI_THEME",
Window_Type = "WINDOW_TYPE",
@ -43,6 +44,7 @@ export const settingOptions: SettingOptions = {
[Setting.BGM_Volume]: new Array(11).fill(null).map((_, i) => i ? (i * 10).toString() : 'Mute'),
[Setting.SE_Volume]: new Array(11).fill(null).map((_, i) => i ? (i * 10).toString() : 'Mute'),
[Setting.Language]: [ 'English', 'Change' ],
[Setting.Move_Effectiveness]:['Off','On'],
[Setting.Damage_Numbers]: [ 'Off', 'Simple', 'Fancy' ],
[Setting.UI_Theme]: [ 'Default', 'Legacy' ],
[Setting.Window_Type]: new Array(5).fill(null).map((_, i) => (i + 1).toString()),
@ -66,6 +68,7 @@ export const settingDefaults: SettingDefaults = {
[Setting.BGM_Volume]: 10,
[Setting.SE_Volume]: 10,
[Setting.Language]: 0,
[Setting.Move_Effectiveness]:0,
[Setting.Damage_Numbers]: 0,
[Setting.UI_Theme]: 0,
[Setting.Window_Type]: 0,
@ -102,6 +105,9 @@ export function setSetting(scene: BattleScene, setting: Setting, value: integer)
scene.seVolume = value ? parseInt(settingOptions[setting][value]) * 0.01 : 0;
scene.updateSoundVolume();
break;
case Setting.Move_Effectiveness:
scene.showEffectiveness = settingOptions[setting][value] === 'On';
break;
case Setting.Damage_Numbers:
scene.damageNumbersMode = value;
break;

View File

@ -8,6 +8,8 @@ import * as Utils from "../utils";
import { CommandPhase } from "../phases";
import { MoveCategory } from "#app/data/move.js";
import i18next from '../plugins/i18n';
import Pokemon from "../field/pokemon.js";
import { Moves } from "../data/enums/moves.js";
export default class FightUiHandler extends UiHandler {
private movesContainer: Phaser.GameObjects.Container;
@ -72,6 +74,19 @@ export default class FightUiHandler extends UiHandler {
messageHandler.commandWindow.setVisible(false);
messageHandler.movesWindowContainer.setVisible(true);
this.setCursor(this.getCursor());
this.displayMoves(this.scene.selectedTarget);
return true;
}
showTargettedMoves(args: any[]): boolean {
super.show(args);
this.fieldIndex = args.length ? args[0] as integer : 0;
const messageHandler = this.getUi().getMessageHandler();
messageHandler.commandWindow.setVisible(false);
messageHandler.movesWindowContainer.setVisible(true);
this.displayMoves();
return true;
@ -141,41 +156,63 @@ export default class FightUiHandler extends UiHandler {
ui.add(this.cursorObj);
}
const activePokemon =(this.scene.getCurrentPhase() as CommandPhase).getPokemon()
const moveset = (this.scene.getCurrentPhase() as CommandPhase).getPokemon().getMoveset();
const hasMove = cursor < moveset.length;
if (hasMove) {
const pokemonMove = moveset[cursor];
this.typeIcon.setTexture('types', Type[pokemonMove.getMove().type].toLowerCase()).setScale(0.8);
this.moveCategoryIcon.setTexture('categories', MoveCategory[pokemonMove.getMove().category].toLowerCase()).setScale(1.0);
const power = pokemonMove.getMove().power;
const maxPP = pokemonMove.getMovePp();
const pp = maxPP - pokemonMove.ppUsed;
this.ppText.setText(`${Utils.padInt(pp, 2, ' ')}/${Utils.padInt(maxPP, 2, ' ')}`);
this.powerText.setText(`${power >= 0 ? power : '---'}`);
}
this.typeIcon.setVisible(hasMove);
this.ppLabel.setVisible(hasMove);
this.ppText.setVisible(hasMove);
this.powerLabel.setVisible(hasMove);
this.powerText.setVisible(hasMove);
this.moveCategoryIcon.setVisible(hasMove);
this.cursorObj.setPosition(13 + (cursor % 2 === 1 ? 100 : 0), -31 + (cursor >= 2 ? 15 : 0));
if (hasMove) {
this.updateMovesWindowContainer(activePokemon,cursor)
}
return changed;
}
displayMoves() {
const moveset = (this.scene.getCurrentPhase() as CommandPhase).getPokemon().getMoveset();
displayMoves(pokemon?: Pokemon,move?:Moves) {
const actingPokemon =(this.scene.getCurrentPhase() as CommandPhase).getPokemon();
const targetPokemon = pokemon || this.scene.getEnemyPokemon();
this.setMoveColor(targetPokemon === actingPokemon ? this.scene.getEnemyPokemon() : targetPokemon, actingPokemon,move);
}
setMoveColor(targetPokemon:Pokemon,actingPokemon:Pokemon,move?:Moves){
const moveset = actingPokemon.getMoveset();
for (let m = 0; m < 4; m++) {
const moveText = addTextObject(this.scene, m % 2 === 0 ? 0 : 100, m < 2 ? 0 : 16, '-', TextStyle.WINDOW);
if (m < moveset.length)
this.typeIcon.setVisible(true);
this.ppText.setVisible(true);
this.moveCategoryIcon.setVisible(true);
if (m < moveset.length){
const pokemonMove = moveset[m];
if (pokemonMove.moveId===move) {
this.updateMovesWindowContainer(actingPokemon,m)
}
moveText.setText(moveset[m].getName());
const effectiveness = (targetPokemon.getAttackMoveEffectiveness(targetPokemon,pokemonMove))
if (this.scene.showEffectiveness) {
if (effectiveness === 0) {
moveText.setColor(this.getTextColor(TextStyle.ZERO_X_EFFECT)); // No effect
} else if (effectiveness === 4) {
moveText.setColor(this.getTextColor(TextStyle.FOUR_X_EFFECT)); // x4 Super effective
} else if (effectiveness === 2) {
moveText.setColor(this.getTextColor(TextStyle.TWO_X_EFFECT)); // x2 effective
} else if (effectiveness === 0.5) {
moveText.setColor(this.getTextColor(TextStyle.HALF_X_EFFECT)); // x0.5 Not very effective
} else if (effectiveness === 0.25) {
moveText.setColor(this.getTextColor(TextStyle.QUARTER_X_EFFECT)); // x0.25 Not very effective
}
}
}
this.movesContainer.add(moveText);
}
}
@ -201,4 +238,27 @@ export default class FightUiHandler extends UiHandler {
this.cursorObj.destroy();
this.cursorObj = null;
}
setVisible(){
this.typeIcon.setVisible(true);
this.ppLabel.setVisible(true);
this.ppText.setVisible(true);
this.powerLabel.setVisible(true);
this.powerText.setVisible(true);
this.moveCategoryIcon.setVisible(true);
}
updateMovesWindowContainer(actingPokemon:Pokemon,m:integer){
const pokemonMove = actingPokemon.getMoveset()[m];
this.typeIcon.setTexture('types', Type[pokemonMove.getMove().type].toLowerCase()).setScale(0.8);
this.moveCategoryIcon.setTexture('categories', MoveCategory[pokemonMove.getMove().category].toLowerCase()).setScale(1.0);
const power = pokemonMove.getMove().power;
const maxPP = pokemonMove.getMovePp();
const pp = maxPP - pokemonMove.ppUsed;
this.ppText.setText(`${Utils.padInt(pp, 2, ' ')}/${Utils.padInt(maxPP, 2, ' ')}`);
this.powerText.setText(`${power >= 0 ? power : '---'}`);
}
}

View File

@ -5,24 +5,37 @@ import { Mode } from "./ui";
import UiHandler from "./ui-handler";
import * as Utils from "../utils";
import { getMoveTargets } from "../data/move";
import FightUiHandler from "./fight-ui-handler";
import { CommandPhase } from "../phases.js";
import Pokemon from "../field/pokemon.js";
export type TargetSelectCallback = (cursor: integer) => void;
export default class TargetSelectUiHandler extends UiHandler {
private fieldIndex: integer;
private move: Moves;
private targetSelectCallback: TargetSelectCallback;
private fightUiHandler: FightUiHandler;
private cursorObj: Phaser.GameObjects.Image;
protected fieldIndex: integer;
protected cursor2: integer;
private targets: BattlerIndex[];
private targetFlashTween: Phaser.Tweens.Tween;
constructor(scene: BattleScene) {
super(scene, Mode.TARGET_SELECT);
this.cursor = -1;
}
setup(): void { }
setup(): void {
const ui = this.getUi();
if (!this.cursorObj) {
this.cursorObj = this.scene.add.image(0, 0, 'cursor');
this.cursorObj.setVisible(false)
ui.add(this.cursorObj);
}
}
show(args: any[]): boolean {
if (args.length < 3)
@ -32,18 +45,48 @@ export default class TargetSelectUiHandler extends UiHandler {
this.fieldIndex = args[0] as integer;
this.move = args[1] as Moves;
this.targetSelectCallback = args[2] as TargetSelectCallback;
this.targetSelectCallback = args[2];
if (this.scene.newEncounter===true){
this.cursor=-1
}
this.targets = getMoveTargets(this.scene.getPlayerField()[this.fieldIndex], this.move).targets;
const messageHandler = this.getUi().getMessageHandler();
messageHandler.movesWindowContainer.setVisible(true);
this.fightUiHandler = this.getUi().getFightUiHandler();
this.fightUiHandler.setVisible();
this.displayCursor()
if (!this.targets.length)
return false;
this.setCursor(this.targets.indexOf(this.cursor) > -1 ? this.cursor : this.targets[0]);
const target = this.scene.getField()[this.cursor]
this.showTargetEffectiveness(target);
return true;
}
showTargetEffectiveness(target:Pokemon){
const fieldPokemon = this.scene.getField();
// Create a mapping from Pokemon name to action
const actionMap = fieldPokemon.reduce((map, pokemon, index) => {
map[pokemon.name] = () => {
this.clearMoves();
this.scene.selectedTarget = fieldPokemon[index];
this.fightUiHandler.displayMoves(fieldPokemon[index], this.move);
};
return map;
}, {});
if (actionMap[target.name]) {
actionMap[target.name]();
}
}
processInput(button: Button): boolean {
const ui = this.getUi();
@ -92,6 +135,7 @@ export default class TargetSelectUiHandler extends UiHandler {
}
const target = this.scene.getField()[cursor];
this.showTargetEffectiveness(target);
this.targetFlashTween = this.scene.tweens.add({
targets: [ target ],
@ -122,5 +166,24 @@ export default class TargetSelectUiHandler extends UiHandler {
clear() {
super.clear();
this.eraseCursor();
this.clearMoves();
this.fightUiHandler.clear()
this.cursorObj.setVisible(false)
}
displayCursor() {
const moveset = (this.scene.getCurrentPhase() as CommandPhase).getPokemon().getMoveset();
for (let m = 0; m < moveset.length; m++) {
const pokemonMove = moveset[m];
if (pokemonMove.moveId===this.move) {
this.cursorObj.setPosition(13 + (m % 2 === 1 ? 100 : 0), -31 + (m >= 2 ? 15 : 0));
this.cursorObj.setVisible(true)
}
}
}
clearMoves() {
this.fightUiHandler.clearMoves()
}
}

View File

@ -23,7 +23,12 @@ export enum TextStyle {
SETTINGS_LABEL,
SETTINGS_SELECTED,
TOOLTIP_TITLE,
TOOLTIP_CONTENT
TOOLTIP_CONTENT,
ZERO_X_EFFECT,
FOUR_X_EFFECT,
TWO_X_EFFECT,
HALF_X_EFFECT,
QUARTER_X_EFFECT
};
export function addTextObject(scene: Phaser.Scene, x: number, y: number, content: string, style: TextStyle, extraStyleOptions?: Phaser.Types.GameObjects.Text.TextStyle): Phaser.GameObjects.Text {
@ -164,6 +169,17 @@ export function getTextColor(textStyle: TextStyle, shadow?: boolean, uiTheme: Ui
return !shadow ? '#f8b050' : '#c07800';
case TextStyle.SETTINGS_SELECTED:
return !shadow ? '#f88880' : '#f83018';
case TextStyle.ZERO_X_EFFECT:
return !shadow ? '#a0a0a0' : '#6b5a73';
case TextStyle.FOUR_X_EFFECT:
return !shadow ? '#2ecc71' : '#6b5a73';
case TextStyle.TWO_X_EFFECT:
return !shadow ? '#229954' : '#6b5a73';
case TextStyle.HALF_X_EFFECT:
return !shadow ? '#922b21' : '#6b5a73';
case TextStyle.QUARTER_X_EFFECT:
return !shadow ? '#e74c3c' : '#6b5a73';
}
}

View File

@ -198,6 +198,10 @@ export default class UI extends Phaser.GameObjects.Container {
return this.handlers[Mode.MESSAGE] as BattleMessageUiHandler;
}
getFightUiHandler(): FightUiHandler {
return this.handlers[Mode.FIGHT] as FightUiHandler;
}
processInput(button: Button): boolean {
if (this.overlayActive)
return false;