User Tools

Site Tools


bot:seer

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

bot:seer [2018/02/21 21:37] โ€“ created karlbot:seer [2018/02/21 21:48] (current) โ€“ removed karl
Line 1: Line 1:
-====== BOT Seer ====== 
  
-The BOT //Seer// found on the [[:servers:metalforge]] [[http://www.metalforge.net|.net]] server is working. \\ 
-As a player, I use him occasionally. 
- 
-This is what the client cmdline ''tell Seer help'' responds : 
-<code> 
-Seer tells you:  
-I'm a bot, and I'm writing kill logs for all players and monsters. 
- 
-You can ask me about: 
- last <player>  to see when the player was here 
- last           to see the last 10 logins/logouts 
- 
-Seer tells you:  
- uptime         for the time the server's up (at least) 
- tell <player> <something> to let me tell the player something when I see him 
- maps           to see the most popular maps 
- 
-Seer tells you:  
- kills <name>   to see what a player or monster has killed and how 
- numkills <name>   to see how many times someone killed 
- how killed <name> to see how someone prefers to kill 
- 
-Seer tells you:  
- deaths <name>  to see who killed a player or monster and how 
- numdeaths <name>  to see how many times someone died 
- how died <name>   to see how someone prefers to die 
- 
-Seer tells you:  
- what killed <name> to see what attack caused someone to die 
- did <name> kill <name> to see if/how somebody killed somebody 
- 
- find <name>       to see all matching monsters or players 
- 
-Seer tells you:  
-Besides this, I'm afraid I'm not very intelligent. :) 
-</code> 
- 
-Some years ago (Modification time tells me February 2013), I found a [[:client_side_scripting:perl:]] script on the net, that contains the above lines.   
-<code> 
-This is Google's cache of http://www.suckfuell.net/jochen/cfbot/cfbot. 
-It is a snapshot of the page as it appeared on Feb 16, 2013 04:44:39 
-GMT. The current page <http://www.suckfuell.net/jochen/cfbot/cfbot> 
-could have changed in the meantime. Learn more 
-<http://support.google.com/websearch/bin/answer.py?hl=en&p=cached&answer=1687222> 
-Tip: To quickly find your search term on this page, press *Ctrl+F* or 
-*โŒ˜-F* (Mac) and use the find bar. 
- 
-Text-only version 
-<http://webcache.googleusercontent.com/search?q=cache:KLwoFyJLg7UJ:www.suckfuell.net/jochen/cfbot/cfbot+cfbot+crossfire&hl=en&gl=us&strip=1> 
-These search terms are highlighted: cfbot crossfire   
-</code> 
-It is a  //GNU General Public License// file by ''Copyright (C) 2003 Jochen Suckfuell <*crossfire* WHAT suckfuell.net>'' . 
-<code pl> 
-#!/usr/bin/perl -w 
- 
-# 
-# ------------------------------------------------------------------------- 
-# 
-#    Copyright (C) 2003 Jochen Suckfuell <*crossfire* WHAT suckfuell.net> 
-# 
-#    This program is free software; you can redistribute it and/or modify 
-#    it under the terms of the GNU General Public License as published by 
-#    the Free Software Foundation; either version 2 of the License, or 
-#    (at your option) any later version. 
-# 
-#    This program is distributed in the hope that it will be useful, 
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of 
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
-#    GNU General Public License for more details. 
-# 
-#    You should have received a copy of the GNU General Public License 
-#    along with this program; if not, write to the Free Software 
-#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
-# 
-# ----------------------------------------------------------------------- 
-# 
-# TODO 
-# 
-#  - fix inventory logging 
-#  - check if event_wait and event_listen loops work 
-# 
-# 
-# Changelog: 
- 
-# 2005-05-28 0.9.9 
-#  - added the setup flag "bot 1" to tell the server that this is a bot 
-# 
-# 2004-03-11 0.9.8 
-#  - new commands: add_admin, rem_admin, admins 
-#  - added the admin commands to the help output 
-#  - removed the "host" command, since 'who doesn't show the IP any more 
-#  - fixed parsing changed 'who output format 
-#  - save the is_admin flag with the players 
-#  - allow several admin users 
-#  - implement numdeaths, numkills 
-#  - 'forget <script>' and 'stop <script>' commands implemented 
-#  - implemented storing more stats 
-#  - added events_stats callbacks 
-#  - we now log the players that enter a map whose name matches a pattern in 
-#    the predefined array @check_maps 
- 
-# 2003-02-13 Release 0.9.7 
- 
-#  - 'last <player>' now also shows the host name 
-#  - implemented the 'host <player>' command which tells the player's hostname 
-#  - Don't answer to "hi" if not addressed directly. 
- 
-# 2003-02-04 Release 0.9.6 
-# 
-#  - implemented script command "when hearing <whatever>" 
-# 
-#   
-# 2003-02-03 Release 0.9.5 
- 
-#  - implemented simple scripting commands, conditions are still missing 
-#  - slowed down the decay of map scores 
-#  - output integer values for map scores 
-#  - use the 'ncom' protocol command instead of 'command' 
-#  - only reply to "hello|hi" to players that talked to me before 
- 
-</code> 
-I am not capable in the //perl// scripting language, and can not say anything about this script. 1900 lines :  
-<code perl> 
-#!/usr/bin/perl -w 
- 
-# 
-# ------------------------------------------------------------------------- 
-# 
-#    Copyright (C) 2003 Jochen Suckfuell <*crossfire*@suckfuell.net> 
-# 
-#    This program is free software; you can redistribute it and/or modify 
-#    it under the terms of the GNU General Public License as published by 
-#    the Free Software Foundation; either version 2 of the License, or 
-#    (at your option) any later version. 
-# 
-#    This program is distributed in the hope that it will be useful, 
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of 
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
-#    GNU General Public License for more details. 
-# 
-#    You should have received a copy of the GNU General Public License 
-#    along with this program; if not, write to the Free Software 
-#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
-# 
-# ----------------------------------------------------------------------- 
-# 
-# TODO 
-# 
-#  - fix inventory logging 
-#  - check if event_wait and event_listen loops work 
-# 
-# 
-# Changelog: 
- 
-# 2005-05-28 0.9.9 
-#  - added the setup flag "bot 1" to tell the server that this is a bot 
-# 
-# 2004-03-11 0.9.8 
-#  - new commands: add_admin, rem_admin, admins 
-#  - added the admin commands to the help output 
-#  - removed the "host" command, since 'who doesn't show the IP any more 
-#  - fixed parsing changed 'who output format 
-#  - save the is_admin flag with the players 
-#  - allow several admin users 
-#  - implement numdeaths, numkills 
-#  - 'forget <script>' and 'stop <script>' commands implemented 
-#  - implemented storing more stats 
-#  - added events_stats callbacks 
-#  - we now log the players that enter a map whose name matches a pattern in 
-#    the predefined array @check_maps 
- 
-# 2003-02-13 Release 0.9.7 
- 
-#  - 'last <player>' now also shows the host name 
-#  - implemented the 'host <player>' command which tells the player's hostname 
-#  - Don't answer to "hi" if not addressed directly. 
- 
-# 2003-02-04 Release 0.9.6 
-# 
-#  - implemented script command "when hearing <whatever>" 
-# 
-#   
-# 2003-02-03 Release 0.9.5 
- 
-#  - implemented simple scripting commands, conditions are still missing 
-#  - slowed down the decay of map scores 
-#  - output integer values for map scores 
-#  - use the 'ncom' protocol command instead of 'command' 
-#  - only reply to "hello|hi" to players that talked to me before 
- 
- 
-# 
- 
-# 
-# 
-# 
- 
-# ======================  configuration section  ======================== 
- 
-use vars qw/$remote_host $player_name $player_password $retry_interval $admin $leave_cmd %players %kills %maps $socket $recvbuf $quit $upsince $getting_who_answer $last_maps_decay_time $version $pkg_sent $pkg_ackd @cmds_waiting $learning %scripts @events_wait @events_listen @events_stats %script_stack %stats %inv %checked_map @check_map/; 
- 
-$remote_host = "127.0.0.1"; 
-$player_name = "*cfbot*"; 
-$player_password = "SeCrEt"; 
-$retry_interval = 30; # time in seconds 
-$admin = " "; 
-$leave_cmd = "go home"; 
- 
-# We keep a player log for these maps: 
-@check_map = ( "^/guilds/" ); 
- 
-# ===================  no configuration below  ========================== 
- 
-$version = "0.9.6"; 
-   
-use POSIX; 
-use IO::Socket; 
-use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK); 
- 
- 
-$events_stats{'maxhp'} = []; 
-$events_stats{'maxsp'} = []; 
-$events_stats{'maxgrace'} = []; 
-$events_stats{'lowfood'} = []; 
- 
-load(); 
- 
-$socket = ''; 
-init_connection(); 
- 
-$recvbuf = ''; 
-$quit = 0; 
-my $save_minutes = 10; # This will be counted down and reset to 10, below. 
- 
-my $last_time = time; 
-$getting_who_answer = 0; 
-$last_maps_decay_time = time; 
- 
-$SIG{INT} = sub { $quit = 1; print STDERR "SIGINT\n"; }; 
- 
-# main event loop 
-while(! $quit) 
-{ 
- my $r_in = ''; 
- vec($r_in, $socket->fileno, 1) = 1; 
- 
- my $rv = select($r_in, undef, undef, 1); 
- if(!defined($rv) || $rv < 0) 
- { 
- unless($! == EINTR) { die "select failed: $!"; } 
- last; 
- } 
- 
- if($rv && vec($r_in, $socket->fileno, 1) == 1) 
- { 
- my $rv = $socket->recv($buf, POSIX::BUFSIZ, 0); 
- unless (defined($rv)) 
- { 
- print STDERR "recv failed: $!\n"; 
- init_connection(); 
- $recvbuf = ''; 
- next; 
- } 
-  
- if(length($buf) == 0) 
- { 
- print STDERR "Connection closed.\n"; 
- init_connection(); 
- $recvbuf = ''; 
- next; 
- } 
- $recvbuf .= $buf; 
- while(length($recvbuf) >= 2) 
- { 
- my $len = unpack("n", $recvbuf); 
- #print "DEBUG len $len , recvbuf length is ".length($recvbuf)."\n"; 
- 
- if(length($recvbuf) < 2 + $len) { last; } 
-  
- #print unpack("H*", $recvbuf)."\n"; 
- my $data = substr($recvbuf, 2, $len); 
- handle($data); 
- $recvbuf = substr($recvbuf, $len + 2); 
- } # len info 
- } # $socket is readable 
- 
- my $now = time; 
- next if $last_time == $now; 
- 
- if($now - $last_time > 60) 
- { 
- # This is processed once per minute. 
- 
- $last_time = $now; 
- 
- $save_minutes--; 
- if($save_minutes == 0) 
- { 
- save(); 
- $save_minutes = 10; 
- } 
- 
- if($now - $last_maps_decay_time > 24*60*60) 
- { 
- # once per day 
-  
- # We halve the map score values once per day: 
- foreach my $map (keys %maps) 
- { 
- $maps{$map} *= 0.25; 
- if($maps{$map} == 0) { delete $maps{$map}; } 
- } 
- $last_maps_decay_time = $now; 
- } 
-  
- cf_send_cmd("who"); # update maps' popularity 
- } 
- 
- for(my $i = 0; $i < scalar @events_wait; $i++) 
- { 
- my $event_ref = $events_wait[$i]; 
- if($event_ref->{"continue_at"} <= $now) 
- { 
- splice @events_wait, $i, 1; # remove the event from the list 
- do_execute($event_ref->{"script"}, $event_ref->{"pc"}); 
- } 
- } 
-  
-} 
- 
-save(); 
- 
-exit 0; 
- 
-# =============================================================== 
- 
-sub init_connection 
-{ 
- if($socket) { $socket->close(); } 
- while(!($socket = IO::Socket::INET->new(PeerAddr => $remote_host, PeerPort => 13327, Proto => "tcp", Type => SOCK_STREAM))) 
- { 
- print STDERR "Couldn't connect to $remote_host:13327 : $@\n"; 
- print STDERR "Retrying in $retry_interval seconds.\n"; 
- sleep $retry_interval; 
- } 
- 
- my $flags = fcntl($socket, F_GETFL, 0) or die "Can't get flags for socket: $!\n"; 
- fcntl($socket, F_SETFL, $flags | O_NONBLOCK) or die "Can't make socket nonblocking: $!\n"; 
- 
- $pkg_sent = 0; 
- $pkg_ackd = 0; 
- cf_send("version 1027 1027 Perl Bot"); 
- cf_send("setup map1cmd 1 map1acmd 1 sound 0 sexp 0 darkness 0 newmapcmd 0 faceset 0 facecache 1 itemcmd 1 bot 1"); 
- cf_send("addme"); 
- $upsince = time; 
- print "Login at ".localtime($upsince)."\n"; 
-} 
- 
-sub handle 
-{ 
- my $line = shift; 
- $line =~ /^(\S+)\s*(.*)$/s or die "Cannot match '$line'"; 
- my $cmd = $1; 
- my $args = $2; 
- 
- if($cmd =~ /^drawinfo$/) 
- { 
- $args =~ /^(\S+)\s*(.*)$/s; 
- my $color = $1; 
- my $info = $2; 
- 
- if($getting_who_answer) 
- { 
- $getting_who_answer = parse_who($info); 
- 
- # Return if we got another WHO line, else process the new line as 
- # normal. 
- return if $getting_who_answer; 
- } 
-  
- if($info =~ /^((?:(?! killed) ?[a-zA-Z0-9'_-]+)+) killed /) 
- { 
- if(defined $kills{$info}) 
- { 
- $kills{$info}++; 
- } 
- else 
- { 
- $kills{$info} = 1; 
- } 
- return; 
- } 
- 
- if($info =~/^Players:$/) 
- { 
- $getting_who_answer = 1; 
- return; 
- } 
- 
- if($info =~ /^(\S+) has entered the game.$/) 
- { 
- my $name = $1; 
- $player_ref = $players{$name}; 
- unless(defined $player_ref) 
- { 
- $player_ref = { asked_me => 0, message => "", is_admin => 0 }; 
- $players{$name} = $player_ref; 
- } 
- elsif($player_ref->{"message"}) 
- { 
- my $msg = $player_ref->{"message"}; 
- $msg =~ s/_-/\n/g; 
- sleep 3; 
- cf_send_info("tell $name", "Hi $name!$msg"); 
- $player_ref->{"message"} = ""; 
- } 
-  
- $player_ref->{"last_seen"} = time; 
- $player_ref->{"is_here"} = 1; 
- 
-  
- print ">$info\n"; 
- return; 
- } 
- 
- if($info =~ /^(\S+) (leaves|left) the game.$/) 
- { 
- my $name = $1; 
- $player_ref = $players{$name}; 
- unless(defined $player_ref) 
- { 
- $player_ref = { asked_me => 0, message => "" }; 
- $players{$name} = $player_ref; 
- } 
- $player_ref->{"last_seen"} = time; 
- $player_ref->{"is_here"} = 0; 
-  
- return; 
- } 
- 
- if($info =~ /^(\S+) tells you: (.*)\??$/) 
- { 
- handle_player_request($1, $2, "tell $1"); 
- return; 
- } 
- 
- if($info =~ /^(\S+) shouts: $player_name[:,!]? *(.*)\??$/) 
- { 
- handle_player_request($1, $2, "shout"); 
- return; 
- } 
- 
- if($info =~ /^(\S+) shouts: (hi\b|hello|morning)\s+$player_name!?/i) 
- { 
- my $pl = $1; 
- return if $pl eq $player_name; 
- my $pl_ref = $players{$pl}; 
- return unless (defined $pl_ref && $pl_ref->{"asked_me"}); 
- sleep 3; 
- cf_send_cmd("shout $2 $1"); 
- return; 
- } 
- 
- if($info =~ /^Welcome Back!$/) 
- { 
- cf_send_cmd("listen 15"); 
- cf_send_cmd("who"); 
- if(defined $scripts{"autorun"}) 
- { 
- $script_stack{"autorun"} = []; 
- do_execute("autorun"); 
- } 
- return; 
- } 
- 
- # Blue color text (in cfclient at least) is for NPC speech and other 
- # messages from the map. 
- if($color == 2) 
- { 
- for(my $i = 0; $i < scalar @events_listen; $i++) 
- { 
- my $event_ref = $events_listen[$i]; 
- if($info =~ /$event_ref->{"listen_text"}/ms) 
- { 
- splice @events_listen, $i, 1; # remove the event from the list 
- do_execute($event_ref->{"script"}, $event_ref->{"pc"}); 
- } 
- } 
- } 
- 
- #print "INFO: $color $info\n"; 
-  
- return; 
- } 
- 
- if($cmd =~ /^query$/) 
- { 
- print "$args "; 
- if($args =~ /What is your name/) 
- { 
- cf_send("reply $player_name"); 
- return; 
- } 
-  
- if($args =~ /What is your password/) 
- { 
- cf_send("reply $player_password"); 
- return; 
- } 
-  
- if($args =~ /Do you want to play again/) 
- { 
- cf_send("reply a"); 
- return; 
- } 
-  
- my $answer = <STDIN>; 
- chomp $answer; 
- cf_send("reply $answer"); 
- return; 
- } 
-  
- if($cmd =~ /^comc$/) 
- { 
- ($pkg_ackd) = unpack("n", $args); 
- if(scalar @cmds_waiting) 
- { 
- $pkg_sent++; 
- if($pkg_sent == 256) { $pkg_sent = 0; } 
- cf_send("ncom ".pack("n", $pkg_sent)."\0\0\0\1".(shift @cmds_waiting)); 
- } 
- 
- return; 
- } 
-  
- if($cmd =~ /^stats$/) 
- { 
- while($args) 
- { 
- my $s; 
- ($s, $args) = unpack ('C a*', $args); 
- last if $s > 26; 
- if($s == 18) # food 
- { 
- ($stats{'food'}, $args) = unpack('n a*', $args); 
- #print "food: $stats{food}\n"; 
- if($stats{'food'} < 80) 
- { 
- foreach my $event_ref (@{$events_stats{'lowfood'}}) 
- { 
- do_execute($event_ref->{"script"}, $event_ref->{"pc"}); 
- } 
- $events_stats{ 'lowfood'} = []; 
- } 
- } 
- elsif($s == 1) # HP 
- { 
- ($stats{'hp'}, $args) = unpack('n a*', $args); 
- #print "hp: $stats{hp}\n"; 
- if(defined $stats{'maxhp'} && $stats{'hp'} ==  $stats{'maxhp'}) 
- { 
- @events = @{$events_stats{'maxhp'}}; 
- $events_stats{ 'maxhp'} = []; 
- foreach my $event_ref (@events) 
- { 
- do_execute($event_ref->{"script"}, $event_ref->{"pc"}); 
- } 
- $events_stats{ 'maxhp'} = []; 
- } 
- } 
- elsif($s == 2) # max HP 
- { 
- ($stats{'maxhp'}, $args) = unpack('n a*', $args); 
- #print "maxhp: $stats{maxhp}\n"; 
- } 
- elsif($s == 3) # SP 
- { 
- ($stats{'sp'}, $args) = unpack('n a*', $args); 
- #print "sp: $stats{sp}\n"; 
- if(defined $stats{'maxsp'} && $stats{'sp'} ==  $stats{'maxsp'}) 
- { 
- @events = @{$events_stats{'maxsp'}}; 
- $events_stats{ 'maxsp'} = []; 
- foreach my $event_ref (@events) 
- { 
- do_execute($event_ref->{"script"}, $event_ref->{"pc"}); 
- } 
- } 
- } 
- elsif($s == 4) # max SP 
- { 
- ($stats{'maxsp'}, $args) = unpack('n a*', $args); 
- #print "maxsp: $stats{maxsp}\n"; 
- } 
- elsif($s == 23) # grace 
- { 
- ($stats{'grace'}, $args) = unpack('n a*', $args); 
- #print "grace: $stats{grace}\n"; 
- if(defined $stats{'maxgrace'} && $stats{'grace'} ==  $stats{'maxgrace'}) 
- { 
- @events = @{$events_stats{'grace'}}; 
- $events_stats{ 'grace'} = []; 
- foreach my $event_ref (@events) 
- { 
- do_execute($event_ref->{"script"}, $event_ref->{"pc"}); 
- } 
- $events_stats{ 'maxgrace'} = []; 
- } 
- } 
- elsif($s == 24) # max SP 
- { 
- ($stats{'maxgrace'}, $args) = unpack('n a*', $args); 
- #print "maxgrace: $stats{maxgrace}\n"; 
- } 
- elsif($s == 11) # exp 
- { 
- ($stats{'exp'}, $args) = unpack('N a*', $args); 
- #print "exp: $stats{exp}\n"; 
- } 
- elsif($s == 12) # level 
- { 
- ($stats{'level'}, $args) = unpack('n a*', $args); 
- print "level: $stats{level}\n"; 
- } 
- elsif($s == 13) # WC 
- { 
- my $wc; 
- ($wc, $args) = unpack('n a*', $args); 
- $stats{'wc'} = ($wc > 32767 ? $wc - 65536 : $wc); 
- print "wc: $stats{wc}\n"; 
- } 
- elsif($s == 14) # AC 
- { 
- my $ac; 
- ($ac, $args) = unpack('n a*', $args); 
- $stats{'ac'} = ($ac > 32767 ? $ac - 65536 : $ac); 
- print "ac: $stats{ac}\n"; 
- } 
- elsif($s == 17 || $s == 19 || $s == 26) 
- { 
- (undef, $args) = unpack('N a*', $args); 
- } 
- else 
- { 
- (undef, $args) = unpack('n a*', $args); 
- } 
- } 
- return; 
- } 
-  
- if($cmd =~ /^item1$/) 
- { 
- my ($location, $tag, $flags, $weight, $name, $nrof); 
- %inv = (); 
- ($location, $args) = unpack ('N a*', $args); 
- return unless $location; 
- while($args) 
- { 
- ($tag, $flags, $weight, undef, $name, undef, undef, $nrof, $args) = unpack ('N N N N C/A n C N a*', $args); 
- ($name, undef) = split /\0/, $name; 
- $inv{$tag} = { name => $name, flags => $flags, weight => $weight, nrof => $nrof }; 
- #print "INV1: $nrof $name ($weight)\n"; 
- } 
- return; 
- } 
-  
- if($cmd =~ /^item2$/) 
- { 
- my ($location, $tag, $flags, $weight, $name, $nrof); 
- %inv = (); 
- ($location, $args) = unpack ('N a*', $args); 
- return unless $location; 
- while($args) 
- { 
- ($tag, $flags, $weight, undef, $name, undef, undef, $nrof, undef, $args) = unpack ('N N N N C/A n C N n a*', $args); 
- $inv{$tag} = { name => $name, flags => $flags, weight => $weight, nrof => $nrof }; 
- #print "INV2: $nrof $name ($weight)\n"; 
- } 
- return; 
- } 
-  
- if($cmd =~ /^map|^face2$|^delinv$|^anim$|^player$/) 
- { 
- return; 
- } 
- 
- print ">$cmd"; 
-  
- if( 
- $cmd =~ /^setup$/ 
- ) 
- { 
- print " $args"; 
- } 
- print "\n"; 
-} 
- 
- 
-sub handle_player_request 
-{ 
- my $player = shift; 
- my $request = shift; 
- my $answer_command = shift; 
- 
- $player_ref = $players{$player}; 
- unless(defined $player_ref) 
- { 
- $player_ref = { asked_me => 0, last_seen => time, is_here => 1, message => "" }; 
- $players{$player} = $player_ref; 
- } 
- 
- $player_ref->{"asked_me"}++; 
- 
- if($learning && $admin =~ / $player /) 
- { 
- # This continues a script. 
- if($request eq "end $learning") 
- { 
- cf_send_cmd("$answer_command Ok, I learnt $learning."); 
- $learning = ""; 
- return; 
- } 
- 
- push @{$scripts{$learning}}, $request; 
- return; 
- } 
-  
- #cf_send_cmd("tell $admin PL_REQ $player $request"); 
- if($request =~ /^(hi|hello)/i) 
- { 
- sleep 2; 
- cf_send_cmd("$answer_command $1 $player!"); 
- return; 
- } 
- 
- if($request =~ /^(help|what do you do|what can you do|how can you help|who are you|yes)/i) 
- { 
- cf_send_info($answer_command, <<HELP); 
-I'm a bot, and I'm writing kill logs for all players and monsters. 
- 
-You can ask me about: 
- 
- last <player>  to see when the player was here 
- last           to see the last 10 logins/logouts 
- uptime         for the time the server's up (at least) 
- tell <player> <something> to let me tell the player something when I see him 
- maps           to see the most popular maps 
- 
- kills <name>   to see what a player or monster has killed and how 
- numkills <name>   to see how many times someone killed 
- how killed <name> to see how someone prefers to kill 
- 
- deaths <name>  to see who killed a player or monster and how 
- numdeaths <name>  to see how many times someone died 
- who killed <name> to see who killed someone 
- what killed <name> to see what attack caused someone to die 
- 
-Besides this, I'm afraid I'm not very intelligent. :) 
- 
-HELP 
- if($players{$player}{is_admin} == 1) 
- { 
- cf_send_info($answer_command, <<ADMIN_HELP); 
-Special admin commands are: 
- 
- do <command>        sends the command to the server 
- learn <scriptname>  starts recording server commands to a script 
- end <scriptname>    ends learning a script [don't recurse!] 
- execute <scriptname> execute a script 
- running             shows all currently running scripts 
- scripts             shows the names of all known scripts 
- stop <scriptname>   stops a running script 
- forget <scriptname> deletes a script 
- 
- stats               to see my character statistics 
- add_admin <player>  to add a player to my admin list 
- rem_admin <player>  to remove a player from my admin list 
- admins              to see who is on my admin lists 
-  
- For my scripting abilities please check the document at: 
- http://www.suckfuell.net/*cfbot*/cfbot_script.txt 
- 
-ADMIN_HELP 
- } 
- return; 
- } 
-  
- if($request =~ /^tell\s+(\S+)\s+(.*)$/) 
- { 
- my $other = $1; 
- my $other_ref = $players{$other}; 
- unless(defined $other_ref) 
- { 
- cf_send_cmd("$answer_command Sorry, I don't know $other yet."); 
- return; 
- } 
- my $msg = "\n$player wants me to tell you:\n\"$2\""; 
- 
- if($other_ref->{"is_here"}) 
- { 
- cf_send_info("command tell $other", $msg); 
- sleep 2; 
- cf_send_cmd("$answer_command I told him what you said."); 
- return; 
- } 
-  
- $msg =~ s#\n#_-#g; 
- $other_ref->{"message"} .= $msg; 
- sleep 2; 
- cf_send_cmd("$answer_command I will tell him when I see him."); 
- return; 
- } 
-  
- if($request =~ /^last\s+(\S+)$/) 
- { 
- my $other = $1; 
- 
- unless(defined $players{$other}) 
- { 
- cf_send_cmd("$answer_command I haven't seen $other."); 
- return; 
- } 
- 
- sleep 2; 
- cf_send_cmd("$answer_command $other was here at ".gmtime($players{$other}{"last_seen"})." GMT"); 
- return; 
- } 
- 
- if($request =~ /^last$/i) 
- { 
- my @last_seen = sort { $players{$b}{last_seen} <=> $players{$a}{last_seen} } keys %players; 
- my $i = 0; 
- my $out = ""; 
- foreach my $pl (@last_seen) 
- { 
- next if $players{$pl}{"is_here"}; 
- $out .= "\n$pl was here at ".gmtime($players{$pl}{"last_seen"})." GMT."; 
- $i++; 
- last if $i == 10; 
- } 
- cf_send_info($answer_command, $out); 
- return; 
- } 
- 
- if($request =~ /uptime/i) 
- { 
- sleep 2; 
- cf_send_cmd("$answer_command The server has been up at least since ".gmtime($upsince)." (GMT)."); 
- return; 
- } 
-  
- if($request =~ /^kills\s+(.*)$/) 
- { 
- my $name = $1; 
- chomp $name; 
- my $info = ""; 
- my $total = 0; 
- foreach my $kill (sort { $kills{$b} <=> $kills{$a} } keys %kills) 
- { 
- if($kill =~ /^$name killed /i) 
- { 
- $info .= $kills{$kill}." times ".$kill."\n"; 
- $total += $kills{$kill}; 
- } 
- } 
- 
- if(!$info) 
- { 
- cf_send_cmd("$answer_command $name hasn't killed anything yet."); 
- return; 
- } 
-  
- $info .= "\nThat's a total of $total kills."; 
-  
- 
- cf_send_info($answer_command, "\n$info"); 
- return; 
- 
-  
- if($request =~ /^numkills\s+(.*)$/) 
- { 
- my $name = $1; 
- chomp $name; 
- my $total = 0; 
- foreach my $kill (sort { $kills{$b} <=> $kills{$a} } keys %kills) 
- { 
- if($kill =~ /^$name killed /i) 
- { 
- $total += $kills{$kill}; 
- } 
- } 
- 
- cf_send_cmd("$answer_command $name has killed $total times."); 
- return; 
- 
-  
- if($request =~ /^numdeaths\s+([^?]*)$/i) 
- { 
- my $name = $1; 
- chomp $name; 
- my $total = 0; 
- foreach my $kill (sort { $kills{$b} <=> $kills{$a} } keys %kills) 
- { 
- if($kill =~ / killed $name(\.| with )/i) 
- { 
- $total += $kills{$kill}; 
- } 
- } 
- 
- cf_send_cmd("$answer_command $name died $total times."); 
- return; 
- 
- 
- if($request =~ /^(?:deaths|who killed)\s+([^?]*)$/i) 
- { 
- my $name = $1; 
- chomp $name; 
- my $info = ""; 
- my $total = 0; 
- foreach my $kill (sort { $kills{$b} <=> $kills{$a} } keys %kills) 
- { 
- if($kill =~ / killed $name(\.| with )/i) 
- { 
- $info .= "\n".$kills{$kill}." times ".$kill; 
- $total += $kills{$kill}; 
- } 
- } 
- 
- if(!$info) 
- { 
- cf_send_cmd("$answer_command $name hasn't been killed yet."); 
- return; 
- } 
- 
- $info .= "\nThat's a total of $total."; 
-  
- cf_send_info($answer_command, $info); 
- return; 
- 
- 
- if($request =~ /find\s+(.*)$/i) 
- { 
- my $who = $1; 
- if(length($who) < 3) 
- { 
- cf_send_cmd("$answer_command The query must be at least two characters long."); 
- return; 
- } 
- 
- my %matches = (); 
- my $info = ""; 
- foreach my $kill (sort { $kills{$b} <=> $kills{$a} } keys %kills) 
- { 
- unless($kill =~ /^(\S+(?:(?! killed ) \S*)*) killed ([^\s\.]+(?:\s(?!with )[^\s\.]*)*)/) 
- { 
- #print STDERR "find regexp failed, '$kill' => '$1' killed '$2'\n"; 
- next; 
- } 
- 
- my $name1 = $1; 
- my $name2 = $2; 
- next if defined $matches{$name1}; 
- next if defined $matches{$name2}; 
- #print STDERR "match: '$name1' '$name2'\n"; 
- if($name1 =~ /$who/i) 
- { 
- $matches{$name1} = 1; 
- $info .= "\n$name1"; 
- } 
- if($name2 =~ /$who/i) 
- { 
- $matches{$name2} = 1; 
- $info .= "\n$name2"; 
- } 
- } 
- 
- if(!$info) 
- { 
- cf_send_cmd("$answer_command I haven't found a match for '$who'."); 
- return; 
- } 
-  
- $info = "Matching '$who' I found:".$info; 
-  
- cf_send_info($answer_command, $info); 
- return; 
- } 
-  
- if($request =~ /did\s+((?! kill ).+) kill ([^?]+)$/i) 
- { 
- my $name = $1; 
- my $killed = $2; 
- 
- my $info = ""; 
- foreach my $kill (sort { $kills{$b} <=> $kills{$a} } keys %kills) 
- { 
- if($kill =~ /$name killed $killed(\.| with )/i) 
- { 
- $info .= "\n".$kills{$kill}." times ".$kill; 
- } 
- } 
- 
- if(!$info) 
- { 
- cf_send_cmd("$answer_command $name hasn't killed $killed yet."); 
- return; 
- } 
-  
- cf_send_info($answer_command, $info); 
- return; 
- } 
-  
- if($request =~ /^how killed\s+([^?]*)$/i) 
- { 
- my $name = $1; 
- chomp $name; 
- my %count; 
- foreach my $kill (keys %kills) 
- { 
- if($kill =~ /^($name) killed (?:(?!with )[^.])*([^.]*)\.$/i) 
- { 
- my $type = $2; 
- if(! $type) { $type = "with melee"; } 
- if(defined $count{$type}) 
- { 
- $count{$type} += $kills{$kill}; 
- } 
- else 
- { 
- $count{$type} = $kills{$kill}; 
- } 
- } 
- } 
-  
- if(scalar keys %count == 0) 
- { 
- cf_send_cmd("$answer_command $name hasn't killed yet."); 
- return; 
- } 
- 
- my $info = "$1 killed"; 
- foreach my $c (sort { $count{$a} <=> $count{$b} } keys %count) 
- { 
- $info .= "\n".$count{$c}." times ".$c; 
- } 
- 
- cf_send_info($answer_command, $info); 
- return; 
- 
-  
- if($request =~ /^how died\s+([^?]*)$/i) 
- { 
- my $name = $1; 
- chomp $name; 
- my %count; 
- foreach my $kill (keys %kills) 
- { 
- if($kill =~ / killed $name(?: with ([^.]+))?\.$/) 
- { 
- my $type = $1; 
- if(! $type) { $type = "melee"; } 
-  
- if(defined $count{$type}) 
- { 
- $count{$type} += $kills{$kill}; 
- } 
- else 
- { 
- $count{$type} = $kills{$kill}; 
- } 
- } 
- } 
-  
- if(scalar keys %count == 0) 
- { 
- cf_send_cmd("$answer_command $name didn't die yet."); 
- return; 
- } 
- 
- my $info = "$name died"; 
- foreach my $c (sort { $count{$a} <=> $count{$b} } keys %count) 
- { 
- $info .= "\n".$count{$c}." times by $c"; 
- } 
- 
- cf_send_info($answer_command, $info); 
- return; 
- 
-  
- if($request =~ /^what killed\s+([^?]*)$/i) 
- { 
- my $name = $1; 
- chomp $name; 
- my %count; 
- foreach my $kill (keys %kills) 
- { 
- if($kill =~ /killed $name\s*(with[^.]*)?\.$/i) 
- { 
- my $type = $1; 
- if(! $type) { $type = "with melee"; } 
- if(defined $count{$type}) 
- { 
- $count{$type} += $kills{$kill}; 
- } 
- else 
- { 
- $count{$type} = $kills{$kill}; 
- } 
- } 
- } 
-  
- if(scalar keys %count == 0) 
- { 
- cf_send_cmd("$answer_command $name hasn't been killed yet."); 
- return; 
- } 
- 
- my $info = "$name was killed"; 
- foreach my $c (sort { $count{$a} <=> $count{$b} } keys %count) 
- { 
- $info .= "\n".$count{$c}." times ".$c; 
- } 
- 
- cf_send_info($answer_command, $info); 
- return; 
- 
-  
- if($request =~ /^$leave_cmd!?$/) 
- { 
- if($admin !~ / $player /) 
- { 
- cf_send_cmd("$answer_command Hey, you're not allowed to send me home!"); 
- admin_msg("$player tried to send me home.\n"); 
- return; 
- } 
-  
- cf_send_cmd("$answer_command bye"); 
- $quit = 1; 
- return; 
- } 
- 
- if($request =~ /thanks|thank you|thx/i) 
- { 
- sleep 2; 
- cf_send_cmd("$answer_command Any time."); 
- return; 
- } 
- 
- if($request =~ /^maps$/i) 
- { 
- sleep 2; 
- my $show = 0; 
- 
- my $info = "The most popular maps are:"; 
-  
- foreach my $map (sort { $maps{$b} <=> $maps{$a} } keys %maps) 
- { 
- #print "MAPS $maps{$map} $map\n"; 
- last if $maps{$map} < 5; 
- $info .= "\n".int($maps{$map})." $map"; 
- $show++; 
- last if $show == 30; 
- } 
- 
- cf_send_info($answer_command, $info); 
- return; 
- } 
-  
- if($request =~ /^learn\s+(.*)$/) 
- { 
- $learning = $1; 
- if($admin !~ / $player /) 
- { 
- cf_send_cmd("$answer_command You're not my teacher!"); 
- admin_msg("$player wanted me to learn '$learning'."); 
- $learning = ""; 
- return; 
- } 
-  
- if(defined $scripts{$learning}) 
- { 
- cf_send_cmd("$answer_command I know this already."); 
- $learning = ""; 
- return; 
- } 
- 
- $scripts{$learning} = []; 
- cf_send_cmd("$answer_command How do I do this?"); 
-  
- return; 
- } 
-  
- if($request =~ /^forget\s+(.*)$/) 
- { 
- my $forget = $1; 
- if($admin !~ / $player /) 
- { 
- cf_send_cmd("$answer_command You're not my teacher!"); 
- admin_msg("$player wanted me to forget '$forget'."); 
- return; 
- } 
-  
- unless(defined $scripts{$forget}) 
- { 
- cf_send_cmd("$answer_command I don't know this anyway."); 
- return; 
- } 
- 
- delete $scripts{$forget}; 
- cf_send_cmd("$answer_command Funny, I forgot how $forget goes."); 
-  
- return; 
- } 
-  
- if($request =~ /^do\s+(.*)$/) 
- { 
- my $command = $1; 
- if($admin !~ / $player /) 
- { 
- cf_send_cmd("$answer_command You're not allowed to request this!"); 
- admin_msg("$player wanted me to do '$command'."); 
- return; 
- } 
-  
- cf_send_cmd("$answer_command Ok, I'll do $command."); 
- do_command($command); 
-  
- return; 
- } 
-  
- if($request =~ /^execute\s+(.*)$/) 
- { 
- my $execute = $1; 
- if($admin !~ / $player /) 
- { 
- cf_send_cmd("$answer_command You're not allowed to request this!"); 
- admin_msg("$player wanted me to execute '$execute'."); 
- return; 
- } 
-  
- if(!defined $scripts{$execute}) 
- { 
- cf_send_cmd("$answer_command I don't know how to do this."); 
- return; 
- } 
- 
- if(defined $script_stack{$execute}) 
- { 
- cf_send_cmd("$answer_command $execute is already running."); 
- return; 
- } 
-  
- $script_stack{$execute} = []; 
- 
- cf_send_cmd("$answer_command Ok, I'll execute $execute."); 
- do_execute($execute); 
-  
- return; 
- } 
- 
- if($request =~ /^stop\s+(.*)$/) 
- { 
- my $stop = $1; 
- if($admin !~ / $player /) 
- { 
- cf_send_cmd("$answer_command You're not allowed to request this!"); 
- admin_msg("$player wanted me to stop '$stop'."); 
- return; 
- } 
- 
- unless(defined $script_stack{$stop}) 
- { 
- cf_send_cmd("$answer_command $stop isn't running at all."); 
- return; 
- } 
-  
- stop_script($stop); 
- 
- cf_send_cmd("$answer_command I stopped $stop."); 
- return; 
- } 
- 
- if($request =~ /^running$/) 
- { 
- if($admin !~ / $player /) 
- { 
- cf_send_cmd("$answer_command You're not allowed to request this!"); 
- return; 
- } 
-  
- my $info = "Running scripts are:"; 
- foreach my $script (keys %script_stack) 
- { 
- $info .= "\n$script"; 
- } 
- cf_send_info($answer_command, $info); 
- return; 
- } 
- 
- if($request =~ /^scripts$/) 
- { 
- if($admin !~ / $player /) 
- { 
- cf_send_cmd("$answer_command You're not allowed to request this!"); 
- return; 
- } 
-  
- my $info = "Known scripts are:"; 
- foreach my $script (keys %scripts) 
- { 
- $info .= "\n$script"; 
- } 
- cf_send_info($answer_command, $info); 
- return; 
- } 
- 
- if($request =~ /^inv/) 
- { 
- if($admin !~ / $player /) 
- { 
- cf_send_cmd("$answer_command You're not allowed to request this!"); 
- admin_msg("$player wanted to see my inventory."); 
- return; 
- } 
-  
- my $info = "My inventory is:"; 
- foreach my $item (keys %inv) 
- { 
- $info .= "\n$inv{$item}{nrof}: $inv{$item}{name} ($inv{$item}{weight}g)"; 
- } 
- 
- cf_send_info($answer_command, $info); 
- return; 
- } 
-  
- if($request =~ /^checked maps$/) 
- { 
- #if($admin !~ / $player /) 
- #{ 
- # cf_send_cmd("$answer_command You're not allowed to request this!"); 
- # admin_msg("$player wanted to see the checked maps."); 
- # return; 
- #} 
-  
- my $info = "Checked maps are:"; 
- foreach my $map (keys %checked_map) 
- { 
- $info .= "\n$map:"; 
- foreach my $pl (keys %{$checked_map{$map}}) 
- { 
- $info .= "\n$pl $checked_map{$map}{$pl}"; 
- } 
- } 
- 
- cf_send_info($answer_command, $info); 
- return; 
- } 
-  
- if($request =~ /^stats$/) 
- { 
- if($admin !~ / $player /) 
- { 
- cf_send_cmd("$answer_command You're not allowed to request this!"); 
- admin_msg("$player wanted to see my stats."); 
- return; 
- } 
-  
- my $info = "My stats are:"; 
- foreach my $stat (keys %stats) 
- { 
- $info .= "\n$stat: $stats{$stat}"; 
- } 
- 
- cf_send_info($answer_command, $info); 
- return; 
- } 
-  
- if($request =~ /^add_admin\s+(\S+)$/) 
- { 
- my $newadm = $1; 
- if($admin !~ / $player /) 
- { 
- cf_send_cmd("$answer_command Hey, you're not allowed to add admins!"); 
- admin_msg("$player tried to add $1 to the admin list.\n"); 
- return; 
- } 
-  
- my $newadm_ref = $players{$newadm}; 
- unless(defined $newadm_ref) 
- { 
- cf_send_cmd("$answer_command Sorry, I don't know $newadm yet."); 
- return; 
- } 
- 
- if($newadm_ref->{"is_admin"} == 1) 
- { 
- cf_send_cmd("$answer_command $newadm is already admin."); 
- return; 
- } 
-  
- $admin .= "$newadm "; 
- $newadm_ref->{"is_admin"} = 1; 
-  
- if($newadm_ref->{"is_here"}) 
- { 
- cf_send_info("command tell $newadm", "$player said you're a really nice gui. I trust you and will do what you suggest."); 
- } 
- else 
- { 
- $newadm_ref->{"message"} .= "$player said you're a really nice gui. I trust you and will do what you suggest."; 
- } 
- cf_send_cmd("$answer_command $newadm is now one of my very close friends."); 
- return; 
- } 
- 
- if($request =~ /^rem_admin\s+(\S+)$/) 
- { 
- my $remadm = $1; 
- if($admin !~ / $player /) 
- { 
- cf_send_cmd("$answer_command Hey, you're not allowed to remove admins!"); 
- admin_msg("$player tried to remove $1 from the admin list.\n"); 
- return; 
- } 
-  
- my $remadm_ref = $players{$remadm}; 
- unless(defined $remadm_ref) 
- { 
- cf_send_cmd("$answer_command Sorry, I don't know $remadm."); 
- return; 
- } 
-  
- if($remadm_ref->{"is_admin"} == 0) 
- { 
- cf_send_cmd("$answer_command $remadm is not an admin."); 
- return; 
- } 
-  
- if($remadm eq $player) 
- { 
- cf_send_cmd("$answer_command You don't want to remove yourself from the admin list, do you?"); 
- return; 
- } 
-  
- $admin =~ s/ $remadm / /; 
- $remadm_ref->{"is_admin"} = 0; 
-  
- if($remadm_ref->{"is_here"}) 
- { 
- cf_send_info("command tell $remadm", "$player removed you from my admin list."); 
- } 
- else 
- { 
- $remadm_ref->{"message"} .= "$player removed you from my admin list."; 
- } 
- cf_send_cmd("$answer_command $remadm is no longer in my admin list."); 
- return; 
- } 
- 
- if($request =~ /^admins$/) 
- { 
- sleep 2; 
- cf_send_cmd("$answer_command My admin friends are:$admin"); 
- return; 
- } 
- 
- sleep 2; 
- cf_send_cmd("$answer_command I don't know what you mean. Do you need help?"); 
-} 
- 
-sub do_command 
-{ 
- my $cmd = shift; 
- if($cmd =~ /^save$|^north$|^south$|^east$|^west$|^northwest$|^northeast$|^southwest$|^southeast$|^say |^tell |^shout |^get\b|^take\b|^drop\b|^cast |^invoke |^apply\b|^pickup \d+$|^title |^ready_skill |^use_skill |^fire/) 
- { 
- # We just pass this through. 
- cf_send_cmd($cmd); 
- } 
-} 
- 
-sub stop_script 
-{ 
- my $scr = shift; 
- return unless defined $scripts{$scr}; 
- return unless defined $script_stack{$scr}; 
- 
- foreach my $events_array_ref (\@events_listen, \@events_wait, \@events_stats) 
- { 
- for(my $i = 0; $i < scalar @$events_array_ref; $i++) 
- { 
- my $event_ref = $events_array_ref->[$i]; 
- if($scr eq $event_ref->{"script"}) 
- { 
- splice @$events_array_ref, $i, 1; # remove the event from the list 
- } 
- } 
- } 
- delete $script_stack{$scr}; 
-} 
- 
-sub do_execute 
-{ 
- my $scriptname = shift; 
- my $pc = shift || 0; 
-  
- for(; $pc < scalar @{$scripts{$scriptname}}; $pc++) 
- { 
- $cmd = $scripts{$scriptname}[$pc]; 
- print "executing: $cmd (stack size: ".(scalar @{$script_stack{$scriptname}}).")\n"; 
- if($cmd =~ /^save$|^north$|^south$|^east$|^west$|^northwest$|^northeast$|^southwest$|^southeast$|^say |^tell |^shout |^get\b|^take\b|^drop\b|^cast |^invoke |^apply\b|^pickup \d+$|^title |^ready_skill |^use_skill |^fire/) 
- { 
- # We just pass this through. 
- cf_send_cmd($cmd); 
- next; 
- } 
- 
- if($cmd =~ /^execute (\S+)$/) 
- { 
- my $scr = $1; 
- next unless defined $scripts{$scr}; 
- next if defined $script_stack{$scr}; 
- 
- $script_stack{$scr} = []; 
- do_execute($scr); 
- next; 
- } 
- 
- if($cmd =~ /^stop (\S+)$/) 
- { 
- stop_script($1); 
- last; 
- } 
- 
- if($cmd =~ /^wait (\d+)$/) 
- { 
- push @events_wait, { script => $scriptname, pc => ($pc+1), continue_at => time + $1 }; 
- last; 
- } 
- 
- if($cmd =~ /^for (\d+) times$/) 
- { 
- push @{$script_stack{$scriptname}}, { context => 'for', pc => $pc, count => $1 }; 
- next; 
- } 
- 
- if($cmd =~ /^end_for$/) 
- { 
- if(scalar @{$script_stack{$scriptname}} == 0) 
- { 
- print "Stack underflow in end_for!\n"; 
- stop_script($scriptname); 
- last; 
- } 
-  
- $stack_last = $script_stack{$scriptname}[0]; 
- unless($stack_last->{"context"} eq 'for') 
- { 
- print "Script error: end_for found, but no for on stack.\n"; 
- stop_script($scriptname); 
- return; 
- } 
- $stack_last->{"count"}--; 
- if($stack_last->{"count"} == 0) 
- { 
- shift @{$script_stack{$scriptname}}; 
- next; 
- } 
-  
- $pc = $stack_last->{"pc"}; 
- next; 
- } 
- 
- if($cmd =~ /^forever$/) 
- { 
- push @{$script_stack{$scriptname}}, { context => 'forever', pc => $pc }; 
- next; 
- } 
- 
- if($cmd =~ /^end_forever$/) 
- { 
- if(scalar @{$script_stack{$scriptname}} == 0) 
- { 
- print "Stack underflow in end_forever!\n"; 
- stop_script($scriptname); 
- return; 
- } 
-  
- $stack_last = $script_stack{$scriptname}[0]; 
- unless($stack_last->{"context"} eq 'forever') 
- { 
- print "Script error: end_forever found, but no forever on stack.\n"; 
- stop_script($scriptname); 
- return; 
- } 
-  
- $pc = $stack_last->{"pc"}; 
- next; 
- } 
- 
- if($cmd =~ /^when hearing\s+(\S.+)$/) 
- { 
- push @events_listen, { script => $scriptname, pc => ($pc+1), listen_text => "$1" }; 
- last; 
- } 
- 
- if($cmd =~ /^when stats_event\s+(maxhp|maxsp|maxgrace|lowfood)$/) 
- { 
- push @{$events_stats{$1}}, { script => $scriptname, pc => ($pc+1) }; 
- last; 
- } 
-  
- if($cmd eq "end") 
- { 
- stop_script($scriptname); 
- last; 
- } 
- 
- if($cmd =~ /^assert (.*)$/) 
- { 
- last unless script_condition($1); 
- next; 
- } 
- 
- cf_send_cmd("tell Zorag Script error: unknown command '$cmd'"); 
- last; 
- } 
- 
- if($pc == scalar @{$scripts{$scriptname}}) 
- { 
- stop_script($scriptname); 
- } 
- 
-} 
- 
-sub script_condition 
-{ 
- my $cond = shift; 
- my @words = split (/\s+/, $cond); 
- my @stack = ( ); 
- while (my $word = shift(@words)) 
- { 
- if($word eq "not") 
- { 
- return 0 if scalar @stack < 1; 
- $stack[$#stack] = !$stack[$#stack]; 
- next; 
- } 
- 
- if($word eq "and") 
- { 
- return 0 if scalar @stack < 2; 
- splice @stack, $#stack-1, 2, ($stack[$#stack] && $stack[$#stack-1]); 
- next; 
- } 
- 
- if($word eq "or") 
- { 
- return 0 if scalar @stack < 2; 
- splice @stack, $#stack-1, 2, ($stack[$#stack] || $stack[$#stack-1]); 
- next; 
- } 
- 
- if($word eq "xor") 
- { 
- return 0 if scalar @stack < 2; 
- splice @stack, $#stack-1, 2, ($stack[$#stack] ^ $stack[$#stack-1]); 
- next; 
- } 
- 
- # implement some conditions here XXX 
- } 
- return pop @stack; 
-} 
- 
-sub parse_who 
-{ 
- my $line = shift; 
- unless ($line =~ /^(\S+) the ([^\]]+)\[([^\]]+)\]/) 
- { 
- #print "WHO next line: $line\n"; 
- return 0; 
- } 
- my $pl = $1; 
- return 1 if $pl eq $player_name; # Don't log ourselves. 
- my $title = $2; 
- my $map = $3; 
- $title =~ s/ $//; 
- 
- #print ">WHO Player: $pl the $title on map $map\n"; 
- 
- # Set this player's is_here: 
- my $player_ref = $players{$pl}; 
- if(defined $player_ref) 
- { 
- if(! $player_ref->{"is_here"}) 
- { 
- $player_ref->{"is_here"} = 1; 
- if($player_ref->{"message"}) 
- { 
- my $msg = $player_ref->{"message"}; 
- $msg =~ s/_-/\n/g; 
- cf_send_info("command tell $pl", "Hi $pl!$msg"); 
- $player_ref->{"message"} = ""; 
- } 
- } 
- } 
- else 
- { 
- $player_ref = { asked_me => 0, is_here => 1, message => "", is_admin => 0 }; 
- $players{$pl} = $player_ref; 
- } 
- $player_ref->{"last_seen"} = time; 
-  
- # Do we log this map's usage? 
- foreach my $map_pat (@check_map) 
- { 
- if($map =~ m#$map_pat#) 
- { 
- if(defined $checked_map{$map}{$pl}) 
- { 
- $checked_map{$map}{$pl}++; 
- } 
- else 
- { 
- $checked_map{$map}{$pl} = 1; 
- } 
- } 
- } 
-  
- if($map =~ m#/_city_apartment_[Aa]partments.?$|/_santo_dominion_sdomino_appartment$|^/guilds/|^/city/city$|^/world/world_..$|^/dragonisland/housebrxzl$#) 
- { 
- # We don't log these maps. 
- return 1; 
- } 
-  
- # remove number from random maps: 
- if($map =~ m#^/random/#) 
- { 
- $map =~ s/\d\d\d\d$//; 
- } 
-  
- # Add to the map popularity: 
- if(defined $maps{$map}) 
- { 
- $maps{$map}++; 
- } 
- else 
- { 
- $maps{$map} = 1; 
- } 
- 
- return 1; 
-} 
- 
-sub admin_msg 
-{ 
- for my $adm (split /\s+/, $admin) 
- { 
- next unless $adm; 
- my $admin_ref = $players{$adm}; 
- return unless defined $admin_ref; 
-  
- my $msg = shift; 
-  
- if($admin_ref->{"is_here"}) 
- { 
- cf_send_cmd("tell $adm $msg"); 
- return; 
- } 
- 
- $msg =~ s#\n#_-#g; 
- $admin_ref->{"message"} .= $msg; 
- } 
-} 
- 
- 
-sub cf_send_info 
-{ 
- my $answer_command = shift; 
- my $info = shift; 
- my @lines = split(/\n/, $info); 
-  
- if(! @lines) { return; } 
- 
- my $chunk = shift @lines; 
- foreach $line (@lines) 
- { 
- if(length($chunk) + length($line) < 220) 
- { 
- $chunk .= "\n".$line; 
- } 
- else 
- { 
- if(! $chunk) 
- { 
- die "Text chunk is too large (".length($chunk)." bytes)"; 
- } 
- cf_send_cmd("$answer_command $chunk"); 
- $chunk = "\n$line"; 
- } 
- } 
- if($chunk) 
- { 
- cf_send_cmd("$answer_command $chunk"); 
- } 
-} 
- 
-sub cf_send_cmd 
-{ 
- push @cmds_waiting, shift; 
- 
- my $pending = $pkg_sent - $pkg_ackd; 
- if($pending < 0) { $pending += 256; } 
- while($pending < 3) 
- { 
- my $msg = shift @cmds_waiting; 
-  
- # send this command immediately 
- $pkg_sent++; 
- if($pkg_sent == 256) { $pkg_sent = 0; } 
- cf_send("ncom ".pack("n", $pkg_sent)."\0\0\0\1$msg"); 
-  
- last unless scalar @cmds_waiting; 
- 
- $pending++; 
- } 
- 
-} 
- 
-sub cf_send 
-{ 
- my $msg = shift; 
- #print "<$msg\n"; 
- my $out = pack("n/a*", $msg); 
- #print unpack("H*", $out)."\n"; 
- print $socket $out; 
- $socket->flush(); 
-} 
- 
- 
-sub save 
-{ 
- open(KILLS, "> cf_kills") or die "Can't write file 'cf_kills': $!"; 
- foreach my $key (keys %kills) 
- { 
- print KILLS $key.":".$kills{$key}."\n"; 
- } 
- close KILLS; 
- 
- open(SCRIPTS, "> cf_scripts") or die "Can't write file 'cf_scripts': $!"; 
- foreach my $scriptname (keys %scripts) 
- { 
- #print "Saving script '$scriptname'.\n"; 
- print SCRIPTS "$scriptname\n"; 
- foreach my $line (@{$scripts{$scriptname}}) 
- { 
- print SCRIPTS "$line\n"; 
- } 
- print SCRIPTS "\n"; 
- } 
- close SCRIPTS; 
- 
- open(PLS, ">cf_players") or die "Can't write file 'cf_players': $!"; 
- foreach my $key (keys %players) 
- { 
- #print "Saving player '$key'.\n"; 
- print PLS "$key\n"; 
- foreach my $plkey (keys %{$players{$key}}) 
- { 
- print PLS "$plkey:$players{$key}{$plkey}\n"; 
- } 
- } 
- close PLS; 
- 
- open(MAPS, ">cf_maps") or die "Can't write file 'cf_maps': $!"; 
- print MAPS "$last_maps_decay_time\n"; 
- foreach my $map (keys %maps) 
- { 
- #print "Saving map info '$map'.\n"; 
- print MAPS "$map $maps{$map}\n"; 
- } 
- print MAPS "\n"; 
- foreach my $map (keys %checked_map) 
- { 
- print MAPS "$map\n"; 
- foreach my $pl (keys %{$checked_map{$map}}) 
- { 
- print MAPS "$pl:$checked_map{$map}{$pl}\n"; 
- } 
- } 
- close MAPS; 
-  
- print STDERR "Data saved.\n"; 
-} 
- 
- 
-sub load 
-{ 
- %kills = (); 
- unless(open(KILLS, "< cf_kills")) 
- { 
- print STDERR "Can't read file 'cf_kills': $!\n"; 
- } 
- else 
- { 
- print "Loading kills.\n"; 
- while(<KILLS>) 
- { 
- chomp; 
- my ($key, $value) = split(/:/, $_); 
- $kills{$key} = $value; 
- } 
- close KILLS; 
- } 
-  
- %scripts = (); 
- unless(open(SCRIPTS, "< cf_scripts")) 
- { 
- print STDERR "Can't read file 'cf_scripts': $!\n"; 
- } 
- else 
- { 
- print "Loading scripts.\n"; 
- while(<SCRIPTS>) 
- { 
- chomp; 
- my $scriptname = $_; 
- print "Loading script '$scriptname'.\n"; 
- $scripts{$scriptname} = []; 
- for(;;) 
- { 
- my $line = <SCRIPTS>; 
- chomp $line; 
- last unless $line; 
- print ":$line\n"; 
- 
- push @{$scripts{$scriptname}}, $line; 
- } 
- } 
- close SCRIPTS; 
- } 
-  
- %players = (); 
- unless(open(PLS, "< cf_players")) 
- { 
- print STDERR "Can't read file 'cf_players': $!\n"; 
- } 
- else 
- { 
- $current_name = ""; 
- print "Loading players.\n"; 
- while(<PLS>) 
- { 
- chomp; 
- if(/^([^:]+):(.*)$/) 
- { 
- my $key = $1; 
- my $val = $2; 
- if($key eq "is_admin" && $val == 1) 
- { 
- $admin .= "$current_name "; 
- } 
- if($key eq "is_here") 
- { 
- # We get the current users from the 'who command. 
- $val = 0; 
- } 
- $players{$current_name}{$key} = $val; 
- } 
- else 
- { 
- $current_name = $_; 
- } 
- } 
- } 
- 
- %maps = (); 
- unless(open(MAPS, "< cf_maps")) 
- { 
- print STDERR "Can't read file 'cf_maps': $!\n"; 
- } 
- else 
- { 
- print "Loading maps.\n"; 
- my $last_maps_decay_time = <MAPS>; 
- chomp $last_maps_decay_time; 
- while(<MAPS>) 
- { 
- chomp; 
- last unless $_; 
- my ($key, $value) = split(/ /, $_); 
- $maps{$key} = $value; 
- } 
- $current_name = ""; 
- while(<MAPS>) 
- { 
- chomp; 
- if(/^([^:]+):(.*)$/) 
- { 
- $checked_map{$current_name}{$1} = $2; 
- } 
- else 
- { 
- $current_name = $_; 
- } 
- } 
- close MAPS; 
- } 
-  
-} 
- 
-</code> 
bot/seer.1519270639.txt.gz ยท Last modified: (external edit)

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki