I'm working on making a text adventure using Electron. I have the basics of the engine working, you can walk around an infinite map. Maps contain things, and you can enter a few basic commands. I'm wondering if the fundamentals of the game (what I currently have) can be improved at all before I go through adding the game's content.
The code currently supports these commands:
- look/look around - Prints your location and the contents of the current room
- look at - Prints an error (what do you want to look at)
- look at [thing] - Prints whether the thing exists where you currently are
- north/east/south/west - Moves the player
I'm leaving out index.js (the script that starts electron) and the CSS, since it doesn't seem relevant.
index.html
<!DOCTYPE html>
<html lang="en-US">
<head>
<title>ProceduralTA</title>
<link rel="stylesheet" href="css/styles.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div id="log"></div>
<div id="input-prefix">></div>
<div id="input-wrapper">
<form onsubmit="newInput(); return false">
<label>
<input id="input-box" type="text" placeholder="You can type here!" autocomplete="off">
</label>
</form>
</div>
<script src="js/game.js"></script>
<script src="js/input-handler.js"></script>
<script src="js/map.js"></script>
<script src="js/player.js"></script>
<script src="js/room.js"></script>
</body>
</html>
game.js
'use strict';
const {ipcRenderer} = window.require('electron');
window.$ = window.require('jquery');
const inputBox = $('#input-box');
const log = $('#log');
const charDelay = 10;
const titleMessage = 'Welcome to ProceduralTA!';
const introMessage = 'You are in a room.';
const gameData = {};
async function logMessage(message, type) {
const entry = $('<div></div>').addClass(type).appendTo(log);
for (const char of message) {
if (char === '\n')
entry.append('<br>');
else
entry.append(char);
await new Promise(resolve => setTimeout(resolve, charDelay));
}
}
$(() => {
gameData.map = new GameMap();
gameData.player = new Player();
logMessage(titleMessage, 'msg-system').then();
logMessage(introMessage, 'msg-game').then();
});
input-handler.js
'use strict';
let input;
let inputArray;
$(() => {
inputBox.trigger('focus');
});
$(window).keypress(() => {
inputBox.trigger('focus');
});
function newInput() {
input = inputBox.val();
inputArray = input.toLowerCase().split(' ');
inputArray = inputArray.filter(word => word !== 'a');
inputArray = inputArray.filter(word => word !== 'an');
inputArray = inputArray.filter(word => word !== 'the');
inputBox.val('');
logMessage('> ' + input, 'msg-player').then();
logMessage(matchInput(), 'msg-game').then();
ipcRenderer.send('saveGame', JSON.parse(JSON.stringify(gameData)));
}
function matchInput() {
const cMap = gameData.map;
const cPlayer = gameData.player;
let response = 'Unknown command.'
if (nextWord('north')) {
cPlayer.y++;
response = 'You move north.';
}
if (nextWord('south')) {
cPlayer.y--;
response = 'You move south.';
}
if (nextWord('east')) {
cPlayer.x++;
response = 'You move east.';
}
if (nextWord('west')) {
cPlayer.x--;
response = 'You move west.';
}
if (!cMap[cPlayer.y]) {
cMap.addRoom(cPlayer.y, cPlayer.x);
} else if (!cMap[cPlayer.y][cPlayer.x]) {
cMap.addRoom(cPlayer.y, cPlayer.x);
}
const cRoom = gameData.map[gameData.player.y][gameData.player.x];
if (nextWord('look')) {
if (nextWord('around') || !wordsLeft())
return 'You are at [' + cPlayer.x + ', ' + cPlayer.y + '].\n' +
'Contents of this room: ' + cRoom.printMonsters();
if (nextWord('at') && !wordsLeft())
return 'What do you want to look at?';
const object = cRoom.printObject(wordsLeft());
if (object)
return object;
else
return 'That doesn\'t exist here.';
}
const object = cRoom.printObject(wordsLeft());
if (object)
return object;
gameData.map = cMap;
gameData.player = cPlayer;
return response;
}
function nextWord(match) {
const word = inputArray[0];
if (word === match)
inputArray.shift();
return word === match;
}
function wordsLeft() {
return inputArray.join(' ');
}
map.js
'use strict';
function GameMap() {
this.addRoom = (y, x) => {
if (!this[y]) {
this[y] = {};
}
if (!this[y][x]) {
this[y][x] = new Room();
this[y][x].addMonster('Zombie', 10);
this[y][x].addMonster('Skeleton', 5);
}
}
this.addRoom(0, 0);
}
room.js
'use strict';
function Room() {
this.monsters = [];
this.addMonster = (name, hp) => {
this.monsters.push({
name: name,
hp: hp
});
}
this.printMonsters = () => {
let monsterDescriptions = '';
for (const [index, monster] of this.monsters.entries()) {
monsterDescriptions += `\n${(index + 1)}) ${monster.name} - ${monster.hp} HP`;
}
return monsterDescriptions;
}
this.printObject = name => {
for (const monster of this.monsters) {
if (monster.name.toLowerCase() === name) {
return 'You are looking at: ' + monster.name;
}
}
return false;
}
}
player.js
'use strict';
function Player() {
this.y = 0;
this.x = 0;
}
```