309 lines
9.3 KiB
JavaScript
309 lines
9.3 KiB
JavaScript
/*
|
|
fore.st is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
fore.st is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with fore.st. If not, see < http://www.gnu.org/licenses/ >.
|
|
(C) 2022- by rainbownapkin, <ourforest@420blaze.it>
|
|
*/
|
|
import fs from 'fs';
|
|
|
|
var ChannelModule = require("./module");
|
|
|
|
//global vars
|
|
var tokes = loadTokes();
|
|
var solotokes = ["", "https://ourfore.st/img/femotes/onetoker.jpg","https://ourfore.st/img/femotes/solotoke.jpg","https://ourfore.st/img/femotes/1toker.gif"];
|
|
|
|
//global functions
|
|
function loadTokes(){//load tokes as array from file
|
|
const rawContents = fs.readFileSync("tokebot/tokes").toString('utf8');
|
|
var spcReg = /^\s*$/g;
|
|
var t = rawContents.split("\n").filter(function(i){
|
|
return !spcReg.test(i);
|
|
});
|
|
return t;
|
|
}
|
|
|
|
//used to store ES6 maps as arrays in JSON
|
|
function mapReplacer(key, value) {
|
|
if(value instanceof Map) {
|
|
return {
|
|
dataType: 'Map',
|
|
value: Array.from(value.entries()), // or with spread: value: [...value]
|
|
};
|
|
} else {
|
|
return value;
|
|
}
|
|
}
|
|
|
|
function mapReviver(key, value) {
|
|
if(typeof value === 'object' && value !== null) {
|
|
if (value.dataType === 'Map') {
|
|
return new Map(value.value);
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
|
|
function randi(len) {//get random number from zero to len, meant for use to pull random items from an array
|
|
return Math.floor(Math.random() * len); //The maximum is exclusive and the minimum is inclusive
|
|
}
|
|
|
|
|
|
//constructor
|
|
function TokebotModule(_channel){
|
|
ChannelModule.apply(this, arguments);
|
|
|
|
//mod command registration
|
|
this.channel.modules.chat.registerCommand("!resettoke", this.resettoke.bind(this));
|
|
|
|
//admin command registration
|
|
this.channel.modules.chat.registerCommand("!updatetokes", this.updatetokesCmd.bind(this));
|
|
this.channel.modules.chat.registerCommand("!reloadtokes", this.updatetokesCmd.bind(this));
|
|
this.channel.modules.chat.registerCommand("!tokesay", this.tokesayCmd.bind(this));
|
|
this.channel.modules.chat.registerCommand("!tokeannounce", this.tokeyellCmd.bind(this));
|
|
this.channel.modules.chat.registerCommand("!tokeyell", this.tokeyellCmd.bind(this));
|
|
this.channel.modules.chat.registerCommand("!tokewhisper", this.tokewhisperCmd.bind(this));
|
|
|
|
//!toke command registration
|
|
this.updatetokes();
|
|
this.channel.modules.chat.registerCommand("!r", this.randotoke.bind(this));
|
|
|
|
this.loadtfile();//load up toke stats from toke file.
|
|
|
|
|
|
}
|
|
|
|
//protoype definition
|
|
TokebotModule.prototype = Object.create(ChannelModule.prototype);
|
|
|
|
//tokebot object properties
|
|
TokebotModule.prototype.toking = 0;
|
|
TokebotModule.prototype.tokers = [];
|
|
TokebotModule.prototype.cdown = 3;
|
|
TokebotModule.prototype.cdel = 120;
|
|
TokebotModule.prototype.ctime = 120;
|
|
TokebotModule.prototype.statmap = null;
|
|
|
|
//mod commands
|
|
TokebotModule.prototype.resettoke = function(user, msg, _meta){
|
|
if(user.account.effectiveRank >= 2 && this.toking == 2){
|
|
this.ctime = 0;
|
|
this.tokewhisper("!toke cooldown reset.", user.account.name);
|
|
}
|
|
}
|
|
|
|
|
|
//siteowner commands
|
|
TokebotModule.prototype.updatetokesCmd = function(user, msg, _meta){
|
|
if(user.account.effectiveRank >= 256){
|
|
this.updatetokes();
|
|
this.tokewhisper("Reloading !toke commands...", user.account.name);
|
|
}
|
|
}
|
|
|
|
TokebotModule.prototype.tokesayCmd = function(user, msg, _meta){
|
|
if(user.account.effectiveRank >= 256){
|
|
var fmsg = msg.split(" ");
|
|
fmsg.shift();
|
|
this.tokesay(fmsg.join(' '), true);
|
|
}
|
|
}
|
|
|
|
TokebotModule.prototype.tokeyellCmd = function(user, msg, _meta){
|
|
if(user.account.effectiveRank >= 256){
|
|
var fmsg = msg.split(" ");
|
|
fmsg.shift();
|
|
this.tokesay(fmsg.join(' '), false);
|
|
}
|
|
}
|
|
|
|
TokebotModule.prototype.tokewhisperCmd = function(user, msg, _meta){
|
|
if(user.account.effectiveRank >= 256){
|
|
var fmsg = msg.split(" ");
|
|
fmsg.shift();
|
|
this.tokewhisper(fmsg.join(' '));
|
|
}
|
|
}
|
|
|
|
//extra user commands
|
|
TokebotModule.prototype.randotoke = function(user, msg, _meta){
|
|
this.toke(user, '!' + tokes[randi(tokes.length)],_meta);
|
|
}
|
|
|
|
//main toke logic (adapted from chozobot implementation)
|
|
TokebotModule.prototype.toke = function (user, msg, _meta){
|
|
var name = user.getName()
|
|
/*if(name === "Ten"){//use in case of anger
|
|
bot.sendChatMsg(">:^(");
|
|
return;
|
|
}*/
|
|
switch (this.toking){
|
|
case 0://ready to start toke
|
|
this.tokesay("A group toke has been started by " + name + "! We'll be taking a toke in 60 seconds - join in by posting " + msg);
|
|
this.cdown = 3;
|
|
this.toking = 1; this.tokers.push(name);
|
|
setTimeout(this.countdown, 57000, this);
|
|
break;
|
|
case 1://taking toke
|
|
if(this.tokers.includes(name)){
|
|
this.tokewhisper(" You're already taking part in this toke!", name);
|
|
}else{
|
|
this.tokesay(name + " joined the toke! Post " + msg + " to take part!");
|
|
this.tokers.push(name);
|
|
this.cdown = 3;
|
|
}
|
|
break;
|
|
case 2://cooldown
|
|
this.tokewhisper(" Please wait " + this.ctime + " seconds before starting a new group toke.", name);
|
|
break;
|
|
}
|
|
};
|
|
|
|
TokebotModule.prototype.countdown = function (tb){
|
|
tb.toking = 1;//set toking mode
|
|
|
|
tb.tokesay(tb.cdown + "...");//send countdown msg
|
|
--tb.cdown;//count down
|
|
|
|
if(tb.cdown <= 0){//if cdown hits 0
|
|
setTimeout(tb.endtoke, 1000, tb);
|
|
}else{
|
|
setTimeout(tb.countdown, 1000, tb);//call endtoke
|
|
}
|
|
};
|
|
|
|
TokebotModule.prototype.endtoke = function (tb){
|
|
if(tb.cdown != 0){
|
|
setTimeout(tb.countdown, 1000, tb);
|
|
return;
|
|
}
|
|
if(tb.tokers.length > 1){
|
|
let callstring = '';
|
|
|
|
for(let i = 0; i < tb.tokers.length - 1; i++){
|
|
callstring += tb.tokers[i] + ', ';
|
|
}
|
|
|
|
callstring += tb.tokers[tb.tokers.length - 1];
|
|
|
|
tb.tokesay("Take a toke " + callstring + "! " + tb.tokers.length + " tokers!");
|
|
}else{
|
|
tb.tokesay("Take a toke " + tb.tokers.toString() + ". " + (solotokes[randi(solotokes.length)]));
|
|
}
|
|
tb.logtoke();
|
|
tb.tokers = [];
|
|
tb.toking = 2;//reset toking mode
|
|
setTimeout(tb.cooldown, 1000, tb);
|
|
};
|
|
|
|
TokebotModule.prototype.cooldown = function (tb){
|
|
if(tb.ctime > 0){
|
|
tb.toking = 2;
|
|
--tb.ctime;
|
|
setTimeout(tb.cooldown, 1000, tb);
|
|
}else{
|
|
tb.toking = 0;
|
|
tb.ctime = tb.cdel;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
//helper functions(mostly just syntactic sugar)
|
|
TokebotModule.prototype.updatetokes = function (){
|
|
tokes = loadTokes();
|
|
|
|
if(this.channel.modules.chat){//register !toke commands
|
|
if(tokes == null){//if for some reason tokes file couldnt be loaded this.channel.modules.chat.registerCommand("!toke", this.toke.bind(this)); console.log("[tokebot] Unable to load toke commands from ./tokebot/tokes, defaulting to !toke definition");
|
|
}else{//if we we're able to pull toke commands
|
|
var _this = this;//we need to use this, might put this up higher to replace the tb parameter in other member functions
|
|
tokes.forEach(function(tokec){
|
|
_this.channel.modules.chat.registerCommand("!" + tokec, _this.toke.bind(_this));
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
TokebotModule.prototype.tokesay = function (msg,quiet){
|
|
var msgobj = {
|
|
username: "tokebot",
|
|
msg: msg,
|
|
meta:{
|
|
addClass: (quiet ? null : "shout"),
|
|
addClassToNameAndTimestamp: true,
|
|
forceShowName: (quiet ? true : false), //It's loud enough when announcing. Toke chats are rare enouhg to be more prominent :P
|
|
modflair: 3
|
|
},
|
|
time: Date.now()
|
|
}
|
|
|
|
this.channel.users.forEach(function (u) {
|
|
u.socket.emit("chatMsg",msgobj);
|
|
});
|
|
};
|
|
|
|
TokebotModule.prototype.tokewhisper = function (msg, usr){//(msg, username)
|
|
if(this.channel.modules.chat != null){
|
|
if(usr != null){
|
|
this.channel.modules.chat.sendModMessage(msg,-1,"tokebot",usr);
|
|
}else{
|
|
var _this = this
|
|
this.channel.users.forEach(function(u){
|
|
_this.channel.modules.chat.sendModMessage(msg,-1,"tokebot",u.account.name);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
//filesystem manipulation functions
|
|
TokebotModule.prototype.writetokelog = function(){//append a toke to current channels toke log
|
|
var _this = this;
|
|
fs.appendFile("tokebot/" + this.channel.name + "_toke.log" ,('[' + this.tokers.toString() + '],' + this.tokers.length + ',' + new Date().getTime() + "\n"), function(err){
|
|
if(err){
|
|
console.log("[chan: " + _this.channel.name + "] TOKE LOG WRITE ERROR: " + err);
|
|
}
|
|
});
|
|
}
|
|
|
|
TokebotModule.prototype.loadtfile = function(){//load tokefile into statmap(default to new Map() on error)
|
|
var _this = this;
|
|
fs.readFile("tokebot/" + this.channel.name + "_tokefile", function(err,data){
|
|
if(err){
|
|
console.log("[chan: " + _this.channel.name + "] TOKE FILE READ ERROR (may overwrite existing stat file!): " + err);
|
|
_this.statmap = new Map();
|
|
}else{
|
|
_this.statmap = JSON.parse(data, mapReviver);
|
|
}
|
|
});
|
|
}
|
|
|
|
TokebotModule.prototype.writetfile = function(){//write statmap to tokefile
|
|
var _this = this;
|
|
fs.writeFile("tokebot/" + this.channel.name + "_tokefile", JSON.stringify(_this.statmap, mapReplacer), function(err,data){
|
|
if(err){
|
|
console.log("[chan: " + _this.channel.name + "] TOKE FILE WRITE ERROR: " + err);
|
|
}
|
|
});
|
|
}
|
|
|
|
TokebotModule.prototype.logtoke = function(){
|
|
this.writetokelog();//save toke to toke log
|
|
var _this = this;
|
|
|
|
this.tokers.forEach(function (u){//for all tokers
|
|
var ct = _this.statmap.get(u);//lets make this a lil prettier :P
|
|
_this.statmap.set(u,(ct == null ? 1 : ++ct));//increment toke counter
|
|
});
|
|
|
|
this.writetfile();//write statmap to tfile
|
|
}
|
|
module.exports = TokebotModule;
|