// no colors to convert /* [Item-parser Syntax Information] 1. [Keyword] separates into three groups - [Property Keywords] : [Type], [Name], [Class], [Quality], [Flag], [Level], [Prefix], [Suffix] - [Stat Keywords] : [Number or Alias] - [Quantity Keywords] : [MaxQuantity] 2. [Keyword] must be surrounded by '[' and ']' 3. [Property Keywords] must be placed first 4. Valid in the Stat section is the keyword description where [description] = "any part of item description" <- must be contained inside quotes e.g. [type] == armor && [quality] == magic # [description] == "required level: 25" 5. Insert '#' symbol between [Property Keywords] and [Stat Keywords] 6. Insert '#' symbol between [Stat Keywords] and [Quantity Keywords] 7. Use '+', '-', '*', '/', '(', ')', '&&', '||', '>', '>=', '<', '<=', '==', '!=' symbols for comparison 8. Use '//' symbol for comment */ Include("libs/common/NTItemAlias.ntl"); var _NTIP_CheckList = new Array(); function NTIPOpenFile(filepath) { var _nipfile; var _line, _originalLine; var _lineNumber = 0; var errorCaught = false; var item; var items = me.GetItems(); if (items) { for(var i = 0 ; i < items.length ; i++) { thisItem = items[i]; item = thisItem; } } else { Print (COLOR_1 + "Fatal Error! Character stash/inventory/body is all completely empty!"); Delay(20000); return false; } _nipfile = FileOpen(filepath, 0); if (!_nipfile) return false; while(!_nipfile.eof) { var tempCheckList = new Array(); _lineNumber++; _originalLine = _nipfile.ReadLine(); _line = NTIPParseLineInt(_originalLine); if(_line) { tempCheckList.push(_line); try { if(tempCheckList[0][0].length > 0) if (eval(tempCheckList[0][0])); if(tempCheckList[0][1].length > 0) if (eval(tempCheckList[0][1])); if(tempCheckList[0][2].length > 0) if (eval(tempCheckList[0][2])); } catch(err) { Print (COLOR_1 + "Error in NIP, line ignored: " + filepath + ", line: " + _lineNumber); errorCaught = true; _line = ""; } } if(_line && _line != "") { _line.push(filepath); _line.push(_lineNumber); _NTIP_CheckList.push(_line); } } _nipfile.Close(); if (errorCaught) Print (COLOR_1 + "Please use the numpad + key to run the NipChecker!"); return true; } function NTIPCheckItem(item) { var _identified = item.itemflag & 0x10; var resultArray = new Array(); resultArray[0] = 0; try { for(i = 0 ; i < _NTIP_CheckList.length ; i++) { resultArray[1] = _NTIP_CheckList[i][3]; resultArray[2] = _NTIP_CheckList[i][4]; if(_NTIP_CheckList[i][0].length > 0) { if(eval(_NTIP_CheckList[i][0])) { if(_NTIP_CheckList[i][1].length > 0) { if(eval(_NTIP_CheckList[i][1])) {return (NTIP_CheckQuantity(item,i,resultArray));} else if(!_identified && resultArray[0] == 0) {resultArray[0] = -1; return resultArray;} } else {return (NTIP_CheckQuantity(item,i,resultArray));} } } else if(_NTIP_CheckList[i][1].length > 0) { if(eval(_NTIP_CheckList[i][1])) {return (NTIP_CheckQuantity(item,i,resultArray));} else if(!_identified && resultArray[0] == 0) {resultArray[0] = -1; return resultArray;} } } } catch(err) { resultArray[0] = 0; SendCopyData("D2NT Manager", null, (D2NT_MGR_PRINT_LOG<<16), "NTIPCheckItem: Bad NIP detected: " + _NTIP_CheckList[i][0] + "#" + _NTIP_CheckList[i][1] + "#" + _NTIP_CheckList[i][2] + ": " + _NTIP_CheckList[i][3] + ", " + _NTIP_CheckList[i][4]); SendCopyData("D2NT Manager", null, (D2NT_MGR_PRINT_LOG<<16), " Error: " + err); } return resultArray; } function NTIP_CheckQuantity(item,i,resultArray) { resultArray[0] = 0; if(_NTIP_CheckList[i][2] && _NTIP_CheckList[i][2]["MaxQuantity"] && !isNaN(_NTIP_CheckList[i][2]["MaxQuantity"])) { var phrase0 = _NTIP_CheckList[i][0]; var phrase1 = _NTIP_CheckList[i][1]; if (_NTIP_CheckList[i][0].length <= 0) {phrase0=null;} if (_NTIP_CheckList[i][1].length <= 0) {phrase1=null;} if(NTIP_CheckQuantityOwned(phrase0, phrase1, false) < _NTIP_CheckList[i][2]["MaxQuantity"]) { //Print("I need more of these "+NTC_ItemQualityToMGRColor[item.quality] + item.itemdesc.split("\n")[0].substring(3)); resultArray[0] = 1; } else { //Print("I already have enough of these "+NTC_ItemQualityToMGRColor[item.quality] + item.itemdesc.split("\n")[0].substring(3)+" in my stash!"); resultArray[0] = 0; } } else {resultArray[0] = 1;} return resultArray; } // Internal function function NTIP_CheckQuantityOwned(item_type, item_stats, check_inventory_too) { var _nb = 0; var _items = me.GetItems(); if (!_items) { Print("I can't find my items!"); return 0; } for(var i = 0 ; i < _items.length ; i++) { if(_items[i].mode == 0 && _items[i].itemloc == 4) { var item = _items[i]; if((item_type != null && item_type.length > 0 && eval(item_type)) || item_type == null) if((item_stats != null && item_stats.length > 0 && eval(item_stats)) || item_stats == null) _nb++; } else if(check_inventory_too && _items[i].mode == 0 && _items[i].itemloc == 0) { var item = _items[i]; if((item_type != null && item_type.length > 0 && eval(item_type)) || item_type == null) if((item_stats != null && item_stats.length > 0 && eval(item_stats)) || item_stats == null) if(NTConfig_Columns[_items[i].y][_items[i].x] > 0) // we check only space that is supposed to be free _nb++; } } //Print("I have "+_nb+" of these."); return _nb; } function NTIPParseLineInt(input) { var i; var _start, _end; var _section, _keyword; var _result; _end = input.indexOf("//"); if(_end != -1) input = input.substring(0, _end); input = input.replace(/\s+|;/g, "").toLowerCase(); if(input.length < 5) return null; _result = input.split("#"); if(_result[0] && _result[0].length > 4) { _section = _result[0].split("["); _result[0] = _section[0]; for(i = 1 ; i < _section.length ; i++) { _end = _section[i].indexOf("]") + 1; switch(_section[i][0]) { case 't': _result[0] += "item.itemtype"; break; case 'n': _result[0] += "item.classid"; break; case 'c': _result[0] += "item.itemclass"; break; case 'q': _result[0] += "item.quality"; break; case 'f': if(_section[i][_end] == '!') _result[0] += "!(item.itemflag&"; else _result[0] += "(item.itemflag&"; _end += 2; break; case 'l': _result[0] += "item.itemlevel"; break; case 'p': _result[0] += "item.itemprefix"; break; case 's': _result[0] += "item.itemsuffix"; break; default: Print("Unknown Keyword : " + input); break; } for(_start = _end ; _end < _section[i].length ; _end++) { if(!NTIPIsSyntaxInt(_section[i][_end])) break; } _result[0] += _section[i].substring(_start, _end); for(_start = _end ; _end < _section[i].length ; _end++) { if(NTIPIsSyntaxInt(_section[i][_end])) break; } _keyword = _section[i].substring(_start, _end); if(isNaN(_keyword)) { switch(_section[i][0]) { case 't': _result[0] += _NTIPAliasType[_keyword]; break; case 'n': _result[0] += _NTIPAliasClassID[_keyword]; break; case 'c': _result[0] += _NTIPAliasClass[_keyword]; break; case 'q': _result[0] += _NTIPAliasQuality[_keyword]; break; case 'f': _result[0] += _NTIPAliasFlag[_keyword] + ")"; break; } } else { if(_section[i][0] == 'f') _result[0] += _keyword + ")"; else _result[0] += _keyword; } _result[0] += _section[i].substring(_end); if (_NTIP_UseAdvancedItemTypes) _result[0] = NTIP_ConvertToAdvancedItemTypeSyntax(_result[0]); } } else _result[0] = ""; if(_result[1] && _result[1].length > 4) { _section = _result[1].split("["); _result[1] = _section[0]; for(i = 1 ; i < _section.length ; i++) { _end = _section[i].indexOf("]"); _keyword = _section[i].substring(0, _end); if(_keyword.toLowerCase() == "description") { _string = _section[i].split("\"")[1]; _result[1] += "item.itemloc == 0 &&"; _result[1] += "item.itemdesc.replace(/ |;|\t/g, \"\").toLowerCase().indexOf(\"" + _string + "\") > -1"; _result[1] += _section[i].split("\"")[2]; } else { if(isNaN(_keyword)) _result[1] += "item.GetStat(" + _NTIPAliasStat[_keyword] + ")"; else _result[1] += "item.GetStat(" + _keyword + ")"; _result[1] += _section[i].substring(_end+1); } } } else _result[1] = ""; if(_result[2] && _result[2].replace(/^\s+|\s+$/, "").length > 0) { _section = _result[2].split("["); _result[2] = new Array(); for(i = 1 ; i < _section.length ; i++) { _end = _section[i].indexOf("]"); _keyword = _section[i].substring(0, _end); if(_keyword.toLowerCase().replace(/^\s+|\s+$/, "") == "maxquantity") { _end = _section[i].split("==")[1].replace(/^\s+|\s+$/, "").indexOf("//"); if(_end == -1) _end = _section[i].split("==")[1].replace(/^\s+|\s+$/, "").length; var _quantity = parseInt(_section[i].split("==")[1].replace(/^\s+|\s+$/, "").substring(0, _end)); _result[2]["MaxQuantity"] = _quantity; } else { Print("Error in your NIP file : unknown 3rd part keyword."); } } } else _result[2] = ""; return _result; } function NTIPIsSyntaxInt(ch) { return (ch == '!' || ch == '%' || ch == '&' || (ch >= '(' && ch <= '+') || ch == '-' || ch == '/' || (ch >= ':' && ch <= '?') || ch == '|'); } function NTIPCheckNipSyntax(line,f) { var end, regexp, i, j, k, openp, closep, phrase, keyword, partialEq, leftEq, rightEq, keys, regexp2; var subphrase = new Array; // if the line is too short, it must be broken if (line && line.length <5) { NTIPCheckNipSyntaxDisplay(line,f,"Line is too short to contain a valid entry"); return false; } // split the line into property, stat and quantity phrases regexp = /#/; phrase = line.split(regexp); if (phrase[3]) { NTIPCheckNipSyntaxDisplay(line,f,"Too many phrases in the line"); return false; } for (i = 0; i<=2; i++) { // make sure a phrase exists before we parse anything if (phrase[i]) { // if the phrase exists but is too short to be anything, bail out if (phrase[i].length <5) { NTIPCheckNipSyntaxDisplay(line,f,"Phrase "+i+" is too short to contain a valid entry"); return false; } // strip out matching sets of regular parens regexp = /.*\(.+\).*/; while (phrase[i].match(regexp)) { openp = phrase[i].indexOf("("); phrase[i] = phrase[i].substring(0,openp) + phrase[i].substring(openp+1,phrase[i].length); closep = phrase[i].indexOf(")"); phrase[i] = phrase[i].substring(0,closep) + phrase[i].substring(closep+1,phrase[i].length); } // if any parens remain they are mismatched regexp = /^.*[\(\)].*$/; if (phrase[i].match(regexp)) { NTIPCheckNipSyntaxDisplay(line,f,"Mismatched parens"); return false; } // check for trailing && and || regexp = /(\&\&|\|\|)$/; if (phrase[i].match(regexp)) { NTIPCheckNipSyntaxDisplay(line,f,"Trailing conjunction at end of phrase"); return false; } // check for leading && and || regexp = /^(\&\&|\|\|)/; if (phrase[i].match(regexp)) { NTIPCheckNipSyntaxDisplay(line,f,"Leading conjunction at end of phrase"); return false; } // split into subphrases based on && and || regexp = /\&\&|\|\|/; subphrase[i] = phrase[i].split(regexp); for (j = 0; subphrase[i][j]; j++) { // split equations into left and right sides while removing the comparitive regexp = /\=\=|!=|<=|>=|<|>/; partialEq = subphrase[i][j].split(regexp); leftEq = ""; rightEq = ""; if (partialEq[0] && partialEq[0].length>0) {leftEq = partialEq[0];} else { NTIPCheckNipSyntaxDisplay(line,f,"Invalid Equation"); return false; } if (partialEq[1] && partialEq[1].length>0) {rightEq = partialEq[1];} else { NTIPCheckNipSyntaxDisplay(line,f,"Invalid Equation"); return false; } // if any comparitives remain they are mismatched regexp = /[=<>]+/; if ((leftEq.match(regexp)) || (rightEq.match(regexp))) { NTIPCheckNipSyntaxDisplay(line,f,"Invalid Comparitive"); return false; } // there can only be a left and right side to any equation if (partialEq[2]) { NTIPCheckNipSyntaxDisplay(line,f,"Malformed equation"); return false; } // unless enclosed in "" // allow word characters (letters and digits), apostrophes and decimals separated but valid arithmatic operators on the right regexp = /^[\w\.\-\']+([\+,\-,\*,\/][\w|\.\-\']+)*$/; regexp2 = /^\"(.)*\"$/; if (!rightEq.match(regexp) && !rightEq.match(regexp2)) { NTIPCheckNipSyntaxDisplay(line,f,"right side equation syntax error"); return false; } // on the left split based on arithmatic operator regexp = /[\+\-\*\/\%]+/; keys = leftEq.split(regexp); for (k = 0; keys[k]; k++) { // on the left allow numbers with decimals and keywords only regexp = /^[\d\.]+$/; regexp2 = /^\[[a-z0-9]+\]$/; if (!keys[k].match(regexp) && !keys[k].match(regexp2)) { NTIPCheckNipSyntaxDisplay(line,f,"invalid left side equation entry"); return false; } // if the entry was a keyword and not a number, validate the keyword against the list if (keys[k].match(regexp2)) { keyword = keys[k].substring(1,keys[k].length-1); if (!NTIPcheckKeyword(keyword,i)) { NTIPCheckNipSyntaxDisplay(line,f,"invalid keyword *"+keyword+"* in segment "+i); return false; } } } } // check for &&&&, ||||, ||&&, &&|| if (j < subphrase[i].length) { NTIPCheckNipSyntaxDisplay(line,f,"Invalid Conjunction"); return false; } } } return true; } function NTIPcheckKeyword(keyword,i) { var k, j; var failedKeyword = ""; var isMember = false; var keywordList = new Array; var numeric = false; var defined = false; keywordList[0] = new Array("name","quality","flag","type","level","prefix","suffix","class"); keywordList[1] = new Array("description"); keywordList[2] = new Array("maxquantity"); for (k=0; k < keywordList[i].length; k++) { if (keyword==keywordList[i][k]) {isMember=true;} } // check stat keywords if (i==1) { // bypass the check if they are already numeric if (keyword.match(/^\d+$/)) {numeric=true;} if (_NTIPAliasStat[keyword] || _NTIPAliasStat[keyword]==0) {defined = true;} if (defined || numeric) {isMember=true;} } return(isMember); } function NTIPCheckNipSyntaxDisplay(line,f,err) { var screenDisplay = false; if (!f) screenDisplay=true; if (screenDisplay) { Print (COLOR_3 +"NIP Error detected: Use the numpad '+' key to run the NIP check utility."); } else { f.WriteLine("NIP Error: "+err); f.WriteLine(" "+line); f.WriteLine(""); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Begin Advanced Item Types //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ var _NTIP_UseAdvancedItemTypes = true; var _NTIP_ItemTypeMappings = { /* The following mappings indicate that an item of type [key] is also of type [value[key]]. i.e. a Scepter is also of types: Weapon, MeleeWeapon, StavesAndRods, and Blunt. * Categorization based on info from the Arreat Summit + common sense */ //==== Weapons ==== 24: {45:1,46:1,55:1,57:1}, //scepter 25: {45:1,46:1,55:1,57:1}, //wand 26: {45:1,46:1,55:1,57:1}, //staff 27: {45:1,47:1}, //bow 28: {45:1,46:1}, //axe 29: {45:1,46:1,57:1}, //club 30: {45:1,46:1}, //sword 31: {45:1,46:1,57:1}, //hammer 32: {45:1,46:1}, //knife 33: {45:1,46:1}, //spear 34: {45:1,46:1}, //polearm 35: {45:1,47:1}, //crossbow 36: {45:1,46:1,57:1}, //mace 38: {45:1,48:1}, //missilepotion 42: {45:1,48:1}, //throwingknife 43: {45:1,48:1}, //throwingaxe 44: {45:1,48:1,33:1}, //javelin // 45: {}, //weapon // 46: {}, //meleeweapon // 47: {}, //missileweapon // MissileWeapons should NOT include Javelins/Zon-Javelins, despite the AS. // 48: {}, //thrownweapon // The Arreat Summit has conflicting notes on what constitutes "thrown" and // 49: {}, //comboweapon // "combo" weapons, so we will use common sense here. ComboWeapon remains unused. // 55: {}, //stavesandrods // Scepters, Wands, Staves, (Not Orbs?) // 57: {}, //blunt // Unclear, so we will call it anything with the 50% damage to undead auto-mod, // 60: {}, //amazonitem // ^ Scepters, Wands, Staves, Clubs, Hammers, Maces ^ // 64: {}, //sorceressitem // 65: {}, //assassinitem 67: {59:1,45:1,46:1,65:1}, //handtohand //unskilled 68: {59:1,45:1,46:1,64:1}, //orb 85: {59:1,45:1,47:1,27:1,60:1}, //amazonbow 86: {59:1,45:1,46:1,33:1,60:1}, //amazonspear 87: {59:1,45:1,48:1,33:1,44:1,60:1}, //amazonjavelin 88: {59:1,45:1,46:1,65:1}, //assassinclaw //skilled // 59: {}, //classspecific //umbrella type //==== ARMOR ==== 2: {50:1,51:1}, //shield 3: {50:1}, //armor 15: {50:1}, //boots 16: {50:1}, //gloves 19: {50:1}, //belt 37: {50:1}, //helm // 50: {}, //anyarmor // 51: {}, //anyshield // 61: {}, //barbarianitem // 62: {}, //necromanceritem // 63: {}, //paladinitem // 66: {}, //druiditem 69: {59:1,50:1,51:1,62:1}, //voodooheads 70: {59:1,50:1,51:1,63:1}, //auricshields 71: {59:1,50:1,37:1,61:1}, //primalhelm 72: {59:1,50:1,37:1,66:1}, //pelt //==== MISC ==== // 4: {}, //gold // 5: {}, //bow quiver // 6: {}, //crossbow quiver // 7: {}, //playerbodypart // 8: {}, //herb // 9: {}, //potion // 10: {}, //ring // 11: {}, //elixir // 12: {}, //amulet // 13: {}, //charm // 14: {}, //notused // 17: {}, //notused // 18: {}, //book // 20: {}, //gem // 21: {}, //torch // 22: {}, //scroll // 23: {}, //notused // 39: {}, //quest // 40: {}, //bodypart // 41: {}, //key // 52: {}, //miscellaneous // 53: {}, //socketfiller // 54: {}, //secondhand // 56: {}, //missile // 58: {}, //jewel // 73: {}, //cloak // 74: {}, //rune // 75: {}, //circlet 76: {9:1}, //healingpotion 77: {9:1}, //manapotion 78: {9:1}, //rejuvpotion 79: {9:1}, //staminapotion 80: {9:1}, //antidotepotion 81: {9:1}, //thawingpotion 82: {13:1}, //smallcharm 83: {13:1}, //mediumcharm 84: {13:1}, //largecharm // 89: {}, //magicbowquiv // 90: {}, //magicxbowquiv // 91: {}, //chippedgem // 92: {}, //flawedgem // 93: {}, //standardgem // 94: {}, //flawlessgem // 95: {}, //perfectgem 96: {20:1,91:"item.classid%5==2",92:"item.classid%5==3",93:"item.classid%5==4",94:"item.classid%5==0",95:"item.classid%5==1"}, //amethyst 97: {20:1,91:"item.classid%5==2",92:"item.classid%5==3",93:"item.classid%5==4",94:"item.classid%5==0",95:"item.classid%5==1"}, //diamond 98: {20:1,91:"item.classid%5==2",92:"item.classid%5==3",93:"item.classid%5==4",94:"item.classid%5==0",95:"item.classid%5==1"}, //emerald 99: {20:1,91:"item.classid%5==2",92:"item.classid%5==3",93:"item.classid%5==4",94:"item.classid%5==0",95:"item.classid%5==1"}, //ruby 100: {20:1,91:"item.classid%5==2",92:"item.classid%5==3",93:"item.classid%5==4",94:"item.classid%5==0",95:"item.classid%5==1"}, //sapphire 101: {20:1,91:"item.classid%5==2",92:"item.classid%5==3",93:"item.classid%5==4",94:"item.classid%5==0",95:"item.classid%5==1"}, //topaz 102: {20:1,91:"item.classid%5==2",92:"item.classid%5==3",93:"item.classid%5==4",94:"item.classid%5==0",95:"item.classid%5==1"} //skull }; function NTIP_CheckItemType(item, type) { if (item.itemtype == type) return true; var typeHash = _NTIP_ItemTypeMappings[item.itemtype]; if (typeHash) { var isType = typeHash[type]; if (isType) { if (isType == 1) { return true; } else { return eval(isType); } } } return false; } function NTIP_ConvertToAdvancedItemTypeSyntax(syntax) { return syntax.replace( /item\.itemtype==(\d+)/, "NTIP_CheckItemType(item,\$1)").replace( /item\.itemtype!=(\d+)/, "!NTIP_CheckItemType(item,\$1)"); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // End Advanced Item Types //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~