Code:
//
// NTCommon.ntl - Commonly used base functions.
//
// Last modified: 2012-09-18 mickey
//
// Include color constants
Include("libs/common/NTColor.ntl");
// Character Classes
const NTC_CHAR_CLASS_AMAZON = 0;
const NTC_CHAR_CLASS_SORCERESS = 1;
const NTC_CHAR_CLASS_NECROMANCER = 2;
const NTC_CHAR_CLASS_PALADIN = 3;
const NTC_CHAR_CLASS_BARBARIAN = 4;
const NTC_CHAR_CLASS_DRUID = 5;
const NTC_CHAR_CLASS_ASSASSIN = 6;
const NTC_CHAR_CLASS_NAMES =
[
"Amazon", "Sorceress", "Necromancer", "Paladin", "Barbarian", "Druid", "Assassin"
];
// Act 1 NPCs
const NTC_NPC_ID_AKARA = 148;
const NTC_NPC_ID_WARRIV_ACT_1 = 155;
const NTC_NPC_ID_CHARSI = 154;
const NTC_NPC_ID_GHEED = 147;
const NTC_NPC_ID_KASHYA = 150;
const NTC_NPC_ID_CAIN_TRISTRAM = 146;
const NTC_NPC_ID_CAIN_ACT_1 = 265;
// Act 2 NPCs
const NTC_NPC_ID_FARA = 178;
const NTC_NPC_ID_LYSANDER = 202;
const NTC_NPC_ID_GREIZ = 198;
const NTC_NPC_ID_ELZIX = 199;
const NTC_NPC_ID_MESHIF_ACT_2 = 210;
const NTC_NPC_ID_DROGNAN = 177;
const NTC_NPC_ID_ATMA = 176;
const NTC_NPC_ID_WARRIV_ACT_2 = 175;
const NTC_NPC_ID_CAIN_ACT_2 = 244;
const NTC_NPC_ID_JERHYN = 201;
const NTC_NPC_ID_TYRAEL_ACT_2 = 251;
// Act 3 NPCs
const NTC_NPC_ID_MESHIF_ACT_3 = 264;
const NTC_NPC_ID_CAIN_ACT_3 = 245;
const NTC_NPC_ID_ALKOR = 254;
const NTC_NPC_ID_ASHEARA = 252;
const NTC_NPC_ID_ORMUS = 255;
const NTC_NPC_ID_HRATLI = 253;
// Act 4 NPCs
const NTC_NPC_ID_CAIN_ACT_4 = 246;
const NTC_NPC_ID_HALBU = 257;
const NTC_NPC_ID_TYRAEL_ACT_4 = 367;
const NTC_NPC_ID_JAMELLA = 405;
// Act 5 NPCs
const NTC_NPC_ID_CAIN_ACT_5 = 520;
const NTC_NPC_ID_TYRAEL_ACT_5 = 521;
const NTC_NPC_ID_LARZUK = 511;
const NTC_NPC_ID_ANYA_FROZEN_RIVER = 527;
const NTC_NPC_ID_ANYA_TOWN = 512;
const NTC_NPC_ID_MALAH = 513;
const NTC_NPC_ID_QUALKEHK = 515;
const NTC_NPC_ID_NIHLATHAK_TOWN = 514;
const NTC_NPC_ID_NIHLATHAK_HALLS_OF_VAUGHT = 526;
// UNIT types
const NTC_UNIT_PLAYER = 0;
const NTC_UNIT_NPC = 1;
const NTC_UNIT_MERC = NTC_UNIT_NPC;
const NTC_UNIT_MONSTER = NTC_UNIT_NPC;
const NTC_UNIT_OBJECT = 2;
const NTC_UNIT_MISSILE = 3;
const NTC_UNIT_ITEM = 4;
const NTC_UNIT_TILE = 5;
const NTC_UNIT_STASH = 267;
const NTC_UNIT_CUBE = 549;
// Town area IDs for all acts
const NTC_AREA_ID_ACT_1 = 1;
const NTC_AREA_ID_ACT_2 = 40;
const NTC_AREA_ID_ACT_3 = 75;
const NTC_AREA_ID_ACT_4 = 103;
const NTC_AREA_ID_ACT_5 = 109;
const NTC_AREA_ID_TOWN =
[
-1, NTC_AREA_ID_ACT_1, NTC_AREA_ID_ACT_2, NTC_AREA_ID_ACT_3, NTC_AREA_ID_ACT_4, NTC_AREA_ID_ACT_5
];
// Skill hand
const NTC_HAND_RIGHT = 0;
const NTC_HAND_LEFT = 1;
// Mouse button actions
const NTC_CLICK_LDOWN = 0;
const NTC_CLICK_LHOLD = 1;
const NTC_CLICK_LUP = 2;
const NTC_CLICK_RDOWN = 3;
const NTC_CLICK_RHOLD = 4;
const NTC_CLICK_RUP = 5;
const NTC_SHIFT_NONE = 0;
const NTC_SHIFT_HOLD = 1;
// Item qualities
const NTC_ITEM_QUALITY_NAMES =
[
"None", "Low Quality", "Normal", "Superior", "Magic", "Set", "Rare", "Unique", "Crafted"
];
// Misc
const NTC_LOG_COMMON = 0;
const NTC_LOG_ITEM = 1;
const NTC_DELAY_FRAME = 40;
// Cached merc.
var _NTC_MERC = null;
//
// Load the character configuration file from the specified path.
//
function NTC_LoadConfig(path)
{
var _charclass = NTC_CHAR_CLASS_NAMES[me.classid];
var _cfgfile = "NTConfig_" + _charclass + "_" + me.charname + ".ntl";
var _cfghandle = FileOpen(path + "/" + _cfgfile, 0);
if(_cfghandle)
{
_cfghandle.Close();
}
else
{
Print(C_RED + "WARNING: " + C_WHITE + "cannot find char config '"
+ C_GREY + _cfgfile + C_WHITE + "' - using default config.");
_cfgfile = "NTConfig_" + _charclass + ".ntl";
}
Include(path + "/NTConfig.ntl");
Include(path + "/NTConfig_Defaults.ntl");
Include(path + "/" + _cfgfile);
NT_SetupDefaults();
NT_SetupConfig();
}
//
// Include all commonly used libraries.
//
function NTC_IncludeLibs()
{
Include("libs/classes/Vector.ntl");
Include("libs/classes/Point.ntl");
Include("libs/classes/Area.ntl");
Include("libs/classes/Spot.ntl");
Include("libs/classes/Rect.ntl");
Include("libs/common/NTData.ntl");
Include("libs/common/NTSkills.ntl");
Include("libs/common/NTClass" + NTC_CHAR_CLASS_NAMES[me.classid] + ".ntl");
Include("libs/common/NTAttack.ntl");
Include("libs/common/NTCubing.ntl");
Include("libs/common/NTItemParser.ntl");
Include("libs/common/NTMove.ntl");
Include("libs/common/NTObjects.ntl");
Include("libs/common/NTPrecast.ntl");
Include("libs/common/NTSnagIt.ntl");
Include("libs/common/NTTown.ntl");
Include("libs/common/NTTownManager.ntl");
Include("libs/common/NTTownMove.ntl");
Include("libs/common/NTLog.ntl");
Include("libs/common/NTItemLog.ntl");
}
//
// Cast the specified skill.
//
// Returns true if successful, false in case of failure.
//
function NTC_CastSkill(skillid, usehand, x, y)
{
var _hand, _shift, _mode;
var i, n;
if(arguments.length < 1)
return false;
if(arguments.length === 1)
{
_hand = NTC_CLICK_RDOWN;
_shift = NTC_SHIFT_NONE;
usehand = NTC_HAND_RIGHT;
}
else
{
if(usehand === NTC_HAND_RIGHT)
{
_hand = NTC_CLICK_RDOWN;
_shift = NTC_SHIFT_NONE;
}
else if(usehand === NTC_HAND_LEFT)
{
_hand = NTC_CLICK_LDOWN;
_shift = NTC_SHIFT_NONE;
}
else
{
_hand = NTC_CLICK_LDOWN;
_shift = NTC_SHIFT_HOLD;
usehand = NTC_HAND_LEFT;
}
}
if(NTC_PutSkill(skillid, usehand))
{
if(!NTC_ClearCursor())
return false;
for(i = 0; i < 5; i++)
{
switch(arguments.length)
{
case 1:
case 2:
ClickMap(_hand, _shift, me.x, me.y);
break;
case 3:
if(!ClickMap(_hand, _shift, x))
{
Delay(NTC_DELAY_FRAME);
return false;
}
break;
default:
ClickMap(_hand, _shift, x, y);
break;
}
for(n = 0; n < 4; n++)
{
Delay(NTC_DELAY_FRAME);
_mode = me.mode;
if(_mode === 7 || _mode === 8 || (_mode >= 10 && _mode <= 16) || _mode === 18)
{
Delay(NTC_DELAY_FRAME);
break;
}
}
ClickMap(_hand + 2, NTC_SHIFT_NONE, null);
if(n < 4)
{
for(i = 0; i < 100; i++)
{
Delay(20);
if(me.mode !== _mode)
break;
}
return true;
}
Delay(NTC_DELAY_FRAME);
}
}
return false;
}
//
// Select a skill for the specified hand.
//
// Returns true if successful, false in case of failure.
//
function NTC_PutSkill(skillid, hand)
{
if(me.GetSkill(hand) === skillid)
return true;
if(GetBaseStat("skills.txt", skillid, 182) || NTC_GetSkillLevel(skillid) < 1)
return false;
return me.SetSkill(skillid, hand);
}
//
// Get the skill level of specified skill, including plus skills.
//
// Returns level of specified skill.
//
function NTC_GetSkillLevel(skillid)
{
var _lvl = me.GetSkill(skillid, true);
return (_lvl != null ? _lvl : 0);
}
//
// Get the name of the specified skill.
//
// Returns a string representation for the specified skillid.
//
function NTC_GetSkillName(skillid)
{
var _name = GetBaseStat("skills.txt", skillid, 0);
return (_name != null ? _name : "-unknown-");
}
//
// Get the casting delay for the specified skill.
//
// Returns casting delay in ms for the specified skillid.
//
function NTC_GetCastDelay(skillid)
{
var _delay = GetBaseStat("skills.txt", skillid, 165);
return (_delay != null ? _delay * NTC_DELAY_FRAME : 0);
}
//
// Switch the active weapons tab.
//
// Returns true if successful, or fals in case of failure.
//
function NTC_SwapWeapons(switchto)
{
if(arguments.length > 0 && me.weaponstab === switchto)
return true;
NTC_PingDelay(200);
if(!NTC_WaitIdleMode())
return false;
return me.SwapWeapons();
}
//
// Perform a click upon the designated map coordinates.
//
// Returns true if successful, or false in case of failure.
//
function NTC_DoClick(button, shift, x, y)
{
if(arguments.length >= 2)
{
if(button !== NTC_CLICK_LDOWN)
button = NTC_CLICK_RDOWN;
switch(arguments.length)
{
case 2: ClickMap(button, shift, me.x, me.y);
break;
case 3: if(!ClickMap(button, shift, x))
return false;
break;
default: ClickMap(button, shift, x, y);
break;
}
Delay(200);
ClickMap(button + 2, NTC_SHIFT_NONE, null);
return true;
}
return false;
}
//
// Get the character's total amount of gold (stash + inventory).
//
// Returns total amount of gold.
//
function NTC_MyGold()
{
return me.GetStat(14) + me.GetStat(15);
}
//
// Get the amount of gold currently in the character's inventory.
//
// Returns current amount of gold carried.
//
function NTC_MyGoldCarry()
{
return me.GetStat(14);
}
//
// Check if the stash has reached it's maximum gold capacity.
//
// Returns true if stash has reached maximum gold capacity, false otherwise.
//
function NTC_StashGoldFull()
{
return (me.GetStat(15) >= 2500000);
}
//
// Check if the character's inventory has reached it's maximum gold capacity.
//
// Returns true if the character's inventory cannot carry any more gold, false otherwise.
//
function NTC_CharGoldFull()
{
return (me.GetStat(14) >= (me.GetStat(12) * 10000));
}
//
// Check the owner of a given object.
//
// Returns true if given object belongs to the designated owner,
// or self if owner is unspecified, otherwise false is returned.
//
function NTC_CheckOwner(object, ownername)
{
var _owner;
if(object)
{
_owner = object.GetParent();
if(_owner)
{
return (arguments.length < 2 ? (_owner === me.name || _owner.name === me.name)
: (_owner === ownername || _owner.name === ownername));
}
}
return false;
}
//
// Move an item to the cursor.
//
// Returns true if successful, or false in case of failure.
//
function NTC_ItemToCursor(item)
{
if(me.itemoncursor)
return true;
for(var i = 0; i < 80; i++)
{
if((i % 40) === 0)
me.ClickItem(0, item);
Delay(100);
if(me.itemoncursor)
{
NTC_PingDelay(200);
return true;
}
}
return false;
}
//
// Drop the item that is currently on the cursor.
//
// Returns true if successful, or false in case of failure.
//
function NTC_ClearCursor()
{
if(!me.itemoncursor)
return true;
for(var i = 0 ; i < 40 ; i++)
{
if((i % 20) === 0)
NTC_DoClick(NTC_CLICK_LDOWN, NTC_SHIFT_NONE);
Delay(100);
if(!me.itemoncursor)
return true;
}
return false;
}
//
// Get our merc.
//
// Returns our merc, or null in case we have none or he's dead.
//
function NTC_GetMerc()
{
if(!_NTC_MERC)
_NTC_MERC = me.GetMerc();
return (_NTC_MERC && _NTC_MERC.hp > 0 && _NTC_MERC.mode !== 0 && _NTC_MERC.mode !== 12 ? _NTC_MERC : null);
}
//
// Delay execution by a specified amount of time, possibly adding a random timespan.
//
function NTC_Delay(amount, random)
{
Delay(arguments.length < 2 ? amount : amount + Random(0, random));
}
//
// Delay execution by a specified amount of time, factoring for current ping.
//
function NTC_PingDelay(amount)
{
var _ping = me.ping;
NTC_Delay(_ping > 100 ? amount + _ping - 100 : amount);
}
//
// Check if the character is currently in town.
//
// Returns true if in town, false otherwise.
//
function NTC_InTown(who)
{
var _areaid;
if(arguments.length < 1)
who = me;
while((_areaid = who.areaid) === 0)
Delay(NTC_DELAY_FRAME);
switch(_areaid)
{
case NTC_AREA_ID_ACT_1:
case NTC_AREA_ID_ACT_2:
case NTC_AREA_ID_ACT_3:
case NTC_AREA_ID_ACT_4:
case NTC_AREA_ID_ACT_5: return true;
}
return false;
}
//
// Check if designated player is in our party.
//
// Returns true if given player is in our party, false otherwise.
//
function NTC_InMyParty(playerName)
{
var _player = GetPlayerUnit();
var _myPartyId;
if(_player)
{
_myPartyId = _player.partyid;
if(_myPartyId !== 65535)
{
do
{
if(_player.name.toLowerCase() === playerName.toLowerCase() && _myPartyId === _player.partyid)
return true;
} while(_player.GetNext());
}
}
return false;
}
//
// Find units of the designated type.
//
// Returns unit, or null if none was found.
//
function NTC_FindUnit(unittype, search, retry)
{
var _unit;
switch(arguments.length)
{
case 0: return null;
case 1: search = null;
case 2: retry = 0;
break;
}
for(var i = 0; i <= retry; i++)
{
if((_unit = GetUnit(unittype, search)))
return _unit;
if(i < retry)
Delay(200);
}
return null;
}
//
// Find minions of the specified type, belonging to the player.
//
// Returns minion or null, if none was found.
//
function NTC_FindMinion(classid)
{
var _u = NTC_FindUnit(NTC_UNIT_NPC, classid);
if(_u)
{
do
{
if(NTC_CheckOwner(_u))
return _u;
} while (_u.GetNext());
}
return null;
}
//
// Get the number of rows of the currently equipped belt.
//
// Returns the number of belt rows (1-4).
//
function NTC_GetBeltSize()
{
var _items = me.GetItems();
if(_items)
{
for(var i = _items.length; i--; )
{
if(_items[i].mode === 1 && _items[i].itemloc === 8)
{
switch(_items[i].classid)
{
case 344: // Sash
case 345: // Light Belt
return 2;
case 346: // Belt
case 347: // Heavy Belt
return 3;
default: return 4;
}
}
}
}
return 1;
}
//
// Find the specified script.
//
// Returns script, or null if the specified script was not found.
//
function NTC_FindScript(scriptname)
{
var _script = GetScript();
var _scriptpath;
if(_script)
{
do
{
_scriptpath = _script.name.toLowerCase();
if(_scriptpath.indexOf(scriptname.toLowerCase()) > -1)
return _script;
} while(_script.GetNext());
}
return null;
}
//
// Send a message to a script.
//
// Returns true if successful, or false in case of failure.
//
function NTC_SendMsgToScript(scriptname, msg)
{
var _script = NTC_FindScript(scriptname);
return (_script ? _script.Send(msg) : false);
}
//
// Stop execution of the designated script.
//
// Returns true if given script is stopped, or false in case of failure.
//
function NTC_StopScript(scriptname)
{
var _script = NTC_FindScript(scriptname);
return (_script ? _script.running ? _script.Stop() : true : false);
}
//
// Wait for a maximum of 25 frames for the character to become idle.
//
// Returns true if character is now idle, false if timed out.
//
function NTC_WaitIdleMode()
{
for(var i = 0; i < 25; i++)
{
switch(me.mode)
{
case 1: // Player standing outside town
case 2: // Player walking
case 3: // Player running
case 5: // Player standing in town
case 6: // Player walking in town
return true;
}
Delay(NTC_DELAY_FRAME);
}
return false;
}
//
// Send a message to the OOG log.
//
// Returns true if successful, or false in case of failure.
//
function NTC_SendLogToOOG(type, logString)
{
return SendCopyData("D2NT Manager", null, 9 << 16 | type, logString);
}
//
// Get a color code string, appropriate for displaying the specified item.
// mgr: If true, swap black/white for display in OOG manager tooltip texts.
//
// Returns color code string for the given item.
//
function NTC_ItemColor(item, mgr)
{
if(arguments.length < 2)
mgr = false;
if(arguments.length >= 1 && item)
{
// Special Orange colored items: Runes, Keys, Organs, Tokens, Essences
if(item.itemtype === 74 || (item.classid >= 647 && item.classid <= 657))
return C_ORANGE;
// Special Gold colored items: Horadric cube, horadric scroll, ...
if(item.classid >= 544 && item.classid <= 555)
return C_GOLD;
// Map color according to item quality if nothing else fits
switch(item.quality)
{
case 0:
case 1:
case 2:
case 3:
if((item.itemflag & 0x400000) || item.GetStat(194))
return C_GREY;
return (mgr ? C_BLACK : C_WHITE);
case 4: return C_BLUE;
case 5: return C_GREEN;
case 6: return C_YELLOW;
case 7: return C_GOLD;
case 8: return C_ORANGE;
}
}
return "";
}
//
// Check if a space of the given dimensions is available within the character's inventory.
//
// Returns true if space is available, false otherwise.
//
function NTC_CheckSpace(width, height)
{
var _items, _inv;
var i, x, y, w;
// Print("Need " + width + "x" + height + " space");
if(width > 0 && width < 11 && height > 0 && height < 5)
{
_items = me.GetItems();
if(_items)
{
_inv = [0, 0, 0, 0];
for(i = _items.length; i--; )
{
if(_items[i].mode === 0 && _items[i].itemloc === 0)
{
for(x = w = 0; x < _items[i].xsize; x++)
w |= (1 << _items[i].x + x);
for(y = 0; y < _items[i].ysize; y++)
_inv[_items[i].y + y] |= w;
}
}
for(x = w = 0; x < width; x++)
w |= (1 << x);
for(y = 0; y < 5 - height; y++)
{
for(x = 0; x < 11 - width; x++)
{
for(i = 0; i < height && !(_inv[y + i] & (w << x)); i++);
if(i === height)
{
// Print("Found space @" + x + "," + y);
return true;
}
}
}
}
}
// Print("No space");
return false;
}
//
// Substitute placeholders in a given string.
//
// Valid placeholders are:
// %gn - Current game name i.e. 'MyBaal-01'
// %gc - Current game count i.e. '01'
// %gp - Current game password i.e. 'topsecret'
// %gd - Current game designator i.e. 'MyBaal-01//topsecret'
// %ngn - Next game name i.e. 'MyBaal-02'
// %ngc - Next game count i.e. '02'
// %ngd - Next game designator i.e. 'MyBaal-02//topsecret'
//
// Returns the input string with substitutions.
//
function NTC_FmtString(str)
{
var gn = me.gamename;
var gp = me.gamepassword;
var gc, gd, ngc, ngd, ngn;
var idx, cnt;
if(!str || !str.length)
return "";
if(gn && (idx = gn.lastIndexOf("-")) > -1)
{
cnt = parseInt(gn.slice(idx + 1), 10);
gd = gn + (gp && gp.length > 0 ? "//" + gp : "");
gc = (cnt < 10 ? "0" : "") + cnt;
ngc = (cnt >= 99 ? "00" : (cnt < 9 ? "0" : "") + (cnt + 1));
ngn = gn.slice(0, idx + 1) + ngc;
ngd = ngn + (gp && gp.length > 0 ? "//" + gp : "");
}
else
{
gn = ngn = gd = ngd = gc = ngc = "";
}
if(!gp)
gp = "";
str = str.replace("%gn", gn).replace("%gc", gc).replace("%gp", gp).replace("%gd", gd);
str = str.replace("%ngn", ngn).replace("%ngc", ngc).replace("%ngd", ngd);
return str;
}
//
// Say the given game message, splitting up multi-line messages.
//
function NTC_SayGameMsg(msg)
{
var _line = NTC_FmtString(msg).split("\n");
for(var i = 0; i < _line.length; i++)
{
Say(_line[i]);
Delay(50);
}
}
//
// Write a message to a debug log file.
//
function NTC_DebugLog(msg)
{
var _date = new Date().toLocaleFormat("<%d.%m.%Y %H:%M:%S> ");
var _fn = "Debug_" + me.charname + ".txt";
var _fd = FileOpen(_fn, 2);
if(!_fd)
_fd = FileOpen(_fn, 1);
_fd.WriteLine(_date + msg);
_fd.Close();
}