-
Notifications
You must be signed in to change notification settings - Fork 4
/
main.lisp
170 lines (122 loc) · 5.13 KB
/
main.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
(in-package #:alice)
;;; "alice" goes here. Hacks and glory await! ;-)
(defparameter *full-name* "Alice Margatroid") ;FIXME not exactly sure where it belongs...
(defvar *connection*)
;; configurables
(defparameter *server* "")
(defvar *nick* "")
(defparameter *password* "")
(defparameter *autojoin-channels* '())
(defparameter *muted* nil)
(defparameter +nickserv+ "NickServ")
(defparameter +nickserv-identify-msg-template+ "IDENTIFY ~a")
(defparameter *debug-last-message* nil)
(defparameter *excluded-from-replying-to* '() "List of users that the bot won't reply to for unrecognized queries.")
(defparameter *throttled-output* nil "A buffer for throttling the output to avoid flooding the channel.")
(defparameter *max-output-sequence-length* 4)
(define-constant +maximum-line-length+ 400)
(defparameter *default-phrase* "Nie wiem co powiedzieć...")
;; functions
;; tools
(defun throttle (messages)
(let ((len (length messages)))
(if (> len *max-output-sequence-length*)
(let* ((split-point (min *max-output-sequence-length*
len))
(to-say (subseq messages 0 split-point))
(to-buffer (subseq messages split-point)))
(setf *throttled-output* (and (> (length to-buffer) 0) to-buffer))
(concatenate 'vector to-say #(:throttled-message)))
(progn
(setf *throttled-output* nil)
messages))))
(defun say (to-where what &key to)
(unless *muted*
(typecase what
(null t)
(keyword (say to-where (cdr (assoc what *answers*)) :to to))
(list (say to-where
(random-elt what)
:to to))
(string
(if (null to)
(irc:privmsg *connection* to-where what)
(irc:privmsg *connection* to-where (concatenate 'string to ": " what))))
(vector
(let ((tosay (throttle what)))
(map 'nil
(lambda (msg)
(say to-where msg :to to))
tosay)))
(t (irc:privmsg *connection* to-where *default-phrase*)))))
;;; handling
(defun msg-hook (message)
(let ((destination (if (string-equal (first (irc:arguments message)) *nick*)
(irc:source message)
(first (irc:arguments message))))
(is-private (private-message-p message))
(is-public (public-message-p message))
(is-directed (directed-message-p message))
(from-who (irc:source message))
(message-body (second (irc:arguments message))))
(check-for-memos destination from-who)
(handle-specials destination is-private is-public is-directed from-who message-body)
(execute-match message)
(setf *debug-last-message* (extract-message-features message))))
;; those hooks handle world state
(defun join-hook (message)
(let ((who (irc:source message))
(where (first (irc:arguments message))))
(store-joining-name where who)))
(defun part-hook (message)
(let ((who (irc:source message))
(where (first (irc:arguments message))))
(when (string= who "kdbot")
(say where :kdbot-down)
(notify-kdbot-down))
(store-parting-name where who)))
(defun names-hook (message)
(let ((channel (third (irc:arguments message)))
(nicks (fourth (irc:arguments message))))
(store-names channel (split-sequence:split-sequence #\Space nicks))))
(defun nick-hook (message)
(let ((from (irc:source message))
(to (first (irc:arguments message))))
(register-nick-change from to)))
(defun invite-hook (message)
(let ((where (second (irc:arguments message))))
(join-channel where)))
;; entry point
(defun start-alice (&key (server *server*) (nick *nick*) (password *password*) (channels *autojoin-channels*))
(clear-nonpersistent-worldstate)
(load-persistent-world-model-data)
(setf *nick* nick)
(setf *connection* (irc:connect :nickname *nick*
:server server))
(irc:privmsg *connection* +nickserv+ (format nil +nickserv-identify-msg-template+ password))
(mapcar (lambda (channel) (join-channel channel)) channels)
(irc:add-hook *connection* 'irc:irc-privmsg-message 'msg-hook)
(irc:add-hook *connection* 'irc:irc-join-message 'join-hook)
(irc:add-hook *connection* 'irc:irc-part-message 'part-hook)
(irc:add-hook *connection* 'irc:irc-rpl_namreply-message 'names-hook)
(irc:add-hook *connection* 'irc:irc-nick-message 'nick-hook)
(irc:add-hook *connection* 'irc:irc-invite-message 'invite-hook)
#+(or sbcl
openmcl)
(irc:start-background-message-handler *connection*)
(start-delayed-notification-timer))
(defun stop-alice (&optional (msg "Goodbye!"))
(irc:quit *connection* msg))
(defun mute ()
(setf *muted* t))
(defun unmute ()
(setf *muted* nil))
;; impersonate function
(defun impersonate-say (destination what)
(irc:privmsg *connection* destination what))
(defun impersonate-join (channel &key password)
(join-channel channel :password password))
(defun impersonate-part (channel)
(part-channel channel))
(defun impersonate-slap (channel user)
(irc::action alice::*connection* channel (concatenate 'string "slaps " user " with a Shanghai doll.")))