Code:
/**
* This file was modified by [Only registered and activated users can see links. Click Here To Register...]
* Check the programming section for updates and further scripts
* Last Update: 10:52 26.03.2011
*/
const NTA_DAMAGE_NONE = 0;
const NTA_DAMAGE_PHYSICAL = 1;
const NTA_DAMAGE_MAGIC = 2;
const NTA_DAMAGE_FIRE = 3;
const NTA_DAMAGE_LIGHTNING = 4;
const NTA_DAMAGE_COLD = 5;
const NTA_DAMAGE_POISON = 6;
var _MWA_Attack_Slot = -1;
var _MWA_Merc_Weapon_Type = -1;
var _MWA_Corpse_Damage_Radius = -1.0;
var _MWA_Minion_Counts = new Array(-1, -1, -1);
var _NTA_SkillHand = new Array(10);
var _NTA_SkillDamage = new Array(10);
var _NTA_SkillRange = new Array(10);
var _MWA_SkipList = new Array();
var _MWA_Attack_Time = new Array();
var _MWA_Traps;
function NTA_Initialize()
{
if(NTConfig_AttackSkill[1] == 0 || NTConfig_AttackSkill[3] == 0)
NTA_DetectAttackPattern();
for(var i = 0; i < NTConfig_AttackSkill.length; i++)
{
if(NTConfig_AttackSkill[i] > 0)
{
_NTA_SkillHand[i] = GetBaseStat("skills.txt", NTConfig_AttackSkill[i], 166) ? 2 : NTC_HAND_RIGHT;
_NTA_SkillDamage[i] = NTA_GetDamageType(NTConfig_AttackSkill[i]);
switch(NTConfig_AttackSkill[i])
{
case MWS_TORNADO:
_NTA_SkillRange[i] = MWConfig_TornadoRange;
break;
case MWS_TWISTER:
_NTA_SkillRange[i] = MWConfig_TwisterRange;
break;
case MWS_FROST_NOVA: //Frost Nova
case MWS_NOVA: // Nova
case MWS_HOLY_BOLT: // Holy Bolt
_NTA_SkillRange[i] = 5;
break;
case MWS_FIRE_BLAST:
case MWS_SHOCK_WEB:
case MWS_FROZEN_ORB: // Frozen Orb
_NTA_SkillRange[i] = 15;
break;
case MWS_CORPSE_EXPLOSION: // Corpse Explosion
_NTA_SkillRange[i] = 25;
break;
case MWS_SMITE: // Smite
case MWS_ZEAL: // Zeal
_NTA_SkillHand[i] = NTC_HAND_LEFT; // Make sure those skills are casted without shift being hold
case MWS_BLESSED_HAMMER: //Blessed Hammer
case MWS_BERSERK: //Berserk
case MWS_WAR_CRY: // War Cry
_NTA_SkillRange[i] = 3;
break;
case MWS_WHIRLWIND: //Whirlwind
_NTA_SkillRange[i] = 8;
break;
case MWS_INFERNO:
_NTA_SkillRange[i] = 10;
break;
// Range definition for traps: [0]: range to place a trap [1]: range of the trap itself
case MWS_CHARGED_BOLT_SENTRY:
case MWS_WAKE_OF_FIRE:
case MWS_WAKE_OF_INFERNO:
_NTA_SkillRange[i] = [15, 10];
break;
case MWS_LIGHTNING_SENTRY:
case MWS_DEATH_SENTRY:
_NTA_SkillRange[i] = [15, 20];
break;
default:
_NTA_SkillRange[i] = 20;
break;
}
}
}
}
function NTA_KillMonster(search)
{
var _target, _attackcount, _attacksFailed;
if(NTConfig_AttackSkill[1] < 1)
return false;
_target = NTC_FindUnit(NTC_UNIT_MONSTER, search, 5);
if(!_target)
return false;
if(_target.IsAttackable())
{
_attackcount = 0;
_attacksFailed = 0;
if(MWConfig_ClearBossPosition && me.diff > 0 && MWA_FindNearbyMonsters(10, _target))
NTA_ClearPosition(15, false, 0, false, false);
while(_attackcount < 350 && NTA_IsValidMonster(_target))
{
if(MWConfig_ShowOverheadStatus)
MWA_PrintAttackStatus(1, _target);
if(NTA_Attack(_target, (_attackcount % 30) == 0) < 2)
_attacksFailed++;
_attackcount++;
if(_attacksFailed > 2)
break;
}
}
if(MWConfig_PickItemsInstantly && (_target.hp <= 0 || _target.mode == 0 || _target.mode == 12))
NTSI_PickItems();
return (_target.hp <= 0 || _target.mode == 0 || _target.mode == 12);
}
function NTA_ClearPosition(range, pickitem, safelevel, openchests, usefinditem, spectype)
{
var _orgx, _orgy;
var _spectype = [0x0A, 0x0E, 0x01];
var _skiplist;
var _attackcount = 0;
var _target;
var _distance, _mingid, _mindistance;
var _mingidPrio, _mindistPrio;
var _result;
var _outputType;
if(NTConfig_AttackSkill[1] < 1 || NTConfig_AttackSkill[3] < 1)
return false;
switch(arguments.length)
{
case 0:
range = 20;
case 1:
pickitem = false;
case 2:
safelevel = 2;
case 3:
if(NTConfig_CheckSelfSafe < 0x01 && NTConfig_CheckMercSafe < 0x01)
safelevel = 0;
openchests = true;
case 4:
usefinditem = true;
case 5:
break;
default:
if(spectype > 0x01)
_spectype = [spectype];
}
if(_spectype.length == 3 && (me.classid == NTC_CHAR_CLASS_NECROMANCER || me.classid == NTC_CHAR_CLASS_SORCERESS && MWConfig_KeepDistanceToMonsters))
_spectype = [0x01];
_orgx = me.x;
_orgy = me.y;
for(var i = 0; i < _spectype.length; i++)
{
_skiplist = new Array();
while(_attackcount < (i+1)*100)
{
_mindistance = 1E6;
_mindistPrio = 1E6;
_target = NTC_FindUnit(NTC_UNIT_MONSTER);
if(_target)
{
do
{
if(_skiplist.indexOf(_target.gid) < 0)
{
if(_target.IsAttackable() && (_target.spectype & _spectype[i]))
{
if(GetDistance(_orgx, _orgy, _target.x, _target.y) <= range && NTA_IsValidMonster(_target))
{
_distance = GetDistance(me, _target);
if(_distance < _mindistance)
{
_mingid = _target.gid;
_mindistance = _distance;
}
if(MWA_IsPriorityTarget(_target))
{
if(_distance < _mindistPrio)
{
_mingidPrio = _target.gid;
_mindistPrio = _distance;
}
}
}
}
else
_skiplist.push(_target.gid);
}
} while(_target.GetNext());
}
if(_mindistance < 1E6)
{
if(_mindistPrio < 1E6)
{
_target = NTC_FindUnit(NTC_UNIT_MONSTER, _mingidPrio, 1);
_outputType = 1;
}
else
{
_target = NTC_FindUnit(NTC_UNIT_MONSTER, _mingid, 1);
_outputType = 0;
}
if(_target)
{
if(MWConfig_ShowOverheadStatus)
MWA_PrintAttackStatus(_outputType, _target);
_result = NTA_Attack(_target, (_attackcount % 30) == 0);
if(MWConfig_ShowOverheadStatus)
MWA_PrintAttackStatus(_outputType, _target);
switch(_result)
{
case 1:
_skiplist.push(_mingid);
break;
case 2:
case 3:
if(MWConfig_PickItemsInstantly && (_target.hp <= 0 || _target.mode == 0 || _target.mode == 12))
NTSI_PickItems();
_attackcount++;
break;
default:
return false;
}
}
}
else
break;
}
}
if(_attackcount > 2)
{
switch(me.classid)
{
case NTC_CHAR_CLASS_PALADIN:
if(parseInt(me.hp * 100 / me.hpmax) < NTConfig_UseRedemptionHP || parseInt(me.mp * 100 / me.mpmax) < NTConfig_UseRedemptionMP)
{
if(NTC_PutSkill(MWS_REDEMPTION, NTC_HAND_RIGHT))
NTC_PingDelay(1000);
}
break;
case NTC_CHAR_CLASS_BARBARIAN:
if(usefinditem && MWConfig_UseFindItem)
MWL_FindItem(MWConfig_FindItemRange);
break;
case NTC_CHAR_CLASS_NECROMANCER:
MWA_RaiseMinions();
break;
}
}
if(pickitem && _attackcount > 0)
NTSI_PickItems();
if(MWConfig_OpenAllNearbyChests && openchests)
MWL_OpenNearbyChests(MWConfig_OpenChestsRange);
if(MWConfig_ActivateNearbyShrines)
MWL_ActivateNearbyShrines();
switch(safelevel)
{
case 1:
return NTTMGR_CheckSafe(0x00, NTConfig_CheckMercSafe&0x01);
case 2:
return NTTMGR_CheckSafe(NTConfig_CheckSelfSafe, NTConfig_CheckMercSafe);
}
if(MWConfig_IdentAfterPickup)
MWL_IDItemsAfterPickup();
return true;
}
function NTA_ClearLevel(pickitem, safelevel, spectype)
{
var _room, _rooms;
var _distance, _minindex, _mindistance;
_room = GetRoom();
if(!_room)
return false;
switch(arguments.length)
{
case 0:
pickitem = true;
case 1:
safelevel = 2;
case 2:
if(NTConfig_CheckSelfSafe < 0x01 && NTConfig_CheckMercSafe < 0x01)
safelevel = 0;
default:
spectype = 0x01;
}
_rooms = new Array();
do
{
_rooms.push([parseInt(_room.x*5 + _room.xsize*5/2), parseInt(_room.y*5 + _room.ysize*5/2)]);
} while(_room.GetNext());
while(_rooms.length > 0)
{
_mindistance = 100000;
for(var i = 0; i < _rooms.length; i++)
{
_distance = GetDistance(me.x, me.y, _rooms[i][0], _rooms[i][1]);
if(_distance < _mindistance)
{
_minindex = i;
_mindistance = _distance;
}
}
if(NTM_MoveTo(me.areaid, _rooms[_minindex][0], _rooms[_minindex][1], 1))
{
if(!NTA_ClearRoom(pickitem, safelevel, spectype))
return false;
NTP_DoPrecast(false);
}
_rooms.splice(_minindex, 1);
}
return true;
}
function NTA_ClearRoom(pickitem, safelevel, spectype)
{
var _room;
var _spectype = [0x0A, 0x0E, 0x01];
var _skiplist;
var _attackcount = 0;
var _target;
var _distance, _mingid, _mindistance;
var _mingidPrio, _mindistPrio;
var _result;
var _outputType;
if(NTConfig_AttackSkill[1] < 1 || NTConfig_AttackSkill[3] < 1)
return false;
_room = me.GetRoom();
if(!_room)
return false;
switch(arguments.length)
{
case 0:
pickitem = false;
case 1:
safelevel = 0;
case 2:
if(NTConfig_CheckSelfSafe < 0x01 && NTConfig_CheckMercSafe < 0x01)
safelevel = 0;
default:
if(spectype > 0x01)
_spectype = [spectype];
}
if(_spectype.length == 3 && (me.classid == NTC_CHAR_CLASS_NECROMANCER || me.classid == NTC_CHAR_CLASS_SORCERESS && MWConfig_KeepDistanceToMonsters))
_spectype = [0x01];
for(var i = 0; i < _spectype.length; i++)
{
_skiplist = new Array();
while(_attackcount < (i+1)*100)
{
_mindistance = 1E6;
_mindistPrio = 1E6;
_target = NTC_FindUnit(NTC_UNIT_MONSTER);
if(_target)
{
do
{
if(_skiplist.indexOf(_target.gid) < 0)
{
if(_target.IsAttackable() && (_target.spectype & _spectype[i]))
{
if(_room.UnitInRoom(_target) && NTA_IsValidMonster(_target))
{
_distance = GetDistance(me, _target);
if(_distance < _mindistance)
{
_mingid = _target.gid;
_mindistance = _distance;
}
if(MWA_IsPriorityTarget(_target))
{
if(_distance < _mindistPrio)
{
_mingidPrio = _target.gid;
_mindistPrio = _distance;
}
}
}
}
else
_skiplist.push(_target.gid);
}
} while(_target.GetNext());
}
if(_mindistance < 1E6)
{
if(_mindistPrio < 1E6)
{
_target = NTC_FindUnit(NTC_UNIT_MONSTER, _mingidPrio, 1);
_outputType = 1;
}
else
{
_target = NTC_FindUnit(NTC_UNIT_MONSTER, _mingid, 1);
_outputType = 0;
}
if(_target)
{
if(MWConfig_ShowOverheadStatus)
MWA_PrintAttackStatus(_outputType, _target);
_result = NTA_Attack(_target, (_attackcount%30) == 0);
if(MWConfig_ShowOverheadStatus)
MWA_PrintAttackStatus(_outputType, _target);
switch(_result)
{
case 1:
_skiplist.push(_mingid);
break;
case 2:
case 3:
if(MWConfig_PickItemsInstantly && (_target.hp <= 0 || _target.mode == 0 || _target.mode == 12))
NTSI_PickItems();
_attackcount++;
break;
default:
return false;
}
}
}
else
break;
}
}
if(_attackcount > 2)
{
switch(me.classid)
{
case NTC_CHAR_CLASS_PALADIN:
if(parseInt(me.hp * 100 / me.hpmax) < NTConfig_UseRedemptionHP || parseInt(me.mp * 100 / me.mpmax) < NTConfig_UseRedemptionMP)
{
if(NTC_PutSkill(MWS_REDEMPTION, NTC_HAND_RIGHT))
NTC_PingDelay(1000);
}
break;
case NTC_CHAR_CLASS_BARBARIAN:
if(MWConfig_UseFindItem)
MWL_FindItem(MWConfig_FindItemRange);
break;
case NTC_CHAR_CLASS_NECROMANCER:
MWA_RaiseMinions();
break;
}
}
if(pickitem && _attackcount > 0)
NTSI_PickItems();
if(MWConfig_OpenAllNearbyChests)
MWL_OpenNearbyChests(_room);
if(MWConfig_ActivateNearbyShrines)
MWL_ActivateNearbyShrines();
switch(safelevel)
{
case 1:
return NTTMGR_CheckSafe(0x00, NTConfig_CheckMercSafe&0x01);
case 2:
return NTTMGR_CheckSafe(NTConfig_CheckSelfSafe, NTConfig_CheckMercSafe);
}
return true;
}
function NTA_IsValidMonster(monster)
{
var _classid;
if(monster.hp <= 0 && (monster.mode == 0 || monster.mode == 12 || monster.mode == 14))
return false;
_classid = monster.classid;
if(((_classid >= 110 && _classid <= 113) || _classid == 608) && monster.mode == 8) // ignore flying scavengers
return false;
if(_classid == 68 && monster.mode == 14) // ignore burrowing maggots
return false;
if(_classid >= 258 && _classid <= 263) // ignore submerged WaterWatchers
return false;
if(monster.GetState(53) || monster.GetState(96)) // Conversion, Revive
return false;
if(!CheckCollision(me, monster, 0)) // Invalid map location
return false;
return true;
}
function NTA_GetDamageType(skillid, target, skillindex)
{
if(target && MWA_IsUndead(target))
{
if(skillid == MWS_HOLY_BOLT || me.GetState(47) || !isNaN(skillindex) && _NTA_SkillDamage[skillindex] == NTA_DAMAGE_PHYSICAL && NTConfig_AttackSkill[skillindex + 1] == MWS_SANCTUARY)
return NTA_DAMAGE_NONE;
}
if(skillid == MWS_CORPSE_EXPLOSION) // Corpse Explosion
return NTA_DAMAGE_PHYSICAL;
if(skillid == MWS_BLESSED_HAMMER) // Blessed Hammer
return NTA_DAMAGE_MAGIC;
switch(GetBaseStat("skills.txt", skillid, 233))
{
case "cold":
return NTA_DAMAGE_COLD;
case "fire":
return NTA_DAMAGE_FIRE;
case "ltng":
return NTA_DAMAGE_LIGHTNING;
case "mag":
return NTA_DAMAGE_MAGIC;
case "pois":
return NTA_DAMAGE_POISON;
case "stun":
return NTA_DAMAGE_NONE;
default:
if(GetBaseStat("skills.txt", skillid, 178) || GetBaseStat("skills.txt", skillid, 182)) // aura or passive
return NTA_DAMAGE_NONE;
}
return NTA_DAMAGE_PHYSICAL;
}
function NTA_GetResistance(enemy, type)
{
switch(type)
{
case NTA_DAMAGE_PHYSICAL:
if(MWA_IsUndead(enemy) && me.GetState(47))
break;
return enemy.GetStat(36);
case NTA_DAMAGE_MAGIC:
return enemy.GetStat(37);
case NTA_DAMAGE_FIRE:
return enemy.GetStat(39);
case NTA_DAMAGE_LIGHTNING:
return enemy.GetStat(41);
case NTA_DAMAGE_COLD:
return enemy.GetStat(43);
case NTA_DAMAGE_POISON:
return enemy.GetStat(45);
}
return 0;
}
function NTA_DetectAttackPattern()
{
switch(me.classid)
{
case NTC_CHAR_CLASS_AMAZON:
return NTA_AmazonAttackPatternInt();
case NTC_CHAR_CLASS_SORCERESS:
return NTA_SorceressAttackPatternInt();
case NTC_CHAR_CLASS_NECROMANCER:
return NTA_NecromancerAttackPatternInt();
case NTC_CHAR_CLASS_PALADIN:
return NTA_PaladinAttackPatternInt();
case NTC_CHAR_CLASS_BARBARIAN:
return NTA_BarbarianAttackPatternInt();
case NTC_CHAR_CLASS_DRUID:
return NTA_DruidAttackPatternInt();
case NTC_CHAR_CLASS_ASSASSIN:
return NTA_AssassinAttackPatternInt();
}
return false;
}
// Return value : 0 = Unrecoverable process, 1 = Unavailable attack, 2 = Onetime fail, 3 = Success
function NTA_Attack(target, firstorder)
{
switch(me.classid)
{
case NTC_CHAR_CLASS_AMAZON:
return NTA_AmazonAttackInt(target, firstorder);
case NTC_CHAR_CLASS_SORCERESS:
return NTA_SorceressAttackInt(target, firstorder);
case NTC_CHAR_CLASS_NECROMANCER:
return NTA_NecromancerAttackInt(target, firstorder);
case NTC_CHAR_CLASS_PALADIN:
return NTA_PaladinAttackInt(target, firstorder);
case NTC_CHAR_CLASS_BARBARIAN:
return NTA_BarbarianAttackInt(target, firstorder);
case NTC_CHAR_CLASS_DRUID:
return NTA_DruidAttackInt(target, firstorder);
case NTC_CHAR_CLASS_ASSASSIN:
return NTA_AssassinAttackInt(target, firstorder);
}
return 0;
}
// Internal function
function NTA_AmazonAttackPatternInt()
{
return false;
}
function NTA_AmazonAttackInt(target, firstorder)
{
return 1;
}
function NTA_AmazonCastSkillInt(index, target)
{
return false;
}
function NTA_SorceressAttackPatternInt()
{
var _maxindex, _maxskill;
var _avgskilllevel = new Array();
_avgskilllevel[0] = parseInt((me.GetSkill(59, false)+me.GetSkill(39, false)+me.GetSkill(45, false)+me.GetSkill(55, false))/4);
_avgskilllevel[1] = parseInt((me.GetSkill(53, false)+me.GetSkill(38, false)+me.GetSkill(48, false)+me.GetSkill(49, false))/4);
_avgskilllevel[2] = parseInt((me.GetSkill(47, false)+me.GetSkill(36, false)+me.GetSkill(56, false)+me.GetSkill(64, false))/4);
_avgskilllevel[3] = parseInt((me.GetSkill(47, false)+me.GetSkill(36, false)+me.GetSkill(56, false))/3);
_maxindex = -1;
_maxskill = 0;
for(var i = 0; i < _avgskilllevel.length; i++)
{
if(_avgskilllevel[i] > _maxskill)
{
_maxindex = i;
_maxskill = _avgskilllevel[i];
}
}
switch(_maxindex)
{
case 0: // Blizzard + Glacial Spike
NTConfig_AttackSkill[1] = 59;
NTConfig_AttackSkill[2] = 55;
NTConfig_AttackSkill[3] = 59;
NTConfig_AttackSkill[4] = 55;
break;
case 1: // Chain Lightning + Lightning
NTConfig_AttackSkill[1] = 49;
NTConfig_AttackSkill[3] = 53;
break;
case 2: // Fire Ball + Frozen Orb
NTConfig_AttackSkill[0] = 64;
NTConfig_AttackSkill[1] = 47;
NTConfig_AttackSkill[3] = 47;
NTConfig_AttackSkill[5] = 64;
NTConfig_AttackSkill[6] = 55;
break;
case 3: // Fire Ball + Meteor
NTConfig_AttackSkill[1] = 56;
NTConfig_AttackSkill[2] = 47;
NTConfig_AttackSkill[3] = 56;
NTConfig_AttackSkill[4] = 47;
break;
}
return (NTConfig_AttackSkill[1] && NTConfig_AttackSkill[3]);
}
function NTA_SorceressAttackInt(target, firstorder)
{
var _primaryindex, _immuneTarget, _useStatic;
_useStatic = false;
if(NTTMGR_CheckCurse(NTConfig_CheckSelfSafe, NTConfig_CheckMercSafe))
{
if(!NTTMGR_VisitTown())
return 0;
}
if(_MWA_SkipList.indexOf(target.gid) > -1)
{
Print("Return A");
return 1;
}
if(MWConfig_AttacksBeforeRepositioning > 0 && _MWA_Attack_Time[3] % MWConfig_AttacksBeforeRepositioning == 0)
{
var _vec = MWA_GetEvasionVector(4, 2, target);
if(_vec && !_vec.isZero())
NTM_MoveTo(target.areaid, parseInt(target.x + _vec.x), parseInt(target.y + _vec.y), 0);
}
_immuneTarget = MWA_CheckMonsterImmunity(target);
if(_immuneTarget && NTConfig_BehaviourOnImmuneMonster == 2 && !(target.spectype&0x02) && me.areaid != 131 || MWA_CheckAttackTimeLimit(target))
{
_MWA_SkipList.push(target.gid);
Print("Return B");
return 1;
}
if(_immuneTarget)
{
if(NTConfig_BehaviourOnImmuneMonster == 3 && NTConfig_AttackSkill[8] > 0) // Attack the target using the selected skill
{
if(!NTA_SorceressCastSkillInt(8, target))
return 2;
return 3;
}
else if(NTConfig_BehaviourOnImmuneMonster == 1 && NTC_GetMerc())// Get close so the merc can attack the target
{
if(GetDistance(me, target) > 5)
NTM_MoveTo(target.areaid, target.x + 2, target.y + 2);
NTC_Delay(100);
_useStatic = true;
}
}
if(firstorder && NTConfig_AttackSkill[0] > 0 && MWA_CheckMonsterResistance(target, _NTA_SkillDamage[0]) && me.GetSkillStatus(NTConfig_AttackSkill[0]) != 8)
{
if(GetDistance(me, target) > _NTA_SkillRange[0] || !CheckCollision(me, target, 4))
{
var _pos = me.GetOptimalAttackPos(target.areaid, target.x, target.y, _NTA_SkillRange[0], 4);
if(_pos)
NTM_MoveTo(target.areaid, _pos[0], _pos[1], 0);
}
if(!NTC_CastSkill(NTConfig_AttackSkill[0], _NTA_SkillHand[0], target))
return 2;
return 3;
}
if((_useStatic || MWA_UseStaticOnTarget(target)) && NTConfig_CastStatic < 100 && parseInt(target.hp * 100 / target.hpmax) > NTConfig_CastStatic && MWA_CheckMonsterResistance(target, NTA_DAMAGE_LIGHTNING))
{
var _staticlevel = NTC_GetSkillLevel(MWS_STATIC_FIELD);
if(_staticlevel > 0)
{
var _staticrange;
var _castx, _casty;
_staticrange = Math.floor(( 5 + _staticlevel - 1) * 2 / 3);
if(GetDistance(me, target) > _staticrange || !CheckCollision(me, target, 6))
{
var _pos = me.GetOptimalAttackPos(target.areaid, target.x, target.y, _staticrange, 6);
if(_pos)
NTM_MoveTo(target.areaid, _pos[0], _pos[1], 0);
}
if(target.x < me.x)
_castx = me.x - 1;
else if(target.x > me.x)
_castx = me.x + 1;
else
_castx = me.x;
if(target.y < me.y)
_casty = me.y - 1;
else if(target.y > me.y)
_casty = me.y + 1;
else
_casty = me.y;
if(!CheckCollision(target.areaid, _castx, _casty, 1))
{
_castx = me.x;
_casty = me.y;
}
if(!NTC_CastSkill(MWS_STATIC_FIELD, NTC_HAND_RIGHT, _castx, _casty))
return 2;
return 3;
}
}
if(_useStatic)
return 3;
_primaryindex = (target.spectype&0x0A) ? 1 : 3;
if(MWA_CheckMonsterResistance(target, _NTA_SkillDamage[_primaryindex]))
{
if(!NTA_SorceressCastSkillInt(_primaryindex, target))
return 2;
return 3;
}
if(NTConfig_AttackSkill[5] > 0 && MWA_CheckMonsterResistance(target, _NTA_SkillDamage[5]))
{
if(!NTA_SorceressCastSkillInt(5, target))
return 2;
return 3;
}
Print("Return C");
return 1;
}
function NTA_SorceressCastSkillInt(index, target, evade)
{
var _maxDist, _pos;
if(arguments.length < 3)
evade = true;
if(me.GetSkillStatus(NTConfig_AttackSkill[index]) != 8)
{
if(GetDistance(me, target) > _NTA_SkillRange[index] || !CheckCollision(me, target, 4))
{
_pos = me.GetOptimalAttackPos(target.areaid, target.x, target.y, _NTA_SkillRange[index], 4);
if(_pos)
NTM_MoveTo(target.areaid, _pos[0], _pos[1], 0);
}
return NTC_CastSkill(NTConfig_AttackSkill[index], _NTA_SkillHand[index], target);
}
switch(target.classid)
{
case 310: // Doom Knight (CS)
case 362: // Venom Lord (CS)
case 472: // Hell Temptress
case 510: // Death Lord (Throne)
case 558: // Venom Lord (Throne)
case 571: // Minion of Desctrution (Throne)
case 638: // Vile Witch
case 691: // Undead Soul Killer (Throne)
_maxDist = 5;
break;
default:
_maxDist = 4;
break;
}
if(evade && NTC_GetSkillLevel(MWS_TELEPORT) >= 1 && MWA_CalcDistToClosestMonster() <= _maxDist && MWConfig_KeepDistanceToMonsters && MWA_AreaCheckEvading(me.areaid))
return MWA_MoveAwayFromMonster(target);
if(NTConfig_AttackSkill[index + 1] > 0 && (index == 8 || MWA_CheckMonsterResistance(target, _NTA_SkillDamage[index + 1])))
{
if(GetDistance(me, target) > _NTA_SkillRange[index+1] || !CheckCollision(me, target, 4))
{
_pos = me.GetOptimalAttackPos(target.areaid, target.x, target.y, _NTA_SkillRange[index + 1], 4);
if(_pos)
NTM_MoveTo(target.areaid, _pos[0], _pos[1], 0);
}
return NTC_CastSkill(NTConfig_AttackSkill[index + 1], _NTA_SkillHand[index + 1], target);
}
else if(NTConfig_AttackSkill[7] > 0 && MWA_CheckMonsterResistance(target, _NTA_SkillDamage[7]))
{
if(GetDistance(me, target) > _NTA_SkillRange[7] || !CheckCollision(me, target, 4))
{
_pos = me.GetOptimalAttackPos(target.areaid, target.x, target.y, _NTA_SkillRange[7], 4);
if(_pos)
NTM_MoveTo(target.areaid, _pos[0], _pos[1], 0);
}
return NTC_CastSkill(NTConfig_AttackSkill[7], _NTA_SkillHand[7], target);
}
for(var i = 0; i < 25; i++)
{
NTC_Delay(NTC_DELAY_FRAME);
if(me.GetSkillStatus(NTConfig_AttackSkill[index]) != 8)
break;
}
return false;
}
function NTA_NecromancerAttackPatternInt()
{
return false;
}
function NTA_NecromancerAttackInt(target, firstorder)
{
var _nextCorpse, _gid, _vec, _viciousFoe, _count, _pos;
var i;
if(NTTMGR_CheckCurse(NTConfig_CheckSelfSafe, NTConfig_CheckMercSafe))
{
if(!NTTMGR_VisitTown())
return 0;
}
if(_MWA_SkipList.indexOf(target.gid) > -1)
return 1;
if(MWA_CheckAttackTimeLimit(target))
{
_MWA_SkipList.push(target.gid);
return 1;
}
if(MWConfig_AttacksBeforeRepositioning > 0 && _MWA_Attack_Time[3] % MWConfig_AttacksBeforeRepositioning == 0)
{
_vec = MWA_GetEvasionVector(4, 2, target);
if(!_vec && !_vec.isZero())
NTM_MoveTo(target.areaid, parseInt(target.x + _vec.x), parseInt(target.y + _vec.y), 0);
}
_viciousFoe = MWA_IsHazardousMonster(target);
// Define the maximum values once as they are mostly constant anyway
if(_MWA_Corpse_Damage_Radius < 0 || _MWA_Minion_Counts[0] < 0 || _MWA_Minion_Counts[1] < 0 || _MWA_Minion_Counts[2] < 0)
{
// Define the Corpse or Poison Explosion Range Radius
if(NTConfig_AttackSkill[3] == 74)
_MWA_Corpse_Damage_Radius = MWA_CalcCorpseExplosionRadius();
else
_MWA_Corpse_Damage_Radius = 5; // TODO: Check poison exp range
MWA_SetMinionCounts();
}
// Cast the initial attack unless it is a curse and the target is already cursed
if(!_viciousFoe && firstorder && NTConfig_AttackSkill[0] > 0 && NTA_GetResistance(target, _NTA_SkillDamage[0]) < 100 && me.GetSkillStatus(NTConfig_AttackSkill[0]) != 8 && !MWA_GetCurseState(NTConfig_AttackSkill[0], target))
{
if(GetDistance(me, target) > _NTA_SkillRange[0] || !CheckCollision(me, target, 4))
{
_pos = me.GetOptimalAttackPos(target.areaid, target.x, target.y, _NTA_SkillRange[0], 4);
if(_pos)
NTM_MoveTo(target.areaid, _pos[0], _pos[1], 0);
}
if(!NTC_CastSkill(NTConfig_AttackSkill[0], _NTA_SkillHand[0], target))
return 2;
}
// The current target is vicious and we gotta use the selected skill in order to make it less dangerous
if(_viciousFoe && !MWA_GetCurseState(NTConfig_AttackSkill[2], target))
{
if(GetDistance(me, target) > _NTA_SkillRange[2] || !CheckCollision(me, target, 4))
{
_pos = me.GetOptimalAttackPos(target.areaid, target.x, target.y, _NTA_SkillRange[2], 4);
if(_pos)
NTM_MoveTo(target.areaid, _pos[0], _pos[1], 0);
}
if(!NTA_NecromancerCastSkillInt(2, target))
return 2;
return 3;
}
// Use the standard curse unless the monster is already curse
if(!_viciousFoe && !MWA_GetCurseState(NTConfig_AttackSkill[1], target))
{
if(GetDistance(me, target) > _NTA_SkillRange[1] || !CheckCollision(me, target, 4))
{
_pos = me.GetOptimalAttackPos(target.areaid, target.x, target.y, _NTA_SkillRange[1], 4);
if(_pos)
NTM_MoveTo(target.areaid, _pos[0], _pos[1], 0);
}
if(!NTA_NecromancerCastSkillInt(1, target))
return 2;
return 3;
}
// The target is vicious and some monsters are very close to the char --> Evade
if(_viciousFoe && MWA_CalcDistToClosestMonster() < 3)
{
MWA_MoveAwayFromMonster(target);
_vec = MWA_GetEvasionVector(3, 2);
if(!_vec || _vec.isZero())
{
_vec = new vector(me.x - target.x, me.y - target.y);
_vec.normalize();
}
_vec.setlength(3);
NTC_Delay(100);
ClickMap(NTC_CLICK_LDOWN, NTC_SHIFT_NONE, me.x + parseInt(_vec.x), me.y + parseInt(_vec.y));
NTC_Delay(100);
ClickMap(NTC_CLICK_LUP, NTC_SHIFT_NONE, null);
NTC_Delay(100);
return 3;
}
// Find the corpse closest to the target's current position
_gid = MWA_GetClosestCorpseGID(target.x, target.y);
// Instantiate the unit if a valid gid was found
if(_gid > 0)
_nextCorpse = NTC_FindUnit(NTC_UNIT_MONSTER, _gid);
if(_nextCorpse)
{
// Use the corpse closest to the target in order to raise primary minions if you do not already have the desired amount of minions
_count = MWC_GetMinionCount(NTConfig_AttackSkill[4]);
if(_count < _MWA_Minion_Counts[0] - 1)
{
if(MWConfig_ShowOverheadStatus)
{
if(NTConfig_AttackSkill[4] == 95)
MWC_PrintOverheadStatus("Reviving " + _corpse.name + " (" + (_count + 1) + "/" + _MWA_Minion_Counts[0] + ")");
else
MWC_PrintOverheadStatus("Summoning " + MWC_GetMinionName(NTConfig_AttackSkill[4]) + " (" + (_count + 1) + "/" + _MWA_Minion_Counts[0] + ")");
}
if(!NTA_NecromancerCastSkillInt(4, _nextCorpse))
return 2;
return 3;
}
// Use the corpse to attack the target using corpse or poison explosion
if(GetDistance(target, _nextCorpse) <= _MWA_Corpse_Damage_Radius)
{
if(!NTA_NecromancerCastSkillInt(3, _nextCorpse))
return 2;
return 3;
}
}
// The target is not too dangerous and the average target - minion distance is too high --> Move close to the target
if(!_viciousFoe && MWA_CalcAverageMinionDistance(target) > 4.0)
{
_vec = new vector(me.x - target.x, me.y - target.y);
if(_vec && !_vec.isZero())
{
_vec.normalize();
NTM_MoveTo(target.areaid, target.x + parseInt(2 * _vec.x), target.y + parseInt(2 * _vec.y));
}
}
// If the distance to our minions is rather short (stuck on our position?) or some enemy monsters are close --> Step aside
if(MWA_CalcAverageMinionDistance() < 2.0 || MWA_CalcDistToClosestMonster() < 3)
{
_vec = MWA_GetEvasionVector(3, 2);
if(!_vec || _vec.isZero())
_vec = new vector(me.x - target.x, me.y - target.y);
_vec.setlength(3);
NTC_Delay(100);
ClickMap(NTC_CLICK_LDOWN, NTC_SHIFT_NONE, me.x + parseInt(_vec.x), me.y + parseInt(_vec.y));
NTC_Delay(100);
ClickMap(NTC_CLICK_LUP, NTC_SHIFT_NONE, null);
NTC_Delay(100);
return 3;
}
// If the enemy is vicious or if our minions are already close to the target --> Wait and let the minions do their job
if(_viciousFoe && MWA_CalcDistToClosestMonster() > 3 || MWA_CalcAverageMinionDistance(target) <= 4.0)
{
for(i = 0; i < 20; i++)
{
NTC_Delay(NTC_DELAY_FRAME);
if(MWA_GetClosestCorpseGID(target.x, target.y, _MWA_Corpse_Damage_Radius) > 0 || !NTA_IsValidMonster(target))
break;
}
return ((i >= 20) ? 3 : 2);
}
NTC_Delay(250);
return NTA_NecromancerAttackInt(target, firstorder);
}
function NTA_NecromancerCastSkillInt(index, target)
{
if(me.GetSkillStatus(NTConfig_AttackSkill[index]) != 8)
{
if(GetDistance(me, target) > _NTA_SkillRange[index] || !CheckCollision(me, target, 4))
{
var _pos = me.GetOptimalAttackPos(target.areaid, target.x, target.y, _NTA_SkillRange[index], 4);
if(_pos)
NTM_MoveTo(target.areaid, _pos[0], _pos[1], 0);
}
return NTC_CastSkill(NTConfig_AttackSkill[index], _NTA_SkillHand[index], target);
}
for(var i = 0; i < 25; i++)
{
NTC_Delay(NTC_DELAY_FRAME);
if(me.GetSkillStatus(NTConfig_AttackSkill[index]) != 8)
break;
}
return false;
}
function NTA_PaladinAttackPatternInt()
{
var _maxindex, _maxskill;
var _avgskilllevel = new Array();
_avgskilllevel[0] = parseInt((me.GetSkill(112, false)+me.GetSkill(108, false)+me.GetSkill(115, false))/3);
_avgskilllevel[1] = parseInt((me.GetSkill(106, false)+me.GetSkill(96, false))/2);
_avgskilllevel[2] = parseInt((me.GetSkill(121, false)+me.GetSkill(101, false)+me.GetSkill(118, false))/3);
_maxindex = -1;
_maxskill = 0;
for(var i = 0 ; i < _avgskilllevel.length ; i++)
{
if(_avgskilllevel[i] > _maxskill)
{
_maxindex = i;
_maxskill = _avgskilllevel[i];
}
}
switch(_maxindex)
{
case 0: // Blessed Hammer
NTConfig_AttackSkill[1] = 112;
NTConfig_AttackSkill[2] = 113;
NTConfig_AttackSkill[3] = 112;
NTConfig_AttackSkill[4] = 113;
break;
case 1: // Zeal
NTConfig_AttackSkill[1] = 106;
NTConfig_AttackSkill[2] = 122;
NTConfig_AttackSkill[3] = 106;
NTConfig_AttackSkill[4] = 122;
break;
case 2: // Fist of the Heavens
NTConfig_AttackSkill[1] = 121;
NTConfig_AttackSkill[2] = 123;
NTConfig_AttackSkill[3] = 121;
NTConfig_AttackSkill[4] = 123;
break;
}
return (NTConfig_AttackSkill[1] && NTConfig_AttackSkill[3]);
}
function NTA_PaladinAttackInt(target, firstorder)
{
var _primaryindex, _immuneTarget;
if(NTTMGR_CheckCurse(NTConfig_CheckSelfSafe, NTConfig_CheckMercSafe))
{
if(!NTTMGR_VisitTown())
return 0;
}
if(_MWA_SkipList.indexOf(target.gid) > -1)
return 1;
if(MWConfig_AttacksBeforeRepositioning > 0 && _MWA_Attack_Time[3] % MWConfig_AttacksBeforeRepositioning == 0)
{
var _vec = MWA_GetEvasionVector(4, 2, target);
if(_vec && !_vec.isZero())
NTM_MoveTo(target.areaid, parseInt(target.x + _vec.x), parseInt(target.y + _vec.y), 0);
}
_immuneTarget = MWA_CheckMonsterImmunity(target);
if(_immuneTarget && NTConfig_BehaviourOnImmuneMonster == 2 && !(target.spectype&0x02) && me.areaid != 131 || MWA_CheckAttackTimeLimit(target)) // Skip the target
{
_MWA_SkipList.push(target.gid);
return 1;
}
if(_immuneTarget)
{
if(NTConfig_BehaviourOnImmuneMonster == 3 && NTConfig_AttackSkill[8] > 0) // Attack the target using the selected skill
{
if(!NTA_PaladinCastSkillInt(8, target))
return 2;
return 3;
}
else if(NTConfig_BehaviourOnImmuneMonster == 1 && MWA_FindNearbyMonsters(15, target) < 3 && NTC_GetMerc())// Get close so the merc can attack the target
{
if(GetDistance(me, target) > 5)
NTM_MoveTo(target.areaid, target.x + 3, target.y + 3);
NTC_Delay(100);
return 2;
}
}
if(firstorder && NTConfig_AttackSkill[0] > 0 && NTA_GetResistance(target, _NTA_SkillDamage[0]) < 100)
{
if(GetDistance(me, target) > _NTA_SkillRange[0] || !CheckCollision(me, target, 4))
{
var _pos = me.GetOptimalAttackPos(target.areaid, target.x, target.y, _NTA_SkillRange[0], 4);
if(_pos)
NTM_MoveTo(target.areaid, _pos[0], _pos[1], 0);
}
if(!NTC_CastSkill(NTConfig_AttackSkill[0], _NTA_SkillHand[0], target))
return 2;
return 3;
}
_primaryindex = (target.spectype&0x0A) ? 1 : 3;
if(NTA_GetResistance(target, _NTA_SkillDamage[_primaryindex]) < 100 || MWA_IsUndead(target) && NTConfig_AttackSkill[_primaryindex + 1] == 119 && _NTA_SkillDamage[_primaryindex] == NTA_DAMAGE_PHYSICAL)
{
if(_NTA_SkillRange[_primaryindex] < 4 && !CheckCollision(target.areaid, target.x, target.y, 1))
return 1;
if(!NTA_PaladinCastSkillInt(_primaryindex, target))
return 2;
return 3;
}
if(NTConfig_AttackSkill[5] > 0 && NTA_GetResistance(target, NTA_GetDamageType(NTConfig_AttackSkill[5], target, 5)) < 100)
{
if(_NTA_SkillRange[5] < 4 && !CheckCollision(target.areaid, target.x, target.y, 1))
return 1;
if(!NTA_PaladinCastSkillInt(5, target))
return 2;
return 3;
}
return 1;
}
function NTA_PaladinCastSkillInt(index, target)
{
if(NTConfig_AttackSkill[index] == MWS_BLESSED_HAMMER)
{
if(me.x-target.x < 1 || me.x-target.x > 2 || me.y-target.y < 1 || me.y-target.y > 2)
{
if(CheckCollision(target.areaid, target.x+2, target.y+2, 1))
{
switch(Random(0, 2))
{
case 0:
NTM_MoveTo(target.areaid, target.x + 1, target.y, 0);
break;
case 1:
NTM_MoveTo(target.areaid, target.x + 2, target.y - 1, 0);
break;
default:
NTM_MoveTo(target.areaid, target.x + 2, target.y, 0);
}
}
else if(me.x-target.x < -4 || me.x-target.x > 2 || me.y-target.y < 0 || me.y-target.y > 2)
NTM_MoveTo(target.areaid, target.x-4, target.y, 0);
}
}
else
{
if(GetDistance(me, target) > _NTA_SkillRange[index] || !CheckCollision(me, target, 4))
{
var _pos = me.GetOptimalAttackPos(target.areaid, target.x, target.y, _NTA_SkillRange[index], 4);
if(_pos)
NTM_MoveTo(target.areaid, _pos[0], _pos[1], 0);
}
}
if(target.classid == 704 && NTConfig_AttackSkill[7] > 0)
NTC_PutSkill(NTConfig_AttackSkill[7], NTC_HAND_RIGHT);
else if(NTConfig_AttackSkill[index + 1] > 0)
NTC_PutSkill(NTConfig_AttackSkill[index + 1], NTC_HAND_RIGHT);
return NTC_CastSkill(NTConfig_AttackSkill[index], _NTA_SkillHand[index], target);
}
function NTA_BarbarianAttackPatternInt()
{
var _maxindex, _maxskill;
var _avgskilllevel = new Array();
_avgskilllevel[0] = me.GetSkill(MWS_WHIRLWIND, false);
_maxindex = -1;
_maxskill = 0;
for(var i = 0 ; i < _avgskilllevel.length ; i++)
{
if(_avgskilllevel[i] > _maxskill)
{
_maxindex = i;
_maxskill = _avgskilllevel[i];
}
}
switch(_maxindex)
{
case 0: // Whirlwind
NTConfig_AttackSkill[1] = MWS_WHIRLWIND;
NTConfig_AttackSkill[3] = MWS_WHIRLWIND;
NTConfig_AttackSkill[5] = MWS_BERSERK;
break;
}
return (NTConfig_AttackSkill[1] && NTConfig_AttackSkill[3]);
}
function NTA_BarbarianAttackInt(target, firstorder)
{
var _primaryindex, _immuneTarget;
if(_MWA_Attack_Slot < 0)
{
_MWA_Attack_Slot = MWC_GetSlotID("attack");
if(_MWA_Attack_Slot < 0)
return 1;
}
NTC_SwapWeapons(_MWA_Attack_Slot);
if(NTTMGR_CheckCurse(NTConfig_CheckSelfSafe, NTConfig_CheckMercSafe))
{
if(!NTTMGR_VisitTown())
return 0;
}
if(_MWA_SkipList.indexOf(target.gid) > -1)
return 1;
if(MWConfig_AttacksBeforeRepositioning > 0 && _MWA_Attack_Time[3] % MWConfig_AttacksBeforeRepositioning == 0)
{
var _vec = MWA_GetEvasionVector(4, 2, target);
if(_vec && !_vec.isZero())
NTM_MoveTo(target.areaid, parseInt(target.x + _vec.x), parseInt(target.y + _vec.y), 0);
}
_immuneTarget = MWA_CheckMonsterImmunity(target);
if(_immuneTarget && NTConfig_BehaviourOnImmuneMonster == 2 && !(target.spectype&0x02) && me.areaid != 131 || MWA_CheckAttackTimeLimit(target))
{
_MWA_SkipList.push(target.gid);
return 1;
}
if(_immuneTarget)
{
if(NTConfig_BehaviourOnImmuneMonster == 3 && NTConfig_AttackSkill[8] > 0) // Attack the target using the selected skill
{
if(!NTA_BarbarianCastSkillInt(8, target))
return 2;
return 3;
}
else if(NTConfig_BehaviourOnImmuneMonster == 1 && MWA_FindNearbyMonsters(15, target) < 3 && NTC_GetMerc())// Get close so the merc can attack the target
{
if(GetDistance(me, target) > 5)
NTM_MoveTo(target.areaid, target.x + 2, target.y + 2);
NTC_Delay(100);
return 2;
}
}
if(firstorder && NTConfig_AttackSkill[0] > 0 && NTA_GetResistance(target, _NTA_SkillDamage[0]) < 100)
{
if(GetDistance(me, target) > _NTA_SkillRange[0] || !CheckCollision(me, target, 4))
{
var _pos = me.GetOptimalAttackPos(target.areaid, target.x, target.y, _NTA_SkillRange[0], 4);
if(_pos)
NTM_MoveTo(target.areaid, _pos[0], _pos[1], 0);
}
if(!NTC_CastSkill(NTConfig_AttackSkill[0], _NTA_SkillHand[0], target))
return 2;
return 3;
}
_primaryindex = (target.spectype&0x0A) ? 1 : 3;
if(NTA_GetResistance(target, _NTA_SkillDamage[_primaryindex]) < 100)
{
if((_NTA_SkillRange[_primaryindex] < 4 || NTConfig_AttackSkill[_primaryindex] == 151) && !CheckCollision(target.areaid, target.x, target.y, 1))
return 1;
if(!NTA_BarbarianCastSkillInt(_primaryindex, target))
return 2;
return 3;
}
if(NTConfig_AttackSkill[5] > 0 && NTA_GetResistance(target, _NTA_SkillDamage[5]) < 100)
{
if((_NTA_SkillRange[5] < 4 || NTConfig_AttackSkill[5] == MWS_WHIRLWIND) && !CheckCollision(target.areaid, target.x, target.y, 1))
return 1;
if(!NTA_BarbarianCastSkillInt(5, target))
return 2;
return 3;
}
return 1;
}
function NTA_BarbarianCastSkillInt(index, target)
{
if(NTConfig_AttackSkill[index] == MWS_WHIRLWIND)
{
var _cast, _vec;
if(GetDistance(me, target) > _NTA_SkillRange[index] || !CheckCollision(me, target, 5))
{
var _pos = me.GetOptimalAttackPos(target.areaid, target.x, target.y, _NTA_SkillRange[index], 5);
if(_pos)
NTM_MoveTo(target.areaid, _pos[0], _pos[1], 0);
}
_cast = new coord();
_vec = new vector(target.x - me.x, target.y - me.y);
if(!_vec)
return false;
_vec.setlength(4);
_angles = new Array(30, -60, 90, -120, 150, -180);
for(var i = 0; i < _angles.length; i++)
{
_cast.x = parseInt(target.x + _vec.x);
_cast.y = parseInt(target.y + _vec.y);
if(CheckCollision(me.areaid, _cast.x, _cast.y, 0))
break;
_vec.rotate(_angles[i]);
}
return NTC_CastSkill(NTConfig_AttackSkill[index], _NTA_SkillHand[index], _cast.x, _cast.y);
}
if(GetDistance(me, target) > _NTA_SkillRange[index] || !CheckCollision(me, target, 4))
{
var _pos = me.GetOptimalAttackPos(target.areaid, target.x, target.y, _NTA_SkillRange[index], 4);
if(_pos)
NTM_MoveTo(target.areaid, _pos[0], _pos[1], 0);
}
return NTC_CastSkill(NTConfig_AttackSkill[index], _NTA_SkillHand[index], target);
}
function NTA_DruidAttackPatternInt()
{
return false;
}
function NTA_DruidAttackInt(target, firstorder)
{
var _primaryindex, _immuneTarget;
if(NTTMGR_CheckCurse(NTConfig_CheckSelfSafe, NTConfig_CheckMercSafe))
{
if(!NTTMGR_VisitTown())
return 0;
}
if(_MWA_SkipList.indexOf(target.gid) > -1)
return 1;
if(firstorder)
NTP_DoPrecast(false);
if(MWConfig_AttacksBeforeRepositioning > 0 && _MWA_Attack_Time[3] % MWConfig_AttacksBeforeRepositioning == 0)
{
var _vec = MWA_GetEvasionVector(4, 2, target);
if(_vec && !_vec.isZero())
NTM_MoveTo(target.areaid, parseInt(target.x + _vec.x), parseInt(target.y + _vec.y), 0);
}
_immuneTarget = MWA_CheckMonsterImmunity(target);
if(_immuneTarget && NTConfig_BehaviourOnImmuneMonster == 2 && !(target.spectype&0x02) && me.areaid != 131 || MWA_CheckAttackTimeLimit(target)) // Skip the target
{
_MWA_SkipList.push(target.gid);
return 1;
}
if(_immuneTarget)
{
if(NTConfig_BehaviourOnImmuneMonster == 3 && NTConfig_AttackSkill[8] > 0) // Attack the target using the selected skill
{
if(!NTA_DruidCastSkillInt(8, target))
return 2;
return 3;
}
else if(NTConfig_BehaviourOnImmuneMonster == 1 && MWA_FindNearbyMonsters(15, target) < 3 && NTC_GetMerc())// Get close so the merc can attack the target
{
if(GetDistance(me, target) > 5)
NTM_MoveTo(target.areaid, target.x + 3, target.y + 3);
NTC_Delay(100);
return 2;
}
}
if(firstorder && NTConfig_AttackSkill[0] > 0 && NTA_GetResistance(target, _NTA_SkillDamage[0]) < 100)
{
if(GetDistance(me, target) > _NTA_SkillRange[0] || !CheckCollision(me, target, 4))
{
var _pos = me.GetOptimalAttackPos(target.areaid, target.x, target.y, _NTA_SkillRange[0], 4);
if(_pos)
NTM_MoveTo(target.areaid, _pos[0], _pos[1], 0);
}
if(!NTC_CastSkill(NTConfig_AttackSkill[0], _NTA_SkillHand[0], target))
return 2;
return 3;
}
_primaryindex = (target.spectype&0x0A) ? 1 : 3;
if(NTA_GetResistance(target, _NTA_SkillDamage[_primaryindex]) < 100 || MWA_IsUndead(target) && NTConfig_AttackSkill[_primaryindex + 1] == 119 && _NTA_SkillDamage[_primaryindex] == NTA_DAMAGE_PHYSICAL)
{
if(_NTA_SkillRange[_primaryindex] < 4 && !CheckCollision(target.areaid, target.x, target.y, 1))
return 1;
if(!NTA_DruidCastSkillInt(_primaryindex, target))
return 2;
return 3;
}
if(NTConfig_AttackSkill[5] > 0 && NTA_GetResistance(target, NTA_GetDamageType(NTConfig_AttackSkill[5], target, 5)) < 100)
{
if(_NTA_SkillRange[5] < 4 && !CheckCollision(target.areaid, target.x, target.y, 1))
return 1;
if(!NTA_DruidCastSkillInt(5, target))
return 2;
return 3;
}
return 1;
}
function NTA_DruidCastSkillInt(index, target)
{
var _pos;
if(me.GetSkillStatus(NTConfig_AttackSkill[index]) != 8)
{
if(GetDistance(me, target) > _NTA_SkillRange[index] || !CheckCollision(me, target, 4))
{
_pos = me.GetOptimalAttackPos(target.areaid, target.x, target.y, _NTA_SkillRange[index], 4);
if(_pos)
NTM_MoveTo(target.areaid, _pos[0], _pos[1], 0);
}
return NTC_CastSkill(NTConfig_AttackSkill[index], _NTA_SkillHand[index], target);
}
if(NTConfig_AttackSkill[index + 1] > 0 && NTA_GetResistance(target, _NTA_SkillDamage[index + 1]) <= 99)
{
if(GetDistance(me, target) > _NTA_SkillRange[index+1] || !CheckCollision(me, target, 4))
{
_pos = me.GetOptimalAttackPos(target.areaid, target.x, target.y, _NTA_SkillRange[index + 1], 4);
if(_pos)
NTM_MoveTo(target.areaid, _pos[0], _pos[1], 0);
}
return NTC_CastSkill(NTConfig_AttackSkill[index + 1], _NTA_SkillHand[index + 1], target);
}
for(var i = 0; i < 25; i++)
{
NTC_Delay(NTC_DELAY_FRAME);
if(me.GetSkillStatus(NTConfig_AttackSkill[index]) != 8)
break;
}
return false;
}
function NTA_AssassinAttackPatternInt()
{
return true;
}
function NTA_AssassinAttackInt(target, firstorder)
{
var _pos, _trapPos, _index, _vec;
if(NTTMGR_CheckCurse(NTConfig_CheckSelfSafe, NTConfig_CheckMercSafe))
{
if(!NTTMGR_VisitTown())
return 0;
}
if(_MWA_SkipList.indexOf(target.gid) > -1)
return 1;
if(MWConfig_AttacksBeforeRepositioning > 0 && _MWA_Attack_Time[3] % MWConfig_AttacksBeforeRepositioning == 0)
{
_vec = MWA_GetEvasionVector(4, 2, target);
if(_vec && !_vec.isZero())
NTM_MoveTo(target.areaid, parseInt(target.x + _vec.x), parseInt(target.y + _vec.y), 0);
}
_immuneTarget = MWA_CheckMonsterImmunity(target);
if(_immuneTarget && NTConfig_BehaviourOnImmuneMonster == 2 && !(target.spectype&0x02) && me.areaid != 131 || MWA_CheckAttackTimeLimit(target)) // Skip the target
{
_MWA_SkipList.push(target.gid);
return 1;
}
if(_immuneTarget)
{
if(NTConfig_BehaviourOnImmuneMonster == 3 && NTConfig_AttackSkill[8] > 0) // Attack the target using the selected skill
{
if(!NTA_AmazonCastSkillInt(8, target))
return 2;
return 3;
}
else if(NTConfig_BehaviourOnImmuneMonster == 1 && MWA_FindNearbyMonsters(15, target) < 3 && NTC_GetMerc())// Get close so the merc can attack the target
{
if(GetDistance(me, target) > 5)
NTM_MoveTo(target.areaid, target.x + 2, target.y + 2);
NTC_Delay(100);
return 2;
}
}
if(firstorder && NTConfig_AttackSkill[0] > 0 && NTA_GetResistance(target, _NTA_SkillDamage[0]) < 100 && me.GetSkillStatus(NTConfig_AttackSkill[0]) != 8)
{
if(GetDistance(me, target) > 20 || !CheckCollision(me, target, 4))
{
_pos = me.GetOptimalAttackPos(target.areaid, target.x, target.y, 20, 4);
if(_pos)
NTM_MoveTo(target.areaid, _pos[0], _pos[1], 0);
}
if(!NTC_CastSkill(NTConfig_AttackSkill[0], _NTA_SkillHand[0], target))
return 2;
return 3;
}
if(!_MWA_Traps)
{
_MWA_Traps = new MWA_Traps(target);
return 2;
}
if(_MWA_Traps.Refresh(target) && _MWA_Traps.Active.length < _MWA_Traps.MAXQUANTITY)
{
_index = -1;
if(target.spectype&0x0A)
{
if(NTConfig_AttackSkill[1] > 0 && NTA_GetResistance(target, _NTA_SkillDamage[1]) <= 99 && _MWA_Traps.GetQuantity(NTConfig_AttackSkill[1]) < MWConfig_TrapRatio[0][0])
_index = 1;
else if(NTConfig_AttackSkill[2] > 0 && NTA_GetResistance(target, _NTA_SkillDamage[2]) <= 99 && _MWA_Traps.GetQuantity(NTConfig_AttackSkill[2]) < MWConfig_TrapRatio[0][1])
_index = 2;
}
else
{
if(NTConfig_AttackSkill[3] > 0 && NTA_GetResistance(target, _NTA_SkillDamage[3]) <= 99 && _MWA_Traps.GetQuantity(NTConfig_AttackSkill[3]) < MWConfig_TrapRatio[1][0])
_index = 3;
else if(NTConfig_AttackSkill[4] > 0 && NTA_GetResistance(target, _NTA_SkillDamage[4]) <= 99 && _MWA_Traps.GetQuantity(NTConfig_AttackSkill[4]) < MWConfig_TrapRatio[1][1])
_index = 4;
}
if(_index > -1)
{
_trapPos = _MWA_Traps.GetTrapPosition(_NTA_SkillRange[_index][1]);
if(_trapPos)
{
_trapPos.areaid = target.areaid;
if(GetDistance(me , _trapPos) > _NTA_SkillRange[_index][0] || !CheckCollision(me.areaid, _trapPos.x, _trapPos.y, 2))
{
_pos = me.GetOptimalAttackPos(_trapPos.areaid, _trapPos.x, _trapPos.y, _NTA_SkillRange[_index][0], 2);
if(_pos)
NTM_MoveTo(_trapPos.areaid, _pos[0], _pos[1], 0);
}
if(!NTC_CastSkill(NTConfig_AttackSkill[_index], _NTA_SkillHand[_index], _trapPos.x, _trapPos.y))
return 2;
}
else
return 2;
return 3;
}
}
if(NTC_GetSkillLevel(MWS_TELEPORT) > 0 && MWA_CalcDistToClosestMonster() < 3 && MWConfig_KeepDistanceToMonsters && MWA_AreaCheckEvading(me.areaid))
{
if(!MWA_MoveAwayFromMonster(target))
return 2;
return 3;
}
if(NTConfig_AttackSkill[5] > 0 && (NTA_GetResistance(target, _NTA_SkillDamage[5]) <= 99 || NTA_GetResistance(target, _NTA_SkillDamage[6]) <= 99))
{
if(!NTA_AssassinCastSkillInt(5, target))
return 2;
return 3;
}
return 1;
}
function NTA_AssassinCastSkillInt(index, target)
{
if(NTA_GetResistance(target, _NTA_SkillDamage[index]) <= 99 && me.GetSkillStatus(NTConfig_AttackSkill[index]) != 8)
{
if(GetDistance(me, target) > _NTA_SkillRange[index] || !CheckCollision(me, target, 4))
{
var _pos = me.GetOptimalAttackPos(target.areaid, target.x, target.y, _NTA_SkillRange[index], 4);
if(_pos)
NTM_MoveTo(target.areaid, _pos[0], _pos[1], 0);
}
return NTC_CastSkill(NTConfig_AttackSkill[index], _NTA_SkillHand[index], target);
}
if(NTA_GetResistance(target, _NTA_SkillDamage[index + 1]) <= 99 && NTConfig_AttackSkill[index + 1] > 0)
{
if(GetDistance(me, target) > _NTA_SkillRange[index + 1] || !CheckCollision(me, target, 4))
{
var _pos = me.GetOptimalAttackPos(target.areaid, target.x, target.y, _NTA_SkillRange[index + 1], 4);
if(_pos)
NTM_MoveTo(target.areaid, _pos[0], _pos[1], 0);
}
return NTC_CastSkill(NTConfig_AttackSkill[index + 1], _NTA_SkillHand[index + 1], target);
}
for(var i = 0; i < 25; i++)
{
NTC_Delay(NTC_DELAY_FRAME);
if(me.GetSkillStatus(NTConfig_AttackSkill[index]) != 8)
break;
}
return false;
}
function MWA_UseStaticOnTarget(monster)
{
if(MWConfig_StaticTargets.length == 0)
return true;
if(me.diff == 0 || !monster || !monster.name)
return false;
for(var i = 0; i < MWConfig_StaticTargets.length; i++)
{
if(MWConfig_StaticTargets[i] == monster.classid || typeof MWConfig_StaticTargets[i] == "string" && monster.name.toLowerCase().indexOf(MWConfig_StaticTargets[i].toLowerCase()) > -1)
return true;
}
return false;
}
function MWA_CheckForCloseMonsters(range)
{
var _monstersClose, _checkMonster;
if(range < 1 || arguments.length < 1)
return false;
_monstersClose = false;
_checkMonster = NTC_FindUnit(NTC_UNIT_MONSTER);
if(_checkMonster)
{
do
{
if(_checkMonster.IsAttackable() && GetDistance(me.x, me.y, _checkMonster.x, _checkMonster.y) < range && NTA_IsValidMonster(_checkMonster))
{
_monstersClose = true;
break;
}
} while(_checkMonster.GetNext());
}
return _monstersClose;
}
function MWA_CalcDistToClosestMonster(x, y, calcAverage)
{
var _dist, _minDist, _checkMonster, _distances;
if(arguments.length < 2)
{
x = me.x;
y = me.y;
}
if(arguments.length < 3)
calcAverage = false;
_checkMonster = NTC_FindUnit(NTC_UNIT_MONSTER);
_dist = 1E3;
_minDist = 1E3;
_distances = new Array();
if(_checkMonster)
{
do
{
if(_checkMonster.IsAttackable() && NTA_IsValidMonster(_checkMonster))
{
_dist = GetDistance(x, y, _checkMonster.x, _checkMonster.y);
if(calcAverage)
_distances.push(_dist);
else if(_dist < _minDist)
_minDist = _dist;
}
} while(_checkMonster.GetNext());
}
if(calcAverage)
{
_dist = 0;
for(var i = 0; i < _distances.length; i++)
_dist += _distances[i];
if(_distances.length > 0)
return _dist / _distances.length;
}
return _minDist;
}
function MWA_AreaCheckEvading(areaid)
{
if(MWConfig_EvasionExceptions.length > 0 && MWConfig_EvasionExceptions.indexOf(areaid) != -1)
return false;
else
return true;
}
function MWA_GetEvasionVector(length, offset, origin, rotationAngle)
{
var _vec, _targetVec, _maxDistIndex, _dist, _maxDist, _destx, _desty, _path, _pathX, _pathY;
_targetVec = new Array();
if(arguments.length < 3 || !origin.x || !origin.y || !origin.areaid)
origin = me;
if(arguments.length < 4 || isNaN(rotationAngle))
rotationAngle = 22.5;
_vec = new vector(1, 0);
if(!_vec)
return new vector();
for(var i = 0; i < parseInt(360 / rotationAngle); i++)
{
_vec.rotate(rotationAngle);
_vec.normalize();
_targetVec.push(new vector(_vec.x, _vec.y));
}
_maxDistIndex = -1;
_maxDist = 0;
_dist = 0;
// Find the spot with the largest distance to the next monster
for(var i = 0; i < _targetVec.length; i++)
{
_destx = origin.x + Math.round(_targetVec[i].x * length);
_desty = origin.y + Math.round(_targetVec[i].y * length);
_path = GetPath(origin.areaid, origin.x, origin.y, _destx, _desty, true);
if(_path)
{
_pathX = _path[_path.length - 1][0];
_pathY = _path[_path.length - 1][1];
if(GetDistance(_destx, _desty, _pathX, _pathY) > offset || !CheckCollision(origin.areaid, _pathX, _pathY, 0)) // DEBUG !CheckCollision(origin.areaid, origin.x, origin.y, _pathX, _pathY, 0)
continue;
_dist = MWA_CalcDistToClosestMonster(_pathX, _pathY);
if(_dist > _maxDist)
{
_maxDist = _dist;
_maxDistIndex = i;
}
}
}
if(_maxDistIndex != -1)
return _targetVec[_maxDistIndex];
else
return new vector();
}
function MWA_MoveAwayFromMonster(target)
{
var _vec, _targetVec, _spotIndex, _targetDist, _destx, _desty, _path;
const _VEC_LENGTH = 8; // Length of the vector pointing to the target spot
const _DELTA_DEST = 2; // Maximum distance to the target location after moving
_targetVec = MWA_GetEvasionVector(_VEC_LENGTH, _DELTA_DEST);
if(_targetVec && !_targetVec.isZero())
{
_targetVec.setlength(_VEC_LENGTH);
_targetDist = MWA_CalcDistToClosestMonster(me.x + Math.round(_targetVec.x), me.y + Math.round(_targetVec.y));
if(_targetDist > MWA_CalcDistToClosestMonster() && _targetDist > 4)
{
_destx = me.x + Math.round(_targetVec.x);
_desty = me.y + Math.round(_targetVec.y);
if(MWConfig_ShowOverheadStatus)
MWC_PrintOverheadStatus("Evading...");
NTM_MoveTo(me.areaid, _destx, _desty, 1);
if(GetDistance(me.x, me.y, _destx, _desty) < _DELTA_DEST)
return true;
}
}
_targetVec = MWA_GetEvasionVector(_VEC_LENGTH * 2.5, _DELTA_DEST, target);
if(_targetVec && !_targetVec.isZero())
{
_targetVec.setlength(_VEC_LENGTH * 2.5);
_targetDist = MWA_CalcDistToClosestMonster(me.x + Math.round(_targetVec.x), me.y + Math.round(_targetVec.y));
if(_targetDist > MWA_CalcDistToClosestMonster())
return NTM_MoveTo(me.areaid, target.x + Math.round(_targetVec.x), target.y + Math.round(_targetVec.y), 1);
}
return false;
}
function MWA_FindNearbyMonsters(range, target)
{
var _monster;
var _count = 0;
if(arguments.length < 1)
range = 20;
if(arguments.length < 2)
target = me;
_monster = NTC_FindUnit(NTC_UNIT_MONSTER);
if(_monster)
{
do
{
if(_monster.IsAttackable() && NTA_IsValidMonster(_monster) && GetDistance(target, _monster) < range)
_count++;
}
while(_monster.GetNext());
}
return _count;
}
function MWA_CheckInfinity()
{
var _merc, _items;
_merc = NTC_GetMerc();
if(!_merc)
return false;
_items = _merc.GetItems();
if(_items)
{
for(var i = 0; i < _items.length; i++)
{
if(_items[i].itemloc == 4)
{
if(_items[i].itemprefix == 0x5056) // Infinity
_MWA_Merc_Weapon_Type = 1;
else if( _items[i].GetStat(198) == 0x21) // The Reaper's Toll
_MWA_Merc_Weapon_Type = 2;
return true;
}
}
_MWA_Merc_Weapon_Type = 0;
}
return false;
}
function MWA_CheckMonsterImmunity(target)
{
var _resistance;
for(var i = 0; i < MWConfig_CheckImmunitySkills.length; i++)
{
if(isNaN(MWConfig_CheckImmunitySkills[i]) || MWConfig_CheckImmunitySkills[i] < 0 || MWConfig_CheckImmunitySkills[i] >= NTConfig_AttackSkill.length)
return false;
if(NTConfig_AttackSkill[MWConfig_CheckImmunitySkills[i]] == 0)
continue;
if(MWA_CheckMonsterResistance(target, NTA_GetDamageType(NTConfig_AttackSkill[MWConfig_CheckImmunitySkills[i]], target, MWConfig_CheckImmunitySkills[i])))
return false;
}
return MWConfig_CheckImmunitySkills.length > 0;
}
function MWA_CheckMonsterResistance(target, damageType)
{
var _res;
if(_MWA_Merc_Weapon_Type == -1)
MWA_CheckInfinity();
_res = NTA_GetResistance(target, damageType);
if(_res < 100)
return true;
if(_MWA_Merc_Weapon_Type == 1 && damageType >= NTA_DAMAGE_FIRE && damageType <= NTA_DAMAGE_COLD) // Infinity
{
if(target.GetState(28))
return false;
return (_res < 117 && NTC_GetMerc())
}
else if(_MWA_Merc_Weapon_Type == 2 && damageType == NTA_DAMAGE_PHYSICAL) // Reaper's Toll
{
if(MWA_GetCurseState(MWS_DECREPIFY, target) || MWA_GetCurseState(MWS_AMPLIFY_DAMAGE, target))
return false;
return (_res < 150 && NTC_GetMerc());
}
return false;
}
function MWA_CalcCorpseExplosionRadius()
{
// Calculate the approximate CE Range using a simple linear regression
if(me.GetSkill(74, true) > 0)
return (0.333684 * me.GetSkill(74, true) + 2.29632).toFixed(1);
else
return 0.0;
}
function MWA_GetClosestCorpseGID(x, y, range)
{
var _gid, _dist, _mindist, _corpses;
if(arguments.length < 3)
range = 50;
_mindist = 10000;
_gid = 0;
_corpses = NTC_FindUnit(NTC_UNIT_MONSTER);
if(_corpses)
{
do
{
if(MWL_CheckLootStatus(_corpses) && MWL_IsLootableMonster(_corpses.classid) && _corpses.name != GetLocaleString(5386) && _corpses.mode == 12) // Only check valid corpses that can be used for corpse explosion or minions
{
_dist = GetDistance(x, y, _corpses.x, _corpses.y);
if(_dist < _mindist && _dist <= range)
{
_mindist = _dist;
_gid = _corpses.gid;
}
}
} while(_corpses.GetNext());
}
return _gid;
}
function MWA_IsHazardousMonster(target)
{
var _viciousness, _damageType, _count;
_viciousness = 0;
_damageType = -1;
switch(target.classid)
{
// Physical damage (type 0)
case 310: // Doom Knight
case 312: // Oblivion Knight
case 472: // Hell Temptress WSK
case 510: // Death Lord WSK
case 571: // Minion Of Destruction
case 638: // Vile Witch WSK
case 691: // Undead Soul Killer Throne
case 700: // Doom Knight Throne
case 702: // Oblivion Knight Throne
_damageType = 0;
_viciousness++;
break;
// Elemental damage (type 1)
case 640: // Black Soul WSK
case 641: // Black Soul Throne
_damageType = 1;
_viciousness++;
break;
// Both physical and elemental damage (type -1)
case 345: // Council Member
case 346: // Council Member
case 347: // Council Member
case 362: // Venom Lord
case 558: // Venom Lord Throne
_viciousness++;
break;
}
_count = MWA_FindNearbyMonsters(6, target);
if(_count > 2)
_viciousness++;
else if(_count > 4)
_viciousness += 2;
else if(_count > 6)
_viciousness += 3;
if(target.GetState(29)) // Conviction
_viciousness += 2;
if(_damageType == 0 || _damageType == -1)
{
if(target.GetState(49)) // Fanatism
_viciousness += 2;
if(target.GetState(33) // Might
|| target.GetState(40)) // Blessed Aim
_viciousness++;
if(me.GetState(9) // Amplify Damage
|| me.GetState(60)) // Decrepify
_viciousness++;
}
if(_damageType == 1 || _damageType == -1)
{
if(me.GetState(28) // Convicted
|| me.GetState(61)) // Lower Resist
_viciousness++;
}
return _viciousness > 3;
}
function MWA_SetMinionCounts()
{
// Define the maximum amount of Skeletons
if(MWConfig_SkeletonMinionCount <= MWC_GetMaxMinionCount(NTConfig_AttackSkill[4]))
_MWA_Minion_Counts[0] = MWConfig_SkeletonMinionCount;
else
_MWA_Minion_Counts[0] = MWC_GetMaxMinionCount(NTConfig_AttackSkill[4]);
// Define the maximum amount of Mages
if(MWConfig_MageMinionCount <= MWC_GetMaxMinionCount(NTConfig_AttackSkill[5]))
_MWA_Minion_Counts[1] = MWConfig_MageMinionCount;
else
_MWA_Minion_Counts[1] = MWC_GetMaxMinionCount(NTConfig_AttackSkill[5]);
// Define the maximum amount of Revives
if(MWConfig_ReviveMinionCount <= MWC_GetMaxMinionCount(NTConfig_AttackSkill[6]))
_MWA_Minion_Counts[2] = MWConfig_ReviveMinionCount;
else
_MWA_Minion_Counts[2] = MWC_GetMaxMinionCount(NTConfig_AttackSkill[6]);
}
function MWA_RaiseMinions()
{
var _corpse, _gid, _gidsHandled, _count;
if(me.classid != NTC_CHAR_CLASS_NECROMANCER)
return false;
_gidsHandled = new Array();
MWA_SetMinionCounts();
for(var i = 0; i < 100; i++)
{
_gid = MWA_GetClosestCorpseGID(me.x, me.y, 30);
if(_gid == 0) // Stop if there are not any corpses nearby
break;
if(_gidsHandled.indexOf(_gid) > -1)
continue;
_corpse = NTC_FindUnit(NTC_UNIT_MONSTER, _gid); // Get the unit of the closest corpse
if(_corpse)
{
_gidsHandled.push(_gid);
if(NTC_GetSkillLevel(NTConfig_AttackSkill[4]) > 0) // Summon first minion type until the desired number of minions is reached
{
_count = MWC_GetMinionCount(NTConfig_AttackSkill[4]);
if(_count < _MWA_Minion_Counts[0] && (NTConfig_AttackSkill[4] != 95 || !(_corpse.spectype&0x0E)))
{
if(MWConfig_ShowOverheadStatus)
{
if(NTConfig_AttackSkill[4] == 95)
MWC_PrintOverheadStatus("Reviving " + _corpse.name + " (" + (_count + 1) + "/" +_MWA_Minion_Counts[0] + ")");
else
MWC_PrintOverheadStatus("Summoning " + MWC_GetMinionName(NTConfig_AttackSkill[4]) + " (" + (_count + 1) + "/" + _MWA_Minion_Counts[0] + ")");
}
if(GetDistance(me, _corpse) > _NTA_SkillRange[4] || !CheckCollision(me, _corpse, 4) || !CheckCollision(me, _corpse, 2))
NTM_MoveTo(_corpse.areaid, _corpse.x, _corpse.y, 0);
NTC_CastSkill(NTConfig_AttackSkill[4], _NTA_SkillHand[4], _corpse);
continue;
}
}
if(NTC_GetSkillLevel(NTConfig_AttackSkill[5]) > 0) // Summon second minion type until the desired number of minions is reached
{
_count = MWC_GetMinionCount(NTConfig_AttackSkill[5]);
if(_count < _MWA_Minion_Counts[1] && (NTConfig_AttackSkill[5] != 95 || !(_corpse.spectype&0x0E)))
{
if(MWConfig_ShowOverheadStatus)
{
if(NTConfig_AttackSkill[5] == 95)
MWC_PrintOverheadStatus("Reviving " + _corpse.name + " (" + (_count + 1) + "/" + _MWA_Minion_Counts[1] + ")");
else
MWC_PrintOverheadStatus("Summoning " + MWC_GetMinionName(NTConfig_AttackSkill[5]) + " (" + (_count + 1) + "/" + _MWA_Minion_Counts[1] + ")");
}
if(GetDistance(me, _corpse) > _NTA_SkillRange[4] || !CheckCollision(me, _corpse, 4) || !CheckCollision(me, _corpse, 2))
NTM_MoveTo(_corpse.areaid, _corpse.x, _corpse.y, 0);
NTC_CastSkill(NTConfig_AttackSkill[5], _NTA_SkillHand[5], _corpse);
continue;
}
}
if(NTC_GetSkillLevel(NTConfig_AttackSkill[6]) > 0) // Summon third minion type until the desired number of minions is reached
{
_count = MWC_GetMinionCount(NTConfig_AttackSkill[6]);
if(_count < _MWA_Minion_Counts[2] && (NTConfig_AttackSkill[6] != 95 || !(_corpse.spectype&0x0E)))
{
if(MWConfig_ShowOverheadStatus)
{
if(NTConfig_AttackSkill[6] == 95)
MWC_PrintOverheadStatus("Reviving " + _corpse.name + " (" + (_count + 1) + "/" + _MWA_Minion_Counts[2] + ")");
else
MWC_PrintOverheadStatus("Summoning " + MWC_GetMinionName(NTConfig_AttackSkill[6]) + " (" + (_count + 1) + "/" + _MWA_Minion_Counts[2] + ")");
}
if(GetDistance(me, _corpse) > _NTA_SkillRange[4] || !CheckCollision(me, _corpse, 4) || !CheckCollision(me, _corpse, 2))
NTM_MoveTo(_corpse.areaid, _corpse.x, _corpse.y, 0);
NTC_CastSkill(NTConfig_AttackSkill[6], _NTA_SkillHand[6], _corpse);
continue;
}
}
// Stop if the the maximum number of each minion type is reached
break;
}
}
return true;
}
function MWA_CalcAverageMinionDistance(unit)
{
var _monsters, _parent, _distances, _averageDist;
_averageDist = 0.0;
_distances = new Array();
if(arguments.length < 1)
unit = me;
_monsters = NTC_FindUnit(NTC_UNIT_MONSTER);
if(_monsters)
{
do
{
if(GetDistance(unit, _monsters) < 45)
{
_parent = _monsters.GetParent();
if(_parent && _parent.name == me.name) // Check whether the unit (Merc, Skeleton, Mage, Revive or Golem) actually belongs to our char
_distances.push(GetDistance(unit, _monsters));
}
} while(_monsters.GetNext());
}
// Calculate the average
for(var i = 0; i < _distances.length; i++)
_averageDist += _distances[i]; // Add all distances
if(_distances.length != 0)
_averageDist /= _distances.length; // Divide the sum by the number of distances
return _averageDist; // Return true if the majority of minions is sharing the same position as our char --> minions stuck
}
function MWA_GetCurseState(skillid, target)
{
if(!target || skillid < 66 || skillid > 91)
return false;
if((target.spectype & 0x04) && target.name.indexOf(GetLocaleString(11086)) != -1) // Ignore possessed champions that cannot be cursed
return true;
// Ignore foes that cannot be cursed anyway
switch(target.classid)
{
case 194: // Blood Maggot Egg
case 207: // Blood Hawk Nest
case 497: // Catapult
case 498: // Catapult
case 499: // Catapult
case 500: // Catapult
case 516: // Catapult
case 517: // Catapult
case 518: // Catapult
case 519: // Catapult
return true;
}
switch(skillid)
{
case 66: // Amplify Damage
return (target.GetState(9) != 0);
case 71: // Dim Vision
return (target.GetState(23) != 0);
case 72: // Weaken
return (target.GetState(19) != 0);
case 76: // Iron Maiden
return (target.GetState(55) != 0);
case 77: // Terror
return (target.GetState(56) != 0);
case 81: // Confuse
return (target.GetState(59) != 0);
case 82: // Life Tap
return (target.GetState(58) != 0);
case 86: // Attract
return (target.GetState(57) != 0);
case 87: // Decrepify
return (target.GetState(60) != 0);
case 91: // Lower Resist
return (target.GetState(61) != 0);
}
return false;
}
function MWA_CheckAttackTimeLimit(target)
{
var _tickLimit;
if(_MWA_Attack_Time.length > 0 && _MWA_Attack_Time[0] == target.gid) // If the target has been attacked before and its gid is saved in the array
{
_MWA_Attack_Time[3]++;
if(GetTickCount() > _MWA_Attack_Time[1] + _MWA_Attack_Time[2]) // Check if the time limit exceeded yet
{
Print("ÿc1Attack time limit exceeded! Skipping " + target.name + "...");
return true;
}
}
else // The target has not been attacked before
{
// Determine the end time in ticks using the limits specified in the char config
if((target.spectype & 0x02) && MWConfig_AttackTimeLimit[4] > 0) // Super Unique
_tickLimit = 1E3 * MWConfig_AttackTimeLimit[1];
else if((target.spectype & 0x04) && MWConfig_AttackTimeLimit[3] > 0) // Champion
_tickLimit = 1E3 * MWConfig_AttackTimeLimit[2];
else if((target.spectype & 0x08) && MWConfig_AttackTimeLimit[2] > 0) // Boss
_tickLimit = 1E3 * MWConfig_AttackTimeLimit[3];
else if((target.spectype & 0x10) && MWConfig_AttackTimeLimit[1] > 0) // Minion
_tickLimit = 1E3 * MWConfig_AttackTimeLimit[4];
else if(MWConfig_AttackTimeLimit[0] > 0) // All
_tickLimit = 1E3 * MWConfig_AttackTimeLimit[0];
else
_tickLimit = 2 * GetTickCount(); // Set Attack time to "infinite" if no time limit is defined
_MWA_Attack_Time = [target.gid, GetTickCount(), _tickLimit, 1]; // Save both the target's gid and the end time
}
return false;
}
function MWA_IsUndead(target)
{
if(arguments.lenth < 1 || !target)
return false;
switch(target.classid)
{
case 0: // Skeleton
case 1: // Returned
case 2: // Bone Warrior
case 3: // Burning Dead
case 4: // Horror
case 5: // Zombie
case 6: // Hungry Dead
case 7: // Ghoule
case 9: // Plague Bearer
case 38: // Ghost
case 40: // Specter
case 41: // Apparition
case 96: // Dried Corpse
case 98: // Embalmed
case 99: // Preserved Dead
case 101: // Hollow One
case 102: // Guardian
case 103: // Unraveler
case 104: // Horadrim Ancient
case 105: // Unraveler
case 111: // Undead Scavenger
case 131: // Ghoul Lord
case 132: // Night Lord
case 133: // Dark Lord
case 134: // Blood Lord
case 135: // The Banished
case 170: // Skeleton Archer
case 171: // Returned Archer
case 172: // Bone Archer
case 174: // Horror Archer
case 215: // Undead Soul Killer
case 276: // Bone Ash
case 306: // Storm Caster
case 310: // Doom Knight
case 311: // Abyss Knight
case 312: // Oblivion Knight
case 365: // Griswold
case 381: // Death Mage
case 383: // Returned Mage
case 384: // Bone Mage
case 385: // Burning Dead mage
case 387: // Returned Mage
case 388: // Bone Mage
case 390: // Horror Mage
case 437: // Reanimated Horde
case 438: // Prowling Dead
case 440: // Defiled Warrior
case 578: // Returned Archer
case 608: // Carrion Bird
case 620: // Returned Mage
case 622: // Returned Mage
case 623: // Horror Mage
case 624: // Bone Mage
case 626: // Horror Mage
case 640: // Black Soul
case 641: // Black Soul Throne
case 669: // Horadrim Ancient
case 670: // Horadrim Ancient
case 696: // Ghoul Lord
case 697: // Dark Lord
case 698: // Unholy Corpse
case 691: // Undead Soul Killer
case 700: // Doom Knight
case 702: // Oblivion Knight
case 713: // Oblivion Knight
case 726: // Horror Archer
case 727: // Burning Dead Mage
case 728: // Horror Mage
case 729: // Bone Mage
case 730: // Horror Mage
case 731: // Dark Lord
return true;
}
return false;
}
function MWA_IsPriorityTarget(target)
{
if(arguments.lenth < 1 || !target)
return false;
switch(target.classid)
{
case 58: // Fallen Shaman
case 59: // Carver Shaman
case 60: // Devilkin Shaman
case 61: // Dark Shaman
case 62: // Warped Shaman
case 68: // Sand Maggot
case 69: // Rock Worm
case 70: // Devourer
case 101: // Hollow One
case 102: // Guardian
case 103: // Unraveler
case 104: // Horadrim Ancient
case 105: // Unraveler
case 207: // Blood Hawk Nest
case 238: // Sexton
case 240: // Heirophant
case 279: // Fetish Shaman
case 280: // Flayer Shaman
case 281: // Soul Killer Shaman
case 298: // Flesh Spawner
case 299: // Stygian Hag
case 300: // Grotesque
case 646: // Devilkin Shaman
case 669: // Horadrim Ancient
case 670: // Horadrim Ancient
case 674: // Heirophant
case 676: // Flesh Spawner
return true;
}
return false;
}
function MWA_PrintAttackStatus(type, target)
{
var _output, _attackTimeString;
if(!MWConfig_ShowOverheadStatus || arguments.length < 2)
return false;
_attackTimeString = "";
switch(type)
{
case 1:
_output = "Killing ";
break;
default:
_output = "Attacking ";
break;
}
if(target.gid == _MWA_Attack_Time[0] && GetTickCount() - _MWA_Attack_Time[1] > 5E3)
_attackTimeString = " [" + MWC_ConvertTicksToTimeString(GetTickCount() - _MWA_Attack_Time[1]) + "]";
if(target.hp / target.hpmax > 0)
return MWC_PrintOverheadStatus(_output + target.name + " " + (target.hp * 100 / target.hpmax).toFixed(0) + "%" + _attackTimeString);
else
return MWC_PrintOverheadStatus("Killed " + target.name + "!");
}
function MWA_Traps(target)
{
this.Active;
this.Target = target;
this.MAXQUANTITY = 5;
this.GetTrapPosition = MWA_Traps_GetTrapPosition;
this.Refresh = MWA_Traps_Refresh;
this.GetQuantity = MWA_Traps_GetQuantity;
this.Refresh();
}
function MWA_Trap(unit)
{
this.X = unit.x;
this.Y = unit.y;
this.GID = unit.gid;
this.ClassID = unit.classid;
this.Mode = unit.mode;
this.RANGE = 20;
this.IsValid = MWA_Trap_IsValid;
}
function MWA_Trap_IsValid(target)
{
var _trap;
if(!target)
return false;
_trap = NTC_FindUnit(NTC_UNIT_MONSTER, this.GID);
if(!_trap || _trap.mode == 12) // The trap is either really far aways or already fired all its shots
return false;
if(_trap.mode == 8) // Traps that are currently fireing are considered valid
return true;
if(!CheckCollision(target, _trap, 2)) // The trap cannot attack the current target due to obstacles
return false;
if(GetDistance(this.X, this.Y, target.x, target.y) > this.RANGE) // The target is too far away from the trap
return false;
if(GetDistance(this.X, this.Y, me.x, me.y) > 40) // The trap is too far away from us
return false;
return true;
}
function MWA_Traps_GetTrapPosition(range)
{
var _pos, _trapPos, _vec, _vecOrtho;
const _DIST = 4;
if(!this.Target || arguments.length < 1)
return null;
_pos = me.GetOptimalAttackPos(this.Target.areaid, this.Target.x, this.Target.y, range, 4);
if(_pos)
{
_vec = new vector(this.Target.x - _pos[0], this.Target.y - _pos[1]);
if(_vec)
{
_vecOrtho = new vector(_vec.x, _vec.y);
if(_vecOrtho)
{
_vecOrtho.rotate(90);
switch(this.Active.length)
{
case 4:
_vec.setlength(_DIST);
_vecOrtho.setlength(_DIST);
break;
case 3:
_vec.setlength(_DIST);
_vecOrtho.setlength(-1 * _DIST);
break;
case 2:
_vec.setlength(_DIST / 2);
_vecOrtho.setlength(_DIST / 2);
break;
case 1:
_vec.setlength(_DIST / 2);
_vecOrtho.setlength(_DIST / -2);
break;
default:
return new coord(_pos[0], _pos[1]);
}
_trapPos = new coord(Math.round(_pos[0] + _vec.x + _vecOrtho.x), Math.round(_pos[1] + _vec.y + _vecOrtho.y));
if(_trapPos && CheckCollision(this.Target.areaid, _trapPos.x, _trapPos.y, 0))
return _trapPos;
}
}
return new coord(_pos[0], _pos[1]);
}
return null;
}
function MWA_Traps_GetQuantity(skillid)
{
var _count, _classid;
_count = 0;
switch(skillid)
{
case MWS_CHARGED_BOLT_SENTRY:
_classid = MWC_MINION_CHARGED_BOLT_SENTRY;
break;
case MWS_WAKE_OF_FIRE:
_classid = MWC_MINION_WAKE_OF_FIRE;
break;
case MWS_LIGHTNING_SENTRY:
_classid = MWC_MINION_LIGHTNING_SENTRY;
break;
case MWS_WAKE_OF_INFERNO:
_classid = MWC_MINION_WAKE_OF_INFERNO;
break;
case MWS_DEATH_SENTRY:
_classid = MWC_MINION_DEATH_SENTRY;
break;
}
for(var i = 0; i < this.Active.length; i++)
{
if(this.Active[i].IsValid(this.Target) && this.Active[i].ClassID == _classid)
_count++;
}
return _count;
}
function MWA_Traps_Refresh(target)
{
var _unit, _trap;
this.Active = new Array();
this.Target = target;
_unit = NTC_FindUnit(NTC_UNIT_MONSTER);
if(_unit)
{
do
{
if(!_unit.IsAttackable() && (_unit.classid >= MWC_MINION_WAKE_OF_FIRE && _unit.classid <= MWC_MINION_LIGHTNING_SENTRY || _unit.classid >= MWC_MINION_WAKE_OF_INFERNO && _unit.classid <= MWC_MINION_DEATH_SENTRY))
{
if(NTC_CheckOwner(_unit))
{
_trap = new MWA_Trap(_unit);
if(_trap && _trap.IsValid(this.target))
this.Active.push(_trap);
}
}
} while(_unit.GetNext());
return true;
}
return false;
}