You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

573 lines
18 KiB
JavaScript

/*
WARNING: THIS IS STILL EXPERIMENTAL STUFF
I want to have the ability to assign specific behaviors to each room without messing with the main engine
So I'm creating a module for server-side modifications (mods). There is one also for the client.
Their naming convention is roomIdFunction.
The functions are called by the engine at crucial points, only if they exist.
*/
//called at the beginning
module.exports.initMod = function (io, gameState, DATA) {
console.log("MOD: Initialized");
//EVERYTHING GLOBALLLLL
global.rita = require('rita');
global.gameState = gameState;
global.io = io;
global.DATA = DATA;
//family room roles
global.familyRoles = {
wife: "",
husband: "", //id of player
child1: "",
child2: "",
child3: "",
uncle: "",
milkman: "",
boyfriend: ""
};
global.lastRhymes = [];
global.rhymingPlayers = {};
global.beatPlaying = false;
global.paranoidTalk = [
"Hey you",
"There are bots in here",
"Are you a bot?",
"Russia is controlling the bots",
"Are you real?",
"Yes",
"I don't trust you",
"This is weird",
"Prove you are human",
"No",
"Have you seen that?",
"That person is a bot",
"Listen",
"Bots everywhere",
"Hello",
"Another bot"
];
//load extended dictionary, this is 3Mb but only sits on the server and it's used by only one room
const fs = require('fs');
global.dictionary = fs.readFileSync('dictionary.json');
//cycle through contraints in the consonant room
global.consonant = 0;
setInterval(function () {
global.consonant++;
//aeiou-
if (global.consonant > 5) {
global.consonant = 0;
}
var msg = "";
if (global.consonant == 0) //a
msg = "All art appalls a fan";
if (global.consonant == 1) //e
msg = "Greet her when she enters";
if (global.consonant == 2) //i
msg = "I sit ildly till twilight";
if (global.consonant == 3) //o
msg = "No stools, no books: work protocol";
if (global.consonant == 4) //u
msg = "But truth: dull suburbs turn fun";
if (global.consonant == 5) //none
msg = "Tsk, tsk... try my rhythms";
//sends a message to the room
io.to("cnsnntrm").emit('nonPlayerTalked', { id: "", labelColor: "#3e7eb0", room: "cnsnntrm", message: msg, x: 36, y: 56 });
}, 60 * 1000); //every minute changes
//global function ffs
global.random = function (min, max) {
return Math.random() * (max - min) + min;
}
//Example of NPC creation and behavior
var npc = new NPC(
{
id: "paranoid",
nickName: "Anonymous",
room: "secondFloor",
x: 23,
y: 78,
avatar: 1,
colors: [2, 2, 1, 5],
labelColor: "#1e839d"
});
npc.behavior = setTimeout(function ramble() {
var dice = random(0, 100);
if (dice < 40) {
npc.talk(global.paranoidTalk[Math.floor(random(0, global.paranoidTalk.length - 1))]);
npc.behavior = setTimeout(ramble, random(7000, 9000));
}
else if (dice < 60) {
npc.move(random(17, 113) * 2, random(76, 98) * 2);
npc.behavior = setTimeout(ramble, random(4000, 8000));
}
else {
//just wait
npc.behavior = setTimeout(ramble, random(1000, 3000));
//to kill the bot
//clearTimeout(npc.behavior);
//npc.delete();
}
}, random(1000, 2000));
global.VIPList = [];
}
//custom function called on the server side when a player successfully enters or exits the room
//executed before it's broadcast to the other players
module.exports.experimentsJoin = function (player, roomId) {
//console.log("MOD: " + player.nickName + " entered room " + roomId);
}
module.exports.experimentsLeave = function (player, roomId) {
//console.log("MOD: " + player.nickName + " exited room " + roomId);
}
//wouldn't it be funny if cetain rooms modified your messages?
module.exports.experimentsTalkFilter = function (player, message) {
//console.log("MOD: " + player.nickName + " said " + message);
//message = message.replace(/[aeiou]/ig, '');
//make sure it returns a message
return message;
}
//wouldn't it be funny if cetain rooms modified your messages?
module.exports.VIPRoomTalkFilter = function (player, message) {
//console.log("MOD: " + player.nickName + " said " + message);
message = global.rita.getPhonemes(message);
message = message.replace(/-/g, "");
//make sure it returns a message
return message;
}
//wouldn't it be funny if cetain rooms modified your messages?
module.exports.cnsnntrmTalkFilter = function (player, message) {
//console.log("MOD: " + player.nickName + " said " + message);
if (global.consonant == 0) //a
message = message.replace(/[eiou]/ig, 'a');
if (global.consonant == 1) //e
message = message.replace(/[aiou]/ig, 'e');
if (global.consonant == 2) //i
message = message.replace(/[aeou]/ig, 'i');
if (global.consonant == 3) //o
message = message.replace(/[aeiu]/ig, 'o');
if (global.consonant == 4) //u
message = message.replace(/[aeio]/ig, 'u');
if (global.consonant == 5) //none
message = message.replace(/[aeiou]/ig, '');
//make sure it returns a message
return message;
}
//words can only be used once
module.exports.censorshipRoomTalkFilter = function (player, message) {
//create a list of censored words
if (global.forbiddenWords == null) {
global.forbiddenWords = [];
}
//strip special characters
message = message.replace(/[`~!@#$%^&*()_|+\-=?;:",.<>\{\}\[\]\\\/]/gi, '');
//break down the message into words
var words = message.split(" ");
var censoredMessage = "";
//check each single word
for (var j = 0; j < words.length; j++) {
/*
//remove repeated character if they occur more than twice like hellooooo > hello
var word = words[j];
var pChar = "";
var ppChar = "";
var newWord = "";
for (var k = 0; k < word.length; k++) {
var newChar = word[k];
if (pChar == "" || ppChar == "" || !(newChar == ppChar && newChar == pChar)) {
newWord += newChar;
}
ppChar = pChar;
pChar = newChar;
}
*/
var newWord = words[j];
//found, censor
if (forbiddenWords.indexOf(newWord.toLowerCase()) > -1) {
var l = newWord.length;
var bleep = "";
for (var i = 0; i < l; i++) {
bleep += "*";
}
censoredMessage += bleep;
}
else {
censoredMessage += newWord;
//not found add
forbiddenWords.push(newWord.toLowerCase());
}
if (j < words.length - 1)
censoredMessage += " ";
}
return censoredMessage;
}
module.exports.rhymeRoomTalkFilter = function (player, message) {
//
if (global.beat == null)
global.beat = 1;
var arr = message.split(" ");
var lastWord = "";
if (arr.length > 0)
lastWord = arr[arr.length - 1].toLowerCase();
//extended dictionary
var exists = global.dictionary.indexOf(lastWord) != -1;
var first = false;
var lastRhyme = "";
var used = false;
if (global.lastRhymes.length == 0)
first = true;
else {
used = global.lastRhymes.indexOf(lastWord) != -1;
lastRhyme = global.lastRhymes[global.lastRhymes.length - 1].toLowerCase();
}
if (exists && !used) {
var rhymes = false;
//not first check the rhym
if (!first)
rhymes = global.rita.isRhyme(lastWord, lastRhyme);
//start the battle
if (first || rhymes) {
if (global.beatPlaying == false) {
io.to("rhymeRoom").emit('musicOn', global.beat);
global.beatPlaying = true;
}
global.lastRhymes.push(lastWord);
//create the rhyming player score
if (global.rhymingPlayers[player.nickName] == null)
global.rhymingPlayers[player.nickName] = 0;
//calculate the score by counting the real words
//skip the first
if (global.lastRhymes.length > 1) {
for (var i = 0; i < arr.length; i++) {
if (global.rita.containsWord(arr[i]))
global.rhymingPlayers[player.nickName]++;
}
}
//console.log("YEAH " + player.nickName + " " + lastWord + "! Words uttered " + global.rhymingPlayers[player.nickName]);
clearTimeout(global.rhymeTime);
global.rhymeTime = setTimeout(function () {
//console.log("Rhyme timeout");
//send to everybody in the room
io.to("rhymeRoom").emit('musicOff');
global.beatPlaying = false;
//change record
global.beat++;
if (global.beat > 3)
global.beat = 1;
var highscore = 0;
var winner = "";
//find high score
for (var nn in global.rhymingPlayers) {
if (global.rhymingPlayers[nn] >= 4 && global.rhymingPlayers[nn] > highscore) {
winner = nn;
highscore = global.rhymingPlayers[nn];
}
}
global.lastRhymes = [];
global.rhymingPlayers = {};
if (winner != "") {
io.to("rhymeRoom").emit('godMessage', winner + " wins!" + highscore + " words uttered");
}
}, 8000);
return message;
}//doesn't ryme
else {
return "...";
}
}//doesn't exist
else {
return "...";
}
}
//if enters when music is playing sent
module.exports.rhymeRoomJoin = function (playerObject, roomId) {
if (io.sockets.sockets[playerObject.id] != null && global.beatPlaying) {
io.sockets.sockets[playerObject.id].emit('musicEnter', global.beat);
}
}
//if enters when music is playing sent
module.exports.rhymeRoomLeave = function (playerObject, roomId) {
if (io.sockets.sockets[playerObject.id] != null) {
io.sockets.sockets[playerObject.id].emit('musicExit');
}
}
module.exports.darkRoomTalkFilter = function (player, message) {
//I should declare them at the init but whatev
var nouns = ["ass", "climax", "coitus", "boner", "booty", "threesome", "tush", "lust", "orgy", "libido", "dildo", "kink",
"porno", "buttplug", "cunnilingus", "cybersex", "sex", "cum", "orgasm", "quickie", "intercourse", "cock", "penis", "dick", "pussy", "fanny", "vagina", "clit", "butt"];
var verbs = ["love", "shag", "mate", "seduce", "hook up", "hump", "arouse", "fornicate", "erect", "get some", "bone", "bang", "fuck", "lick", "suck", "cum", "penetrate", "screw", "sodomize", "arouse", "kiss", "pet", "masturbate", "come"];
var arr = rita.tokenize(message);
var replaced = false;
for (var i = 0; i < arr.length && !replaced; i++) {
var word = arr[i];
//skip verbs 50% since they are more likely to come before nouns
if (rita.isVerb(word) && Math.random() < 0.5) {
arr[i] = rita.randomItem(verbs);
replaced = true;
}
if (rita.isNoun(word)) {
arr[i] = rita.randomItem(nouns);
replaced = true;
}
}
return arr.join(" ");
}
//player enters family room roles are assigned by the server
module.exports.familyRoomJoin = function (playerObject, roomId) {
var foundRole = false;
for (var roleId in global.familyRoles) {
//role not assigned
if (global.familyRoles[roleId] == "" && !foundRole) {
foundRole = true;
global.familyRoles[roleId] = playerObject.id;
console.log(playerObject.id + " becomes " + roleId);
}
}
if (!foundRole)
console.log(playerObject.id + " becomes a fly");
//assign a new role and send all the roles to the room
io.to("familyRoom").emit('updateRoles', playerObject.id, global.familyRoles);
//io.to("familyRoom").emit('assignRole', { id: playerObject.id, roleId: "wife", roleLabel: "Wife", rolePrompt: "You are feeling frustrated" });
//send the existing roles
}
//exit > free up the role
//player enters family room roles are assigned by the server
module.exports.familyRoomLeave = function (playerObject, roomId) {
for (var roleId in global.familyRoles) {
//role not assigned
if (global.familyRoles[roleId] == playerObject.id) {
global.familyRoles[roleId] = "";
console.log(roleId + " is now free");
}
}
//I don't need to send updated roles
//io.to("familyRoom").emit('updateRoles', playerObject.id, global.familyRoles);
}
//mute spectators on the server-side
module.exports.familyRoomTalkFilter = function (player, message) {
var spectator = true;
for (var roleId in global.familyRoles) {
//role assigned
if (global.familyRoles[roleId] == player.id) {
spectator = false;
}
}
if (spectator)
return "zzzz";
else
return message;
}
module.exports.VIPRoomJoin = function (playerObject, roomId) {
//console.log(playerObject.nickName + " enters the VIP room");
//...
global.VIPList.push(playerObject.id);
if (global.VIPList.length > 3) {
var expelled = global.VIPList.shift();
//force leave
if (io.sockets.sockets[expelled] != null) {
this.transferPlayer(expelled, "VIPRoom", "likelikeOutside", 121 * 2, 89 * 2);
io.to(expelled).emit('godMessage', "Sorry, we had to expel you to make room for " + playerObject.nickName);
}
}
}
module.exports.VIPRoomIntro = function (newComerId, introObj) {
//the problem with the auto expulsion in VIPRoom is that the intro is sent before it's the other person is expelled
//so the intros arrive too late creating ghosts.
//since the server has the real list I can override the intro after the fact and expel the ghost. Ugly but necessary.
//console.log("Obsolete intro? " + gameState.players[introObj.id].room);
if (gameState.players[introObj.id].room != "VIPRoom")
io.to("VIPRoom").emit("playerLeft", { id: introObj.id, room: "VIPRoom", disconnect: false });
}
//force change room
module.exports.transferPlayer = function (playerId, from, to, x, y) {
//console.log(playerId + " is transfered to " + to);
var s = io.sockets.sockets[playerId];
var p = gameState.players[playerId];
if (s != null)
if (p.room != null) {
//var from = p.room;
s.leave(from);
s.join(to);
//broadcast the change to everybody in the current room
//from the client perspective leaving the room is the same as disconnecting
io.to(from).emit("playerLeft", { id: playerId, room: from, disconnect: false });
//same for joining, sending everybody in the room the player state
p.room = to;
p.x = p.destinationX = x;
p.y = p.destinationY = y;
p.new = false;
//check if there is a custom function in the MOD to call at this point
if (this[from + "Leave"] != null) {
//call it!
this[from + "Leave"](p, from);
}
io.to(to).emit("playerJoined", p);
//check if there is a custom function in the MOD to call at this point
if (this[to + "Join"] != null) {
//call it!
this[to + "Join"](p, to);
}
//check if there are NPCs in this room and make them send info to the player
for (var NPCId in gameState.NPCs) {
var npc = gameState.NPCs[NPCId];
if (npc.room == to) {
npc.sendIntroTo(playerId);
}
}
}
}
//if a player leaves the room on their own accord make sure they are removed from the list as well
module.exports.VIPRoomLeave = function (playerObject, roomId) {
//console.log(playerObject.nickName + " exits the VIP room");
var index = global.VIPList.indexOf(playerObject.id);
if (index !== -1) {
global.VIPList.splice(index, 1);
}
}
//a client can send generic action request to the server
//the action logic is defined in functions named "on"+ActionId like this one
//I don't want a hacked client to be able to call whatever function exists on the server mod hence the naming
//and I want send only an id without arguments to force all my logic here on the server side
module.exports.onTVInteract = function (pId) {
//console.log("Action onTVInteract called by " + pId);
//a persistent change to the game state: change the DATA sent to the new players
//*persistent until server restarts
var TVState = !DATA.ROOMS.familyRoom.things.TV.visible;
//change the visibility
DATA.ROOMS.familyRoom.things.TV.visible = TVState;
//send a thing update too ALL clients, changing the client data and telling them to delete and recreate the sprite if they are in the room
io.sockets.emit("thingChanged", { thingId: "TV", room: "familyRoom", property: "visible", value: TVState });
}