from npc import NPC import random, re, json from flask_socketio import emit """ 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. """ # family room roles # values are id's of player familyRoles = { 'wife': "", 'husband': "", 'child1': "", 'child2': "", 'child3': "", 'uncle': "", 'milkman': "", 'boyfriend': "" } lastRhymes = [] rhymingPlayers = {} beatPlaying = False 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" ]; with open("dictionary.json") as fin: dictionary = json.load(fin) # cycle through contraints in the consonant room consonant = 0 def random_between (min, max): return random.random() * (max-min) + min VIPList = [] def initMod (io, gameState, DATA, taskmaster): """ called at the beginning """ return print("MOD: Initialized"); # EVERYTHING GLOBALLLLL # global.rita = require('rita'); # global.gameState = gameState; # global.io = io; # global.DATA = DATA; # //global function ffs # global.random = function (min, max) { # return Math.random() * (max - min) + min; # } # Example of NPC creation and behavior npc = NPC(io, { 'id': "paranoid", 'nickName': "Anonymous", 'room': "secondFloor", 'x': 23, 'y': 78, 'avatar': 1, 'colors': [2, 2, 1, 5], 'labelColor': "#1e839d" }, gameState) def ramble(): print ("ramble") dice = random_between(0, 100) if (dice < 40): npc.talk(random.choice(paranoidTalk)) npc.behavior = taskmaster.setTimeout(ramble, random_between(7000, 9000)) elif (dice < 60): npc.move(random_between(17, 113) * 2, random_between(76, 98) * 2) npc.behavior = taskmaster.setTimeout(ramble, random_between(4000, 8000)) else: # just wait npc.behavior = taskmaster.setTimeout(ramble, random_between(1000, 3000)); # to kill the bot # clearTimeout(npc.behavior) # npc.delete() npc.behavior = taskmaster.setTimeout(ramble, random_between(1000, 2000)) def consonant_interval(): global consonant print (f"consonant_interval: {consonant}") # aeiou- consonant+=1 if (consonant > 5): consonant = 0 msg = "" if (consonant == 0): # a msg = "All art appalls a fan" elif (consonant == 1): # e msg = "Greet her when she enters" elif (consonant == 2): # i msg = "I sit ildly till twilight" elif (consonant == 3): # o msg = "No stools, no books: work protocol" elif (consonant == 4): # u msg = "But truth: dull suburbs turn fun" elif (consonant == 5): # none msg = "Tsk, tsk... try my rhythms" # sends a message to the room io.emit('nonPlayerTalked', { 'id': "", 'labelColor': "#3e7eb0", 'room': "cnsnntrm", 'message': msg, 'x': 36, 'y': 56 }, room="cnsnntrm") taskmaster.setInterval(consonant_interval, 60*1000) # 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 def experimentsJoin(player, roomId): # print("MOD: " + player.nickName + " entered room " + roomId) pass def experimentsLeave(player, roomId): # print("MOD: " + player.nickName + " exited room " + roomId) pass def experimentsTalkFilter(player, message): """ wouldn't it be funny if cetain rooms modified your messages? """ # print("MOD: " + player.nickName + " said " + message); # message = re.sub('[aeiou]', '', message, flags=re.I) # make sure it returns a message return message # # wouldn't it be funny if cetain rooms modified your messages? # def VIPRoomTalkFilter(player, message): # # print("MOD: " + player.nickName + " said " + message); # message = 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? # def cnsnntrmTalkFilter(player, message): # # print("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 }); # }