exploring/fighting is functional
[sketchy-heroes.git] / src / routes / fight / fight.ts
diff --git a/src/routes/fight/fight.ts b/src/routes/fight/fight.ts
new file mode 100644 (file)
index 0000000..8c3ca0b
--- /dev/null
@@ -0,0 +1,208 @@
+import { server } from '../../lib/server';
+import { Static, Type } from '@sinclair/typebox';
+import { prisma } from '../../lib/db';
+import { ForbiddenError } from '../../lib/http-errors';
+import {Fight, Player} from '@prisma/client';
+import {maxExp, maxHp} from '../../formulas';
+
+
+const FightRoundInput = Type.Object({
+  params: Type.Object({
+    playerId: Type.String(),
+    fightId: Type.String()
+  }),
+  body: Type.Object({
+    action: Type.String()
+  })
+});
+
+type FightRoundInputType = Static<typeof FightRoundInput>;
+
+export type RoundData = {
+  attacker: string;
+  defender: string;
+  damage: number;
+}
+
+export type FightRoundOutput = {
+  player: Player,
+  monster: Fight,
+  winner: 'monster' | 'player' | 'flee',
+  roundData: RoundData[],
+  reward: any
+}
+
+function round(player: Player, monster: Fight): FightRoundOutput {
+
+  const roundData: RoundData[] = [];
+  if(player.stamina <= 0 || player.hp <= 0) {
+    return {
+      player: player,
+      monster: monster,
+      winner: 'monster',
+      roundData: roundData,
+      reward: {}
+    };
+  }
+
+  const first = player.woosh >= monster.woosh ? player : monster;
+  const second = player.woosh >= monster.woosh ? monster : player;
+
+
+  while(first.hp > 0 && second.hp > 0) {
+    // eventually these will include weapon and skill damage
+    const firstDamage = first.pow;
+    const secondDamage = second.pow;
+
+    second.hp -= firstDamage;
+    roundData.push({
+      attacker: first.id,
+      defender: second.id,
+      damage: firstDamage
+    });
+
+    if(second.hp > 0) {
+      first.hp -= secondDamage;
+      roundData.push({
+        attacker: second.id,
+        defender: first.id,
+        damage: secondDamage
+      })
+    }
+  }
+
+
+  // now we figure out who won!
+  if(player.hp <= 0) {
+    // the player lost
+    player.hp = 0;
+
+    return {
+      player: player,
+      monster: monster,
+      winner: 'monster',
+      roundData: roundData,
+      reward: {}
+    }
+  }
+  else {
+    return {
+      player: player,
+      monster: monster,
+      winner: 'player',
+      roundData: roundData,
+      reward: {
+        exp: monster.exp,
+        currency: monster.currency
+      }
+    }
+  }
+
+}
+
+export const fightRound = server.post<FightRoundInputType, FightRoundOutput>('/v1/accounts/:playerId/fight/:fightId/round', {
+  schema: FightRoundInput,
+  authenicated: true
+}, async req => {
+
+  const [fight, player] = await prisma.$transaction([
+    prisma.fight.findUnique({
+      where: {
+        id: req.params.fightId
+      }
+    }),
+    prisma.player.findUnique({
+      where: {
+        id: req.params.playerId
+      }
+    })
+  ]);
+
+  if(!player) {
+    throw new ForbiddenError('Not a valid fight');
+  }
+
+  if(!fight) {
+    throw new ForbiddenError('Not a real fight');
+  }
+
+  if(fight.playerId !== req.params.playerId) {
+    throw new ForbiddenError('Not a real fight');
+  }
+
+  if(req.body.action === 'Flee') {
+    await prisma.fight.delete({
+      where: {
+        id: req.params.fightId
+      }
+    });
+
+    return {
+      player: player,
+      monster: fight,
+      winner: 'flee',
+      reward: {},
+      roundData: []
+    }
+  }
+
+  if(req.body.action === 'Fight') {
+      const output = round(player, fight);
+      if(output.winner === 'monster') {
+        await prisma.$transaction([
+          prisma.fight.delete({
+            where: {
+              id: fight.id
+            }
+          }),
+          prisma.player.update({
+            where: {
+              id: player.id
+            },
+            data: {
+              hp: 0
+            }
+          })
+        ]);
+      }
+      else if(output.winner === 'player') {
+        player.currency += fight.currency;
+        player.exp += fight.exp;
+        while(player.exp >= maxExp(player.level)) {
+          player.exp -= maxExp(player.level);
+          player.level++;
+          player.statPoints++;
+          player.hp = maxHp(player.level, player.zest);
+        }
+
+        await prisma.$transaction([
+          prisma.fight.delete({
+            where: {
+              id: fight.id
+            }
+          }),
+          prisma.player.update({
+            where: {
+              id: player.id
+            },
+            data: {
+              hp: player.hp,
+              exp: player.exp,
+              level: player.level,
+              currency: player.currency,
+              stamina: player.stamina--,
+              statPoints: player.statPoints
+            }
+          })
+        ]);
+
+        // update the player with the new data
+        output.player = player;
+      }
+
+      return output;
+  }
+
+  throw new ForbiddenError('You can not do that in a fight');
+
+});