File Coverage

blib/lib/Chatbot/Alpha.pm
Criterion Covered Total %
statement 12 451 2.6
branch 0 176 0.0
condition 0 29 0.0
subroutine 4 17 23.5
pod 12 13 92.3
total 28 686 4.0


line stmt bran cond sub pod time code
1             package Chatbot::Alpha;
2              
3             our $VERSION = '2.05';
4              
5             # For debugging...
6 1     1   21750 use strict;
  1         2  
  1         35  
7 1     1   4 use warnings;
  1         2  
  1         24  
8 1     1   1054 use Data::Dumper;
  1         9952  
  1         71  
9              
10             # Syntax checking
11 1     1   2176 use Chatbot::Alpha::Syntax;
  1         2  
  1         5406  
12              
13             sub new {
14 0     0 1   my $proto = shift;
15              
16 0   0       my $class = ref($proto) || $proto;
17              
18 0           my $self = {
19             debug => 0,
20             version => $VERSION,
21             default => "I'm afraid I don't know how to reply to that!",
22             stream => undef,
23             syntax => new Chatbot::Alpha::Syntax(
24             syntax => 'strict',
25             denytype => 'allow_all',
26             ),
27             verify => 1,
28             @_,
29             };
30              
31 0           bless ($self,$class);
32              
33 0           return $self;
34             }
35              
36             sub version {
37 0     0 1   my $self = shift;
38              
39 0           return $self->{version};
40             }
41              
42             sub debug {
43 0     0 0   my ($self,$msg) = @_;
44              
45             # Only show if debug mode is on.
46 0 0         if ($self->{debug} == 1) {
47 0           print STDOUT "Alpha::Debug // $msg\n";
48             }
49              
50 0           return 1;
51             }
52              
53             sub loadFolder {
54 0     0 1   my ($self,$dir) = (shift,shift);
55 0   0       my $type = shift || undef;
56              
57             # Open the folder.
58 0 0         opendir (DIR, $dir) or return 0;
59 0           foreach my $file (sort(grep(!/^\./, readdir(DIR)))) {
60 0 0         if (defined $type) {
61 0 0         if ($file !~ /\.$type$/i) {
62 0           next;
63             }
64             }
65              
66 0           my $load = $self->loadFile ("$dir/$file");
67 0 0         return $load unless $load == 1;
68             }
69 0           closedir (DIR);
70              
71 0           return 1;
72             }
73              
74             sub stream {
75 0     0 1   my ($self,$code) = @_;
76              
77             # Must have Alpha code defined.
78 0 0         if (!defined $code) {
79 0           warn "Chatbot::Alpha::stream - no code included with call!\n";
80 0           return 0;
81             }
82              
83             # Stream the code.
84 0           $self->{stream} = $code;
85 0           $self->loadFile (undef,1);
86             }
87              
88             sub loadFile {
89 0     0 1   my ($self,$file,$stream) = @_;
90 0 0         $stream = 0 unless defined $stream;
91 0 0         $stream = 0 if defined $file;
92              
93 0 0         $file = '(Streamed)' unless defined $file;
94              
95 0           $self->debug ("loadFile called for file: $file");
96              
97             # Open the file.
98 0           my @data = ();
99 0 0         if ($stream != 1) {
100             # Syntax check this.
101 0 0         if ($self->{verify} == 1) {
102 0           $self->{syntax}->check ($file);
103             }
104              
105 0 0         open (FILE, "$file") or return 0;
106 0           @data = ;
107 0           close (FILE);
108 0           chomp @data;
109             }
110             else {
111 0           @data = split ("\n", $self->{stream});
112             }
113              
114             # (Re)-define temporary variables.
115 0           my $topic = 'random';
116 0           my $inReply = 0;
117 0           my $trigger = '';
118 0           my $counter = 0;
119 0           my $ccount = 0; # Conditions counter
120 0           my $holder = 0;
121 0           my $num = 0;
122              
123             # Go through the file.
124 0           foreach my $line (@data) {
125 0           $num++;
126 0           $self->debug ("Line $num: $line");
127 0 0         next if length $line == 0;
128 0 0         next if $line =~ /^\//;
129 0           $line =~ s/^\s+//g;
130 0           $line =~ s/^\t+//g;
131 0           $line =~ s/^\s//g;
132 0           $line =~ s/^\t//g;
133              
134             # Get the command off.
135 0           my ($command,$data) = split(//, $line, 2);
136              
137             # Go through commands...
138 0 0         if ($command eq '>') {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
139 0           $self->debug ("> Command - Label Begin!");
140 0           $data =~ s/^\s//g;
141 0           my ($type,$text) = split(/\s+/, $data, 2);
142 0 0         if ($type eq 'topic') {
143 0           $self->debug ("Topic set to $data");
144 0           $topic = $text;
145             }
146             }
147             elsif ($command eq '<') {
148 0           $self->debug ("< Command - Label Ender!");
149 0           $data =~ s/^\s//g;
150 0 0 0       if ($data eq 'topic' || $data eq '/topic') {
151 0           $self->debug ("Topic reset");
152 0           $topic = 'random';
153             }
154             }
155             elsif ($command eq '+') {
156 0           $self->debug ("+ Command - Reply Trigger!");
157 0 0         if ($inReply == 1) {
158             # Reset the topics?
159 0 0         if ($topic =~ /^_that_/i) {
160 0           $topic = 'random';
161             }
162              
163             # New reply.
164 0           $inReply = 0;
165 0           $trigger = '';
166 0           $counter = 0;
167 0           $holder = 0;
168             }
169              
170             # Reply trigger.
171 0           $inReply = 1;
172              
173 0           $data =~ s/^\s//g;
174 0           $data =~ s/([^A-Za-z0-9 ])/\\$1/ig;
175 0           $data =~ s/\\\*/\(\.\*\?\)/ig;
176 0           $trigger = $data;
177 0           $self->debug ("Trigger: $trigger");
178              
179             # Set the trigger's topic.
180 0           $self->{_replies}->{$topic}->{$trigger}->{topic} = $topic;
181 0           $self->{_syntax}->{$topic}->{$trigger}->{ref} = "$file line $num";
182             }
183             elsif ($command eq '~') {
184 0           $self->debug ("~ Command - Regexp Trigger!");
185 0 0         if ($inReply == 1) {
186             # Reset the topics?
187 0 0         if ($topic =~ /^_that_/i) {
188 0           $topic = 'random';
189             }
190              
191             # New reply.
192 0           $inReply = 0;
193 0           $trigger = '';
194 0           $counter = 0;
195 0           $holder = 0;
196             }
197              
198             # Reply trigger.
199 0           $inReply = 1;
200              
201 0           $data =~ s/^\s//g;
202 0           $trigger = $data;
203 0           $self->debug ("Trigger: $trigger");
204              
205             # Set the trigger's topic.
206 0           $self->{_replies}->{$topic}->{$trigger}->{topic} = $topic;
207 0           $self->{_syntax}->{$topic}->{$trigger}->{ref} = "$file line $num";
208             }
209             elsif ($command eq '%') {
210 0           $self->debug ("% Command - That!");
211 0 0         if ($inReply != 1) {
212             # Error.
213 0           $self->debug ("Syntax error at $file line $num");
214 0           return -2;
215             }
216              
217             # That tag.
218 0           $data =~ s/^\s//g;
219              
220             # Set the topic to "_that_$data"
221 0           $topic = "_that_$data";
222             }
223             elsif ($command eq '-') {
224 0           $self->debug ("- Command - Reply Response!");
225 0 0         if ($inReply != 1) {
226             # Error.
227 0           $self->debug ("Syntax Error at $file line $num");
228 0           return -2;
229             }
230              
231             # Reply response.
232 0           $counter++;
233 0           $data =~ s/^\s//g;
234              
235 0           $self->{_replies}->{$topic}->{$trigger}->{$counter} = $data;
236 0           $self->debug ("Reply #$counter : $data");
237 0           $self->{_syntax}->{$topic}->{$trigger}->{$counter}->{ref} = "$file line $num";
238             }
239             elsif ($command eq '^') {
240 0           $self->debug ("^ Command - Reply Continuation");
241 0           $data =~ s/^\s//g;
242 0           $self->{_replies}->{$topic}->{$trigger}->{$counter} .= $data;
243             }
244             elsif ($command eq '@') {
245             # A redirect.
246 0           $self->debug ("\@ Command - A Redirect!");
247 0 0         if ($inReply != 1) {
248             # Error.
249 0           $self->debug ("Syntax Error at $file line $num");
250 0           return -2;
251             }
252 0           $data =~ s/^\s//g;
253 0           $self->{_replies}->{$topic}->{$trigger}->{redirect} = $data;
254 0           $self->{_syntax}->{$topic}->{$trigger}->{redirect}->{ref} = "$file line $num";
255             }
256             elsif ($command eq '*') {
257             # A conditional.
258 0           $self->debug ("* Command - A Conditional!");
259 0 0         if ($inReply != 1) {
260             # Error.
261 0           $self->debug ("Syntax Error at $file line $num");
262 0           return -2;
263             }
264             # Get the conditional's data.
265 0           $data =~ s/^\s//g;
266 0           $self->debug ("Counter: $ccount");
267 0           $self->{_replies}->{$topic}->{$trigger}->{conditions}->{$ccount} = $data;
268 0           $self->{_syntax}->{$topic}->{$trigger}->{conditions}->{$ccount}->{ref} = "$file line $num";
269 0           $ccount++;
270             }
271             elsif ($command eq '&') {
272             # A conversation holder.
273 0           $self->debug ("\& Command - A Conversation Holder!");
274 0 0         if ($inReply != 1) {
275             # Error.
276 0           $self->debug ("Syntax Error at $file line $num");
277 0           return -2;
278             }
279              
280             # Save this.
281 0           $data =~ s/^\s//g;
282 0           $self->debug ("Holder: $holder");
283 0           $self->{_replies}->{$topic}->{$trigger}->{convo}->{$holder} = $data;
284 0           $self->{_syntax}->{$topic}->{$trigger}->{convo}->{$holder}->{ref} = "$file line $num";
285 0           $holder++;
286             }
287             elsif ($command eq '#') {
288             # A system command.
289 0           $self->debug ("\# Command - A System Command!");
290 0 0         if ($inReply != 1) {
291             # Error.
292 0           $self->debug ("Syntax Error at $file line $num");
293 0           return -2;
294             }
295              
296             # Save this.
297 0           $data =~ s/^\s//g;
298 0           $self->debug ("System Command: $data");
299 0           $self->{_replies}->{$topic}->{$trigger}->{system}->{codes} .= $data;
300 0           $self->{_syntax}->{$topic}->{$trigger}->{system}->{codes}->{ref} = "$file line $num";
301             }
302             }
303              
304 0           return 1;
305             }
306              
307             sub sortReplies {
308 0     0 1   my $self = shift;
309              
310             # Reset loop.
311 0           $self->{loops} = 0;
312              
313             # Fail if replies hadn't been loaded.
314 0 0         return 0 unless exists $self->{_replies};
315              
316             # Delete the replies array (if it exists).
317 0 0         if (exists $self->{_array}) {
318 0           delete $self->{_array};
319             }
320              
321 0           $self->debug ("Sorting the replies...");
322              
323             # Count replies.
324 0           my $count = 0;
325              
326             # Go through each reply.
327 0           foreach my $topic (keys %{$self->{_replies}}) {
  0            
328             # Sort by number of whole words.
329 0           my $sort = {
330             def => [],
331             0 => [],
332             1 => [],
333             2 => [],
334             3 => [],
335             4 => [],
336             5 => [],
337             6 => [],
338             7 => [],
339             8 => [],
340             9 => [],
341             10 => [],
342             11 => [],
343             12 => [],
344             13 => [],
345             14 => [],
346             15 => [],
347             16 => [],
348             unknown => [],
349             };
350              
351 0           my @trigNorm = ();
352 0           my @trigWild = ();
353 0           foreach my $key (keys %{$self->{_replies}->{$topic}}) {
  0            
354 0           $self->debug ("Sorting key $key");
355 0           $count++;
356             # If it's a wildcard...
357 0 0         if ($key =~ /\*/) {
358             # See how many full words it has.
359 0           my @words = split(/\s/, $key);
360 0           my $cnt = 0;
361 0           foreach my $word (@words) {
362 0           $word =~ s/\s//g;
363 0 0         next unless length $word;
364 0 0         if ($word !~ /\*/) {
365             # A whole word.
366 0           $cnt++;
367             }
368             }
369              
370             # Save to wildcard array.
371 0           $self->debug ("Key $key has a wildcard ($cnt words)!");
372              
373 0 0         if (exists $sort->{$cnt}) {
374 0           push (@{$sort->{$cnt}}, $key);
  0            
375             }
376             else {
377 0           push (@{$sort->{unknown}}, $key);
  0            
378             }
379             }
380             else {
381             # Save to normal array.
382 0           $self->debug ("Key $key is normal!");
383 0           push (@{$sort->{def}}, $key);
  0            
384             }
385             }
386              
387             # Merge the arrays.
388 0           $self->{_array}->{$topic} = [
389 0           @{$sort->{def}},
390 0           @{$sort->{16}},
391 0           @{$sort->{15}},
392 0           @{$sort->{14}},
393 0           @{$sort->{13}},
394 0           @{$sort->{12}},
395 0           @{$sort->{11}},
396 0           @{$sort->{10}},
397 0           @{$sort->{9}},
398 0           @{$sort->{8}},
399 0           @{$sort->{7}},
400 0           @{$sort->{6}},
401 0           @{$sort->{5}},
402 0           @{$sort->{4}},
403 0           @{$sort->{3}},
404 0           @{$sort->{2}},
405 0           @{$sort->{1}},
406 0           @{$sort->{unknown}},
407 0           @{$sort->{0}},
408             ];
409             }
410              
411             # Save the count.
412 0           $self->{replycount} = $count;
413              
414             # Return true.
415 0           return 1;
416             }
417              
418             sub setVariable {
419 0     0 1   my ($self,$var,$value) = @_;
420 0 0         return 0 unless defined $var;
421 0 0         return 0 unless defined $value;
422              
423 0           $self->{vars}->{$var} = $value;
424 0           return 1;
425             }
426              
427             sub removeVariable {
428 0     0 1   my ($self,$var) = @_;
429 0 0         return 0 unless defined $var;
430              
431 0           delete $self->{vars}->{$var};
432 0           return 1;
433             }
434              
435             sub clearVariables {
436 0     0 1   my $self = shift;
437              
438 0           delete $self->{vars};
439 0           return 1;
440             }
441              
442             sub search {
443 0     0 1   my ($self,$msg) = @_;
444              
445 0           my @results = ();
446              
447             # Sort replies if it hasn't already been done.
448 0 0         if (!exists $self->{_array}) {
449 0           $self->sortReplies;
450             }
451              
452             # Too many loops?
453 0 0         if ($self->{loops} >= 15) {
454 0           $self->{loops} = 0;
455 0           my $topic = 'random';
456 0           return "ERR: Deep Recursion (15+ loops in reply set) at $self->{_syntax}->{$topic}->{$msg}->{redirect}->{ref}";
457             }
458              
459 0           my %star;
460             my $reply;
461              
462             # Make sure some replies are loaded.
463 0 0         if (!exists $self->{_replies}) {
464 0           return "ERROR: No replies have been loaded!";
465             }
466              
467             # Go through each reply.
468 0           foreach my $topic (keys %{$self->{_array}}) {
  0            
469 0           $self->debug ("On Topic: $topic");
470              
471 0           foreach my $in (@{$self->{_array}->{$topic}}) {
  0            
472 0           $self->debug ("On Reply Trigger: $in");
473              
474 0 0         if ($msg =~ /^$in$/i) {
475             # Add to the results.
476 0           my $t = $in;
477 0           $t =~ s/\(\.\*\?\)/\*/g;
478 0           push (@results, "+ $t (topic: $topic) at $self->{_syntax}->{$topic}->{$in}->{ref}");
479             }
480             }
481             }
482              
483 0           return @results;
484             }
485              
486             sub reply {
487 0     0 1   my ($self,$id,$msg) = @_;
488              
489             # Sort replies if it hasn't already been done.
490 0 0         if (!exists $self->{_array}) {
491 0           $self->sortReplies;
492             }
493              
494             # Create history.
495 0 0         if (!exists $self->{users}->{$id}->{history}) {
496 0           $self->{users}->{$id}->{history}->{input} = [ '', 'undefined', 'undefined', 'undefined', 'undefined',
497             'undefined', 'undefined', 'undefined', 'undefined', 'undefined' ];
498 0           $self->{users}->{$id}->{history}->{reply} = [ '', 'undefined', 'undefined', 'undefined', 'undefined',
499             'undefined', 'undefined', 'undefined', 'undefined', 'undefined' ];
500             }
501              
502             # Too many loops?
503 0 0         if ($self->{loops} >= 15) {
504 0           $self->{loops} = 0;
505 0   0       my $topic = $self->{users}->{$id}->{topic} || 'random';
506 0           return "ERR: Deep Recursion (15+ loops in reply set) at $self->{_syntax}->{$topic}->{$msg}->{redirect}->{ref}";
507             }
508              
509 0           my %star;
510             my $reply;
511              
512 0           for (my $i = 1; $i <= 9; $i++) {
513 0           $star{$i} = '';
514             }
515              
516             # Topics?
517 0   0       $self->{users}->{$id}->{topic} ||= 'random';
518              
519 0 0         $self->{users}->{$id}->{last} = '' unless exists $self->{users}->{$id}->{last};
520 0 0         $self->{users}->{$id}->{that} = '' unless exists $self->{users}->{$id}->{that};
521              
522 0           $self->debug ("User Topic: $self->{users}->{$id}->{topic}");
523              
524 0           $self->debug ("Message: $msg");
525              
526             # Make sure some replies are loaded.
527 0 0         if (!exists $self->{_replies}) {
528 0           return "ERROR: No replies have been loaded!";
529             }
530              
531             # See if this topic has any "that's" associated with it.
532 0           my $thatTopic = "_that_$self->{users}->{$id}->{that}";
533 0           my $isThat = 0;
534 0           my $keepTopic = '';
535              
536             # Go through each reply.
537 0           foreach my $topic (keys %{$self->{_array}}) {
  0            
538 0           $self->debug ("On Topic: $topic");
539              
540 0           my $lastSent = $self->{users}->{$id}->{that};
541              
542 0 0 0       if ($isThat != 1 && length $lastSent > 0 && exists $self->{_replies}->{$thatTopic}->{$msg}) {
      0        
543             # It does exist. Set this as the topic so this reply should be matched.
544 0           $isThat = 1;
545 0           $keepTopic = $self->{users}->{$id}->{topic};
546 0           $self->{users}->{$id}->{topic} = $thatTopic;
547             }
548              
549 0 0         next unless $topic eq $self->{users}->{$id}->{topic};
550              
551 0           foreach my $in (@{$self->{_array}->{$topic}}) {
  0            
552 0           $self->debug ("On Reply Trigger: $in");
553              
554             # Conversations?
555 0           my $found_convo = 0;
556 0           $self->debug ("Checking for conversation holders...");
557 0 0         if (exists $self->{_replies}->{$topic}->{$in}->{convo}) {
558 0           $self->debug ("This reply has a convo holder!");
559             # See if this was our conversation.
560 0           my $h = 0;
561 0           for ($h = 0; exists $self->{_replies}->{$topic}->{$in}->{convo}->{$h}; $h++) {
562 0 0         last if $found_convo == 1;
563 0           $self->debug ("On Holder #$h");
564              
565 0           my $next = $self->{_replies}->{$topic}->{$in}->{convo}->{$h};
566              
567 0           $self->debug ("Last Msg: $self->{users}->{$id}->{last}");
568              
569             # See if this was for their last message.
570 0 0         if ($self->{users}->{$id}->{last} =~ /^$in$/i) {
571 0 0         if (!exists $self->{_replies}->{$topic}->{$in}->{convo}->{$self->{users}->{$id}->{hold}}) {
572 0           delete $self->{users}->{$id}->{hold};
573 0           $self->{users}->{$id}->{last} = $msg;
574 0           last;
575             }
576              
577             # Give the reply.
578 0           $reply = $self->{_replies}->{$topic}->{$in}->{convo}->{$self->{users}->{$id}->{hold}};
579 0           $self->{users}->{$id}->{hold}++;
580 0           $star{msg} = $msg;
581 0           $msg = $in;
582 0           $found_convo = 1;
583             }
584             }
585             }
586 0 0         last if defined $reply;
587              
588 0 0         if ($msg =~ /^$in$/i) {
589 0           $self->debug ("Reply Matched!");
590 0           $star{1} = $1; $star{2} = $2; $star{3} = $3; $star{4} = $4; $star{5} = $5;
  0            
  0            
  0            
  0            
591 0           $star{6} = $6; $star{7} = $7; $star{8} = $8; $star{9} = $9;
  0            
  0            
  0            
592              
593             # A redirect?
594 0           $self->debug ("Checking for a redirection...");
595 0 0         if (exists $self->{_replies}->{$topic}->{$in}->{redirect}) {
596 0           $self->debug ("Redirection found! Getting new reply for $self->{_replies}->{$topic}->{$in}->{redirect}...");
597 0           my $redirect = $self->{_replies}->{$topic}->{$in}->{redirect};
598              
599             # Filter in wildcards.
600 0           for (my $s = 0; $s <= 9; $s++) {
601 0           $redirect =~ s//$star{$s}/ig;
602             }
603              
604 0 0         $redirect =~ s//$star{1}/ig if exists $star{1};
605              
606 0           $self->{loops}++;
607 0           $reply = $self->reply ($id,$redirect);
608 0           return $reply;
609             }
610              
611             # Conditionals?
612 0           $self->debug ("Checking for conditionals...");
613 0 0         if (exists $self->{_replies}->{$topic}->{$in}->{conditions}) {
614 0           $self->debug ("This response DOES have conditionals!");
615             # Go through each one.
616 0           my $c = 0;
617 0           for ($c = 0; exists $self->{_replies}->{$topic}->{$in}->{conditions}->{$c}; $c++) {
618 0           $self->debug ("On Condition #$c");
619 0 0         last if defined $reply;
620              
621 0           my $conditional = $self->{_replies}->{$topic}->{$in}->{conditions}->{$c};
622 0           my ($condition,$happens) = split(/::/, $conditional, 2);
623 0           $self->debug ("Condition: $condition");
624 0           my ($var,$value) = split(/=/, $condition, 2);
625 0           $self->debug ("var = $var; value = $value");
626              
627 0 0         if (exists $self->{vars}->{$var}) {
628 0           $self->debug ("Variable asked for exists!");
629             # Check values.
630 0 0 0       if (($var =~ /^[0-9]/ && $self->{vars}->{$var} eq $value) || ($self->{vars}->{$var} eq $value)) {
      0        
631 0           $self->debug ("Values match!");
632             # True. This is the reply.
633 0           $reply = $happens;
634 0           $self->debug ("Reply = $reply");
635             }
636             }
637             }
638             }
639              
640 0 0         last if defined $reply;
641              
642             # A reply?
643 0 0         return "ERROR: No reply set for \"$msg\"!" unless exists $self->{_replies}->{$topic}->{$in}->{1};
644              
645 0           my @replies;
646 0           foreach my $key (keys %{$self->{_replies}->{$topic}->{$in}}) {
  0            
647 0 0         next if $key =~ /[^0-9]/;
648 0           push (@replies,$self->{_replies}->{$topic}->{$in}->{$key});
649             }
650              
651 0           $reply = 'INFLOOP';
652 0           while ($reply =~ /^(INFLOOP|HASH|SCALAR|ARRAY)/i) {
653 0           $self->{loops}++;
654 0           $reply = $replies [ int(rand(scalar(@replies))) ];
655 0 0         if ($self->{loops} >= 20) {
656 0           $reply = "ERR: Infinite Loop near $self->{_syntax}->{$topic}->{$in}->{ref}";
657             }
658             }
659              
660 0           $self->debug ("Checking system commands...");
661             # Execute system commands?
662 0 0         if (exists $self->{_replies}->{$topic}->{$in}->{system}->{codes}) {
663 0           $self->debug ("Found System: $self->{_replies}->{$topic}->{$in}->{system}->{codes}");
664 0   0       my $eval = eval ($self->{_replies}->{$topic}->{$in}->{system}->{codes}) || $@;
665 0           $self->debug ("Eval Result: $eval");
666             }
667             }
668             }
669             }
670              
671             # Reset "That" topics.
672 0 0         if ($isThat == 1) {
673 0           $self->{users}->{$id}->{topic} = $keepTopic;
674 0           $self->{users}->{$id}->{that} = '<>';
675             }
676              
677             # A reply?
678 0 0         if (defined $reply) {
679             # Filter in stars...
680 0           my $i;
681 0           for ($i = 1; $i <= 9; $i++) {
682 0           $reply =~ s//$star{$i}/ig;
683             }
684 0 0         $reply =~ s//$star{1}/ig if exists $star{1};
685 0 0         $reply =~ s//$star{msg}/ig if exists $star{msg};
686             }
687             else {
688             # Were they in a topic?
689 0 0         if ($self->{users}->{$id}->{topic} ne 'random') {
690 0 0         if (exists $self->{_array}->{$self->{users}->{$id}->{topic}}) {
691 0           $reply = "ERR: No Reply Matched in Topic $self->{users}->{$id}->{topic}";
692             }
693             else {
694 0           $self->{users}->{$id}->{topic} = 'random';
695 0           $reply = "ERR: No Reply (possibly void topic?)";
696             }
697             }
698             else {
699 0           $reply = "ERR: No Reply Found";
700             }
701             }
702              
703             # History tags.
704 0           $reply =~ s//$self->{users}->{$id}->{history}->{input}->[$1]/g;
705 0           $reply =~ s//$self->{users}->{$id}->{history}->{reply}->[$1]/g;
706              
707             # String modifiers.
708 0           while ($reply =~ /\{(formal|uppercase|lowercase|sentence)\}(.*?)\{\/(formal|uppercase|lowercase|sentence)\}/i) {
709 0           my ($type,$string) = ($1,$2);
710 0           $type = lc($type);
711 0           my $o = $string;
712 0           $string = &stringUtil ($type,$string);
713 0           $o =~ s/([^A-Za-z0-9 =<>])/\\$1/g;
714 0           $reply =~ s/\{$type\}$o\{\/$type\}/$string/ig;
715             }
716              
717             # A topic setter?
718 0 0         if ($reply =~ /\{topic=(.*?)\}/i) {
719 0           my $to = $1;
720 0 0         if ($to eq 'random') {
721 0           $self->{users}->{$id}->{topic} = '';
722             }
723             else {
724 0           $self->{users}->{$id}->{topic} = $to;
725             }
726 0           $reply =~ s/\{topic=(.*?)\}//g;
727             }
728              
729             # Sub-replies?
730 0           while ($reply =~ /\{\@(.*?)\}/i) {
731 0           my $o = $1;
732 0           my $trig = $o;
733 0           $trig =~ s/^\s+//g;
734 0           $trig =~ s/\s$//g;
735              
736 0           my $resp = $self->reply ($id,$trig);
737              
738 0           $reply =~ s/\{\@$o\}/$resp/i;
739             }
740              
741             # Randomness?
742 0           while ($reply =~ /\{random\}(.*?)\{\/random\}/i) {
743 0           my $text = $1;
744 0           my @options = ();
745              
746             # Pipes?
747 0 0         if ($text =~ /\|/) {
748 0           @options = split(/\|/, $text);
749             }
750             else {
751 0           @options = split(/\s+/, $text);
752             }
753              
754 0           my $rep = $options [ int(rand(scalar(@options))) ];
755 0           $reply =~ s/\{random\}(.*?)\{\/random\}/$rep/i;
756             }
757              
758             # Update history.
759 0           shift (@{$self->{users}->{$id}->{history}->{input}});
  0            
760 0           shift (@{$self->{users}->{$id}->{history}->{reply}});
  0            
761 0           unshift (@{$self->{users}->{$id}->{history}->{input}}, $msg);
  0            
762 0           unshift (@{$self->{users}->{$id}->{history}->{reply}}, $reply);
  0            
763 0           unshift (@{$self->{users}->{$id}->{history}->{input}}, '');
  0            
764 0           unshift (@{$self->{users}->{$id}->{history}->{reply}}, '');
  0            
765 0           pop (@{$self->{users}->{$id}->{history}->{input}});
  0            
766 0           pop (@{$self->{users}->{$id}->{history}->{reply}});
  0            
767              
768             # Format the bot's reply.
769 0           my $simple = lc($reply);
770 0           $simple =~ s/[^A-Za-z0-9 ]//g;
771 0           $simple =~ s/^\s+//g;
772 0           $simple =~ s/\s$//g;
773              
774             # Save this message.
775 0           $self->debug ("Saving this as last msg...");
776 0           $self->{users}->{$id}->{that} = $simple;
777 0           $self->{users}->{$id}->{last} = $msg;
778 0   0       $self->{users}->{$id}->{hold} ||= 0;
779              
780             # Reset the loop timer.
781 0           $self->{loops} = 0;
782              
783             # There SHOULD be a reply now.
784             # So, return it.
785 0           return $reply;
786             }
787              
788             sub stringUtil {
789 0     0 1   my ($type,$string) = @_;
790              
791 0 0         if ($type eq 'uppercase') {
    0          
    0          
    0          
792 0           return uc($string);
793             }
794             elsif ($type eq 'lowercase') {
795 0           return lc($string);
796             }
797             elsif ($type eq 'sentence') {
798 0           $string = lc($string);
799 0           return ucfirst($string);
800             }
801             elsif ($type eq 'formal') {
802 0           $string = lc($string);
803 0           my @words = split(/ /, $string);
804 0           my @out = ();
805 0           foreach my $word (@words) {
806 0           push (@out, ucfirst($word));
807             }
808 0           return join (" ", @out);
809             }
810             else {
811 0           return $string;
812             }
813             }
814              
815             1;
816             __END__