# ======================= # reactOnNPC v.2.0.3 (mod v3 [06/04/53]) # ======================= # This plugin is licensed under the GNU GPL # Copyright 2006 by hakore [mod by windows98SE (2010)] # # v3 Add # Attribute : npcName # # v2 Add # Attribute : debug, respIgnoreColor # Report : conditions,type # # - referer - # OpenKore : http://forums.openkore.com/viewtopic.php?f=34&t=198 # OPKwin : http://www.opkwin.com/forum/?topic=27.msg60#msg60 # # Credit hakore and windows98SE, # If you can. # # ex. #reactOnNPC { # type # debug <1|0> # useColors <1|0> # disabled <1|0> # can use "checkSelfCondition" read more infomation in http://wiki.openkore.com/index.php?title=Category:Self_Condition # respIgnoreColor <1|0> # respIgnoreChar # npcName # msg_0 #} package reactOnNPC; use strict; use Plugins; use Globals; use Utils; use Misc; use Commands; use Log qw(message error); Plugins::register('reactOnNPC', "react on NPC messages", \&Unload); my $hooks = ( Plugins::addHooks( ['packet/npc_talk', \&onNPCTalk, undef], ['packet/npc_talk_close', \&onNPCAction, undef], ['packet/npc_talk_continue', \&onNPCAction, undef], ['packet/npc_talk_number', \&onNPCAction, undef], ['packet/npc_talk_responses', \&onNPCAction, undef], ['packet/npc_talk_text', \&onNPCAction, undef], ['mainLoop_pre', \&onCheckCmd, undef] ) ); my $i = '0'; my $npc_name; my %reactOnNPC; my @reactOnNPC; sub Unload{ Plugins::delHooks($hooks); } sub onNPCTalk{ my (undef, $args) = @_; my $ID = unpack("V", substr($args->{RAW_MSG}, 4, 4)); $npc_name = getNPCName(substr($args->{RAW_MSG}, 4, 4)); my $msg = I18N::bytesToString(unpack("Z*", substr($args->{RAW_MSG}, 8))); $msg =~ s/$config{"reactOnNPC_${i}_respIgnoreChar"}//ig; if(!defined %reactOnNPC || $reactOnNPC{action}){ undef %reactOnNPC if defined %reactOnNPC; $reactOnNPC{index} = 0; $reactOnNPC{ID} = $ID; $reactOnNPC{msg}[$reactOnNPC{index}] = $msg; }else{ $reactOnNPC{index}++; $reactOnNPC{msg}[$reactOnNPC{index}] = $msg; } message "[reactOnNPC] NPC message saved ($reactOnNPC{index}): \"$msg\".\n", "reactOnNPC" if($config{"reactOnNPC_${i}_debug"}); } sub onNPCAction{ my $type = substr(shift, 16); $reactOnNPC{action} = $type; message "[reactOnNPC] onNPCAction type is: $type. ($npc_name)\n", "reactOnNPC" if($config{"reactOnNPC_${i}_debug"}); if($type eq 'responses'){ my $args = shift; my $msg = I18N::bytesToString(unpack("Z*", substr($args->{RAW_MSG}, 8))); undef @{$reactOnNPC{responses}}; my @responses = split /:/, $msg; foreach my $var (@responses){ push @{$reactOnNPC{responses}}, $var if $var ne ""; } } $i = 0; while(exists $config{"reactOnNPC_$i"}){ if(!$config{"reactOnNPC_$i"} && $config{"reactOnNPC_${i}_npcName"} || !main::checkSelfCondition("reactOnNPC_$i") || ($config{"reactOnNPC_${i}_type"} && $config{"reactOnNPC_${i}_type"} ne $type)){ my $npcfound = match("NPC Name" , "Block $i", $npc_name, $config{"reactOnNPC_${i}_npcName"}); if(!main::checkSelfCondition("reactOnNPC_$i") && $npcfound && $config{"reactOnNPC_${i}_npcName"} && ($config{"reactOnNPC_${i}_type"} && $config{"reactOnNPC_${i}_type"} eq $type)){ # Report if checkSelfCondition not met message "[reactOnNPC] Conditions for reactOnNPC_$i checkSelfCondition not met.\n", "reactOnNPC" if($config{"reactOnNPC_${i}_debug"}); }elsif(!main::checkSelfCondition("reactOnNPC_$i") && !$npcfound && $config{"reactOnNPC_${i}_npcName"} && ($config{"reactOnNPC_${i}_type"} && $config{"reactOnNPC_${i}_type"} eq $type)){ # Report if checkSelfCondition and NPC name not met message "[reactOnNPC] Conditions for reactOnNPC_$i (npc:${type} , rect:".$config{"reactOnNPC_${i}_type"}.", NPC name:". $npc_name.") checkSelfCondition and NPC name not met.\n", "reactOnNPC" if($config{"reactOnNPC_${i}_debug"}); }elsif(main::checkSelfCondition("reactOnNPC_$i") && $npcfound && $config{"reactOnNPC_${i}_npcName"} && ($config{"reactOnNPC_${i}_type"} && $config{"reactOnNPC_${i}_type"} ne $type)){ # Report if type not met message "[reactOnNPC] Conditions for reactOnNPC_$i (npc:${type} , rect:".$config{"reactOnNPC_${i}_type"}.") type not met.\n", "reactOnNPC" if($config{"reactOnNPC_${i}_debug"}); }elsif(main::checkSelfCondition("reactOnNPC_$i") && !$npcfound && $config{"reactOnNPC_${i}_npcName"} && ($config{"reactOnNPC_${i}_type"} && $config{"reactOnNPC_${i}_type"} ne $type)){ # Report if type and NPC name not met message "[reactOnNPC] Conditions for reactOnNPC_$i (npc:${type} , rect:".$config{"reactOnNPC_${i}_type"}.", NPC name:". $npc_name.") type and NPC name not met.\n", "reactOnNPC" if($config{"reactOnNPC_${i}_debug"}); }elsif(main::checkSelfCondition("reactOnNPC_$i") && !$npcfound && $config{"reactOnNPC_${i}_npcName"} && ($config{"reactOnNPC_${i}_type"} && $config{"reactOnNPC_${i}_type"} eq $type)){ # Report if NPC name not met message "[reactOnNPC] Conditions for reactOnNPC_$i (NPC name:". $npc_name.") NPC name not met.\n", "reactOnNPC" if($config{"reactOnNPC_${i}_debug"}); }else{ # Report if checkSelfCondition and and NPC name and type not met message "[reactOnNPC] Conditions for reactOnNPC_$i (npc:${type} , rect:".$config{"reactOnNPC_${i}_type"}.", NPC name:". $npc_name.") checkSelfCondition and type and NPC name not met.\n", "reactOnNPC" if($config{"reactOnNPC_${i}_debug"}); } $i++; next; } # Report if checkSelfCondition and type met message "[reactOnNPC] Conditions for reactOnNPC_$i (NPC ${type}:". $npc_name.") is met.\n", "reactOnNPC" if($config{"reactOnNPC_${i}_debug"}); my $j = 0; my $ok = 1; while(exists $config{"reactOnNPC_${i}_msg_$j"}){ my $msg; if(exists $reactOnNPC{msg}[$j]){ $msg = $reactOnNPC{msg}[$j]; # Remove RO color codes $msg =~ s/\^[A-F0-9]{6}//ig unless ($config{"reactOnNPC_${i}_useColors"}); } if(!defined $msg || !match("msg" ,$j, $msg, $config{"reactOnNPC_${i}_msg_$j"})){ message "[reactOnNPC] One or more lines doesn't match for \"reactOnNPC_$i\" ($j).\n", "reactOnNPC" if($config{"reactOnNPC_${i}_debug"}); $ok = 0; last; } $j++; } if($ok){ my $cmd = $config{"reactOnNPC_$i"}; $cmd =~ s/#(\d+)~(\d+)/$reactOnNPC{match}[$1][$2]/g; my $kws = 'eval|resp'; while(my ($kw, $expr) = $cmd =~ /\@($kws)\(((?:(?!(? $rIC =~ s/\^[A-F0-9]{6}//ig if($config{"reactOnNPC_${i}_respIgnoreColor"}); if(match("response", $k, $rIC, $eval_expr)){ last; } $k++; } $eval = $k; } $expr = quotemeta $expr; $cmd =~ s/\@$kw\($expr\)/$eval/g; } if(my $delay = $config{"reactOnNPC_${i}_delay"}){ my $params = { cmd => $cmd, time => time, timeout => $delay }; message "[reactOnNPC] React to NPC with delay. Execute command \"$cmd\" after $delay seconds.\n", "success"; push @reactOnNPC, $params; }else{ message "[reactOnNPC] Reacting to NPC. Executing command \"$cmd\".\n", "success"; Commands::run($cmd); } last; } $i++; } undef %reactOnNPC if $type eq 'close'; } sub onCheckCmd{ for(my $i = 0; $i < @reactOnNPC; $i++){ my $args = $reactOnNPC[$i]; if(timeOut($args->{time}, $args->{timeout})){ message "[reactOnNPC] Reacting to NPC. Executing command \"".$args->{cmd}."\".\n", "success"; Commands::run($args->{cmd}); } } } sub match{ my ($type,$line, $subject, $pattern) = @_; # $head for report matching in one line ^^" my $head = "[reactOnNPC] Matching [$type ($line)] \"$subject\" to \"$pattern\" ..."; if(my ($re, $ci) = $pattern =~ /^\/(.+?)\/(i?)$/){ if(($ci && $subject =~ /$re/i) || (!$ci && $subject =~ /$re/)){ if(defined $line){ no strict; foreach my $index (1..$#-){ $reactOnNPC{match}[$line][$index] = ${$index}; } } message "$head regexp ok.\n", "reactOnNPC" if($config{"reactOnNPC_${i}_debug"}); return 1; } }elsif($subject eq $pattern){ message "$head ok.\n", "reactOnNPC" if($config{"reactOnNPC_${i}_debug"}); return 1; } error "$head doesn't match.\n", "reactOnNPC" if($config{"reactOnNPC_${i}_debug"}); } return 1;