Skip to content

Instantly share code, notes, and snippets.

@mloberg
Created June 22, 2012 17:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mloberg/2974092 to your computer and use it in GitHub Desktop.
Save mloberg/2974092 to your computer and use it in GitHub Desktop.
NodeJS - Werebot
var irc = require('irc'),
werewolf = require('./game');
var client = new irc.Client('server', 'Werebot', {
channels: [ '#channel' ],
autoConnect: false
});
client.connect();
client.addListener('registered', function(msg) {
var gameRoom = '#werewolf',
game = game = new werewolf.Game(gameRoom, client);
client.addListener('message#', function(from, room, text, message) {
if (text.match(/werewolf/i) && room !== gameRoom) {
client.say(room, "There is a game in " + gameRoom);
}
});
});
exports.Game = Game;
function objectSize(obj) {
var key, size = 0;
for (key in obj) {
if (obj.hasOwnProperty(key)) size++;
}
return size;
}
function clone(obj) {
var newObj = (obj instanceof Array) ? [] : {};
for (i in obj) {
if (i == 'clone') continue;
if (obj[i] && typeof obj[i] == "object") {
newObj[i] = obj[i].clone();
} else {
newObj[i] = obj[i];
}
}
return newObj;
}
var NIGHT = 1, DAWN = 2, DAY = 3, VOTE = 4,
gameMin = 4;
function Game(room, client) {
this.room = room;
this.client = client;
this.create();
}
Game.prototype.players = [];
Game.prototype.villagers = [];
Game.prototype.hasStarted = false;
Game.prototype.roles = {
werewolf: null,
angel: null,
seer: null
};
Game.prototype.round = 0;
Game.prototype.roundResults = {
kill: null,
protect: null,
scan: null
};
Game.prototype.voted = [];
Game.prototype.votes = {};
Game.prototype.create = function() {
var self = this;
this.client.join(this.room, function() {
// set topic
self.client.send("TOPIC", self.room, "WereWolf");
// add join listener
self.client.addListener("join" + self.room, function(nick, message) {
self.players.push(nick);
if (self.hasStarted) {
self.client.say(self.room, "Welcome " + nick + ". Please wait for a new game to start.");
this.client.send("MODE", this.room, "-v", nick);
} else {
self.client.say(self.room, "Welcome " + nick + ". Please wait for the game to start.");
}
});
// add part listener
self.client.addListener("part" + self.room, function(nick, reason, message) {
if (self.hasStarted) {
// active game
if (nick === self.roles.werewolf) {
self.gameOver(true);
}
self.villagers.splice(self.villagers.indexOf(nick), 1);
}
self.client.say(self.room, nick + " has parted the room.");
self.players.splice(self.players.indexOf(nick), 1);
});
// add private message listener (for game)
self.client.addListener("pm", function(nick, text, message) {
if (self.villagers.indexOf(nick) !== -1) {
switch (self.round) {
case NIGHT:
if (nick === self.roles.werewolf) {
if (self.villagers.indexOf(text) === -1) {
self.client.say(nick, "Sorry, that's not a valid user.");
} else if (self.roundResults.kill) {
self.client.say(nick, "You can only choose one person per round.");
} else {
self.roundResults.kill = text;
self.client.say(nick, "You have chosen to kill " + text + ".");
}
} else if(nick === self.roles.seer) {
if (self.villagers.indexOf(text) === -1) {
self.client.say(nick, "Sorry, that's not a valid user.");
} else if (self.roundResults.scan) {
self.client.say(nick, "You can only scan one person per round.");
} else {
self.roundResults.scan = text;
if (text === self.roles.werewolf) {
self.client.say(nick, text + " is the werewolf.");
} else if(text === self.roles.angel) {
self.client.say(nick, text + " is the angel.");
} else {
self.client.say(nick, text + " is a common villager.");
}
}
} else if (nick === self.roles.angel) {
if (self.villagers.indexOf(text) === -1) {
self.client.say(nick, "Sorry, that's not a valid user.");
} else if (self.roundResults.protect) {
self.client.say(nick, "You can only protect one person per round.");
} else {
self.roundResults.protect = text;
self.client.say(nick, "You have chosen to protect " + text + ".");
}
}
break;
case VOTE:
if (self.voted.indexOf(nick) === -1) {
var vote = text.replace(/vote /, '');
self.voted.push(nick);
if (self.votes[vote]) {
self.votes[vote]++;
} else {
self.votes[vote] = 1;
}
} else {
self.client.say(nick, "You can only cast one vote per round.");
}
break;
}
}
});
self.waitForUsers();
});
};
Game.prototype.waitForUsers = function() {
var self = this;
if (self.players.length < gameMin) {
console.log(self.players.length);
self.client.say(self.room, "We need " + gameMin + " players to start the game.");
setTimeout(function() {
self.waitForUsers();
}, 30000);
} else {
self.startGame();
}
};
Game.prototype.startGame = function() {
var self = this;
this.hasStarted = true;
this.villagers = clone(this.players);
self.client.send("MODE", self.room, "+m");
for (var i = 0; i < self.villagers.length; i++) {
self.client.send("MODE", self.room, "+v", self.villagers[i]);
}
// rules
self.client.say(self.room, "You are a part of the village. This is a normal village like any other, except for one thing. A werewolf is terrorizing the village at night. It is the job of the villagers to find and kill the werewolf before it kills all of the villagers.")
self.client.say(self.room, "Along with the werewolf, there are two more 'special' players, the seer and the angel.");
self.client.say(self.room, "The seer may scan any player to find out what role he plays in the village. The angel may choose one person to save from being killed by the werewolf.");
self.client.say(self.room, "As night falls on the village the werewolf will choose someone to kill, the seer someone to scan, and angel someone to save. In the morning the results of the night will be revealed. If you are killed, you will be silenced in the room for the remainder of the game.");
self.client.say(self.room, "Next comes the debate. During this you will be able to discuss who you think is the werewolf, and then put it to a vote. The person with the most votes will be killed off.");
// roles
this.handOutRoles();
setTimeout(function() {
self.night();
}, 10000);
};
Game.prototype.night = function() {
var self = this;
this.round = NIGHT;
this.client.say(this.room, "Night falls on the village.");
if (this.villagers.indexOf(this.roles.werewolf) !== -1) {
this.client.say(this.roles.werewolf, "Please send me the name of who you would like to kill.");
}
if (this.villagers.indexOf(this.roles.seer) !== -1) {
this.client.say(this.roles.seer, "Please send me the name of who you would like to scan.");
}
if (this.villagers.indexOf(this.roles.angel) !== -1) {
this.client.say(this.roles.angel, "Please send me the name of who you would like to protect.");
}
setTimeout(function() {
self.dawn();
}, 60000);
};
Game.prototype.dawn = function() {
var self = this, message, kill;
this.round = DAWN;
if (!self.roundResults.kill) {
message = "As the sun rises, the villagers gather and find that everyone is accounted for.";
} else if (self.roundResults.kill === self.roundResults.protect) {
message = "As the sun starts to rise, a flash illuminates the village. They gather and find that everyone is accounted for.";
} else {
message = "As the sun rises, the villagers gather, but something isn't right. People notice " + self.roundResults.kill + " is missing. They rush over to their house, and find them mauled to death.";
kill = self.roundResults.kill;
}
this.client.say(this.room, message);
if (kill) {
this.killUser(kill);
}
this.roundResults.kill = null;
this.roundResults.scan = null;
this.roundResults.protect = null;
setTimeout(function() {
if (self.villagers.indexOf(self.roles.werewolf) !== -1 && self.villagers.length === 1) {
self.gameOver(false);
} else {
self.day();
}
}, 10000);
};
Game.prototype.day = function() {
var self = this;
this.round = DAY;
this.client.say(this.room, "The floor is open for debate. Voting will begin in 10 seconds.");
setTimeout(function() {
self.vote();
}, 10000);
};
Game.prototype.vote = function() {
var self = this;
this.round = VOTE;
this.client.say(this.room, "Villagers, please cast your vote now by typing \"/msg Werebot vote <name>\". The person with the most votes will be lynched. You have 60 seconds to vote.");
setTimeout(function() {
self.voteResults();
}, 60000);
};
Game.prototype.voteResults = function() {
var self = this;
this.round = 0;
if (objectSize(self.votes) > 0) {
var lynch = null,
votes = 0;
for (var vote in self.votes) {
if (self.votes[vote] > votes) {
lynch = vote;
votes = self.votes[vote];
} else if (self.votes[vote] === votes) {
lynch = null;
}
}
if (!lynch) {
self.client.say(self.room, "The villagers were unable to reach a decision.");
} else {
self.client.say(self.room, "Villagers grab " + lynch + ", they try to escape but the other villagers overpower them. The sun sets that night with " + lynch + " hanging limply from a tree.");
self.killUser(lynch);
}
} else {
self.client.say(self.room, "No votes were cast, therefore no one is lynched.");
}
this.voted = [];
this.votes = {};
setTimeout(function() {
if (self.villagers.indexOf(self.roles.werewolf) === -1) {
self.gameOver(true);
} else if (self.villagers.length === 1) {
self.gameOver(false);
} else {
self.night();
}
}, 10000);
};
Game.prototype.gameOver = function(won) {
var self = this;
if (won) {
self.client.say(self.room, "Congratulations! The villagers have won the game.");
} else {
self.client.say(self.room, "The Werewolf has killed all the villagers and won the game.");
}
self.client.send("MODE", self.room, "-m");
self.villagers = [];
self.hasStarted = false;
self.roles = {
werewolf: null,
seer: null,
angel: null
};
self.client.say(self.room, "A new game will start in 30 seconds. (Assuming there are enough players)");
setTimeout(function() {
self.waitForUsers();
}, 30000);
};
Game.prototype.killUser = function(user) {
this.client.send("MODE", this.room, "-v", user);
this.villagers.splice(this.villagers.indexOf(user), 1);
};
Game.prototype.handOutRoles = function() {
var self = this,
select = function() {
var key = Math.floor(Math.random() * self.villagers.length),
user = self.villagers[key];
if (self.roles.werewolf === user || self.roles.seer === user || self.roles.angel === user) return false
return user;
};
while (!self.roles.werewolf) {
self.roles.werewolf = select();
}
self.client.say(self.roles.werewolf, "You are the Werewolf.");
while (!self.roles.seer) {
self.roles.seer = select();
}
self.client.say(self.roles.seer, "You are the Seer.");
while (!self.roles.angel) {
self.roles.angel = select();
}
self.client.say(self.roles.angel, "You are the Angel.");
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment