diff --git a/control/config.txt b/control/config.txt index 05fc49daaa..58b7bf96d6 100644 --- a/control/config.txt +++ b/control/config.txt @@ -10,6 +10,33 @@ password loginPinCode char +flameBarrier 1 +flameBarrier_lvl 10 +flameBarrier_maxCastTime +flameBarrier_minCastTime + +flameBarrier_timeLeft_recastWhenLessThan 6 +flameBarrier_timeLeft_notFleeToWhenLessThan 6 + +flameBarrier_hitsLeft_recastWhenLessThan 4 +flameBarrier_hitsLeft_notFleeToWhenLessThan 4 + +flameBarrier_distBehindBarrier 2 +flameBarrier_sp > 40 +flameBarrier_whenStatusInactive EFST_POSTDELAY +flameBarrier_attack_maxDistance 7 +flameBarrier_runWhenUnsafeAndCantCast 1 +flameBarrier_mustBeMiddle 1 + +attackSkillSlot_0 MG_FIREBOLT +attackSkillSlot_0_lvl 10 +attackSkillSlot_0_sp > 30 +attackSkillSlot_0_disabled 0 +attackSkillSlot_0_dist 7 +attackSkillSlot_0_whenStatusInactive EFST_POSTDELAY + +runFromTarget_dist_BehindBarrier 3 + # Poseidon Settings: https://openkore.com/wiki/Poseidon # They must be the same as Query Server config in Poseidon.txt poseidonServer 127.0.0.1 @@ -66,12 +93,12 @@ attackAuto 2 attackAuto_party 1 attackAuto_onlyWhenSafe 0 attackAuto_followTarget 1 -attackAuto_inLockOnly 1 +attackAuto_inLockOnly 2 attackAuto_notInTown 1 attackAuto_notWhile_storageAuto 1 attackAuto_notWhile_buyAuto 1 attackAuto_notWhile_sellAuto 1 -attackAuto_considerDamagedAggressive 0 +attackAuto_considerDamagedAggressive 1 attackBeyondMaxDistance_waitForAgressive 1 attackDistance 1 attackDistanceAuto 0 @@ -80,11 +107,11 @@ attackMaxRouteDistance 50 attackMaxRouteTime 4 attackMinPlayerDistance 2 attackMinPortalDistance 4 -attackUseWeapon 1 +attackUseWeapon 0 attackNoGiveup 0 -attackCanSnipe 0 -attackCheckLOS 0 -attackRouteMaxPathDistance 13 +attackCanSnipe 1 +attackCheckLOS 1 +attackRouteMaxPathDistance 28 attackLooters 0 attackLooters_dist 1 attackChangeTarget 1 @@ -188,9 +215,9 @@ followLostStep 12 followSitAuto 0 followBot 0 -itemsTakeAuto 2 +itemsTakeAuto 0 itemsTakeAuto_party 0 -itemsGatherAuto 2 +itemsGatherAuto 0 itemsGatherAuto_notInTown 0 itemsGatherAutoMinPlayerDistance 6 itemsGatherAutoMinPortalDistance 5 @@ -201,7 +228,7 @@ cartMaxWeight 7900 itemsTakeGreed 0 itemsCheckWeight 1 -lockMap +lockMap pay_fild08 lockMap_x lockMap_y lockMap_randX @@ -226,7 +253,7 @@ route_removeMissingPortals 0 route_tryToGuessMissingPortalByDistance 1 route_reAddMissingPortals 1 -runFromTarget 0 +runFromTarget 1 runFromTarget_inAdvance 0 runFromTarget_dist 5 runFromTarget_minStep 7 @@ -521,75 +548,6 @@ pet_return 20 # You can copy & paste any block multiple times. So if you want to # configure two attack skills, just duplicate the attackSkillSlot block. -attackSkillSlot { - lvl - dist 1 - maxDist 1 - maxCastTime 0 - minCastTime 0 - hp - sp > 10 - ap - homunculus - homunculus_hp - homunculus_sp - homunculus_dead - homunculus_resting - homunculus_onAction - homunculus_notOnAction - homunculus_whenIdle - homunculus_whenNotIdle - mercenary - mercenary_hp - mercenary_sp - mercenary_whenStatusActive - mercenary_whenStatusInactive - mercenary_onAction - mercenary_notOnAction - mercenary_whenIdle - mercenary_whenNotIdle - onAction - whenStatusActive - whenStatusInactive - whenFollowing - spirit - amuletType - aggressives - previousDamage - stopWhenHit 0 - inLockOnly 0 - notInTown 0 - timeout 0 - disabled 0 - monsters - notMonsters - monstersCount - monstersCountDist - maxAttempts 0 - maxUses 0 - target_hp - target_whenStatusActive - target_whenStatusInactive - target_deltaHp - whenPartyMembersNear - whenPartyMembersNearDist - inInventory - isSelfSkill 0 - isStartSkill 0 - equip_topHead - equip_midHead - equip_lowHead - equip_leftHand - equip_rightHand - equip_leftAccessory - equip_rightAccessory - equip_robe - equip_armor - equip_shoes - equip_arrow - manualAI 0 -} - attackComboSlot { afterSkill waitBeforeUse @@ -951,7 +909,7 @@ getAuto { ######## Debugging options; only useful for developers ######## -debug 0 +debug 2 debugPacket_unparsed 0 debugPacket_received 0 debugPacket_ro_sent 0 diff --git a/control/sys.txt b/control/sys.txt index 305d81b40d..f93071778a 100644 --- a/control/sys.txt +++ b/control/sys.txt @@ -50,7 +50,7 @@ loadPlugins 2 # loadPlugins_list # if loadPlugins is set to 2, this comma-separated list of plugin names (filename without the extension) # specifies which plugin files to load at startup or when the "plugin load all" command is used. -loadPlugins_list macro,profiles,breakTime,raiseStat,raiseSkill,map,reconnect,eventMacro,item_weight_recorder,xconf +loadPlugins_list checkAggressive # skipPlugins_list # if loadPlugins is set to 3, this comma-separated list of plugin names (filename without the extension) diff --git a/plugins/checkAggressive/checkAggressive.pl b/plugins/checkAggressive/checkAggressive.pl new file mode 100644 index 0000000000..750338be0c --- /dev/null +++ b/plugins/checkAggressive/checkAggressive.pl @@ -0,0 +1,115 @@ +package checkAggressive; + +use utf8; +use strict; +use warnings; +use File::Spec; +use JSON::Tiny qw(from_json to_json); +use FileParsers; +use Plugins; +use Settings; +use Globals; +use Log qw(message error debug warning); + +Plugins::register('checkAggressive', 'checkAggressive', \&Unload, \&Unload); + +my $hooks = Plugins::addHooks( + ['start3', \&on_start3, undef], + ['ai_check_Aggressiveness', \&on_ai_check_Aggressiveness, undef], + ['ai_slave_check_Aggressiveness', \&on_ai_slave_check_Aggressiveness, undef], +); + +use constant { + PLUGIN_NAME => 'checkAggressive', +}; + +my $mobs_info; + +our $folder = $Plugins::current_plugin_folder; + +sub Unload { + Plugins::delHook($hooks); + message "[".PLUGIN_NAME."] Plugin unloading or reloading.\n", 'success'; +} + +sub on_start3 { + $mobs_info = loadFile(File::Spec->catdir($folder,'mobs_info.json')); + if (!defined $mobs_info) { + error "[".PLUGIN_NAME."] Could not load mobs info due to a file loading problem.\n."; + return; + } +} + +sub loadFile { + my $file = shift; + + unless (open FILE, "<:utf8", $file) { + error "[".PLUGIN_NAME."] Could not load file $file.\n."; + return; + } + my @lines = ; + close(FILE); + chomp @lines; + my $jsonString = join('',@lines); + + my %converted = %{from_json($jsonString, { utf8 => 1 } )}; + + return \%converted; +} + +sub on_ai_check_Aggressiveness { + my ($self, $args) = @_; + + my $monster = $args->{monster}; + my $ID = $monster->{ID}; + + return unless (exists $mobs_info->{$monster->{nameID}}); + return unless ($mobs_info->{$monster->{nameID}}{is_aggressive} == 1); + + #$mobs_info->{$monster->{nameID}}{lvl} + #$mobs_info->{$monster->{nameID}}{is_aggressive} + + + my $found_clean = 0; + my $found_moving = 0; + + $found_clean = 1 if (Misc::checkMonsterCleanness($ID)); + $found_moving = 1 if (Misc::objectIsMovingTowards($monster, $char)); + + foreach my $slave (values %{$char->{slaves}}) { + $found_clean = 1 if (Misc::slave_checkMonsterCleanness($slave, $ID)); + $found_moving = 1 if (Misc::objectIsMovingTowards($monster, $slave)); + } + + return unless ($found_clean && $found_moving); + + debug "[".PLUGIN_NAME."] Monster $monster at ($monster->{pos}{x} $monster->{pos}{y}) | Lvl $mobs_info->{$monster->{nameID}}{lvl} | is Aggressive, clean, and coming to us\n"; + + $args->{return} = 1; + return; +} + +sub on_ai_slave_check_Aggressiveness { + my ($self, $args) = @_; + + my $monster = $args->{monster}; + my $ID = $monster->{ID}; + my $slave = $args->{slave}; + + return unless (exists $mobs_info->{$monster->{nameID}}); + return unless ($mobs_info->{$monster->{nameID}}{is_aggressive} == 1); + + #$mobs_info->{$monster->{nameID}}{lvl} + #$mobs_info->{$monster->{nameID}}{is_aggressive} + + return unless (Misc::slave_checkMonsterCleanness($slave, $ID) || Misc::checkMonsterCleanness($ID)); + + return unless (Misc::objectIsMovingTowards($monster, $slave) || Misc::objectIsMovingTowards($monster, $char)); + + debug "[".PLUGIN_NAME."] Monster $monster at ($monster->{pos}{x} $monster->{pos}{y}) | Lvl $mobs_info->{$monster->{nameID}}{lvl} | is Aggressive towards slave, clean, and coming to him\n"; + + $args->{return} = 1; + return; +} + +1; \ No newline at end of file diff --git a/plugins/checkAggressive/mobs_info.json b/plugins/checkAggressive/mobs_info.json new file mode 100644 index 0000000000..7ed86033ea --- /dev/null +++ b/plugins/checkAggressive/mobs_info.json @@ -0,0 +1 @@ +{"1001":{"is_aggressive":1,"lvl":"24"},"1002":{"is_aggressive":0,"lvl":"1"},"1004":{"is_aggressive":0,"lvl":"8"},"1005":{"is_aggressive":1,"lvl":"8"},"1007":{"is_aggressive":0,"lvl":"2"},"1008":{"is_aggressive":0,"lvl":"2"},"1009":{"is_aggressive":0,"lvl":"5"},"1010":{"is_aggressive":0,"lvl":"4"},"1011":{"is_aggressive":0,"lvl":"4"},"1012":{"is_aggressive":0,"lvl":"5"},"1013":{"is_aggressive":0,"lvl":"25"},"1014":{"is_aggressive":0,"lvl":"16"},"1015":{"is_aggressive":1,"lvl":"15"},"1016":{"is_aggressive":1,"lvl":"31"},"1018":{"is_aggressive":0,"lvl":"16"},"1019":{"is_aggressive":0,"lvl":"19"},"1020":{"is_aggressive":1,"lvl":"12"},"1023":{"is_aggressive":1,"lvl":"24"},"1024":{"is_aggressive":0,"lvl":"14"},"1025":{"is_aggressive":0,"lvl":"15"},"1026":{"is_aggressive":1,"lvl":"30"},"1028":{"is_aggressive":1,"lvl":"29"},"1029":{"is_aggressive":1,"lvl":"47"},"1030":{"is_aggressive":0,"lvl":"23"},"1031":{"is_aggressive":0,"lvl":"14"},"1032":{"is_aggressive":0,"lvl":"38"},"1033":{"is_aggressive":1,"lvl":"20"},"1034":{"is_aggressive":0,"lvl":"22"},"1035":{"is_aggressive":1,"lvl":"42"},"1036":{"is_aggressive":1,"lvl":"40"},"1037":{"is_aggressive":1,"lvl":"43"},"1038":{"is_aggressive":1,"lvl":"78"},"1039":{"is_aggressive":1,"lvl":"81"},"1040":{"is_aggressive":0,"lvl":"25"},"1041":{"is_aggressive":1,"lvl":"37"},"1042":{"is_aggressive":0,"lvl":"17"},"1044":{"is_aggressive":1,"lvl":"31"},"1045":{"is_aggressive":1,"lvl":"36"},"1046":{"is_aggressive":1,"lvl":"72"},"1047":{"is_aggressive":0,"lvl":"3"},"1048":{"is_aggressive":0,"lvl":"4"},"1049":{"is_aggressive":0,"lvl":"3"},"1050":{"is_aggressive":0,"lvl":"4"},"1051":{"is_aggressive":0,"lvl":"6"},"1052":{"is_aggressive":0,"lvl":"9"},"1053":{"is_aggressive":0,"lvl":"10"},"1054":{"is_aggressive":1,"lvl":"19"},"1055":{"is_aggressive":0,"lvl":"17"},"1056":{"is_aggressive":0,"lvl":"18"},"1057":{"is_aggressive":0,"lvl":"21"},"1058":{"is_aggressive":0,"lvl":"22"},"1059":{"is_aggressive":1,"lvl":"74"},"1060":{"is_aggressive":0,"lvl":"25"},"1061":{"is_aggressive":1,"lvl":"49"},"1062":{"is_aggressive":0,"lvl":"3"},"1063":{"is_aggressive":0,"lvl":"3"},"1064":{"is_aggressive":0,"lvl":"24"},"1065":{"is_aggressive":1,"lvl":"48"},"1066":{"is_aggressive":0,"lvl":"19"},"1067":{"is_aggressive":0,"lvl":"23"},"1068":{"is_aggressive":1,"lvl":"14"},"1069":{"is_aggressive":1,"lvl":"30"},"1070":{"is_aggressive":0,"lvl":"11"},"1071":{"is_aggressive":1,"lvl":"25"},"1072":{"is_aggressive":1,"lvl":"60"},"1073":{"is_aggressive":0,"lvl":"20"},"1074":{"is_aggressive":0,"lvl":"15"},"1076":{"is_aggressive":0,"lvl":"10"},"1077":{"is_aggressive":1,"lvl":"19"},"1078":{"is_aggressive":0,"lvl":"1"},"1079":{"is_aggressive":0,"lvl":"1"},"1080":{"is_aggressive":0,"lvl":"1"},"1081":{"is_aggressive":0,"lvl":"1"},"1082":{"is_aggressive":0,"lvl":"1"},"1083":{"is_aggressive":0,"lvl":"1"},"1084":{"is_aggressive":0,"lvl":"1"},"1085":{"is_aggressive":0,"lvl":"1"},"1086":{"is_aggressive":0,"lvl":"64"},"1087":{"is_aggressive":1,"lvl":"77"},"1088":{"is_aggressive":1,"lvl":"18"},"1089":{"is_aggressive":1,"lvl":"10"},"1090":{"is_aggressive":1,"lvl":"2"},"1091":{"is_aggressive":1,"lvl":"8"},"1092":{"is_aggressive":1,"lvl":"24"},"1093":{"is_aggressive":1,"lvl":"6"},"1094":{"is_aggressive":0,"lvl":"13"},"1095":{"is_aggressive":0,"lvl":"17"},"1096":{"is_aggressive":1,"lvl":"20"},"1097":{"is_aggressive":0,"lvl":"4"},"1098":{"is_aggressive":1,"lvl":"75"},"1099":{"is_aggressive":1,"lvl":"41"},"1100":{"is_aggressive":1,"lvl":"25"},"1101":{"is_aggressive":1,"lvl":"50"},"1102":{"is_aggressive":1,"lvl":"44"},"1103":{"is_aggressive":0,"lvl":"23"},"1104":{"is_aggressive":0,"lvl":"17"},"1105":{"is_aggressive":0,"lvl":"19"},"1106":{"is_aggressive":1,"lvl":"27"},"1107":{"is_aggressive":0,"lvl":"9"},"1108":{"is_aggressive":0,"lvl":"47"},"1109":{"is_aggressive":1,"lvl":"46"},"1110":{"is_aggressive":0,"lvl":"33"},"1111":{"is_aggressive":1,"lvl":"24"},"1112":{"is_aggressive":1,"lvl":"70"},"1113":{"is_aggressive":0,"lvl":"3"},"1114":{"is_aggressive":0,"lvl":"21"},"1115":{"is_aggressive":1,"lvl":"65"},"1116":{"is_aggressive":0,"lvl":"24"},"1117":{"is_aggressive":1,"lvl":"58"},"1118":{"is_aggressive":1,"lvl":"26"},"1119":{"is_aggressive":1,"lvl":"30"},"1120":{"is_aggressive":1,"lvl":"18"},"1121":{"is_aggressive":0,"lvl":"29"},"1122":{"is_aggressive":1,"lvl":"25"},"1123":{"is_aggressive":1,"lvl":"24"},"1124":{"is_aggressive":1,"lvl":"24"},"1125":{"is_aggressive":1,"lvl":"23"},"1126":{"is_aggressive":1,"lvl":"22"},"1127":{"is_aggressive":0,"lvl":"26"},"1128":{"is_aggressive":0,"lvl":"18"},"1129":{"is_aggressive":1,"lvl":"34"},"1130":{"is_aggressive":1,"lvl":"38"},"1131":{"is_aggressive":1,"lvl":"57"},"1132":{"is_aggressive":1,"lvl":"63"},"1133":{"is_aggressive":1,"lvl":"36"},"1134":{"is_aggressive":1,"lvl":"31"},"1135":{"is_aggressive":1,"lvl":"31"},"1138":{"is_aggressive":0,"lvl":"26"},"1139":{"is_aggressive":1,"lvl":"26"},"1140":{"is_aggressive":1,"lvl":"40"},"1141":{"is_aggressive":0,"lvl":"21"},"1142":{"is_aggressive":0,"lvl":"28"},"1143":{"is_aggressive":1,"lvl":"41"},"1144":{"is_aggressive":0,"lvl":"31"},"1145":{"is_aggressive":0,"lvl":"18"},"1146":{"is_aggressive":1,"lvl":"31"},"1147":{"is_aggressive":1,"lvl":"81"},"1148":{"is_aggressive":1,"lvl":"79"},"1149":{"is_aggressive":1,"lvl":"52"},"1150":{"is_aggressive":1,"lvl":"67"},"1151":{"is_aggressive":1,"lvl":"38"},"1152":{"is_aggressive":1,"lvl":"28"},"1153":{"is_aggressive":1,"lvl":"24"},"1154":{"is_aggressive":1,"lvl":"61"},"1155":{"is_aggressive":1,"lvl":"44"},"1156":{"is_aggressive":1,"lvl":"45"},"1157":{"is_aggressive":1,"lvl":"93"},"1158":{"is_aggressive":0,"lvl":"26"},"1159":{"is_aggressive":1,"lvl":"69"},"1160":{"is_aggressive":0,"lvl":"18"},"1161":{"is_aggressive":0,"lvl":"10"},"1162":{"is_aggressive":1,"lvl":"17"},"1163":{"is_aggressive":1,"lvl":"52"},"1164":{"is_aggressive":1,"lvl":"35"},"1165":{"is_aggressive":1,"lvl":"34"},"1166":{"is_aggressive":0,"lvl":"26"},"1167":{"is_aggressive":0,"lvl":"7"},"1169":{"is_aggressive":1,"lvl":"30"},"1170":{"is_aggressive":0,"lvl":"33"},"1174":{"is_aggressive":0,"lvl":"16"},"1175":{"is_aggressive":0,"lvl":"11"},"1176":{"is_aggressive":0,"lvl":"20"},"1177":{"is_aggressive":0,"lvl":"31"},"1178":{"is_aggressive":1,"lvl":"23"},"1179":{"is_aggressive":1,"lvl":"34"},"1180":{"is_aggressive":1,"lvl":"51"},"1182":{"is_aggressive":0,"lvl":"1"},"1183":{"is_aggressive":1,"lvl":"4"},"1184":{"is_aggressive":1,"lvl":"1"},"1185":{"is_aggressive":0,"lvl":"34"},"1186":{"is_aggressive":1,"lvl":"34"},"1187":{"is_aggressive":0,"lvl":"1"},"1188":{"is_aggressive":1,"lvl":"32"},"1189":{"is_aggressive":1,"lvl":"49"},"1190":{"is_aggressive":1,"lvl":"74"},"1191":{"is_aggressive":1,"lvl":"51"},"1192":{"is_aggressive":1,"lvl":"53"},"1193":{"is_aggressive":1,"lvl":"58"},"1194":{"is_aggressive":1,"lvl":"59"},"1195":{"is_aggressive":1,"lvl":"59"},"1196":{"is_aggressive":1,"lvl":"52"},"1197":{"is_aggressive":1,"lvl":"53"},"1198":{"is_aggressive":1,"lvl":"79"},"1199":{"is_aggressive":1,"lvl":"43"},"1200":{"is_aggressive":1,"lvl":"63"},"1201":{"is_aggressive":1,"lvl":"71"},"1202":{"is_aggressive":1,"lvl":"73"},"1203":{"is_aggressive":1,"lvl":"76"},"1204":{"is_aggressive":1,"lvl":"71"},"1205":{"is_aggressive":1,"lvl":"65"},"1206":{"is_aggressive":1,"lvl":"61"},"1207":{"is_aggressive":1,"lvl":"61"},"1208":{"is_aggressive":1,"lvl":"74"},"1209":{"is_aggressive":1,"lvl":"56"},"1211":{"is_aggressive":1,"lvl":"46"},"1212":{"is_aggressive":1,"lvl":"47"},"1213":{"is_aggressive":1,"lvl":"52"},"1214":{"is_aggressive":1,"lvl":"43"},"1215":{"is_aggressive":1,"lvl":"40"},"1216":{"is_aggressive":1,"lvl":"57"},"1219":{"is_aggressive":1,"lvl":"79"},"1220":{"is_aggressive":1,"lvl":"27"},"1221":{"is_aggressive":1,"lvl":"26"},"1229":{"is_aggressive":0,"lvl":"2"},"1230":{"is_aggressive":0,"lvl":"2"},"1231":{"is_aggressive":0,"lvl":"16"},"1232":{"is_aggressive":0,"lvl":"3"},"1234":{"is_aggressive":0,"lvl":"19"},"1235":{"is_aggressive":1,"lvl":"24"},"1236":{"is_aggressive":0,"lvl":"4"},"1237":{"is_aggressive":0,"lvl":"17"},"1238":{"is_aggressive":0,"lvl":"18"},"1239":{"is_aggressive":0,"lvl":"19"},"1240":{"is_aggressive":0,"lvl":"3"},"1241":{"is_aggressive":0,"lvl":"4"},"1242":{"is_aggressive":0,"lvl":"15"},"1243":{"is_aggressive":1,"lvl":"30"},"1244":{"is_aggressive":0,"lvl":"38"},"1245":{"is_aggressive":0,"lvl":"25"},"1246":{"is_aggressive":0,"lvl":"28"},"1247":{"is_aggressive":0,"lvl":"10"},"1248":{"is_aggressive":1,"lvl":"35"},"1249":{"is_aggressive":0,"lvl":"38"},"1250":{"is_aggressive":1,"lvl":"42"},"1251":{"is_aggressive":1,"lvl":"77"},"1252":{"is_aggressive":1,"lvl":"73"},"1253":{"is_aggressive":1,"lvl":"48"},"1254":{"is_aggressive":1,"lvl":"21"},"1255":{"is_aggressive":1,"lvl":"40"},"1256":{"is_aggressive":1,"lvl":"40"},"1257":{"is_aggressive":1,"lvl":"51"},"1258":{"is_aggressive":1,"lvl":"28"},"1259":{"is_aggressive":1,"lvl":"72"},"1260":{"is_aggressive":1,"lvl":"59"},"1261":{"is_aggressive":0,"lvl":"38"},"1262":{"is_aggressive":1,"lvl":"65"},"1263":{"is_aggressive":1,"lvl":"51"},"1264":{"is_aggressive":1,"lvl":"53"},"1265":{"is_aggressive":0,"lvl":"25"},"1266":{"is_aggressive":0,"lvl":"18"},"1267":{"is_aggressive":1,"lvl":"51"},"1268":{"is_aggressive":1,"lvl":"82"},"1269":{"is_aggressive":0,"lvl":"60"},"1270":{"is_aggressive":0,"lvl":"63"},"1271":{"is_aggressive":0,"lvl":"42"},"1272":{"is_aggressive":1,"lvl":"80"},"1273":{"is_aggressive":1,"lvl":"31"},"1274":{"is_aggressive":1,"lvl":"45"},"1275":{"is_aggressive":0,"lvl":"62"},"1276":{"is_aggressive":1,"lvl":"52"},"1277":{"is_aggressive":1,"lvl":"40"},"1278":{"is_aggressive":0,"lvl":"60"},"1279":{"is_aggressive":1,"lvl":"32"},"1280":{"is_aggressive":0,"lvl":"35"},"1281":{"is_aggressive":0,"lvl":"43"},"1282":{"is_aggressive":1,"lvl":"33"},"1283":{"is_aggressive":1,"lvl":"70"},"1285":{"is_aggressive":1,"lvl":"74"},"1286":{"is_aggressive":1,"lvl":"86"},"1287":{"is_aggressive":1,"lvl":"56"},"1288":{"is_aggressive":0,"lvl":"90"},"1289":{"is_aggressive":1,"lvl":"81"},"1290":{"is_aggressive":1,"lvl":"73"},"1291":{"is_aggressive":1,"lvl":"74"},"1292":{"is_aggressive":1,"lvl":"68"},"1293":{"is_aggressive":1,"lvl":"62"},"1294":{"is_aggressive":1,"lvl":"56"},"1295":{"is_aggressive":1,"lvl":"75"},"1296":{"is_aggressive":1,"lvl":"65"},"1297":{"is_aggressive":1,"lvl":"64"},"1298":{"is_aggressive":1,"lvl":"62"},"1299":{"is_aggressive":1,"lvl":"64"},"1300":{"is_aggressive":1,"lvl":"64"},"1301":{"is_aggressive":1,"lvl":"61"},"1302":{"is_aggressive":1,"lvl":"77"},"1303":{"is_aggressive":1,"lvl":"56"},"1304":{"is_aggressive":1,"lvl":"55"},"1305":{"is_aggressive":1,"lvl":"67"},"1306":{"is_aggressive":1,"lvl":"58"},"1307":{"is_aggressive":1,"lvl":"76"},"1308":{"is_aggressive":1,"lvl":"59"},"1309":{"is_aggressive":1,"lvl":"63"},"1310":{"is_aggressive":1,"lvl":"66"},"1311":{"is_aggressive":1,"lvl":"62"},"1312":{"is_aggressive":1,"lvl":"97"},"1313":{"is_aggressive":1,"lvl":"61"},"1314":{"is_aggressive":0,"lvl":"63"},"1315":{"is_aggressive":1,"lvl":"71"},"1316":{"is_aggressive":0,"lvl":"70"},"1317":{"is_aggressive":1,"lvl":"63"},"1318":{"is_aggressive":1,"lvl":"68"},"1319":{"is_aggressive":1,"lvl":"72"},"1320":{"is_aggressive":1,"lvl":"75"},"1321":{"is_aggressive":1,"lvl":"61"},"1322":{"is_aggressive":0,"lvl":"58"},"1323":{"is_aggressive":1,"lvl":"59"},"1324":{"is_aggressive":0,"lvl":"99"},"1325":{"is_aggressive":0,"lvl":"99"},"1326":{"is_aggressive":0,"lvl":"99"},"1327":{"is_aggressive":0,"lvl":"99"},"1328":{"is_aggressive":0,"lvl":"99"},"1329":{"is_aggressive":0,"lvl":"99"},"1330":{"is_aggressive":0,"lvl":"99"},"1331":{"is_aggressive":0,"lvl":"99"},"1332":{"is_aggressive":0,"lvl":"99"},"1333":{"is_aggressive":0,"lvl":"99"},"1334":{"is_aggressive":0,"lvl":"99"},"1335":{"is_aggressive":0,"lvl":"99"},"1336":{"is_aggressive":0,"lvl":"99"},"1337":{"is_aggressive":0,"lvl":"99"},"1338":{"is_aggressive":0,"lvl":"99"},"1339":{"is_aggressive":0,"lvl":"99"},"1340":{"is_aggressive":0,"lvl":"99"},"1341":{"is_aggressive":0,"lvl":"99"},"1342":{"is_aggressive":0,"lvl":"99"},"1343":{"is_aggressive":0,"lvl":"99"},"1344":{"is_aggressive":0,"lvl":"99"},"1345":{"is_aggressive":0,"lvl":"99"},"1346":{"is_aggressive":0,"lvl":"99"},"1347":{"is_aggressive":0,"lvl":"99"},"1348":{"is_aggressive":0,"lvl":"99"},"1349":{"is_aggressive":0,"lvl":"99"},"1350":{"is_aggressive":0,"lvl":"99"},"1351":{"is_aggressive":0,"lvl":"99"},"1352":{"is_aggressive":0,"lvl":"99"},"1353":{"is_aggressive":0,"lvl":"99"},"1354":{"is_aggressive":0,"lvl":"99"},"1355":{"is_aggressive":0,"lvl":"99"},"1356":{"is_aggressive":0,"lvl":"99"},"1357":{"is_aggressive":0,"lvl":"99"},"1358":{"is_aggressive":0,"lvl":"99"},"1359":{"is_aggressive":0,"lvl":"99"},"1360":{"is_aggressive":0,"lvl":"99"},"1361":{"is_aggressive":0,"lvl":"99"},"1362":{"is_aggressive":0,"lvl":"99"},"1363":{"is_aggressive":0,"lvl":"99"},"1364":{"is_aggressive":1,"lvl":"59"},"1365":{"is_aggressive":0,"lvl":"66"},"1366":{"is_aggressive":1,"lvl":"77"},"1367":{"is_aggressive":1,"lvl":"43"},"1368":{"is_aggressive":1,"lvl":"56"},"1369":{"is_aggressive":0,"lvl":"58"},"1370":{"is_aggressive":1,"lvl":"85"},"1371":{"is_aggressive":1,"lvl":"65"},"1372":{"is_aggressive":0,"lvl":"69"},"1373":{"is_aggressive":1,"lvl":"94"},"1374":{"is_aggressive":1,"lvl":"75"},"1375":{"is_aggressive":1,"lvl":"56"},"1376":{"is_aggressive":1,"lvl":"70"},"1377":{"is_aggressive":1,"lvl":"64"},"1378":{"is_aggressive":1,"lvl":"56"},"1379":{"is_aggressive":1,"lvl":"78"},"1380":{"is_aggressive":1,"lvl":"52"},"1381":{"is_aggressive":1,"lvl":"68"},"1382":{"is_aggressive":1,"lvl":"67"},"1383":{"is_aggressive":1,"lvl":"46"},"1384":{"is_aggressive":1,"lvl":"66"},"1385":{"is_aggressive":1,"lvl":"65"},"1386":{"is_aggressive":1,"lvl":"67"},"1387":{"is_aggressive":1,"lvl":"60"},"1388":{"is_aggressive":1,"lvl":"60"},"1389":{"is_aggressive":1,"lvl":"85"},"1390":{"is_aggressive":1,"lvl":"75"},"1391":{"is_aggressive":0,"lvl":"61"},"1392":{"is_aggressive":1,"lvl":"25"},"1393":{"is_aggressive":1,"lvl":"37"},"1394":{"is_aggressive":1,"lvl":"15"},"1395":{"is_aggressive":0,"lvl":"1"},"1396":{"is_aggressive":0,"lvl":"1"},"1397":{"is_aggressive":0,"lvl":"1"},"1398":{"is_aggressive":0,"lvl":"1"},"1399":{"is_aggressive":1,"lvl":"68"},"1400":{"is_aggressive":0,"lvl":"30"},"1401":{"is_aggressive":1,"lvl":"69"},"1402":{"is_aggressive":0,"lvl":"46"},"1403":{"is_aggressive":1,"lvl":"47"},"1404":{"is_aggressive":0,"lvl":"33"},"1405":{"is_aggressive":1,"lvl":"65"},"1406":{"is_aggressive":1,"lvl":"41"},"1408":{"is_aggressive":1,"lvl":"55"},"1409":{"is_aggressive":0,"lvl":"27"},"1410":{"is_aggressive":1,"lvl":"53"},"1412":{"is_aggressive":1,"lvl":"56"},"1413":{"is_aggressive":0,"lvl":"46"},"1415":{"is_aggressive":1,"lvl":"32"},"1416":{"is_aggressive":1,"lvl":"63"},"1417":{"is_aggressive":0,"lvl":"35"},"1418":{"is_aggressive":1,"lvl":"73"},"1419":{"is_aggressive":1,"lvl":"8"},"1420":{"is_aggressive":1,"lvl":"31"},"1421":{"is_aggressive":1,"lvl":"43"},"1422":{"is_aggressive":1,"lvl":"42"},"1423":{"is_aggressive":1,"lvl":"39"},"1424":{"is_aggressive":1,"lvl":"43"},"1425":{"is_aggressive":1,"lvl":"31"},"1426":{"is_aggressive":1,"lvl":"36"},"1427":{"is_aggressive":1,"lvl":"49"},"1428":{"is_aggressive":1,"lvl":"19"},"1429":{"is_aggressive":1,"lvl":"41"},"1430":{"is_aggressive":1,"lvl":"25"},"1431":{"is_aggressive":1,"lvl":"50"},"1432":{"is_aggressive":1,"lvl":"27"},"1433":{"is_aggressive":1,"lvl":"46"},"1434":{"is_aggressive":1,"lvl":"24"},"1435":{"is_aggressive":1,"lvl":"58"},"1436":{"is_aggressive":1,"lvl":"38"},"1437":{"is_aggressive":1,"lvl":"57"},"1438":{"is_aggressive":1,"lvl":"63"},"1439":{"is_aggressive":1,"lvl":"52"},"1440":{"is_aggressive":1,"lvl":"40"},"1441":{"is_aggressive":1,"lvl":"57"},"1442":{"is_aggressive":1,"lvl":"30"},"1443":{"is_aggressive":1,"lvl":"35"},"1444":{"is_aggressive":1,"lvl":"42"},"1445":{"is_aggressive":1,"lvl":"21"},"1446":{"is_aggressive":1,"lvl":"51"},"1447":{"is_aggressive":1,"lvl":"72"},"1448":{"is_aggressive":1,"lvl":"59"},"1449":{"is_aggressive":1,"lvl":"65"},"1450":{"is_aggressive":1,"lvl":"51"},"1451":{"is_aggressive":1,"lvl":"53"},"1452":{"is_aggressive":1,"lvl":"31"},"1453":{"is_aggressive":1,"lvl":"52"},"1454":{"is_aggressive":1,"lvl":"32"},"1455":{"is_aggressive":1,"lvl":"33"},"1456":{"is_aggressive":1,"lvl":"70"},"1457":{"is_aggressive":1,"lvl":"26"},"1458":{"is_aggressive":1,"lvl":"40"},"1459":{"is_aggressive":1,"lvl":"41"},"1460":{"is_aggressive":1,"lvl":"31"},"1461":{"is_aggressive":1,"lvl":"52"},"1462":{"is_aggressive":1,"lvl":"28"},"1463":{"is_aggressive":1,"lvl":"24"},"1464":{"is_aggressive":1,"lvl":"61"},"1465":{"is_aggressive":1,"lvl":"44"},"1466":{"is_aggressive":1,"lvl":"45"},"1467":{"is_aggressive":1,"lvl":"52"},"1468":{"is_aggressive":1,"lvl":"35"},"1469":{"is_aggressive":1,"lvl":"30"},"1470":{"is_aggressive":1,"lvl":"23"},"1471":{"is_aggressive":1,"lvl":"51"},"1472":{"is_aggressive":1,"lvl":"32"},"1473":{"is_aggressive":1,"lvl":"49"},"1474":{"is_aggressive":1,"lvl":"51"},"1475":{"is_aggressive":1,"lvl":"53"},"1476":{"is_aggressive":1,"lvl":"58"},"1477":{"is_aggressive":1,"lvl":"59"},"1478":{"is_aggressive":1,"lvl":"59"},"1479":{"is_aggressive":1,"lvl":"52"},"1480":{"is_aggressive":1,"lvl":"53"},"1481":{"is_aggressive":1,"lvl":"43"},"1482":{"is_aggressive":1,"lvl":"63"},"1483":{"is_aggressive":1,"lvl":"71"},"1484":{"is_aggressive":1,"lvl":"73"},"1485":{"is_aggressive":1,"lvl":"76"},"1486":{"is_aggressive":1,"lvl":"71"},"1487":{"is_aggressive":1,"lvl":"65"},"1488":{"is_aggressive":1,"lvl":"63"},"1489":{"is_aggressive":1,"lvl":"61"},"1490":{"is_aggressive":1,"lvl":"74"},"1491":{"is_aggressive":1,"lvl":"33"},"1492":{"is_aggressive":1,"lvl":"71"},"1493":{"is_aggressive":1,"lvl":"50"},"1494":{"is_aggressive":0,"lvl":"34"},"1495":{"is_aggressive":1,"lvl":"42"},"1497":{"is_aggressive":1,"lvl":"51"},"1498":{"is_aggressive":1,"lvl":"39"},"1499":{"is_aggressive":1,"lvl":"41"},"1500":{"is_aggressive":1,"lvl":"49"},"1502":{"is_aggressive":1,"lvl":"99"},"1503":{"is_aggressive":1,"lvl":"58"},"1504":{"is_aggressive":1,"lvl":"62"},"1505":{"is_aggressive":1,"lvl":"71"},"1506":{"is_aggressive":1,"lvl":"55"},"1507":{"is_aggressive":1,"lvl":"72"},"1508":{"is_aggressive":1,"lvl":"40"},"1509":{"is_aggressive":1,"lvl":"36"},"1510":{"is_aggressive":1,"lvl":"51"},"1511":{"is_aggressive":1,"lvl":"88"},"1512":{"is_aggressive":1,"lvl":"56"},"1513":{"is_aggressive":1,"lvl":"62"},"1514":{"is_aggressive":0,"lvl":"54"},"1515":{"is_aggressive":1,"lvl":"61"},"1516":{"is_aggressive":0,"lvl":"51"},"1517":{"is_aggressive":1,"lvl":"48"},"1518":{"is_aggressive":1,"lvl":"72"},"1519":{"is_aggressive":1,"lvl":"49"},"1520":{"is_aggressive":0,"lvl":"15"},"1521":{"is_aggressive":0,"lvl":"62"},"1522":{"is_aggressive":1,"lvl":"64"},"1523":{"is_aggressive":1,"lvl":"47"},"1524":{"is_aggressive":1,"lvl":"32"},"1525":{"is_aggressive":1,"lvl":"44"},"1526":{"is_aggressive":1,"lvl":"55"},"1527":{"is_aggressive":0,"lvl":"63"},"1528":{"is_aggressive":0,"lvl":"60"},"1529":{"is_aggressive":1,"lvl":"73"},"1530":{"is_aggressive":1,"lvl":"85"},"1531":{"is_aggressive":1,"lvl":"56"},"1532":{"is_aggressive":1,"lvl":"46"},"1533":{"is_aggressive":1,"lvl":"63"},"1534":{"is_aggressive":1,"lvl":"25"},"1535":{"is_aggressive":1,"lvl":"24"},"1536":{"is_aggressive":1,"lvl":"24"},"1537":{"is_aggressive":1,"lvl":"23"},"1538":{"is_aggressive":1,"lvl":"22"},"1539":{"is_aggressive":1,"lvl":"64"},"1540":{"is_aggressive":0,"lvl":"25"},"1541":{"is_aggressive":1,"lvl":"40"},"1542":{"is_aggressive":1,"lvl":"71"},"1543":{"is_aggressive":1,"lvl":"41"},"1544":{"is_aggressive":0,"lvl":"30"},"1545":{"is_aggressive":1,"lvl":"36"},"1546":{"is_aggressive":1,"lvl":"31"},"1547":{"is_aggressive":1,"lvl":"31"},"1548":{"is_aggressive":1,"lvl":"65"},"1549":{"is_aggressive":1,"lvl":"77"},"1550":{"is_aggressive":1,"lvl":"53"},"1551":{"is_aggressive":0,"lvl":"31"},"1552":{"is_aggressive":0,"lvl":"33"},"1553":{"is_aggressive":1,"lvl":"38"},"1554":{"is_aggressive":1,"lvl":"78"},"1555":{"is_aggressive":1,"lvl":"49"},"1556":{"is_aggressive":0,"lvl":"46"},"1557":{"is_aggressive":1,"lvl":"25"},"1558":{"is_aggressive":1,"lvl":"34"},"1559":{"is_aggressive":1,"lvl":"24"},"1560":{"is_aggressive":1,"lvl":"69"},"1561":{"is_aggressive":0,"lvl":"18"},"1562":{"is_aggressive":1,"lvl":"29"},"1563":{"is_aggressive":1,"lvl":"65"},"1564":{"is_aggressive":1,"lvl":"63"},"1565":{"is_aggressive":0,"lvl":"46"},"1566":{"is_aggressive":1,"lvl":"74"},"1567":{"is_aggressive":1,"lvl":"67"},"1568":{"is_aggressive":1,"lvl":"20"},"1569":{"is_aggressive":1,"lvl":"82"},"1570":{"is_aggressive":1,"lvl":"56"},"1571":{"is_aggressive":0,"lvl":"47"},"1572":{"is_aggressive":0,"lvl":"3"},"1573":{"is_aggressive":1,"lvl":"64"},"1574":{"is_aggressive":1,"lvl":"20"},"1575":{"is_aggressive":1,"lvl":"26"},"1576":{"is_aggressive":1,"lvl":"18"},"1577":{"is_aggressive":1,"lvl":"28"},"1578":{"is_aggressive":1,"lvl":"34"},"1579":{"is_aggressive":1,"lvl":"14"},"1580":{"is_aggressive":1,"lvl":"75"},"1581":{"is_aggressive":1,"lvl":"18"},"1582":{"is_aggressive":1,"lvl":"31"},"1583":{"is_aggressive":1,"lvl":"70"},"1584":{"is_aggressive":1,"lvl":"52"},"1585":{"is_aggressive":0,"lvl":"40"},"1586":{"is_aggressive":0,"lvl":"38"},"1587":{"is_aggressive":1,"lvl":"50"},"1588":{"is_aggressive":0,"lvl":"24"},"1589":{"is_aggressive":1,"lvl":"12"},"1590":{"is_aggressive":1,"lvl":"56"},"1591":{"is_aggressive":0,"lvl":"29"},"1592":{"is_aggressive":0,"lvl":"40"},"1593":{"is_aggressive":1,"lvl":"52"},"1594":{"is_aggressive":1,"lvl":"72"},"1595":{"is_aggressive":0,"lvl":"15"},"1596":{"is_aggressive":1,"lvl":"52"},"1597":{"is_aggressive":1,"lvl":"48"},"1598":{"is_aggressive":1,"lvl":"43"},"1599":{"is_aggressive":1,"lvl":"34"},"1600":{"is_aggressive":1,"lvl":"68"},"1601":{"is_aggressive":1,"lvl":"63"},"1602":{"is_aggressive":1,"lvl":"70"},"1603":{"is_aggressive":0,"lvl":"25"},"1604":{"is_aggressive":1,"lvl":"56"},"1605":{"is_aggressive":1,"lvl":"77"},"1606":{"is_aggressive":1,"lvl":"61"},"1607":{"is_aggressive":1,"lvl":"25"},"1608":{"is_aggressive":1,"lvl":"19"},"1609":{"is_aggressive":0,"lvl":"54"},"1610":{"is_aggressive":1,"lvl":"30"},"1611":{"is_aggressive":1,"lvl":"32"},"1612":{"is_aggressive":1,"lvl":"56"},"1613":{"is_aggressive":0,"lvl":"26"},"1614":{"is_aggressive":0,"lvl":"56"},"1615":{"is_aggressive":1,"lvl":"50"},"1616":{"is_aggressive":0,"lvl":"43"},"1617":{"is_aggressive":1,"lvl":"68"},"1618":{"is_aggressive":1,"lvl":"69"},"1619":{"is_aggressive":0,"lvl":"28"},"1620":{"is_aggressive":1,"lvl":"35"},"1621":{"is_aggressive":1,"lvl":"42"},"1622":{"is_aggressive":1,"lvl":"71"},"1623":{"is_aggressive":1,"lvl":"86"},"1624":{"is_aggressive":1,"lvl":"68"},"1625":{"is_aggressive":1,"lvl":"43"},"1626":{"is_aggressive":1,"lvl":"88"},"1627":{"is_aggressive":1,"lvl":"23"},"1628":{"is_aggressive":0,"lvl":"36"},"1629":{"is_aggressive":1,"lvl":"43"},"1630":{"is_aggressive":1,"lvl":"85"},"1631":{"is_aggressive":1,"lvl":"59"},"1632":{"is_aggressive":0,"lvl":"53"},"1633":{"is_aggressive":0,"lvl":"56"},"1634":{"is_aggressive":1,"lvl":"91"},"1635":{"is_aggressive":1,"lvl":"87"},"1636":{"is_aggressive":1,"lvl":"83"},"1637":{"is_aggressive":1,"lvl":"90"},"1638":{"is_aggressive":1,"lvl":"82"},"1639":{"is_aggressive":1,"lvl":"92"},"1640":{"is_aggressive":1,"lvl":"99"},"1641":{"is_aggressive":1,"lvl":"99"},"1642":{"is_aggressive":1,"lvl":"99"},"1643":{"is_aggressive":1,"lvl":"99"},"1644":{"is_aggressive":1,"lvl":"99"},"1645":{"is_aggressive":1,"lvl":"99"},"1646":{"is_aggressive":1,"lvl":"99"},"1647":{"is_aggressive":1,"lvl":"99"},"1648":{"is_aggressive":1,"lvl":"99"},"1649":{"is_aggressive":1,"lvl":"99"},"1650":{"is_aggressive":1,"lvl":"99"},"1651":{"is_aggressive":1,"lvl":"99"},"1652":{"is_aggressive":1,"lvl":"58"},"1653":{"is_aggressive":1,"lvl":"62"},"1654":{"is_aggressive":1,"lvl":"66"},"1655":{"is_aggressive":1,"lvl":"59"},"1656":{"is_aggressive":1,"lvl":"60"},"1657":{"is_aggressive":1,"lvl":"61"},"1658":{"is_aggressive":1,"lvl":"79"},"1659":{"is_aggressive":1,"lvl":"62"},"1660":{"is_aggressive":1,"lvl":"66"},"1661":{"is_aggressive":1,"lvl":"59"},"1662":{"is_aggressive":1,"lvl":"60"},"1663":{"is_aggressive":1,"lvl":"61"},"1664":{"is_aggressive":1,"lvl":"66"},"1665":{"is_aggressive":1,"lvl":"67"},"1666":{"is_aggressive":1,"lvl":"64"},"1667":{"is_aggressive":1,"lvl":"65"},"1668":{"is_aggressive":1,"lvl":"79"},"1669":{"is_aggressive":1,"lvl":"77"},"1670":{"is_aggressive":1,"lvl":"79"},"1671":{"is_aggressive":1,"lvl":"89"},"1672":{"is_aggressive":1,"lvl":"80"},"1673":{"is_aggressive":1,"lvl":"82"},"1674":{"is_aggressive":1,"lvl":"88"},"1675":{"is_aggressive":1,"lvl":"77"},"1676":{"is_aggressive":1,"lvl":"72"},"1677":{"is_aggressive":1,"lvl":"80"},"1678":{"is_aggressive":1,"lvl":"78"},"1679":{"is_aggressive":1,"lvl":"75"},"1680":{"is_aggressive":1,"lvl":"45"},"1681":{"is_aggressive":1,"lvl":"72"},"1682":{"is_aggressive":1,"lvl":"55"},"1683":{"is_aggressive":1,"lvl":"46"},"1684":{"is_aggressive":1,"lvl":"57"},"1685":{"is_aggressive":1,"lvl":"97"},"1686":{"is_aggressive":1,"lvl":"21"},"1687":{"is_aggressive":0,"lvl":"54"},"1688":{"is_aggressive":1,"lvl":"89"},"1689":{"is_aggressive":1,"lvl":"85"},"1690":{"is_aggressive":0,"lvl":"12"},"1691":{"is_aggressive":1,"lvl":"70"},"1692":{"is_aggressive":1,"lvl":"56"},"1693":{"is_aggressive":1,"lvl":"56"},"1694":{"is_aggressive":1,"lvl":"43"},"1695":{"is_aggressive":1,"lvl":"47"},"1696":{"is_aggressive":1,"lvl":"49"},"1697":{"is_aggressive":1,"lvl":"44"},"1698":{"is_aggressive":1,"lvl":"65"},"1699":{"is_aggressive":1,"lvl":"60"},"1700":{"is_aggressive":1,"lvl":"81"},"1701":{"is_aggressive":1,"lvl":"80"},"1702":{"is_aggressive":1,"lvl":"79"},"1703":{"is_aggressive":1,"lvl":"77"},"1704":{"is_aggressive":1,"lvl":"92"},"1705":{"is_aggressive":1,"lvl":"88"},"1706":{"is_aggressive":1,"lvl":"83"},"1707":{"is_aggressive":1,"lvl":"83"},"1708":{"is_aggressive":1,"lvl":"99"},"1709":{"is_aggressive":1,"lvl":"92"},"1710":{"is_aggressive":1,"lvl":"88"},"1711":{"is_aggressive":1,"lvl":"83"},"1712":{"is_aggressive":1,"lvl":"83"},"1713":{"is_aggressive":1,"lvl":"80"},"1714":{"is_aggressive":1,"lvl":"70"},"1715":{"is_aggressive":1,"lvl":"42"},"1716":{"is_aggressive":1,"lvl":"76"},"1717":{"is_aggressive":1,"lvl":"69"},"1718":{"is_aggressive":1,"lvl":"43"},"1719":{"is_aggressive":1,"lvl":"90"},"1720":{"is_aggressive":1,"lvl":"89"},"1721":{"is_aggressive":0,"lvl":"43"},"1722":{"is_aggressive":0,"lvl":"99"},"1723":{"is_aggressive":1,"lvl":"82"},"1724":{"is_aggressive":1,"lvl":"66"},"1725":{"is_aggressive":0,"lvl":"1"},"1726":{"is_aggressive":0,"lvl":"3"},"1727":{"is_aggressive":0,"lvl":"7"},"1728":{"is_aggressive":0,"lvl":"9"},"1729":{"is_aggressive":0,"lvl":"50"},"1730":{"is_aggressive":0,"lvl":"46"},"1731":{"is_aggressive":1,"lvl":"72"},"1732":{"is_aggressive":0,"lvl":"98"},"1733":{"is_aggressive":1,"lvl":"90"},"1734":{"is_aggressive":1,"lvl":"90"},"1735":{"is_aggressive":1,"lvl":"75"},"1736":{"is_aggressive":1,"lvl":"75"},"1737":{"is_aggressive":0,"lvl":"69"},"1738":{"is_aggressive":1,"lvl":"55"},"1739":{"is_aggressive":1,"lvl":"75"},"1740":{"is_aggressive":1,"lvl":"75"},"1741":{"is_aggressive":1,"lvl":"28"},"1742":{"is_aggressive":1,"lvl":"51"},"1743":{"is_aggressive":1,"lvl":"38"},"1744":{"is_aggressive":1,"lvl":"38"},"1745":{"is_aggressive":1,"lvl":"55"},"1746":{"is_aggressive":1,"lvl":"69"},"1747":{"is_aggressive":1,"lvl":"15"},"1748":{"is_aggressive":1,"lvl":"23"},"1749":{"is_aggressive":1,"lvl":"79"},"1750":{"is_aggressive":0,"lvl":"1"},"1751":{"is_aggressive":1,"lvl":"99"},"1752":{"is_aggressive":1,"lvl":"70"},"1753":{"is_aggressive":1,"lvl":"69"},"1754":{"is_aggressive":1,"lvl":"81"},"1755":{"is_aggressive":1,"lvl":"83"},"1756":{"is_aggressive":1,"lvl":"89"},"1757":{"is_aggressive":1,"lvl":"80"},"1758":{"is_aggressive":1,"lvl":"70"},"1759":{"is_aggressive":1,"lvl":"76"},"1760":{"is_aggressive":1,"lvl":"69"},"1761":{"is_aggressive":1,"lvl":"70"},"1762":{"is_aggressive":1,"lvl":"69"},"1763":{"is_aggressive":1,"lvl":"81"},"1764":{"is_aggressive":1,"lvl":"83"},"1765":{"is_aggressive":1,"lvl":"99"},"1766":{"is_aggressive":1,"lvl":"99"},"1767":{"is_aggressive":1,"lvl":"99"},"1768":{"is_aggressive":1,"lvl":"89"},"1769":{"is_aggressive":1,"lvl":"73"},"1770":{"is_aggressive":1,"lvl":"69"},"1771":{"is_aggressive":1,"lvl":"59"},"1772":{"is_aggressive":1,"lvl":"62"},"1773":{"is_aggressive":1,"lvl":"61"},"1774":{"is_aggressive":1,"lvl":"65"},"1775":{"is_aggressive":1,"lvl":"60"},"1776":{"is_aggressive":0,"lvl":"42"},"1777":{"is_aggressive":1,"lvl":"60"},"1778":{"is_aggressive":1,"lvl":"55"},"1779":{"is_aggressive":1,"lvl":"98"},"1780":{"is_aggressive":1,"lvl":"57"},"1781":{"is_aggressive":1,"lvl":"46"},"1782":{"is_aggressive":0,"lvl":"31"},"1783":{"is_aggressive":0,"lvl":"44"},"1784":{"is_aggressive":0,"lvl":"23"},"1785":{"is_aggressive":1,"lvl":"82"},"1786":{"is_aggressive":1,"lvl":"73"},"1787":{"is_aggressive":1,"lvl":"69"},"1788":{"is_aggressive":1,"lvl":"60"},"1789":{"is_aggressive":1,"lvl":"38"},"1790":{"is_aggressive":1,"lvl":"17"},"1791":{"is_aggressive":0,"lvl":"44"},"1792":{"is_aggressive":0,"lvl":"1"},"1793":{"is_aggressive":1,"lvl":"45"},"1794":{"is_aggressive":1,"lvl":"31"},"1795":{"is_aggressive":1,"lvl":"82"},"1796":{"is_aggressive":1,"lvl":"62"},"1797":{"is_aggressive":1,"lvl":"62"},"1798":{"is_aggressive":0,"lvl":"99"},"1799":{"is_aggressive":1,"lvl":"99"},"1800":{"is_aggressive":1,"lvl":"99"},"1801":{"is_aggressive":1,"lvl":"99"},"1802":{"is_aggressive":1,"lvl":"99"},"1803":{"is_aggressive":1,"lvl":"99"},"1804":{"is_aggressive":1,"lvl":"99"},"1805":{"is_aggressive":1,"lvl":"99"},"1806":{"is_aggressive":1,"lvl":"99"},"1807":{"is_aggressive":1,"lvl":"99"},"1808":{"is_aggressive":1,"lvl":"99"},"1809":{"is_aggressive":1,"lvl":"99"},"1810":{"is_aggressive":1,"lvl":"99"},"1811":{"is_aggressive":0,"lvl":"18"},"1812":{"is_aggressive":0,"lvl":"99"},"1813":{"is_aggressive":1,"lvl":"99"},"1814":{"is_aggressive":1,"lvl":"80"},"1815":{"is_aggressive":0,"lvl":"12"},"1816":{"is_aggressive":0,"lvl":"12"},"1817":{"is_aggressive":1,"lvl":"99"},"1818":{"is_aggressive":1,"lvl":"58"},"1819":{"is_aggressive":1,"lvl":"44"},"1820":{"is_aggressive":0,"lvl":"25"},"1821":{"is_aggressive":1,"lvl":"27"},"1822":{"is_aggressive":1,"lvl":"46"},"1823":{"is_aggressive":1,"lvl":"72"},"1824":{"is_aggressive":1,"lvl":"61"},"1825":{"is_aggressive":1,"lvl":"25"},"1826":{"is_aggressive":1,"lvl":"38"},"1827":{"is_aggressive":1,"lvl":"30"},"1828":{"is_aggressive":1,"lvl":"20"},"1829":{"is_aggressive":1,"lvl":"86"},"1830":{"is_aggressive":1,"lvl":"80"},"1831":{"is_aggressive":1,"lvl":"91"},"1832":{"is_aggressive":1,"lvl":"99"},"1833":{"is_aggressive":1,"lvl":"85"},"1834":{"is_aggressive":1,"lvl":"91"},"1835":{"is_aggressive":1,"lvl":"85"},"1836":{"is_aggressive":0,"lvl":"40"},"1837":{"is_aggressive":1,"lvl":"76"},"1838":{"is_aggressive":0,"lvl":"50"},"1839":{"is_aggressive":1,"lvl":"86"},"1840":{"is_aggressive":0,"lvl":"99"},"1841":{"is_aggressive":0,"lvl":"15"},"1842":{"is_aggressive":0,"lvl":"23"},"1843":{"is_aggressive":1,"lvl":"43"},"1844":{"is_aggressive":1,"lvl":"47"},"1845":{"is_aggressive":0,"lvl":"98"},"1846":{"is_aggressive":0,"lvl":"90"},"1847":{"is_aggressive":1,"lvl":"98"},"1848":{"is_aggressive":1,"lvl":"50"},"1849":{"is_aggressive":1,"lvl":"60"},"1850":{"is_aggressive":1,"lvl":"50"},"1851":{"is_aggressive":1,"lvl":"61"},"1852":{"is_aggressive":1,"lvl":"99"},"1853":{"is_aggressive":1,"lvl":"99"},"1854":{"is_aggressive":0,"lvl":"17"},"1855":{"is_aggressive":1,"lvl":"19"},"1856":{"is_aggressive":0,"lvl":"26"},"1857":{"is_aggressive":0,"lvl":"15"},"1858":{"is_aggressive":0,"lvl":"10"},"1859":{"is_aggressive":1,"lvl":"12"},"1860":{"is_aggressive":0,"lvl":"17"},"1861":{"is_aggressive":1,"lvl":"43"},"1862":{"is_aggressive":0,"lvl":"18"},"1863":{"is_aggressive":0,"lvl":"25"},"1864":{"is_aggressive":1,"lvl":"77"},"1865":{"is_aggressive":1,"lvl":"75"},"1866":{"is_aggressive":1,"lvl":"71"},"1867":{"is_aggressive":1,"lvl":"81"},"1868":{"is_aggressive":1,"lvl":"81"},"1869":{"is_aggressive":1,"lvl":"60"},"1870":{"is_aggressive":1,"lvl":"88"},"1871":{"is_aggressive":1,"lvl":"80"},"1872":{"is_aggressive":1,"lvl":"66"},"1873":{"is_aggressive":1,"lvl":"98"},"1874":{"is_aggressive":1,"lvl":"98"},"1875":{"is_aggressive":1,"lvl":"80"},"1876":{"is_aggressive":1,"lvl":"99"},"1877":{"is_aggressive":0,"lvl":"1"},"1878":{"is_aggressive":0,"lvl":"1"},"1879":{"is_aggressive":1,"lvl":"6"},"1880":{"is_aggressive":0,"lvl":"42"},"1881":{"is_aggressive":0,"lvl":"39"},"1882":{"is_aggressive":1,"lvl":"49"},"1883":{"is_aggressive":1,"lvl":"61"},"1884":{"is_aggressive":1,"lvl":"63"},"1885":{"is_aggressive":1,"lvl":"85"},"1886":{"is_aggressive":1,"lvl":"63"},"1887":{"is_aggressive":1,"lvl":"72"},"1888":{"is_aggressive":1,"lvl":"61"},"1889":{"is_aggressive":1,"lvl":"73"},"1890":{"is_aggressive":1,"lvl":"85"},"1891":{"is_aggressive":1,"lvl":"99"},"1892":{"is_aggressive":1,"lvl":"71"},"1893":{"is_aggressive":1,"lvl":"79"},"1894":{"is_aggressive":0,"lvl":"50"},"1895":{"is_aggressive":1,"lvl":"91"},"1896":{"is_aggressive":1,"lvl":"92"},"1897":{"is_aggressive":1,"lvl":"81"},"1898":{"is_aggressive":1,"lvl":"12"},"1899":{"is_aggressive":1,"lvl":"86"},"1901":{"is_aggressive":0,"lvl":"5"},"1902":{"is_aggressive":0,"lvl":"99"},"1903":{"is_aggressive":0,"lvl":"99"},"1904":{"is_aggressive":1,"lvl":"28"},"1905":{"is_aggressive":0,"lvl":"98"},"1906":{"is_aggressive":0,"lvl":"98"},"1907":{"is_aggressive":0,"lvl":"90"},"1908":{"is_aggressive":0,"lvl":"90"},"1909":{"is_aggressive":0,"lvl":"90"},"1910":{"is_aggressive":0,"lvl":"90"},"1911":{"is_aggressive":0,"lvl":"90"},"1912":{"is_aggressive":0,"lvl":"90"},"1913":{"is_aggressive":0,"lvl":"90"},"1914":{"is_aggressive":0,"lvl":"90"},"1915":{"is_aggressive":0,"lvl":"90"},"1916":{"is_aggressive":1,"lvl":"99"},"1917":{"is_aggressive":1,"lvl":"99"},"1918":{"is_aggressive":1,"lvl":"97"},"1919":{"is_aggressive":1,"lvl":"97"},"1920":{"is_aggressive":1,"lvl":"96"},"1921":{"is_aggressive":1,"lvl":"98"},"1922":{"is_aggressive":1,"lvl":"97"},"1923":{"is_aggressive":1,"lvl":"97"},"1924":{"is_aggressive":1,"lvl":"96"},"1925":{"is_aggressive":1,"lvl":"98"},"1926":{"is_aggressive":1,"lvl":"38"},"1927":{"is_aggressive":1,"lvl":"34"},"1928":{"is_aggressive":1,"lvl":"46"},"1929":{"is_aggressive":1,"lvl":"98"},"1930":{"is_aggressive":1,"lvl":"90"},"1931":{"is_aggressive":1,"lvl":"98"},"1932":{"is_aggressive":0,"lvl":"80"},"1933":{"is_aggressive":1,"lvl":"81"},"1934":{"is_aggressive":0,"lvl":"98"},"1935":{"is_aggressive":0,"lvl":"98"},"1936":{"is_aggressive":0,"lvl":"98"},"1937":{"is_aggressive":1,"lvl":"55"},"1938":{"is_aggressive":0,"lvl":"99"},"1939":{"is_aggressive":0,"lvl":"99"},"1940":{"is_aggressive":0,"lvl":"99"},"1941":{"is_aggressive":0,"lvl":"99"},"1942":{"is_aggressive":0,"lvl":"99"},"1943":{"is_aggressive":0,"lvl":"99"},"1944":{"is_aggressive":0,"lvl":"99"},"1945":{"is_aggressive":0,"lvl":"99"},"1946":{"is_aggressive":0,"lvl":"99"},"1947":{"is_aggressive":1,"lvl":"90"},"1948":{"is_aggressive":1,"lvl":"58"},"1949":{"is_aggressive":1,"lvl":"86"},"1950":{"is_aggressive":1,"lvl":"80"},"1951":{"is_aggressive":0,"lvl":"1"},"1952":{"is_aggressive":0,"lvl":"1"},"1953":{"is_aggressive":0,"lvl":"1"},"1954":{"is_aggressive":0,"lvl":"1"},"1955":{"is_aggressive":0,"lvl":"99"},"1956":{"is_aggressive":1,"lvl":"99"},"1957":{"is_aggressive":1,"lvl":"90"},"1958":{"is_aggressive":1,"lvl":"89"},"1959":{"is_aggressive":1,"lvl":"89"},"1960":{"is_aggressive":1,"lvl":"89"},"1961":{"is_aggressive":1,"lvl":"89"},"1962":{"is_aggressive":0,"lvl":"10"},"1963":{"is_aggressive":1,"lvl":"49"},"1964":{"is_aggressive":0,"lvl":"30"},"1965":{"is_aggressive":0,"lvl":"38"},"1966":{"is_aggressive":0,"lvl":"72"},"1967":{"is_aggressive":0,"lvl":"79"},"1968":{"is_aggressive":0,"lvl":"48"},"1969":{"is_aggressive":0,"lvl":"36"},"1970":{"is_aggressive":0,"lvl":"31"},"1971":{"is_aggressive":0,"lvl":"19"},"1972":{"is_aggressive":0,"lvl":"21"},"1973":{"is_aggressive":0,"lvl":"1"},"1974":{"is_aggressive":1,"lvl":"84"},"1975":{"is_aggressive":1,"lvl":"70"},"1976":{"is_aggressive":1,"lvl":"72"},"1977":{"is_aggressive":1,"lvl":"73"},"1978":{"is_aggressive":1,"lvl":"86"},"1979":{"is_aggressive":1,"lvl":"82"},"1980":{"is_aggressive":1,"lvl":"85"},"1981":{"is_aggressive":1,"lvl":"88"},"1982":{"is_aggressive":1,"lvl":"85"},"1983":{"is_aggressive":1,"lvl":"87"},"1984":{"is_aggressive":1,"lvl":"58"},"1985":{"is_aggressive":1,"lvl":"37"},"1986":{"is_aggressive":0,"lvl":"106"},"1987":{"is_aggressive":1,"lvl":"110"},"1988":{"is_aggressive":1,"lvl":"75"},"1989":{"is_aggressive":1,"lvl":"105"},"1990":{"is_aggressive":1,"lvl":"115"},"1991":{"is_aggressive":1,"lvl":"113"},"1992":{"is_aggressive":0,"lvl":"108"},"1993":{"is_aggressive":1,"lvl":"111"},"1994":{"is_aggressive":1,"lvl":"104"},"1995":{"is_aggressive":1,"lvl":"80"},"1997":{"is_aggressive":0,"lvl":"106"},"1998":{"is_aggressive":1,"lvl":"105"},"1999":{"is_aggressive":1,"lvl":"80"},"2008":{"is_aggressive":1,"lvl":"82"},"2009":{"is_aggressive":1,"lvl":"82"},"2010":{"is_aggressive":0,"lvl":"66"},"2013":{"is_aggressive":0,"lvl":"82"},"2014":{"is_aggressive":0,"lvl":"67"},"2015":{"is_aggressive":1,"lvl":"83"},"2016":{"is_aggressive":1,"lvl":"83"},"2017":{"is_aggressive":1,"lvl":"107"},"2018":{"is_aggressive":1,"lvl":"107"},"2019":{"is_aggressive":1,"lvl":"102"},"2020":{"is_aggressive":1,"lvl":"85"},"2021":{"is_aggressive":1,"lvl":"85"},"2022":{"is_aggressive":1,"lvl":"117"},"2023":{"is_aggressive":1,"lvl":"114"},"2024":{"is_aggressive":1,"lvl":"101"},"2026":{"is_aggressive":1,"lvl":"90"},"2027":{"is_aggressive":1,"lvl":"114"},"2030":{"is_aggressive":1,"lvl":"90"},"2031":{"is_aggressive":1,"lvl":"80"},"2042":{"is_aggressive":1,"lvl":"100"},"2043":{"is_aggressive":1,"lvl":"100"},"2044":{"is_aggressive":1,"lvl":"100"},"2045":{"is_aggressive":1,"lvl":"100"},"2046":{"is_aggressive":1,"lvl":"100"},"2047":{"is_aggressive":1,"lvl":"99"},"2049":{"is_aggressive":1,"lvl":"99"},"2057":{"is_aggressive":0,"lvl":"1"},"2068":{"is_aggressive":1,"lvl":"93"},"2069":{"is_aggressive":0,"lvl":"79"},"2070":{"is_aggressive":1,"lvl":"75"},"2071":{"is_aggressive":1,"lvl":"80"},"2072":{"is_aggressive":1,"lvl":"71"},"2073":{"is_aggressive":1,"lvl":"70"},"2074":{"is_aggressive":0,"lvl":"68"},"2076":{"is_aggressive":1,"lvl":"105"},"2077":{"is_aggressive":1,"lvl":"105"},"2078":{"is_aggressive":1,"lvl":"105"},"2081":{"is_aggressive":0,"lvl":"34"},"2082":{"is_aggressive":1,"lvl":"75"},"2308":{"is_aggressive":0,"lvl":"1"}} \ No newline at end of file diff --git a/src/AI/Attack.pm b/src/AI/Attack.pm index d684dd824d..d64da26a67 100644 --- a/src/AI/Attack.pm +++ b/src/AI/Attack.pm @@ -325,7 +325,20 @@ sub main { my $realMonsterDist = blockDistance($realMyPos, $realMonsterPos); my $cleanMonster = checkMonsterCleanness($ID); - + + my $flameBarrier; + my $canCastFlameBarrier; + if ($config{"flameBarrier"}) { + $canCastFlameBarrier = checkSelfCondition("flameBarrier"); + if (scalar keys %{$flameBarriers{exist}} == 3) { + $canCastFlameBarrier = 0; + } + + $flameBarrier = Misc::check_flameBarrier($realMyPos, $realMonsterPos); + if ($flameBarrier) { + Misc::BarrierDefineNeedRecast($flameBarrier); + } + } # If the damage numbers have changed, update the giveup time so we don't timeout if ($args->{dmgToYou_last} != $target->{dmgToYou} @@ -438,6 +451,11 @@ sub main { if ($args->{attackMethod}{maxDistance} < $args->{attackMethod}{distance}) { $args->{attackMethod}{maxDistance} = $args->{attackMethod}{distance}; } + + if(!defined $args->{attackMethod}{type} && $config{"flameBarrier"}) { + $args->{attackMethod}{type} = "flameBarrier"; + $args->{attackMethod}{maxDistance} = $config{"flameBarrier_attack_maxDistance"}; + } Benchmark::end("ai_attack (part 1.2)") if DEBUG; Benchmark::end("ai_attack (part 1)") if DEBUG; @@ -445,6 +463,20 @@ sub main { if (defined $args->{attackMethod}{type} && exists $args->{ai_attack_failed_give_up} && defined $args->{ai_attack_failed_give_up}{time}) { delete $args->{ai_attack_failed_give_up}{time}; } + + my $flameBarrier_safeCheck = $flameBarrier; + if ($config{"flameBarrier"} && !$flameBarrier) { + my $meeting_safe = meetingPosition($char, 1, $target, $args->{attackMethod}{maxDistance}, 0, 1); + if ($meeting_safe) { + if ($realMyPos->{x} == $meeting_safe->{x} && $realMyPos->{y} == $meeting_safe->{y}) { + warning TF("[Barrier | Unsafe flameBarrier | flameBarrier_safeCheck] %s (%d %d), Barrier at (%d %d), mob at (%d %d).\n", 1, $char, $realMyPos->{x}, $realMyPos->{y}, $meeting_safe->{pos}{x}, $meeting_safe->{pos}{y}, $realMonsterPos->{x}, $realMonsterPos->{y}), 'ai_attack'; + $flameBarrier_safeCheck = $meeting_safe->{flamebarrier}; + Misc::BarrierDefineNeedRecast($flameBarrier_safeCheck); + } else { + $flameBarrier_safeCheck = 0; + } + } + } if ($char->{sitting}) { ai_setSuspend(0); @@ -459,17 +491,38 @@ sub main { message T("Teleport due to dropping attack target\n"), "teleport"; ai_useTeleport(1); } - - } elsif ($config{'runFromTarget'} && ($realMonsterDist < $config{'runFromTarget_dist'} || $hitYou)) { - my $cell = meetingPosition($char, 1, $target, $args->{attackMethod}{maxDistance}, 1); - if ($cell) { - debug TF("[runFromTarget] %s kiteing from (%d %d) to (%d %d), mob at (%d %d).\n", $char, $realMyPos->{x}, $realMyPos->{y}, $cell->{x}, $cell->{y}, $realMonsterPos->{x}, $realMonsterPos->{y}), 'ai_attack'; - $args->{avoiding} = 1; - $char->route(undef, @{$cell}{qw(x y)}, noMapRoute => 1, avoidWalls => 0, runFromTarget => 1); - } else { - debug TF("%s no acceptable place to kite from (%d %d), mob at (%d %d).\n", $char, $realMyPos->{x}, $realMyPos->{y}, $realMonsterPos->{x}, $realMonsterPos->{y}), 'ai_attack'; + + } elsif ( + $config{'runFromTarget'} && + ( + ($realMonsterDist < $config{'runFromTarget_dist'} && (!$config{"flameBarrier"} || !$config{"runFromTarget_dist_BehindBarrier"} || ($config{"flameBarrier"} && $config{"runFromTarget_dist_BehindBarrier"} && !$flameBarrier && !$flameBarrier_safeCheck))) + || + ($config{"flameBarrier"} && $config{"runFromTarget_dist_BehindBarrier"} && ($flameBarrier || $flameBarrier_safeCheck) && $realMonsterDist < $config{'runFromTarget_dist_BehindBarrier'}) + ) + + ) { + my $cell; + if ($config{"flameBarrier"}) { + $cell = meetingPosition($char, 1, $target, $args->{attackMethod}{maxDistance}, 0, 1); + + if ($cell) { + warning TF("[Barrier runFromTarget 1] %s (%d %d) moving behind barrier to (%d %d), mob at (%d %d).\n", $char, $realMyPos->{x}, $realMyPos->{y}, $cell->{x}, $cell->{y}, $realMonsterPos->{x}, $realMonsterPos->{y}), 'ai_attack'; + $args->{avoiding} = 1; + # TODO Check if this runFromTarget => 1 should be bellow + $char->route(undef, @{$cell}{qw(x y)}, noMapRoute => 1, avoidWalls => 0, runFromTarget => 1); + } } + if (!$cell) { + $cell = meetingPosition($char, 1, $target, $args->{attackMethod}{maxDistance}, 1); + if ($cell) { + debug TF("[runFromTarget] %s kiteing from (%d %d) to (%d %d), mob at (%d %d).\n", $char, $realMyPos->{x}, $realMyPos->{y}, $cell->{x}, $cell->{y}, $realMonsterPos->{x}, $realMonsterPos->{y}), 'ai_attack'; + $args->{avoiding} = 1; + $char->route(undef, @{$cell}{qw(x y)}, noMapRoute => 1, avoidWalls => 0, runFromTarget => 1); + } else { + debug TF("%s no acceptable place to kite from (%d %d), mob at (%d %d).\n", $char, $realMyPos->{x}, $realMyPos->{y}, $realMonsterPos->{x}, $realMonsterPos->{y}), 'ai_attack'; + } + } if (!$cell) { my $max = $args->{attackMethod}{maxDistance} + 4; if ($max > 14) { @@ -485,7 +538,6 @@ sub main { } } - } elsif(!defined $args->{attackMethod}{type}) { debug T("Can't determine a attackMethod (check attackUseWeapon and Skills blocks)\n"), "ai_attack"; $args->{ai_attack_failed_give_up}{timeout} = 6 if !$args->{ai_attack_failed_give_up}{timeout}; @@ -496,7 +548,6 @@ sub main { giveUp($args, $ID); } - } elsif ( # We are out of range, but already hit enemy, should wait for him in a safe place instead of going after him # Example at https://youtu.be/kTRk5Na1aCQ?t=25 in which this check did not exist, we tried getting closer intead of waiting and got hit @@ -505,17 +556,114 @@ sub main { $config{"attackBeyondMaxDistance_waitForAgressive"} && $target->{dmgFromYou} > 0 ) { - $args->{ai_attack_failed_waitForAgressive_give_up}{timeout} = 6 if !$args->{ai_attack_failed_waitForAgressive_give_up}{timeout}; - $args->{ai_attack_failed_waitForAgressive_give_up}{time} = time if !$args->{ai_attack_failed_waitForAgressive_give_up}{time}; - - if (timeOut($args->{ai_attack_failed_waitForAgressive_give_up})) { - delete $args->{ai_attack_failed_waitForAgressive_give_up}{time}; - message T("[Out of Range] Waited too long for target to get closer, dropping target\n"), "ai_attack"; - giveUp($args, $ID); + if ($config{"flameBarrier"}) { + if ($flameBarrier) { + # We are already protected behind a wall, but out of range, maybe there is another wall closer to the mob where we would still be safe but be able to attack? + # Example at https://youtu.be/Kxym-WD5gAg?t=181 + my $cell = meetingPosition($char, 1, $target, $args->{attackMethod}{maxDistance}, 0, 2, $flameBarrier); + if ($cell) { + my $new_barrier = $cell->{flamebarrier}; + warning TF("[Barrier Out of Range] %s (%d %d) behind barrier at (%d %d) (BID %d), moving to (%d %d) behind another closer barrier at (%d %d) (BID %d), mob at (%d %d).\n", $char, $realMyPos->{x}, $realMyPos->{y}, $flameBarrier->{pos}{x}, $flameBarrier->{pos}{y}, $flameBarrier->{'barrierID'}, $cell->{x}, $cell->{y}, $new_barrier->{pos}{x}, $new_barrier->{pos}{y}, $new_barrier->{'barrierID'}, $realMonsterPos->{x}, $realMonsterPos->{y}), 'ai_attack'; + $args->{avoiding} = 1; + # TODO Check if this runFromTarget => 1 should be bellow + $char->route(undef, @{$cell}{qw(x y)}, noMapRoute => 1, avoidWalls => 0, runFromTarget => 1); + + # There is no other barrier closer to the target, our barrier needs to be recast and we can do it + } elsif ($canCastFlameBarrier && $flameBarrier->{'needs_recast'}) { + warning "[Barrier Out of Range] Need to recast flamebarrier as it will expire soon.\n"; + + my $bpos = Misc::getBarrierPos($realMyPos, $realMonsterPos, $target, 1); + if (defined $bpos) { + warning "[Barrier Out of Range] Recast - Found location $bpos->{x} $bpos->{y} to cast fire barrier (me: $realMyPos->{x} $realMyPos->{y}| mob: $realMonsterPos->{x} $realMonsterPos->{y}).\n"; + Misc::castBarrier($bpos); + } else { + warning "[Barrier Out of Range] Recast on same location $bpos->{x} $bpos->{y} to cast fire barrier (me: $realMyPos->{x} $realMyPos->{y}| mob: $realMonsterPos->{x} $realMonsterPos->{y}).\n"; + Misc::castBarrier($flameBarrier->{'pos'}); + } + + } + + } elsif ($flameBarrier_safeCheck) { + my $cell = meetingPosition($char, 1, $target, $args->{attackMethod}{maxDistance}, 0, 2, $flameBarrier_safeCheck); + if ($cell) { + my $new_barrier = $cell->{flamebarrier}; + warning TF("[Barrier Out of Range] %s (%d %d) behind barrier-safe at (%d %d) (BID %d), moving to (%d %d) behind another closer barrier at (%d %d) (BID %d), mob at (%d %d).\n", $char, $realMyPos->{x}, $realMyPos->{y}, $flameBarrier_safeCheck->{pos}{x}, $flameBarrier_safeCheck->{pos}{y}, $flameBarrier_safeCheck->{'barrierID'}, $cell->{x}, $cell->{y}, $new_barrier->{pos}{x}, $new_barrier->{pos}{y}, $new_barrier->{'barrierID'}, $realMonsterPos->{x}, $realMonsterPos->{y}), 'ai_attack'; + $args->{avoiding} = 1; + # TODO Check if this runFromTarget => 1 should be bellow + $char->route(undef, @{$cell}{qw(x y)}, noMapRoute => 1, avoidWalls => 0, runFromTarget => 1); + + # There is no other barrier closer to the target, our barrier needs to be recast and we can do it + } elsif ($canCastFlameBarrier && $flameBarrier_safeCheck->{'needs_recast'}) { + warning "[Barrier Out of Range] Need to recast flamebarrier-safe as it will expire soon.\n"; + + my $bpos = Misc::getBarrierPos($realMyPos, $realMonsterPos, $target, 1); + if (defined $bpos) { + warning "[Barrier Out of Range] Recast - Found location $bpos->{x} $bpos->{y} to cast fire barrier-safe (me: $realMyPos->{x} $realMyPos->{y}| mob: $realMonsterPos->{x} $realMonsterPos->{y}).\n"; + Misc::castBarrier($bpos); + } else { + warning "[Barrier Out of Range] Recast on same location $bpos->{x} $bpos->{y} to cast fire barrier-safe (me: $realMyPos->{x} $realMyPos->{y}| mob: $realMonsterPos->{x} $realMonsterPos->{y}).\n"; + Misc::castBarrier($flameBarrier_safeCheck->{'pos'}); + } + + } + + # Out of range, no barrier + } else { + my $cell = meetingPosition($char, 1, $target, $realMonsterDist, 0, 1); + if ($cell) { + warning TF("[Barrier Out of Range] %s (%d %d) moving behind barrier to (%d %d), mob at (%d %d).\n", $char, $realMyPos->{x}, $realMyPos->{y}, $cell->{x}, $cell->{y}, $realMonsterPos->{x}, $realMonsterPos->{y}), 'ai_attack'; + $args->{avoiding} = 1; + # TODO Check if this runFromTarget => 1 should be bellow + $char->route(undef, @{$cell}{qw(x y)}, noMapRoute => 1, avoidWalls => 0, runFromTarget => 1); + } elsif ($canCastFlameBarrier) { + warning TF("[Barrier Out of Range] %s (%d %d) no acceptable place behind barrier, mob at (%d %d).\n", $char, $realMyPos->{x}, $realMyPos->{y}, $realMonsterPos->{x}, $realMonsterPos->{y}), 'ai_attack'; + warning "[Barrier Out of Range] Trying to cast flamebarrier on attack.\n"; + + my $bpos = Misc::getBarrierPos($realMyPos, $realMonsterPos, $target, 1); + if (defined $bpos) { + warning "[Barrier Out of Range] Found location $bpos->{x} $bpos->{y} to cast fire barrier (me: $realMyPos->{x} $realMyPos->{y}| mob: $realMonsterPos->{x} $realMonsterPos->{y}).\n"; + Misc::castBarrier($bpos); + } else { + my $bpos = Misc::getBarrierPos($realMyPos, $realMonsterPos, $target, 0); + if (defined $bpos) { + warning "[Barrier Out of Range] Found not optimal location $bpos->{x} $bpos->{y} to cast fire barrier (me: $realMyPos->{x} $realMyPos->{y}| mob: $realMonsterPos->{x} $realMonsterPos->{y}).\n"; + Misc::castBarrier($bpos); + } + } + # Here normally we would dequeue, but that accomplishes nothing and puts us in danger, better to just wait in place + #if (!defined $bpos) { + # warning "[Barrier Out of Range] No acceptable place to cast flamebarrier\n"; + # $target->{attack_failedLOS} = time; + # AI::dequeue while (AI::inQueue("attack")); + #} + } else { + warning "[Barrier Out of Range] Don't have wall and can't cast one right now, find other distant barriers.\n"; + my $max = $realMonsterDist + 3; + if ($max > 14) { + $max = 14; + } + my $cell = meetingPosition($char, 1, $target, $max, 0, 1); + if ($cell) { + warning TF("[Barrier Out of Range - Cant cast] %s (%d %d) moving behind distant barrier to (%d %d), mob at (%d %d).\n", $char, $realMyPos->{x}, $realMyPos->{y}, $cell->{x}, $cell->{y}, $realMonsterPos->{x}, $realMonsterPos->{y}), 'ai_attack'; + $args->{avoiding} = 1; + # TODO Check if this runFromTarget => 1 should be bellow + $char->route(undef, @{$cell}{qw(x y)}, noMapRoute => 1, avoidWalls => 0, runFromTarget => 1); + } + } + } } else { - warning TF("[Out of Range - Waiting] %s (%d %d), target %s (%d %d), distance %d, maxDistance %d, dmgFromYou %d.\n", $char, $realMyPos->{x}, $realMyPos->{y}, $target, $realMonsterPos->{x}, $realMonsterPos->{y}, $realMonsterDist, $args->{attackMethod}{maxDistance}, $target->{dmgFromYou}), 'ai_attack'; - } + $args->{ai_attack_failed_waitForAgressive_give_up}{timeout} = 6 if !$args->{ai_attack_failed_waitForAgressive_give_up}{timeout}; + $args->{ai_attack_failed_waitForAgressive_give_up}{time} = time if !$args->{ai_attack_failed_waitForAgressive_give_up}{time}; + if (timeOut($args->{ai_attack_failed_waitForAgressive_give_up})) { + delete $args->{ai_attack_failed_waitForAgressive_give_up}{time}; + message T("[Out of Range] Waited too long for target to get closer, dropping target\n"), "ai_attack"; + giveUp($args, $ID); + } else { + warning TF("[Out of Range - Waiting] %s (%d %d), target %s (%d %d), distance %d, maxDistance %d, dmgFromYou %d.\n", $char, $realMyPos->{x}, $realMyPos->{y}, $target, $realMonsterPos->{x}, $realMonsterPos->{y}, $realMonsterDist, $args->{attackMethod}{maxDistance}, $target->{dmgFromYou}), 'ai_attack'; + } + } + } elsif ( # We are out of range ($args->{attackMethod}{maxDistance} == 1 && !canReachMeleeAttack($realMyPos, $realMonsterPos)) || @@ -579,9 +727,14 @@ sub main { message TF("%s; moving to (%s, %s)\n", $msg, $best_spot->{x}, $best_spot->{y}); $char->route(undef, @{$best_spot}{qw(x y)}, noMapRoute => 1, avoidWalls => 0, LOSSubRoute => 1); } else { - warning TF("%s; no acceptable place to stand\n", $msg); - $target->{attack_failedLOS} = time; - AI::dequeue while (AI::inQueue("attack")); + # Here normally we would dequeue, but that accomplishes nothing and puts us in danger, better to just wait in place, unless we did not hit hte target yet + if ($target->{dmgFromYou} > 0) { + warning TF("%s; no acceptable place to stand, but already hit, waiting\n", $msg); + } else { + warning TF("%s; no acceptable place to stand\n", $msg); + $target->{attack_failedLOS} = time; + AI::dequeue while (AI::inQueue("attack")); + } } } elsif ( @@ -599,11 +752,99 @@ sub main { message TF("%s; moving to (%s, %s)\n", $msg, $best_spot->{x}, $best_spot->{y}); $char->route(undef, @{$best_spot}{qw(x y)}, noMapRoute => 1, avoidWalls => 0, LOSSubRoute => 1); } else { - warning TF("%s; no acceptable place to stand\n", $msg); - $target->{attack_failedLOS} = time; - AI::dequeue while (AI::inQueue("attack")); + # Here normally we would dequeue, but that accomplishes nothing and puts us in danger, better to just wait in place, unless we did not hit hte target yet + if ($target->{dmgFromYou} > 0) { + warning TF("%s; no acceptable place to stand, but already hit, waiting\n", $msg); + } else { + warning TF("%s; no acceptable place to stand\n", $msg); + $target->{attack_failedLOS} = time; + AI::dequeue while (AI::inQueue("attack")); + } } - + + } elsif ($config{"flameBarrier"} && $flameBarrier && $flameBarrier->{'needs_recast'} && $canCastFlameBarrier) { + warning "[TEST Barrier] Need to recast flamebarrier as it will expire soon.\n"; + + my $bpos = Misc::getBarrierPos($realMyPos, $realMonsterPos, $target, 1); + if (defined $bpos) { + warning "[TEST Barrier] Recast - Found location $bpos->{x} $bpos->{y} to cast fire barrier (me: $realMyPos->{x} $realMyPos->{y}| mob: $realMonsterPos->{x} $realMonsterPos->{y}).\n"; + Misc::castBarrier($bpos); + } else { + warning "[TEST Barrier] Recast on same location $bpos->{x} $bpos->{y} to cast fire barrier (me: $realMyPos->{x} $realMyPos->{y}| mob: $realMonsterPos->{x} $realMonsterPos->{y}).\n"; + Misc::castBarrier($flameBarrier->{'pos'}); + } + + } elsif ($config{"flameBarrier"} && !$flameBarrier && $flameBarrier_safeCheck && $flameBarrier_safeCheck->{'needs_recast'} && $canCastFlameBarrier) { + warning "[TEST Barrier] Need to recast flamebarrier-safe as it will expire soon.\n"; + + my $bpos = Misc::getBarrierPos($realMyPos, $realMonsterPos, $target, 1); + if (defined $bpos) { + warning "[TEST Barrier] Recast - Found location $bpos->{x} $bpos->{y} to cast fire barrier-safe (me: $realMyPos->{x} $realMyPos->{y}| mob: $realMonsterPos->{x} $realMonsterPos->{y}).\n"; + Misc::castBarrier($bpos); + } else { + warning "[TEST Barrier] Recast on same location $bpos->{x} $bpos->{y} to cast fire barrier-safe (me: $realMyPos->{x} $realMyPos->{y}| mob: $realMonsterPos->{x} $realMonsterPos->{y}).\n"; + Misc::castBarrier($flameBarrier_safeCheck->{'pos'}); + } + + } elsif ($config{"flameBarrier"} && !$flameBarrier && !$flameBarrier_safeCheck) { + + my $cell = meetingPosition($char, 1, $target, $args->{attackMethod}{maxDistance}, 0, 1);# Cannot use values > $args->{attackMethod}{maxDistance} or meetingPosition will make us move back + + if ($cell) { + warning TF("[TEST Barrier] %s (%d %d) moving behind barrier to (%d %d), mob at (%d %d).\n", $char, $realMyPos->{x}, $realMyPos->{y}, $cell->{x}, $cell->{y}, $realMonsterPos->{x}, $realMonsterPos->{y}), 'ai_attack'; + + $args->{avoiding} = 1; + $char->route(undef, @{$cell}{qw(x y)}, noMapRoute => 1, avoidWalls => 0); + + } elsif ($canCastFlameBarrier) { + warning TF("[TEST Barrier] %s (%d %d) no acceptable place behind barrier, mob at (%d %d).\n", $char, $realMyPos->{x}, $realMyPos->{y}, $realMonsterPos->{x}, $realMonsterPos->{y}), 'ai_attack'; + warning "[TEST Barrier] Trying to cast flamebarrier on attack.\n"; + + my $bpos = Misc::getBarrierPos($realMyPos, $realMonsterPos, $target, 1); + if (defined $bpos) { + warning "[TEST Barrier] Found location $bpos->{x} $bpos->{y} to cast fire barrier (me: $realMyPos->{x} $realMyPos->{y}| mob: $realMonsterPos->{x} $realMonsterPos->{y}).\n"; + Misc::castBarrier($bpos); + } else { + my $bpos = Misc::getBarrierPos($realMyPos, $realMonsterPos, $target, 0); + if (defined $bpos) { + warning "[TEST Barrier 2] Found not optimal location $bpos->{x} $bpos->{y} to cast fire barrier (me: $realMyPos->{x} $realMyPos->{y}| mob: $realMonsterPos->{x} $realMonsterPos->{y}).\n"; + Misc::castBarrier($bpos); + } + } + + # Only dequeue if we have not hit the mob yet + if (!defined $bpos && !($target->{dmgFromYou} > 0)) { + warning "[TEST Barrier] No acceptable place to cast flamebarrier and target not hit yet, dequeueing\n"; + $target->{attack_failedLOS} = time; + AI::dequeue while (AI::inQueue("attack")); + } + + } elsif ($target->{dmgFromYou} > 0 && $config{"flameBarrier_runWhenUnsafeAndCantCast"}) { + warning TF("[Barrier] %s (%d %d) Unsafe and Can't Cast, running, mob at (%d %d).\n", $char, $realMyPos->{x}, $realMyPos->{y}, $realMonsterPos->{x}, $realMonsterPos->{y}), 'ai_attack'; + + my $max = $realMonsterDist + 3; + if ($max > 14) { + $max = 14; + } + $cell = meetingPosition($char, 1, $target, $max, 0, 1); + if ($cell) { + warning TF("[Barrier Inside Range - Unsafe - Cant cast] %s (%d %d) moving behind distant barrier to (%d %d), mob at (%d %d).\n", $char, $realMyPos->{x}, $realMyPos->{y}, $cell->{x}, $cell->{y}, $realMonsterPos->{x}, $realMonsterPos->{y}), 'ai_attack'; + $args->{avoiding} = 1; + $char->route(undef, @{$cell}{qw(x y)}, noMapRoute => 1, avoidWalls => 0); + } + + if (!$cell) { + $cell = meetingPosition($char, 1, $target, $max, 1); + if ($cell) { + debug TF("[Barrier Inside Range - Unsafe - Cant cast] %s kiteing from (%d %d) to (%d %d), mob at (%d %d).\n", $char, $realMyPos->{x}, $realMyPos->{y}, $cell->{x}, $cell->{y}, $realMonsterPos->{x}, $realMonsterPos->{y}), 'ai_attack'; + $args->{avoiding} = 1; + $char->route(undef, @{$cell}{qw(x y)}, noMapRoute => 1, avoidWalls => 0); + } else { + debug TF("%s no acceptable place to kite from (%d %d), mob at (%d %d).\n", $char, $realMyPos->{x}, $realMyPos->{y}, $realMonsterPos->{x}, $realMonsterPos->{y}), 'ai_attack'; + } + } + } + } elsif ((!$config{'runFromTarget'} || $realMonsterDist >= $config{'runFromTarget_dist'}) && (!$config{'tankMode'} || !$target->{dmgFromYou})) { # Attack the target. In case of tanking, only attack if it hasn't been hit once. @@ -651,14 +892,19 @@ sub main { my $best_spot = meetingPosition($char, 1, $target, $args->{attackMethod}{maxDistance}); # Move to the closest spot - my $msg = TF("No LOS in from %s (%d, %d) to target %s (%d, %d) (distance: %d)", $char, $realMyPos->{x}, $realMyPos->{y}, $target, $realMonsterPos->{x}, $realMonsterPos->{y}, $realMonsterDist); + my $msg = TF("No LOS to cast skill from %s (%d, %d) to target %s (%d, %d) (distance: %d)", $char, $realMyPos->{x}, $realMyPos->{y}, $target, $realMonsterPos->{x}, $realMonsterPos->{y}, $realMonsterDist); if ($best_spot) { message TF("%s; moving to (%s, %s)\n", $msg, $best_spot->{x}, $best_spot->{y}); $char->route(undef, @{$best_spot}{qw(x y)}, noMapRoute => 1, avoidWalls => 0, LOSSubRoute => 1); } else { - warning TF("%s; no acceptable place to stand\n", $msg); - $target->{attack_failedLOS} = time; - AI::dequeue while (AI::inQueue("attack")); + # Here normally we would dequeue, but that accomplishes nothing and puts us in danger, better to just wait in place, unless we did not hit hit target yet + if ($target->{dmgFromYou} > 0) { + warning TF("%s; no acceptable place to stand, but already hit, waiting\n", $msg); + } else { + warning TF("%s; no acceptable place to stand\n", $msg); + $target->{attack_failedLOS} = time; + AI::dequeue while (AI::inQueue("attack")); + } } } diff --git a/src/Globals.pm b/src/Globals.pm index 00b2fbb77b..2b9dc4f238 100644 --- a/src/Globals.pm +++ b/src/Globals.pm @@ -29,7 +29,7 @@ our %EXPORT_TAGS = ( config => [qw(%arrowcraft_items %avoid @chatResponses %cities_lut %config %consoleColors %directions_lut %equipTypes_lut %equipSlot_rlut %equipSlot_lut %haircolors @headgears_lut @msgTable %items_control %items_lut %itemSlotCount_lut %itemsDesc_lut %itemTypes_lut %itemOptionHandle %itemOption_lut %jobs_lut %maps_lut %masterServers %monsters_lut %npcs_lut %packetDescriptions %portals_lut @portals_lut_missed %responses %sex_lut %shop %banking %buyer_shop %skillsDesc_lut %lookHandle %skillsArea %skillsEncore %spells_lut %emotions_lut %timeout $char %mon_control %priority %routeWeights %pickupitems %rpackets %itemSlots_lut %statusHandle %statusName %effectName %hatEffectHandle %hatEffectName %portals_los %stateHandle %ailmentHandle %mapTypeHandle %mapPropertyTypeHandle %mapPropertyInfoHandle %elements_lut %mapAlias_lut %quests_lut $Blacksmith_Blessing %itemStackLimit %title_lut %attendance_rewards)], ai => [qw(@ai_seq @ai_seq_args %ai_v %targetTimeout)], - state => [qw($accountID $cardMergeIndex @cardMergeItemsID $charID @chars @chars_old @friendsID %friends %incomingFriend $field %homunculus $itemsList @itemsID %items $monstersList @monstersID %monsters @npcsID %npcs $npcsList @playersID %players @portalsID @portalsID_old %portals %portals_old $portalsList $storeList $currentChatRoom @currentChatRoomUsers @chatRoomsID %createdChatRoom %chatRooms @skillsID $storageTitle @arrowCraftID %guild %incomingGuild @spellsID %spells @unknownPlayers @unknownNPCs $useArrowCraft %currentDeal %incomingDeal %outgoingDeal @identifyID @partyUsersID %incomingParty @petsID %pets $venderItemList $venderID $venderCID @venderListsID $buyerItemList $buyerPriceLimit @selfBuyerItemList $buyerID $buyingStoreID @buyerListsID @articles $articles %venderLists %buyerLists %monsters_old @monstersID_old %npcs_old %items_old %players_old @playersID_old @servers $sessionID $sessionID2 $accountSex $accountSex2 $map_ip $map_port $KoreStartTime $secureLoginKey $initSync $lastConfChangeTime $petsList $playersList $portalsList %elementals $elementalsList @elementalsID @playerNameCacheIDs %playerNameCache %pet $pvp $cashList $slavesList @slavesID %slaves %cashShop $skillExchangeItem $refineUI %clan %universalCatalog $mergeItemList)], + state => [qw($accountID $cardMergeIndex @cardMergeItemsID $charID @chars @chars_old @friendsID %friends %incomingFriend $field %homunculus $itemsList @itemsID %items $monstersList @monstersID %monsters @npcsID %npcs $npcsList @playersID %players @portalsID @portalsID_old %portals %portals_old $portalsList $storeList $currentChatRoom @currentChatRoomUsers @chatRoomsID %createdChatRoom %chatRooms @skillsID $storageTitle @arrowCraftID %guild %incomingGuild @spellsID %flameBarriers %spells @unknownPlayers @unknownNPCs $useArrowCraft %currentDeal %incomingDeal %outgoingDeal @identifyID @partyUsersID %incomingParty @petsID %pets $venderItemList $venderID $venderCID @venderListsID $buyerItemList $buyerPriceLimit @selfBuyerItemList $buyerID $buyingStoreID @buyerListsID @articles $articles %venderLists %buyerLists %monsters_old @monstersID_old %npcs_old %items_old %players_old @playersID_old @servers $sessionID $sessionID2 $accountSex $accountSex2 $map_ip $map_port $KoreStartTime $secureLoginKey $initSync $lastConfChangeTime $petsList $playersList $portalsList %elementals $elementalsList @elementalsID @playerNameCacheIDs %playerNameCache %pet $pvp $cashList $slavesList @slavesID %slaves %cashShop $skillExchangeItem $refineUI %clan %universalCatalog $mergeItemList)], network => [qw($remote_socket $net $messageSender $charServer $conState $conState_tries $encryptVal $ipc $bus $masterServer $lastSwitch $packetParser $clientPacketHandler $bytesSent $incomingMessages $outgoingClientMessages $enc_val1 $enc_val2 $captcha_state $captcha_image $captcha_image_content $captcha_key $captcha_size)], interface => [qw($interface)], misc => [qw($quit $reconnectCount @lastpm %lastpm @privMsgUsers %timeout_ex $shopstarted $buyershopstarted $bankingopened $dmgpsec $totalelasped $elasped $totaldmg %overallAuth %responseVars %talk $startTime_EXP $startingzeny @monsters_Killed $bExpSwitch $jExpSwitch $totalBaseExp $totalJobExp $shopEarned %itemChange $XKore_dontRedirect $monkilltime $monstarttime $startedattack $firstLoginMap $sentWelcomeMessage $versionSearch $monsterBaseExp $monsterJobExp %flags %damageTaken $logAppend @sellList $userSeed $taskManager $repairList $mailList $rodexList $rodexWrite $rodexCurrentType $auctionList $questList %achievements $achievementList $hotkeyList $devotionList $cookingList $currentCookingType $makableList %charSvrSet @deadTime $refineList $current_item_list $ignored_all %roulette $in_market @reputation_list_name @reputation_list)], @@ -453,6 +453,7 @@ our %guild; our %clan; our %incomingGuild; our @spellsID; +our %flameBarriers; our %spells; our @unknownPlayers; our @unknownNPCs; diff --git a/src/Misc.pm b/src/Misc.pm index 959494418d..ca59704451 100644 --- a/src/Misc.pm +++ b/src/Misc.pm @@ -2559,7 +2559,7 @@ sub canReachMeleeAttack { # # Returns: the position where the character should go to meet a moving monster. sub meetingPosition { - my ($actor, $actorType, $target, $attackMaxDistance, $runFromTargetActive) = @_; + my ($actor, $actorType, $target, $attackMaxDistance, $runFromTargetActive, $behindFlameBarrier, $current_flamebarrier) = @_; # Actor was going from 'pos' to 'pos_to' in the last movement my %myPos; @@ -2584,6 +2584,11 @@ sub meetingPosition { } else { ($realMyPos, undef) = calcPosFromTime(\%myPos, \%myPosTo, $mySpeed, $timeSinceActorMoved); } + + my $firePos; + if ($behindFlameBarrier) { + $firePos = getFirePos(0); + } # Target was going from 'pos' to 'pos_to' in the last movement my %targetPos; @@ -2624,13 +2629,18 @@ sub meetingPosition { # Target started moving from %targetPos to %targetPosTo and has not finished moving yet, it is currently at $realTargetPos, here we calculate every block still in its path and the time to reach them if ($target_moving) { my $steps_count = 0; - foreach my $currentStep ($targetCurrentStep..$targetTotalSteps) { + TARGETSTEP: foreach my $currentStep ($targetCurrentStep..$targetTotalSteps) { # Calculate the steps %targetPosInStep = moveAlong(\%targetPos, \%targetPosTo, $currentStep); # Calculate time to walk for target if ($steps_count == 0) { $timeForTargetToGetToStep = 0; + + } elsif ($behindFlameBarrier && exists $firePos->{$targetPosInStep{x}} && exists $firePos->{$targetPosInStep{x}}{$targetPosInStep{y}}) { + # Target cannot get to this cell because there is a flamebarrier in it + last TARGETSTEP; + } else { $timeForTargetToGetToStep = calcTime(\%targetPos, \%targetPosInStep, $targetSpeed) - $timeSinceTargetMoved; } @@ -2668,6 +2678,7 @@ sub meetingPosition { my $runFromTarget_dist; my $runFromTarget_minStep; my $runFromTarget_maxPathDistance; + my $runFromTarget_dist_BehindBarrier; # actor is char if ($actorType == 1) { @@ -2676,6 +2687,7 @@ sub meetingPosition { $runFromTarget = $config{runFromTarget}; $runFromTarget_dist = $config{runFromTarget_dist}; $runFromTarget_minStep = $config{runFromTarget_minStep}; + $runFromTarget_dist_BehindBarrier = $config{runFromTarget_dist_BehindBarrier}; $followDistanceMax = $config{followDistanceMax}; $attackCanSnipe = $config{attackCanSnipe}; if ($config{follow}) { @@ -2750,9 +2762,6 @@ sub meetingPosition { my $max_destination_dist; if ($ranged && $runFromTarget) { $min_destination_dist = $runFromTarget_dist; - if ($runFromTargetActive) { - $min_destination_dist = $runFromTarget_minStep; - } } my $max_path_dist; @@ -2779,6 +2788,7 @@ sub meetingPosition { my $best_spot; my $best_time; + my $best_flamebarrier; foreach my $possible_target_pos (@target_pos_to_check) { if ($possible_target_pos->{myDistToTargetPosInStep} >= $max_pathfinding_dist) { $max_pathfinding_dist = $possible_target_pos->{myDistToTargetPosInStep} + 1; @@ -2827,6 +2837,32 @@ sub meetingPosition { next unless ($field->checkLOS($spot, $possible_target_pos->{targetPosInStep}, $attackCanSnipe)); } } + + my $flameBarrier; + if ($behindFlameBarrier) { + $flameBarrier = check_flameBarrier($spot, $possible_target_pos->{targetPosInStep}); + next SPOT unless ($flameBarrier); + + Misc::BarrierCanFleeTo($flameBarrier); + next SPOT unless ($flameBarrier->{'can_flee_to'}); + + if ($behindFlameBarrier == 2) { + if ($current_flamebarrier->{'barrierID'} == $flameBarrier->{'barrierID'}) { + next SPOT; + } + } + + my $min_barrier_dist = $config{'flameBarrier_distBehindBarrier'}; + + for my $barrier_x (keys %{$firePos}) { + BARRIER: for my $barrier_y (keys %{$firePos->{$barrier_x}}) { + my $test_barrier = $firePos->{$barrier_x}{$barrier_y}; + next BARRIER unless ($test_barrier->{ID} eq $flameBarrier->{ID}); + # Gotta be at least $config{'flameBarrier_distBehindBarrier'} cells away from the barrier that protects us + next SPOT if (blockDistance($spot, $test_barrier->{'pos'}) < $min_barrier_dist); + } + } + } # 4. The route should not exceed at any point $max_pathfinding_dist distance from the target. my $solution = []; @@ -2845,6 +2881,9 @@ sub meetingPosition { next unless ($dist >= 0 && $dist <= $max_path_dist); my $time_actor_to_get_to_spot = calcTime($realMyPos, $spot, $mySpeed); + + ### + my $time_actor_will_have_to_wait_in_spot_for_target_to_be_at_targetPosInStep; if ($time_actor_to_get_to_spot >= $possible_target_pos->{timeForTargetToGetToStep}) { @@ -2854,19 +2893,24 @@ sub meetingPosition { } my $time_target_to_get_to_spot = calcTime($realTargetPos, $spot, $targetSpeed); - next if ($runFromTargetActive && $time_actor_to_get_to_spot > $time_target_to_get_to_spot); + next if (($runFromTargetActive || $behindFlameBarrier) && $time_actor_to_get_to_spot > $time_target_to_get_to_spot); my $sum_time = $time_actor_to_get_to_spot + $time_actor_will_have_to_wait_in_spot_for_target_to_be_at_targetPosInStep; - if (!defined($best_time) || $sum_time < $best_time) { $best_time = $sum_time; $best_spot = $spot; + if ($behindFlameBarrier) { + $best_flamebarrier = $flameBarrier; + } } } } } if ($best_spot) { + if ($behindFlameBarrier) { + $best_spot->{flamebarrier} = $best_flamebarrier; + } return $best_spot; } } @@ -3797,7 +3841,7 @@ sub canUseTeleport { if ($config{teleportAuto_item1}) { $item = $char->inventory->getByName($config{teleportAuto_item1}); $item = $char->inventory->getByNameID($config{teleportAuto_item1}) if (!($item) && $config{teleportAuto_item1} =~ /^\d{3,}$/); - } + } $item = $char->inventory->getByNameID(23280) unless $item; # Beginner's Fly Wing $item = $char->inventory->getByNameID(12323) unless $item; # Novice Fly Wing $item = $char->inventory->getByNameID(601) unless $item; # Fly Wing @@ -5205,6 +5249,333 @@ sub checkMonsterCondition { return $args{return}; } +sub castBarrier { + my ($pos) = @_; + ai_setSuspend(0); + + my $skill = new Skill(handle => 'MG_FIREWALL'); + my $lvl = $config{"flameBarrier_lvl"}; + my $maxCastTime = $config{"flameBarrier_maxCastTime"}; + my $minCastTime = $config{"flameBarrier_minCastTime"}; + + ai_skillUse( + $skill->getHandle(), + $lvl, + $maxCastTime, + $minCastTime, + $pos->{x}, + $pos->{y} + ); +} + +sub previewBarrierPos { + my ($pos, $realMyPos, $verb) = @_; + + my %vec; + my $direction; + getVector(\%vec, $pos, $realMyPos); + $direction = int(sprintf("%.0f", (360 - vectorToDegree(\%vec)) / 45)) % 8; + if ($direction == 8) { + $direction = 0; + } + + my @change_x; + my @change_y; + my @middle; + + if ($direction == 0) {# North + @change_x = (-1, 0, 1); + @change_y = ( 0, 0, 0); + @middle = ( 0, 1, 0); + + } elsif ($direction == 1) {# Northwest + @change_x = ( 1, 1 ,0, 0,-1); + @change_y = ( 1, 0, 0,-1,-1); + @middle = ( 0, 0, 1, 0, 0); + + } elsif ($direction == 2) {# West + @change_x = ( 0, 0, 0); + @change_y = (-1, 0, 1); + @middle = ( 0, 1, 0); + + } elsif ($direction == 3) {# Southwest + @change_x = (-1,-1, 0, 0, 1); + @change_y = ( 1, 0, 0,-1,-1); + @middle = ( 0, 0, 1, 0, 0); + + } elsif ($direction == 4) {# South + @change_x = (-1, 0, 1); + @change_y = ( 0, 0, 0); + @middle = ( 0, 1, 0); + + } elsif ($direction == 5) {# Southeast + @change_x = ( 1, 1 ,0, 0,-1); + @change_y = ( 1, 0, 0,-1,-1); + @middle = ( 0, 0, 1, 0, 0); + + } elsif ($direction == 6) {# East + @change_x = ( 0, 0, 0); + @change_y = (-1, 0, 1); + @middle = ( 0, 1, 0); + + } elsif ($direction == 7) {# Northeast + @change_x = (-1,-1, 0, 0, 1); + @change_y = ( 1, 0, 0,-1,-1); + @middle = ( 0, 0, 1, 0, 0); + } + + my %positions; + foreach my $index (0..$#change_x) { + my $posx = $pos->{x} + $change_x[$index]; + my $posy = $pos->{y} + $change_y[$index]; + next unless ($field->isWalkable($posx, $posy)); + my $mid = $middle[$index]; + $positions{$posx}{$posy} = $mid; + warning "[check_flameBarrier] Preview barrier at $posx $posy\n" if ($verb == 1); + } + return \%positions; +} + +sub getBarrierPos { + my ($me, $mob, $target, $optimal) = @_; + + my @cells; + my $dist = blockDistance($me, $mob); + my @dist_array = (0..$dist); + @dist_array = reverse @dist_array; + if ($optimal) { + pop @dist_array if (@dist_array > 1); + shift @dist_array if (@dist_array > 1); + shift @dist_array if (@dist_array > 1); + if (@dist_array > 1) { + my $size = $#dist_array; + my $middle = ceil($size/2); + my $low_priority = shift @dist_array; + splice @dist_array, $middle, 0, $low_priority; + } + } + + foreach my $c_dist (@dist_array) { + my %bpos = moveAlong($mob, $me, $c_dist); + push(@cells, \%bpos); + } + + DIST: foreach my $cell (@cells) { + my %bpos; + $bpos{x} = $cell->{x}; + $bpos{y} = $cell->{y}; + + next DIST unless ($field->isWalkable($bpos{x}, $bpos{y})); + + my $barrierPositions = previewBarrierPos($cell, $me, 0); + + MOB: for my $c_mob (@$monstersList) { + next MOB if ($c_mob->{ID} eq $target->{ID}); + next MOB if ($c_mob->{dmgFromYou} > 0); + next MOB if ($c_mob->{dmgToYou} > 0); + next MOB if ($c_mob->{missedYou} > 0); + my $mobpos = calcPosition($c_mob); + next DIST if (exists $barrierPositions->{$mobpos->{x}} && exists $barrierPositions->{$mobpos->{x}}{$mobpos->{y}}); + } + return { x => $bpos{x}, y => $bpos{y} }; + } + return undef; +} + +sub getFirePos { + my ($mustBeMiddle) = @_; + my %firePos; + for my $ID (@spellsID) { + my $spell = $spells{$ID}; + next unless $spell; + next unless ($spell->{type} == 127); + next unless ($spell->{sourceID} eq $accountID); + next if ($mustBeMiddle && !$spell->{'middle'}); + + if (exists $firePos{$spell->{pos}{x}} && exists $firePos{$spell->{pos}{x}}{$spell->{pos}{y}}) { + if ($spell->{'time'} > $firePos{$spell->{pos}{x}}{$spell->{pos}{y}}{'time'}) { + $firePos{$spell->{pos}{x}}{$spell->{pos}{y}} = $spell; + } + } else { + $firePos{$spell->{pos}{x}}{$spell->{pos}{y}} = $spell; + } + + } + return \%firePos; +} + +sub BarrierDefineNeedRecast { + my ($flameBarrier) = @_; + if (timeOut($flameBarrier->{'time'},($flameBarrier->{'duration'} - $config{"flameBarrier_timeLeft_recastWhenLessThan"}))) { + $flameBarrier->{'needs_recast'} = 1; + } elsif ($flameBarrier->{'hits_left'} < $config{"flameBarrier_hitsLeft_recastWhenLessThan"}) { + $flameBarrier->{'needs_recast'} = 1; + } else { + $flameBarrier->{'needs_recast'} = 0; + } +} + +sub BarrierCanFleeTo { + my ($flameBarrier) = @_; + if (timeOut($flameBarrier->{'time'},($flameBarrier->{'duration'} - $config{"flameBarrier_timeLeft_notFleeToWhenLessThan"}))) { + $flameBarrier->{'can_flee_to'} = 0; + } elsif ($flameBarrier->{'hits_left'} < $config{"flameBarrier_hitsLeft_notFleeToWhenLessThan"}) { + $flameBarrier->{'can_flee_to'} = 0; + } else { + $flameBarrier->{'can_flee_to'} = 1; + } +} + +sub getClosestAdjacentCell { + my ($me, $mob) = @_; + my @blocks = calcRectArea($me->{x}, $me->{y}, 1, $field); + + my $best_block; + my $shortest_dist; + + foreach my $block (@blocks) { + next if (!$field->isWalkable($block->{x}, $block->{y})); + my $dist = adjustedBlockDistance($mob, $block); + if (!defined $shortest_dist || $shortest_dist > $dist) { + $shortest_dist = $dist; + $best_block = $block; + } + } + return $best_block; +} + +sub check_flameBarrier { + my ($me, $mob) = @_; + + my $mustBeMiddle = 0; + if ($config{"flameBarrier_mustBeMiddle"}) { + $mustBeMiddle = 1; + } + + my $firePos = getFirePos($mustBeMiddle); + + my $mob_attack_cell = getClosestAdjacentCell($me, $mob); + #warning "[check_flameBarrier] from $me->{x} $me->{y} | to $mob->{x} $mob->{y} | mob_attack_cell $mob_attack_cell->{x} $mob_attack_cell->{y}.\n"; + + #warning Data::Dumper::Dumper \%firePos; + #warning "[check_flameBarrier] from $me->{x} $me->{y} | to $mob->{x} $mob->{y}.\n"; + + # Simulate tracing a line to the location (Bresenham's algorithm) + + my $current_spell; + + my @cells; + my $dist = blockDistance($mob_attack_cell, $mob); + my @dist_array = (0..$dist); + @dist_array = reverse @dist_array; + shift @dist_array; + shift @dist_array; + + foreach my $c_dist (@dist_array) { + my %bpos = moveAlong($mob, $mob_attack_cell, $c_dist); + push(@cells, \%bpos); + } + + foreach my $cells (@cells) { + if (exists $firePos->{$cells->{x}} && exists $firePos->{$cells->{x}}{$cells->{y}}) { + if (!defined $current_spell || $firePos->{$cells->{x}}{$cells->{y}}{'time'} > $current_spell->{'time'}) { + $current_spell = $firePos->{$cells->{x}}{$cells->{y}}; + } + } + } + + if (defined $current_spell) { + #warning "[check_flameBarrier] cell $current_spell->{pos}{x} $current_spell->{pos}{y} is between ($me->{x} $me->{y}) and ($mob->{x} $mob->{y}) and has my flame barrier.\n"; + return $current_spell; + } else { + return 0; + } +} + +sub Barrier_skill_use_location { + my ($x, $y) = @_; + + my $pos; + $pos->{x} = $x; + $pos->{y} = $y; + my $realMyPos = calcPosition($char); + delete $flameBarriers{sent} if (exists $flameBarriers{sent}); + my $preview = previewBarrierPos($pos, $realMyPos, 1); + my $total = 0; + foreach my $x (keys %{$preview}) { + foreach my $y (keys %{$preview->{$x}}) { + $total++; + } + } + + $flameBarriers{sent}{x} = $x; + $flameBarriers{sent}{y} = $y; + $flameBarriers{sent}{time} = time; + $flameBarriers{sent}{got_first} = 0; + $flameBarriers{sent}{total} = $total; + $flameBarriers{sent}{count} = 0; +} + +sub Barrier_area_spell_multiple3 { + my ($ID) = @_; + + $spells{$ID}{'duration'} = $spells{$ID}{'lvl'} + 4; + $spells{$ID}{'disappear_time'} = $spells{$ID}{'time'} + $spells{$ID}{'duration'}; + $spells{$ID}{'hits_left'} = $spells{$ID}{'lvl'} + 4; + + $flameBarriers{sent}{count}++; + $spells{$ID}{'my_flamebarrier'} = 1; + + if (!$flameBarriers{sent}{got_first} && $flameBarriers{sent}{count} == 1) { + $flameBarriers{sent}{got_first} = $spells{$ID}{'unpackedID'}; + } + + $spells{$ID}{'barrierID'} = $flameBarriers{sent}{got_first}; + + # Middle + if ($flameBarriers{sent}{x} == $spells{$ID}{'pos'}{'x'} && $flameBarriers{sent}{y} == $spells{$ID}{'pos'}{'y'}) { + $spells{$ID}{'middle'} = 1; + } else { + $spells{$ID}{'middle'} = 0; + } + + $flameBarriers{exist}{$flameBarriers{sent}{got_first}}{$spells{$ID}{'unpackedID'}} = 1; + + if ($flameBarriers{sent}{count} == $flameBarriers{sent}{total}) { + delete $flameBarriers{sent}; + } +} + +sub Barrier_area_spell_disappears { + my ($unpackedID, $ID) = @_; + my $spell = $spells{$ID}; + if (exists $spell->{'my_flamebarrier'} && exists $flameBarriers{exist}{$spell->{'barrierID'}} && exists $flameBarriers{exist}{$spell->{'barrierID'}}{$unpackedID}) { + delete $flameBarriers{exist}{$spell->{'barrierID'}}{$unpackedID}; + + if (scalar keys %{$flameBarriers{exist}{$spell->{'barrierID'}}} == 0) { + delete $flameBarriers{exist}{$spell->{'barrierID'}}; + } + } +} + +sub Barrier_skill_use { + my ($pos) = @_; + return unless (exists $flameBarriers{exist} && scalar keys %{$flameBarriers{exist}} > 0); + + for my $ID (@spellsID) { + my $spell = $spells{$ID}; + next unless $spell; + next unless (exists $spell->{'my_flamebarrier'}); + next unless (exists $spell->{'hits_left'} && $spell->{'hits_left'} > 0); + #next if ($mustBeMiddle && !$spell->{'middle'}); + + if ($pos->{x} == $spell->{pos}{x} && $pos->{y} == $spell->{pos}{y}) { + $spell->{'hits_left'} -= 1; + warning "[FlameBarrier] Barrier at cell $pos->{x} $pos->{y} lost 1 HP point, remaining $spell->{'hits_left'}.\n"; + } + } +} + ## # makeShop() # diff --git a/src/Network/Receive.pm b/src/Network/Receive.pm index 418af69f2c..d388e0111d 100644 --- a/src/Network/Receive.pm +++ b/src/Network/Receive.pm @@ -4359,6 +4359,7 @@ sub area_spell_multiple3 { } $spells{$ID}{'ID'} = $ID; + $spells{$ID}{'unpackedID'} = unpack('V',$ID); $spells{$ID}{'sourceID'} = $sourceID; $spells{$ID}{'pos'}{'x'} = $x; $spells{$ID}{'pos'}{'y'} = $y; @@ -4369,10 +4370,13 @@ sub area_spell_multiple3 { $spells{$ID}{'range'} = $range; $spells{$ID}{'isVisible'} = $isVisible; $spells{$ID}{'lvl'} = $lvl; + $spells{$ID}{'time'} = time; if ($type == 0x81) { message TF("%s opened Warp Portal on (%d, %d)\n", getActorName($sourceID), $x, $y), "skill"; + } elsif ($type == 127 && $sourceID eq $accountID && exists $flameBarriers{sent}) { + Misc::Barrier_area_spell_multiple3($ID); } - debug "Area effect ".getSpellName($type)." ($binID) from ".getActorName($sourceID)." appeared on ($x, $y), isVisible = $isVisible, range = $range, lvl = $lvl\n", "skill", 2; + debug "Area effect ".getSpellName($type)." (type $type) (ID ".$spells{$ID}{'unpackedID'}.") ($binID) from ".getActorName($sourceID)." appeared on ($x, $y), isVisible = $isVisible, range = $range, lvl = $lvl\n", "skill", 2; } Plugins::callHook('packet_areaSpell', { @@ -10099,8 +10103,14 @@ sub area_spell_disappears { my ($self, $args) = @_; # The area effect spell with ID dissappears my $ID = $args->{ID}; + my $unpackedID = unpack('V',$ID); my $spell = $spells{$ID}; debug "Area effect ".getSpellName($spell->{type})." ($spell->{binID}) from ".getActorName($spell->{sourceID})." disappeared from ($spell->{pos}{x}, $spell->{pos}{y})\n", "skill", 2; + + if (exists $spell->{'barrierID'}) { + Misc::Barrier_area_spell_disappears($unpackedID, $ID); + } + delete $spells{$ID}; binRemove(\@spellsID, $ID); } diff --git a/src/Network/Receive/ServerType0.pm b/src/Network/Receive/ServerType0.pm index 4da82adfb0..678d49af51 100644 --- a/src/Network/Receive/ServerType0.pm +++ b/src/Network/Receive/ServerType0.pm @@ -1326,6 +1326,10 @@ sub skill_use { }); message $disp, $domain, 1; + if ($args->{skillID} == 18 && $args->{sourceID} eq $accountID) { + Misc::Barrier_skill_use($target->{pos}); + } + if ($args->{targetID} eq $accountID && $args->{damage} > 0) { $damageTaken{$source->{name}}{$skill->getName()} += $args->{damage}; } @@ -1358,6 +1362,10 @@ sub skill_use_location { my $domain = ($sourceID eq $accountID) ? "selfSkill" : "skill"; message $disp, $domain; + if ($skillID == 18 && $sourceID eq $accountID) { + Misc::Barrier_skill_use_location($x, $y); + } + #EFST_MAGICPOWER OVERRIDE if ($args->{sourceID} eq $accountID && $char->statusActive('EFST_MAGICPOWER') && $args->{skillID} != 366) { $char->setStatus("EFST_MAGICPOWER", 0); diff --git a/src/Network/Receive/kRO/Sakexe_0.pm b/src/Network/Receive/kRO/Sakexe_0.pm index 629adb08ce..ab7c40ac56 100644 --- a/src/Network/Receive/kRO/Sakexe_0.pm +++ b/src/Network/Receive/kRO/Sakexe_0.pm @@ -1313,6 +1313,10 @@ sub skill_use { }); message $disp, $domain, 1; + if ($args->{skillID} == 18 && $args->{sourceID} eq $accountID) { + Misc::Barrier_skill_use($target->{pos}); + } + if ($args->{targetID} eq $accountID && $args->{damage} > 0) { $damageTaken{$source->{name}}{$skill->getName()} += $args->{damage}; } @@ -1342,6 +1346,10 @@ sub skill_use_location { my $domain = ($sourceID eq $accountID) ? "selfSkill" : "skill"; message $disp, $domain; + if ($skillID == 18 && $sourceID eq $accountID) { + Misc::Barrier_skill_use_location($x, $y); + } + Plugins::callHook('packet_skilluse', { 'skillID' => $skillID, 'sourceID' => $sourceID, diff --git a/src/functions.pl b/src/functions.pl index 36c2d6f371..ec39dcc4a8 100644 --- a/src/functions.pl +++ b/src/functions.pl @@ -724,6 +724,7 @@ sub initMapChangeVars { undef @itemsID; undef @identifyID; undef @spellsID; + undef %flameBarriers; undef @arrowCraftID; undef %items; undef %spells;