1 /++
2     The Chatbot plugin is a diminishing collection of small, harmless features;
3     like `say`/`echo` for simple repeating of text.
4 
5     It's mostly legacy.
6 
7     See_Also:
8         https://github.com/zorael/kameloso/wiki/Current-plugins#chatbot,
9         [kameloso.plugins.common.core],
10         [kameloso.plugins.common.misc]
11 
12     Copyright: [JR](https://github.com/zorael)
13     License: [Boost Software License 1.0](https://www.boost.org/users/license.html)
14 
15     Authors:
16         [JR](https://github.com/zorael)
17  +/
18 module kameloso.plugins.chatbot;
19 
20 version(WithChatbotPlugin):
21 
22 private:
23 
24 import kameloso.plugins;
25 import kameloso.plugins.common.core;
26 import kameloso.plugins.common.awareness : MinimalAuthentication;
27 import kameloso.messaging;
28 import dialect.defs;
29 import std.typecons : Flag, No, Yes;
30 
31 
32 // ChatbotSettings
33 /++
34     Settings for a chatbot, to toggle its features.
35  +/
36 @Settings struct ChatbotSettings
37 {
38     /// Whether or not the Chatbot plugin should react to events at all.
39     @Enabler bool enabled = true;
40 }
41 
42 
43 // onCommandSay
44 /++
45     Repeats text to the channel the event was sent to.
46 
47     If it was sent in a query, respond in a private message in kind.
48  +/
49 @(IRCEventHandler()
50     .onEvent(IRCEvent.Type.CHAN)
51     .onEvent(IRCEvent.Type.QUERY)
52     .permissionsRequired(Permissions.anyone)
53     .channelPolicy(ChannelPolicy.home)
54     .addCommand(
55         IRCEventHandler.Command()
56             .word("say")
57             .policy(PrefixPolicy.prefixed)
58             .description("Repeats text to the current channel. Amazing.")
59             .addSyntax("$command [text to repeat]")
60     )
61     .addCommand(
62         IRCEventHandler.Command()
63             .word("säg")
64             .policy(PrefixPolicy.nickname)
65             .hidden(true)
66     )
67     .addCommand(
68         IRCEventHandler.Command()
69             .word("echo")
70             .policy(PrefixPolicy.prefixed)
71             .hidden(true)
72     )
73 )
74 void onCommandSay(ChatbotPlugin plugin, const ref IRCEvent event)
75 {
76     immutable message = event.content.length ?
77         event.content :
78         "Say what?";
79 
80     privmsg(plugin.state, event.channel, event.sender.nickname, message);
81 }
82 
83 
84 // onDance
85 /++
86     Does the bash.org dance emotes.
87 
88     - http://bash.org/?4281
89  +/
90 @(IRCEventHandler()
91     .onEvent(IRCEvent.Type.CHAN)
92     .permissionsRequired(Permissions.anyone)
93     .channelPolicy(ChannelPolicy.home)
94 )
95 void onDance(ChatbotPlugin plugin, const /*ref*/ IRCEvent event)
96 {
97     import kameloso.constants : BufferSize;
98     import lu.string : strippedRight;
99     import std.string : indexOf;
100     import core.thread : Fiber;
101     import core.time : seconds;
102 
103     immutable content = event.content.strippedRight;
104     immutable dancePos = content.indexOf("DANCE");
105 
106     if (dancePos == -1) return;
107 
108     if ((dancePos > 0) && (content[dancePos-1] != ' '))
109     {
110         return;
111     }
112     else if (content.length > (dancePos+5))
113     {
114         string trailing = content[dancePos+5..$];  // mutable
115 
116         while (trailing.length)
117         {
118             import std.algorithm.comparison : among;
119             if (!trailing[0].among!(' ', '!', '.', '?')) return;
120             trailing = trailing[1..$];
121         }
122     }
123 
124     // Should dance. Stagger it a bit with a second in between.
125     static immutable timeBetweenDances = 1.seconds;
126 
127     void danceDg()
128     {
129         import kameloso.plugins.common.delayawait : delay;
130         import kameloso.messaging : emote;
131 
132         emote(plugin.state, event.channel, "dances :D-<");
133         delay(plugin, timeBetweenDances, Yes.yield);
134 
135         emote(plugin.state, event.channel, "dances :D|-<");
136         delay(plugin, timeBetweenDances, Yes.yield);
137 
138         emote(plugin.state, event.channel, "dances :D/-<");
139     }
140 
141     Fiber danceFiber = new Fiber(&danceDg, BufferSize.fiberStack);
142     danceFiber.call();
143 }
144 
145 
146 mixin MinimalAuthentication;
147 mixin PluginRegistration!ChatbotPlugin;
148 
149 public:
150 
151 
152 // Chatbot
153 /++
154     The Chatbot plugin provides trivial chat functionality.
155  +/
156 final class ChatbotPlugin : IRCPlugin
157 {
158 private:
159     /// All Chatbot plugin settings gathered.
160     ChatbotSettings chatbotSettings;
161 
162     mixin IRCPluginImpl;
163 }