chore(release): 0.4.0
[risinglegends.git] / seeds / dungeons.ts
1 import { config as dotenv } from 'dotenv';
2 import { db } from "../src/server/lib/db";
3 import { join } from 'path';
4 import { Dungeon, DungeonRoom, RoomExit } from '../src/shared/dungeon';
5 import * as fs from 'fs';
6 import * as marked from 'marked';
7 import { map, max } from 'lodash';
8
9 dotenv();
10
11 type TwisonLink = {
12   name: string;
13   ink: string;
14   pid: string;
15 }
16
17 type TwisonPassage = {
18   text: string;
19   name: string;
20   pid: string;
21   props?: {
22     fight?: {
23       monster_id: string;
24       one_time: string;
25     },
26     visit?: Record<string, string>,
27     end?: string,
28     rewards?: {
29       base: {
30         exp?: string,
31         gold?: string
32       },
33       per_kill_bonus?: {
34         exp?: string,
35         gold?: string
36       }
37     }
38   },
39   position: {
40     x: string;
41     y: string;
42   };
43   links:TwisonLink[]
44 }
45
46 type TwisonDungeon = {
47   passages: TwisonPassage[];
48   name: string;
49   startnode: string;
50   creator: string;
51   'creator-version': string;
52   ifid: string;
53 }
54
55 async function getFileData(filename: string): Promise<TwisonDungeon>  {
56   const data = fs.readFileSync(join(__dirname, '..', 'data', 'dungeons', filename), 'utf8');
57
58   console.log(data);
59
60   return JSON.parse(data) as TwisonDungeon;
61 }
62
63 export async function main(filename: string, done?: any) {
64   await db('dungeon_players').delete();
65
66   const raw = await getFileData(filename);
67
68   // attempt to create base dungeon!
69   const dungeon: Dungeon = (await db('dungeons').insert({
70     id: raw.ifid.toLowerCase(),
71     name: raw.name
72   }).onConflict('id').merge().returning('*')).pop();
73
74   // clear the rooms for the created dungeon
75   await db('dungeon_rooms').where({dungeon_id: dungeon.id}).delete();
76
77   // create the rooms first!
78   const roomsToCreate = raw.passages.map(passage => {
79     let data: Omit<DungeonRoom, 'id'> = {
80       dungeon_id: dungeon.id,
81       description: marked.parse(passage.text.split('<commands>')[0]),
82       exits: [],
83       settings: {}
84     };
85
86     if(passage.props) {
87       if(passage.props.fight) {
88         data.settings.fight = {
89           monster_id: parseInt(passage.props.fight.monster_id),
90           one_time: passage.props.fight.one_time.toLowerCase() === 'true'
91         }
92       }
93       if(passage.props.visit) {
94         data.settings.visit = map(passage.props.visit, (str: string, index: string) => {
95           return {
96             visit_number: parseInt(index),
97             description: marked.parse(str)
98           }
99         });
100       }
101       if(passage.props.end) {
102         data.settings.end = true;
103       }
104       if(passage.props.rewards) {
105         data.settings.rewards = {
106           base: {
107             exp: max([parseInt(passage.props.rewards.base.exp || '0'), 0]),
108             gold: max([parseInt(passage.props.rewards.base.gold || '0'), 0]),
109           }
110         };
111
112         if(passage.props.rewards.per_kill_bonus) {
113           data.settings.rewards.per_kill_bonus = {
114             exp: max([parseInt(passage.props.rewards.per_kill_bonus.exp || '0'), 0]),
115             gold: max([parseInt(passage.props.rewards.per_kill_bonus.gold || '0'), 0]),
116           }
117         }
118       }
119     }
120
121     return data;
122   });
123
124   const createdRooms: DungeonRoom[] = await db('dungeon_rooms').insert(roomsToCreate,).returning('*');
125
126   console.log(createdRooms);
127
128   // set the starting room!
129   await db('dungeons').update({starting_room: createdRooms[pidToIndex(raw.startnode)].id.toLowerCase()}).where({
130     id: dungeon.id
131   });
132
133   const exits = raw.passages.map(passage => {
134     const roomIndex = pidToIndex(passage.pid);
135     let exits: RoomExit[] = [];
136
137     // ending nodes don't have any links
138     if(passage.links) {
139       exits = passage.links.map(link => {
140         const pid = pidToIndex(link.pid);
141         return {
142           name: link.name,
143           target_room_id: createdRooms[pid].id
144         } 
145       });
146     }
147
148     return {
149       id: createdRooms[roomIndex].id,
150       exits
151     };
152   });
153
154   let i = 0;
155   exits.map(async exit => {
156     await db('dungeon_rooms').update({exits: JSON.stringify(exit.exits)}).where({
157       id: exit.id
158     });
159     console.log(`${++i}/${raw.passages.length} rooms created`);
160
161     if(i === raw.passages.length) {
162       done();
163     }
164   });
165
166   console.log(JSON.stringify(exits, null, 2));
167 }
168
169 function pidToIndex(str: string): number {
170   return parseInt(str)-1;
171 }
172
173 main('storage_cellar.json', () => {
174   console.log('Dungeons created!');
175   process.exit(0);
176 });