Kadiliman Plugin v 1.3 - ChatBot by Kali

Other plugins for extending OpenKore's functionality. This forum is only for posting new plugins and commenting on existing plugins. For support, use the Support forum.

Moderator: Moderators

Message
Author
kali
OpenKore Monk
OpenKore Monk
Posts: 457
Joined: 04 Apr 2008, 10:10

Re: Kadiliman Plugin v 1.3 - ChatBot by Kali

#81 Post by kali »

Glad to know my plugin is still getting some usage :P

I might get some more time these coming weeks, and I'm thinking of revising the plugin to have it easier to install, and collate all of the fixes you guys have made.

Mucilon, thanks a lot for your support. And thanks for keeping the chatbot alive :)
Got your topic trashed by a mod?

Trashing topics is one click, and moving a topic to its proper forum is a lot harder. You expend the least effort in deciding where to post, mods expend the least effort by trashing.

Have a nice day.

Mucilon
Cybernatic Entity
Cybernatic Entity
Posts: 249
Joined: 04 Apr 2008, 13:15
Noob?: Yes
Location: Brazil

Re: Kadiliman Plugin v 1.3 - ChatBot by Kali

#82 Post by Mucilon »

No problem...
I'm the one who need to thank you for developed this kind of plugin... it saved my bot's life a lot of times!

runicsabre007

Re: Kadiliman Plugin v 1.3 - ChatBot by Kali

#83 Post by runicsabre007 »

Can we make where it creates the line.txt in a different directory other than the openkore root directory? Like say the chat logs?

fco2783
Plain Yogurt
Plain Yogurt
Posts: 95
Joined: 05 Apr 2008, 05:15
Noob?: Yes
Location: in place where you cant go
Contact:

Re: Kadiliman Plugin v 1.3 - ChatBot by Kali

#84 Post by fco2783 »

testing it for quite sometimes... i notice i cant use command message...

it seems it also ignoring my command message such like... relog, stop, follow, ai off, and others...

and also the other plugin like ditto...

please kali and mucilon look up for this... TIA!!!

kali
OpenKore Monk
OpenKore Monk
Posts: 457
Joined: 04 Apr 2008, 10:10

Re: Kadiliman Plugin v 1.3 - ChatBot by Kali

#85 Post by kali »

Mucilon, can you do me a bit of a favor?

Could you post up the latest working plugin (with all the fixes and features)? So that I won't have to collate the info first when I go about improving the plugin.

You can just paste it in a code block in a post. Thanks.
Got your topic trashed by a mod?

Trashing topics is one click, and moving a topic to its proper forum is a lot harder. You expend the least effort in deciding where to post, mods expend the least effort by trashing.

Have a nice day.

Mucilon
Cybernatic Entity
Cybernatic Entity
Posts: 249
Joined: 04 Apr 2008, 13:15
Noob?: Yes
Location: Brazil

Re: Kadiliman Plugin v 1.3 - ChatBot by Kali

#86 Post by Mucilon »

Kali
The first post has the latest version... I didn't change anything else, because I stopped to play for some time... I don't have much time now. I didn't change the pm file.
As you asked, here is the plugin with all the changes and features:

Code: Select all

    package kadiliman;

    #
    # This plugin is licensed under the GNU GPL
    # Copyright 2005 by kaliwanagan, now know as Kali
    # Ported by Thrice aka Noface
    # Adds by Mucilon
    # Version 1.3 - 03/04/2008
    # --------------------------------------------------
    #
    # How to install this thing..:
    #
    # in control\config.txt add:
    #
    #chatBot Kadiliman {
    #   inLockOnly 1      # (0|1) Just answer to public chat at lockmap, pm will be answered normally
    #       scriptfile lines.txt   # Name of the file where all sentences are storage, it will be create at openkore root directory
    #       replyRate 80      # (0..100) Rate to answer, 80 means: answer 80% of chats and don't answer 20%
    #       onPublicChat 1      # (0|1) Enable to answer any plublic chat
    #       onPrivateMessage 1   # (0|1) Enable to answer any private message
    #       onSystemChat 1      # (0|1) Enable to answer any system message
    #       onGuildChat 1      # (0|1) Enable to answer any guild chat
    #       onPartyChat 1      # (0|1) Enable to answer any party chat
    #       wpm 65         # Don't need to change - words per minute, simulate typing speed
    #       smileys ^_^,xD,^^,:),XD   # Smileys that may end your sentences on chat (separeted by commas)
    #       smileyRate 20      # Rate to add smiley to the sentences, means: add smileys to 20% of messages
    #       learn 1         # This plugin can "learn" every sentence read by the bot, this sentences are storage at the scriptfile
    #   noPlayers , ,      # Name of the players (supported by regexp) you don't want to answer any thing, like party members (separeted by commas)
    #   noWords  , , ,       # Words (supported by regexp) at the chats you don't want to answer, like "bot", "heal", "buffs" or something like this (separeted by commas)
    #   timesToBlockPM 10   # Number of times of pms received by each player to ignore him, work just to pm
    #   timeToResetCount 300   # Number of seconds to reset the count to ignore any player
    #}

    #This new add will ignore any player that send 10 or more pms to you in 300 seconds. But if he send 9 pms to you and the
    # count is reseted, he will need to send more 10 pms inside the 300 seconds to the plugin ignore him.
    #You can change this 2 last values as you like.

    use strict;
    use Plugins;
    use Globals;
    use Log qw(message warning error debug);
    use Misc;
    use Network;
    use Network::Send;
    use Network::Receive;
    use Chatbot::Kadiliman;
    use I18N qw(bytesToString);
    #use Utils;


    Plugins::register('kadiliman', 'autoresponse bot', \&Unload, \&Reload);
    my $hooks = Plugins::addHooks(
            ['packet/public_chat', \&onMessage, undef],
            ['packet/private_message', \&onMessage, undef],
            ['packet/system_chat', \&onMessage, undef],
            ['packet/guild_chat', \&onMessage, undef],
            ['packet/party_chat', \&onMessage, undef],
            ['start3', \&start3, undef],
            ['AI_post', \&AI_post, undef]
    );

    my $prefix = "chatBot_";
    my %bot;
    my %chatcountPrivate;
    my %chatcountPublic;
    my %Timecount;

    message "Initializing chatBot\n", "plugins";
    for (my $i = 0; (exists $config{$prefix.$i}); $i++) {
            $bot{$i} = new Chatbot::Kadiliman {
            };
    }

    sub Unload {
            Plugins::delHooks($hooks);
    }

    sub Reload {
            for (my $i = 0; (exists $config{$prefix.$i}); $i++) {
                    message "Plugin Kadiliman: checking for duplicate lines in ". $config{$prefix.$i."_scriptfile"} ."...", "plugins";
                    checkForDupes($config{$prefix.$i."_scriptfile"});
                    message "[Kadiliman] done.\n", "plugins";
                    $bot{$i} = new Chatbot::Kadiliman {
                            name        => $config{$prefix.$i},
                            scriptfile      => $config{$prefix.$i."_scriptfile"},
                            learn      => $config{$prefix.$i."_learn"},
                            reply      => 1,
                    };
            }
    }

    sub onMessage {
            my ($packet, $args) = @_;
            my $prefix = "chatBot_";

            for (my $i = 0; (exists $config{$prefix.$i}); $i++) {
          #Don't answer, case it is the own message
          my $msg = $args->{message};
                    my ($chatMsgUser, $chatMsg);
                
          if ($msg =~/:/) {
                            ($chatMsgUser, $chatMsg) = $msg =~ /(.*?).:.(.*)/;
                    } else {
                            $chatMsg = $msg;
                    }
                    return if ($chatMsgUser eq $char->{name});
                
          #Don't answer the player, if he is at _noPlayers from config file
          my @noplayers = split /\s*\,+\s*/, $config{$prefix.$i."_noPlayers"};
          foreach my $player (@noplayers) {
                if ((match($player,$chatMsgUser)) || (match($player,$args->{privMsgUser}))){
                   message "[Kadiliman] Don't answering player $player\n", "plugins";
                   return 1;
                }
          }
          
          #Message Count         
          if ($packet eq 'packet/public_chat') {
                $chatcountPublic{$i}{$chatMsgUser}++;
                message "[Kadiliman] Player $chatMsgUser has spoken on public chat $chatcountPublic{$i}{$chatMsgUser} time(s)\n", "plugins";
                    } elsif ($packet eq 'packet/private_message') {
                my $pmuser = $args->{privMsgUser};
                $chatcountPrivate{$i}{$pmuser}++;
                message "[Kadiliman] Player $pmuser has spoken on PM $chatcountPrivate{$i}{$pmuser} time(s)\n", "plugins";
                if (($chatcountPrivate{$i}{$pmuser} >= $config{$prefix.$i."_timesToBlockPM"}) && ($config{$prefix.$i."_timesToBlockPM"} > 0)) {
                      Commands::cmdIgnore "ignore","1 $pmuser";
                }
                    }
          
          #Don't answer the player, if some word of the message is at _noWords from config file
          my @nowords = split /\s*\,+\s*/, $config{$prefix.$i."_noWords"};
          foreach my $word (@nowords) {
                if (match($word,$chatMsg)){
                   message "[Kadiliman] Don't answering message with word: $word\n", "plugins";
                   return 1;
                }
          }
                
                    $bot{$i}->{reply} = ($config{$prefix.$i."_replyRate"}) ? 1 : 0;
                    $config{$prefix.$i."_replyRate"} = 80 if (!exists $config{$prefix.$i."_replyRate"});
                    $config{$prefix.$i."_replyRate"} = 100 if ($config{$prefix.$i."_replyRate"} > 100);

                    my $type;
                    my $reply;

                    if ($packet eq 'packet/public_chat' && $config{$prefix.$i."_onPublicChat"}) {
             #return if bot isn't at lockmap
             return if (($config{$prefix.$i."_inLockOnly"} > 0) && ($field{name} ne $config{lockMap}));
             $reply = $bot{$i}->transform($chatMsg);
                            $type = "c";
                    } elsif ($packet eq 'packet/system_chat' && $config{$prefix.$i."_onSystemChat"}) {
             $reply = $bot{$i}->transform();
                            $type = "c";
                    } elsif ($packet eq 'packet/guild_chat' && $config{$prefix.$i."_onGuildChat"}) {
                            $reply = $bot{$i}->transform($chatMsg);
                            $type = "g";
                    } elsif ($packet eq 'packet/party_chat' && $config{$prefix.$i."_onPartyChat"}) {
                            $reply = $bot{$i}->transform($chatMsg);
                            $type = "p";
                    } elsif ($packet eq 'packet/private_message' && $config{$prefix.$i."_onPrivateMessage"}) {
                            $reply = $bot{$i}->transform($args->{privMsg});
                            $type = "pm";
                    }


                    # exit if the config option is not enabled
                    return if (!$type);

                    # exit if we don't have any reply
                    return if (!$reply);

                    # add a smiley at the end of the reply
                    my @smileys = split /\,+/, $config{$prefix.$i."_smileys"};
                    $reply .= $smileys[rand(@smileys)] if ((rand(100) < ($config{$prefix.$i."_smileyRate"})));

                    ## COPIED FROM processChatResponse, ChatQueue.pm
                    # Calculate a small delay (to simulate typing)
                    # The average typing speed is 65 words per minute.
                    # The average length of a word used by RO players is 4.25 characters (yes I measured it).
                    # So the average user types 65 * 4.25 = 276.25 charcters per minute, or
                    # 276.25 / 60 = 4.6042 characters per second
                    # We also add a random delay of 0.5-1.5 seconds.
                    $args->{wpm} = $config{$prefix.$i."_wpm"} || 65;
                    my @words = split /\s+/, $reply;
                    my $average;
                    foreach my $word (@words) {
                            $average += length($word);
                    }
                    $average /= (scalar @words);
                    my $typeSpeed = $args->{wpm} * $average / 60;

                    $args->{timeout} = (0.5 + rand(1)) + (length($reply) / $typeSpeed);
                    $args->{time} = time;
                    $args->{stage} = "start";
                    $args->{reply} = $reply;
                    $args->{prefix} = $prefix.$i;
                    $args->{type} = $type;
                    my $rand = rand(100);
                    debug "[Kadiliman] $rand: " . $config{$prefix.$i."_replyRate"} . "\n";
                    AI::queue("chatBot", $args)
                            if ((AI::action ne 'chatBot')
                                    && ($rand < ($config{$prefix.$i."_replyRate"}))
                                    && ($bot{$i}->{reply})
                                    && (main::checkSelfCondition($prefix))
                            );
            }
    }

    sub start3 {
            for (my $i = 0; (exists $config{$prefix.$i}); $i++) {
                    #message "Plugin Kadiliman: checking for duplicate lines in ". $config{$prefix.$i."_scriptfile"} ."...", "plugins";
                    #checkForDupes($config{$prefix.$i."_scriptfile"});
                    message "[Kadiliman] done.\n", "plugins";
                    $bot{$i} = new Chatbot::Kadiliman {
                            name        => $config{$prefix.$i},
                            scriptfile      => $config{$prefix.$i."_scriptfile"},
                            learn      => $config{$prefix.$i."_learn"},
                            reply      => 1,
                    };
            }
    }

    sub AI_post {
            if (AI::action eq 'chatBot') {
                    my $args = AI::args;
                    if ($args->{stage} eq 'end') {
                            AI::dequeue;
                    } elsif ($args->{stage} eq 'start') {
                            $args->{stage} = 'message' if (main::timeOut($args->{time}, $args->{timeout}));
                    } elsif ($args->{stage} eq 'message') {
                            sendMessage($messageSender, $args->{type}, $args->{reply}, $args->{privMsgUser});
                            debug "[Kadiliman] chatBot: $args->{reply}\n", "plugins";
                            $args->{stage} = 'end';
                    }
            }
          #Time to reset the message count (loopless code)
          for (my $i = 0; (exists $config{$prefix.$i}); $i++) {
                if ($Timecount{$i}{start} eq ''){
                      $Timecount{$i}{start} = time;
                      debug "[Kadiliman] start: $Timecount{$i}{start}\n", "plugins";
                }
                $Timecount{$i}{current} = time;

                $Timecount{$i}{toreset} = $config{$prefix.$i."_timeToResetCount"};
                if (($Timecount{$i}{toreset} ne '') || ($Timecount{$i}{toreset} > 0)) {
                      $Timecount{$i}{after} = $Timecount{$i}{start} + $Timecount{$i}{toreset};
                      if ($Timecount{$i}{current} >= $Timecount{$i}{after}){
                            #message "[Kadiliman] Reseted, start: $Timecount{$i}{start}, time now: $Timecount{$i}{current}, next: $Timecount{$i}{after}, time to count: $Timecount{$i}{toreset}\n", "plugins";
                            message "[Kadiliman] Chat count reseted, next in $Timecount{$i}{toreset} secs\n", "plugins";
                            $Timecount{$i}{start} = time;
                            delete $chatcountPublic{$i};
                            delete $chatcountPrivate{$i};
                      }
                }
          }
    }


    sub match
    {
            my ($pattern,$subject) = @_;
            if (my ($re, $ci) = $pattern =~ /^\/(.+?)\/(i?)$/)
            {       
                    if (($ci && $subject =~ /$re/i) || (!$ci && $subject =~ /$re/))
                    {
                            return 1;
                    }
            }
            elsif ($subject eq $pattern)
            {
                    return 1;
            }
            return 0;
    }


    sub checkForDupes {
            my $scriptfile = shift;
            my %self;

            $scriptfile = "lines.txt" if ($scriptfile eq 1);

            # read scriptfile in (the whole thing, all at once).
            my @scriptlines;
            if (open (SCRIPTFILE, "<$scriptfile")) {
                    @scriptlines = <SCRIPTFILE>; # read in script data
                    close (SCRIPTFILE);
            }

            # check for duplicate lines
            for (my $i = 0; $i < (scalar @scriptlines); $i++) {
                    for (my $j = $i + 1; $j < (scalar @scriptlines); $j++) {
                            $scriptlines[$i] = '' if ($scriptlines[$i] eq $scriptlines[$j]);
                    }
            }

            # save cleaned-up file
            open (SCRIPTFILE, ">$scriptfile");
            foreach my $line (@scriptlines) {
                    print SCRIPTFILE ("$line");
            }
            close (SCRIPTFILE);
    }

    return 1;

kali
OpenKore Monk
OpenKore Monk
Posts: 457
Joined: 04 Apr 2008, 10:10

Re: Kadiliman Plugin v 1.3 - ChatBot by Kali

#87 Post by kali »

Ah, so the message creation logic was not changed at all. Just the interface to OpenKore :)

Thanks a lot. I plan on merging the message creation as well as the interface so it's easier to install. Maybe then with v1.4 we can close this thread and open up a new one?
Got your topic trashed by a mod?

Trashing topics is one click, and moving a topic to its proper forum is a lot harder. You expend the least effort in deciding where to post, mods expend the least effort by trashing.

Have a nice day.

Mucilon
Cybernatic Entity
Cybernatic Entity
Posts: 249
Joined: 04 Apr 2008, 13:15
Noob?: Yes
Location: Brazil

Re: Kadiliman Plugin v 1.3 - ChatBot by Kali

#88 Post by Mucilon »

Yep, sure we can...
About the plugin there is one little issue, the sub check for dupes is disable, so the file keeps a lots of duplicate lines... as I didn't analyze the pm file, I don't know if it uses the duplicate lines to calculate the rate of sentences to answer or if it doesn't matter...

Are you thinking in change the message creation logic, like a conversation bot? Where it will learn not just the sentences, but the possible sequence of the sentences too... or something like that!
About a 15 years ago, a friend of mine show me a chat bot program and I though it was quite impressive. Considering that I didn't speak English very well at the time. But I could see that it was learning, because it repeated some words that I wrote wrong! :lol: And more then this... it always answered coherent sentences, but some times it changed the subject.

freezer123
Plain Yogurt
Plain Yogurt
Posts: 90
Joined: 28 Jul 2008, 05:12
Noob?: No

Re: Kadiliman Plugin v 1.3 - ChatBot by Kali

#89 Post by freezer123 »

This is a great and awesome plugins.. /no1. I have installed it and it works great. many thanks Kali and Mucilon.
Image

Technology
Super Moderators
Super Moderators
Posts: 801
Joined: 06 May 2008, 12:47
Noob?: No

Re: Kadiliman Plugin v 1.3 - ChatBot by Kali

#90 Post by Technology »

kadiliman plugin is now in SVN:
https://openkore.svn.sourceforge.net/sv ... kadiliman/

is it fully functional on openkore SVN version?
One ST0 to rule them all? One PE viewer to find them!
One ST_kRO to bring them all and in the darkness bind them...

Mount Doom awaits us, fellowship of OpenKore!

Post Reply