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';
17 type TwisonPassage = {
26 visit?: Record<string, string>,
46 type TwisonDungeon = {
47 passages: TwisonPassage[];
51 'creator-version': string;
55 async function getFileData(filename: string): Promise<TwisonDungeon> {
56 const data = fs.readFileSync(join(__dirname, '..', 'data', 'dungeons', filename), 'utf8');
60 return JSON.parse(data) as TwisonDungeon;
63 export async function main(filename: string, done?: any) {
64 await db('dungeon_players').delete();
66 const raw = await getFileData(filename);
68 // attempt to create base dungeon!
69 const dungeon: Dungeon = (await db('dungeons').insert({
70 id: raw.ifid.toLowerCase(),
72 }).onConflict('id').merge().returning('*')).pop();
74 // clear the rooms for the created dungeon
75 await db('dungeon_rooms').where({dungeon_id: dungeon.id}).delete();
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]),
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'
93 if(passage.props.visit) {
94 data.settings.visit = map(passage.props.visit, (str: string, index: string) => {
96 visit_number: parseInt(index),
97 description: marked.parse(str)
101 if(passage.props.end) {
102 data.settings.end = true;
104 if(passage.props.rewards) {
105 data.settings.rewards = {
107 exp: max([parseInt(passage.props.rewards.base.exp || '0'), 0]),
108 gold: max([parseInt(passage.props.rewards.base.gold || '0'), 0]),
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]),
124 const createdRooms: DungeonRoom[] = await db('dungeon_rooms').insert(roomsToCreate,).returning('*');
126 console.log(createdRooms);
128 // set the starting room!
129 await db('dungeons').update({starting_room: createdRooms[pidToIndex(raw.startnode)].id.toLowerCase()}).where({
133 const exits = raw.passages.map(passage => {
134 const roomIndex = pidToIndex(passage.pid);
135 let exits: RoomExit[] = [];
137 // ending nodes don't have any links
139 exits = passage.links.map(link => {
140 const pid = pidToIndex(link.pid);
143 target_room_id: createdRooms[pid].id
149 id: createdRooms[roomIndex].id,
155 exits.map(async exit => {
156 await db('dungeon_rooms').update({exits: JSON.stringify(exit.exits)}).where({
159 console.log(`${++i}/${raw.passages.length} rooms created`);
161 if(i === raw.passages.length) {
166 console.log(JSON.stringify(exits, null, 2));
169 function pidToIndex(str: string): number {
170 return parseInt(str)-1;
173 main('storage_cellar.json', () => {
174 console.log('Dungeons created!');