summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/dist/assets/demo-videos/recording.mpgbin0 -> 18624512 bytes
-rw-r--r--client/dist/assets/pokemon/RGB_Red_Back.webpbin0 -> 242 bytes
-rw-r--r--client/dist/assets/pokemon/Spr_Y_Brock.webpbin0 -> 336 bytes
-rw-r--r--client/dist/assets/pokemon/opponentFront.pngbin0 -> 854 bytes
-rw-r--r--client/dist/assets/pokemon/playerBack.pngbin0 -> 651 bytes
-rw-r--r--client/src/akkamon/client/Client.ts4
-rw-r--r--client/src/akkamon/client/IncomingEvents.ts22
-rw-r--r--client/src/akkamon/render/BattleEngine.ts51
-rw-r--r--client/src/akkamon/render/battleUI.ts230
-rw-r--r--client/src/akkamon/scenes/BattleScene.ts71
-rw-r--r--client/src/akkamon/scenes/BootScene.ts4
-rw-r--r--client/src/akkamon/scenes/UIElement.ts9
-rw-r--r--domain/src/main/java/akkamon/domain/model/akkamon/MonStats.java30
-rw-r--r--domain/src/main/java/akkamon/domain/model/akkamon/Stat.java11
14 files changed, 378 insertions, 54 deletions
diff --git a/client/dist/assets/demo-videos/recording.mpg b/client/dist/assets/demo-videos/recording.mpg
new file mode 100644
index 0000000..6f3f5ad
--- /dev/null
+++ b/client/dist/assets/demo-videos/recording.mpg
Binary files differ
diff --git a/client/dist/assets/pokemon/RGB_Red_Back.webp b/client/dist/assets/pokemon/RGB_Red_Back.webp
new file mode 100644
index 0000000..fcf0ecd
--- /dev/null
+++ b/client/dist/assets/pokemon/RGB_Red_Back.webp
Binary files differ
diff --git a/client/dist/assets/pokemon/Spr_Y_Brock.webp b/client/dist/assets/pokemon/Spr_Y_Brock.webp
new file mode 100644
index 0000000..f12b6a5
--- /dev/null
+++ b/client/dist/assets/pokemon/Spr_Y_Brock.webp
Binary files differ
diff --git a/client/dist/assets/pokemon/opponentFront.png b/client/dist/assets/pokemon/opponentFront.png
new file mode 100644
index 0000000..2e2fda3
--- /dev/null
+++ b/client/dist/assets/pokemon/opponentFront.png
Binary files differ
diff --git a/client/dist/assets/pokemon/playerBack.png b/client/dist/assets/pokemon/playerBack.png
new file mode 100644
index 0000000..b76851c
--- /dev/null
+++ b/client/dist/assets/pokemon/playerBack.png
Binary files differ
diff --git a/client/src/akkamon/client/Client.ts b/client/src/akkamon/client/Client.ts
index 3d44dd5..c6b0f24 100644
--- a/client/src/akkamon/client/Client.ts
+++ b/client/src/akkamon/client/Client.ts
@@ -172,6 +172,10 @@ export class Client implements AkkamonClient
this.scene = scene;
+ if (this.BattleEngine) {
+ this.BattleEngine = undefined;
+ }
+
let playerSprite = new PlayerSprite({
scene: scene,
tilePos: new Phaser.Math.Vector2(scene.spawnPointTilePos!),
diff --git a/client/src/akkamon/client/IncomingEvents.ts b/client/src/akkamon/client/IncomingEvents.ts
index bc2c731..aa515f0 100644
--- a/client/src/akkamon/client/IncomingEvents.ts
+++ b/client/src/akkamon/client/IncomingEvents.ts
@@ -23,17 +23,23 @@ export type BattleState = {
}
}
+export type Stat = {
+ base: number,
+ effective: number
+}
+
export type Mon = {
name: string,
stats: {
- HP: number,
- Attack: number,
- Defence: number,
- SpecialAttack: number,
- SpecialDefence: number,
- Speed: number,
- accuracy: number,
- evasion: number,
+ level: number,
+ HP: Stat,
+ Attack: Stat,
+ Defence: Stat,
+ SpecialAttack: Stat,
+ SpecialDefence: Stat,
+ Speed: Stat,
+ accuracy: Stat,
+ evasion: Stat,
},
status: {}
}
diff --git a/client/src/akkamon/render/BattleEngine.ts b/client/src/akkamon/render/BattleEngine.ts
index f775046..a6524c4 100644
--- a/client/src/akkamon/render/BattleEngine.ts
+++ b/client/src/akkamon/render/BattleEngine.ts
@@ -9,6 +9,13 @@ import {
import { client } from '../../app';
+function delay(ms: number) {
+ return new Promise(resolve => {
+ setTimeout(resolve, ms);
+ });
+}
+
+
export enum BattleEventType {
INTRODUCTION = "INTRODUCTION"
}
@@ -38,12 +45,19 @@ export class BattleEngine extends AkkamonEngine {
private uiEventTriggers = baseQueue<() => void>();
+ private playerName: string
+ private opponentName: string
+
constructor(
message: BattleMessage,
) {
super();
this.state = message.state;
this.eventsToPlay.pushArray(message.eventsToPlay);
+
+ this.playerName = client.getTrainerID()!.id;
+ this.opponentName = this.getOpponentName();
+
}
getOpponentName(): string {
@@ -78,20 +92,35 @@ export class BattleEngine extends AkkamonEngine {
[BattleEventType.INTRODUCTION](eventToPlay: BattleEvent) {
let scene = this.scene!;
- let opponentName = this.getOpponentName();
-
// scene.showPlayerSprites();
scene.pushEvents(
- [
- new DialogueUIEvent(opponentName + " wants to fight!", () => {scene.busy = false;}),
- new DialogueUIEvent(opponentName + " sent out " + this.state.teams[opponentName].activeMon.name + "!", () => {scene.busy = false;})
- ],
- () => {
- scene.pushMenu(new BattleOptions(
- scene
- ));
- });
+ [
+ new DialogueUIEvent(this.opponentName + " wants to fight!", async () => {
+ scene.removePlayerSprites();
+ scene.busy = false;
+ }),
+ new DialogueUIEvent(this.opponentName + " sent out " + this.state.teams[this.opponentName].activeMon.name + "!", async () => {
+ scene.showOpponentMonInterface(this.opponentName, this.state.teams[this.opponentName].activeMon);
+ scene.busy = false;
+ }),
+ new DialogueUIEvent("Go! " + this.state.teams[this.playerName].activeMon.name + "!", async () => {
+ scene.showPlayerMonInterface(this.playerName, this.state.teams[this.playerName].activeMon);
+ scene.busy = false;
+ }),
+ ],
+ () => {
+ scene.clearDialogue();
+ scene.pushMenu(new BattleOptions(
+ scene
+ ));
+ },
+ new InstantUIEvent(async () => {
+ scene.showPlayerSpritesAndBalls();
+ await delay(1000);
+ scene.busy = false;
+ })
+ );
}
diff --git a/client/src/akkamon/render/battleUI.ts b/client/src/akkamon/render/battleUI.ts
index bc5d876..2f204e3 100644
--- a/client/src/akkamon/render/battleUI.ts
+++ b/client/src/akkamon/render/battleUI.ts
@@ -1,3 +1,4 @@
+import type { Mon, Stat } from "../client/IncomingEvents";
import { baseQueue, Queue } from "../DataWrappers";
import type BattleScene from "../scenes/BattleScene";
import { AkkamonMenu, Dialogue, MenuText, Picker } from "../scenes/UIElement";
@@ -38,10 +39,11 @@ export class BattleDialogue extends Dialogue {
this.confirmNextBehavior();
} else {
console.log("currentlyWriting removing timed printer!");
+ this.timeEvent!.destroy();
this.timeEvent!.remove();
+ this.timeCallback!();
this.displayedText.text = this.currentlyWriting!;
this.currentlyWriting = undefined;
- this.timeCallback!();
}
}
@@ -55,35 +57,46 @@ export class BattleDialogue extends Dialogue {
this.endBehaviour();
} else {
console.log("Pushing ui trigger to client update handling!");
- let trigger = () => {
- console.log("The trigger is fired!");
- this.playNextEvent();
- }
- console.log(trigger);
+ this.pushTriggerWhenNotBusy(() => { this.playNextEvent(); });
+ }
+ }
- // this.scene!.pushMen this.playNextEvent();
- this.battleScene!.pushUIEvent(
- trigger
- );
+ pushTriggerWhenNotBusy(trigger: () => void) {
+ // let trigger = () => {
+ // console.log("The trigger is fired!");
+ // callback();
+ // }
+ // console.log(trigger);
- }
+ // this.scene!.pushMen this.playNextEvent();
+ this.battleScene!.pushUIEvent(
+ trigger
+ );
}
pushEvents(events: DialogueUIEvent[], endBehaviour: () => void) {
this.endBehaviour = endBehaviour;
this.eventQueue.pushArray(events);
- this.playNextEvent();
+ this.pushTriggerWhenNotBusy(() => { this.playNextEvent(); } );
}
playNextEvent() {
+ this.battleScene.busy = true;
this.displayedText.text = '';
if (!this.eventQueue.isEmpty()) {
let uiEvent = this.eventQueue.pop()!;
- this.timeEvent = this.typewriteText(uiEvent.dialogue, uiEvent.callback);
+ console.log("Playing event now:");
+ console.log(uiEvent);
+ this.timeEvent = this.typewriteText(uiEvent.dialogue, uiEvent.callback, () => {this.currentlyWriting = undefined;});
this.timeCallback = uiEvent.callback;
+ this.currentlyWriting = uiEvent.dialogue;
}
}
+ clearText() {
+ this.displayedText.text = '';
+ }
+
}
enum BattleOptionsButtons {
@@ -118,7 +131,7 @@ export class BattleOptions extends Phaser.GameObjects.Image implements AkkamonMe
this.paddingX = 120;
this.paddingY = 60;
- this.buttonSpacing = 30;
+ this.buttonSpacing = 45;
this.battleScene = scene;
this.group = new Phaser.GameObjects.Group(scene);
@@ -285,3 +298,192 @@ export class BattleOptions extends Phaser.GameObjects.Image implements AkkamonMe
setMenuVisible() {
}
}
+
+class HPBar extends Phaser.GameObjects.Rectangle {
+ constructor(
+ scene: BattleScene,
+ group: Phaser.GameObjects.Group,
+ groupDepth: number,
+ pos: {x: number, y: number},
+ size: {width: number, height: number},
+ ori: {x: number, y: number},
+ ) {
+ super(scene, pos.x, pos.y, size.width, size.height, 0x00ff00);
+ this.setOrigin(ori.x, ori.y);
+ scene.add.existing(this);
+ group.add(this);
+ this.setDepth(groupDepth);
+ }
+
+ setHP(hp: Stat) {
+ }
+}
+
+export class MonInterface extends Phaser.GameObjects.Image {
+
+ battleScene: BattleScene;
+ group: Phaser.GameObjects.Group;
+ groupDepth: number;
+
+ mon: Mon
+
+ monName?: MenuText;
+ level?: MenuText;
+
+ hpBar?: HPBar;
+ baseHP?: MenuText;
+ effectiveHP?: MenuText;
+
+ constructor(
+ scene: BattleScene,
+ mon: Mon,
+ imageKey: string,
+ pos: {x: number, y: number},
+ ori: {x: number, y: number},
+ aspect: number
+ ) {
+ super(
+ scene,
+ pos.x,pos.y,
+ imageKey
+ );
+ let width = scene.cameras.main.displayWidth / 2.2;
+ this.setDisplaySize(width, aspect * width);
+ this.setOrigin(ori.x, ori.y);
+ scene.add.existing(this);
+ this.group = new Phaser.GameObjects.Group(scene);
+ this.groupDepth = 10;
+ this.group.setDepth(this.groupDepth);
+ this.battleScene = scene;
+
+ this.mon = mon;
+ }
+
+}
+
+export class PlayerInterface extends MonInterface {
+ constructor(scene: BattleScene,
+ mon: Mon,
+ imageKey: string,
+ pos: {x: number, y: number},
+ ori: {x: number, y: number},
+ aspect: number) {
+ super(scene, mon, imageKey, pos, ori, aspect);
+ this.setMonName(mon.name);
+ this.setLevel(mon.stats.level);
+ this.setHP(mon.stats.HP);
+ this.setSprite(mon.name);
+ }
+
+ setSprite(name: string) {
+ console.log("Setting back sprite for " + name);
+ let image = this.scene.add.image(this.x - this.displayWidth - 200, this.y, name.toLowerCase() + "-back")
+ .setDisplaySize(200,200)
+ .setOrigin(0.5, 0.5)
+
+ this.group.add(image);
+ }
+
+ setMonName(name: string) {
+ this.monName = new MenuText(
+ this.battleScene,
+ this.group,
+ this.groupDepth,
+ this.x - this.displayWidth + 20, this.y - this.displayHeight / 2 - 20,
+ name
+ );
+ }
+
+ setLevel(level: number) {
+ this.level = new MenuText(
+ this.battleScene,
+ this.group,
+ this.groupDepth,
+ this.x - this.displayWidth * (1 - 490 / 790), this.y - this.displayHeight / 2,
+ level.toString()
+ );
+ }
+
+ setHP(hp: Stat) {
+ this.baseHP = new MenuText(
+ this.battleScene,
+ this.group,
+ this.groupDepth,
+ this.x - this.displayWidth * (1 - 500 / 790), this.y + this.displayHeight * ((220 - 178) / 314),
+ hp.base.toString()
+ );
+
+ this.effectiveHP = new MenuText(
+ this.battleScene,
+ this.group,
+ this.groupDepth,
+ this.x - this.displayWidth * (1 - 320 / 790), this.y + this.displayHeight * ((220 - 178) / 314),
+ hp.base.toString()
+ );
+
+ this.hpBar = new HPBar(
+ this.battleScene,
+ this.group,
+ this.groupDepth,
+ {x: this.x - this.displayWidth * (1 - 245 / 790), y: this.y - this.displayHeight / 2 * (103 / 314)},
+ {width: this.displayWidth * ((731 - 237) / 790), height: this.displayHeight * ((129 - 105) / 314)},
+ {x: 0, y: 0}
+ );
+ }
+}
+
+export class OpponentInterface extends MonInterface {
+ constructor(scene: BattleScene,
+ mon: Mon,
+ imageKey: string,
+ pos: {x: number, y: number},
+ ori: {x: number, y: number},
+ aspect: number) {
+ super(scene, mon, imageKey, pos, ori, aspect);
+ this.setMonName(mon.name);
+ this.setLevel(mon.stats.level);
+ this.setHP(mon.stats.HP);
+ this.setSprite(mon.name);
+ }
+
+ setSprite(name: string) {
+ console.log("Setting front sprite for " + name);
+ let image = this.scene.add.image(this.x + this.displayWidth + 200, this.y + this.displayHeight / 2 + 60, name.toLowerCase() + "-front")
+ .setDisplaySize(200,200)
+ .setOrigin(0.5, 0.5)
+
+ this.group.add(image);
+ }
+
+ setMonName(name: string) {
+ this.monName = new MenuText(
+ this.battleScene,
+ this.group,
+ this.groupDepth,
+ this.x + 10, this.y - 20,
+ name
+ );
+ }
+
+ setLevel(level: number) {
+ this.level = new MenuText(
+ this.battleScene,
+ this.group,
+ this.groupDepth,
+ this.x + this.displayWidth * (289 / 788), this.y + this.displayHeight * (24 / 223) - 10,
+ level.toString()
+ );
+ }
+
+ setHP(hp: Stat) {
+ this.hpBar = new HPBar(
+ this.battleScene,
+ this.group,
+ this.groupDepth,
+ {x: this.x + this.displayWidth * (217 / 788), y: this.y + this.displayHeight * (106 / 223)},
+ {width: this.displayWidth * ((705.14 - 215.66) / 788), height: this.displayHeight * ((130.5 - 104.2) / 223)},
+ {x: 0, y: 0}
+ );
+ }
+
+}
diff --git a/client/src/akkamon/scenes/BattleScene.ts b/client/src/akkamon/scenes/BattleScene.ts
index c2746d8..8ff430f 100644
--- a/client/src/akkamon/scenes/BattleScene.ts
+++ b/client/src/akkamon/scenes/BattleScene.ts
@@ -1,8 +1,9 @@
import { client } from '../../app';
+import type { Mon } from '../client/IncomingEvents';
import { baseStack, Queue, queueFromArray } from '../DataWrappers';
import type { BasePhaserScene, GConstructor } from '../PhaserTypes';
-import type { BattleUIEvent, DialogueUIEvent } from '../render/BattleEngine';
-import { BattleDialogue } from '../render/battleUI';
+import type { BattleUIEvent, DialogueUIEvent, InstantUIEvent } from '../render/BattleEngine';
+import { BattleDialogue, MonInterface, OpponentInterface, PlayerInterface } from '../render/battleUI';
import { Direction } from '../render/Direction';
import type { AkkamonMenu, Dialogue, Menu, MenuText, Picker } from './UIElement';
import type { WorldScene } from './WorldScene';
@@ -14,6 +15,9 @@ export default class BattleScene extends Phaser.Scene {
dialogueBox?: BattleDialogue;
busy = false;
+ playerSprites: Phaser.GameObjects.Image[] = [];
+ monInterfaces: Map<string, MonInterface> = new Map();
+
constructor() {
super('BattleScene')
}
@@ -61,10 +65,12 @@ export default class BattleScene extends Phaser.Scene {
client.setBattleControls(input, menu);
}
- pushEvents(events: DialogueUIEvent[], endBehavior: () => void, before?: BattleUIEvent) {
+ pushEvents(events: DialogueUIEvent[], endBehavior: () => void, before?: InstantUIEvent) {
this.toggleVisible(false);
this.menuTakesUIControl(this.input, this.dialogueBox!);
if (before) {
+ this.busy = true;
+ before.callback();
}
this.dialogueBox!.pushEvents(
events,
@@ -85,4 +91,63 @@ export default class BattleScene extends Phaser.Scene {
isBusy() {
return this.busy;
}
+
+ showPlayerSpritesAndBalls() {
+ this.showPlayerSprites();
+ this.showBalls();
+ }
+
+ showPlayerSprites() {
+ let playerBack = this.add.image(0,0, "playerBack")
+ .setOrigin(0, 1)
+ .setPosition(0 + 100, (1 - 0.28) * this.cameras.main.displayHeight - 20)
+ .setDisplaySize(200, 200)
+
+ let opponentFront = this.add.image(0,0, "opponentFront")
+ .setOrigin(1, 0.5)
+ .setPosition(this.cameras.main.displayWidth - 100, 150)
+ .setDisplaySize(200, 200)
+
+ this.playerSprites.push(playerBack);
+ this.playerSprites.push(opponentFront);
+ }
+
+ showBalls() {
+
+ }
+
+ removePlayerSprites() {
+ for (let sprite of this.playerSprites) {
+ sprite.destroy();
+ }
+ }
+
+ showPlayerMonInterface(trainer: string, monObj: Mon) {
+ this.monInterfaces.set(trainer,
+ new PlayerInterface(
+ this,
+ monObj,
+ "hp-player",
+ {x: this.cameras.main.displayWidth - 20, y: (1 - 0.28) * this.cameras.main.displayHeight - 400 * 0.4 / 1.5},
+ {x: 1, y: 0.5},
+ 0.4
+ ));
+ }
+
+ showOpponentMonInterface(trainer: string, monObj: Mon) {
+ this.monInterfaces.set(trainer,
+ new OpponentInterface(
+ this,
+ monObj,
+ "hp-opponent",
+ {x: 30, y: 30},
+ {x: 0, y: 0},
+ 0.28
+ ));
+
+ }
+
+ clearDialogue() {
+ this.dialogueBox!.clearText();
+ }
}
diff --git a/client/src/akkamon/scenes/BootScene.ts b/client/src/akkamon/scenes/BootScene.ts
index d3d8dba..98be8b6 100644
--- a/client/src/akkamon/scenes/BootScene.ts
+++ b/client/src/akkamon/scenes/BootScene.ts
@@ -31,6 +31,10 @@ function createBootScene<PhaserScene extends BasePhaserScene>(base: PhaserScene,
this.load.pack("general-interface", "assets/images/general-ui.json")
this.load.pack("battle-interface", "assets/images/battle-ui.json")
+
+ this.load.image("playerBack", "assets/pokemon/playerBack.png")
+ this.load.image("opponentFront", "assets/pokemon/opponentFront.png")
+
}
create(): void {
diff --git a/client/src/akkamon/scenes/UIElement.ts b/client/src/akkamon/scenes/UIElement.ts
index 104bb7c..d9447f7 100644
--- a/client/src/akkamon/scenes/UIElement.ts
+++ b/client/src/akkamon/scenes/UIElement.ts
@@ -435,20 +435,21 @@ export class Dialogue extends Phaser.GameObjects.Image implements AkkamonMenu {
}
}
- typewriteText(text: string, uiEventCallback?: () => void) {
+ typewriteText(text: string, uiEventCallback?: () => void, endDialogueCallback?: () => void) {
const length = text.length
let i = 0
- if (uiEventCallback) {
+ if (uiEventCallback && endDialogueCallback) {
let timeEvent = this.scene.time.addEvent({
callback: () => {
this.displayedText.text += text[i]
++i
if (i === length - 1) {
uiEventCallback();
+ endDialogueCallback();
}
},
repeat: length - 1,
- delay: 20
+ delay: 50
})
return timeEvent;
} else {
@@ -458,7 +459,7 @@ export class Dialogue extends Phaser.GameObjects.Image implements AkkamonMenu {
++i
},
repeat: length - 1,
- delay: 20
+ delay: 50
})
return timeEvent;
}
diff --git a/domain/src/main/java/akkamon/domain/model/akkamon/MonStats.java b/domain/src/main/java/akkamon/domain/model/akkamon/MonStats.java
index ee4eee3..2e8ab68 100644
--- a/domain/src/main/java/akkamon/domain/model/akkamon/MonStats.java
+++ b/domain/src/main/java/akkamon/domain/model/akkamon/MonStats.java
@@ -1,22 +1,24 @@
package akkamon.domain.model.akkamon;
public class MonStats {
- public final int HP;
- public final int Attack;
- public final int Defence;
- public final int SpecialAttack;
- public final int SpecialDefence;
- public final int Speed;
- public final int accuracy = 1;
- public final int evasion = 1;
+ public final int level;
+ public final Stat HP;
+ public final Stat Attack;
+ public final Stat Defence;
+ public final Stat SpecialAttack;
+ public final Stat SpecialDefence;
+ public final Stat Speed;
+ public final Stat accuracy = new Stat(1);
+ public final Stat evasion = new Stat(1);
public MonStats(int[] base, int[] evs, int[] ivs, double[] natureMultiplier, int level) {
- this.HP = setHP(base[0], evs[0], ivs[0], level);
- this.Attack = setStat(base[1], evs[1], ivs[1], natureMultiplier[1], level);
- this.Defence = setStat(base[2], evs[2], ivs[2], natureMultiplier[2], level);
- this.SpecialAttack = setStat(base[3], evs[3], ivs[3], natureMultiplier[3], level);
- this.SpecialDefence = setStat(base[4], evs[4], ivs[4], natureMultiplier[4], level);
- this.Speed = setStat(base[5], evs[5], ivs[5], natureMultiplier[5], level);
+ this.level = level;
+ this.HP = new Stat(setHP(base[0], evs[0], ivs[0], level));
+ this.Attack = new Stat(setStat(base[1], evs[1], ivs[1], natureMultiplier[1], level));
+ this.Defence = new Stat(setStat(base[2], evs[2], ivs[2], natureMultiplier[2], level));
+ this.SpecialAttack = new Stat(setStat(base[3], evs[3], ivs[3], natureMultiplier[3], level));
+ this.SpecialDefence = new Stat(setStat(base[4], evs[4], ivs[4], natureMultiplier[4], level));
+ this.Speed = new Stat(setStat(base[5], evs[5], ivs[5], natureMultiplier[5], level));
}
private int setStat(int base, int ev, int iv, double nature, int level) {
diff --git a/domain/src/main/java/akkamon/domain/model/akkamon/Stat.java b/domain/src/main/java/akkamon/domain/model/akkamon/Stat.java
new file mode 100644
index 0000000..92bc76e
--- /dev/null
+++ b/domain/src/main/java/akkamon/domain/model/akkamon/Stat.java
@@ -0,0 +1,11 @@
+package akkamon.domain.model.akkamon;
+
+public class Stat {
+ public final int base;
+ public int effective;
+
+ public Stat(int base) {
+ this.base = base;
+ this.effective = base;
+ }
+}