autokill SVN

Other plugins for extending OpenKore's functionality. This forum is only for posting new plugins and commenting on existing plugins. For support, use the Support forum.

Moderator: Moderators

Message
Author
various
Noob
Noob
Posts: 1
Joined: 11 Feb 2011, 11:39
Noob?: Yes

autokill SVN

#1 Post by various »

this credit goes by smbot
i just save it for later use

just copy to notepad and save it as AUTOKILL_2_SVN_DELUX.pl
in plugin folder
################################
### AUTOKILL 2 6.1 SVN DELUX ###
################################

### Config Options ###
#autokill_timeout 0.2
#gtb_giveup 0
#gtb_defend 0
#emp_priority 0
#emp_break_dist
#woe_map_name
#woe_castle_name
#maps_ignore
#min_autokill_lvl 0
#hp_upper 0
#sp_upper 5
#stop_if_weight 99
#status_prio_first
#class_priority_1 Creator
#class_priority_2 Assassin Cross
#class_priority_3 Lord Knight
#class_priority_4 Wizzard
#status_prio_last_
#ignore_if_status
#ignore_if_self_status Silence, Mute, Stun
###################
### Future ideas ###
# Add options wheter you want to attack or ignore
# guild mambers , allies, or party members.
# isntead of reseting all AI maybe just focus on
# "attack" "move" etc


package AUTOKILL_2_SVN_DELUX;

use strict;
use Time::HiRes qw(time);
use Log qw(message);

use Globals; # try qw (%players) maybe it would be faster and better
use Plugins;
use Skill;
use Utils;
use Misc;
use AI;
use Commands;

Plugins::register("AUTOKILL 2 6.1 SVN DELUX", "Systematic Approach to AUTOKILLING non-friendly players.", \&nokill);

### Hooks ###
my $commands_hook;
my $config_hook;
my $log_hook;
my $mainAI_hook;
#############

### Config Values ###
my $algorithm_timeout_check;

my $GTB_giveup;
my $GTB_defend;

my $emp_priority;
my $emp_break_dist;
my $woe_map_name;
my $woe_castle_name;
my $maps_ignore;
my @maps_ignore;

my $min_autokill_lvl;

my $hp_upper;
my $sp_upper;

my $no_autokill_if_weight;

my $class_prio_1;
my $class_prio_2;
my $class_prio_3;
my $class_prio_4;
# make CLASS PRIO 5

my $status_prio_first;
my $status_prio_last;
my $status_ignore;
my $status_self_ignore;
###################

### WoE Emperium priority status ###
my $emperium_status;
# 0 = emperium is control by others or idle
# 1 = emperium is broken (Castle belongs to you)
# my $emperium_stuck_timeout;
# make timeout option to prevent bots from gettinf suck on emperium.
################################

### mainAI Controller scalars###
my $attackAI;
# 0 = idle
# 1 = autokill
# 2 = ignore players and attack emperium
# 3 = stops autokill to allow other plugins
my $GTB_on_defend;
# 0 = does nothing
# 1 = use magic crasher on player
my $non_GTB_player_found;
# this function only works if $GTB_defend is set to 1
# 0 = all players have GTB
# 1 = player found without GTB
###########################

### killable player algorithm scalars ###
my %candidate_players;
my @player_prio_candidate;
my %search_nearest_player;
#################################

### Current player on autokill ###
my $current_player;
# next version or autokill
# make current player able to
# be read like so: my $p_ID = $current_player->{binID};
############################

### Timeout(s) ###
my $timeout_AI;
# timeout for the autokill search algorith
my $unstuckAI_timeout;
# if bot is attacking but there's no response after a certain timeout
# move a little if it's still stuck reset
################

### magic skills for GTB check ###
my @magic_skills = (
"Napalm Beat",
"Soul Strike",
"Cold Bolt",
"Frost Diver",
"Fire Ball",
"Fire Wall",
"Fire Bolt",
"Lightening Bolt",
"Thunderstorm",
"Ruwach",
"Holy Light",
"Fire Pillar",
"Sightrasher",
"Meteor Storm",
"Jupitel Thunder",
"Lord of Vermilion",
"Water Ball",
"Frost Nova",
"Storm Gust",
"Earth Spike",
"Heaven's Drive",
"Napalm Vulcan",
"put_new_here"
);
##############################

### Commands for the autokill bot ###
$commands_hook = Commands::register(
["autokill", "Activate the autokill", \&autokill_load],
["nokill", "Deactivates the autokill", \&nokill],
["killinfo", "Debug Info on AUTOKILL", \&autokill_debug_info],
["killreset", "Resets the AUTOKILL", \&autokill_reset]
);
################################

sub autokill_load {
undef $attackAI;
$log_hook = Log::addHook(\&log_autokill_check, "log checks");
$mainAI_hook = Plugins::addHook("AI_pre", \&mainAI);
message "\nAUTOKILL 2 6.1 SVN DELUX\nDeveloped by:\n\t'smbot31' (programming and testing)\n\t'frankieapps' (testing and support)\n\t'shikamarux35' (testing)\nEmail: secretmission3001\@yahoo.com\n\nAutokill Activated\n", "info";
### check if HP, SP, WEIGHT, and STATUS IGNORE and warn player
# also do it fo the killinfo
my $p_HP = $char->{'hp'}/$char->{'hp_max'} * 100;
my $p_SP = $char->{'sp'}/$char->{'sp_max'} * 100;
my $p_weight = $char->{'weight'}/$char->{'weight_max'} * 100;
if ($status_self_ignore) {
if (whenStatusActive($status_self_ignore)) {
message ("AUTOKILL - idle, you are: $status_self_ignore\n", "info");
}
}
if ($p_HP < $hp_upper) {
my $hp = int($p_HP);
my $hp_s = int($hp_upper);
message ("AUTOKILL - idle, HP too low ($hp) from specified ($hp_s)\n", "info");
}
if ($p_SP < $sp_upper) {
my $sp = int($p_SP);
my $sp_s = int($sp_upper);
message ("AUTOKILL - idle, SP too low ($sp) from specified ($sp_s)\n", "info");
}
if ($p_weight >= $no_autokill_if_weight) {
my $weight = int($p_weight);
my $weight_s = int($no_autokill_if_weight);
message ("AUTOKILL - idle, weight too high ($weight) from specified ($weight_s)\n", "info");
}
}

sub nokill {
reset_autokill();
Log::delHook($log_hook);
Plugins::delHook("AI_pre", $mainAI_hook);
message "\nAUTOKILL 6.0 SVN DELUX\nDeveloped by:\n\t'smbot31' (programming and testing)\n\t'frankieapps' (testing and support)\n\t'shikamarux35' (testing)\nEmail: secretmission3001\@yahoo.com\n\nAutokill Deactivated\n", "info";
}

sub autokill_debug_info {

my $msg;

foreach my Actor::Player $player (@{$playersList->getItems()}) {

my $p_accID = $player->{nameID};
my $p_ID = $player->{binID};
my $p_name = $player->{name};
my $p_lv = $player->{lv};
my $p_job = $jobs_lut{$player->{jobID}};
my $p_sex = $sex_lut{$player->{sex}};
my $p_party = $player->{party}{name};
my $p_guild = $player->{guild}{name};
my $my_party = $char->{party}{name};
my $my_guild = $char->{guild}{name};

my $dist = distance($char->{pos_to}, $player->{pos_to});

$my_party = "No Party" if !$my_party;
$my_guild = "No Guild" if !$my_guild;

### players common info ###
$msg .= "-------------------------------------------------------------------------------\n";
$msg .= swrite (
" Account ID: @<<<<<<<<<<<<<<<<<",
[$p_accID]
);
$msg .= swrite (
" ID: @<<< ",
[$p_ID]
);
$msg .= swrite (
" Name: @<<<<<<<<<<<<<<<<<<<<<<<<<<< Level: @<<<< Sex: @<<<< ",
[$p_name,$p_lv,$p_sex]
);
$msg .= swrite (
" Job: @<<<<<<<<<<<<<<<<<<<<<<<<<<< Dist: @<<<<<<<<<<<<<<<<<<<<<<<<<<< ",
[$p_job, $dist]
);
$msg .= swrite (
" Guild: @<<<<<<<<<<<<<<<<<<<<<<<<<<< Party: @<<<<<<<<<<<<<<<<<<<<<<<<<<< ",
[$p_guild, $p_party]
);
#############################

### autokill specificinfo ###
$msg .= "\n\nAUTOKILL SPECIFIC INFO:\n";

if (whenStatusActivePL($playersID[$p_ID], $status_prio_first)) {
$msg .= " - Status over class priority (Player is: $status_prio_first)\n";
}
elsif ($p_job eq $class_prio_1) {
$msg .= " - First class priority\n";
}
elsif ($p_job eq $class_prio_2) {
$msg .= " - Second class priority\n";
}
elsif ($p_job eq $class_prio_3) {
$msg .= " - Third class priority\n";
}
elsif ($p_job eq $class_prio_4) {
$msg .= " - Fourth class priority\n";
}
elsif (whenStatusActivePL($playersID[$p_ID], $status_prio_last)) {
$msg .= " - Class over status priority (Player is: $status_prio_last)\n";
}
else {
$msg .= " - No class priority\n";
}

my $non_autokill_candidate;
undef $non_autokill_candidate;
# 0 = player can be atuokilled
# 1 = player will not be attacked

if ($p_party eq $my_party ) {
$msg .= " - Player is in your party";
$non_autokill_candidate = 1;
}
if ($p_guild eq $my_guild) {
$msg .= " - Player is in your guild";
$non_autokill_candidate = 1;
}
foreach (keys %{$guild{ally}}) {
if ($guild{ally}{$_} eq $p_guild) {
$msg .= " - Player is allied guild";
$non_autokill_candidate = 1;
}
}

#elsif ($guild{ally}{$player->{guildID}}) {
# $msg .= " - Player is allied guild";
# $non_autokill_candidate = 1;
#}

if (whenStatusActivePL($playersID[$p_ID], $status_ignore)) {
$msg .= " - Player is: $status_ignore\n";
$non_autokill_candidate = 1;
}

if ($player->{GTB} && $GTB_defend == 0) {
$msg .= " - Player has a GTB\n";
$non_autokill_candidate = 1;
}
elsif ($player->{GTB} && $GTB_defend == 1) {
$msg .= " - Player has a GTB (defend mode on)\n";
}

if ($p_lv < $min_autokill_lvl) {
$msg .= " - Player level is below specified (lvl: $p_lv) (min: $min_autokill_lvl)\n";
$non_autokill_candidate = 1;
}

if ($player->{'dead'}) {
$msg .= " - Player is dead\n";
$non_autokill_candidate = 1;
}

if ($non_autokill_candidate) {
$msg .= "\n --> Player can't be killed\n";
} else {
$msg .= "\n --> PLAYER IS ON AUTOKILL\n";
}

#######################
}

$msg .= "-------------------------------------------------------------------------------\n";
$msg .= "CHAR (DEBUG)\n";
my $c_name = $char->{'name'};
$msg .= "Name: $c_name\n";
my $c_hp = ($char->{'hp'}/$char->{'hp_max'} * 100);
my $c_sp = ($char->{'sp'}/$char->{'sp_max'} * 100);
$msg .= "HP: $c_hp%\t";
$msg .= "SP: $c_sp%\n";
my $c_weight = int($char->{'weight'}/$char->{'weight_max'} * 100);
$msg .= "Weight: $c_weight%\n";
my $my_party = $char->{party}{name};
my $my_guild = $char->{guild}{name};
$my_party = "No Party" if !$my_party;
$my_guild = "No Guild" if !$my_guild;
$msg .= "Guild: $my_guild\t";
$msg .= "Party: $my_party\n";
my $p_HP = $char->{'hp'}/$char->{'hp_max'} * 100;
my $p_SP = $char->{'sp'}/$char->{'sp_max'} * 100;
my $p_weight = $char->{'weight'}/$char->{'weight_max'} * 100;
my $autokill_active = 1;
if ($status_self_ignore) {
if (whenStatusActive($status_self_ignore)) {
$autokill_active = 0;
$msg .= "- you are: $status_self_ignore\n";
}
}
if ($p_HP < $hp_upper) {
my $hp = int($p_HP);
my $hp_s = int($hp_upper);
$autokill_active = 0;
$msg .= " - HP too low ($hp) from specified ($hp_s)\n";
}
if ($p_SP < $sp_upper) {
my $sp = int($p_SP);
my $sp_s = int($sp_upper);
$autokill_active = 0;
$msg .= " - SP too low ($sp) from specified ($sp_s)\n";
}
if ($p_weight >= $no_autokill_if_weight) {
my $weight = int($p_weight);
my $weight_s = int($no_autokill_if_weight);
$autokill_active = 0;
$msg .= " - Weight too high ($weight) from specified ($weight_s)\n";
}
if ($autokill_active == 1) {
$msg .= " --> AUTOKILL IS ACTIVE\n";
}
else {
$msg .= " --> AUTOKILL IS IDLE\n";
}
$msg .= "________________\n";
$msg .= "\$emperium_status - $emperium_status\n";
$msg .= "\$attackAI - $attackAI\n";
$msg .= "\$GTB_on_defend - $GTB_on_defend\n";
$msg .= "\$current_player - $current_player\n";
### other tests ###

################
$msg .= "-------------------------------------------------------------------------------\n";
message($msg, "list");

undef $msg;
}

sub autokill_reset {
reset_autokill();
message ("AUTOKILL - manual reset\n" , "info");
}

### Configuration Hook ###
$config_hook = Plugins::addHook("start3", \&load_config);
#######################

sub load_config {
$algorithm_timeout_check = $::config{autokill_timeout};

$GTB_giveup = $::config{gtb_giveup};
$GTB_defend = $::config{gtb_defend};

$emp_priority = $::config{emp_priority};
$emp_break_dist = $::config{emp_break_dist};
$woe_map_name = $::config{woe_map_name};
$woe_castle_name = $::config{woe_castle_name};
$maps_ignore = $::config{maps_ignore};
@maps_ignore = split(/, /, $maps_ignore);

$min_autokill_lvl = $::config{min_autokill_lvl};

$hp_upper = $::config{hp_upper};
$sp_upper = $::config{sp_upper};

$no_autokill_if_weight = $::config{stop_if_weight};

$class_prio_1 = $::config{class_priority_1};
$class_prio_2 = $::config{class_priority_2};
$class_prio_3 = $::config{class_priority_3};
$class_prio_4 = $::config{class_priority_4};
# $class_prio_5 = $::config{class_priority_5}; # NOT IMPELEMTED YET

$status_prio_first = $::config{status_prio_first};
$status_prio_last = $::config{status_prio_last_};

$status_ignore = $::config{ignore_if_status};
$status_self_ignore = $::config{ignore_if_self_status};

message "
__________________________________
DEBUG AUTOKILL - \(CONFIG OPTION\)

\$algorithm_timeout_check - $algorithm_timeout_check

\$GTB_giveup - $GTB_giveup
\$GTB_defend - $GTB_defend

\$emp_priority - $emp_priority
\$emp_break_dist - $emp_break_dist
\$woe_map_name - $woe_map_name
\$woe_castle_name - $woe_castle_name
\$maps_ignore - $maps_ignore
\@maps_ignore - @maps_ignore

\$min_autokill_lvl - $min_autokill_lvl

\$hp_upper - $hp_upper
\$sp_upper - $sp_upper

\$no_autokill_if_weight - $no_autokill_if_weight

\$class_prio_1 - $class_prio_1
\$class_prio_2 - $class_prio_2
\$class_prio_3 - $class_prio_3
\$class_prio_4 - $class_prio_4

\$status_prio_first - $status_prio_first
\$status_prio_last - $status_prio_last
\$status_ignore - $status_ignore
\$status_self_ignore - $status_self_ignore
__________________________________

";
}

### GTB detect ###
my $magic_miss = 'You use (.*) \(.* on Player (.*) \((.*)\) - Dmg: Miss';
my $magic_failed = 'Skill (.*) failed \(Basic\)';
### Player log conditions ###
my $taget_died = 'Player Died';
my $target_lost = 'Target lost';
my $cant_reach = 'Can\'t reach or damage target, dropping target';
### Char log conditions ###
my $you_died = 'You have died';
my $map_change = 'Map Change: ';
#### Timeout that checks if player is stuck ###
my $you_attack = 'You attack Player';
my $you_use_skill = 'You use .* on player';
### Fix for Asura strike ###
### WoE Spesific comand ###
my $castle_is_ours = '\] (.*) : castleours'; # maybe set in config
my $castle_not_ours = '\] (.*) : castlenotours'; # maybe set in config
my $castle_taken = '\[GM\] Guild Base \[(.*)\] has been taken by the \[(.*)] guild.';
# my $permited_use = 'Permitted to use Extremity Fist';
# my $you_use_Asura = 'You use Extremity Fist';
### Compatability with other of my plugins ###
my $autokill_remote_player_stop = ' .*?A6_B_'; # prevent player from messing autokill remotly
my $autokill_remote_player_start = ' .*?A6_E_'; # prevent player from messing autokill remotly
my $autokill_remote_stop = '^A6_B_';
my $autokill_remote_start = '^A6_E_';
# also make sure that the other plugins say ex: "A6_B_ BUFF - PLAYER X is being buffed by SKILL"
# and when it end to use the 'A6_E_' command
#######################################

sub log_autokill_check {

### Log scalars ###
my $type = shift;
my $domain = shift;
my $level = shift;
my $currentVerbosity = shift;
my $log_message = shift;
my $user_data = shift;
#################

### prevents players from messing with autokill remotly ###
return if $log_message =~ /$autokill_remote_player_stop/;
return if $log_message =~ /$autokill_remote_player_start/;
#################################################

### GTB detect ###
if ($attackAI == 1 && $GTB_giveup == 1 && $log_message =~ /$magic_miss/i) {
my $GTBcheck_skill = $1;
my $GTBget_name = $2;
my $GTBget_ID = $3;
my $player = $players{$playersID[$GTBget_ID]};
my $GTB = $player->{GTB};
if (!$GTB) {
foreach (@magic_skills) {
if ($_ && $GTBcheck_skill) {
my $p_name = $player->{name};
$player->{GTB} = 1;
message ("AUTOKILL - PLAYER \($GTBget_ID\) $p_name has a GTB: ", "info");
if ($GTB_defend) {
message ("defend\n", "info");
}
else {
message ("ignoring\n", "info");
}
return;
}
}
}
}
if ($attackAI == 1 && $GTB_giveup == 1 && $log_message =~ /$magic_failed/i) {
my $GTBcheck_skill = $1;
my $player = $players{$playersID[$current_player]};
my $GTB = $player->{GTB};
if (!$GTB) {
foreach (@magic_skills) {
if ($_ eq $GTBcheck_skill) {
my $p_name = $player->{name};
my $p_ID = $player->{binID};
$player->{GTB} = 1;
message ("AUTOKILL - PLAYER \($p_ID\) $p_name has a GTB: ", "info");
if ($GTB_defend) {
message ("defend\n", "info");
}
else {
message ("ignoring\n", "info");
}
return;
}
}
}
}
#################
### Log conditions ###
if ($attackAI == 2 && $log_message =~ /$taget_died/i) {
$emperium_status = 1;
reset_autokill(1);
}
elsif ($attackAI == 1 && $log_message =~ /$taget_died/i) {
my $player = $players{$playersID[$current_player]};
my $p_name = $player->{name};
my $p_ID = $player->{binID};
message ("AUTOKILLED - Player \($p_ID\) $p_name\n", "info");
reset_autokill(1);
}
elsif ($attackAI == 1 && $log_message =~ /$target_lost/i) {
reset_autokill(1);
}
elsif ($attackAI == 1 && $log_message =~ /$cant_reach/i) {
reset_autokill(1);
}
###################
### Char log conditions ###
elsif ($attackAI == 1 && $log_message =~ /$you_died/i) {
reset_autokill(1);
}
elsif ($attackAI == 1 && $log_message =~ /$map_change/i) {
reset_autokill(1);
}
#######################
#### Timeout that checks if player is stuck ###
elsif ($attackAI == 1 && $log_message =~ /$you_attack/i) {
$unstuckAI_timeout = time;
}
elsif ($attackAI == 1 && $log_message =~ /$you_use_skill/i) {
$unstuckAI_timeout = time;
}
########################################
### WoE Specific comand ###
elsif ($log_message =~ /$castle_is_ours/i) {
$emperium_status = 1;
message ("AUTOKILL - Castle '$woe_castle_name' is ours.\n", "info");
}
elsif ($log_message =~ /$castle_not_ours/i) {
$emperium_status = 0;
message ("AUTOKILL - Castle '$woe_castle_name' belongs to 'unknown'.\n", "info");
}
elsif ($log_message =~ /$castle_taken/i) {
my $check_castle = $1;
my $check_guild = $2;
my $my_guild = $char->{guild}{name};
if ($check_castle eq $woe_castle_name && $check_guild eq $my_guild) {
$emperium_status = 1;
message ("AUTOKILL - Castle '$woe_castle_name' is ours.\n", "info");
}
elsif ($check_castle eq $woe_castle_name && $check_guild ne $my_guild) {
$emperium_status = 0;
message ("AUTOKILL - Castle '$woe_castle_name' belongs to '$check_guild'.\n", "info");
}
}
##########################
### Compatability With Buff plugin ####
elsif ($log_message =~ m/$autokill_remote_stop/) {
reset_autokill();
$attackAI = 3;
message ("AUTOKILL - Remote stop (waiting for command)\n", "info");
}
elsif ($log_message =~ m/$autokill_remote_start/) {
message ("AUTOKILL - Remote start\n");
reset_autokill(1);
}
##################################
}

### GTB defend scalaras ### # later on try to add is as a config
my $skill_on_GTBdefend = 365; #Skills->new(auto => 365);
my $skill_lv_GTBdefend = 1;
my $GTBdefend_skill_dist = 8;
# Timeout (idenpendent of config)
my $GTBdefend_timeout;
# do however add a timeout limit if its in config to
# specify how fast to continuosly cast the skill
#########################

sub mainAI {

### Check for emperium priority ###
if ($emp_priority == 1 && $woe_map_name eq $field{name} && $emperium_status == 0 && not $attackAI >= 2) {
my $monsters = $monstersList->getItems();
foreach my $monster (@{$monsters}) {
my $m_ID = $monster->{binID};
my $m_name = $monster->{name};
if ($m_name eq "Emperium") {
my $m_dist = distance($char->{pos_to}, $monster->{pos_to});
if ($m_dist <= $emp_break_dist) {
reset_autokill();
$attackAI = 2;
$monster->{dmgFrom} = 1;
main::attack($monstersID[$m_ID]);
message ("AUTOKILL - Emperium priority (attacking)\n", "info");
last;
}
else {
last;
}
}
}
}
##############################

### Autokill GTB defend ###
if ($attackAI == 1 && $GTB_on_defend == 1) {
my $player = $players{$playersID[$current_player]};
if ($player) {
my $dist = distance($player->{'pos_to'}, $char->{'pos_to'});
if ($dist > $GTBdefend_skill_dist && !AI::inQueue("route")) {
my $p_pos = calcPosition($player);
my $p_x = $p_pos->{x};
my $p_y = $p_pos->{y};
my $map = $field{name};
main::ai_route($map, $p_x, $p_y, attackOnRoute => 0, noSitAuto => 1, notifyUponArrival => 0);
}
elsif ($dist < $GTBdefend_skill_dist) {
if (AI::inQueue("route")) {
AI::clear("move", "route", "mapRoute");
}
elsif (timeOut($GTBdefend_timeout, 0.1)) {
$GTBdefend_timeout = time;
# main::ai_skillUse($skill_on_GTBdefend->handle, 1, 0, 0, $target_player);
Commands::run("sp $skill_on_GTBdefend $current_player $skill_lv_GTBdefend");
}
}
}
else {
reset_autokill(1);
}
}
########################

### checks for several conditions ###
my $condtinal_pass_fail = 0;
# 0 = pass
# 1 = condition not met (will not autokill)
################################

### Check for specified maps ot ignore ###
foreach (@maps_ignore) {
if ($_ eq $field{name}) {
$condtinal_pass_fail = 1;
last;
}
}
####################################

### Check SP, HP, weight ###
my $p_HP = $char->{'hp'}/$char->{'hp_max'} * 100;
my $p_SP = $char->{'sp'}/$char->{'sp_max'} * 100;
my $p_weight = $char->{'weight'}/$char->{'weight_max'} * 100;
if ($p_HP < $hp_upper) {
$condtinal_pass_fail = 1;
}
if ($p_SP < $sp_upper) {
$condtinal_pass_fail = 1;
}
if ($p_weight >= $no_autokill_if_weight) {
$condtinal_pass_fail = 1;
}
######################

### Check for status condition ###
if ($status_self_ignore) { # prevents crash if undef
if (whenStatusActive($status_self_ignore)) {
$condtinal_pass_fail = 1;
}
}
#############################

### Prevents openkore from crash ###
# only used when $attackAI = 1
my $check_if_current_player_exists = 0;
# 0 - player doest not exist
# 1 - player exists
################################

### Check for players (in autokill idle) ###
if ($attackAI == 0 && !$condtinal_pass_fail && !$char->{'dead'} && timeOut($timeout_AI, $algorithm_timeout_check)) {
### search for player priorities ###
undef @player_prio_candidate;
undef %search_nearest_player;
@player_prio_candidate = search_for_player();
# push @player_prio_candidate, 0;
### if no priorities select all candidate players ###
if (!@player_prio_candidate && %candidate_players) { # Rest of players with no priorities
foreach (keys %candidate_players) {
my $arr_to_scl = @player_prio_candidate;
$player_prio_candidate[$arr_to_scl] = $_;
}
}
elsif (!@player_prio_candidate && !%candidate_players) { # prevents undef values being treated as player 0
### timeout of the algorithm ###
$timeout_AI = time;
###########################
return;
}
#########################################
### Search and select nearest player(s) ###
my @delete_far_player;
foreach (0 .. $#player_prio_candidate) {
$search_nearest_player{$_} = $player_prio_candidate[$_];
}
foreach my $p_comp_1 (keys %search_nearest_player) {
foreach my $p_comp_2 (keys %search_nearest_player) {
my $player_1 = $players{$playersID[$search_nearest_player{$p_comp_1}]};
my $dist_1 = distance($player_1->{'pos_to'}, $char->{'pos_to'});
my $player_2 = $players{$playersID[$search_nearest_player{$p_comp_2}]};
my $dist_2 = distance($player_2->{'pos_to'}, $char->{'pos_to'});
if ($dist_1 > $dist_2) {
push @delete_far_player, $p_comp_1;
next;
}
elsif ($dist_1 < $dist_2) {
push @delete_far_player, $p_comp_2;
next;
}
}
}
foreach (@delete_far_player) {
# message "player $_ - deleted\n";
delete $search_nearest_player{$_};
}
####################################
### attack reaming player(s) ###
foreach (keys %search_nearest_player) {
if ($GTB_defend == 1 && !$non_GTB_player_found) {
my $player = $players{$playersID[$search_nearest_player{$_}]};
my $p_name = $player->{name};
my $p_ID = $player->{binID};
my $p_job = $jobs_lut{$player->{'jobID'}};
$GTB_on_defend = 1;
$attackAI = 1;
$current_player = $search_nearest_player{$_};
AI::clear("attack", "move", "route", "mapRoute");
message ("AUTOKILLING(GTB defend) - \($p_ID\) $p_name '$p_job'\n", "info");
last;
}
else {
my $player = $players{$playersID[$search_nearest_player{$_}]};
my $p_name = $player->{name};
my $p_ID = $player->{binID};
my $p_job = $jobs_lut{$player->{'jobID'}};
my $target = $playersID[$p_ID];
next if !$p_name;
$unstuckAI_timeout = time;
reset_autokill();
$attackAI = 1;
$current_player = $search_nearest_player{$_};
attack($target);
message ("AUTOKILLING - \($p_ID\) $p_name '$p_job'\n", "info");
last;
}
}
###########################
### timeout of the algorithm ###
$timeout_AI = time;
###########################
}
###################################
### Prevents openkore from crash ###
elsif ($attackAI == 1 && timeOut($timeout_AI, $algorithm_timeout_check)) {
my $player = $players{$playersID[$current_player]};
my $p_name = $player->{name};
my $p_ID = $player->{binID};
# message "DEBUG \($p_ID\) - $p_name\n";
if ($p_name) {
$check_if_current_player_exists = 1;
}
else {
reset_autokill(1);
}
}
################################
### Check for player priorities when autokilling a player ###
if ($attackAI == 1 && $check_if_current_player_exists == 1) {
my $player = $players{$playersID[$current_player]};
my $GTB = $player->{GTB};
my $p_HP = $char->{'hp'}/$char->{'hp_max'} * 100;
my $p_SP = $char->{'sp'}/$char->{'sp_max'} * 100;
my $p_weight = $char->{'weight'}/$char->{'weight_max'} * 100;
if ($status_self_ignore) {
if (whenStatusActive($status_self_ignore)) {
reset_autokill();
message ("AUTOKILL - stoping, you are: $status_self_ignore\n", "info");
}
}
### Make a define checkign for status to prevent crash ###
my $_CHECK_STATUS_SPL = undef;
if ($playersID[$current_player] && $status_ignore) {
if (whenStatusActivePL($playersID[$current_player], $status_ignore)) {
$_CHECK_STATUS_SPL = 1;
}
}
################################################
if ($p_HP < $hp_upper) {
reset_autokill();
my $hp = int($p_HP);
my $hp_s = int($hp_upper);
message ("AUTOKILL - stoping, HP too low ($hp) from specified ($hp_s)\n", "info");
}
elsif ($p_SP < $sp_upper) {
reset_autokill();
my $sp = int($p_SP);
my $sp_s = int($sp_upper);
message ("AUTOKILL - stoping, SP too low ($sp) from specified ($sp_s)\n", "info");
}
elsif ($p_weight >= $no_autokill_if_weight) {
reset_autokill();
my $weight = int($p_weight);
my $weight_s = int($no_autokill_if_weight);
message ("AUTOKILL - stoping, weight too high ($weight) from specified ($weight_s)\n", "info");
}
elsif ($GTB && $GTB_defend == 0) {
reset_autokill(1);
}
elsif ($GTB && $GTB_defend == 1 && $GTB_on_defend == 0) {
reset_autokill(1);
}
elsif ($GTB_defend == 1 && $non_GTB_player_found == 1 && $GTB_on_defend == 1 ) {
reset_autokill(1);
}
elsif ($_CHECK_STATUS_SPL) {
reset_autokill(1);
}
else {
undef @player_prio_candidate;
undef %search_nearest_player;
@player_prio_candidate = search_for_player();
if (@player_prio_candidate) {
### Search and select nearest player(s) ###
my @delete_far_player;
foreach (0 .. $#player_prio_candidate) {
$search_nearest_player{$_} = $player_prio_candidate[$_];
}
foreach my $p_comp_1 (keys %search_nearest_player) {
foreach my $p_comp_2 (keys %search_nearest_player) {
my $player_1 = $players{$playersID[$search_nearest_player{$p_comp_1}]};
my $dist_1 = distance($player_1->{'pos_to'}, $char->{'pos_to'});
my $player_2 = $players{$playersID[$search_nearest_player{$p_comp_2}]};
my $dist_2 = distance($player_2->{'pos_to'}, $char->{'pos_to'});
if ($dist_1 > $dist_2) {
push @delete_far_player, $p_comp_1;
next;
}
elsif ($dist_1 < $dist_2) {
push @delete_far_player, $p_comp_2;
next;
}
}
}
foreach (@delete_far_player) {
delete $search_nearest_player{$_};
}
####################################
### attack priority players player(s) ###
foreach (keys %search_nearest_player) {
if ($current_player != $search_nearest_player{$_}) {
my $player = $players{$playersID[$search_nearest_player{$_}]};
my $p_name = $player->{name};
my $p_ID = $player->{binID};
my $p_job = $jobs_lut{$player->{'jobID'}};
my $target = $playersID[$p_ID];
# replace with subroutine reset
$unstuckAI_timeout = time;
reset_autokill();
$attackAI = 1;
$current_player = $search_nearest_player{$_};
attack($target);
message ("AUTOKILLING - \($p_ID\) $p_name '$p_job'\n", "info");
last;
}
}
################################
}
}
### timeout of the algorithm ###
$timeout_AI = time;
###########################
### Check if player is stuck ###
if (AI::is("move", "route", "mapRoute")) {
$unstuckAI_timeout = time;
}
elsif (AI::is("attack", "skill_use") && timeOut($unstuckAI_timeout, 3.2)) {
### Makes the bot moce a little if stuck ###
my $move_dir = int(rand(4));
if ($move_dir == 0) {
main::ai_route($field{name}, $char->{pos_to}{x}, $char->{pos_to}{y} - 2);
}
elsif ($move_dir == 1) {
main::ai_route($field{name}, $char->{pos_to}{x} + 2, $char->{pos_to}{y});
}
elsif ($move_dir == 2) {
main::ai_route($field{name}, $char->{pos_to}{x} , $char->{pos_to}{y} + 2);
}
elsif ($move_dir == 3) {
main::ai_route($field{name}, $char->{pos_to}{x} - 2, $char->{pos_to}{y});
}
####################################
message "AUTOKILL - player timeout (unstucking)\n";
}
elsif (AI::is("attack", "skill_use") && timeOut($unstuckAI_timeout, 5.2)) {
message "AUTOKILL - player timeout (reseting)\n";
reset_autokill(1);
}
###########################
}
#################################################

}

### Autokill subroutines ###
sub search_for_player {

my @player_prio_candidate;
undef %candidate_players;
undef @player_prio_candidate;

foreach my Actor::Player $player (@{$playersList->getItems()}) {
my $p_accID = $player->{nameID};
my $p_ID = $player->{binID};
my $p_name = $player->{name};
my $p_lv = $player->{lv};
my $p_job = $jobs_lut{$player->{jobID}};
my $p_sex = $sex_lut{$player->{sex}};
my $p_party = $player->{party}{name};
my $p_guild = $player->{guild}{name};

my $my_party = $char->{party}{name};
my $my_guild = $char->{guild}{name};

my $_guild_ally_CHECK = 0;
foreach (keys %{$guild{ally}}) {
if ($guild{ally}{$_} eq $p_guild) {
$_guild_ally_CHECK = 1;
}
}
next if $_guild_ally_CHECK == 1;
$p_party = "P_No_Party" if !$p_party;
$p_guild = "P_No_Guild" if !$p_guild;
$my_party = "C_No_Party" if !$my_party;
$my_guild = "C_No_Guild" if !$my_guild;
next if $p_party eq $my_party;
next if $p_guild eq $my_guild;
# next if $guild{ally}{$player->{guildID}};
next if whenStatusActivePL($playersID[$p_ID], $status_ignore);
next if $p_lv < $min_autokill_lvl;
next if $player->{'dead'};
if ($GTB_defend == 0 && $player->{GTB}) {
next;
}
$candidate_players{$p_ID} = $p_job;
}

return if not %candidate_players;
### check for GTB on defend ###
undef $non_GTB_player_found;
if ($GTB_defend == 1) {
foreach (keys %candidate_players) {
my $player = $players{$playersID[$_]};
my $GTB = $player->{GTB};
if (!$GTB) {
foreach my $i (keys %candidate_players) {
my $iplayer = $players{$playersID[$i]};
my $iGTB = $iplayer->{GTB};
if ($iGTB) {
delete $candidate_players{$i};
}
}
$non_GTB_player_found = 1;
last;
}
}
}
############################

### Check for player priorities ###
# Status over class priority
if ($status_prio_first) {
foreach (keys %candidate_players) {
if (whenStatusActivePL($playersID[$_], $status_prio_first)) {
# my $arr_to_scl = @player_prio_candidate;
# $player_prio_candidate[$arr_to_scl] = $_;
push @player_prio_candidate, $_;
}
}
}
# Class priority 1
if (!@player_prio_candidate) {
foreach (keys %candidate_players) {
if ($candidate_players{$_} eq $class_prio_1) {
# my $arr_to_scl = @player_prio_candidate;
# $player_prio_candidate[$arr_to_scl] = $_;
push @player_prio_candidate, $_;
}
}
}
# Class priority 2
if (!@player_prio_candidate) {
foreach (keys %candidate_players) {
if ($candidate_players{$_} eq $class_prio_2) {
# my $arr_to_scl = @player_prio_candidate;
# $player_prio_candidate[$arr_to_scl] = $_;
push @player_prio_candidate, $_;
}
}
}
# Class priority 3
if (!@player_prio_candidate) {
foreach (keys %candidate_players) {
if ($candidate_players{$_} eq $class_prio_3) {
# my $arr_to_scl = @player_prio_candidate;
# $player_prio_candidate[$arr_to_scl] = $_;
push @player_prio_candidate, $_;
}
}
}
# Class priority 4
if (!@player_prio_candidate) {
foreach (keys %candidate_players) {
if ($candidate_players{$_} eq $class_prio_4) {
# my $arr_to_scl = @player_prio_candidate;
# $player_prio_candidate[$arr_to_scl] = $_;
push @player_prio_candidate, $_;
}
}
}
# Class over status priority
if (!@player_prio_candidate) {
if ($status_prio_last) {
foreach (keys %candidate_players) {
if (whenStatusActivePL($playersID[$_], $status_prio_last)) {
# my $arr_to_scl = @player_prio_candidate;
# $player_prio_candidate[$arr_to_scl] = $_;
push @player_prio_candidate, $_;
}
}
}
}
# Any player at random
if (!@player_prio_candidate) {
foreach (keys %candidate_players) {
# my $arr_to_scl = @player_prio_candidate;
# $player_prio_candidate[$arr_to_scl] = $_;
push @player_prio_candidate, $_;
}
}
############################

# FOR FUTURE DEBUG
# foreach (keys %candidate_players) {message "-> ATTACKING: $_\n";};
# foreach (@player_prio_candidate) {message "-> ATTACKINGARR: $_\n";};

### Output ###
return @player_prio_candidate;
## returns the list of players in priority
#############

}

sub reset_autokill {
my $message_check = @_;

undef $attackAI;
undef $current_player;
undef $GTB_on_defend;

AI::clear("attack", "move", "route", "mapRoute");

if ($message_check) {
message ("AUTOKILL - Searching for next target\n", "info");
}
}
########################

return 1;