factions!
authorxangelo <git@xangelo.ca>
Fri, 16 Jun 2023 16:50:07 +0000 (12:50 -0400)
committerxangelo <git@xangelo.ca>
Fri, 16 Jun 2023 16:50:07 +0000 (12:50 -0400)
This adds a simple "faction" system which is that a monster may belong
to a single faction. For now nothing is done with this but later on this
can be expanded to include a reputation system or titles and the like.

migrations/20230616153627_factions.ts [new file with mode: 0644]
seeds/monsters.ts
src/server/api.ts
src/server/monster.ts
src/shared/factions.ts [new file with mode: 0644]
src/shared/fight.ts
src/shared/monsters.ts

diff --git a/migrations/20230616153627_factions.ts b/migrations/20230616153627_factions.ts
new file mode 100644 (file)
index 0000000..2b20a15
--- /dev/null
@@ -0,0 +1,20 @@
+import { Knex } from "knex";
+
+
+export async function up(knex: Knex): Promise<void> {
+  return knex.schema.createTable('factions', function(table) {
+    table.increments('id').primary();
+    table.string('name').unique();
+    table.text('description').nullable();
+  }).alterTable('monsters', function(table) {
+    table.integer('faction_id').nullable();
+  });
+}
+
+
+export async function down(knex: Knex): Promise<void> {
+  return knex.schema.dropTable('factions').alterTable('monsters', function(table) {
+    table.dropColumn('faction_id');
+  });
+}
+
index 538b31ea7816315a46658ec9ff2c830ba7020f44..f7efe01e8fb8b3f7750e2b90eacd07801c462341 100644 (file)
@@ -13,10 +13,29 @@ Airtable.configure({
 
 const base = Airtable.base('appDfPLPajPNog5Iw');
 
+export async function createFactions(): Promise<void> {
+  return new Promise(async (resolve, reject) => {
+    base('Factions').select().eachPage(async (records, next) => {
+      await db('factions').insert(records.map(r => {
+        console.log(`Creating faction ${r.fields.Name}`);
+        return {
+          id: r.fields.ID,
+          name: r.fields.Name,
+          description: r.fields.Description
+        }
+      })).onConflict('id').merge();
+
+      next();
+    }).finally(() => {
+      resolve();
+    })
+
+  });
+}
+
 
 export async function createMonsters(): Promise<void> {
   return new Promise(async (resolve, reject) => {
-    await db('monsters').delete();
     await db('fight').delete();
 
     base('Monsters').select().eachPage(async (records, next) => {
@@ -26,6 +45,8 @@ export async function createMonsters(): Promise<void> {
         }
         stats.monsters[r.fields.location_id[0]]++;
 
+        const factionId = r.fields.faction_id ? r.fields.faction_id[0] : null;
+
         return {
           id: r.fields.id,
           name: r.fields.Name,
@@ -42,7 +63,8 @@ export async function createMonsters(): Promise<void> {
           chestAp: r.fields.chestAp,
           legsAp: r.fields.legsAp,
           armsAp: r.fields.armsAm,
-          location_id: r.fields.location_id[0]
+          location_id: r.fields.location_id[0],
+          faction_id: factionId
         }
       })).onConflict('id').merge();
 
@@ -56,7 +78,7 @@ export async function createMonsters(): Promise<void> {
 
 // run this script manually
 if(!module.parent) {
-  createMonsters().then(() => {
+  createFactions().then(createMonsters).then(() => {
     console.log(stats.monsters);
     console.log('Complete');
     process.exit(0);
index b35b73a5d310ebf9d22a4e95e02c5b673afc556c..bc83886bf51b611c8ad36251d14c9fc090cbcd26 100644 (file)
@@ -10,7 +10,7 @@ import * as _ from 'lodash';
 import {broadcastMessage, Message} from '../shared/message';
 import {expToLevel, maxHp, Player} from '../shared/player';
 import { professionList } from '../shared/profession';
-import {clearFight, createFight, getMonsterList, loadMonster, loadMonsterFromFight, saveFightState} from './monster';
+import {clearFight, createFight, getMonsterList, loadMonster, loadMonsterFromFight, loadMonsterWithFaction, saveFightState} from './monster';
 import {FightRound} from '../shared/fight';
 import {addInventoryItem, deleteInventoryItem, getEquippedItems, getInventory, updateAp} from './inventory';
 import {Monster, MonsterForFight, MonsterForList} from '../shared/monsters';
@@ -195,7 +195,7 @@ io.on('connection', async socket => {
   });
 
   socket.on('fight', async (data: {action: 'attack' | 'cast' | 'flee', target: 'head' | 'body' | 'arms' | 'legs'}) => {
-    const monster = await loadMonsterFromFight(player.id);
+    const monster = await loadMonsterWithFaction(player.id);
     const playerSkills = await getPlayerSkillsAsObject(player.id);
     const roundData: FightRound = {
       monster,
@@ -320,6 +320,7 @@ io.on('connection', async socket => {
     const playerFinalHeal = Math.floor(boost.hp + hpHealAfterMasteries);
 
     roundData.roundDetails.push(`You targeted the monsters ${data.target.toUpperCase()} with ${attackType} damage!`);
+    console.log(monster);
     if(data.target === 'arms') {
       if(monster.armsAp > 0) {
         monster.armsAp -= playerFinalDamage;
index b1b84819ddc832a03e32b6a6b8817f1d15a8092a..3a522dd477195f61b7810c0a61ff88ba83922063 100644 (file)
@@ -1,5 +1,5 @@
 import { db } from './lib/db';
-import { Fight, Monster } from '../shared/monsters';
+import { Fight, Monster, MonsterWithFaction } from '../shared/monsters';
 
 export async function getMonsterList(location_id: string): Promise<Monster[]> {
   const res: Monster[] = await db.select('*')
@@ -22,6 +22,20 @@ export async function loadMonsterFromFight(authToken: string): Promise<Fight> {
   });
 }
 
+export async function loadMonsterWithFaction(authToken: string): Promise<MonsterWithFaction> {
+  const res = await db.raw(`
+                      select 
+                        f.*, fa.id as faction_id, fa.name as faction_name
+                      from fight f
+                      join monsters m on f.ref_id = m.id
+                      left outer join factions fa on m.faction_id = fa.id
+                      where f.player_id = ?
+                        limit 1
+                      `, [authToken]);
+
+  return res.rows[0];
+}
+
 export async function saveFightState(authToken: string, monster: Fight) {
   return db('fight').where({
     player_id: authToken,
diff --git a/src/shared/factions.ts b/src/shared/factions.ts
new file mode 100644 (file)
index 0000000..080c769
--- /dev/null
@@ -0,0 +1,5 @@
+export type Faction = {
+  id: number;
+  name: string;
+  description: string;
+}
index fcbc86a09bfe5fdd759bc021617efa2412e8c479..2adc735933e232da0b2d6619cd791c561468ad7e 100644 (file)
@@ -1,4 +1,4 @@
-import {Fight} from "./monsters"
+import {MonsterWithFaction} from "./monsters"
 import {Player} from "./player"
 
 export type FightReward = {
@@ -8,7 +8,7 @@ export type FightReward = {
 }
 
 export type FightRound = {
-  monster: Fight,
+  monster: MonsterWithFaction,
   player: Player,
   winner: 'player' | 'monster' | 'in-progress',
   rewards: FightReward,
index fe9cc2f3613efc900e6099ffd0df65a0ba25dde6..e75cc364d7fbfaf52e14fff22589883208c5b803 100644 (file)
@@ -15,6 +15,7 @@ export type Monster = {
   legsAp: number;
   maxHp: number;
   location_id: string;
+  faction_id: number;
 }
 
 export type MonsterForList = {
@@ -23,12 +24,17 @@ export type MonsterForList = {
   level: number;
 }
 
-export type Fight = Omit<Monster, 'id'> & { 
+export type Fight = Omit<Monster, 'id' | 'faction_id'> & { 
   id: string,
   player_id: string,
   ref_id: number
 };
 
+export type MonsterWithFaction = Fight & {
+  faction_id: string;
+  faction_name: string;
+}
+
 export type MonsterForFight = {
   id: number | string;
   hp: number;