feat: add class stats to professions
authorxangelo <me@xangelo.ca>
Tue, 12 Mar 2024 03:21:50 +0000 (23:21 -0400)
committerxangelo <me@xangelo.ca>
Tue, 12 Mar 2024 03:21:50 +0000 (23:21 -0400)
When you select a profession, there are a certain number of stats that
are considered "class stats". They may automatically increases on level
up.

For example:

Warrior class stats: Strength, Constitution.
On even level up, you gain +2 strength, +1 constitution
On odd level up, you gain +1 strength, +2 constitution

Class stats only cost a single stat point to increase, and non-class
stats cost 2 stat points.

You only ever gain 1 stat point on level up.

Wanderers are a special profession that do not gain any stats on level
up.. but all stats are considered "class stats"

src/server/fight.ts
src/server/routes/locations/recruiter.ts
src/server/routes/profile.ts
src/shared/profession.ts

index 4515c30b60edbd8890d9202ee69905b0995cdbb6..93e9b3c5e768b84e50ffb1c5ebe0e39eb12d99ee 100644 (file)
@@ -12,6 +12,7 @@ import { SkillID, Skills } from '../shared/skills';
 import { Request, Response } from 'express';
 import * as Alert from './views/alert';
 import { addEvent } from './events';
+import { Professions } from '../shared/profession';
 
 export async function blockPlayerInFight(req: Request, res: Response, next: any) {
   const fight = await loadMonsterFromFight(req.player.id);
@@ -186,10 +187,24 @@ export async function fightRound(player: Player, monster: Fight,  data: {action:
         to_level: player.level
       });
       roundData.rewards.levelIncrease = true;
-      let statPointsGained = 1;
-
-      if(player.profession !== 'Wanderer') {
-        statPointsGained = 2;
+      const statPointsGained = 1;
+      const prof = Professions.get(player.profession);
+
+      if(player.level%2) {
+        if(prof.levelUpStatIncrease.odd) {
+          for(let stat in prof.levelUpStatIncrease.odd) {
+            player[stat] += prof.levelUpStatIncrease.odd[stat];
+            roundData.roundDetails.push(`You gained +${prof.levelUpStatIncrease.odd[stat]} ${stat}`);
+          }
+        }
+      }
+      else {
+        if(prof.levelUpStatIncrease.even) {
+          for(let stat in prof.levelUpStatIncrease.even) {
+            player[stat] += prof.levelUpStatIncrease.even[stat];
+            roundData.roundDetails.push(`You gained +${prof.levelUpStatIncrease.even[stat]} ${stat}`);
+          }
+        }
       }
 
       player.stat_points += statPointsGained;
index 73a3c1a82df67201170a845fb1a3fa399d91b4bb..fd2c816916ddcd941620c8ae7b36ab4cea0ccd3a 100644 (file)
@@ -7,6 +7,7 @@ import { changeProfession } from "../../player";
 import { renderPlayerBar } from "../../views/player-bar";
 import { BackToTown } from "../../views/components/button";
 import { MIN_LEVEL_TO_CHANGE_PROFESSIONS } from "../../../shared/constants";
+import { Profession, Professions } from "../../../shared/profession";
 
 function p(str: string) {
   return `<p>${str}</p>`;
@@ -38,9 +39,9 @@ recruiterRouter.get('/city/services/profession_recruitor/:location_id', authEndp
       html.push(`
           <div>
           <form hx-post="/city/services/profession_change/${service.id}">
-          <button type="submit" value="warrior" name="profession">Become a Warrior</button>
-          <button type="submit" value="mage" name="profession">Become a Mage</button>
-          <button type="submit" value="rogue" name="profession">Become a Rogue</button>
+          <button type="submit" value="${Professions.get('Warrior').id}" name="profession">Become a Warrior</button>
+          <button type="submit" value="${Professions.get('Mage').id}" name="profession">Become a Mage</button>
+          <button type="submit" value="${Professions.get('Rogue')}" name="profession">Become a Rogue</button>
           </form>
           </div>
         `);
@@ -87,29 +88,19 @@ recruiterRouter.post('/city/services/profession_change/:location_id', authEndpoi
     res.sendStatus(400);
   }
 
-  let update: {level: number, exp: number};
+  const potentialProfession: Profession = req.body.profession;
 
-  switch(req.body.profession.toLowerCase()) {
-    case 'warrior':
-      update = await changeProfession(req.player.id, 'Warrior');
-      req.player.profession = 'Warrior';
-    break;
-    case 'mage':
-      update = await changeProfession(req.player.id, 'Mage');
-      req.player.profession = 'Mage';
-    break;
-    case 'rogue':
-      update = await changeProfession(req.player.id, 'Rogue');
-      req.player.profession = 'Rogue';
-    break;
-    default:
-      res.send(Alert.ErrorAlert(`Invalid profession`));
-    break;
+  if(!Professions.has(potentialProfession)) {
+    res.send(Alert.ErrorAlert(`Invalid profession`));
   }
+  else {
+    const prof = Professions.get(potentialProfession);
+    const update = await changeProfession(req.player.id, prof.id);
 
-  if(update) {
+    req.player.profession = prof.id;
     req.player.level = update.level;
     req.player.exp = update.exp;
+
     res.send(renderPlayerBar(req.player) + `<div id="recruiter-target" class="service-in-town" hx-swap-oob="true">Congrats! You are now a ${req.player.profession}</div>`);
   }
 
index da868644dfcfeb98b523182150508d73232fc8fa..79b0bd50cad62a4735be9ed139865dc8c7e36925 100644 (file)
@@ -6,6 +6,8 @@ import {maxHp, maxVigor } from '../../shared/player';
 import * as Alert from '../views/alert';
 import { renderPlayerBar } from '../views/player-bar'
 import { renderProfilePage } from '../views/profile';
+import { Professions } from '../../shared/profession';
+import { Stat } from '../../shared/stats';
 
 export const profileRouter = Router();
 
@@ -16,18 +18,26 @@ profileRouter.get('/player', authEndpoint, async (req: Request, res: Response) =
 
 profileRouter.post('/player/stat/:stat', authEndpoint, async (req: Request, res: Response) => {
   const equipment = await getEquippedItems(req.player.id);
-  const stat = req.params.stat;
+  const profession = Professions.get(req.player.profession);
+  const stat = req.params.stat as Stat;
+  let statIncreaseCost = 2;
   if(!['strength', 'constitution', 'dexterity', 'intelligence'].includes(stat)) {
     res.send(Alert.ErrorAlert(`Sorry, that's not a valid stat to increase`));
     return;
   }
 
-  if(req.player.stat_points <= 0) {
+
+  // class stats cost 1
+  if(profession.classStats.includes(stat)) {
+    statIncreaseCost = 1;
+  }
+
+  if(req.player.stat_points < statIncreaseCost) {
     res.send(Alert.ErrorAlert(`Sorry, you don't have enough stat points`));
     return;
   }
 
-  req.player.stat_points -= 1;
+  req.player.stat_points -= statIncreaseCost;
   req.player[stat]++;
 
   req.player.hp = maxHp(req.player.constitution, req.player.level);
index ed8097a647762e79df20dfb25aede75db52c0bf4..3a7f4886b60b50395c70409ce798bcb3a5d172f3 100644 (file)
@@ -2,31 +2,72 @@ import { Stat } from './stats';
 
 export type Profession = 'Wanderer' | 'Warrior' | 'Mage' | 'Rogue';
 
+export type ProfessionStatBoost = {
+  [key in Stat]?: number
+};
+
 export type ProfessionDefinition = {
   id: Profession;
   name: string;
-  classStats: Stat[]
+  classStats: Stat[];
+  levelUpStatIncrease: {
+    even?: ProfessionStatBoost,
+    odd?: ProfessionStatBoost
+  }
 }
 
-export const professionList: Record<Profession, ProfessionDefinition> = {
-  'Wanderer': {
-    id: 'Wanderer',
-    name: 'Wanderer',
-    classStats: [Stat.strength, Stat.constitution, Stat.dexterity, Stat.intelligence]
-  },
-  'Warrior': {
-    id: 'Warrior',
-    name: 'Warrior',
-    classStats: [Stat.strength, Stat.constitution]
-  },
-  'Mage': {
-    id: 'Mage',
-    name: 'Mage',
-    classStats: [Stat.intelligence, Stat.constitution]
-  },
-  'Rogue': {
-    id: 'Rogue',
-    name: 'Rogue',
-    classStats: [Stat.dexterity, Stat.constitution]
+export const Professions: Map<Profession, ProfessionDefinition> = new Map<Profession, ProfessionDefinition>();
+
+Professions.set('Wanderer', {
+  id: 'Wanderer',
+  name: 'Wanderer',
+  classStats: [Stat.strength, Stat.constitution, Stat.dexterity, Stat.intelligence],
+  levelUpStatIncrease: {}
+});
+
+Professions.set('Warrior', {
+  id: 'Warrior',
+  name: 'Warrior',
+  classStats: [Stat.strength, Stat.constitution],
+  levelUpStatIncrease: {
+    even: {
+      [Stat.strength]: 2,
+      [Stat.constitution]: 1
+    },
+    odd: {
+      [Stat.strength]: 1,
+      [Stat.constitution]: 1
+    }
   }
-};
+});
+
+Professions.set('Mage', {
+  id: 'Mage',
+  name: 'Mage',
+  classStats: [Stat.intelligence, Stat.constitution],
+  levelUpStatIncrease: {
+    even: {
+      [Stat.intelligence]: 2,
+      [Stat.constitution]: 1
+    },
+    odd: {
+      [Stat.intelligence]: 2
+    }
+  }
+});
+
+Professions.set('Rogue', {
+  id: 'Rogue',
+  name: 'Rogue',
+  classStats: [Stat.dexterity, Stat.strength],
+  levelUpStatIncrease: {
+    even: {
+      [Stat.dexterity]: 2,
+      [Stat.strength]: 1
+    },
+    odd: {
+      [Stat.dexterity]: 1,
+      [Stat.strength]: 2
+    }
+  }
+});