在 config.txt 新增如下的迴避地面陷阱設定區塊 - #啟動迴避地面陷阱插件
- autoAvoidTrap 1
- #掃瞄地面陷阱插件的間隔時間
- avoidTrapTimeout 1
- avoidTrap 傳送之陣,病毒散撥,滑動陷阱,定位陷阱,睡魔陷阱,霜凍陷阱,強光陷阱,易燃之網,震波陷阱,魔耗陷阱,爆散陷阱,火柱攻擊 {
- #區塊名稱
- label myPlug_T0
- #地面陷阱來源 Monster, Player, Pet, NPC, Party, Slave 其中之一
- source
- #地面陷阱位置方圓距離之面
- radius 5
- #迴避方法
- # 0 - 隨機位移 step 格數
- # 1 - 反向位移 step 格數
- # 2 - 向左或右移動
- # 3 - 瞬移
- # 5 - 放放技能 (僅 source 設定 Monster 時)
- method 2
- #位移格數
- step 10
- #技能 (method 設定 5) - 以下參數請參考 attackSkillSlot 設定
- skill
- lvl
- maxCastTime
- minCastTime
- isSelfSkill
- }
- }
複製代碼
迴避地面陷阱 (avoidTrap) 的插件程式(plugin)如下,
另存成 avoidTrap.pl 檔案,並置於 plugins 資料夾中即可: - # avoidTrap by Snoopy
- package avoidTrap;
- use strict;
- use Plugins;
- #use warnings;
- use Time::HiRes qw(time);
- use Globals;
- use Utils;
- use Misc;
- use AI;
- use Network::Send;
- use Commands;
- use Skill;
- use Log qw(debug message warning error);
- use Translation;
- #use encoding 'utf8';
- our $lasttime = time;
- our $dirTurn = 1;
- Plugins::register('avoidTrap', 'React to traps.', \&on_unload, \&on_reload);
- my $hooks = Plugins::addHooks(['AI_pre', \&AI_hook]);
- my $prefix = "avoidTrap_";
- my $prefix2 = "_afterCast";
- sub on_unload {
- Plugins::delHooks($hooks);
- undef $prefix;
- undef $prefix2;
- }
- sub on_reload {
- message "avoidTrap plugin reloading\n";
- Plugins::delHooks($hooks);
- undef $prefix;
- undef $prefix2;
- }
- sub AI_hook {
- return if (!$config{autoAvoidTrap});
- my $timeout = $config{avoidTrapTimeout} ? $config{avoidTrapTimeout} : 1;
- if (timeOut($lasttime, $timeout)) {
- checkGroundTrap();
- $lasttime = time;
- }
- }
- sub checkGroundTrap {
- for my $ID (@spellsID) {
- my $spell = $spells{$ID};
- my $binID = $spell->{binID};
- next unless $spell;
- if (!$spell->{mark}) {
- $spell->{mark} = 1;
- last if (avoidTrap('AI_hook', {
- 'binID' => $binID,
- 'skill' => getSpellName($spell->{type}),
- 'skillID' => $spell->{type},
- 'x' => $spell->{pos}{x},
- 'y' => $spell->{pos}{y}
- }));
- }
- }
- }
- sub avoidTrap {
- my (undef, $args) = @_;
- my $hookName = shift;
- my $binID = $args->{binID};
- my $skill = $args->{skill};
- my $skillID = $args->{skillID};
- my $x = $args->{x};
- my $y = $args->{y};
- my $i = 0;
- my $pos = calcPosition($char);
- my $ret = 0;
- debug "checking if we should avoid $skill at ($x, $y)\n";
- for (my $i = 0; exists $config{"avoidTrap_$i"}; $i++) {
- next if (!$config{"avoidTrap_$i"});
- if (existsInList($config{"avoidTrap_$i"}, $skill)) {
- 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{"avoidTrap_$i"."_radius"};
- $right = $x + $config{"avoidTrap_$i"."_radius"};
- $top = $y - $config{"avoidTrap_$i"."_radius"};
- $bottom = $y + $config{"avoidTrap_$i"."_radius"};
- $inRange = 1 if ($left <= $pos->{x} && $right >= $pos->{x} && $top <= $pos->{y} && $bottom >= $pos->{y});
- }
- if ($inRange) {
- if ($char->{sitting}) {
- main::stand();
- }
- # Methods (choose one)
- # 0 - Random position outside <avoidTrap_#_radius> by <avoidTrap_#_step>
- # 1 - Move to opposite side by <avoidTrap_#_step>
- # 2 - Move the right or left side.
- # 3 - Teleport
- # 5 - Use skill. (monsters only)
- if ($config{"avoidTrap_$i"."_method"} == 0) {
- my $found = 1;
- my $count = 0;
- my %move;
- do {
- ($move{x}, $move{y}) = getRandPosition($config{"avoidTrap_${i}_step"});
- $count++;
- if ($count > 100) {
- $found = 0;
- last;
- }
- } while ($left <= $move{x} && $right >= $move{x} && $top <= $move{y} && $bottom >= $move{y});
- if ($found) {
- $char->stopAttack();
- sendMove(\$remote_socket, $move{x}, $move{y});
- message "-- Avoid trap $skill, random move to $move{x}, $move{y}.\n";
- }
- } elsif ($config{"avoidTrap_$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{"avoidTrap_$i"."_step"})) + 1;
- $random{y} = int(rand($config{"avoidTrap_$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) {
- $char->stopAttack();
- sendMove(\$remote_socket, $move{x}, $move{y});
- message "-- Avoid trap $skill, move to $move{x}, $move{y}.\n";
- $ret = 1;
- }
- } elsif ($config{"avoidTrap_$i"."_method"} == 2) {
- my $found = 1;
- my $count = 0;
- my %move;
- ($move{x}, $move{y}) = getSidePosition($config{"avoidTrap_${i}_step"}, $x, $y, $pos->{x}, $pos->{y});
- $char->stopAttack();
- sendMove(\$remote_socket, $move{x}, $move{y});
- message "- Avoid trap $skill [$binID] ($x, $y), random move from ($pos->{x}, $pos->{y}) to ($move{x}, $move{y}).\n";
- $ret = 1;
- } elsif ($config{"avoidTrap_$i"."_method"} == 3) {
- message "-- Avoid trap $skill, use random teleport.\n";
- main::useTeleport(1);
- $ret = 1;
- } elsif ($config{"avoidTrap_$i"."_method"} == 5 && timeOut($AI::Timeouts::avoidTrap_skill, 3)) {
- message "Avoid trap $skill, use ".$config{"avoidTrap_$i"."_skill"}." from ($x, $y)\n";
- $skill = new Skill(name => $config{"avoidTrap_$i"."_skill"});
- if (main::ai_getSkillUseType($skill->getHandle)) {
- my $pos = $char->{pos_to};
- main::ai_skillUse(
- $skill->getHandle,
- $config{"avoidTrap_$i"."_lvl"},
- $config{"avoidTrap_$i"."_maxCastTime"},
- $config{"avoidTrap_$i"."_minCastTime"},
- $pos->{x},
- $pos->{y});
- } else {
- main::ai_skillUse(
- $skill->getHandle,
- $config{"avoidTrap_$i"."_lvl"},
- $config{"avoidTrap_$i"."_maxCastTime"},
- $config{"avoidTrap_$i"."_minCastTime"},
- $accountID);
- }
- $AI::Timeouts::avoidTrap_skill = time;
- $ret = 1;
- }
- }
- last;
- }
- }
- return $ret;
- }
- 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;
- }
- sub getSidePosition {
- my $range = shift;
- my $x2 = shift;
- my $y2 = shift;
- my $x1 = shift;
- my $y1 = shift;
- if ($x1 eq "" || $y1 eq "") {
- my $pos = calcPosition($char);
- $x1 = $pos->{x};
- $y1 = $pos->{y};
- }
- my $a = 0.0;
- my $dx = 0;
- my $dy = $range;
- if ($y1 != $y2) {
- $a = ($x2 - $x1) / ($y1 - $y2);
- $dx = $range / sqrt(1 + $a * $a);
- $dy = $a * $dx;
- }
- my $x;
- my $y;
- $x = $x1 + int($dirTurn * $dx);
- $y = $y1 + int($dirTurn * $dy);
- if (!($field->isWalkable($x, $y))) {
- $dirTurn = -1 * $dirTurn;
- $x = $x1 + int($dirTurn * $dx);
- $y = $y1 + int($dirTurn * $dy);
- }
- my @ret = ($x, $y);
- return @ret;
- }
- 1;
|