Skip to content

Commit

Permalink
refactor(Player): Change player.role.group to player.side. Closes #…
Browse files Browse the repository at this point in the history
  • Loading branch information
antoinezanardi committed Nov 28, 2020
1 parent c1b50a2 commit 729127f
Show file tree
Hide file tree
Showing 14 changed files with 71 additions and 63 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
### ♻️ Refactoring

* [#74](https://github.com/antoinezanardi/werewolves-assistant-api/issues/74) - During the night, all actions are pushed into the waiting queue instead of predicting them one by one.
* [#76](https://github.com/antoinezanardi/werewolves-assistant-api/issues/76) - Changed `player.role.group` to `player.side`.

### 📚 Documentation

Expand Down
8 changes: 4 additions & 4 deletions config/apidoc/header.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
|   isSeerTalkative | Boolean | If set to `true`, the game master must say out loud what the seer saw during her night, otherwise, he must mime the seen role to the seer. Default is `true`. |
| history | [GameHistory[]](#game-history-class) | Game's history. (_See: [Classes - Game History](#game-history-class)_) |
| **won*** | Object | Winner(s) of the game when status is `done`. |
|   by | String | Can be either a group or a role. (_Possibilities: `werewolves`, `villagers` or null if nobody won_) |
|   by | String | Can be either a group or a role. (_Possibilities: `werewolves`, `villagers`, `lovers` or null if nobody won_) |
| **  players*** | [Player[]](#player-class) | List of player(s) who won. (_See: [Classes - Player](#player-class)_) |
| **review*** | Object | Game master can attach a game review only if its status is set to `canceled` or `done`. |
|   rating | Number | Review's rating, from 0 to 5. |
Expand All @@ -58,7 +58,7 @@
| role | Object | |
|   original | String | Player's Original role when the game started. (_See: [Codes - Player Roles](#player-roles)_) |
|   current | String | Player's current role. (_See: [Codes - Player Roles](#player-roles)_) |
|   group | String | Player's current group. (_Possibilities: [Codes - Player Groups](#player-groups)_) |
| side | String | Player's current side. (_Possibilities: [Codes - Player Groups](#player-sides)_) |
| attributes | Object[] | An attribute is an effect or a status on a player. |
|   attribute | String | Attribute's name on the player. (_Possibilities: [Codes - Player Attributes](#player-attributes)_) |
|   source | String | Which role or group gave this attribute to the player. (_Possibilities: [Codes - Player Roles](#player-roles) or [Codes - Player Groups](#player-groups) or `sheriff`_) |
Expand All @@ -74,14 +74,14 @@
|-------------------------------|:--------:|---------------------------------------------------------------------------------------------------------|
| _id | ObjectId | Role's ID. |
| name | String | Role's name. |
| group | String | Role's group. |
| side | String | Role's original side. |
| **minInGame*** | Number | If the role is chosen by at least one player, then minimum X players must choose it to start the game. |
| maxInGame | Number | Maximum possible of this role in a game. |
| **recommendedMinPlayers*** | Number | It is recommended to have at least X players in game for choosing this role. |

## <a id="game-history-class"></a>📜 Game History

Each time a play is done by anyone or any group, an entry in game's history is saved. Each entry has the following structure:
Each time a play is done by anyone, any group or any side, an entry in game's history is saved. Each entry has the following structure:

| Field | Type | Description |
|----------------------------------|:-------------------------:|------------------------------------------------------------------------|
Expand Down
30 changes: 15 additions & 15 deletions src/controllers/Game.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@ const { generateError, sendError } = require("../helpers/functions/Error");
const { checkRequestData } = require("../helpers/functions/Express");
const {
isVillagerSideAlive, isWerewolfSideAlive, areAllPlayersDead, getPlayersWithAttribute, getPlayersWithRole, getGameTurNightActionsOrder,
areLoversTheOnlyAlive, isGameDone, getPlayerWithRole, getPlayersWithGroup, areAllWerewolvesAlive, getAlivePlayers,
areLoversTheOnlyAlive, isGameDone, getPlayerWithRole, getPlayersWithSide, areAllWerewolvesAlive, getAlivePlayers,
} = require("../helpers/functions/Game");
const { getPlayerAttribute } = require("../helpers/functions/Player");
const { getPlayerRoles } = require("../helpers/functions/Role");
const { getRoles, getGroupNames } = require("../helpers/functions/Role");
const { populate: fullGamePopulate } = require("../helpers/constants/Game");
const { groupNames } = require("../helpers/constants/Role");
const { filterOutHTMLTags } = require("../helpers/functions/String");

exports.getFindPopulate = projection => {
Expand Down Expand Up @@ -57,9 +56,9 @@ exports.fillTickData = game => {
};

exports.checkRolesCompatibility = players => {
if (!players.filter(player => player.role.group === "werewolves").length) {
if (!players.filter(player => player.side === "werewolves").length) {
throw generateError("NO_WEREWOLF_IN_GAME_COMPOSITION", "No player has the `werewolf` role in game composition.");
} else if (!players.filter(player => player.role.group === "villagers").length) {
} else if (!players.filter(player => player.side === "villagers").length) {
throw generateError("NO_VILLAGER_IN_GAME_COMPOSITION", "No player has the `villager` role in game composition.");
} else if (getPlayerWithRole("two-sisters", { players }) &&
players.filter(({ role }) => role.current === "two-sisters").length !== 2) {
Expand All @@ -73,8 +72,9 @@ exports.checkRolesCompatibility = players => {
exports.fillPlayersData = players => {
for (const player of players) {
player.name = filterOutHTMLTags(player.name);
const role = getPlayerRoles().find(playerRole => playerRole.name === player.role);
player.role = { original: role.name, current: role.name, group: role.group };
const role = getRoles().find(playerRole => playerRole.name === player.role);
player.role = { original: role.name, current: role.name };
player.side = role.side;
}
};

Expand Down Expand Up @@ -169,15 +169,15 @@ exports.assignRoleToPlayers = (players, roles) => {
return players;
};

exports.filterAvailablePowerfulVillagerRoles = (roles, players, leftToPick) => roles.filter(role => role.group === "villagers" &&
exports.filterAvailablePowerfulVillagerRoles = (roles, players, leftToPick) => roles.filter(role => role.side === "villagers" &&
role.name !== "villager" && (!role.recommendedMinPlayers || role.recommendedMinPlayers <= players.length) &&
(!role.minInGame || role.minInGame <= leftToPick));

exports.getVillagerRoles = (players, werewolfRoles) => {
const villagerRoles = [];
const villagerCount = players.length - werewolfRoles.length;
const villagerRole = getPlayerRoles().find(role => role.name === "villager");
let availablePowerfulVillagerRoles = getPlayerRoles();
const villagerRole = getRoles().find(role => role.name === "villager");
let availablePowerfulVillagerRoles = getRoles();
for (let i = 0; i < villagerCount; i++) {
const leftToPick = villagerCount - i;
availablePowerfulVillagerRoles = this.filterAvailablePowerfulVillagerRoles(availablePowerfulVillagerRoles, players, leftToPick);
Expand Down Expand Up @@ -226,7 +226,7 @@ exports.getWerewolfCount = players => {
exports.getWerewolfRoles = players => {
const werewolfRoles = [];
const werewolfCount = this.getWerewolfCount(players);
const availableWerewolfRoles = getPlayerRoles().filter(role => role.group === "werewolves");
const availableWerewolfRoles = getRoles().filter(role => role.side === "werewolves");
for (let i = 0; i < werewolfCount; i++) {
werewolfRoles.push(this.pickRandomRole(availableWerewolfRoles));
}
Expand Down Expand Up @@ -301,9 +301,9 @@ exports.checkGameWinners = game => {
} else if (areLoversTheOnlyAlive(game)) {
game.won = { by: "lovers", players: getPlayersWithAttribute("in-love", game) };
} else if (!isVillagerSideAlive(game)) {
game.won = { by: "werewolves", players: game.players.filter(player => player.role.group === "werewolves") };
game.won = { by: "werewolves", players: game.players.filter(player => player.side === "werewolves") };
} else if (!isWerewolfSideAlive(game)) {
game.won = { by: "villagers", players: game.players.filter(player => player.role.group === "villagers") };
game.won = { by: "villagers", players: game.players.filter(player => player.side === "villagers") };
}
game.status = "done";
}
Expand Down Expand Up @@ -351,7 +351,7 @@ exports.isGroupCallableDuringTheNight = (game, group) => {
if (group === "lovers" && getPlayerWithRole("cupid", game)) {
return true;
}
const players = getPlayersWithGroup(group, game);
const players = getPlayersWithSide(group, game);
return game.tick === 1 ? !!players.length : !!players.length && players.some(({ isAlive }) => isAlive);
};
exports.areThreeBrothersCallableDuringTheNight = async game => {
Expand Down Expand Up @@ -388,7 +388,7 @@ exports.isSourceCallableDuringTheNight = (game, source) => {
if (source === "all" || source === "sheriff") {
return true;
}
const sourceType = groupNames.includes(source) ? "group" : "role";
const sourceType = getGroupNames().includes(source) ? "group" : "role";
return sourceType === "group" ? this.isGroupCallableDuringTheNight(game, source) : this.isRoleCallableDuringTheNight(game, source);
};

Expand Down
6 changes: 3 additions & 3 deletions src/controllers/Player.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ exports.checkTargetDependingOnPlay = async(target, game, { source, action }) =>
if (action === "look" && target.player.role.current === "seer") {
throw generateError("CANT_LOOK_AT_HERSELF", "Seer can't see herself.");
} else if (action === "eat") {
if (target.player.role.group === "werewolves") {
if (target.player.side === "werewolves") {
throw generateError("CANT_EAT_EACH_OTHER", `Werewolves target can't be a player with group "werewolves".`);
}
if (source === "big-bad-wolf" && doesPlayerHaveAttribute(target.player, "eaten")) {
Expand Down Expand Up @@ -116,7 +116,7 @@ exports.applyConsequencesDependingOnKilledPlayerAttributes = (player, game) => {
if (doesPlayerHaveAttribute(player, "worshiped")) {
const wildChildPlayer = getPlayerWithRole("wild-child", game);
if (wildChildPlayer && wildChildPlayer.isAlive) {
wildChildPlayer.role.group = "werewolves";
wildChildPlayer.side = "werewolves";
}
}
};
Expand Down Expand Up @@ -279,7 +279,7 @@ exports.dogWolfPlays = (play, game) => {
} else if (play.side === "werewolves") {
const dogWolfPlayer = getPlayerWithRole("dog-wolf", game);
if (dogWolfPlayer) {
dogWolfPlayer.role.group = "werewolves";
dogWolfPlayer.side = "werewolves";
}
}
};
Expand Down
12 changes: 6 additions & 6 deletions src/db/schemas/Player.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const { Schema } = require("mongoose");
const { playerAttributes, playerActions, murderedPossibilities } = require("../../helpers/constants/Player");
const { groupNames, roleNames } = require("../../helpers/constants/Role");
const { sideNames, roleNames } = require("../../helpers/constants/Role");
const { waitingForPossibilities } = require("../../helpers/constants/Game");

const PlayerAttributeSchema = new Schema({
Expand Down Expand Up @@ -69,11 +69,11 @@ const PlayerSchema = new Schema({
enum: roleNames,
required: true,
},
group: {
type: String,
enum: groupNames,
required: true,
},
},
side: {
type: String,
enum: sideNames,
required: true,
},
attributes: {
type: [PlayerAttributeSchema],
Expand Down
32 changes: 16 additions & 16 deletions src/helpers/constants/Role.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,22 @@ exports.roleNames = [

exports.sideNames = ["villagers", "werewolves"];

exports.groupNames = ["villagers", "werewolves", "lovers"];
exports.groupNames = [...this.sideNames, "lovers"];

exports.roles = [
{ name: "villager", group: "villagers", maxInGame: 9 },
{ name: "villager-villager", group: "villagers", maxInGame: 1 },
{ name: "seer", group: "villagers", maxInGame: 1, powers: [{ name: "look" }] },
{ name: "guard", group: "villagers", maxInGame: 1, powers: [{ name: "protect" }] },
{ name: "witch", group: "villagers", maxInGame: 1, powers: [{ name: "use-potion" }] },
{ name: "hunter", group: "villagers", maxInGame: 1, powers: [{ name: "shoot" }] },
{ name: "raven", group: "villagers", maxInGame: 1, powers: [{ name: "mark" }] },
{ name: "little-girl", group: "villagers", maxInGame: 1 },
{ name: "cupid", group: "villagers", maxInGame: 1, powers: [{ name: "charm" }] },
{ name: "two-sisters", group: "villagers", minInGame: 2, maxInGame: 2, recommendedMinPlayers: 12 },
{ name: "three-brothers", group: "villagers", minInGame: 3, maxInGame: 3, recommendedMinPlayers: 15 },
{ name: "wild-child", group: "villagers", maxInGame: 1 },
{ name: "dog-wolf", group: "villagers", maxInGame: 1 },
{ name: "werewolf", group: "werewolves", maxInGame: 4, powers: [{ name: "eat" }] },
{ name: "big-bad-wolf", group: "werewolves", maxInGame: 1, powers: [{ name: "eat" }], recommendedMinPlayers: 12 },
{ name: "villager", side: "villagers", maxInGame: 9 },
{ name: "villager-villager", side: "villagers", maxInGame: 1 },
{ name: "seer", side: "villagers", maxInGame: 1, powers: [{ name: "look" }] },
{ name: "guard", side: "villagers", maxInGame: 1, powers: [{ name: "protect" }] },
{ name: "witch", side: "villagers", maxInGame: 1, powers: [{ name: "use-potion" }] },
{ name: "hunter", side: "villagers", maxInGame: 1, powers: [{ name: "shoot" }] },
{ name: "raven", side: "villagers", maxInGame: 1, powers: [{ name: "mark" }] },
{ name: "little-girl", side: "villagers", maxInGame: 1 },
{ name: "cupid", side: "villagers", maxInGame: 1, powers: [{ name: "charm" }] },
{ name: "two-sisters", side: "villagers", minInGame: 2, maxInGame: 2, recommendedMinPlayers: 12 },
{ name: "three-brothers", side: "villagers", minInGame: 3, maxInGame: 3, recommendedMinPlayers: 15 },
{ name: "wild-child", side: "villagers", maxInGame: 1 },
{ name: "dog-wolf", side: "villagers", maxInGame: 1 },
{ name: "werewolf", side: "werewolves", maxInGame: 4, powers: [{ name: "eat" }] },
{ name: "big-bad-wolf", side: "werewolves", maxInGame: 1, powers: [{ name: "eat" }], recommendedMinPlayers: 12 },
];
8 changes: 4 additions & 4 deletions src/helpers/functions/Game.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
const { patchableGameStatuses, waitingForPossibilities, gameStatuses, turnNightActionsOrder } = require("../constants/Game");
const { doesPlayerHaveAttribute } = require("./Player");

exports.isWerewolfSideAlive = game => game.players.some(player => player.role.group === "werewolves" && player.isAlive);
exports.isWerewolfSideAlive = game => game.players.some(player => player.side === "werewolves" && player.isAlive);

exports.areAllWerewolvesAlive = game => this.getPlayersWithGroup("werewolves", game).every(({ isAlive }) => isAlive);
exports.areAllWerewolvesAlive = game => this.getPlayersWithSide("werewolves", game).every(({ isAlive }) => isAlive);

exports.isVillagerSideAlive = game => game.players.some(player => player.role.group === "villagers" && player.isAlive);
exports.isVillagerSideAlive = game => game.players.some(player => player.side === "villagers" && player.isAlive);

exports.areAllPlayersDead = game => game.players.every(player => !player.isAlive);

Expand Down Expand Up @@ -34,6 +34,6 @@ exports.getPlayerWithRole = (roleName, game) => game.players.find(({ role }) =>

exports.getPlayersWithRole = (roleName, game) => game.players.filter(({ role }) => role.current === roleName);

exports.getPlayersWithGroup = (groupName, game) => game.players.filter(({ role }) => role.group === groupName);
exports.getPlayersWithSide = (sideName, game) => game.players.filter(({ side }) => side === sideName);

exports.getAlivePlayers = game => game.players.filter(({ isAlive }) => isAlive);
8 changes: 5 additions & 3 deletions src/helpers/functions/Role.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
const { roles, sideNames } = require("../constants/Role");
const { roles, sideNames, groupNames } = require("../constants/Role");

exports.getPlayerRoles = () => JSON.parse(JSON.stringify(roles));
exports.getRoles = () => JSON.parse(JSON.stringify(roles));

exports.getSideNames = () => JSON.parse(JSON.stringify(sideNames));
exports.getSideNames = () => JSON.parse(JSON.stringify(sideNames));

exports.getGroupNames = () => JSON.parse(JSON.stringify(groupNames));
Loading

0 comments on commit 729127f

Please sign in to comment.