diff --git a/lib/plugins/command.js b/lib/plugins/command.js index 32cc364..f1f16b7 100644 --- a/lib/plugins/command.js +++ b/lib/plugins/command.js @@ -6,7 +6,7 @@ let bot = {} // bot.chatAddPattern(new RegExp(`^hi|hello ${bot.username}`, "i"), 'greet', "General greeting") function todo() { - bot.chat("not implemented yet") + cfg.quiet && console.warn("not implemented") || bot.chat("not implemented yet") } function checkBlockExists(name) { @@ -34,7 +34,12 @@ const events = { if (username === cfg.admin) { message = message.replace("\\", "@") console.info("whispered command", message) - bot.chat("/" + message) + if (/^!/.test(message)) { + command(username, message) + } else { + bot.chat(message) + // bot.chat("/" + message) + } } else { bot.whisper(cfg.admin, `gossip ${username}: ${message}`) console.info(username, "whispered", message) @@ -47,6 +52,19 @@ const events = { const events_registered = [] function command(username, message) { + function fuzzyRespond(responses, probability = 1, timeout = 1) { + if (Math.random() < probability) { + const response = responses[Math.floor(Math.random() * responses.length)] + return setTimeout(() => bot.chat(response), timeout * Math.random() * 1000) + } + } + + function swingArm(swung = 3) { + if (swung > 0) { + setTimeout(swingArm, 500 * Math.random(), --swung) + bot.swingArm() + } + } if (username === bot.username && !message.startsWith("!")) return @@ -59,240 +77,457 @@ function command(username, message) { return } - switch (message) { - case "hi": - case "hello": - case "howdy": - case "yo": - bot.swingArm() - return - case "69": - Math.random() > 0.5 && bot.chat("nice!") - return - case "awesome": - case "cool": - case "superb": - case "nice": - Math.random() > 0.1 && setTimeout(() => bot.chat("very nice!"), 1000) - return - default: - break; - } if (message.startsWith("!") || cfg.botAddress.test(message)) { message = cfg.botAddress.test(message) ? cfg.botAddress.exec(message)[1] : message console.log(message) - message = message.slice(1) - message_parts = message.split(/\s+/) - switch (message_parts[0]) { - // case "follow": - // // if(username === cfg.admin) - // cfg.stateMachines.follow.transitions[4].trigger() - // // cfg.stateMachines.follow.transitions[1].trigger() - // break; - // case "stay": - // // if(username === cfg.admin) - // cfg.stateMachines.follow.transitions[3].trigger() - // break; - case "echo": - // bot.chat(message_parts[1]) - // bot.chat(message.slice(1)) - bot.chat(message) - break; - case "autosleep": - case "sleep": - message_parts[1] = message_parts[0] == "autosleep" ? "auto" : message_parts[1] - switch (message_parts[1]) { - case "auto": - cfg.sleep.auto = !cfg.sleep.auto - bot.chat(`ok, ${cfg.sleep.auto ? "" : "not "}auto sleeping `) - bot.chat("/afk") - break; - case "silent": - case "quiet": - cfg.sleep.quiet = !cfg.sleep.quiet - bot.chat(`ok, ${cfg.sleep.quiet ? "" : "not "}sleeping quietly`) - break; - case "timeout": - if (!message_parts[2]) { - bot.chat(`sleeping every ${Math.round(cfg.sleep.timeout / 60 / 1000)}mins`) - return - } - const timeout = parseFloat(message_parts[2], 10) - if (timeout) { - cfg.sleep.timeout = timeout * 60 * 1000 - cfg.sleep.timeoutFn = null - cfg.plugins.sleeper.sleep(true) //reset timer - bot.chat(`ok, next sleep attempt in ${timeout}mins`) + message = message.slice(1) // remove `!` + // TODO command dispatchEvent, for aliases + function subcommand(message) { + const message_parts = message.split(/\s+/) + + switch (message_parts[0]) { + case "stop": + bot.pathfinder && bot.pathfinder.setGoal(null) + bot.stopDigging() + bot.chat("ok") + break; + + case "mute": + case "quiet": + case "silent": + cfg.quiet = !cfg.quiet + cfg.quiet || bot.chat(`ok, ${cfg.quiet ? "" : "not "}being ${message_parts[0]}`) + break; + // case "follow": + // // if(username === cfg.admin) + // cfg.stateMachines.follow.transitions[4].trigger() + // // cfg.stateMachines.follow.transitions[1].trigger() + // break; + // case "stay": + // // if(username === cfg.admin) + // cfg.stateMachines.follow.transitions[3].trigger() + // break; + case "echo": + // bot.chat(message_parts[1]) + // bot.chat(message.slice(1)) + cfg.quiet && bot.whisper(username, message) || bot.chat(message) + break; + case "autosleep": + case "sleep": + message_parts[1] = message_parts[0] == "autosleep" ? "auto" : message_parts[1] + switch (message_parts[1]) { + case "auto": + cfg.sleep.auto = !cfg.sleep.auto + bot.chat(`ok, ${cfg.sleep.auto ? "" : "not "}auto sleeping`) + bot.chat("/afk") break; - } - default: - bot.chat(`usage: !sleep [auto | quiet | timeout ], or zzz for manual sleep`) - break; - } - break; //todo; needed? - case "zzz": - cfg.plugins.sleeper.sleep() - case "afk": - bot.chat("/afk") - break; - case "awaken": - case "wake": - case "wakeup": - cfg.plugins.sleeper.wake() - break; - case "attack": - case "rage": - case "ragemode": - case "guard": - switch (message_parts.length) { - case 1: - if (!player) { - bot.chat("can't see you.") - return - } - bot.chat('for glory!') - cfg.plugins.guard.guardArea(player.position) - break - case 2: - switch (message_parts[1]) { - case "self": - cfg.guard.self = !cfg.guard.self - bot.chat(`ok, ${cfg.guard.self?"no longer being altruistic":"self sacrifice!"}`) - return; - case "stop": - cfg.plugins.guard.stopGuarding() - bot.chat('no longer guarding this area.') - return; - - default: + case "silent": + case "quiet": + cfg.sleep.quiet = !cfg.sleep.quiet + bot.chat(`ok, ${cfg.sleep.quiet ? "" : "not "}sleeping quietly`) + break; + case "timeout": + if (!message_parts[2]) { + bot.chat(`sleeping every ${Math.round(cfg.sleep.timeout / 60 / 1000)}mins`) + return + } + const timeout = parseFloat(message_parts[2], 10) + if (timeout) { + cfg.sleep.timeout = timeout * 60 * 1000 + cfg.sleep.timeoutFn = null + cfg.plugins.sleeper.sleep(true) //reset timer + bot.chat(`ok, next sleep attempt in ${timeout}mins`) break; - } - default: - bot.chat("don't know wym") - } - // entity = new BehaviorGetClosestEntity(bot, bot.nearestEntity(), a => EntityFilters().MobsOnly(a)) - // if (entity) { - // bot.attack(entity, true) - // } else { - // bot.chat('no nearby entities') + } + default: + bot.chat(`usage: !sleep [auto | quiet | timeout ], or zzz for manual sleep`) + break; + } + break; //todo; needed? + case "zzz": + cfg.plugins.sleeper.sleep() + case "afk": + bot.chat("/afk") + break; + case "awaken": + case "wake": + case "wakeup": + cfg.plugins.sleeper.wake() + break; + case "autoeat": + case "eat": + switch (message_parts[1]) { + case "auto": + cfg.eat.auto = !cfg.eat.auto + bot.chat(`ok, ${cfg.eat.auto ? "" : "not "}auto eating `) + break; + case "at": + case "set": + const amount = parseInt(message_parts[2], 10) + if (amount < 20 && amount > 0) { + cfg.eat.startAt = amount + cfg.eat.quiet || bot.chat(`ok, eating when hunger at ${amount}`) + } + break + case "silent": + case "quiet": + cfg.eat.quiet = !!!cfg.eat.quiet + break; + default: + cfg.plugins.eater.eat((err) => { if (err) { bot.chat(err.message) } }) + // bot.chat(`usage: !sleep [auto | quiet | timeout ], or zzz for manual sleep`) + break; + } + break; + + case "follow": + subcommand("go follow me") + break; + case "come": + subcommand("go follow once") + break; + case "move": + case "go": + // TODO move most of the subcommands into mover.js? + const message_parts2 = message_parts.slice(2) + switch (message_parts[1]) { + case "init": + cfg.plugins.mover.initMoves() + break + case "near": + // message_parts2 = message_parts.slice(2) + switch (message_parts2.length) { + case 0: + cfg.plugins.mover.moveNear(bot.nearestEntity().position) + break + case 1: + switch (message_parts2[0]) { + case "me": + if (player) { + cfg.plugins.mover.moveNear(player.position) + } else { + cfg.quiet || bot.chat("can't see you") + } + break; + + default: + const aPlayer = bot.players[message_parts[2]] ? bot.players[message_parts[2]].entity : null + if (aPlayer) { + cfg.plugins.mover.moveNear(aPlayer.position) + } else { + cfg.quiet || bot.chat(`can't see ${message_parts[2]}`) + } + break; + } + break + case 2: + todo() + // bot.lookAt({}) goalxz? + break + case 3: + //TODO more checks + cfg.plugins.mover.moveNear(message_parts2) + break + default: + break + } + break + + case "follow": + // message_parts2 = message_parts.slice(2) + switch (message_parts2.length) { + case 0: + cfg.plugins.mover.follow(bot.nearestEntity()) + break + case 1: + switch (message_parts2[0]) { + case "me": + case "once": + if (player) { + cfg.plugins.mover.follow(player, message_parts2[0] !== "once") + } else { + cfg.quiet || bot.chat("can't see you") + } + break; + + default: + const aPlayer = bot.players[message_parts[2]] ? bot.players[message_parts[2]].entity : null + if (aPlayer) { + cfg.plugins.mover.follow(aPlayer) + } else { + cfg.quiet || bot.chat(`can't see ${message_parts[2]}`) + } + break; + } + break + // case 2: + // bot.lookAt({}) goalxz? + // break + // case 3: + //TODO more checks + // cfg.plugins.mover.moveNear(message_parts2) + // break + default: + todo() + break + } + break + case "stop": + cfg.plugins.mover.stop() + break + default: + return todo() + break; + } + break; + + case "attack": + case "rage": + case "ragemode": + case "guard": + switch (message_parts.length) { + case 1: + if (!player) { + bot.chat("can't see you.") + return + } + bot.chat('for glory!') + cfg.plugins.guard.guardArea(player.position) + break + case 2: + switch (message_parts[1]) { + case "self": + cfg.guard.self = !cfg.guard.self + bot.chat(`ok, ${cfg.guard.self ? "no longer being altruistic" : "self sacrifice!"}`) + return; + case "stop": + cfg.plugins.guard.stopGuarding() + bot.chat('no longer guarding this area.') + return; + + default: + break; + } + default: + bot.chat("don't know wym") + } + // entity = new BehaviorGetClosestEntity(bot, bot.nearestEntity(), a => EntityFilters().MobsOnly(a)) + // if (entity) { + // bot.attack(entity, true) + // } else { + // bot.chat('no nearby entities') + // } + // // bot.attack(new BehaviorGetClosestEntity(bot, {}, EntityFilters().MobsOnly())) + break; + case "find": + switch (message_parts.length) { + case 2: + cfg.plugins.finder.findBlocks(message_parts[1]) + break + + default: + break; + } + break + case "lookat": + // const coords = v(message_parts.splice(1)) + switch (message_parts.length) { + case 1: + bot.lookAt(bot.nearestEntity().position) + break + case 2: + switch (message_parts[1]) { + case "me": + if (player) { + bot.lookAt((new v.Vec3(0, 1, 0)).add(player.position)) + } else { + cfg.quiet || bot.chat("can't see you") + } + break; + + case "this": + // TODO lookat the block the user is looking at + if (player) { + bot.lookAt((new v.Vec3(0, 1, 0)).add(player.position)) + todo() + } else { + cfg.quiet || bot.chat("can't see you") + } + break; + break + default: + const aPlayer = bot.players[message_parts[2]] ? bot.players[message_parts[2]].entity : null + if (aPlayer) bot.lookAt((new v.Vec3(0, 1, 0)).add(aPlayer.position)) + break; + } + break + case 3: + todo() + // bot.lookAt({}) + break + case 4: + //TODO more checks + bot.lookAt(v(message_parts.splice(1))) + break + default: + break + } + break + case "ride": + case "mount": + bot.mount(bot.nearestEntity()) + break + case "getoff": + case "unmount": + case "dismount": + bot.dismount() + break + case "go": + bot.moveVehicle(0, 10) + break + // case "use": + // bot.useOn(bot.nearestEntity()) + // break; + + // // TODO move all inventory related tasks into inventory.js + case "craft": + cfg.plugins.inventory.craftItem(message_parts[1]) + break + // case "give": + // // switch (message_parts[1]) { + // // case "hand": + // // case "right": + // // break; + // // case "left": + // // break; + // // // case "slot": + // // default: + // // let slot = parseInt(message_parts[1]) + // // if (!isNaN(slot)) { + + // // } else { + + // // } + // // break; + // // } + // // break; + // case "take": + // // TODO take only what's requested, then throw all the rest + // // TODO take all + // case "toss": + // case "drop": + // if (!message_parts[1]) { return false } // FIXME, works but ugly + // if (!checkItemExists(message_parts[1])) { return false } + // switch (message_parts.length) { + // case 2: + // bot.toss(mcData.blocksByName[message_parts[1]].id) + // break + // case 3: + // bot.tossStack( + // mcData.itemsByName[message_parts[1]].id, + // (err) => { + // if (err) { + // console.log(err) + // bot.chat(err) + // } + // } + // ) + // break + // default: + // break // } - // // bot.attack(new BehaviorGetClosestEntity(bot, {}, EntityFilters().MobsOnly())) - break; - case "find": - switch (message_parts.length) { - case 2: - cfg.plugins.finder.findBlocks(message_parts[1]) - break - - default: - break; - } - break - case "lookat": - // const coords = v(message_parts.splice(1)) - switch (message_parts.length) { - case 2: - case 3: - todo() - // bot.lookAt({}) - break - case 1: - bot.lookAt(bot.nearestEntity().position) - break - case 4: - bot.lookAt(v(message_parts.splice(1))) - break - default: - break - } - break - case "ride": - case "mount": - bot.mount(bot.nearestEntity()) - break - case "getoff": - case "unmount": - case "dismount": - bot.dismount() - break - case "go": - bot.moveVehicle(0, 10) - break - // case "use": - // bot.useOn(bot.nearestEntity()) - // break; - - // // TODO move all inventory related tasks into own module - // case "give": - // // switch (message_parts[1]) { - // // case "hand": - // // case "right": - // // break; - // // case "left": - // // break; - // // // case "slot": - // // default: - // // let slot = parseInt(message_parts[1]) - // // if (!isNaN(slot)) { - - // // } else { - - // // } - // // break; - // // } - // // break; - // case "take": - // // TODO take only what's requested, then throw all the rest - // // TODO take all - // case "toss": - // case "drop": - // if (!message_parts[1]) { return false } // FIXME, works but ugly - // if (!checkItemExists(message_parts[1])) { return false } - // switch (message_parts.length) { - // case 2: - // bot.toss(mcData.blocksByName[message_parts[1]].id) - // break - // case 3: - // bot.tossStack( - // mcData.itemsByName[message_parts[1]].id, - // (err) => { - // if (err) { - // console.log(err) - // bot.chat(err) - // } - // } - // ) - // break - // default: - // break - // } - // break; - case "location": - switch (message_parts[1]) { - case "add": - case "record": - - break; - - default: - break; - } - case "where": - case "where?": - // TODO put in /lib/location - console.log(bot.entity.position) - bot.chat(bot.entity.position.floored().toString()) - break; - case "warp": - // if(message_parts[1] == "spawn") - bot.chat("/" + message) - break; + // break; + case "location": + // TODO put in /lib/location + switch (message_parts[1]) { + case "add": + case "record": - default: - if (cfg.mods.includes(username)) + break; + + default: + break; + } + case "where": + case "where?": + // TODO put in /lib/location + console.log(bot.entity.position) + if (cfg.mods.includes(username)) //anarchy + bot.chat( + bot.game.dimension.split(":", 2)[1].replace("_", " ") + + " " + bot.entity.position.floored().toString() + ) + break; + case "warp": + // if (message_parts[1] == "spawn") + // if (cfg.mods.includes(username)) //anarchy bot.chat("/" + message) + break; + + default: + if (cfg.mods.includes(username)) + bot.chat("/" + message) + break; + + } + } + subcommand(message) + } else { + // TODO, maybe extract to a new function `fuzzychat`?, so can address direct messages + switch (message) { + case "wassup": + case "what's cooking": + case "what's new": + case "what's up": + case "whats cooking": + case "whats new": + case "whats up": + case "sup": + case "suh": + fuzzyRespond([ + "jus chilin", "nothin", "random stuff" + ], 0.3, 3) + case "hi": + case "hey": + case "hello": + case "ola": + case "howdy": + case "heyo": + case "yo": + if (player) bot.lookAt((new v.Vec3(0, 1, 0)).add(player.position)) + + // TODO sneak + // function swingArm() { + // if (swung > 0) { + // setTimeout(swing, 500 * Math.random()) + // bot.p() + // swung-- + // } + // } + + setTimeout(swingArm, 1000, 4) // or sneak greating + return + case "F": + return fuzzyRespond(["F"], 0.9, 1) + case "RIP": + return fuzzyRespond(["F", "oh no"], 0.3, 2) + case "69": + case "cool": + Math.random() < 0.5 && bot.chat("nice!") + return + case "awesome": + case "superb": + case "nice": + case "nice!": + return fuzzyRespond(["cool", "very nice!"], 0.3, 5) + case "good bot": + return fuzzyRespond(["thanks", "why, thank you!", ":)", "(:", "you're too kind!"], 1, 5) + case "bad bot": + case "not nice": + return fuzzyRespond([":(", "):", "sorry"], 0.1, 10) + default: break; } }