/var/www/www.irssi.org-old/scripts/html/quizgr.pl
1 #!/usr/bin/perl -T
2 # Quizgr script for irssi with "KAOS" questions enabled, modified for greek too
3 # copyright Athanasius Emilius Arvanitis
4 # arvan@kronos.eng.auth.gr
5 # based on quiz.pl version 0.7
6 # Quiz script for irssi
7 # (C) Simon Huggins 2001
8 # huggie@earth.li
9
10 # This program is free software; you can redistribute it and/or modify it
11 # under the terms of the GNU General Public License as published by the Free
12 # Software Foundation; either version 2 of the License, or (at your option)
13 # any later version.
14 #
15 # This program is distributed in the hope that it will be useful, but
16 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 # for more details.
19 #
20 # You should have received a copy of the GNU General Public License along
21 # with this program; if not, write to the Free Software Foundation, Inc., 59
22 # Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #
24 # DONE:
25 # - support for many answers (not alternate though) per question
26 # - support for hellenic (aka greek)
27 # - remembers the questions that were answered (stores them in
28 # ./wr/used_questions)
29 # - if nobody says anything for a period of time, game ends
30 # - added !repeat to repeat the question
31 # - it wont crash if you smile!
32 # TODO:
33 # - known bug: sometimes it ignores some people (they cant join etc).
34 # if you join #CHANNEL and the bot is on #channel forget it...
35 # - fix kaos hints
36 # - if we have kaos, there should be more time to answer
37 # - CLEAN up the code
38 # - Do something when people quit (remove from team, readd when rejoin?)
39
40 use strict;
41 use vars qw($VERSION %IRSSI);
42
43 use Irssi 20020217.1542 (); # Version 0.8.1 or perhaps get the most up to date irssi version
44 $VERSION = "0.7GR02";
45 %IRSSI = (
46 authors => "Athanasius Emilius Arvanitis based on Simon Huggins quiz 0.7",
47 contact => "arvan",
48 name => "Quizgr",
49 description => "Turns irssi into a quiz bot. Has greek language and many answers support",
50 license => "GPLv2",
51 url => "http://kronos.eng.auth.gr/~arvan/irssi/",
52 changed => "Tue Nov 26 13:37:59 EET 2002",
53 );
54
55 use Irssi::Irc;
56 use Data::Dumper;
57
58 Irssi::settings_add_str("misc","quiz_admin","jbg");
59 Irssi::settings_add_str("misc","quiz_passwd","stuff");
60 Irssi::settings_add_str("misc","quiz_file","$ENV{HOME}/.irssi/scripts/autorun/gr_quiz_questions");
61 Irssi::settings_add_str("misc","used_file","$ENV{HOME}/.irssi/scripts/autorun/wr/used_questions");
62
63 Irssi::settings_add_int("misc","quiz_qlength",70);
64 Irssi::settings_add_int("misc","quiz_hints",7);
65 Irssi::settings_add_int("misc","quiz_target_score",50);
66 Irssi::settings_add_int("misc","quiz_leave_concealed_chars",1);
67
68 Irssi::command("set cmd_queue_speed 2010");
69
70 {
71 # when warnings used $s complains
72 my $s;
73 my $answerBAKforCHAOS;
74
75 sub load_questions($$) {
76 my ($game,$force) = @_;
77 my $tag = $game->{'tag'};
78 my $channel = $game->{'channel'};
79
80 my $server = Irssi::server_find_tag($tag);
81
82 if (!defined $server) {
83 Irssi::print("Hrm, couldn't find server for tag ($tag) in load_questions");
84 return;
85 }
86
87 return if $game->{'questions'} and not $force;
88
89 #the next must be checked
90
91 my $file = Irssi::settings_get_str("quiz_file");
92 if (open(QS, "<$file")) { #open for QS
93 @{$game->{'questions'}}=sort <QS>;
94 close(QS);
95 Irssi::print("Loaded questions");
96
97 my $file2 = Irssi::settings_get_str("used_file");
98 if (open(QS2, "<$file2")) { #open for QS2
99 @{$game->{'used_questions'}}=sort <QS2>;
100 close(QS2);
101
102 #from perlfaq copy paste
103 @{$game->{'intersection'}} = @{$game->{'difference'}} = ();
104 %{$game->{'count'}} = ();
105
106 my $element;
107 foreach $element (@{$game->{'questions'}}, @{$game->{'used_questions'}}) { ${$game->{'count'}}{$element}++ };
108
109 foreach $element (keys %{$game->{'count'}}) { #open foreach
110 push @{ ${$game->{'count'}}{$element} > 1 ? \@{$game->{'intersection'}} : \@{$game->{'difference'}} }, $element;
111 } #close foreach
112
113 my $ts = Irssi::settings_get_int("quiz_target_score");
114 my $qCounter=@{$game->{'questions'}};
115 ${$game->{'usedCounter'}}=@{$game->{'used_questions'}};
116
117 my $qGOT=($qCounter - ${$game->{'usedCounter'}});
118 my $qNEEDED=(2*($ts)+12);
119 Irssi::print("${$game->{'usedCounter'}} used out of $qCounter total questions");
120
121 if ( $qGOT >= $qNEEDED ) {
122 @{$game->{'questions'}}=@{$game->{'difference'}};
123 Irssi::print("Loaded not used questions");
124 return 1;#used
125 }
126
127 if ( $qGOT < $qNEEDED ) {
128 @{$game->{'used_questions'}}=();
129 Irssi::print("Clearing used questions");
130 return 1;#used
131 }
132 } #close QS2
133
134 return 1;#questions
135 } #close QS
136
137 else {
138 $server->command("msg $channel Can't find quiz questions, sorry.");
139 return;
140 }
141
142
143
144 }
145
146 sub start_game($) {
147 my $game = shift;
148 my $tag = $game->{'tag'};
149 my $channel = $game->{'channel'};
150 my $server = Irssi::server_find_tag($tag);
151
152 if (!defined $server) {
153 Irssi::print("Hrm, couldn't find server for tag ($tag) in start_game");
154 return;
155 }
156
157 Irssi::timeout_remove($game->{'timeouttag'});
158 undef $game->{'timeouttag'};
159
160 if (!keys %{$game->{'teams'}}) {
161 $server->command("msg $channel Sorry no one joined!");
162 $game->{'state'} = "over";
163 game_over($game);
164 return;
165 }
166
167 $game->{'state'} = "game";
168
169 $server->command("msg $channel Game starts now. Questions last ".
170 Irssi::settings_get_int("quiz_qlength").
171 " seconds and there are ".
172 (Irssi::settings_get_int("quiz_hints")-1).
173 " hints. First to reach ".
174 Irssi::settings_get_int("quiz_target_score")." wins.");
175 next_question($game);
176 }
177
178 sub show_scores($) {
179 my $game = shift;
180 my $tag = $game->{'tag'};
181 my $channel = $game->{'channel'};
182 my $server = Irssi::server_find_tag($tag);
183
184 if (!defined $server) {
185 Irssi::print("Hrm, couldn't find server for tag ($tag) in show_scores");
186 return;
187 }
188
189 my (@redscorers,@bluescorers);
190
191 foreach my $score (sort keys %{$game->{'scores'}}) {
192 if ($score =~ /^blue/) {
193 $score =~ s/^blue//;
194 push @bluescorers, "$score(".
195 $game->{'scores'}->{"blue".$score}.")";
196 } else {
197 $score =~ s/^red//;
198 push @redscorers, "$score(".
199 $game->{'scores'}->{"red".$score}.")";
200 }
201 }
202
203 $server->command("msg $channel 12Blue: ".$game->{'bluescore'}
204 ." ".join(",",@bluescorers));
205 $server->command("msg $channel 4Red: ".$game->{'redscore'}
206 ." ".join(",",@redscorers));
207
208 my $ts = Irssi::settings_get_int("quiz_target_score");
209
210 if ($game->{'bluescore'} >= $ts or $game->{'redscore'} >= $ts) {
211 if ($game->{'bluescore'} > $game->{'redscore'}) {
212 $server->command("msg $channel 12Blue team wins ".
213 $game->{'bluescore'}." to ".
214 $game->{'redscore'});
215 } else {
216 $server->command("msg $channel 4Red team wins ".
217 $game->{'redscore'}." to ".
218 $game->{'bluescore'});
219 }
220 $game->{'state'}="over";
221 } elsif ($game->{'state'} ne "over") {
222 $game->{'state'}="pause";
223 $server->command("msg $channel Next question in 6 20 seconds.");
224 if ($game->{'timeouttag'}) {
225 Irssi::timeout_remove($game->{'timeouttag'});
226 }
227 $game->{'timeouttag'} = Irssi::timeout_add(20000,
228 "next_question",$game);
229 $game->{'timeout'} = time() + 20;
230 }
231 game_over($game);
232 }
233
234 sub hint($) {
235 my $game = shift;
236 my $tag = $game->{'tag'};
237 my $channel = $game->{'channel'};
238 my $server = Irssi::server_find_tag($tag);
239
240 if (!defined $server) {
241 Irssi::print("Hrm, couldn't find server for tag ($tag) in hint");
242 return;
243 }
244
245 return if game_over($game);
246 if ($game->{'end'} <= time()) {
247 $server->command("msg $channel Time's up. The answer is: 2 ".$game->{'answer'});
248 show_scores($game);
249 } else {
250 $game->{'hint'}++;
251 my $num = $game->{'current_answer'} =~ s/\*/*/g;
252 if ($num <= Irssi::settings_get_int("quiz_leave_concealed_chars")) {
253 return;
254 }
255
256 my $pos = index($game->{'current_answer'},"*");
257 if ($pos >= 0) {
258 #$game->{'current_answer'} =~ s/\*/substr($game->{'answer'},$pos,1)/e;
259 $game->{'current_answer'} =~ s/\*/substr($answerBAKforCHAOS,$pos,1)/e;
260 }
261
262 my $hinttime = $game->{'hint'}*$game->{'hintlen'};
263 if ($hinttime != int($hinttime)) {
264 $hinttime = sprintf("%.2f", $hinttime);
265 }
266 $server->command("msg $channel 2 $hinttime second hint: 6 ".
267 $game->{'current_answer'});
268 } #else end
269 }
270
271 sub game_over($) {
272 my $game = shift;
273 my $tag = $game->{'tag'};
274 my $channel = $game->{'channel'};
275 my $server = Irssi::server_find_tag($tag);
276
277 if (!defined $server) {
278 Irssi::print("Hrm, couldn't find server for tag ($tag) in game_over");
279 return;
280 }
281
282 if ($game->{'state'} eq "over") {
283 Irssi::timeout_remove($game->{'timeouttag'});
284 undef $game->{'timeouttag'};
285 undef $game->{'state'};
286 undef $game->{'teams'};
287 undef $game->{'scores'};
288
289 #save used questions
290 my $file2 = Irssi::settings_get_str("used_file");
291 if (open(QS2, ">$file2")) {
292 my $line;
293 @{$game->{'used_questions'}}=sort @{$game->{'used_questions'}};
294 foreach $line (@{$game->{'used_questions'}}){
295 print QS2 $line ;
296 }
297 close(QS2);
298 Irssi::print("Saved used questions");
299 }
300
301
302 $server->command("msg $channel Trivia is disabled. Use !start or !trivon to restart.");
303 return 1;
304 }
305 return;
306 }
307
308 sub next_question($) {
309 my $game = shift;
310 my $tag = $game->{'tag'};
311 my $channel = $game->{'channel'};
312 my $server = Irssi::server_find_tag($tag);
313
314 if (!defined $server) {
315 Irssi::print("Hrm, couldn't find server for tag ($tag) in next_question");
316 return;
317 }
318
319 #check previous text time and
320 #if noone says anything for 180 seconds end game
321 if (defined $game->{'time_last_text'}) {
322 my $diff2=time() - $game->{'time_last_text'};
323 if ( $diff2 > 180) {
324 $game->{'state'}="over";
325 }
326 }
327
328
329 my $len = Irssi::settings_get_int("quiz_qlength")/
330 Irssi::settings_get_int("quiz_hints");
331 if ($game->{'timeouttag'}) {
332 Irssi::timeout_remove($game->{'timeouttag'});
333 }
334 $game->{'timeouttag'} = Irssi::timeout_add($len*1000, "hint",$game);
335 my $t = time();
336 $game->{'timeout'} = $t + $len;
337 $game->{'end'} = Irssi::settings_get_int("quiz_qlength")+$t;
338 $game->{'hint'}=0;
339 $game->{'hintlen'} = $len;
340 if (!@{$game->{'questions'}}) {
341 load_questions($game,1);
342 if (!$game->{'questions'}) {
343 $server->command("msg $channel Hmmm, no questions found sorry");
344 $game->{'state'}="over";
345 }
346 Irssi::print("Questions looped");
347 }
348 return if game_over($game);
349
350 #random question
351 ${$game->{'randIDX'}}= @{$game->{'questions'}};
352 ${$game->{'randIDX'}}=rand(${$game->{'randIDX'}});
353 my $q = ${$game->{'questions'}}[${$game->{'randIDX'}}];
354 ${$game->{'the_question'}} = $q;
355
356 #removing it from the questions
357 splice (@{$game->{'questions'}}, ${$game->{'randIDX'}}, 1);
358
359 #see faq for splice/random may be bad
360 #my $q = splice(@{$game->{'questions'}},rand(@{$game->{'questions'}}),1);
361 chomp $q;
362 $q =~ s///;
363 #($game->{'answer'} = $q) =~ s/^(.*)\|//;
364
365 ($game->{'question'}, $game->{'answer'}) = split(/\|/, $q,2);
366 $answerBAKforCHAOS = $game->{'answer'};
367 if ( $game->{'answer'} =~ /\|/ )
368 { $server->command("msg $channel KAOS CHAOS ×ÁÏÓ!!!");
369 $game->{'answer'} = $game->{'answer'}."|";
370
371 }
372 $server->command("msg $channel 13Question: 10 $game->{'question'} ");
373 #added Á-Ùá-ù so it can hide greek too
374 ($game->{'current_answer'} = $game->{'answer'}) =~ s/[a-zA-Z0-9Á-Ùá-ù]/*/g;
375 #$q = s/^(.*)\|.*?$/$1/;
376 $server->command("msg $channel Answer: ".$game->{'current_answer'});
377 $game->{'state'}="question";
378 }
379
380 sub invite_join($$) {
381 my ($server,$channel) = @_;
382 my $game = $s->{$server->{'tag'}}->{$channel};
383
384 $server->command("msg $channel Team Trivia thingummie v($VERSION) starts in 1 minute. Type 4!join red or 12!join blue");
385 $game->{'timeouttag'} = Irssi::timeout_add(60000,"start_game",$game);
386 $game->{'timeout'} = time()+60;
387 }
388
389 sub secstonormal($) {
390 my $seconds = shift;
391 my ($m,$s);
392
393 $s = $seconds % 60;
394 $m = ($seconds - $s)/60;
395 return sprintf("%02d:%02d",$m,$s);
396 }
397
398 sub do_pubcommand($$$$) {
399 my ($command,$channel,$server,$nick) = @_;
400 my $game = $s->{$server->{'tag'}}->{$channel};
401
402 $command = lc $command;
403 $command =~ s/\s*$//;
404
405 if ($command =~ /^!bang$/) {
406 $server->command("msg $channel Dumping...");
407 foreach (split /\n/,Dumper($s)) {
408 Irssi::print("$_");
409 }
410 } elsif ($command =~ /^!trivon$|^!start$|!ðÜìå$/) {
411 if ($s->{$server->{'tag'}}->{$channel}) {
412 if ($s->{$server->{'tag'}}->{$channel}->{'state'}) {
413 $server->command("msg $nick Trivia is already on. Use !trivoff or !stop to remove it.");
414 return;
415 }
416 #undef $s->{$server->{'tag'}}->{$channel};
417 } else {
418 # create structure magically
419 $game = $s->{$server->{'tag'}}->{$channel} = {};
420 $game->{'tag'} = $server->{'tag'};
421 $game->{'channel'} = $channel;
422 }
423 $game->{'teams'}={};
424 $game->{'redscore'} = 0;
425 $game->{'bluescore'} = 0;
426 load_questions($game,0);
427 $game->{'state'} = "join";
428 invite_join($server,$channel);
429 } elsif ($command =~ /^!trivoff$|^!stop$|!öôÜíåé$/) {
430 return if !$game->{'state'};
431 $game->{'state'}="over";
432 game_over($game);
433 } elsif ($command =~ /^!join/) {
434 if ($command =~ /^!join (red|blue)$/) {
435 return if !$game->{'state'};
436 $game->{'teams'}->{$nick}=$1;
437 if ($1 eq "blue") {
438 $server->command("notice $nick You have joined the 12Blue team");
439 } else {
440 $server->command("notice $nick You have joined the 4Red team");
441 }
442 }
443 } elsif ($command =~ /^!teams/) {
444 return if !$game->{'state'};
445 my @blue=();
446 my @red=();
447 foreach (sort keys %{$game->{'teams'}}) {
448 push @blue, $_ if $game->{'teams'}->{$_} eq "blue";
449 push @red, $_ if $game->{'teams'}->{$_} eq "red";
450 }
451 $server->command("msg $channel 12Blue: ".join(",",@blue));
452 $server->command("msg $channel 4Red : ".join(",",@red));
453 } elsif ($command =~ /^!repeat$/) {
454 return if !$game->{'state'};
455 $server->command("msg $channel Question is $game->{'question'}");
456 } elsif ($command =~ /^!timeleft$/) {
457 if ($game->{'state'} eq "join" and $game->{'timeout'}) {
458 my $diff = $game->{'timeout'} - time();
459 if ($diff > 0) {
460 $server->command("msg $channel Time left: ".secstonormal($diff));
461 } else {
462 Irssi::print("Timeleft: $diff ??");
463 }
464 }
465 }
466 }
467
468 sub do_command($$$) {
469 my ($command,$nick,$server) = @_;
470
471 $command = lc $command;
472 $command =~ s/\s*$//;
473
474 if ($command =~ /^!bang$/) {
475 $server->command("msg $nick BOOM!");
476 } elsif ($command =~ /^admin/) {
477 if ($command !~ /^admin (.*)$/) {
478 $server->command("msg $nick admin needs a nick to change the admin user to!");
479 } else {
480 Irssi::settings_remove("quiz_admin");
481 Irssi::settings_add_str("misc","quiz_admin",$1);
482 $server->command("msg $nick admin user is now $1");
483 }
484 } else {
485 #$server->command("msg $nick Unknown command '$command'");
486 }
487 }
488
489 #check check_answer for bad { }
490
491 sub check_answer($$$$) {
492 my ($server,$channel,$nick,$text) = @_;
493 my $game = $s->{$server->{'tag'}}->{$channel};
494
495 return if not exists $game->{'teams'}->{$nick};
496
497 #if $text exist check time and remembers it for end-game
498 if (defined $text) {
499 $game->{'time_last_text'} = time();
500 }
501
502
503 $text =~ s/\s*$//;
504 $text =~ s/^ //;
505 $text =~ s/ $//;
506
507 #from cgi input-purify / try without it and it will crash with :(
508 #dont know if it needs em all, may check it in future
509
510 if ($text =~ s/([\&;\`'\\\|"*?~<>^\(\)\[\]\{\}\$\n\r])/\\$1/g)
511 { $text="abcdef";
512 }
513 # is the above the reason it didnt join?
514
515 #if greek supports troubles you comment the next
516 $text =~ y/ÜÝÞßúÀüýûàþ¢¶¸¹ºÚ¼¾Û¿ÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÓÔÕÖרÙ/áåçéééïõõõù¶áåçééïõõùáâãäåæçèéêëìíîïðñóôõö÷øù/;
517
518 my $answerNOtonos = lc $game->{'answer'};
519 #if greek supports troubles you comment the next
520 $answerNOtonos =~ y/ÜÝÞßúÀüýûàþ¢¶¸¹ºÚ¼¾Û¿ÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÓÔÕÖרÙ/áåçéééïõõõù¶áåçééïõõùáâãäåæçèéêëìíîïðñóôõö÷øù/;
521
522 if ( $answerNOtonos =~ /\|/) {
523
524 if ( ($answerNOtonos =~ /\|$text\|/)||($answerNOtonos =~ /^$text\|/) )
525 {
526 $answerNOtonos =~ s/$text\|//;
527
528 $game->{'answer'}=$answerNOtonos;
529
530
531 $server->command("msg $channel 2Correct answer by ".
532 ($game->{'teams'}->{$nick} eq "blue"?"12":"4").
533 $nick.": ".$text);
534
535 $game->{$game->{'teams'}->{$nick}."score"}++;
536 $game->{'scores'}->{$game->{'teams'}->{$nick}.$nick}++;
537
538 if ($answerNOtonos eq "") {
539
540 #putting it in used
541 if (@{$game->{'used_questions'}}){
542 ${$game->{'usedCounter'}} = @{$game->{'used_questions'}};
543 } else {my ${$game->{'usedCounter'}}=0;}
544
545 ${$game->{'used_questions'}}[${$game->{'usedCounter'}}]=${$game->{'the_question'}};
546
547 $game->{'state'}="won";
548
549 $server->command("msg $channel 2 $answerBAKforCHAOS") ;
550 show_scores($game);
551 return;
552 }
553
554 #show_scores($game);
555 }
556 }
557
558
559 elsif (( $answerNOtonos !~ /\|/) && (lc $text eq $answerNOtonos)) {
560
561 $server->command("msg $channel 2Correct answer by ".
562 ($game->{'teams'}->{$nick} eq "blue"?"12":"4").
563 $nick.": ".$game->{'answer'});
564 $game->{'state'}="won";
565
566 #putting it in used
567 if (@{$game->{'used_questions'}}){
568 ${$game->{'usedCounter'}} = @{$game->{'used_questions'}};
569 } else {my ${$game->{'usedCounter'}} =0;}
570
571 ${$game->{'used_questions'}}[${$game->{'usedCounter'}}]=${$game->{'the_question'}};
572
573 $game->{$game->{'teams'}->{$nick}."score"}++;
574 $game->{'scores'}->{$game->{'teams'}->{$nick}.$nick}++;
575 show_scores($game);
576 return;
577 }
578
579
580
581 my $show=0;
582 my @chars = split //,$text;
583
584 for (my $i=0; $i<length($game->{'answer'}); $i++) {
585 if (lc $chars[$i] eq lc substr($game->{'answer'},$i,1)) {
586 $show = 1 if substr($game->{'current_answer'},$i,1)
587 eq "*";
588 substr($game->{'current_answer'},$i,1) =
589 substr($game->{'answer'},$i,1);
590 }
591 }
592
593 $server->command("msg $channel Answer: ".$game->{'current_answer'})
594 if $show;
595 }
596
597
598
599 sub event_privmsg {
600 my ($server,$data,$nick,$address) = @_;
601 my ($target, $text) = split / :/,$data,2;
602 my ($command);
603
604 if ($target =~ /^#/) {
605 my $game = $s->{$server->{'tag'}}->{$target};
606 if ($text =~ /^!/) {
607 do_pubcommand($text,$target,$server,$nick);
608 } elsif ($game->{'state'} eq "question") {
609 check_answer($server,$target,$nick,$text);
610 }
611 } else {
612 if ($nick ne Irssi::settings_get_str("quiz_admin")) {
613 my ($passwd);
614 ($passwd, $command) = split /\s/,$text,2;
615 if ($passwd ne Irssi::settings_get_str("quiz_passwd")) {
616 #Irssi::print("$nick tried to do $command but got the password wrong.");
617 Irssi::print("$nick got the password wrong.");
618 }
619 } else {
620 $command = $text;
621 }
622 do_command($command,$nick,$server);
623 }
624 }
625
626 sub event_changed_nick {
627 my ($channel,$nick,$oldnick) = @_;
628 my $server = $channel->{'server'};
629 my $game = $s->{$server->{'tag'}}->{$channel->{'name'}};
630
631 return if !$game->{'state'};
632
633 my $nicktxt = $nick->{'nick'};
634 if ($game->{'teams'}->{$oldnick}) {
635 $game->{'teams'}->{$nicktxt} = $game->{'teams'}->{$oldnick};
636 delete $game->{'teams'}->{$oldnick};
637 }
638
639 }
640
641
642 }
643
644 Irssi::signal_add_last("event privmsg", "event_privmsg");
645 # Irssi::signal_add_last("massjoin", "sig_massjoin");
646 #Irssi::signal_add_last("message nick", "on_nick"); #when /nick
647 #Irssi::signal_add_last("message part", "on_part");
648 #Irssi::signal_add_last("message join", "on_join");
649 #Irssi::signal_add_last("message quit", "on_quit");
650
651 # Channel::nicks(channel) Return a list of all nicks in channel.
652
653 Irssi::signal_add("nicklist changed", "event_changed_nick");