OpenKore 新增迴避技能 avoidSkill 外掛

OpenKore並無內建迴避技能的功能,需使用 plugins 附加此功能‧

1.將以下 avoidSkill 的程式碼(轉貼自 OpenKore 官方論壇)複製貼到記事本中
2.另存檔案為UTF-8編碼格式,檔案名稱命名為 avoidSkill.pl
3.放入 plugins 資料夾中

    # avoidSkill by Joseph
    # original code from MessyKoreXP
    # licensed under GPL

    package avoidSkill;

    use strict;
    #use warnings;

    use Time::HiRes qw(time);

    use Globals;
    use Utils;
    use Misc;
    use AI;
    use Network::Send;
    use Commands;
    use Log qw(debug message warning error);
    use Skill;
    use encoding 'utf8';

    Plugins::register('avoidSkill', 'React to skills.', \&onUnload);

    my $hooks = Plugins::addHooks(
       ['AI_pre', \&AI_hook],
    #   ['is_casting', \&hookAvoidSkill]
       ['is_casting', \&avoidSkill, undef],
       ['packet_skilluse', \&avoidSkill, undef]
    );

    my $prefix = "avoidSkill_";
    my $prefix2 = "_afterCast";

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

    sub avoidSkill {
            return if (!$config{autoAvoidSkill});   
       
       my (undef, $args) = @_;
            my $hookName = shift;
    #        my $args = shift;   
            my $sourceID = $args->{sourceID};
            my $targetID = $args->{targetID};
            my $source = $args->{source};
            my $skill = $args->{skill};
            my $skillID = $args->{skillID};
       my $x = $args->{x};
       my $y = $args->{y};
            my $i = 0;
           
    #rufvin plugin
    #http://bibian.ath.cx/openkore/viewtopic.php?t=12123&postdays=0&postorder=asc&start=0

    #        while (exists $config{$prefix.$i}) {
    #                my ($dist, %coords);
    #                if ($x != 0 || $y != 0) {
    #                        # If $dist is positive we are in range of the attack?
    #                        $coords{x} = $x;
    #                        $coords{y} = $y;
    #                        $dist = judgeSkillArea($skillID) - distance($char->{pos_to}, \%coords);
    #                }

    #                if (existsInList($config{$prefix.$i}, $skill->name) && $sourceID ne $accountID) {
    #                        if ($dist > 0 || $targetID eq $accountID) {
    #                                AI::queue("avoidskill");
    #                                AI::args->{timeout} = ($source->{casting}->{castTime} - $config{$prefix.$i."_delay"})/1000;
    #                                AI::args->{timeout} = 0 if (AI::args->{timeout}*1000 == $source->{casting}->{castTime} || AI::args->{timeout} < 0);
    #                                AI::args->{time} = time;
    #                                my $lvl;
    #                                my $skillUse = new Skills(name => $config{$prefix.$i."_use"});
    #                                if ($config{$prefix.$i."_lvl"}>$char->{skills}{$skillUse->handle}->{lv} || !$config{$prefix.$i."_lvl"}) {
    #                                        $lvl = $char->{skills}{$skillUse->handle}->{lv};
    #                                } else {
    #                                        $lvl = $config{$prefix.$i."_lvl"};
    #                                }
    #                                AI::args->{lvl} = $lvl;
    #                                AI::args->{skillID} = $skillUse->id if ($lvl > 0);
    #                                if (ai_getSkillUseType($skillUse->handle)) {
    #                                        AI::args->{char_state} = whenGroundStatus($char->{pos_to}, $skillUse->name);
    #                                } else {
    #                                        AI::args->{char_state} = existsInList(join(",", keys %{$char->{statuses}}), $skillUse->name);
    #                                }
    #                                AI::args->{i} = $i;
    #                                Commands::run($config{$prefix.$i."_doCommand"}) if ($config{$prefix.$i."_doCommand"} ne "");
    #                        }
    #                }
    #                $i++;
    #        }       
    #########################################

       my $skill = new Skill(idn => $skillID);
       $skill = $skill->getName();

       my $source = Actor::get($sourceID);

       debug "checking if we should avoid $skill from $source\n";

       for (my $i = 0; exists $config{"avoidSkill_$i"}; $i++) {
          next if (!$config{"avoidSkill_$i"});

          if (existsInList($config{"avoidSkill_$i"}, $skill)) {
             # if source is specified, make sure type is correct
             next if ($config{"avoidSkill_$i"."_source"} && $config{"avoidSkill_$i"."_source"} ne $source->{actorType});

             debug "checking avoid radius on $skill\n";

             # check if we are inside the skill area of effect
             my $inRange;
             my ($left,$right,$top,$bottom);
             if ($x != 0 || $y != 0) {
                $left = $x - $config{"avoidSkill_$i"."_radius"};
                $right = $x + $config{"avoidSkill_$i"."_radius"};
                $top = $y - $config{"avoidSkill_$i"."_radius"};
                $bottom = $y + $config{"avoidSkill_$i"."_radius"};
                $inRange = 1 if ($left <= $char->{pos_to}{x} && $right >= $char->{pos_to}{x} && $top <= $char->{pos_to}{y} && $bottom >= $char->{pos_to}{y});

             } elsif ($targetID eq $accountID) {
                $inRange = 1;
             }

             if ($inRange) {
                if ($char->{sitting}) {
                   main::stand();
                }

                if ($config{"avoidSkill_$i"."_method"} == 0) {
                   my $found = 1;
                   my $count = 0;
                   my %move;
                   do {
                      ($move{x}, $move{y}) = getRandPosition($config{"avoidSkill_${i}_step"});
                      $count++;
                      if ($count > 100) {
                         $found = 0;
                         last;
                      }
                   } while ($left <= $move{x} && $right >= $move{x} && $top <= $move{y} && $bottom >= $move{y});

                   if ($found) {
                      stopAttack();
                      sendMove(\$remote_socket, $move{x}, $move{y});
                      message "Avoid skill $skill, random move to $move{x}, $move{y}.\n";
                   }

    #   Methods (choose one)
    #   0 - Random position outside  by 
    #   1 - Move to opposite side by 
    #   2 - Move nearest enemy.
    #   3 - Teleport
    #   4 - Attack (monsters only)
    #   5 - Use skill. (monsters only)

                } elsif ($config{"avoidSkill_$i"."_method"} == 1) {
                   my $dx = $x - $char->{pos_to}{x};
                   my $dy = $y - $char->{pos_to}{y};
                   my %random;
                   my %move;

                   my $found = 1;
                   my $count = 0;
                   do {
                      $random{x} = int(rand($config{"avoidSkill_$i"."_step"})) + 1;
                      $random{y} = int(rand($config{"avoidSkill_$i"."_step"})) + 1;

                      if ($dx >= 0) {
                         $move{x} = $char->{pos_to}{x} - $random{x};
                      } else {
                         $move{x} = $char->{pos_to}{x} + $random{x};
                      }

                      if ($dy >= 0) {
                         $move{y} = $char->{pos_to}{y} - $random{y};
                      } else {
                         $move{y} = $char->{pos_to}{y} + $random{y};
                      }

                      $count++;
                      if ($count > 100) {
                         $found = 0;
                         last;
                      }
                   } while (!($field->isWalkable($x, $y)));

                   if ($found) {
                      stopAttack();
                      sendMove(\$remote_socket, $move{x}, $move{y});
                      message "Avoid skill $skill, move to $move{x}, $move{y}.\n";
                   }

                } elsif ($config{"avoidSkill_$i"."_method"} == 2) {
                   my %src;
                   $src{x} = $source->{pos_to}{x};
                   $src{y} = $source->{pos_to}{y};

                   my $found = 0;
                   my $count = 0;
                   my ($ex_left, $ex_right, $ex_top, $ex_bottom);
                   my ($in_left, $in_right, $in_top, $in_bottom);
                   my %move;
                   my %nearest;

                   do {
                      $ex_left = $src{'x'} - $count;
                      $ex_right = $src{'x'} + $count;
                      $ex_top = $src{'y'} - $count;
                      $ex_bottom = $src{'y'} + $count;

                      $count++;

                      $in_left = $src{'x'} - $count;
                      $in_right = $src{'x'} + $count;
                      $in_top = $src{'y'} - $count;
                      $in_bottom = $src{'y'} + $count;

                      my $nearest_dist = 9999;
                      for ($move{'y'} = $in_top; $move{'y'} <= $in_bottom; $move{'y'}++) {
                         for ($move{'x'} = $in_left; $move{'x'} <= $in_right; $move{'x'}++) {
                            if (($move{'x'} < $ex_left || $move{'x'} > $ex_right) && ($move{'y'} < $ex_top || $move{'y'} > $ex_bottom)) {
                               next if (($left <= $move{'x'} && $right >= $move{'x'} && $top <= $move{'y'} && $bottom >= $move{'y'}) ||
                                  !($field->isWalkable($move{x}, $move{y})));

                               my $dist = distance(\%move, \%src);

                               if ($dist < $nearest_dist) {
                                  $nearest_dist = $dist;
                                  $nearest{'x'} = $move{'x'};
                                  $nearest{'y'} = $move{'y'};
                                  $found = 1;
                               }
                            }
                         }
                      }
                   } while (($count < 100) && (!$found));

                   if ($found) {
                      stopAttack();
                      sendMove(\$remote_socket, $nearest{x}, $nearest{y});
                      message "Avoid skill $skill, move to nearest position $nearest{'x'}, $nearest{'y'}.\n";
                   }

                } elsif ($config{"avoidSkill_$i"."_method"} == 3) {
                   message "Avoid skill $skill, use random teleport.\n";
                   main::useTeleport(1);

                } elsif ($config{"avoidSkill_$i"."_method"} == 4) {
                   return unless ($source->{actorType} eq 'Monster');
                   message "Avoid skill $skill, attack to $source->{name}\n";
                   # may not care about portal distance, oh well
                   stopAttack();
                   main::attack($sourceID);

                } elsif ($config{"avoidSkill_$i"."_method"} == 5 && timeOut($AI::Timeouts::avoidSkill_skill, 3)) {
                   return unless ($source->{actorType} eq 'Monster');
                   message "Avoid skill $skill, use ".$config{"avoidSkill_$i"."_skill"}." to $source->{name}\n";

                   $skill = new Skill(name => $config{"avoidSkill_$i"."_skill"});

                   message "Use ".$skill->getHandle." on target\n";

                   if (main::ai_getSkillUseType($skill->getHandle)) {
                      my $pos = ($config{"avoidSkill_${i}_isSelfSkill"}) ? $char->{pos_to} : $monsters{$sourceID}{pos_to};
                      main::ai_skillUse(
                         $skill->getHandle,
                         $config{"avoidSkill_$i"."_lvl"},
                         $config{"avoidSkill_$i"."_maxCastTime"},
                         $config{"avoidSkill_$i"."_minCastTime"},
                         $pos->{x},
                         $pos->{y});
                   } else {
                      main::ai_skillUse(
                         $skill->getHandle,
                         $config{"avoidSkill_$i"."_lvl"},
                         $config{"avoidSkill_$i"."_maxCastTime"},
                         $config{"avoidSkill_$i"."_minCastTime"},
                         $config{"avoidSkill_${i}_isSelfSkill"} ? $accountID : $sourceID);
                   }
                   $AI::Timeouts::avoidSkill_skill = time;
                }

             }

             last;
          }
       }
    }

    sub AI_hook {
            AI::dequeue if (AI::action eq "avoidskill" && AI::args->{skillID} eq "");
            if (AI::action eq "avoidskill" && timeOut(AI::args)) {
                    my $i = AI::args->{i};
                    my $skillUse = new Skills(id => AI::args->{skillID});
                    if (ai_getSkillUseType($skillUse->handle)) {
                            if (whenGroundStatus($char->{pos_to}, $skillUse->name) == AI::args->{char_state}) {
                                    $messageSender->sendSkillUseLoc(AI::args->{skillID}, AI::args->{lvl}, $char->{pos_to}{x}, $char->{pos_to}{y});
                            } elsif (!AI::args->{dequeue} && $config{$prefix.$i.$prefix2}) {
                                    AI::args->{timeout} = $config{$prefix.$i.$prefix2."_wait"};
                                    AI::args->{time} = time;
                                    my $lvl;
                                    my $skillUseAfter = new Skills(name => $config{$prefix.$i.$prefix2."_use"});
                                    if ($config{$prefix.$i.$prefix2."_lvl"}>$char->{skills}{$skillUseAfter->handle}->{lv} || !$config{$prefix.$i.$prefix2."_lvl"}) {
                                            $lvl = $char->{skills}{$skillUseAfter->handle}->{lv};
                                    } else {
                                            $lvl = $config{$prefix.$i.$prefix2."_lvl"};
                                    }
                                    AI::args->{lvl} = $lvl;
                                    AI::args->{skillID} = $skillUseAfter->id if ($lvl > 0);
                                    AI::args->{char_state} = whenGroundStatus($char->{pos_to}, $skillUseAfter->name);
                                    AI::args->{dequeue} = 1;
                            } else {
                                    Commands::run($config{$prefix.$i.$prefix2."_doCommand"}) if ($config{$prefix.$i.$prefix2."_doCommand"} ne "");
                                    AI::dequeue;
                            }
                    } else {
                            if (existsInList(join(",", keys %{$char->{statuses}}), $skillUse->name) == AI::args->{char_state}) {
                                    $messageSender->sendSkillUse(AI::args->{skillID}, AI::args->{lvl}, $accountID);
                            } elsif (!AI::args->{dequeue} && $config{$prefix.$i.$prefix2}) {
                                    AI::args->{timeout} = $config{$prefix.$i.$prefix2."_wait"};
                                    AI::args->{time} = time;
                                    my $lvl;
                                    my $skillUseAfter = new Skills(name => $config{$prefix.$i.$prefix2."_use"});
                                    if ($config{$prefix.$i.$prefix2."_lvl"}>$char->{skills}{$skillUseAfter->handle}->{lv} || !$config{$prefix.$i.$prefix2."_lvl"}) {
                                            $lvl = $char->{skills}{$skillUseAfter->handle}->{lv};
                                    } else {
                                            $lvl = $config{$prefix.$i.$prefix2."_lvl"};
                                    }
                                    AI::args->{lvl} = $lvl;
                                    AI::args->{skillID} = $skillUseAfter->id if ($lvl > 0);
                                    AI::args->{char_state} = existsInList(join(",", keys %{$char->{statuses}}), $skillUseAfter->name);
                                    AI::args->{dequeue} = 1;
                            } else {
                                    Commands::run($config{$prefix.$i.$prefix2."_doCommand"}) if ($config{$prefix.$i.$prefix2."_doCommand"} ne "");
                                    AI::dequeue;
                            }
                    }
            }
    }

    sub getRandPosition {
       my $range = shift;
       my $x_pos = shift;
       my $y_pos = shift;
       my $x_rand;
       my $y_rand;
       my $x;
       my $y;

       if ($x_pos eq "" || $y_pos eq "") {
          $x_pos = $char->{'pos_to'}{'x'};
          $y_pos = $char->{'pos_to'}{'y'};
       }

       do {
          $x_rand = int(rand($range)) + 1;
          $y_rand = int(rand($range)) + 1;

          if (int(rand(2))) {
             $x = $x_pos + $x_rand;
          } else {
             $x = $x_pos - $x_rand;
          }

          if (int(rand(2))) {
             $y = $y_pos + $y_rand;
          } else {
             $y = $y_pos - $y_rand;
          }
       } while (!($field->isWalkable($x, $y)));

       my @ret = ($x, $y);
       return @ret;
    }

並在config.txt新增以下設定

avoidSkill <要避免的技能名稱> {
	radius <要避免的技能的半徑範圍格數>
	source <施放者類型,Monster=魔物;Player=玩家。若二者都有則留空白。有分大小寫>
	method <以下數字選一個>
#		0 - 隨機移動至半徑  以外  格的地方
#		1 - 往施法點反方向移動  格
#		2 - 移動至最接近的施法者
#		3 - 瞬移飛走(免服不適用)
#		4 - 攻擊施法者(只能用在魔物)
#		5 - 使用技能(只能用在魔物)

#	(methods 0-1 的選項)
	step <要移動多遠的格數>

#	(method 5 的選項)
	skill <用來對付魔物的技能>
#	lvl <技能等級>
	isSelfSkill 0
#	技能是否用在自己身上
	maxCastTime
#	like normal skill slots
	minCastTime
#	like normal skill slots
}

範例:

avoidSkill 傳送之陣,病毒散撥,滑動陷阱,定位陷阱,魔耗陷阱,睡魔陷阱,霜凍陷阱 {

source
radius 1
method 1
step 5

}

「OpenKore 新增迴避技能 avoidSkill 外掛」有一則迴響

發表迴響