RCRPG/C++11
Javascript (node) version of RCRPG. The code can also be checked out and contributed to on github .
Code
<lang javascript> const _ = require('lodash'),
readline = require('readline');
///////////////////
// LODASH IMPORT //
///////////////////
// import all lodash functions to the main namespace, but isNaN not to cause conflicts _.each(_.keys(_), k => global[k === 'isNaN' ? '_isNaN' : k] = _[k]);
/////////////// // CONSTANTS // ///////////////
const DIRECTIONS = {
n: [ 0, -1, 0], s: [ 0, 1, 0], e: [-1, 0, 0], w: [ 1, 0, 0], u: [ 0, 0, -1], d: [ 0, 0, 1]
};
///////////// // HELPERS // /////////////
function findDirection (world, dir, longName=false) {
const maybeDirection = find(world.commands, c => contains(first(c), dir)), dirLetter = first(first(maybeDirection));
if (maybeDirection && has(DIRECTIONS, dirLetter)) { return longName ? first(maybeDirection)[1] : dirLetter; }
}
function makeRoom(location) {
return [location, null, compact([ random(0, 2) === 0 ? 'sledge': null, random(0, 2) === 0 ? 'ladder': null, random(0, 2) === 0 ? 'gold': null ])];
}
function listToDescriptiveString (lst) {
if (!lst) return; if (lst.length === 1) return first(lst); return dropRight(lst).join(', ') + ' and ' + last(lst);
}
function itemsToDescriptiveItems (items) {
return map(items, i => { switch (i) { case 'sledge': return 'a sledge'; case 'ladder': return 'a ladder'; case 'gold': return 'some gold'; } });
}
////////////// // MESSAGES // //////////////
function help () {
return `You need a sledge to dig rooms and ladders to go upwards.
Valid commands are: directions (north, south...), dig, take, drop, equip, inventory and look. Additionally you can tag rooms with the 'name' command and alias commands with 'alias'. Have fun! `; }
function welcome () {
console.log(`Welcome to the dungeon!
Grab the sledge and make your way to room 1,1,5 for a non-existant prize! `);
console.log(help());
}
///////////// // ACTIONS // /////////////
function gotoRoom (direction, world) {
const wantedRoom = zipWith(world.player.location, DIRECTIONS[direction], add), room = find(world.rooms, r => isEqual(first(r), world.player.location));
if (direction === 'u' && !contains(room[2], 'ladder')) { console.log("You can't go upwards without a ladder!"); } else { if (find(world.rooms, r => isEqual(first(r), wantedRoom))) { world.player.location = wantedRoom; look(world); } else { console.log("There's no exit in that direction!"); } }
return world
}
function dig (world, [direction]) {
let dir, dirLongName, wantedRoom;
if (!direction) { console.log('Where do you want to dig?'); return world } if (!(dir = findDirection(world, direction))) { console.log('That is not a direction I recognize'); return world; } if (!contains(world.player.inventory, 'sledge')) { console.log('With your bare hands?'); return world; }
dirLongName = findDirection(world, direction, true); wantedRoom = zipWith(world.player.location, DIRECTIONS[dir], add);
if (find(world.rooms, r => isEqual(first(r), wantedRoom))) { console.log('There is already an exit, there!'); return world; }
world.rooms.push(makeRoom(wantedRoom)); console.log(`There is now an exit ${dirLongName}ward`); return world;
}
function look (world) {
const room = find(world.rooms, r => isEqual(first(r), world.player.location)),
itemsOnFloor = itemsToDescriptiveItems(room[2]), itemsOnFloorStr = isEmpty(itemsOnFloor) ? : (itemsOnFloor.length === 1 ? itemsOnFloor[0] : listToDescriptiveString(itemsOnFloor)),
exits = chain(DIRECTIONS) .map((d, kd) => [kd, zipWith(d, first(room), add)]) .filter(r => find(world.rooms, rr => isEqual(first(rr), r[1]))) .map(d => find(world.commands, c => { return contains(first(c), first(d)) })[0][1]) .value(), exitsStr = isEmpty(exits) ? : (exits.length === 1 ? `There is one exit: ${exits[0]}.` : `You can see the following exits: ${listToDescriptiveString(exits)}.`);
console.log( (room[1] ? room[1] : `Room at ${world.player.location[0]}, ${world.player.location[1]}, ${world.player.location[2]}`) + '\n' + (!itemsOnFloorStr ? : `On the floor you can see ${itemsOnFloorStr}.\n`) + exitsStr );
return world;
}
function inventory (world) {
if (world.player.inventory.length === 0) { console.log('You are not carrying anything'); } else { console.log(`You are carrying: ${listToDescriptiveString(itemsToDescriptiveItems(world.player.inventory))}`); }
return world;
}
function take (world, [item]) {
const room = find(world.rooms, r => isEqual(first(r), world.player.location))
if (!item) { console.log('Take what?'); return world; }
if (item === 'all') { if (isEmpty(room[2])) { console.log('There is nothing to take here'); } else{ world.player.inventory = uniq(world.player.inventory.concat(room[2] || [])); room[2] = []; console.log('All items taken'); } return world; }
if (!contains(room[2], item)) { console.log("You can't see anything like that here"); return world; }
world.player.inventory = uniq(world.player.inventory.concat([item])); pull(room[2], item); console.log('Taken');
return world
}
function drop (world, [item]) {
const room = find(world.rooms, r => isEqual(first(r), world.player.location))
if (!item) { console.log('Drop what?'); return world; }
if (item === 'all') { if (isEmpty(world.player.inventory)) { console.log('You have nothing to drop'); } else{ room[2] = uniq(room[2].concat(world.player.inventory || [])); world.player.inventory = []; console.log('All items dropped'); } return world; }
if (!contains(world.player.inventory, item)) { console.log("You don't have that item"); return world; }
room[2] = uniq(room[2].concat([item])); pull(world.player.inventory, item); console.log('Dropped');
return world
}
function equip (world, [item]) {
if (!item) { console.log('What do you want to equip?'); return world; } if (!contains(world.player.inventory, item)) { console.log("You don't have such object"); return world; }
world.player.equipped = item; console.log('Item equipped!'); return world;
}
function unequip (world, [item]) {
if (!item) { console.log('What do you want to unequip?'); return world; } if (item !== world.player.equipped) { console.log("You don't have it equipped"); return world; }
world.player.equipped = null; console.log('Item unequipped!'); return world;
}
function alias (world, [cmd, al]) {
let foundCommand;
if (!cmd && !al) { console.log('Aliases:' + chain(world.commands) .filter(c => first(c).length > 1) .map(first) .reduce((acc, c) => `${acc}\n${first(c)} => ${rest(c).join(', ')}`, ) .value()); return world; }
if (!(foundCommand = find(world.commands, c => contains(first(c), cmd)))) { console.log('There is no such command'); return world }
if (!al) { let aliases = reject(first(foundCommand), c => c === cmd);
if (isEmpty(aliases)) { console.log(`There are no aliases for ${cmd}`); } else { console.log(`Aliases for "${cmd}": ${aliases.join(', ')}`); }
return world; }
foundCommand[0] = uniq(first(foundCommand).concat([al])); console.log('Alias assigned'); return world;
}
////////////////////// // INPUT PROCESSING // //////////////////////
function processInput(input, world) {
const splitInput = trim(input).split(/\s+/g), [command, options] = [first(splitInput), rest(splitInput)], commandFn = find(world.commands, c => contains(first(c), command.toLowerCase()));
if (commandFn) { return commandFn[1](world, options); } else { console.log("I don't know what you mean."); return world; }
}
/////////////// // MAIN LOOP // ///////////////
(function runGame () {
let world = { rooms: [ [[0, 0, 0], "The room where it all started...", ['ladder', 'sledge']], [[1, 1 , 5], "You found it! Lots of gold!"] ], commands: [ [['n', 'north'], partial(gotoRoom, 'n')], [['s', 'south'], partial(gotoRoom, 's')], [['w', 'west'], partial(gotoRoom, 'w')], [['e', 'east'], partial(gotoRoom, 'e')], [['d', 'down'], partial(gotoRoom, 'd')], [['u', 'up'], partial(gotoRoom, 'u')],
[['help'], help], [['dig'], dig], [['l', 'look'], look], [['i', 'inventory'], inventory], [['take'], take], [['drop'], drop], [['equip'], equip], [['unequip'], unequip], [['alias'], alias] ], player: { location: [0, 0, 0], inventory: ['sledge'], equipped: null } };
welcome();
process.stdin.resume(); process.stdin.setEncoding('utf8');
process.stdin.on('data', input => world = processInput(input, world))
})(); </lang>