(!empty($user->lang['CODE'])) ? $user->lang['CODE'] : ucwords(strtolower(str_replace('_', ' ', 'CODE'))):
package ClosedKore;
use Globals;
use Plugins;
use Settings;
use Log qw(message);
use Utils;
my ($initialized_hook, $start2_hook, $AI_pre_hook, $packet_privMsg_hook);
my %realTimeout;
sub initializeEliza {
# use Chatbot::Eliza;
# $bot = new Chatbot::Eliza "Kore", "elizascript.txt";
}
# Reset %timeout based on %realTimeout.
# Generate random timeout values.
sub initTimeouts {
%timeout = () if (!%timeout);
foreach my $key (keys %realTimeout) {
$timeout{$key}{'timeout'} = $realTimeout{$key}{'timeout'};
$timeout{$key}{'timeout'} += rand($realTimeout{$key}{'variance'}) if ($realTimeout{$key}{'variance'});
}
$timeout{'ai_resetTimeouts'}{'time'} = time;
#print "Reset: $timeout{'ai_attack'}{'timeout'} - $timeout{'ai_resetTimeouts'}{'timeout'}\n";
}
sub parseTimeouts {
my $file = shift;
my $r_hash = shift;
open(FILE, "<file> 0 && !$main::monsters_old{$main::ai_v{'ai_attack_ID_old'}}{'attackedByPlayer'} && !$main::monsters_old{$main::ai_v{'ai_attack_ID_old'}}{'ignore'}) {
main::ai_items_take($main::monsters_old{$main::ai_v{'ai_attack_ID_old'}}{'pos'}{'x'}, $main::monsters_old{$main::ai_v{'ai_attack_ID_old'}}{'pos'}{'y'}, $main::monsters_old{$main::ai_v{'ai_attack_ID_old'}}{'pos_to'}{'x'}, $main::monsters_old{$main::ai_v{'ai_attack_ID_old'}}{'pos_to'}{'y'});
} elsif (!main::ai_getAggressives()) {
# Cheap way to suspend all movement to make it look real
main::ai_clientSuspend(0, $main::timeout{'ai_attack_waitAfterKill'}{'timeout'});
}
## kokal start
## mosters counting
my $i = 0;
my $found = 0;
while ($main::monsters_Killed[$i]) {
if ($main::monsters_Killed[$i]{'nameID'} eq $main::monsters_old{$main::ai_v{'ai_attack_ID_old'}}{'nameID'}) {
$main::monsters_Killed[$i]{'count'}++;
$found = 1;
last;
}
$i++;
}
if (!$found) {
$main::monsters_Killed[$i]{'nameID'} = $main::monsters_old{$main::ai_v{'ai_attack_ID_old'}}{'nameID'};
$main::monsters_Killed[$i]{'name'} = $main::monsters_old{$main::ai_v{'ai_attack_ID_old'}}{'name'};
$main::monsters_Killed[$i]{'count'} = 1;
}
## kokal end
} else {
message "Target lost\n", 1;
}
} elsif ($main::ai_seq[0] eq "attack") {
$main::ai_v{'temp'}{'ai_follow_index'} = binFind(\@ai_seq, "follow");
if ($main::ai_v{'temp'}{'ai_follow_index'} ne "") {
$main::ai_v{'temp'}{'ai_follow_following'} = $main::ai_seq_args[$main::ai_v{'temp'}{'ai_follow_index'}]{'following'};
$main::ai_v{'temp'}{'ai_follow_ID'} = $main::ai_seq_args[$main::ai_v{'temp'}{'ai_follow_index'}]{'ID'};
} else {
undef $main::ai_v{'temp'}{'ai_follow_following'};
}
$main::ai_v{'ai_attack_cleanMonster'} = (
!($main::monsters{$main::ai_seq_args[0]{'ID'}}{'dmgFromYou'} == 0 && ($main::monsters{$main::ai_seq_args[0]{'ID'}}{'dmgTo'} > 0 || $main::monsters{$main::ai_seq_args[0]{'ID'}}{'dmgFrom'} > 0 || %{$main::monsters{$main::ai_seq_args[0]{'ID'}}{'missedFromPlayer'}} || %{$main::monsters{$main::ai_seq_args[0]{'ID'}}{'missedToPlayer'}} || %{$main::monsters{$main::ai_seq_args[0]{'ID'}}{'castOnByPlayer'}}))
|| ($main::config{'attackAuto_party'} && ($main::monsters{$main::ai_seq_args[0]{'ID'}}{'dmgFromParty'} > 0 || $main::monsters{$main::ai_seq_args[0]{'ID'}}{'dmgToParty'} > 0))
|| ($main::config{'attackAuto_followTarget'} && $main::ai_v{'temp'}{'ai_follow_following'} && ($main::monsters{$main::ai_seq_args[0]{'ID'}}{'dmgToPlayer'}{$main::ai_v{'temp'}{'ai_follow_ID'}} > 0 || $main::monsters{$main::ai_seq_args[0]{'ID'}}{'missedToPlayer'}{$main::ai_v{'temp'}{'ai_follow_ID'}} > 0 || $main::monsters{$main::ai_seq_args[0]{'ID'}}{'dmgFromPlayer'}{$main::ai_v{'temp'}{'ai_follow_ID'}} > 0))
|| ($main::monsters{$main::ai_seq_args[0]{'ID'}}{'dmgToYou'} > 0 || $main::monsters{$main::ai_seq_args[0]{'ID'}}{'missedYou'} > 0)
);
$main::ai_v{'ai_attack_cleanMonster'} = 0 if ($main::monsters{$main::ai_seq_args[0]{'ID'}}{'attackedByPlayer'});
$main::ai_v{'ai_attack_cleanMonster'} = 1 if ($main::mon_control{lc($main::monsters{$main::_}{'name'})}{'kill_steal'});
$main::ai_v{'ai_attack_monsterDist'} = main::distance(\%{$main::chars[$main::config{'char'}]{'pos_to'}}, \%{$main::monsters{$main::ai_seq_args[0]{'ID'}}{'pos_to'}});
if ($main::ai_seq_args[0]{'dmgToYou_last'} != $main::monsters{$main::ai_seq_args[0]{'ID'}}{'dmgToYou'}
|| $main::ai_seq_args[0]{'missedYou_last'} != $main::monsters{$main::ai_seq_args[0]{'ID'}}{'missedYou'}
|| $main::ai_seq_args[0]{'dmgFromYou_last'} != $main::monsters{$main::ai_seq_args[0]{'ID'}}{'dmgFromYou'}) {
$main::ai_seq_args[0]{'ai_attack_giveup'}{'time'} = time;
}
$main::ai_seq_args[0]{'dmgToYou_last'} = $main::monsters{$main::ai_seq_args[0]{'ID'}}{'dmgToYou'};
$main::ai_seq_args[0]{'missedYou_last'} = $main::monsters{$main::ai_seq_args[0]{'ID'}}{'missedYou'};
$main::ai_seq_args[0]{'dmgFromYou_last'} = $main::monsters{$main::ai_seq_args[0]{'ID'}}{'dmgFromYou'};
$main::ai_seq_args[0]{'missedFromYou_last'} = $main::monsters{$main::ai_seq_args[0]{'ID'}}{'missedFromYou'};
if (!%{$main::ai_seq_args[0]{'attackMethod'}}) {
if ($main::config{'attackUseWeapon'}) {
$main::ai_seq_args[0]{'attackMethod'}{'distance'} = $main::config{'attackDistance'};
$main::ai_seq_args[0]{'attackMethod'}{'type'} = "weapon";
} else {
$main::ai_seq_args[0]{'attackMethod'}{'distance'} = 30;
undef $main::ai_seq_args[0]{'attackMethod'}{'type'};
}
$i = 0;
while ($main::config{"attackSkillSlot_$i"} ne "") {
if (main::percent_hp(\%{$main::chars[$main::config{'char'}]}) >= $main::config{"attackSkillSlot_$i"."_hp_lower"} && main::percent_hp(\%{$main::chars[$main::config{'char'}]}) <main>= $main::config{"attackSkillSlot_$i"."_sp_lower"} && main::percent_sp(\%{$main::chars[$main::config{'char'}]}) <main>= $main::skillsSP_lut{$main::skills_rlut{lc($main::config{"attackSkillSlot_$i"})}}{$main::config{"attackSkillSlot_$i"."_lvl"}}
&& !($main::config{"attackSkillSlot_$i"."_stopWhenHit"} && amain::i_getMonstersWhoHitMe())
&& (!$main::config{"attackSkillSlot_$i"."_maxUses"} || $main::ai_seq_args[0]{'attackSkillSlot_uses'}{$i} < $main::config{"attackSkillSlot_$i"."_maxUses"})
&& $main::config{"attackSkillSlot_$i"."_minAggressives"} <main>= main::ai_getAggressives())
&& (!$main::config{"attackSkillSlot_$i"."_monsters"} || main::existsInList($main::config{"attackSkillSlot_$i"."_monsters"}, $main::monsters{$main::ai_seq_args[0]{'ID'}}{'name'}))) {
$main::ai_seq_args[0]{'attackSkillSlot_uses'}{$i}++;
$main::ai_seq_args[0]{'attackMethod'}{'distance'} = $main::config{"attackSkillSlot_$i"."_dist"};
$main::ai_seq_args[0]{'attackMethod'}{'type'} = "skill";
$main::ai_seq_args[0]{'attackMethod'}{'skillSlot'} = $i;
last;
}
$i++;
}
}
if ($main::chars[$main::config{'char'}]{'sitting'}) {
main::ai_setSuspend(0);
main::stand();
} elsif (!$main::ai_v{'ai_attack_cleanMonster'}) {
# Drop target if it's already attacked by someone else
message "Dropping target - you will not kill steal others\n", 1;
$main::monsters{$main::ai_seq_args[0]{'ID'}}{'ignore'} = 1;
main::sendAttackStop(\$main::remote_socket);
shift @ai_seq;
shift @ai_seq_args;
} elsif ($main::ai_v{'ai_attack_monsterDist'} > $main::ai_seq_args[0]{'attackMethod'}{'distance'}) {
# Move to target
if (%{$main::ai_seq_args[0]{'char_pos_last'}} && %{$main::ai_seq_args[0]{'attackMethod_last'}}
&& $main::ai_seq_args[0]{'attackMethod_last'}{'distance'} == $main::ai_seq_args[0]{'attackMethod'}{'distance'}
&& $main::ai_seq_args[0]{'char_pos_last'}{'x'} == $main::chars[$main::config{'char'}]{'pos_to'}{'x'}
&& $main::ai_seq_args[0]{'char_pos_last'}{'y'} == $main::chars[$main::config{'char'}]{'pos_to'}{'y'}) {
$main::ai_seq_args[0]{'distanceDivide'}++;
} else {
$main::ai_seq_args[0]{'distanceDivide'} = 1;
}
if (int($main::ai_seq_args[0]{'attackMethod'}{'distance'} / $main::ai_seq_args[0]{'distanceDivide'}) == 0 || ($main::config{'attackMaxRouteDistance'} && $main::ai_seq_args[0]{'ai_route_returnHash'}{'solutionLength'} > $main::config{'attackMaxRouteDistance'}) || ($main::config{'attackMaxRouteTime'} && $main::ai_seq_args[0]{'ai_route_returnHash'}{'solutionTime'} > $main::config{'attackMaxRouteTime'})) {
$main::monsters{$main::ai_seq_args[0]{'ID'}}{'attack_failed'}++;
shift @ai_seq;
shift @ai_seq_args;
message "Dropping target - couldn't reach target\n",,1;
} else {
main::getVector(\%{$main::ai_v{'temp'}{'vec'}}, \%{$main::monsters{$main::ai_seq_args[0]{'ID'}}{'pos_to'}}, \%{$main::chars[$main::config{'char'}]{'pos_to'}});
main::moveAlongVector(\%{$main::ai_v{'temp'}{'pos'}}, \%{$main::chars[$main::config{'char'}]{'pos_to'}}, \%{$main::ai_v{'temp'}{'vec'}},
$main::ai_v{'ai_attack_monsterDist'} - ($main::ai_seq_args[0]{'attackMethod'}{'distance'} / $main::ai_seq_args[0]{'distanceDivide'}) + 1);
%{$main::ai_seq_args[0]{'char_pos_last'}} = %{$main::chars[$main::config{'char'}]{'pos_to'}};
%{$main::ai_seq_args[0]{'attackMethod_last'}} = %{$main::ai_seq_args[0]{'attackMethod'}};
main::ai_setSuspend(0);
if (@{$main::field{'field'}} > 1) {
main::ai_route(\%{$main::ai_seq_args[0]{'ai_route_returnHash'}}, $main::ai_v{'temp'}{'pos'}{'x'}, $main::ai_v{'temp'}{'pos'}{'y'}, $main::field{'name'}, $main::config{'attackMaxRouteDistance'}, $main::config{'attackMaxRouteTime'}, 0, 0, 0, 0, $main::ai_seq_args[0]{'ID'});
} else {
main::move($main::ai_v{'temp'}{'pos'}{'x'}, $main::ai_v{'temp'}{'pos'}{'y'}, 0, $main::ai_seq_args[0]{'ID'});
}
}
} elsif ((($main::config{'tankMode'} && $main::monsters{$main::ai_seq_args[0]{'ID'}}{'dmgFromYou'} == 0)
|| !$main::config{'tankMode'})) {
# Attack the target. In case of tanking, only attack if it hasn't been hit once.
if ($main::ai_seq_args[0]{'attackMethod'}{'type'} eq "weapon" && timeOut(\%{$main::timeout{'ai_attack'}})) {
if ($main::config{'tankMode'}) {
main::sendAttack(\$main::remote_socket, $main::ai_seq_args[0]{'ID'}, 0);
} else {
main::sendAttack(\$main::remote_socket, $main::ai_seq_args[0]{'ID'}, 7);
}
$main::timeout{'ai_attack'}{'time'} = time;
undef %{$main::ai_seq_args[0]{'attackMethod'}};
} elsif ($main::ai_seq_args[0]{'attackMethod'}{'type'} eq "skill") {
$main::ai_v{'ai_attack_method_skillSlot'} = $main::ai_seq_args[0]{'attackMethod'}{'skillSlot'};
$main::ai_v{'ai_attack_ID'} = $main::ai_seq_args[0]{'ID'};
undef %{$main::ai_seq_args[0]{'attackMethod'}};
main::ai_setSuspend(0);
if (!main::ai_getSkillUseType($main::skills_rlut{lc($main::config{"attackSkillSlot_$main::ai_v{'ai_attack_method_skillSlot'}"})})) {
main::ai_skillUse($main::chars[$main::config{'char'}]{'skills'}{$main::skills_rlut{lc($main::config{"attackSkillSlot_$main::ai_v{'ai_attack_method_skillSlot'}"})}}{'ID'}, $main::config{"attackSkillSlot_$main::ai_v{'ai_attack_method_skillSlot'}"."_lvl"}, $main::config{"attackSkillSlot_$main::ai_v{'ai_attack_method_skillSlot'}"."_maxCastTime"}, $main::config{"attackSkillSlot_$main::ai_v{'ai_attack_method_skillSlot'}"."_minCastTime"}, $main::ai_v{'ai_attack_ID'});
} else {
main::ai_skillUse($main::chars[$main::config{'char'}]{'skills'}{$main::skills_rlut{lc($main::config{"attackSkillSlot_$main::ai_v{'ai_attack_method_skillSlot'}"})}}{'ID'}, $main::config{"attackSkillSlot_$main::ai_v{'ai_attack_method_skillSlot'}"."_lvl"}, $main::config{"attackSkillSlot_$main::ai_v{'ai_attack_method_skillSlot'}"."_maxCastTime"}, $main::config{"attackSkillSlot_$main::ai_v{'ai_attack_method_skillSlot'}"."_minCastTime"}, $main::monsters{$main::ai_v{'ai_attack_ID'}}{'pos_to'}{'x'}, $main::monsters{$main::ai_v{'ai_attack_ID'}}{'pos_to'}{'y'});
}
# debug 'Auto-skill on monster: $main::skills_lut{$main::skills_rlut{lc($main::config{"attackSkillSlot_$main::ai_v{'ai_attack_method_skillSlot'}"})}} (lvl $main::config{"attackSkillSlot_$main::ai_v{'ai_attack_method_skillSlot'}"."_lvl"})\n', "ai";
}
} elsif ($main::config{'HitAndRun'} = "1") {
my $flee_x;
my $flee_y;
while ($main::config{'attackDistance'} >= main::distance(\%{$main::chars[$main::config{'char'}]{'pos_to'}}, \%{$main::monsters{$main::ai_v{'ai_attack_ID'}}{'pos_to'}})) {
if (($main::chars[$main::config{'char'}]{'pos'}{'x'}) - ($main::monsters{$main::ai_v{'ai_attack_ID'}}{'pos_to'}{'x'}) <0> 0) {
$flee_x = $main::config{'runDistance'};
} else {
$flee_x = 0;
}
if (($main::chars[$main::config{'char'}]{'pos'}{'y'}) - ($main::monsters{$main::ai_v{'ai_attack_ID'}}{'pos_to'}{'y'}) <0> 0) {
$flee_y = $main::config{'runDistance'};
} else {
$flee_y = 0;
}
$flee_x = ($main::chars[$main::config{'char'}]{'pos'}{'x'}) + $flee_x;
$flee_y = ($main::chars[$main::config{'char'}]{'pos'}{'y'}) + $flee_y;
$flee_x = 0 if ($flee_x <main> $main::field{'width'});
$flee_y = 0 if ($flee_y <main> $main::field{'height'});
if ($flee_x && $flee_y eq 0) {
$flee_x = int(rand() * ($main::field{'width'} - 1));
$flee_y = int(rand() * ($main::field{'height'} - 1));
} elsif ($flee_x eq $main::field{'width'} && $flee_y eq $main::field{'height'}) {
$flee_x = int(rand() * ($main::field{'width'} - 1));
$flee_y = int(rand() * ($main::field{'height'} - 1));
}
main::move($flee_x, $flee_y);
}
message "Fleeing from target\n",,1;
} elsif ($main::config{'tankMode'}) {
if ($main::ai_seq_args[0]{'dmgTo_last'} != $main::monsters{$main::ai_seq_args[0]{'ID'}}{'dmgTo'}) {
$main::ai_seq_args[0]{'ai_attack_giveup'}{'time'} = time;
}
$main::ai_seq_args[0]{'dmgTo_last'} = $main::monsters{$main::ai_seq_args[0]{'ID'}}{'dmgTo'};
}
}
# Check for kill steal while moving
if (main::binFind(\@ai_seq, "attack") ne ""
&& (($main::ai_seq[0] eq "move" || $main::ai_seq[0] eq "route") && $main::ai_seq_args[0]{'attackID'})) {
$main::ai_v{'temp'}{'ai_follow_index'} = main::binFind(\@ai_seq, "follow");
if ($main::ai_v{'temp'}{'ai_follow_index'} ne "") {
$main::ai_v{'temp'}{'ai_follow_following'} = $main::ai_seq_args[$main::ai_v{'temp'}{'ai_follow_index'}]{'following'};
$main::ai_v{'temp'}{'ai_follow_ID'} = $main::ai_seq_args[$main::ai_v{'temp'}{'ai_follow_index'}]{'ID'};
} else {
undef $main::ai_v{'temp'}{'ai_follow_following'};
}
my $iD = $main::ai_seq_args[0]{'attackID'};
$main::ai_v{'ai_attack_cleanMonster'} = (
!($main::monsters{$iD}{'dmgFromYou'} == 0 && ($main::monsters{$iD}{'dmgTo'} > 0 || $main::monsters{$iD}{'dmgFrom'} > 0 || %{$main::monsters{$iD}{'missedFromPlayer'}} || %{$main::monsters{$iD}{'missedToPlayer'}} || %{$main::monsters{$iD}{'castOnByPlayer'}}))
|| ($main::config{'attackAuto_party'} && ($main::monsters{$iD}{'dmgFromParty'} > 0 || $main::monsters{$iD}{'dmgToParty'} > 0))
|| ($main::config{'attackAuto_followTarget'} && $main::ai_v{'temp'}{'ai_follow_following'} && ($main::monsters{$iD}{'dmgToPlayer'}{$main::ai_v{'temp'}{'ai_follow_ID'}} > 0 || $main::monsters{$iD}{'missedToPlayer'}{$main::ai_v{'temp'}{'ai_follow_ID'}} > 0 || $main::monsters{$iD}{'dmgFromPlayer'}{$main::ai_v{'temp'}{'ai_follow_ID'}} > 0))
|| ($main::monsters{$iD}{'dmgToYou'} > 0 || $main::monsters{$iD}{'missedYou'} > 0)
);
$main::ai_v{'ai_attack_cleanMonster'} = 0 if ($main::monsters{$iD}{'attackedByPlayer'});
$main::ai_v{'ai_attack_cleanMonster'} = 1 if ($main::mon_control{lc($main::monsters{$main::_}{'name'})}{'kill_steal'});
if (!$main::ai_v{'ai_attack_cleanMonster'}) {
message "Dropping target - you will not kill steal others\n",,1;
main::sendAttackStop(\$main::remote_socket);
$main::monsters{$main::ai_seq_args[0]{'ID'}}{'ignore'} = 1;
shift @ai_seq;
shift @ai_seq_args;
if ($main::ai_seq[0] eq "route") {
shift @ai_seq;
shift @ai_seq_args;
}
shift @ai_seq;
shift @ai_seq_args;
}
}
}
}
sub timeOut {
my ($r_time, $compare_time) = @_;
if ($compare_time ne "") {
return (time - $r_time > $compare_time);
} else {
return (time - $$r_time{'time'} > $$r_time{'timeout'});
}
}
# statConvert(stat)
# where stat is agi or str or dex etc etc
# returns the id code
sub statConvert {
my $stat = shift;
my $ID;
if ($stat eq "str") {
$ID = 0x0D;
} elsif ($stat eq "agi") {
$ID = 0x0E;
} elsif ($stat eq "vit") {
$ID = 0x0F;
} elsif ($stat eq "int") {
$ID = 0x10;
} elsif ($stat eq "dex") {
$ID = 0x11;
} elsif ($stat eq "luk") {
$ID = 0x12;
} else {
$ID = 0;
}
return $ID;
}
sub unload_cb {
Plugins::delHook('start2', $start2_hook);
Plugins::delHook('initialized', $initialized_hook);
Plugins::delHook('AI_pre_hook', $AI_pre_hook);
Plugins::delHook('packet_privMsg', $packet_privMsg_hook);
Plugins::delHook('Command_post', $input_hook);
Plugins::delHook('AI_pre', $autoadd_hook);
Plugins::delHook('AI_pre', $automap_hook);
Plugins::delHook('AI_pre', $autosave_hook);
Plugins::delHook('AI_pre', $closedattack_hook);
Plugins::delHook('start3', $initializedEliza_hook);
}
sub reload_cb {
&unload_cb;
}
Plugins::register('ClosedKore', 'The ClosedKore Plugin', \&unload_cb, \&reload_cb);
$start2_hook = Plugins::addHook('start2', \&addParseFile);
$initialized_hook = Plugins::addHook('initialized', \&initTimeouts);
$AI_pre_hook = Plugins::addHook('AI_pre', \&resetTimeouts);
$packet_privMsg_hook = Plugins::addHook('packet_privMsg', \&packet_privMsg_cb);
$input_hook = Plugins::addHook('Command_post', \&input);
$autoadd_hook = Plugins::addHook('AI_pre', \&autoadd);
$automap_hook = Plugins::addHook('AI_pre', \&automap);
$autosave_hook = Plugins::addHook('AI_pre', \&autosave);
$closedattack_hook = Plugins::addHook('AI_pre', \&closedattack);
$initializeEliza_hook = Plugins::addHook('start3', \&initializeEliza);
return 1;