exploring/fighting is functional
[sketchy-heroes.git] / src / public / app / api.ts
index cccdbe26c736b04249bed38ea1e9893ed181a30f..25b1a3262b4beab5869b9442a52dcd79eac28ffc 100644 (file)
@@ -1,8 +1,9 @@
 import {Player} from '@prisma/client';
 import axios from 'axios';
 import { Events } from './events';
-import { LoginOutputType, AccountCreateType, MoveOutputType } from 'src/routes';
+import { LoginOutputType, AccountCreateType, MoveOutputType, FightStartType, FightRoundOutput } from 'src/routes';
 import {actionLog} from './components';
+import {$fightButton} from './dom';
 
 type ApiResponse<T> = {
   status: 'ok' | 'error',
@@ -29,6 +30,11 @@ export class Api extends Events {
     this.player = null;
   }
 
+  setPlayer(player: Player) {
+    this.player = player;
+    this.emit('player', player);
+  }
+
 
   async get<T>(endpoint: string, params: Record<string, string> = {}): Promise<ApiResponse<T>> {
     const res = await axios({
@@ -72,6 +78,24 @@ export class Api extends Events {
     return res.payload;
   }
 
+  async setGameTime(gameTime: number) {
+    const str = gameTime < 10 ? `0${gameTime}` : gameTime.toString();
+
+    $('body').removeClass().addClass(`sky-gradient-${str}`);
+  }
+
+  async getPlayerInfo() {
+    if(!this.player) {
+      throw new Error('Not authenticated');
+    }
+    const res = await this.get<Player>(`/v1/accounts/${this.player.id}`);
+
+    this.setPlayer(res.payload);
+
+    // this also sets the background based on the time!
+    this.setGameTime(res.meta.gameTime);
+  }
+
   async login(username: string, password: string): Promise<LoginOutputType> {
     const res = await this.post<LoginOutputType>('/v1/accounts/auth', { 
       username: username,
@@ -79,9 +103,13 @@ export class Api extends Events {
     });
 
     this.headers['x-auth-token'] = res.payload.token;
-    this.player = res.payload.player;
 
-    this.emit('player', this.player);
+    this.setPlayer(res.payload.player);
+
+    this.setGameTime(res.meta.gameTime);
+    
+
+    setInterval(this.getPlayerInfo.bind(this), 5000);
 
     return res.payload;
   }
@@ -92,12 +120,106 @@ export class Api extends Events {
     }
     const res = await this.post<MoveOutputType>(`/v1/accounts/${this.player.id}/move`);
 
-    this.player = res.payload.player;
+    this.setPlayer(res.payload.player);
+
+    if(res.payload.generatedMonster !== null) {
+      actionLog(`You see a ${res.payload.generatedMonster.name}`);
+      if(this.player.hp > 0 && this.player.stamina > 0) {
+        $fightButton().prop('disabled', false)
+                      .removeClass(['disabled', 'hidden'])
+                      .attr('data-fight-id', res.payload.generatedMonster.id);
+      }
+    }
+    else {
+      actionLog(res.payload.displayText, true);
+      $fightButton().prop('disabled', true)
+                    .addClass(['disabled', 'hidden'])
+                    .attr('data-fight-id', 'unset');
+    }
 
-    this.emit('player', this.player);
+    return res.payload;
+  }
 
-    actionLog(res.payload.displayText, true);
+  async increaseStat(stat: string): Promise<Player> {
+    if(this.player === null) {
+      throw new Error('Not authenticated');
+    }
+    const res = await this.post<Player>(`/v1/accounts/${this.player.id}/stat`, {
+      stat: stat
+    });
 
+    this.setPlayer(res.payload);
     return res.payload;
   }
+
+  async startFight(fightId: string): Promise<FightStartType> {
+    if(this.player === null) {
+      throw new Error('Not authenticated');
+    }
+
+    const res = await this.post<FightStartType>(`/v1/accounts/${this.player.id}/fight/${fightId}`);
+
+    if(!res.payload.id) {
+      throw new Error('Invalid fight!');
+    }
+
+    return res.payload;
+  }
+
+  async fight(fightId: string): Promise<FightRoundOutput> {
+    if(this.player === null) {
+      throw new Error('Not authenticated');
+    }
+
+    await this.startFight(fightId);
+
+    const res = await this.post<FightRoundOutput>(`/v1/accounts/${this.player.id}/fight/${fightId}/round`, {
+      action: 'Fight'
+    });
+
+    const output = res.payload;
+
+    this.setPlayer(output.player);
+
+    console.log(output);
+
+    const participants = {
+      [output.player.id]: output.player.username,
+      [output.monster.id]: output.monster.name
+    }
+
+    output.roundData.map(round => {
+      const p1 = participants[round.attacker];
+      const p2 = participants[round.defender];
+
+      const css = round.attacker === output.player.id ? 'text-secondary' : 'text-info';
+      let str = `<span class="${css}">${p1}</span> dealt <span class="text-danger">${round.damage} damage</span> to ${p2}`;
+
+      return str;
+    }).forEach(a => actionLog(a, false));
+
+    if(output.winner === 'player') {
+      actionLog(`<span class="text-success">You defeated the ${output.monster.name}</span>`, false);
+    }
+    else {
+      actionLog(`<span class="text-danger">You were defeated by the ${output.monster.name}</span>`, false);
+    }
+
+    Object.keys(output.reward).forEach(rewardType => {
+      switch(rewardType) {
+        case 'exp':
+          actionLog(`You gained <span class="text-info">${output.reward.exp}</span> Exp`, false);
+          break;
+        case 'currency':
+          actionLog(`You gained <span class="text-warning">${output.reward.currency}</span> Steel`, false);
+          break;
+      }
+    });
+
+    $fightButton().prop('disabled', true)
+                  .addClass(['disabled', 'hidden'])
+                  .attr('data-fight-id', 'unset');
+
+    return output;
+  }
 }