Basic bot support and option to change opening text

This commit is contained in:
Cam Spry committed 2026-03-01 08:10:35 -05:00
1 parent 7bc9d67544
commit 499a5954f5
7 files changed
+264 -13

No files matched your search

+75 -11
View File
@@ -5,6 +5,7 @@ const path = require('path');
const cookieParser = require('cookie-parser');
//const { v4: uuidv4 } = require('uuid');
const { randomUUID } = require('node:crypto');
const BotFactory = require('./bots/BotFactory');
const app = express();
const server = http.createServer(app);
@@ -25,8 +26,10 @@ class YarnGame {
this.gameSettings = {
scoreLimit: 50,
timeLimit: 60,
botCount: 0
botCount: 0,
startText: "It was a dark and stormy night..."
};
this.bots = [];
this.players = []; // { player_id, name, score, socketId }
this.disconnectedPlayers = []; // So people can keep their score when they reconnect
this.yarnStory = []; // { player: "", str: "" }
@@ -78,20 +81,23 @@ class YarnGame {
removePlayer(playerId) {
const index = this.players.findIndex(p => p.player_id === playerId);
if (index !== -1) {
console.log(`Player ${this.players[index].name} dropped.`)
const removed = this.players.splice(index, 1);
this.disconnectedPlayers.push(removed[0]);
// Assign new host if host left
if (this.gameHost === playerId && this.players.length > 0) {
this.gameHost = this.players[0].player_id;
if (this.gameHost === playerId && this.getHumanPlayers().length > 0) {
const human_players = this.getHumanPlayers();
this.gameHost = human_players[0].player_id;
}
}
if (this.players.length > 0) {
console.log(`Player ${this.players[index].name} dropped.`)
}
return this.players.length;
}
getHumanPlayers() {
return this.players.filter(p => !this.bots.some(b => b.bot_id === p.player_id));
}
getPlayer(playerId) {
return this.players.find(p => p.player_id === playerId);
}
@@ -107,19 +113,49 @@ class YarnGame {
}
}
startBots(botCount) {
console.log("Creating bots...")
for (let i = 0; i < botCount; i++) {
const bot_id = randomUUID()
const bot = BotFactory.createBot("random");
this.bots.push({ bot_id, bot });
const bot_player = {
player_id: bot_id,
name: BotFactory.generateBotName(),
score: 0,
socketId: null
};
this.players.push(bot_player);
console.log(`Created bot with UUID ${bot_id}`)
}
}
startGame(settings) {
this.gameSettings = { ...this.gameSettings, ...settings };
this.startBots(this.gameSettings.botCount);
this.inProgress = true;
this.yarnStory = [{ player: "Narrator", str: "It was a dark and stormy night..." }];
this.yarnStory = [{ player: "Narrator", str: this.gameSettings.startText }];
this.players.forEach(p => p.score = 0);
this.startWritingPhase();
}
processBotWriting() {
for (const botObj of this.bots) {
const botText = botObj.bot.Write(this.getStoryText());
this.submitEntry(botObj.bot_id, botText)
}
}
startWritingPhase() {
this.currentPhase = 'writing';
this.round_data = [];
this.submittedPlayers = new Set();
this.timeRemaining = this.gameSettings.timeLimit;
this.processBotWriting()
}
getStoryText() {
return this.yarnStory.map(entry => entry.str).join('');
}
submitEntry(playerId, entryText) {
@@ -140,10 +176,18 @@ class YarnGame {
return this.submittedPlayers.size >= this.players.length;
}
processBotVoting() {
for (const botObj of this.bots) {
const botVote = botObj.bot.Vote(this.getStoryText(), this.round_data);
this.submitVote(botObj.bot_id, botVote)
}
}
startVotingPhase() {
this.currentPhase = 'voting';
this.votedPlayers = new Set();
this.timeRemaining = 30; // 30 seconds for voting
this.processBotVoting()
}
submitVote(playerId, entryIndex) {
@@ -203,9 +247,17 @@ class YarnGame {
return null;
}
purgeBots() {
for (const botObj of this.bots) {
this.removePlayer(botObj.bot_id)
}
this.bots = [];
}
resetGame() {
this.inProgress = false;
this.currentPhase = 'lobby';
this.purgeBots();
this.round_data = [];
this.yarnStory = [];
this.submittedPlayers = new Set();
@@ -216,6 +268,18 @@ class YarnGame {
}
}
botBanter() {
for (const botObj of this.bots) {
if (Math.random() > 0.8) {
console.log("Bot bantering")
const botBanter = botObj.bot.Banter(this.getStoryText());
console.log(botBanter)
const chatMsg = this.addChatMessage(botObj.bot_id, botBanter)
io.to(this.roomName).emit('newChatMessage', chatMsg); //I don't like using io calls here but chat is weird
}
}
}
addChatMessage(playerId, msg) {
const player = this.getPlayer(playerId);
const chatMsg = {
@@ -331,7 +395,7 @@ io.on('connection', (socket) => {
const game = games[currentRoom];
if (!game || game.gameHost !== playerId) return;
if (game.players.length < 2) {
if (game.players.length < 2 && settings.botCount == 0) {
socket.emit('error', { message: 'Need at least 2 players to start' });
return;
}
@@ -422,9 +486,9 @@ io.on('connection', (socket) => {
io.to(currentRoom).emit('playersUpdate', game.getState().players);
io.to(currentRoom).emit('gameState', game.getState());
// Clean up empty rooms
console.log(`Removing empty room ${currentRoom}`)
if (remaining === 0) {
if (remaining === 0 || game.bots.length === game.players.length) {
// Clean up empty rooms
console.log(`Removing empty room ${currentRoom}`)
if (game.timer) clearInterval(game.timer);
delete games[currentRoom];
}