Skip to content

Commit

Permalink
Mass Hysteria + Volcano Events + Butterfly Philsopher bug fix. (#1847)
Browse files Browse the repository at this point in the history
Volcano: a random player will die every 30 Seconds until the day ends.

Mass Hysteria: Everyone gains the Frustrated Modifier for 1 day

A Philsopher that turns into butterfly no longer breaks the game

---------

Co-authored-by: SawJester <SawJester@users.noreply.github.com>
  • Loading branch information
SawJester and SawJester authored Jan 21, 2025
1 parent 120b3bc commit 24f245a
Show file tree
Hide file tree
Showing 9 changed files with 238 additions and 8 deletions.
2 changes: 1 addition & 1 deletion Games/types/Mafia/Game.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ module.exports = class MafiaGame extends Game {

this.queueAction(actionVisit);
}
if (this.getStateName() == "Night" && this.PossibleEvents.length > 0) {
if (this.getStateName() == "Night" && this.CurrentEvents.length > 0) {
this.selectedEvent = false;
/*
this.alivePlayers()[0].holdItem("EventManager", 1);
Expand Down
80 changes: 80 additions & 0 deletions Games/types/Mafia/effects/Frustrated.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
const Effect = require("../Effect");
const Action = require("../Action");
const { PRIORITY_OVERTHROW_VOTE } = require("../const/Priority");

module.exports = class Frustrated extends Effect {
constructor(lifespan) {
super("Frustrated");
this.lifespan = lifespan || Infinity;
this.immunity["condemn"] = 3;

this.listeners = {
state: function (stateInfo) {
if (!this.player.alive) {
return;
}

if (!stateInfo.name.match(/Day/)) {
return;
}

var action = new Action({
actor: this.player,
game: this.player.game,
priority: PRIORITY_OVERTHROW_VOTE - 3,
labels: ["hidden", "absolute"],
run: function () {
//if (this.game.getStateName() != "Day" && this.game.getStateName() != "Dusk") return;

let villageMeeting = this.game.getMeetingByName("Village");

//New code
const voteCounts = Object.values(villageMeeting.votes).reduce(
(acc, vote) => {
acc[vote] = (acc[vote] || 0) + 1;
return acc;
},
{}
);

const minVotes = Math.min(...Object.values(voteCounts));
const maxVotes = Math.max(...Object.values(voteCounts));

if (
voteCounts[this.actor.id] !== minVotes ||
voteCounts[this.actor.id] === maxVotes ||
voteCounts[this.actor.id] === 0
) {
return;
}

for (let action of this.game.actions[0]) {
if (action.hasLabel("condemn") && !action.hasLabel("overthrow")) {
// Only one village vote can be overthrown
action.cancel(true);
break;
}
}

let action = new Action({
actor: this.actor,
target: this.actor,
game: this.game,
labels: ["kill", "frustration", "hidden"],
power: 3,
run: function () {
this.game.sendAlert(
`${this.target.name} feels immensely frustrated!`
);
if (this.dominates()) this.target.kill("basic", this.actor);
},
});
action.do();
},
});

this.game.queueAction(action);
},
};
}
};
55 changes: 55 additions & 0 deletions Games/types/Mafia/effects/Volcanic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
const Effect = require("../Effect");
const Action = require("../Action");
const Random = require("../../../../lib/Random");

module.exports = class Volcanic extends Effect {
constructor(lifespan) {
super("Volcanic");
this.lifespan = lifespan;

this.listeners = {
state: function (stateInfo) {
if (!stateInfo.name.match(/Day/)) {
return;
}
this.game.events.emit("Volcano");
},
Volcano: function () {
if (this.timer) {
return;
}

let toDetonate = 30000;
this.timer = setTimeout(() => {
if (this.game.finished) {
return;
}

let players = this.game.alivePlayers();
this.target = Random.randArrayVal(players);

let action = new Action({
target: this.target,
game: this.target.game,
labels: ["kill", "bomb"],
run: function () {
this.game.queueAlert(
`The Volcano erupts hiting ${this.target.name} with a molten rock.`
);
if (this.dominates()) this.target.kill("bomb", this.target, true);
},
});

this.game.instantAction(action);
this.timer = null;
this.game.events.emit("Volcano");
}, toDetonate);

let toDetonateSound = toDetonate - 1800;
this.soundTimer = setTimeout(() => {
this.game.broadcast("explosion");
}, toDetonateSound);
},
};
}
};
40 changes: 40 additions & 0 deletions Games/types/Mafia/events/MassHysteria.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
const Event = require("../Event");
const Action = require("../Action");
const Random = require("../../../../lib/Random");
const {
PRIORITY_EFFECT_GIVER_DEFAULT,
PRIORITY_BECOME_DEAD_ROLE,
} = require("../const/Priority");

module.exports = class MassHysteria extends Event {
constructor(modifiers, game) {
super("Mass Hysteria", modifiers, game);
}

getNormalRequirements() {
return true;
}

doEvent() {
super.doEvent();
let victim = Random.randArrayVal(this.game.alivePlayers());
this.action = new Action({
actor: victim,
target: victim,
game: this.game,
priority: PRIORITY_EFFECT_GIVER_DEFAULT,
labels: ["hidden", "absolute"],
run: function () {
if (this.game.SilentEvents != false) {
this.game.queueAlert(
`Event: Mass Hysteria, All players have Frustrated Modifier today!`
);
}
for (const player of this.game.players) {
player.giveEffect("Frustrated", 1);
}
},
});
this.game.queueAction(this.action);
}
};
39 changes: 39 additions & 0 deletions Games/types/Mafia/events/Volcano.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
const Event = require("../Event");
const Action = require("../Action");
const Random = require("../../../../lib/Random");
const {
PRIORITY_EFFECT_GIVER_DEFAULT,
PRIORITY_BECOME_DEAD_ROLE,
} = require("../const/Priority");

module.exports = class Volcano extends Event {
constructor(modifiers, game) {
super("Volcano", modifiers, game);
}

getNormalRequirements() {
return true;
}

doEvent() {
super.doEvent();
let victim = Random.randArrayVal(this.game.alivePlayers());
this.action = new Action({
actor: victim,
target: victim,
game: this.game,
priority: PRIORITY_EFFECT_GIVER_DEFAULT,
labels: ["hidden", "absolute"],
run: function () {
if (this.game.SilentEvents != false) {
this.game.queueAlert(
`Event: Volcano, A RANDOM PLAYER WILL DIE EVERY 30 SECONDS UNTIL THE DAY ENDS!`
);
}

this.actor.giveEffect("Volcanic", 1);
},
});
this.game.queueAction(this.action);
}
};
6 changes: 3 additions & 3 deletions Games/types/Mafia/roles/cards/MeetingTurkey.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ module.exports = class MeetingTurkey extends Card {
this.listeners = {
roleAssigned: function (player) {
if (player != this.player) return;

if (
!this.game.CurrentEvents.map((e) => e.split(":")[0]).includes(
"Famine"
)
this.game.CurrentEvents.filter((e) => e.split(":")[0] == "Famine")
.length <= 0
) {
this.game.CurrentEvents.push("Famine");
}
Expand Down
5 changes: 3 additions & 2 deletions Games/types/Mafia/roles/cards/ResetRolesOnDeath.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ module.exports = class ResetRolesOnDeath extends Card {
for (let _player of this.game.players) {
if (_player.alive) {
_player.setRole(
this.data.originalRoles[_player.name],
this.game.originalRoles[_player.id],
_player.role.data
);
}
}
},
start: function () {
roleAssigned: function (player) {
if (player != this.player) return;
this.data.originalRoles = {};
for (let player of this.game.players) {
this.data.originalRoles[
Expand Down
4 changes: 2 additions & 2 deletions data/modifiers.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const modifierData = {
Astral: {
internal: ["Astral"],
tags: ["Visits", "Astral"],
description: "All actions done by this player do not appear as visits.",
description: "All actions done by this player are not visits.",
},
Backup: {
internal: ["BackUpModifier"],
Expand Down Expand Up @@ -269,7 +269,7 @@ const modifierData = {
internal: ["ModifierLone"],
tags: ["Lone"],
description:
"If this role typically has a group meeting at night, they will not meet with or know the identity of their partner(s). Can join their regular meeting, at the cost of their role.",
"If this role typically has a group meeting at night, they will not meet with or know the identity of their partner(s).",
},
Loud: {
internal: ["ModifierLoud"],
Expand Down
15 changes: 15 additions & 0 deletions data/roles.js
Original file line number Diff line number Diff line change
Expand Up @@ -3789,6 +3789,14 @@ const roleData = {
"If this Event occurs, all speech and votes are anonymous.",
],
},
"Mass Hysteria": {
alignment: "Event",
tags: ["Event"],
description: [
"If this Event occurs, all are Frustrated for 1 day.",
"Frustrated players cannot be condemned by majority vote. A non-zero minority vote will kill a frustrated player.",
],
},
"Sensible Mood": {
alignment: "Event",
tags: ["Event"],
Expand All @@ -3811,6 +3819,13 @@ const roleData = {
"Kites can be used to kill a random player with the same alignment as the user.",
],
},
Volcano: {
alignment: "Event",
tags: ["Event"],
description: [
"If this Event occurs, a random player will die every 30 Seconds until the day ends.",
],
},
},

Resistance: {
Expand Down

0 comments on commit 24f245a

Please sign in to comment.