|
|
@@ -6,10 +6,10 @@ function LoupGarou(config) {
|
|
|
const ROLES = {
|
|
|
WOLF: "WOLF",
|
|
|
VILLAGER: "VILLAGER",
|
|
|
- CUPIDON: "CUPIDON",
|
|
|
+ CUPIDON: "CUPIDON", // OK
|
|
|
HUNTER: "HUNTER",
|
|
|
WITCH: "WITCH",
|
|
|
- SEER: "SEER",
|
|
|
+ SEER: "SEER", // OK
|
|
|
GIRL: "GIRL"
|
|
|
};
|
|
|
|
|
|
@@ -61,12 +61,15 @@ const langMng = [
|
|
|
remainingPseudos: function(nicks) { return "Vous avez le choix entre : " +nicks.join(", "); },
|
|
|
seerMessage: function(players) { return "Tu vas pouvoir decouvrir le role d'un joueur. Tapes juste le pseudo du joueur qui t'interesse. Tu as le choix entre: " +players.join(", "); },
|
|
|
seerTimeout: function() { return "Il est tard et tu vas te coucher. Tu pourras reessayer demain."; },
|
|
|
+ wolfTimeout: function() { return "Les Loups-Garous ne se sont pas nourris ce soir et sont tous morts de faim !"; },
|
|
|
loverWins: function() { return "Les amoureux gagnent la partie !"; },
|
|
|
wolfWins: function() { return "Les loup-garous gagnent la partie !"; },
|
|
|
villagerWins: function() { return "Les villageois gagnent la partie !"; },
|
|
|
congrats: function(nickList) { return nickList.length == 1 ? ("Félicitations au gagnant " +nickList[0]) : ("Félicitations aux gagnants " +nickList.join(", ")); },
|
|
|
waitingCupidon: function(timeSec) { return `En attente de cupidon (${timeSec} secondes)`; },
|
|
|
waitingSeer: function(timeSec) { return `En attente de la voyante (${timeSec} secondes)`; },
|
|
|
+ waitingWolf: function(timeSec) { return `En attente des loup-garous (${timeSec} secondes)`; },
|
|
|
+ currentVotes: function() { return "Etat des votes:"; },
|
|
|
whoiswhat: {
|
|
|
"WOLF": function(who) { return `${who} est un Loup-Garou.`; },
|
|
|
"VILLAGER": function(who) { return `${who} est un simple villageois.`; },
|
|
|
@@ -102,7 +105,8 @@ const KILL_REASON = {
|
|
|
WOLF: 1,
|
|
|
LEFT: 2,
|
|
|
LOVE: 3,
|
|
|
- VILLAGER: 4
|
|
|
+ VILLAGER: 4,
|
|
|
+ HUNGER: 5
|
|
|
}
|
|
|
|
|
|
function Player(lg, name) {
|
|
|
@@ -122,7 +126,71 @@ Player.prototype.kill = function(reason, msg) {
|
|
|
this.dead = reason;
|
|
|
this.killReason = msg;
|
|
|
this.loupgarou.onKilled(this);
|
|
|
-}
|
|
|
+};
|
|
|
+
|
|
|
+VoteEngine = function() {
|
|
|
+ this.players = null;
|
|
|
+ this.canBeVoted = null;
|
|
|
+};
|
|
|
+
|
|
|
+VoteEngine.prototype.init = function(canVote, canBeVoted) {
|
|
|
+ this.players = {};
|
|
|
+ this.canBeVoted = {};
|
|
|
+ canVote.forEach(i => this.players[i.toLowerCase()] = false);
|
|
|
+ canBeVoted.forEach(i => this.canBeVoted[i.toLowerCase()] = true);
|
|
|
+};
|
|
|
+
|
|
|
+VoteEngine.prototype.vote = function(player, text) {
|
|
|
+ text = text.trim().toLowerCase();
|
|
|
+ if (!player ||
|
|
|
+ this.players[player] === undefined ||
|
|
|
+ this.canBeVoted[text] === undefined)
|
|
|
+ return;
|
|
|
+ this.players[player] = text;
|
|
|
+ if (this.canBeVoted === true)
|
|
|
+ this.canBeVoted = Date.now();
|
|
|
+};
|
|
|
+
|
|
|
+VoteEngine.prototype.hasVotes = function() {
|
|
|
+ for (var i in this.players)
|
|
|
+ if (this.players[i])
|
|
|
+ return true;
|
|
|
+ return false;
|
|
|
+};
|
|
|
+
|
|
|
+VoteEngine.prototype.getVotes = function() {
|
|
|
+ var votedByName = {},
|
|
|
+ voted = [];
|
|
|
+
|
|
|
+ for (var i in this.players) {
|
|
|
+ if (this.players[i] !== false) {
|
|
|
+ var arr = votedByName[this.players[i]];
|
|
|
+ if (!arr)
|
|
|
+ voted.push(arr = votedByName[this.players[i]] = {name: this.players[i], from: []});
|
|
|
+ arr.from.push(i);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return voted.sort((i, j) => j.from.length -i.from.length);
|
|
|
+};
|
|
|
+
|
|
|
+VoteEngine.prototype.getVote = function() {
|
|
|
+ var voted = {};
|
|
|
+ for (var i in this.players)
|
|
|
+ if (this.players[i] !== undefined)
|
|
|
+ voted[this.players[i]] = (voted[this.players[i]] || 0) +1
|
|
|
+ var result = null,
|
|
|
+ max = 0,
|
|
|
+ time = null;
|
|
|
+
|
|
|
+ for (var i in voted) {
|
|
|
+ if (voted[i] > max || (voted[i] === max && (time === null || time > this.canBeVoted[i]))) {
|
|
|
+ result = i;
|
|
|
+ max = voted[i];
|
|
|
+ time = this.canBeVoted[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+};
|
|
|
|
|
|
LoupGarou.prototype.init = function(bot, chanName) {
|
|
|
this.room = chanName;
|
|
|
@@ -135,6 +203,7 @@ LoupGarou.prototype.init = function(bot, chanName) {
|
|
|
this.currentScenario = langMng[0];
|
|
|
this.nightChannelPersons = {};
|
|
|
this.justDead = [];
|
|
|
+ this.voteEngine = new VoteEngine();
|
|
|
|
|
|
for (var i in STEP) this.stepListeners[STEP[i]] = [];
|
|
|
this.stepListeners[STEP.NOT_STARTED].push(function() { this.bot.setModes(this.room, "-m"); this.bot.endGame(this); });
|
|
|
@@ -150,10 +219,10 @@ LoupGarou.prototype.init = function(bot, chanName) {
|
|
|
this.stepListeners[STEP.DAY_HUNTER].push(LoupGarou.prototype.onHunter);
|
|
|
this.stepListeners[STEP.DAY].push(LoupGarou.prototype.onDay);
|
|
|
this.stepListeners[STEP.DAY].push(LoupGarou.prototype.cleanCorpses);
|
|
|
- this.stepListeners[STEP.DAY].push(LoupGarou.prototype.checkEndOfGame);
|
|
|
+ this.stepListeners[STEP.DAY].push(LoupGarou.prototype.checkEndOfGameAndContinue);
|
|
|
this.stepListeners[STEP.DAY_VILLA].push(LoupGarou.prototype.onVillagers);
|
|
|
this.stepListeners[STEP.DAY_EVENING].push(LoupGarou.prototype.onEvening);
|
|
|
- this.stepListeners[STEP.DAY_EVENING].push(LoupGarou.prototype.checkEndOfGame);
|
|
|
+ this.stepListeners[STEP.DAY_EVENING].push(LoupGarou.prototype.checkEndOfGameAndContinue);
|
|
|
|
|
|
var self = this;
|
|
|
this.bot.bot.addListener("pm", (from, text) => {
|
|
|
@@ -211,8 +280,11 @@ LoupGarou.prototype.onSelfJoin = function() {
|
|
|
var _this = this;
|
|
|
this.nightChannelPersons = this.nightChannelPersons || {};
|
|
|
this.bot.bot.addListener("join" +_this.config.privateChannel, nick => {
|
|
|
- if (this.bot.name.toLowerCase() !== nick.toLowerCase())
|
|
|
+ if (_this.bot.name.toLowerCase() !== nick.toLowerCase()) {
|
|
|
_this.nightChannelPersons[nick.toLowerCase()] = true;
|
|
|
+ if (_this.currentStep === STEP.NIGHT_LG)
|
|
|
+ _this.bot.voice(_this.config.privateChannel, nick);
|
|
|
+ }
|
|
|
});
|
|
|
this.bot.bot.addListener("names" +_this.config.privateChannel, nicks => {
|
|
|
for (var nick in nicks)
|
|
|
@@ -225,9 +297,12 @@ LoupGarou.prototype.onSelfJoin = function() {
|
|
|
this.bot.bot.addListener("kick" +_this.config.privateChannel, nick => {
|
|
|
delete _this.nightChannelPersons[nick.toLowerCase()];
|
|
|
});
|
|
|
- this.bot.bot.join(this.config.privateChannel, () => {
|
|
|
- this.bot.setModes(_this.config.privateChannel, "+iKmnpt");
|
|
|
+ this.bot.bot.addListener("message" +_this.config.privateChannel, (user, text) => {
|
|
|
+ var player = this.players[user];
|
|
|
+ if (this.currentStep === STEP.NIGHT_LG && player && player.dead === null)
|
|
|
+ this.voteEngine.vote(player.name.toLowerCase(), text);
|
|
|
});
|
|
|
+ this.bot.bot.join(this.config.privateChannel);
|
|
|
this.bot.setModes(this.room, "-m");
|
|
|
};
|
|
|
|
|
|
@@ -249,7 +324,7 @@ LoupGarou.prototype.setStep = function(newStep) {
|
|
|
}
|
|
|
LoupGarou.prototype.nextStep.messageDelayed = [];
|
|
|
LoupGarou.prototype.setStep.recursive = true;
|
|
|
- this.timeInStep = Date.now();
|
|
|
+ this.timeInStep = Date.now() / 1000;
|
|
|
this.clearReminder();
|
|
|
this.currentStep = newStep;
|
|
|
this.stepListeners[newStep] && this.stepListeners[newStep].some(i => i.call(this), this);
|
|
|
@@ -472,21 +547,43 @@ LoupGarou.prototype.onGirl = function() {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-LoupGarou.prototype.onWolfInternal = function(player) {
|
|
|
- //FIXME ...
|
|
|
- this.bot.sendMsg(this.room, "Attente loups"); // FIXME this.currentScenario
|
|
|
- setTimeout((function() { this.nextStep(); }).bind(this), 15000);
|
|
|
+LoupGarou.prototype.sendCurrentVotes = function(channel) {
|
|
|
+ if (this.voteEngine.hasVotes()) {
|
|
|
+ this.bot.sendMsg(channel, this.currentScenario.currentVotes());
|
|
|
+ this.voteEngine.getVotes().forEach(i => {
|
|
|
+ this.bot.sendMsg(channel, i.name +' : ' +i.from.join(", "));
|
|
|
+ }, this);
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
LoupGarou.prototype.onWolf = function() {
|
|
|
- var notWolf = [];
|
|
|
- for (var i in this.players) if (this.players[i].role !== ROLES.WOLF) notWolf.push(this.players[i]);
|
|
|
- notWolf = notWolf.sort(() => Math.random() -.5)[0];
|
|
|
- notWolf.kill(KILL_REASON.WOLF, this.currentScenario.killedWolf(notWolf.name));
|
|
|
-
|
|
|
var players = this.withRole(ROLES.WOLF);
|
|
|
if (players.length) {
|
|
|
- this.onWolfInternal(players[0]);
|
|
|
+ this.bot.voice(this.config.privateChannel, Object.keys(this.nightChannelPersons));
|
|
|
+ this.voteEngine.init(players.map(i => i.name), this.aliveNicks());
|
|
|
+ this.setReminder(function() {
|
|
|
+ this.bot.sendMsg(this.room, this.currentScenario.waitingWolf(Math.round((this.config.wolfDelay -(Date.now() / 1000) +this.timeInStep))));
|
|
|
+ this.bot.sendMsg(this.config.privateChannel, this.currentScenario.remainingPseudos(this.aliveNicks()));
|
|
|
+ this.sendCurrentVotes(this.config.privateChannel);
|
|
|
+ });
|
|
|
+ setTimeout((function() {
|
|
|
+ this.bot.devoice(this.config.privateChannel, Object.keys(this.nightChannelPersons));
|
|
|
+ if (!this.voteEngine.hasVotes()) {
|
|
|
+ var msg = this.currentScenario.wolfTimeout();
|
|
|
+ this.bot.sendMsg(this.room, msg);
|
|
|
+ players.forEach(i => {
|
|
|
+ this.bot.sendMsg(this.room, this.currentScenario.whowaswhat[i.role](i.name))
|
|
|
+ i.kill(KILL_REASON.HUNGER, msg);
|
|
|
+ });
|
|
|
+ this.checkEndOfGameAndContinue(); // Will end game
|
|
|
+ return;
|
|
|
+ } else {
|
|
|
+ var p = this.players[this.voteEngine.getVote()];
|
|
|
+ p.kill(KILL_REASON.WOLF, this.currentScenario.killedWolf(p.name));
|
|
|
+ this.bot.sendMsg(this.room, this.current);
|
|
|
+ this.nextStep();
|
|
|
+ }
|
|
|
+ }).bind(this), this.config.wolfDelay * 1000);
|
|
|
} else {
|
|
|
this.nextStep();
|
|
|
}
|
|
|
@@ -545,6 +642,13 @@ LoupGarou.prototype.cleanCorpses = function() {
|
|
|
this.justDead = [];
|
|
|
};
|
|
|
|
|
|
+LoupGarou.prototype.checkEndOfGameAndContinue = function() {
|
|
|
+ if (this.checkEndOfGame())
|
|
|
+ this.setStep(STEP.NOT_STARTED);
|
|
|
+ else
|
|
|
+ this.nextStep();
|
|
|
+};
|
|
|
+
|
|
|
LoupGarou.prototype.checkEndOfGame = function() {
|
|
|
var alive = [];
|
|
|
for (var i in this.players) this.players[i].dead === null && alive.push(this.players[i]);
|
|
|
@@ -552,23 +656,20 @@ LoupGarou.prototype.checkEndOfGame = function() {
|
|
|
if (alive.length === 2 && alive[0].lover === alive[1]) {
|
|
|
this.bot.sendMsg(this.room, this.currentScenario.loverWins());
|
|
|
this.bot.sendMsg(this.room, this.currentScenario.congrats(alive.map(i => i.name)));
|
|
|
- this.setStep(STEP.NOT_STARTED);
|
|
|
return true;
|
|
|
}
|
|
|
var liveWolfCount = alive.filter(i => i.role === ROLES.WOLF).length;
|
|
|
if (liveWolfCount === alive.length) {
|
|
|
this.bot.sendMsg(this.room, this.currentScenario.wolfWins());
|
|
|
this.bot.sendMsg(this.room, this.currentScenario.congrats(alive.map(i => i.name)));
|
|
|
- this.setStep(STEP.NOT_STARTED);
|
|
|
return true;
|
|
|
}
|
|
|
if(!liveWolfCount) {
|
|
|
this.bot.sendMsg(this.room, this.currentScenario.villagerWins());
|
|
|
this.bot.sendMsg(this.room, this.currentScenario.congrats(alive.map(i => i.name)));
|
|
|
- this.setStep(STEP.NOT_STARTED);
|
|
|
return true;
|
|
|
}
|
|
|
- this.nextStep();
|
|
|
+ return false;
|
|
|
};
|
|
|
|
|
|
LoupGarou.prototype.advertiseDeath = function(player) {
|