diff --git a/src/custom.rs b/src/custom.rs index 6107797..01fde56 100644 --- a/src/custom.rs +++ b/src/custom.rs @@ -13,6 +13,7 @@ pub use crate::core::botmodules::ModulesManager; // mod experiments; mod experimental; +mod text_mods; // [ ] init() function that accepts bot instance - this is passed to init() on submodules @@ -20,6 +21,7 @@ pub async fn init(mgr: Arc) { // Modules initializer loads modules into the bot // this is achieved by calling submodules that also have fn init() defined - // experiments::init(mgr).await - experimental::init(mgr).await; -} + experimental::init(mgr.clone()).await; + text_mods::init(Arc::clone(&mgr)).await; + +} \ No newline at end of file diff --git a/src/custom/text_mods.rs b/src/custom/text_mods.rs new file mode 100644 index 0000000..2a1b87b --- /dev/null +++ b/src/custom/text_mods.rs @@ -0,0 +1,409 @@ +//! A module about editing and messing around with user text +//! +use std::collections::HashMap; +use std::sync::Arc; +use rand::{thread_rng, Rng}; +use rand::seq::SliceRandom; +use twitch_irc::message::ReplyToMessage; + +use crate::core::bot_actions::{actions_util, ExecBodyParams}; +use crate::core::botinstance::Channel; +use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, Listener, ModulesManager}; +use crate::core::identity::UserRole::*; +const OF_CMD_CHANNEL:Channel = Channel(String::new()); + +pub async fn init(mgr: Arc) { + + let replyer = BotCommand { + module: BotModule(String::from("Replyer")), + command: String::from("Reply"), + alias: vec![ + String::from("reply") + ], + exec_body: actions_util::asyncbox(thereplyer), + help: String::from("txt mods help"), + required_roles: vec![ + BotAdmin, + Broadcaster, + Mod(OF_CMD_CHANNEL), + VIP(OF_CMD_CHANNEL), + Chatter + ], + }; + + replyer.add_to_modmgr(Arc::clone(&mgr)).await; + + + let forsen_listener = Listener{ + module:BotModule(String::from("TextMods")), + name:String::from("Forsen Listener"), + exec_body:actions_util::asyncbox(forsenforsen), + help:String::from("Forsen helper"), + }; + forsen_listener.add_to_modmgr(Arc::clone(&mgr)).await; + + + let butt = BotCommand{ + module:BotModule(String::from("ButtModule")), + command:String::from("butt"), + alias:vec![], + exec_body:actions_util::asyncbox(butt), + help:String::from("butt helper"), + required_roles:vec![ + BotAdmin, + Broadcaster, + Mod(OF_CMD_CHANNEL), + Chatter, + ] + }; + butt.add_to_modmgr(Arc::clone(&mgr)).await; + + let shuffler = BotCommand{ + module:BotModule(String::from("Shuffler")), + command:String::from("Shuffle"), + alias: vec![ + String::from("shuffle") + ], + exec_body: actions_util::asyncbox(shuffle), + help:String::from("Shuffle Help"), + required_roles:vec![ + BotAdmin, + Broadcaster, + Mod(OF_CMD_CHANNEL), + VIP(OF_CMD_CHANNEL), + Chatter + ] + }; + shuffler.add_to_modmgr(Arc::clone(&mgr)).await; + + + let the8ball: BotCommand = BotCommand { + module:BotModule(String::from("8ball")), + command:String::from("8ball"), + alias: vec![String::from("8b")], + exec_body: actions_util::asyncbox(the8ball), + help:String::from("8ball Help"), + required_roles:vec![ + BotAdmin, + Broadcaster, + Mod(OF_CMD_CHANNEL), + VIP(OF_CMD_CHANNEL), + Chatter + ] + }; + the8ball.add_to_modmgr(Arc::clone(&mgr)).await; + + let percent:BotCommand = BotCommand{ + module:BotModule(String::from("percent")), + command:String::from("%"), + alias:vec![], + exec_body: actions_util::asyncbox(percentage), + help: String::from("Percent Help"), + required_roles: vec![ + BotAdmin, + Broadcaster, + Mod(OF_CMD_CHANNEL), + VIP(OF_CMD_CHANNEL), + Chatter + ] + }; + percent.add_to_modmgr(Arc::clone(&mgr)).await; + + let filler: BotCommand = BotCommand{ + module:BotModule(String::from("filler")), + command:String::from("fill"), + alias:vec![String::from("Fill")], + exec_body:actions_util::asyncbox(fill), + help:String::from("fill Help"), + required_roles: vec![ + BotAdmin, + Broadcaster, + Mod(OF_CMD_CHANNEL), + VIP(OF_CMD_CHANNEL) + ] + }; + filler.add_to_modmgr(Arc::clone(&mgr)).await; + +} + +///Fill command, can be used to make the bot reply with a certain quantity of the same message +/// +/// only works with `(prefix)fill` `word` `quantity` +/// +/// +async fn fill(params : ExecBodyParams) +{ + let usermessage = usermsg(¶ms); + let quantity = usermessage.get(&2).unwrap(); + let mut botreply = String::new(); + + for _i in 0..quantity.parse::().unwrap(){ + botreply.push_str(usermessage.get(&1).unwrap().trim()); + botreply.push(' '); + } + + let bot = Arc::clone(¶ms.bot); + let botlock = bot.read().await; + botlock + .botmgrs + .chat + .say_in_reply( + Channel(params.clone().msg.channel_login().to_string()), + botreply.clone(), + params.clone() + ).await; +} + + +///Percentage is a function that returns a ramdom % +/// +async fn percentage (params : ExecBodyParams) +{ + let mut _botreply = String::new(); + let rng = thread_rng().gen_range(0..100); + let rng_string = rng.to_string(); + _botreply = rng_string + "%"; + + let bot = Arc::clone(¶ms.bot); + let botlock = bot.read().await; + botlock + .botmgrs + .chat + .say_in_reply( + Channel(params.clone().msg.channel_login().to_string()), + _botreply.clone(), + params.clone() + ).await; +} + + +///The 8 ball function +/// it returns a answear to the user message based on random +/// +async fn the8ball(params : ExecBodyParams) +{ + + let mut vecanswears = Vec::new(); + vecanswears.push(String::from("It is certain")); + vecanswears.push(String::from("It is decidedly so")); + vecanswears.push(String::from("Without a doubt")); + vecanswears.push(String::from("Yes definitely")); + vecanswears.push(String::from("You may rely on it")); + + vecanswears.push(String::from("As I see it, yes")); + vecanswears.push(String::from("Most likely")); + vecanswears.push(String::from("Outlook good")); + vecanswears.push(String::from("Yes")); + vecanswears.push(String::from("Signs point to yes")); + + vecanswears.push(String::from("Reply hazy, try again")); + vecanswears.push(String::from("Ask again later")); + vecanswears.push(String::from("Better not tell you now")); + vecanswears.push(String::from("Cannot predict now")); + vecanswears.push(String::from("Concentrate and ask again")); + + vecanswears.push(String::from("Don't count on it")); + vecanswears.push(String::from("My reply is no")); + vecanswears.push(String::from("My sources say no")); + vecanswears.push(String::from("Outlook not so good")); + vecanswears.push(String::from("Very doubtful")); + + + let randchoice = thread_rng().gen_range(0..vecanswears.len()); + let ballmessage = &vecanswears[randchoice]; + + let bot = Arc::clone(¶ms.bot); + let botlock = bot.read().await; + botlock + .botmgrs + .chat + .say_in_reply( + Channel(params.clone().msg.channel_login().to_string()), + ballmessage.clone(), + params.clone() + ).await; +} + + + /// Shuffle Function + /// + /// Grabs The user message and checks how many words it has + /// + /// If the user message constains more the one word, it shuffles the words + /// + /// If its only One word, it shuffles the letters in the word + async fn shuffle(params : ExecBodyParams) + { + let usermessage = usermsg(¶ms); + + if usermessage.len() > 2 + { + + let mut indexes: Vec = (1..usermessage.len()).collect(); + indexes.shuffle(&mut thread_rng()); + + let mut new_reply: HashMap = HashMap::new(); + for (index, &new_index) in indexes.iter().enumerate() { + new_reply.insert(index, usermessage[&new_index].clone()); + } + let mut botreply = String::new(); + for value in new_reply.values(){ + botreply.push_str(value); + botreply.push(' '); + } + + + let bot = Arc::clone(¶ms.bot); + let botlock = bot.read().await; + botlock + .botmgrs + .chat + .say_in_reply( + Channel(params.clone().msg.channel_login().to_string()), + botreply, + params.clone() + ).await; + + } + else { + //if it only has one word, shuffle its chars + let word = usermessage.get(&1).unwrap(); + + let shuffle_word: String = + word.chars() + .collect::>() + .choose_multiple(&mut thread_rng(), word.len()) + .collect(); + + let bot = Arc::clone(¶ms.bot); + let botlock = bot.read().await; + botlock + .botmgrs + .chat + .say_in_reply( + Channel(params.clone().msg.channel_login().to_string()), + shuffle_word, + params.clone() + ).await; + } + + } + + ///butt command hehe + /// + /// All this function does is grab the user message, and randomly pick one of the words + /// in the phrase to change the random word for `butt` + /// + async fn butt(params : ExecBodyParams) + { + //getting User message + let mut userm = usermsg(¶ms); + + //choose a random word from the user phrase + let w = thread_rng().gen_range(1..userm.len()); + + //change the random word to butt :pepepains + userm.insert(w, String::from("Butt")); + + + let mut bot_reply = String::new(); + + for index in 1..userm.len() + { + if let Some(word) = userm.get(&index) + { + bot_reply.push_str(word); + bot_reply.push(' '); + } + } + + let bot = Arc::clone(¶ms.bot); + let botlock = bot.read().await; + botlock + .botmgrs + .chat + .say_in_reply( + Channel(params.clone().msg.channel_login().to_string()), + bot_reply, + params.clone() + ).await; + + } + + ///Forsen. + async fn forsenforsen(params : ExecBodyParams) + { + if params.msg.message_text == "forsen" || params.msg.message_text == "Forsen" + { + let bot = Arc::clone(¶ms.bot); + let botlock = bot.read().await; + botlock + .botmgrs + .chat + .say_in_reply( + Channel(params.clone().msg.channel_login().to_string()), + String::from("Forsen!"), + params.clone() + ).await; + } + } + + ///Thereplyer Function + /// + /// This Function grabs the user message and reply the same message, without the command + /// at the beginning + /// + async fn thereplyer(params : ExecBodyParams) +{ + let user_message: HashMap = usermsg(¶ms); + let mut bot_reply = String::new(); + + for index in 1..user_message.len() + { + if let Some(word) = user_message.get(&index) + { + bot_reply.push_str(word); + bot_reply.push(' '); + } + } + + + let bot = Arc::clone(¶ms.bot); + let botlock = bot.read().await; + botlock + .botmgrs + .chat + .say_in_reply( + Channel(params.clone().msg.channel_login().to_string()), + bot_reply.clone(), + params.clone() + ).await; + +} + +///Usermsg Function +/// +/// Usage: this function grabs the user message, and indexate with a vector and hashmap +/// +/// It returns the User message as a `Hashmap`, with indexs so you can utilize especific words +/// +/// Where `Usize` is index and `String` is the word +pub fn usermsg(params : &ExecBodyParams) -> HashMap +{ + //getting the user message + let sender_message = ¶ms.msg.message_text; + + //vector to store the words + let words: Vec<&str> = sender_message.split_whitespace().collect(); + + //using Hashmap to store the words + let mut index_words:HashMap = HashMap::new(); + + //adding to the hashmap each word + for(index,word) in words.iter().enumerate() + { + index_words.insert(index, String::from(*word)); + } + index_words + +} \ No newline at end of file