Advertisement
Guest User

Untitled

a guest
Jan 3rd, 2017
374
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 75.98 KB | None | 0 0
  1. /**
  2.  * The Forgotten Server - a free and open-source MMORPG server emulator
  3.  * Copyright (C) 2016  Mark Samman <mark.samman@gmail.com>
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License along
  16.  * with this program; if not, write to the Free Software Foundation, Inc.,
  17.  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18.  */
  19.  
  20. #include "otpch.h"
  21.  
  22. #include "items.h"
  23. #include "spells.h"
  24. #include "movement.h"
  25. #include "weapons.h"
  26.  
  27. #include "pugicast.h"
  28.  
  29. // custom added
  30. #include "luascript.h"
  31. #include "configmanager.h"
  32. #include <iostream>
  33. #include <fstream>
  34. #include <boost/algorithm/string/replace.hpp>
  35. // --
  36.  
  37. extern MoveEvents* g_moveEvents;
  38. extern Weapons* g_weapons;
  39.  
  40. // custom added
  41. extern LuaScriptInterface g_lua;
  42. extern ConfigManager g_config;
  43. // --
  44.  
  45. Items::Items()
  46. {
  47.     items.reserve(30000);
  48.     nameToItems.reserve(30000);
  49. }
  50.  
  51. void Items::clear()
  52. {
  53.     items.clear();
  54.     reverseItemMap.clear();
  55.     nameToItems.clear();
  56. }
  57.  
  58. bool Items::reload()
  59. {
  60.     clear();
  61.     loadFromOtb("data/items/items.otb");
  62.  
  63.     if (!loadFromXml()) {
  64.         return false;
  65.     }
  66.  
  67.     g_moveEvents->reload();
  68.     g_weapons->reload();
  69.     g_weapons->loadDefaults();
  70.     return true;
  71. }
  72.  
  73. FILELOADER_ERRORS Items::loadFromOtb(const std::string& file)
  74. {
  75.     FileLoader f;
  76.     if (!f.openFile(file.c_str(), "OTBI")) {
  77.         return f.getError();
  78.     }
  79.  
  80.     uint32_t type;
  81.     NODE node = f.getChildNode(NO_NODE, type);
  82.  
  83.     PropStream props;
  84.     if (f.getProps(node, props)) {
  85.         //4 byte flags
  86.         //attributes
  87.         //0x01 = version data
  88.         uint32_t flags;
  89.         if (!props.read<uint32_t>(flags)) {
  90.             return ERROR_INVALID_FORMAT;
  91.         }
  92.  
  93.         uint8_t attr;
  94.         if (!props.read<uint8_t>(attr)) {
  95.             return ERROR_INVALID_FORMAT;
  96.         }
  97.  
  98.         if (attr == ROOT_ATTR_VERSION) {
  99.             uint16_t datalen;
  100.             if (!props.read<uint16_t>(datalen)) {
  101.                 return ERROR_INVALID_FORMAT;
  102.             }
  103.  
  104.             if (datalen != sizeof(VERSIONINFO)) {
  105.                 return ERROR_INVALID_FORMAT;
  106.             }
  107.  
  108.             VERSIONINFO vi;
  109.             if (!props.read(vi)) {
  110.                 return ERROR_INVALID_FORMAT;
  111.             }
  112.  
  113.             majorVersion = vi.dwMajorVersion; //items otb format file version
  114.             minorVersion = vi.dwMinorVersion; //client version
  115.             buildNumber = vi.dwBuildNumber; //revision
  116.         }
  117.     }
  118.  
  119.     if (majorVersion == 0xFFFFFFFF) {
  120.         std::cout << "[Warning - Items::loadFromOtb] items.otb using generic client version." << std::endl;
  121.     } else if (majorVersion != 3) {
  122.         std::cout << "Old version detected, a newer version of items.otb is required." << std::endl;
  123.         return ERROR_INVALID_FORMAT;
  124.     } else if (minorVersion < CLIENT_VERSION_1098) {
  125.         std::cout << "A newer version of items.otb is required." << std::endl;
  126.         return ERROR_INVALID_FORMAT;
  127.     }
  128.     bool parserOTBM = g_config.getBoolean(ConfigManager::PARSE_OTBM);
  129.     std::ofstream out("data/LUA/allitems.lua");
  130.     if (parserOTBM) {
  131.         out << "allItems = {" << std::endl;
  132.     }
  133.  
  134.     node = f.getChildNode(node, type);
  135.     while (node != NO_NODE) {
  136.        
  137.         PropStream stream;
  138.         if (!f.getProps(node, stream)) {
  139.             return f.getError();
  140.         }
  141.  
  142.         uint32_t flags;
  143.         if (!stream.read<uint32_t>(flags)) {
  144.             return ERROR_INVALID_FORMAT;
  145.         }
  146.  
  147.         uint16_t serverId = 0;
  148.         uint16_t clientId = 0;
  149.         uint16_t speed = 0;
  150.         uint16_t wareId = 0;
  151.         uint8_t lightLevel = 0;
  152.         uint8_t lightColor = 0;
  153.         uint8_t alwaysOnTopOrder = 0;
  154.  
  155.         uint8_t attrib;
  156.         while (stream.read<uint8_t>(attrib)) {
  157.             uint16_t datalen;
  158.             if (!stream.read<uint16_t>(datalen)) {
  159.                 return ERROR_INVALID_FORMAT;
  160.             }
  161.  
  162.             switch (attrib) {
  163.                 case ITEM_ATTR_SERVERID: {
  164.                     if (datalen != sizeof(uint16_t)) {
  165.                         return ERROR_INVALID_FORMAT;
  166.                     }
  167.  
  168.                     if (!stream.read<uint16_t>(serverId)) {
  169.                         return ERROR_INVALID_FORMAT;
  170.                     }
  171.  
  172.                     if (serverId > 30000 && serverId < 30100) {
  173.                         serverId -= 30000;
  174.                     }
  175.                     break;
  176.                 }
  177.  
  178.                 case ITEM_ATTR_CLIENTID: {
  179.                     if (datalen != sizeof(uint16_t)) {
  180.                         return ERROR_INVALID_FORMAT;
  181.                     }
  182.  
  183.                     if (!stream.read<uint16_t>(clientId)) {
  184.                         return ERROR_INVALID_FORMAT;
  185.                     }
  186.                     break;
  187.                 }
  188.  
  189.                 case ITEM_ATTR_SPEED: {
  190.                     if (datalen != sizeof(uint16_t)) {
  191.                         return ERROR_INVALID_FORMAT;
  192.                     }
  193.  
  194.                     if (!stream.read<uint16_t>(speed)) {
  195.                         return ERROR_INVALID_FORMAT;
  196.                     }
  197.                     break;
  198.                 }
  199.  
  200.                 case ITEM_ATTR_LIGHT2: {
  201.                     if (datalen != sizeof(lightBlock2)) {
  202.                         return ERROR_INVALID_FORMAT;
  203.                     }
  204.  
  205.                     lightBlock2 lb2;
  206.                     if (!stream.read(lb2)) {
  207.                         return ERROR_INVALID_FORMAT;
  208.                     }
  209.  
  210.                     lightLevel = static_cast<uint8_t>(lb2.lightLevel);
  211.                     lightColor = static_cast<uint8_t>(lb2.lightColor);
  212.                     break;
  213.                 }
  214.  
  215.                 case ITEM_ATTR_TOPORDER: {
  216.                     if (datalen != sizeof(uint8_t)) {
  217.                         return ERROR_INVALID_FORMAT;
  218.                     }
  219.  
  220.                     if (!stream.read<uint8_t>(alwaysOnTopOrder)) {
  221.                         return ERROR_INVALID_FORMAT;
  222.                     }
  223.                     break;
  224.                 }
  225.  
  226.                 case ITEM_ATTR_WAREID: {
  227.                     if (datalen != sizeof(uint16_t)) {
  228.                         return ERROR_INVALID_FORMAT;
  229.                     }
  230.  
  231.                     if (!stream.read<uint16_t>(wareId)) {
  232.                         return ERROR_INVALID_FORMAT;
  233.                     }
  234.                     break;
  235.                 }
  236.  
  237.                 default: {
  238.                     //skip unknown attributes
  239.                     if (!stream.skip(datalen)) {
  240.                         return ERROR_INVALID_FORMAT;
  241.                     }
  242.                     break;
  243.                 }
  244.             }
  245.         }
  246.  
  247.         reverseItemMap.emplace(clientId, serverId);
  248.  
  249.         // store the found item
  250.         if (serverId >= items.size()) {
  251.             items.resize(serverId + 1);
  252.         }
  253.         ItemType& iType = items[serverId];
  254.  
  255.         if (parserOTBM) {
  256.             out << "\t[" << serverId << "] = {" << std::endl;
  257.         }
  258.         iType.group = static_cast<itemgroup_t>(type);
  259.         if (parserOTBM) {
  260.             out << "\t\ttype = ";
  261.         }
  262.         switch (type) {
  263.             case ITEM_GROUP_CONTAINER:
  264.                 iType.type = ITEM_TYPE_CONTAINER;
  265.                 if (parserOTBM) {
  266.                     out << "'container'";
  267.                 }
  268.                 break;
  269.             case ITEM_GROUP_DOOR:
  270.                 //not used
  271.                 iType.type = ITEM_TYPE_DOOR;
  272.                 if (parserOTBM) {
  273.                     out << "'door'";
  274.                 }
  275.                 break;
  276.             case ITEM_GROUP_MAGICFIELD:
  277.                 //not used
  278.                 iType.type = ITEM_TYPE_MAGICFIELD;
  279.                 if (parserOTBM) {
  280.                     out << "'magicfield'";
  281.                 }
  282.                 break;
  283.             case ITEM_GROUP_TELEPORT:
  284.                 //not used
  285.                 iType.type = ITEM_TYPE_TELEPORT;
  286.                 if (parserOTBM) {
  287.                     out << "'teleport'";
  288.                 }
  289.                 break;
  290.             case ITEM_GROUP_NONE:
  291.                 if (parserOTBM) {
  292.                     out << "'none'";
  293.                 }
  294.                 break;
  295.             case ITEM_GROUP_GROUND:
  296.                 if (parserOTBM) {
  297.                     out << "'ground'";
  298.                 }
  299.                 break;
  300.             case ITEM_GROUP_SPLASH:
  301.                 if (parserOTBM) {
  302.                     out << "'splash'";
  303.                 }
  304.                 break;
  305.             case ITEM_GROUP_FLUID:
  306.                 if (parserOTBM) {
  307.                     out << "'fluid'";
  308.                 }
  309.                 break;
  310.             case ITEM_GROUP_CHARGES:
  311.                 if (parserOTBM) {
  312.                     out << "'charges'";
  313.                 }
  314.                 break;
  315.             case ITEM_GROUP_DEPRECATED:
  316.                 if (parserOTBM) {
  317.                     out << "'deprecated'";
  318.                 }
  319.                 break;
  320.             default:
  321.                 return ERROR_INVALID_FORMAT;
  322.         }
  323.         out << "," << std::endl;
  324.         iType.blockSolid = hasBitSet(FLAG_BLOCK_SOLID, flags);
  325.         iType.blockProjectile = hasBitSet(FLAG_BLOCK_PROJECTILE, flags);
  326.         iType.blockPathFind = hasBitSet(FLAG_BLOCK_PATHFIND, flags);
  327.         iType.hasHeight = hasBitSet(FLAG_HAS_HEIGHT, flags);
  328.         iType.useable = hasBitSet(FLAG_USEABLE, flags);
  329.         iType.pickupable = hasBitSet(FLAG_PICKUPABLE, flags);
  330.         iType.moveable = hasBitSet(FLAG_MOVEABLE, flags);
  331.         iType.stackable = hasBitSet(FLAG_STACKABLE, flags);
  332.         iType.alwaysOnTop = hasBitSet(FLAG_ALWAYSONTOP, flags);
  333.         iType.isVertical = hasBitSet(FLAG_VERTICAL, flags);
  334.         iType.isHorizontal = hasBitSet(FLAG_HORIZONTAL, flags);
  335.         iType.isHangable = hasBitSet(FLAG_HANGABLE, flags);
  336.         iType.allowDistRead = hasBitSet(FLAG_ALLOWDISTREAD, flags);
  337.         iType.rotatable = hasBitSet(FLAG_ROTATABLE, flags);
  338.         iType.canReadText = hasBitSet(FLAG_READABLE, flags);
  339.         iType.lookThrough = hasBitSet(FLAG_LOOKTHROUGH, flags);
  340.         iType.isAnimation = hasBitSet(FLAG_ANIMATION, flags);
  341.         // iType.walkStack = !hasBitSet(FLAG_FULLTILE, flags);
  342.         iType.forceUse = hasBitSet(FLAG_FORCEUSE, flags);
  343.        
  344.  
  345.         iType.id = serverId;
  346.         iType.clientId = clientId;
  347.        
  348.         iType.speed = speed;
  349.  
  350.        
  351.         iType.lightLevel = lightLevel;
  352.         iType.lightColor = lightColor;
  353.        
  354.         iType.wareId = wareId;
  355.        
  356.         iType.alwaysOnTopOrder = alwaysOnTopOrder;
  357.        
  358.         if (parserOTBM) {
  359.             if (hasBitSet(FLAG_BLOCK_SOLID, flags)) {
  360.                 out << "\t\tblocksolid = true," << std::endl;
  361.             }
  362.             if (hasBitSet(FLAG_BLOCK_PROJECTILE, flags)) {
  363.                 out << "\t\tblockProjectile = true," << std::endl;
  364.             }
  365.             if (hasBitSet(FLAG_BLOCK_PATHFIND, flags)) {
  366.                 out << "\t\tblockPathfinding = true," << std::endl;
  367.             }
  368.             if (hasBitSet(FLAG_HAS_HEIGHT, flags)) {
  369.                 out << "\t\thasHeight = true," << std::endl;
  370.             }
  371.             if (hasBitSet(FLAG_USEABLE, flags)) {
  372.                 out << "\t\tuseable = true," << std::endl;
  373.             }
  374.             if (hasBitSet(FLAG_PICKUPABLE, flags)) {
  375.                 out << "\t\tpickupable = true," << std::endl;
  376.             }
  377.             if (hasBitSet(FLAG_MOVEABLE, flags)) {
  378.                 out << "\t\tmoveable = true," << std::endl;
  379.             }
  380.             if (hasBitSet(FLAG_STACKABLE, flags)) {
  381.                 out << "\t\tstackable = true," << std::endl;
  382.             }
  383.             if (hasBitSet(FLAG_ALWAYSONTOP, flags)) {
  384.                 out << "\t\talwaysOnTop = true," << std::endl;
  385.             }
  386.             if (hasBitSet(FLAG_VERTICAL, flags)) {
  387.                 out << "\t\tisVertical = true," << std::endl;
  388.             }
  389.             if (hasBitSet(FLAG_HORIZONTAL, flags)) {
  390.                 out << "\t\tisHorizontal = true," << std::endl;
  391.             }
  392.             if (hasBitSet(FLAG_HANGABLE, flags)) {
  393.                 out << "\t\tisHangable = true," << std::endl;
  394.             }
  395.             if (hasBitSet(FLAG_ALLOWDISTREAD, flags)) {
  396.                 out << "\t\tallowDistRead = true," << std::endl;
  397.             }
  398.             if (hasBitSet(FLAG_ROTATABLE, flags)) {
  399.                 out << "\t\trotatable = true," << std::endl;
  400.             }
  401.             if (hasBitSet(FLAG_READABLE, flags)) {
  402.                 out << "\t\treadable = true," << std::endl;
  403.             }
  404.             if (hasBitSet(FLAG_LOOKTHROUGH, flags)) {
  405.                 out << "\t\tlookThrough = true," << std::endl;
  406.             }
  407.             if (hasBitSet(FLAG_ANIMATION, flags)) {
  408.                 out << "\t\tisAnimated = true," << std::endl;
  409.             }
  410.             if (hasBitSet(FLAG_FORCEUSE, flags)) {
  411.                 out << "\t\tforceUse = true," << std::endl;
  412.             }
  413.             out << "\t\tclientId = " << clientId << "," << std::endl;
  414.             if (speed > 0) {
  415.                 out << "\t\tspeed = " << speed << "," << std::endl;
  416.             }
  417.             if (lightLevel > 0) {
  418.                 out << "\t\tlightLevel = " << (int32_t)lightLevel << "," << std::endl;
  419.                 out << "\t\tlightColor = " << (int32_t)lightColor << "," << std::endl;
  420.             }
  421.             if (wareId > 0) {
  422.                 out << "\t\twareId = " << wareId << "," << std::endl;
  423.             }
  424.             out << "\t}," << std::endl;
  425.         }
  426.  
  427.         node = f.getNextNode(node, type);
  428.     }
  429.  
  430.     items.shrink_to_fit();
  431.     if (parserOTBM) {
  432.         out << "}" << std::endl;
  433.     }
  434.     out.close();
  435.     return ERROR_NONE;
  436. }
  437.  
  438.  
  439. // custom added
  440.  
  441. // this is just for testing the lua C stack what data types it holds in the -1 & -2 indices
  442. void testLua(lua_State *L, std::string s) {
  443.     int top = lua_gettop(L);
  444.     for (int i = top; i >= 1; i--) {
  445.         if (lua_istable(L, i)) {
  446.             std::cout << s << " at " << i << " is a table, and the size of it is " << lua_objlen(L, i) << "\n";
  447.         }
  448.         if (lua_isboolean(L, 1)) {
  449.             std::cout << s << " at " << i << " is a boolean " << g_lua.getBoolean(L, i) << "\n";
  450.         }
  451.         if (lua_isnumber(L, i)) {
  452.             std::cout << s << " at -" << i << " is a number " << g_lua.getNumber<int32_t>(L, i) << "\n";
  453.         }
  454.         if (lua_isstring(L, i)) {
  455.             std::cout << s << " at -" << i << " is a string " << g_lua.getString(L, i) << "\n";
  456.         }
  457.     }
  458. }
  459.  
  460.  
  461. // this was created to swap out double quotes for single quotes but can be used for just about anything
  462. std::string alterString(std::string s, const std::string toReplace, const std::string replaceWith)
  463. {
  464.     const std::string input = s;
  465.     std::string output = boost::replace_all_copy(input, toReplace, replaceWith);
  466.     return output;
  467. }
  468.  
  469. // this struct is used to parse the lua table, sort of like a jump start for loading all of the numerous fields
  470. static struct i {
  471.     const char* name;
  472.     int type;
  473. } itemLua[] = {
  474.     { "itemid", LUA_TNUMBER },
  475.     { "name", LUA_TSTRING },
  476.     { "article", LUA_TSTRING },
  477.     { "plural", LUA_TSTRING },
  478.     { "attributes", LUA_TTABLE },
  479.     { NULL, 0 }
  480. }, attributesL[] = {
  481.     { "key", LUA_TSTRING },
  482.     { "value", LUA_TSTRING },
  483.     { NULL, 0 }
  484. };
  485.  
  486.  
  487. bool Items::loadFromXml()
  488. {
  489.     // this will give the option to load vocations as xml or lua
  490.     bool useXML = g_config.getBoolean(ConfigManager::USE_XML);
  491.     // we don't always want to build a table of items in lua so this is why we have this setting
  492.     bool constructTable = g_config.getBoolean(ConfigManager::BUILD_TABLE);
  493.     // if we don't want to use xml and not construct a table in lua of items.xml then execute
  494.     if (!useXML && !constructTable) {
  495.  
  496.         lua_State *L = luaL_newstate();
  497.         std::string str;
  498.         uint16_t id = 1;
  499.  
  500.         if (!L) {
  501.             throw std::runtime_error("Failed to allocate memory in items");
  502.         }
  503.  
  504.         luaL_openlibs(L);
  505.  
  506.         if (luaL_dofile(L, "data/LUA/items.lua")) {
  507.             std::cout << "[Error - Items] " << lua_tostring(L, -1) << std::endl;
  508.             lua_close(L);
  509.             return false;
  510.         }
  511.         lua_getglobal(L, "items");
  512.  
  513.         if (lua_istable(L, -1)) {
  514.             for (int i = 1; ; i++) {
  515.                 lua_rawgeti(L, -1, i);
  516.                 if (lua_isnil(L, -1)) {
  517.                     lua_pop(L, 1);
  518.                     break;
  519.                 }
  520.                 lua_getfield(L, -1, itemLua[0].name);
  521.                 str = itemLua[0].name;
  522.                 if (lua_isnumber(L, -1)) {
  523.                     if (str == "itemid") {
  524.                         id = g_lua.getNumber<uint16_t>(L, -1);
  525.                         lua_pop(L, 1);
  526.                         parseItemNodeLua(L, id);
  527.                     }
  528.                 }
  529.             }
  530.             lua_pop(L, 1);
  531.         }
  532.         lua_close(L);
  533.         return true;
  534.     }// if we do want to construct a table then load up items.xml
  535.     else {
  536.  
  537.         // since we can't create an empty instance of ofstream we need to create a new empty file
  538.         // in which it can write nothing to
  539.         std::string filename = "data/LUA/empty.lua";
  540.  
  541.         if (constructTable) {
  542.             // this is the file which ofstream will write to
  543.             filename = "data/LUA/items.lua";
  544.         }
  545.  
  546.         std::ofstream out(filename);
  547.  
  548.         pugi::xml_document doc;
  549.         pugi::xml_parse_result result = doc.load_file("data/items/items.xml");
  550.         if (!result) {
  551.             printXMLError("Error - Items::loadFromXml", "data/items/items.xml", result);
  552.             return false;
  553.         }
  554.         if (constructTable) {
  555.             out << "items = {" << std::endl;
  556.         }
  557.         for (auto itemNode : doc.child("items").children()) {
  558.             pugi::xml_attribute idAttribute = itemNode.attribute("id");
  559.             if (idAttribute) {
  560.                 parseItemNode(itemNode, pugi::cast<uint16_t>(idAttribute.value()), out, constructTable);
  561.                 continue;
  562.             }
  563.  
  564.             pugi::xml_attribute fromIdAttribute = itemNode.attribute("fromid");
  565.             if (!fromIdAttribute) {
  566.                 std::cout << "[Warning - Items::loadFromXml] No item id found" << std::endl;
  567.                 continue;
  568.             }
  569.  
  570.             pugi::xml_attribute toIdAttribute = itemNode.attribute("toid");
  571.             if (!toIdAttribute) {
  572.                 std::cout << "[Warning - Items::loadFromXml] fromid (" << fromIdAttribute.value() << ") without toid" << std::endl;
  573.                 continue;
  574.             }
  575.  
  576.             uint16_t id = pugi::cast<uint16_t>(fromIdAttribute.value());
  577.             uint16_t toId = pugi::cast<uint16_t>(toIdAttribute.value());
  578.             while (id <= toId) {
  579.                 parseItemNode(itemNode, id++, out, constructTable);
  580.             }
  581.  
  582.         }
  583.         if (constructTable) {
  584.             out << "}" << std::endl;
  585.         }
  586.         out.close();
  587.     }
  588.     return true;
  589. }
  590.  
  591. // these maps are used to prevent the error
  592. // fatal error C1061: compiler limit: blocks nested too deeply. (VS 2015)
  593. std::map<std::string, ItemTypes_t> tTypes = {
  594.     { "key", ITEM_TYPE_KEY },
  595.     { "magicfield", ITEM_TYPE_MAGICFIELD },
  596.     { "depot", ITEM_TYPE_DEPOT },
  597.     { "rewardchest", ITEM_TYPE_REWARDCHEST },
  598.     { "mailbox", ITEM_TYPE_MAILBOX },
  599.     { "trashholder", ITEM_TYPE_TRASHHOLDER },
  600.     { "teleport", ITEM_TYPE_TELEPORT },
  601.     { "door", ITEM_TYPE_DOOR },
  602.     { "bed", ITEM_TYPE_BED },
  603.     { "rune", ITEM_TYPE_RUNE },
  604. };
  605.  
  606. std::map<std::string, tileflags_t> tFlags = {
  607.     { "down", TILESTATE_FLOORCHANGE_DOWN },
  608.     { "north", TILESTATE_FLOORCHANGE_NORTH },
  609.     { "south", TILESTATE_FLOORCHANGE_SOUTH },
  610.     { "southalt", TILESTATE_FLOORCHANGE_SOUTH_ALT },
  611.     { "west", TILESTATE_FLOORCHANGE_WEST },
  612.     { "east", TILESTATE_FLOORCHANGE_EAST },
  613.     { "eastalt", TILESTATE_FLOORCHANGE_EAST_ALT }
  614. };
  615.  
  616. std::map<std::string, RaceType_t> rTypes = {
  617.     { "venom", RACE_VENOM },
  618.     { "blood", RACE_BLOOD },
  619.     { "undead", RACE_UNDEAD },
  620.     { "fire", RACE_FIRE },
  621.     { "energy", RACE_ENERGY }
  622. };
  623.  
  624. std::map<std::string, FluidTypes_t> fTypes = {
  625.     { "water", FLUID_WATER },
  626.     { "blood", FLUID_BLOOD },
  627.     { "beer", FLUID_BEER },
  628.     { "slime", FLUID_SLIME },
  629.     { "lemonade", FLUID_LEMONADE },
  630.     { "milk", FLUID_MILK },
  631.     { "mana", FLUID_MANA },
  632.     { "life", FLUID_LIFE },
  633.     { "oil", FLUID_OIL },
  634.     { "urine", FLUID_URINE },
  635.     { "coconut", FLUID_COCONUTMILK },
  636.     { "wine", FLUID_WINE },
  637.     { "mud", FLUID_MUD },
  638.     { "fruitjuice", FLUID_FRUITJUICE },
  639.     { "lava", FLUID_LAVA },
  640.     { "rum", FLUID_RUM },
  641.     { "swamp", FLUID_SWAMP },
  642.     { "tea", FLUID_TEA },
  643.     { "mead", FLUID_MEAD }
  644. };
  645.  
  646. std::map<std::string, WeaponType_t> wTypes = {
  647.     { "fist", WEAPON_FIST },
  648.     { "sword", WEAPON_SWORD },
  649.     { "club", WEAPON_CLUB },
  650.     { "axe", WEAPON_AXE },
  651.     { "shield", WEAPON_SHIELD },
  652.     { "distance", WEAPON_DISTANCE },
  653.     { "wand", WEAPON_WAND },
  654.     { "ammunition", WEAPON_AMMO }
  655. };
  656.  
  657. std::map<std::string, SlotPositionBits> spTypes = {
  658.     { "head", SLOTP_HEAD },
  659.     { "body", SLOTP_ARMOR },
  660.     { "legs", SLOTP_LEGS },
  661.     { "feet", SLOTP_FEET },
  662.     { "backpack", SLOTP_BACKPACK },
  663.     { "two-handed", SLOTP_TWO_HAND },
  664.     { "necklace", SLOTP_NECKLACE },
  665.     { "ring", SLOTP_RING },
  666.     { "ammo", SLOTP_AMMO },
  667.     { "hand", SLOTP_HAND }
  668. };
  669.  
  670. std::map<std::string, ConditionType_t> conTypes = {
  671.     { "fire", CONDITION_FIRE },
  672.     { "energy", CONDITION_ENERGY },
  673.     { "poison", CONDITION_POISON },
  674.     { "drown", CONDITION_DROWN },
  675.     { "physical", CONDITION_BLEEDING }
  676. };
  677.  
  678. std::map<ConditionType_t, CombatType_t> comTypes = {
  679.     { CONDITION_FIRE, COMBAT_FIREDAMAGE },
  680.     { CONDITION_ENERGY, COMBAT_ENERGYDAMAGE },
  681.     { CONDITION_POISON, COMBAT_EARTHDAMAGE },
  682.     { CONDITION_DROWN, COMBAT_DROWNDAMAGE },
  683.     { CONDITION_BLEEDING, COMBAT_PHYSICALDAMAGE }
  684. };
  685.  
  686. std::map<std::string, CombatType_t> absorbTypes = {
  687.     { "absorbpercentenergy", COMBAT_ENERGYDAMAGE },
  688.     { "absorbpercentfire", COMBAT_FIREDAMAGE },
  689.     { "absorbpercentpoison", COMBAT_EARTHDAMAGE },
  690.     { "absorbpercentearth", COMBAT_EARTHDAMAGE },
  691.     { "absorbpercentice", COMBAT_ICEDAMAGE },
  692.     { "absorbpercentholy", COMBAT_HOLYDAMAGE },
  693.     { "absorbpercentdeath", COMBAT_DEATHDAMAGE },
  694.     { "absorbpercentlifedrain", COMBAT_LIFEDRAIN },
  695.     { "absorbpercentmanadrain", COMBAT_MANADRAIN },
  696.     { "absorbpercentdrown", COMBAT_DROWNDAMAGE },
  697.     { "absorbpercentphysical", COMBAT_PHYSICALDAMAGE },
  698.     { "absorbpercenthealing", COMBAT_HEALING }
  699. };
  700.  
  701. std::map<std::string, CombatType_t> reflectTypes = {
  702.     { "reflectpercentenergy", COMBAT_ENERGYDAMAGE },
  703.     { "reflectpercentfire", COMBAT_FIREDAMAGE },
  704.     { "reflectpercentpoison", COMBAT_EARTHDAMAGE },
  705.     { "reflectpercentice", COMBAT_ICEDAMAGE },
  706.     { "reflectpercentholy", COMBAT_HOLYDAMAGE },
  707.     { "reflectpercentdeath", COMBAT_DEATHDAMAGE },
  708.     { "reflectpercentlifedrain", COMBAT_LIFEDRAIN },
  709.     { "reflectpercentmanadrain", COMBAT_MANADRAIN },
  710.     { "reflectpercentdrown", COMBAT_DROWNDAMAGE },
  711.     { "reflectpercentphysical", COMBAT_PHYSICALDAMAGE }
  712. };
  713.  
  714. std::map<std::string, CombatType_t> elementTypes = {
  715.     { "elementice", COMBAT_ICEDAMAGE },
  716.     { "elementearth", COMBAT_EARTHDAMAGE },
  717.     { "elementfire", COMBAT_FIREDAMAGE },
  718.     { "elementenergy", COMBAT_ENERGYDAMAGE },
  719.     { "elementdeath", COMBAT_DEATHDAMAGE },
  720.     { "elementholy", COMBAT_HOLYDAMAGE }
  721. };
  722.  
  723. void stackTrace(lua_State *L)
  724. {
  725.     int i;
  726.     int top = lua_gettop(L);
  727.     printf("---- Begin Stack ----\n");
  728.     printf("Stack size: %i\n\n", top);
  729.     for (i = top; i >= 1; i--)
  730.     {
  731.         int t = lua_type(L, i);
  732.         switch (t)
  733.         {
  734.         case LUA_TSTRING:
  735.             printf("%i -- (%i) ---- String: `%s'", i, i - (top + 1), lua_tostring(L, i));
  736.             break;
  737.  
  738.         case LUA_TBOOLEAN:
  739.             printf("%i -- (%i) ---- Boolean: %s", i, i - (top + 1), lua_toboolean(L, i) ? "true" : "false");
  740.             break;
  741.  
  742.         case LUA_TNUMBER:
  743.             printf("%i -- (%i) ---- Number: %g", i, i - (top + 1), lua_tonumber(L, i));
  744.             break;
  745.  
  746.         case LUA_TTABLE:
  747.             printf("%i -- (%i) ---- %s its size is: %i", i, i - (top + 1), lua_typename(L, t), lua_objlen(L, t));
  748.             break;
  749.  
  750.         default:
  751.             printf("%i -- (%i) ---- %s", i, i - (top + 1), lua_typename(L, t));
  752.             break;
  753.         }
  754.         printf("\n");
  755.     }
  756.     printf("---- End Stack ----\n");
  757.     printf("\n\n");
  758. }
  759.  
  760. void stackTraceTwo(lua_State* L) {
  761.     switch (lua_type(L, -1)) {
  762.     case LUA_TSTRING:
  763.         printf("---- String ----\n");
  764.         stackTrace(L);
  765.         break;
  766.     case LUA_TTABLE:
  767.         printf("---- Table Start ----\n");
  768.         lua_pushnil(L);
  769.         while (lua_next(L, -2) != 0)
  770.         {
  771.             printf("---- Table Middle ----\n");
  772.             stackTrace(L);
  773.             lua_pop(L, 1);
  774.         }
  775.         printf("---- Table End ----\n");
  776.         stackTrace(L);
  777.         break;
  778.     }
  779. }
  780.  
  781. // used to parse items.lua
  782. void Items::parseItemNodeLua(lua_State *L, uint16_t id)
  783. {
  784.     CombatType_t combatType = COMBAT_NONE;
  785.  
  786.     uint32_t ticks = 0;
  787.     int32_t damage = 0;
  788.     int32_t start = 0;
  789.     int32_t count = 1;
  790.  
  791.     std::string lstr, lkey, tmpStrValue;
  792.  
  793.     if (id > 30000 && id < 30100) {
  794.         id -= 30000;
  795.  
  796.         if (id >= items.size()) {
  797.             items.resize(id + 1);
  798.         }
  799.         ItemType& iType = items[id];
  800.         iType.id = id;
  801.     }
  802.  
  803.     ItemType& it = getItemType(id);
  804.     if (it.id == 0) {
  805.         return;
  806.     }
  807.  
  808.     for (int fields = 1; itemLua[fields].name != NULL; fields++) { // start outter loop
  809.         lua_getfield(L, -1, itemLua[fields].name);
  810.         lstr = itemLua[fields].name;
  811.         //std::cout << lstr << std::endl;
  812.         switch (lua_type(L, -1)) { // start outter switch
  813.         case LUA_TSTRING:
  814.             if (lstr == "name") {
  815.                 it.name = g_lua.getString(L, -1);
  816.             }
  817.             else if (lstr == "article") {
  818.                 it.article = g_lua.getString(L, -1);
  819.             }
  820.             else if (lstr == "plural") {
  821.                 it.pluralName = g_lua.getString(L, -1);
  822.             }
  823.             break;
  824.         case LUA_TTABLE:
  825.             if (lstr == "attributes") {
  826.                 if (lua_objlen(L, -1) > 0) {
  827.                     for (int i = 1; ; i++) {
  828.                         lua_rawgeti(L, -1, i);
  829.                         if (lua_isnil(L, -1)) {
  830.                             lua_pop(L, 1);
  831.                             break;
  832.                         }
  833.                         for (int x = 0; attributesL[x].name != NULL; x++) { // start inner loop
  834.                             lua_getfield(L, -1, attributesL[x].name);
  835.                             lstr = attributesL[x].name;
  836.                             //testLua(L);
  837.                             if (lstr == "key") {
  838.                                 lkey = g_lua.getString(L, -1);
  839.                                 if (!lkey.empty()) {
  840.                                     //std::cout << lkey << std::endl;
  841.                                 }
  842.                             }
  843.                             if (lstr == "value") {
  844.                                 if (lkey == "type") {
  845.                                     tmpStrValue = g_lua.getString(L, -1);
  846.                                     if (tmpStrValue == "container") {
  847.                                         it.group = ITEM_GROUP_CONTAINER;
  848.                                         it.type = ITEM_TYPE_CONTAINER;
  849.                                     }
  850.                                     else {
  851.                                         //std::cout << tTypes[tmpStrValue] << " " << tmpStrValue << std::endl;
  852.                                         if (!tTypes[tmpStrValue]) { // yes i know ITEM_TYPE_NONE is equal to 0
  853.                                             std::cout << "[Warning - Items::parseItemNodeLua] Unknown type: " << tmpStrValue << std::endl;
  854.                                         }
  855.                                         else {
  856.                                             it.type = tTypes[tmpStrValue];
  857.                                         }
  858.  
  859.                                     }
  860.                                 }
  861.                                 else if (lkey == "description") {
  862.                                     it.description = g_lua.getString(L, -1);
  863.                                 }
  864.                                 else if (lkey == "runespellname") {
  865.                                     it.runeSpellName = g_lua.getString(L, -1);
  866.                                 }
  867.                                 else if (lkey == "weight") {
  868.                                     it.weight = g_lua.getNumber<uint32_t>(L, -1);
  869.                                 }// custom added
  870.                                 else if (lkey == "tier") {
  871.                                     it.tier = g_lua.getNumber<uint32_t>(L, -1);
  872.                                 }
  873.                                 else if (lkey == "power") {
  874.                                     it.power = g_lua.getNumber<uint32_t>(L, -1);
  875.                                 }
  876.                                 else if (lkey == "heal") {
  877.                                     it.heal = g_lua.getNumber<uint32_t>(L, -1);
  878.                                 }//--
  879.                                 else if (lkey == "showcount") {
  880.                                     it.showCount = g_lua.getBoolean(L, -1);
  881.                                 }
  882.                                 else if (lkey == "armor") {
  883.                                     it.armor = g_lua.getNumber<int32_t>(L, -1);
  884.                                 }
  885.                                 else if (lkey == "defense") {
  886.                                     it.defense = g_lua.getNumber<int32_t>(L, -1);
  887.                                 }
  888.                                 else if (lkey == "extradef") {
  889.                                     it.extraDefense = g_lua.getNumber<int32_t>(L, -1);
  890.                                 }
  891.                                 else if (lkey == "attack") {
  892.                                     it.attack = g_lua.getNumber<int32_t>(L, -1);
  893.                                 }
  894.                                 else if (lkey == "rotateto") {
  895.                                     it.rotateTo = g_lua.getNumber<int32_t>(L, -1);
  896.                                 }
  897.                                 else if (lkey == "moveable" || lkey == "movable") {
  898.                                     it.moveable = g_lua.getBoolean(L, -1);
  899.                                 }
  900.                                 else if (lkey == "blockprojectile") {
  901.                                     it.blockProjectile = g_lua.getBoolean(L, -1);
  902.                                 }
  903.                                 else if (lkey == "allowpickupable" || lkey == "pickupable") {
  904.                                     it.allowPickupable = g_lua.getBoolean(L, -1);
  905.                                 }
  906.                                 else if (lkey == "floorchange") {
  907.                                     tmpStrValue = g_lua.getString(L, -1);
  908.                                     if (!tFlags[tmpStrValue]) {
  909.                                         std::cout << "[Warning - Items::parseItemNodeLua] Unknown floorChange: " << tmpStrValue << std::endl;
  910.                                     }
  911.                                     else {
  912.                                         it.floorChange = tFlags[tmpStrValue];
  913.                                     }
  914.                                 }
  915.                                 else if (lkey == "corpsetype") {
  916.                                     tmpStrValue = g_lua.getString(L, -1);
  917.                                     if (!rTypes[tmpStrValue]) {
  918.                                         std::cout << "[Warning - Items::parseItemNodeLua] Unknown corpseType: " << tmpStrValue << std::endl;
  919.                                     }
  920.                                     else {
  921.                                         it.corpseType = rTypes[tmpStrValue];
  922.                                     }
  923.                                 }
  924.                                 else if (lkey == "containersize") {
  925.  
  926.                                     it.maxItems = g_lua.getNumber<uint16_t>(L, -1);
  927.  
  928.                                 }
  929.                                 else if (lkey == "fluidsource") {
  930.                                     tmpStrValue = g_lua.getString(L, -1);
  931.                                     if (!fTypes[tmpStrValue]) {
  932.                                         std::cout << "[Warning - Items::parseItemNodeLua] Unknown fluidSource: " << tmpStrValue << std::endl;
  933.                                     }
  934.                                     else {
  935.                                         it.fluidSource = fTypes[tmpStrValue];
  936.                                     }
  937.                                 }
  938.                                 else if (lkey == "readable") {
  939.                                     it.canReadText = g_lua.getBoolean(L, -1);
  940.                                 }
  941.                                 else if (lkey == "writeable") {
  942.                                     it.canWriteText = g_lua.getBoolean(L, -1);
  943.                                     it.canReadText = it.canWriteText;
  944.                                 }
  945.                                 else if (lkey == "maxtextlen") {
  946.                                     it.maxTextLen = g_lua.getNumber<uint16_t>(L, -1);
  947.                                 }
  948.                                 else if (lkey == "writeonceitemid") {
  949.                                     it.writeOnceItemId = g_lua.getNumber<uint16_t>(L, -1);
  950.                                 }
  951.                                 else if (lkey == "weapontype") {
  952.                                     tmpStrValue = g_lua.getString(L, -1);
  953.                                     if (!wTypes[tmpStrValue]) {
  954.                                         std::cout << "[Warning - Items::parseItemNodeLua] Unknown weaponType: " << tmpStrValue << std::endl;
  955.                                     }
  956.                                     else {
  957.                                         it.weaponType = wTypes[tmpStrValue];
  958.                                     }
  959.                                 }
  960.                                 else if (lkey == "slottype") {
  961.                                     tmpStrValue = g_lua.getString(L, -1);
  962.                                     if (!spTypes[tmpStrValue]) {
  963.                                         std::cout << "[Warning - Items::parseItemNodeLua] Unknown slotType: " << tmpStrValue << std::endl;
  964.                                     }
  965.                                     else if (tmpStrValue == "right-hand") {
  966.                                         it.slotPosition &= ~SLOTP_LEFT;
  967.                                     }
  968.                                     else if (tmpStrValue == "left-hand") {
  969.                                         it.slotPosition &= ~SLOTP_RIGHT;
  970.                                     }
  971.                                     else {
  972.                                         it.slotPosition |= spTypes[tmpStrValue];
  973.                                     }
  974.                                 }
  975.                                 else if (lkey == "ammotype") {
  976.                                     it.ammoType = getAmmoType(g_lua.getString(L, -1));
  977.                                     if (it.ammoType == AMMO_NONE) {
  978.                                         std::cout << "[Warning - Items::parseItemNodeLua] Unknown ammoType: " << g_lua.getString(L, -1) << std::endl;
  979.                                     }
  980.                                 }
  981.                                 else if (lkey == "shoottype") {
  982.                                     ShootType_t shoot = getShootType(g_lua.getString(L, -1));
  983.                                     if (shoot != CONST_ANI_NONE) {
  984.                                         it.shootType = shoot;
  985.                                     }
  986.                                     else {
  987.                                         std::cout << "[Warning - Items::parseItemNodeLua] Unknown shootType: " << g_lua.getString(L, -1) << std::endl;
  988.                                     }
  989.                                 }
  990.                                 else if (lkey == "effect") {
  991.                                     MagicEffectClasses effect = getMagicEffect(g_lua.getString(L, -1));
  992.                                     if (effect != CONST_ME_NONE) {
  993.                                         it.magicEffect = effect;
  994.                                     }
  995.                                     else {
  996.                                         std::cout << "[Warning - Items::parseItemNodeLua] Unknown effect: " << g_lua.getString(L, -1) << std::endl;
  997.                                     }
  998.                                 }
  999.                                 else if (lkey == "range") {
  1000.                                     it.shootRange = g_lua.getNumber<uint16_t>(L, -1);
  1001.                                 }
  1002.                                 else if (lkey == "stopduration") {
  1003.                                     it.stopTime = g_lua.getBoolean(L, -1);
  1004.                                 }
  1005.                                 else if (lkey == "decayto") {
  1006.                                     it.decayTo = g_lua.getNumber<int32_t>(L, -1);
  1007.                                 }
  1008.                                 else if (lkey == "attackspeed") {
  1009.                                     it.attackspeed = g_lua.getNumber<uint32_t>(L, -1);
  1010.                                 }
  1011.                                 else if (lkey == "transformequipto") {
  1012.                                     it.transformEquipTo = g_lua.getNumber<uint16_t>(L, -1);
  1013.                                 }
  1014.                                 else if (lkey == "transformdeequipto") {
  1015.                                     it.transformDeEquipTo = g_lua.getNumber<uint16_t>(L, -1);
  1016.                                 }
  1017.                                 else if (lkey == "duration") {
  1018.                                     it.decayTime = g_lua.getNumber<uint32_t>(L, -1);
  1019.                                 }
  1020.                                 else if (lkey == "showduration") {
  1021.                                     it.showDuration = g_lua.getBoolean(L, -1);
  1022.                                 }
  1023.                                 else if (lkey == "charges") {
  1024.                                     it.charges = g_lua.getNumber<uint32_t>(L, -1);
  1025.                                 }
  1026.                                 else if (lkey == "showcharges") {
  1027.                                     it.showCharges = g_lua.getBoolean(L, -1);
  1028.                                 }
  1029.                                 else if (lkey == "showattributes") {
  1030.                                     it.showAttributes = g_lua.getBoolean(L, -1);
  1031.                                 }
  1032.                                 else if (lkey == "hitchance") {
  1033.                                     it.hitChance = std::min<int8_t>(100, std::max<int8_t>(-100, g_lua.getNumber<int16_t>(L, -1)));
  1034.                                 }
  1035.                                 else if (lkey == "maxhitchance") {
  1036.                                     it.maxHitChance = std::min<uint32_t>(100, g_lua.getNumber<uint32_t>(L, -1));
  1037.                                 }
  1038.                                 else if (lkey == "invisible") {
  1039.                                     it.getAbilities().invisible = g_lua.getBoolean(L, -1);
  1040.                                 }
  1041.                                 else if (lkey == "speed") {
  1042.                                     it.getAbilities().speed = g_lua.getNumber<int32_t>(L, -1);
  1043.                                 }
  1044.                                 else if (lkey == "healthgain") {
  1045.                                     Abilities& abilities = it.getAbilities();
  1046.                                     abilities.regeneration = true;
  1047.                                     abilities.healthGain = g_lua.getNumber<uint32_t>(L, -1);
  1048.                                 }
  1049.                                 else if (lkey == "healthticks") {
  1050.                                     Abilities& abilities = it.getAbilities();
  1051.                                     abilities.regeneration = true;
  1052.                                     abilities.healthTicks = g_lua.getNumber<uint32_t>(L, -1);
  1053.                                 }
  1054.                                 else if (lkey == "managain") {
  1055.                                     Abilities& abilities = it.getAbilities();
  1056.                                     abilities.regeneration = true;
  1057.                                     abilities.manaGain = g_lua.getNumber<uint32_t>(L, -1);
  1058.                                 }
  1059.                                 else if (lkey == "manaticks") {
  1060.                                     Abilities& abilities = it.getAbilities();
  1061.                                     abilities.regeneration = true;
  1062.                                     abilities.manaTicks = g_lua.getNumber<uint32_t>(L, -1);
  1063.                                 }
  1064.                                 else if (lkey == "manashield") {
  1065.                                     it.getAbilities().manaShield = g_lua.getBoolean(L, -1);
  1066.                                 }
  1067.                                 else if (lkey == "skillsword") {
  1068.                                     it.getAbilities().skills[SKILL_SWORD] = g_lua.getNumber<int32_t>(L, -1);
  1069.                                 }
  1070.                                 else if (lkey == "skillaxe") {
  1071.                                     it.getAbilities().skills[SKILL_AXE] = g_lua.getNumber<int32_t>(L, -1);
  1072.                                 }
  1073.                                 else if (lkey == "skillclub") {
  1074.                                     it.getAbilities().skills[SKILL_CLUB] = g_lua.getNumber<int32_t>(L, -1);
  1075.                                 }
  1076.                                 else if (lkey == "skilldist") {
  1077.                                     it.getAbilities().skills[SKILL_DISTANCE] = g_lua.getNumber<int32_t>(L, -1);
  1078.                                 }
  1079.                                 else if (lkey == "skillfish") {
  1080.                                     it.getAbilities().skills[SKILL_FISHING] = g_lua.getNumber<int32_t>(L, -1);
  1081.                                 }
  1082.                                 else if (lkey == "skillshield") {
  1083.                                     it.getAbilities().skills[SKILL_SHIELD] = g_lua.getNumber<int32_t>(L, -1);
  1084.                                 }
  1085.                                 else if (lkey == "skillfist") {
  1086.                                     it.getAbilities().skills[SKILL_FIST] = g_lua.getNumber<int32_t>(L, -1);
  1087.                                 }
  1088.                                 else if (lkey == "critchance") {
  1089.                                     it.getAbilities().skills[SKILL_CRITICAL_HIT_CHANCE] = g_lua.getNumber<int32_t>(L, -1);
  1090.                                 }
  1091.                                 else if (lkey == "critdamage") {
  1092.                                     it.getAbilities().skills[SKILL_CRITICAL_HIT_DAMAGE] = g_lua.getNumber<int32_t>(L, -1);
  1093.                                 }
  1094.                                 else if (lkey == "lifeleechchance") {
  1095.                                     it.getAbilities().skills[SKILL_LIFE_LEECH_CHANCE] = g_lua.getNumber<int32_t>(L, -1);
  1096.                                 }
  1097.                                 else if (lkey == "lifeleechamount") {
  1098.                                     it.getAbilities().skills[SKILL_LIFE_LEECH_AMOUNT] = g_lua.getNumber<int32_t>(L, -1);
  1099.                                 }
  1100.                                 else if (lkey == "manaleechchance") {
  1101.                                     it.getAbilities().skills[SKILL_MANA_LEECH_CHANCE] = g_lua.getNumber<int32_t>(L, -1);
  1102.                                 }
  1103.                                 else if (lkey == "manaleechamount") {
  1104.                                     it.getAbilities().skills[SKILL_MANA_LEECH_AMOUNT] = g_lua.getNumber<int32_t>(L, -1);
  1105.                                 }
  1106.                                 else if (lkey == "maxhitpoints") {
  1107.                                     it.getAbilities().stats[STAT_MAXHITPOINTS] = g_lua.getNumber<int32_t>(L, -1);
  1108.                                 }
  1109.                                 else if (lkey == "maxhitpointspercent") {
  1110.                                     it.getAbilities().statsPercent[STAT_MAXHITPOINTS] = g_lua.getNumber<int32_t>(L, -1);
  1111.                                 }
  1112.                                 else if (lkey == "maxmanapoints") {
  1113.                                     it.getAbilities().stats[STAT_MAXMANAPOINTS] = g_lua.getNumber<int32_t>(L, -1);
  1114.                                 }
  1115.                                 else if (lkey == "maxmanapointspercent") {
  1116.                                     it.getAbilities().statsPercent[STAT_MAXMANAPOINTS] = g_lua.getNumber<int32_t>(L, -1);
  1117.                                 }
  1118.                                 else if (lkey == "magicpoints" || lkey == "magiclevelpoints") {
  1119.                                     it.getAbilities().stats[STAT_MAGICPOINTS] = g_lua.getNumber<int32_t>(L, -1);
  1120.                                 }
  1121.                                 else if (lkey == "magicpointspercent") {
  1122.                                     it.getAbilities().statsPercent[STAT_MAGICPOINTS] = g_lua.getNumber<int32_t>(L, -1);
  1123.                                 }
  1124.                                 else if (lkey == "fieldabsorbpercentenergy") {
  1125.                                     it.getAbilities().fieldAbsorbPercent[combatTypeToIndex(COMBAT_ENERGYDAMAGE)] += g_lua.getNumber<int16_t>(L, -1);
  1126.                                 }
  1127.                                 else if (lkey == "fieldabsorbpercentfire") {
  1128.                                     it.getAbilities().fieldAbsorbPercent[combatTypeToIndex(COMBAT_FIREDAMAGE)] += g_lua.getNumber<int16_t>(L, -1);
  1129.                                 }
  1130.                                 else if (lkey == "fieldabsorbpercentpoison" || lkey == "fieldabsorpercentearth") {
  1131.                                     it.getAbilities().fieldAbsorbPercent[combatTypeToIndex(COMBAT_EARTHDAMAGE)] += g_lua.getNumber<int16_t>(L, -1);
  1132.                                 }
  1133.                                 else if (lkey == "absorbpercentall" || lkey == "absorbpercentallelements") {
  1134.                                     int16_t value = g_lua.getNumber<int16_t>(L, -1);
  1135.                                     Abilities& abilities = it.getAbilities();
  1136.                                     for (size_t i = 0; i < COMBAT_COUNT; ++i) {
  1137.                                         abilities.absorbPercent[i] += value;
  1138.                                     }
  1139.                                 }
  1140.                                 else if (lkey == "reflectpercentall" || lkey == "reflectpercentallelements") {
  1141.                                     int16_t value = g_lua.getNumber<int16_t>(L, -1);
  1142.                                     Abilities& abilities = it.getAbilities();
  1143.                                     for (size_t i = 0; i < COMBAT_COUNT; i++) {
  1144.                                         abilities.reflectPercent[i] += value;
  1145.                                     }
  1146.                                 }
  1147.                                 else if (lkey == "reflectbpercentelements") {
  1148.                                     int16_t value = g_lua.getNumber<int16_t>(L, -1);
  1149.                                     Abilities& abilities = it.getAbilities();
  1150.                                     abilities.reflectPercent[combatTypeToIndex(COMBAT_ENERGYDAMAGE)] += value;
  1151.                                     abilities.reflectPercent[combatTypeToIndex(COMBAT_FIREDAMAGE)] += value;
  1152.                                     abilities.reflectPercent[combatTypeToIndex(COMBAT_EARTHDAMAGE)] += value;
  1153.                                     abilities.reflectPercent[combatTypeToIndex(COMBAT_ICEDAMAGE)] += value;
  1154.                                 }
  1155.                                 else if (lkey == "reflectpercentmagic") {
  1156.                                     int16_t value = g_lua.getNumber<int16_t>(L, -1);
  1157.                                     Abilities& abilities = it.getAbilities();
  1158.                                     abilities.reflectPercent[combatTypeToIndex(COMBAT_ENERGYDAMAGE)] += value;
  1159.                                     abilities.reflectPercent[combatTypeToIndex(COMBAT_FIREDAMAGE)] += value;
  1160.                                     abilities.reflectPercent[combatTypeToIndex(COMBAT_EARTHDAMAGE)] += value;
  1161.                                     abilities.reflectPercent[combatTypeToIndex(COMBAT_ICEDAMAGE)] += value;
  1162.                                     abilities.reflectPercent[combatTypeToIndex(COMBAT_HOLYDAMAGE)] += value;
  1163.                                     abilities.reflectPercent[combatTypeToIndex(COMBAT_DEATHDAMAGE)] += value;
  1164.                                 }
  1165.                                 else if (lkey == "absorbpercentelements") {
  1166.                                     int16_t value = g_lua.getNumber<int16_t>(L, -1);
  1167.                                     Abilities& abilities = it.getAbilities();
  1168.                                     abilities.absorbPercent[combatTypeToIndex(COMBAT_ENERGYDAMAGE)] += value;
  1169.                                     abilities.absorbPercent[combatTypeToIndex(COMBAT_FIREDAMAGE)] += value;
  1170.                                     abilities.absorbPercent[combatTypeToIndex(COMBAT_EARTHDAMAGE)] += value;
  1171.                                     abilities.absorbPercent[combatTypeToIndex(COMBAT_ICEDAMAGE)] += value;
  1172.                                 }
  1173.                                 else if (lkey == "absorbpercentmagic") {
  1174.                                     int16_t value = g_lua.getNumber<int16_t>(L, -1);
  1175.                                     Abilities& abilities = it.getAbilities();
  1176.                                     abilities.absorbPercent[combatTypeToIndex(COMBAT_ENERGYDAMAGE)] += value;
  1177.                                     abilities.absorbPercent[combatTypeToIndex(COMBAT_FIREDAMAGE)] += value;
  1178.                                     abilities.absorbPercent[combatTypeToIndex(COMBAT_EARTHDAMAGE)] += value;
  1179.                                     abilities.absorbPercent[combatTypeToIndex(COMBAT_ICEDAMAGE)] += value;
  1180.                                     abilities.absorbPercent[combatTypeToIndex(COMBAT_HOLYDAMAGE)] += value;
  1181.                                     abilities.absorbPercent[combatTypeToIndex(COMBAT_DEATHDAMAGE)] += value;
  1182.                                 }
  1183.                                 else if (absorbTypes[lkey]) {
  1184.                                     it.getAbilities().absorbPercent[combatTypeToIndex(absorbTypes[lkey])] += g_lua.getNumber<int16_t>(L, -1);
  1185.                                 }
  1186.                                 else if (reflectTypes[lkey]) {
  1187.                                     it.getAbilities().reflectPercent[combatTypeToIndex(reflectTypes[lkey])] += g_lua.getNumber<int16_t>(L, -1);
  1188.                                 }
  1189.                                 else if (lkey == "suppressdrunk") {
  1190.                                     if (g_lua.getBoolean(L, -1)) {
  1191.                                         it.getAbilities().conditionSuppressions |= CONDITION_DRUNK;
  1192.                                     }
  1193.                                 }
  1194.                                 else if (lkey == "suppressenergy") {
  1195.                                     if (g_lua.getBoolean(L, -1)) {
  1196.                                         it.getAbilities().conditionSuppressions |= CONDITION_ENERGY;
  1197.                                     }
  1198.                                 }
  1199.                                 else if (lkey == "suppressfire") {
  1200.                                     if (g_lua.getBoolean(L, -1)) {
  1201.                                         it.getAbilities().conditionSuppressions |= CONDITION_FIRE;
  1202.                                     }
  1203.                                 }
  1204.                                 else if (lkey == "suppresspoison") {
  1205.                                     if (g_lua.getBoolean(L, -1)) {
  1206.                                         it.getAbilities().conditionSuppressions |= CONDITION_POISON;
  1207.                                     }
  1208.                                 }
  1209.                                 else if (lkey == "suppressdrown") {
  1210.                                     if (g_lua.getBoolean(L, -1)) {
  1211.                                         it.getAbilities().conditionSuppressions |= CONDITION_DROWN;
  1212.                                     }
  1213.                                 }
  1214.                                 else if (lkey == "suppressphysical") {
  1215.                                     if (g_lua.getBoolean(L, -1)) {
  1216.                                         it.getAbilities().conditionSuppressions |= CONDITION_BLEEDING;
  1217.                                     }
  1218.                                 }
  1219.                                 else if (lkey == "suppressfreeze") {
  1220.                                     if (g_lua.getBoolean(L, -1)) {
  1221.                                         it.getAbilities().conditionSuppressions |= CONDITION_FREEZING;
  1222.                                     }
  1223.                                 }
  1224.                                 else if (lkey == "suppressdazzle") {
  1225.                                     if (g_lua.getBoolean(L, -1)) {
  1226.                                         it.getAbilities().conditionSuppressions |= CONDITION_DAZZLED;
  1227.                                     }
  1228.                                 }
  1229.                                 else if (lkey == "suppresscurse") {
  1230.                                     if (g_lua.getBoolean(L, -1)) {
  1231.                                         it.getAbilities().conditionSuppressions |= CONDITION_CURSED;
  1232.                                     }
  1233.                                 }
  1234.                                 else if (lkey == "field") {
  1235.                                     it.group = ITEM_GROUP_MAGICFIELD;
  1236.                                     it.type = ITEM_TYPE_MAGICFIELD;
  1237.  
  1238.  
  1239.                                     tmpStrValue = asLowerCaseString(g_lua.getString(L, -1));
  1240.                                     if (!conTypes[tmpStrValue]) {
  1241.                                         std::cout << "[Warning - Items::parseItemNodeLua] Unknown field value: " << tmpStrValue << std::endl;
  1242.                                     }
  1243.                                     else {
  1244.                                         combatType = comTypes[conTypes[tmpStrValue]];
  1245.                                     }
  1246.  
  1247.                                 }
  1248.                                 // eliminate setting damage in the sources for now
  1249.                                 else if (lkey == "replaceable") {
  1250.                                     it.replaceable = g_lua.getBoolean(L, -1);
  1251.                                 }
  1252.                                 else if (lkey == "partnerdirection") {
  1253.                                     it.bedPartnerDir = getDirection(g_lua.getString(L, -1));
  1254.                                 }
  1255.                                 else if (lkey == "leveldoor") {
  1256.                                     it.levelDoor = g_lua.getNumber<uint32_t>(L, -1);
  1257.                                 }
  1258.                                 else if (lkey == "maletransformto" || lkey == "malesleeper") {
  1259.                                     uint16_t value = g_lua.getNumber<uint16_t>(L, -1);
  1260.                                     it.transformToOnUse[PLAYERSEX_MALE] = value;
  1261.                                     ItemType& other = getItemType(value);
  1262.                                     if (other.transformToFree == 0) {
  1263.                                         other.transformToFree = it.id;
  1264.                                     }
  1265.  
  1266.                                     if (it.transformToOnUse[PLAYERSEX_FEMALE] == 0) {
  1267.                                         it.transformToOnUse[PLAYERSEX_FEMALE] = value;
  1268.                                     }
  1269.                                 }
  1270.                                 else if (lkey == "femaletransformto" || lkey == "femalesleeper") {
  1271.                                     uint16_t value = g_lua.getNumber<uint16_t>(L, -1);
  1272.                                     it.transformToOnUse[PLAYERSEX_FEMALE] = value;
  1273.  
  1274.                                     ItemType& other = getItemType(value);
  1275.                                     if (other.transformToFree == 0) {
  1276.                                         other.transformToFree = it.id;
  1277.                                     }
  1278.  
  1279.                                     if (it.transformToOnUse[PLAYERSEX_MALE] == 0) {
  1280.                                         it.transformToOnUse[PLAYERSEX_MALE] = value;
  1281.                                     }
  1282.                                 }
  1283.                                 else if (lkey == "transformto") {
  1284.                                     it.transformToFree = g_lua.getNumber<uint16_t>(L, -1);
  1285.                                 }
  1286.                                 else if (lkey == "destroyto") {
  1287.                                     it.destroyTo = g_lua.getNumber<uint16_t>(L, -1);
  1288.                                 }
  1289.                                 else if (lkey == "elementice") {
  1290.                                     Abilities& abilities = it.getAbilities();
  1291.                                     abilities.elementDamage = g_lua.getNumber<uint16_t>(L, -1);
  1292.                                     abilities.elementType = COMBAT_ICEDAMAGE;
  1293.                                 }
  1294.                                 else if (lkey == "elementearth") {
  1295.                                     Abilities& abilities = it.getAbilities();
  1296.                                     abilities.elementDamage = g_lua.getNumber<uint16_t>(L, -1);
  1297.                                     abilities.elementType = COMBAT_EARTHDAMAGE;
  1298.                                 }
  1299.                                 else if (lkey == "elementfire") {
  1300.                                     Abilities& abilities = it.getAbilities();
  1301.                                     abilities.elementDamage = g_lua.getNumber<uint16_t>(L, -1);
  1302.                                     abilities.elementType = COMBAT_FIREDAMAGE;
  1303.                                 }
  1304.                                 else if (lkey == "elementenergy") {
  1305.                                     Abilities& abilities = it.getAbilities();
  1306.                                     abilities.elementDamage = g_lua.getNumber<uint16_t>(L, -1);
  1307.                                     abilities.elementType = COMBAT_ENERGYDAMAGE;
  1308.                                 }
  1309.                                 else if (lkey == "elementdeath") {
  1310.                                     Abilities& abilities = it.getAbilities();
  1311.                                     abilities.elementDamage = g_lua.getNumber<uint16_t>(L, -1);
  1312.                                     abilities.elementType = COMBAT_DEATHDAMAGE;
  1313.                                 }
  1314.                                 else if (lkey == "elementholy") {
  1315.                                     Abilities& abilities = it.getAbilities();
  1316.                                     abilities.elementDamage = g_lua.getNumber<uint16_t>(L, -1);
  1317.                                     abilities.elementType = COMBAT_HOLYDAMAGE;
  1318.                                 }
  1319.                                 else if (lkey == "walkstack") {
  1320.                                     it.walkStack = g_lua.getBoolean(L, -1);
  1321.                                 }
  1322.                                 else if (lkey == "blocking") {
  1323.                                     it.blockSolid = g_lua.getBoolean(L, -1);
  1324.                                 }
  1325.                                 else if (lkey == "allowdistread") {
  1326.                                     it.allowDistRead = booleanString(g_lua.getString(L, -1));
  1327.                                 }
  1328.                                 else {
  1329.                                     std::cout << "[Warning - Items::parseItemNodeLua] Unknown key value: " << lkey << std::endl;
  1330.                                 }
  1331.  
  1332.                             }// end of value
  1333.  
  1334.                              //check bed items
  1335.                             if ((it.transformToFree != 0 || it.transformToOnUse[PLAYERSEX_FEMALE] != 0 || it.transformToOnUse[PLAYERSEX_MALE] != 0) && it.type != ITEM_TYPE_BED) {
  1336.                                 //std::cout << "[Warning - Items::parseItemNodeLua] Item " << it.id << " is not set as a bed-type" << std::endl;
  1337.                             }//
  1338.                             lua_pop(L, 1);
  1339.                         }// end of inner for loop  
  1340.                         lua_pop(L, 1);
  1341.                     }
  1342.  
  1343.                 }// end of objlen
  1344.             }// end of attributes
  1345.             lua_pop(L, 1);
  1346.             break;
  1347.         } // end of outter switch
  1348.         lua_pop(L, 1);
  1349.     }//end of outter loop
  1350. }
  1351.  
  1352. // this function not only parses the items.xml but it also can construct items.xml in a lua table
  1353. void Items::parseItemNode(const pugi::xml_node& itemNode, uint16_t id, std::ofstream& out, bool constructTable)
  1354. {
  1355.     bool description = false, field = false;
  1356.     std::string parser, pattribute, desc, key, pfield = "";
  1357.     if (constructTable) {
  1358.         parser = "\t{\n\t\titemid = " + std::to_string(id) + ", ";
  1359.     }
  1360.     if (id > 30000 && id < 30100) {
  1361.         id -= 30000;
  1362.  
  1363.         if (id >= items.size()) {
  1364.             items.resize(id + 1);
  1365.         }
  1366.         ItemType& iType = items[id];
  1367.         iType.id = id;
  1368.     }
  1369.  
  1370.     ItemType& it = getItemType(id);
  1371.     if (it.id == 0) {
  1372.         return;
  1373.     }
  1374.  
  1375.     it.name = itemNode.attribute("name").as_string();
  1376.     if (constructTable) {
  1377.         parser += "name = \"" + it.name + "\", ";
  1378.     }
  1379.     pugi::xml_attribute articleAttribute = itemNode.attribute("article");
  1380.     if (articleAttribute) {
  1381.         it.article = articleAttribute.as_string();
  1382.         if (constructTable) {
  1383.             parser += "article = \"" + it.article + "\", ";
  1384.         }
  1385.     }
  1386.  
  1387.     pugi::xml_attribute pluralAttribute = itemNode.attribute("plural");
  1388.     if (pluralAttribute) {
  1389.         it.pluralName = pluralAttribute.as_string();
  1390.         if (constructTable) {
  1391.             parser += "plural = \"" + it.pluralName + "\", ";
  1392.         }
  1393.     }
  1394.  
  1395.     for (auto attributeNode : itemNode.children()) {
  1396.         pugi::xml_attribute keyAttribute = attributeNode.attribute("key");
  1397.         if (!keyAttribute) {
  1398.             continue;
  1399.         }
  1400.         if (constructTable) {
  1401.             key = asLowerCaseString(keyAttribute.as_string());
  1402.             if (key == "description")
  1403.             {
  1404.                 description = true;
  1405.             }
  1406.             //out << "\t\t\t{ key = \"" << key << "\", ";
  1407.             if (key == "field") {
  1408.                 field = true;
  1409.                 //pfield += "\t\t\t{ key = \"" + key + "\", ";
  1410.             }
  1411.             else {
  1412.                 pattribute += "\t\t\t{ key = \"" + key + "\", ";
  1413.             }
  1414.  
  1415.         }
  1416.  
  1417.         pugi::xml_attribute valueAttribute = attributeNode.attribute("value");
  1418.         if (!valueAttribute) {
  1419.             continue;
  1420.         }
  1421.         if (constructTable) {
  1422.             desc = valueAttribute.as_string();
  1423.             if (description) {
  1424.                 desc = alterString(desc, "\"", "'");
  1425.             }
  1426.             //out << "value = \"" << desc << "\" },\n";
  1427.             if (field) {
  1428.                 //pfield += "value = \"" + desc + "\" },\n";
  1429.             }
  1430.             else {
  1431.                 pattribute += "value = \"" + desc + "\" },\n";
  1432.             }
  1433.         }
  1434.         std::string tmpStrValue = asLowerCaseString(keyAttribute.as_string());
  1435.         if (tmpStrValue == "type") {
  1436.             tmpStrValue = asLowerCaseString(valueAttribute.as_string());
  1437.             if (tmpStrValue == "key") {
  1438.                 it.type = ITEM_TYPE_KEY;
  1439.             }
  1440.             else if (tmpStrValue == "magicfield") {
  1441.                 it.type = ITEM_TYPE_MAGICFIELD;
  1442.             }
  1443.             else if (tmpStrValue == "container") {
  1444.                 it.group = ITEM_GROUP_CONTAINER;
  1445.                 it.type = ITEM_TYPE_CONTAINER;
  1446.             }
  1447.             else if (tmpStrValue == "depot") {
  1448.                 it.type = ITEM_TYPE_DEPOT;
  1449.             }
  1450.             else if (tmpStrValue == "rewardchest") {
  1451.                 it.type = ITEM_TYPE_REWARDCHEST;
  1452.             }
  1453.             else if (tmpStrValue == "mailbox") {
  1454.                 it.type = ITEM_TYPE_MAILBOX;
  1455.             }
  1456.             else if (tmpStrValue == "trashholder") {
  1457.                 it.type = ITEM_TYPE_TRASHHOLDER;
  1458.             }
  1459.             else if (tmpStrValue == "teleport") {
  1460.                 it.type = ITEM_TYPE_TELEPORT;
  1461.             }
  1462.             else if (tmpStrValue == "door") {
  1463.                 it.type = ITEM_TYPE_DOOR;
  1464.             }
  1465.             else if (tmpStrValue == "bed") {
  1466.                 it.type = ITEM_TYPE_BED;
  1467.             }
  1468.             else if (tmpStrValue == "rune") {
  1469.                 it.type = ITEM_TYPE_RUNE;
  1470.             }
  1471.             else {
  1472.                 std::cout << "[Warning - Items::parseItemNode] Unknown type: " << valueAttribute.as_string() << std::endl;
  1473.             }
  1474.         }
  1475.         else if (tmpStrValue == "description") {
  1476.             it.description = valueAttribute.as_string();
  1477.         }
  1478.         else if (tmpStrValue == "runespellname") {
  1479.             it.runeSpellName = valueAttribute.as_string();
  1480.         }
  1481.         else if (tmpStrValue == "weight") {
  1482.             it.weight = pugi::cast<uint32_t>(valueAttribute.value());
  1483.         }// custom added
  1484.         else if (tmpStrValue == "tier") {
  1485.             it.tier = pugi::cast<uint32_t>(valueAttribute.value());
  1486.         }
  1487.         else if (tmpStrValue == "power") {
  1488.             it.power = pugi::cast<uint32_t>(valueAttribute.value());
  1489.         }
  1490.         else if (tmpStrValue == "heal") {
  1491.             it.heal = pugi::cast<uint32_t>(valueAttribute.value());
  1492.         }// custom added
  1493.         else if (tmpStrValue == "showcount") {
  1494.             it.showCount = valueAttribute.as_bool();
  1495.         }
  1496.         else if (tmpStrValue == "armor") {
  1497.             it.armor = pugi::cast<int32_t>(valueAttribute.value());
  1498.         }
  1499.         else if (tmpStrValue == "defense") {
  1500.             it.defense = pugi::cast<int32_t>(valueAttribute.value());
  1501.         }
  1502.         else if (tmpStrValue == "extradef") {
  1503.             it.extraDefense = pugi::cast<int32_t>(valueAttribute.value());
  1504.         }
  1505.         else if (tmpStrValue == "attack") {
  1506.             it.attack = pugi::cast<int32_t>(valueAttribute.value());
  1507.         }
  1508.         else if (tmpStrValue == "rotateto") {
  1509.             it.rotateTo = pugi::cast<int32_t>(valueAttribute.value());
  1510.         }
  1511.         else if (tmpStrValue == "moveable" || tmpStrValue == "movable") {
  1512.             it.moveable = valueAttribute.as_bool();
  1513.         }
  1514.         else if (tmpStrValue == "blockprojectile") {
  1515.             it.blockProjectile = valueAttribute.as_bool();
  1516.         }
  1517.         else if (tmpStrValue == "allowpickupable" || tmpStrValue == "pickupable") {
  1518.             it.allowPickupable = valueAttribute.as_bool();
  1519.         }
  1520.         else if (tmpStrValue == "floorchange") {
  1521.             tmpStrValue = asLowerCaseString(valueAttribute.as_string());
  1522.             if (tmpStrValue == "down") {
  1523.                 it.floorChange = TILESTATE_FLOORCHANGE_DOWN;
  1524.             }
  1525.             else if (tmpStrValue == "north") {
  1526.                 it.floorChange = TILESTATE_FLOORCHANGE_NORTH;
  1527.             }
  1528.             else if (tmpStrValue == "south") {
  1529.                 it.floorChange = TILESTATE_FLOORCHANGE_SOUTH;
  1530.             }
  1531.             else if (tmpStrValue == "southalt") {
  1532.                 it.floorChange = TILESTATE_FLOORCHANGE_SOUTH_ALT;
  1533.             }
  1534.             else if (tmpStrValue == "west") {
  1535.                 it.floorChange = TILESTATE_FLOORCHANGE_WEST;
  1536.             }
  1537.             else if (tmpStrValue == "east") {
  1538.                 it.floorChange = TILESTATE_FLOORCHANGE_EAST;
  1539.             }
  1540.             else if (tmpStrValue == "eastalt") {
  1541.                 it.floorChange = TILESTATE_FLOORCHANGE_EAST_ALT;
  1542.             }
  1543.             else {
  1544.                 std::cout << "[Warning - Items::parseItemNode] Unknown floorChange: " << valueAttribute.as_string() << std::endl;
  1545.             }
  1546.         }
  1547.         else if (tmpStrValue == "corpsetype") {
  1548.             tmpStrValue = asLowerCaseString(valueAttribute.as_string());
  1549.             if (tmpStrValue == "venom") {
  1550.                 it.corpseType = RACE_VENOM;
  1551.             }
  1552.             else if (tmpStrValue == "blood") {
  1553.                 it.corpseType = RACE_BLOOD;
  1554.             }
  1555.             else if (tmpStrValue == "undead") {
  1556.                 it.corpseType = RACE_UNDEAD;
  1557.             }
  1558.             else if (tmpStrValue == "fire") {
  1559.                 it.corpseType = RACE_FIRE;
  1560.             }
  1561.             else if (tmpStrValue == "energy") {
  1562.                 it.corpseType = RACE_ENERGY;
  1563.             }
  1564.             else {
  1565.                 std::cout << "[Warning - Items::parseItemNode] Unknown corpseType: " << valueAttribute.as_string() << std::endl;
  1566.             }
  1567.         }
  1568.         else if (tmpStrValue == "containersize") {
  1569.             it.maxItems = pugi::cast<uint16_t>(valueAttribute.value());
  1570.         }
  1571.         else if (tmpStrValue == "fluidsource") {
  1572.             tmpStrValue = asLowerCaseString(valueAttribute.as_string());
  1573.             if (tmpStrValue == "water") {
  1574.                 it.fluidSource = FLUID_WATER;
  1575.             }
  1576.             else if (tmpStrValue == "blood") {
  1577.                 it.fluidSource = FLUID_BLOOD;
  1578.             }
  1579.             else if (tmpStrValue == "beer") {
  1580.                 it.fluidSource = FLUID_BEER;
  1581.             }
  1582.             else if (tmpStrValue == "slime") {
  1583.                 it.fluidSource = FLUID_SLIME;
  1584.             }
  1585.             else if (tmpStrValue == "lemonade") {
  1586.                 it.fluidSource = FLUID_LEMONADE;
  1587.             }
  1588.             else if (tmpStrValue == "milk") {
  1589.                 it.fluidSource = FLUID_MILK;
  1590.             }
  1591.             else if (tmpStrValue == "mana") {
  1592.                 it.fluidSource = FLUID_MANA;
  1593.             }
  1594.             else if (tmpStrValue == "life") {
  1595.                 it.fluidSource = FLUID_LIFE;
  1596.             }
  1597.             else if (tmpStrValue == "oil") {
  1598.                 it.fluidSource = FLUID_OIL;
  1599.             }
  1600.             else if (tmpStrValue == "urine") {
  1601.                 it.fluidSource = FLUID_URINE;
  1602.             }
  1603.             else if (tmpStrValue == "coconut") {
  1604.                 it.fluidSource = FLUID_COCONUTMILK;
  1605.             }
  1606.             else if (tmpStrValue == "wine") {
  1607.                 it.fluidSource = FLUID_WINE;
  1608.             }
  1609.             else if (tmpStrValue == "mud") {
  1610.                 it.fluidSource = FLUID_MUD;
  1611.             }
  1612.             else if (tmpStrValue == "fruitjuice") {
  1613.                 it.fluidSource = FLUID_FRUITJUICE;
  1614.             }
  1615.             else if (tmpStrValue == "lava") {
  1616.                 it.fluidSource = FLUID_LAVA;
  1617.             }
  1618.             else if (tmpStrValue == "rum") {
  1619.                 it.fluidSource = FLUID_RUM;
  1620.             }
  1621.             else if (tmpStrValue == "swamp") {
  1622.                 it.fluidSource = FLUID_SWAMP;
  1623.             }
  1624.             else if (tmpStrValue == "tea") {
  1625.                 it.fluidSource = FLUID_TEA;
  1626.             }
  1627.             else if (tmpStrValue == "mead") {
  1628.                 it.fluidSource = FLUID_MEAD;
  1629.             }
  1630.             else {
  1631.                 std::cout << "[Warning - Items::parseItemNode] Unknown fluidSource: " << valueAttribute.as_string() << std::endl;
  1632.             }
  1633.         }
  1634.         else if (tmpStrValue == "readable") {
  1635.             it.canReadText = valueAttribute.as_bool();
  1636.         }
  1637.         else if (tmpStrValue == "writeable") {
  1638.             it.canWriteText = valueAttribute.as_bool();
  1639.             it.canReadText = it.canWriteText;
  1640.         }
  1641.         else if (tmpStrValue == "maxtextlen") {
  1642.             it.maxTextLen = pugi::cast<uint16_t>(valueAttribute.value());
  1643.         }
  1644.         else if (tmpStrValue == "writeonceitemid") {
  1645.             it.writeOnceItemId = pugi::cast<uint16_t>(valueAttribute.value());
  1646.         }
  1647.         else if (tmpStrValue == "weapontype") {
  1648.             tmpStrValue = asLowerCaseString(valueAttribute.as_string());
  1649.             if (tmpStrValue == "sword") {
  1650.                 it.weaponType = WEAPON_SWORD;
  1651.             }
  1652.             else if (tmpStrValue == "club") {
  1653.                 it.weaponType = WEAPON_CLUB;
  1654.             }
  1655.             else if (tmpStrValue == "axe") {
  1656.                 it.weaponType = WEAPON_AXE;
  1657.             }
  1658.             else if (tmpStrValue == "shield") {
  1659.                 it.weaponType = WEAPON_SHIELD;
  1660.             }
  1661.             else if (tmpStrValue == "distance") {
  1662.                 it.weaponType = WEAPON_DISTANCE;
  1663.             }
  1664.             else if (tmpStrValue == "wand") {
  1665.                 it.weaponType = WEAPON_WAND;
  1666.             }
  1667.             else if (tmpStrValue == "ammunition") {
  1668.                 it.weaponType = WEAPON_AMMO;
  1669.             }
  1670.             else if (tmpStrValue == "fist") {
  1671.                 it.weaponType = WEAPON_FIST;
  1672.             }
  1673.             else {
  1674.                 std::cout << "[Warning - Items::parseItemNode] Unknown weaponType: " << valueAttribute.as_string() << std::endl;
  1675.             }
  1676.         }
  1677.         else if (tmpStrValue == "slottype") {
  1678.             tmpStrValue = asLowerCaseString(valueAttribute.as_string());
  1679.             if (tmpStrValue == "head") {
  1680.                 it.slotPosition |= SLOTP_HEAD;
  1681.             }
  1682.             else if (tmpStrValue == "body") {
  1683.                 it.slotPosition |= SLOTP_ARMOR;
  1684.             }
  1685.             else if (tmpStrValue == "legs") {
  1686.                 it.slotPosition |= SLOTP_LEGS;
  1687.             }
  1688.             else if (tmpStrValue == "feet") {
  1689.                 it.slotPosition |= SLOTP_FEET;
  1690.             }
  1691.             else if (tmpStrValue == "backpack") {
  1692.                 it.slotPosition |= SLOTP_BACKPACK;
  1693.             }
  1694.             else if (tmpStrValue == "two-handed") {
  1695.                 it.slotPosition |= SLOTP_TWO_HAND;
  1696.             }
  1697.             else if (tmpStrValue == "right-hand") {
  1698.                 it.slotPosition &= ~SLOTP_LEFT;
  1699.             }
  1700.             else if (tmpStrValue == "left-hand") {
  1701.                 it.slotPosition &= ~SLOTP_RIGHT;
  1702.             }
  1703.             else if (tmpStrValue == "necklace") {
  1704.                 it.slotPosition |= SLOTP_NECKLACE;
  1705.             }
  1706.             else if (tmpStrValue == "ring") {
  1707.                 it.slotPosition |= SLOTP_RING;
  1708.             }
  1709.             else if (tmpStrValue == "ammo") {
  1710.                 it.slotPosition |= SLOTP_AMMO;
  1711.             }
  1712.             else if (tmpStrValue == "hand") {
  1713.                 it.slotPosition |= SLOTP_HAND;
  1714.             }
  1715.             else {
  1716.                 std::cout << "[Warning - Items::parseItemNode] Unknown slotType: " << valueAttribute.as_string() << std::endl;
  1717.             }
  1718.         }
  1719.         else if (tmpStrValue == "ammotype") {
  1720.             it.ammoType = getAmmoType(valueAttribute.as_string());
  1721.             if (it.ammoType == AMMO_NONE) {
  1722.                 std::cout << "[Warning - Items::parseItemNode] Unknown ammoType: " << valueAttribute.as_string() << std::endl;
  1723.             }
  1724.         }
  1725.         else if (tmpStrValue == "shoottype") {
  1726.             ShootType_t shoot = getShootType(valueAttribute.as_string());
  1727.             if (shoot != CONST_ANI_NONE) {
  1728.                 it.shootType = shoot;
  1729.             }
  1730.             else {
  1731.                 std::cout << "[Warning - Items::parseItemNode] Unknown shootType: " << valueAttribute.as_string() << std::endl;
  1732.             }
  1733.         }
  1734.         else if (tmpStrValue == "effect") {
  1735.             MagicEffectClasses effect = getMagicEffect(valueAttribute.as_string());
  1736.             if (effect != CONST_ME_NONE) {
  1737.                 it.magicEffect = effect;
  1738.             }
  1739.             else {
  1740.                 std::cout << "[Warning - Items::parseItemNode] Unknown effect: " << valueAttribute.as_string() << std::endl;
  1741.             }
  1742.         }
  1743.         else if (tmpStrValue == "range") {
  1744.             it.shootRange = pugi::cast<uint16_t>(valueAttribute.value());
  1745.         }
  1746.         else if (tmpStrValue == "stopduration") {
  1747.             it.stopTime = valueAttribute.as_bool();
  1748.         }
  1749.         else if (tmpStrValue == "decayto") {
  1750.             it.decayTo = pugi::cast<int32_t>(valueAttribute.value());
  1751.         }
  1752.         else if (tmpStrValue == "transformequipto") {
  1753.             it.transformEquipTo = pugi::cast<uint16_t>(valueAttribute.value());
  1754.         }
  1755.         else if (tmpStrValue == "transformdeequipto") {
  1756.             it.transformDeEquipTo = pugi::cast<uint16_t>(valueAttribute.value());
  1757.         }
  1758.         else if (tmpStrValue == "duration") {
  1759.             it.decayTime = pugi::cast<uint32_t>(valueAttribute.value());
  1760.         }
  1761.         else if (tmpStrValue == "showduration") {
  1762.             it.showDuration = valueAttribute.as_bool();
  1763.         }
  1764.         else if (tmpStrValue == "charges") {
  1765.             it.charges = pugi::cast<uint32_t>(valueAttribute.value());
  1766.         }
  1767.         else if (tmpStrValue == "showcharges") {
  1768.             it.showCharges = valueAttribute.as_bool();
  1769.         }
  1770.         else if (tmpStrValue == "showattributes") {
  1771.             it.showAttributes = valueAttribute.as_bool();
  1772.         }
  1773.         else if (tmpStrValue == "hitchance") {
  1774.             it.hitChance = std::min<int8_t>(100, std::max<int8_t>(-100, pugi::cast<int16_t>(valueAttribute.value())));
  1775.         }
  1776.         else if (tmpStrValue == "maxhitchance") {
  1777.             it.maxHitChance = std::min<uint32_t>(100, pugi::cast<uint32_t>(valueAttribute.value()));
  1778.         }
  1779.         else if (tmpStrValue == "invisible") {
  1780.             it.getAbilities().invisible = valueAttribute.as_bool();
  1781.         }
  1782.         else if (tmpStrValue == "speed") {
  1783.             it.getAbilities().speed = pugi::cast<int32_t>(valueAttribute.value());
  1784.         }
  1785.         else if (tmpStrValue == "healthgain") {
  1786.             Abilities& abilities = it.getAbilities();
  1787.             abilities.regeneration = true;
  1788.             abilities.healthGain = pugi::cast<uint32_t>(valueAttribute.value());
  1789.         }
  1790.         else if (tmpStrValue == "healthticks") {
  1791.             Abilities& abilities = it.getAbilities();
  1792.             abilities.regeneration = true;
  1793.             abilities.healthTicks = pugi::cast<uint32_t>(valueAttribute.value());
  1794.         }
  1795.         else if (tmpStrValue == "managain") {
  1796.             Abilities& abilities = it.getAbilities();
  1797.             abilities.regeneration = true;
  1798.             abilities.manaGain = pugi::cast<uint32_t>(valueAttribute.value());
  1799.         }
  1800.         else if (tmpStrValue == "manaticks") {
  1801.             Abilities& abilities = it.getAbilities();
  1802.             abilities.regeneration = true;
  1803.             abilities.manaTicks = pugi::cast<uint32_t>(valueAttribute.value());
  1804.         }
  1805.         else if (tmpStrValue == "manashield") {
  1806.             it.getAbilities().manaShield = valueAttribute.as_bool();
  1807.         }
  1808.         else if (tmpStrValue == "skillsword") {
  1809.             it.getAbilities().skills[SKILL_SWORD] = pugi::cast<int32_t>(valueAttribute.value());
  1810.         }
  1811.         else if (tmpStrValue == "skillaxe") {
  1812.             it.getAbilities().skills[SKILL_AXE] = pugi::cast<int32_t>(valueAttribute.value());
  1813.         }
  1814.         else if (tmpStrValue == "skillclub") {
  1815.             it.getAbilities().skills[SKILL_CLUB] = pugi::cast<int32_t>(valueAttribute.value());
  1816.         }
  1817.         else if (tmpStrValue == "skilldist") {
  1818.             it.getAbilities().skills[SKILL_DISTANCE] = pugi::cast<int32_t>(valueAttribute.value());
  1819.         }
  1820.         else if (tmpStrValue == "skillfish") {
  1821.             it.getAbilities().skills[SKILL_FISHING] = pugi::cast<int32_t>(valueAttribute.value());
  1822.         }
  1823.         else if (tmpStrValue == "skillshield") {
  1824.             it.getAbilities().skills[SKILL_SHIELD] = pugi::cast<int32_t>(valueAttribute.value());
  1825.         }
  1826.         else if (tmpStrValue == "skillfist") {
  1827.             it.getAbilities().skills[SKILL_FIST] = pugi::cast<int32_t>(valueAttribute.value());
  1828.         }
  1829.         else if (tmpStrValue == "skillcriticalchance") {
  1830.             it.getAbilities().skills[SKILL_CRITICAL_HIT_CHANCE] = pugi::cast<int32_t>(valueAttribute.value());
  1831.         }
  1832.         else if (tmpStrValue == "skillcriticaldamage") {
  1833.             it.getAbilities().skills[SKILL_CRITICAL_HIT_DAMAGE] = pugi::cast<int32_t>(valueAttribute.value());
  1834.         }
  1835.         else if (tmpStrValue == "skilllifechance") {
  1836.             it.getAbilities().skills[SKILL_LIFE_LEECH_CHANCE] = pugi::cast<int32_t>(valueAttribute.value());
  1837.         }
  1838.         else if (tmpStrValue == "skilllifeamount") {
  1839.             it.getAbilities().skills[SKILL_LIFE_LEECH_AMOUNT] = pugi::cast<int32_t>(valueAttribute.value());
  1840.         }
  1841.         else if (tmpStrValue == "skillmanachance") {
  1842.             it.getAbilities().skills[SKILL_MANA_LEECH_CHANCE] = pugi::cast<int32_t>(valueAttribute.value());
  1843.         }
  1844.         else if (tmpStrValue == "skillmanaamount") {
  1845.             it.getAbilities().skills[SKILL_MANA_LEECH_AMOUNT] = pugi::cast<int32_t>(valueAttribute.value());
  1846.         }
  1847.         else if (tmpStrValue == "maxhitpoints") {
  1848.             it.getAbilities().stats[STAT_MAXHITPOINTS] = pugi::cast<int32_t>(valueAttribute.value());
  1849.         }
  1850.         else if (tmpStrValue == "maxhitpointspercent") {
  1851.             it.getAbilities().statsPercent[STAT_MAXHITPOINTS] = pugi::cast<int32_t>(valueAttribute.value());
  1852.         }
  1853.         else if (tmpStrValue == "maxmanapoints") {
  1854.             it.getAbilities().stats[STAT_MAXMANAPOINTS] = pugi::cast<int32_t>(valueAttribute.value());
  1855.         }
  1856.         else if (tmpStrValue == "maxmanapointspercent") {
  1857.             it.getAbilities().statsPercent[STAT_MAXMANAPOINTS] = pugi::cast<int32_t>(valueAttribute.value());
  1858.         }
  1859.         else if (tmpStrValue == "magicpoints" || tmpStrValue == "magiclevelpoints") {
  1860.             it.getAbilities().stats[STAT_MAGICPOINTS] = pugi::cast<int32_t>(valueAttribute.value());
  1861.         }
  1862.         else if (tmpStrValue == "magicpointspercent") {
  1863.             it.getAbilities().statsPercent[STAT_MAGICPOINTS] = pugi::cast<int32_t>(valueAttribute.value());
  1864.         }
  1865.         else if (tmpStrValue == "fieldabsorbpercentenergy") {
  1866.             it.getAbilities().fieldAbsorbPercent[combatTypeToIndex(COMBAT_ENERGYDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  1867.         }
  1868.         else if (tmpStrValue == "fieldabsorbpercentfire") {
  1869.             it.getAbilities().fieldAbsorbPercent[combatTypeToIndex(COMBAT_FIREDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  1870.         }
  1871.         else if (tmpStrValue == "fieldabsorbpercentpoison" || tmpStrValue == "fieldabsorpercentearth") {
  1872.             it.getAbilities().fieldAbsorbPercent[combatTypeToIndex(COMBAT_EARTHDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  1873.         }
  1874.         else if (tmpStrValue == "absorbpercentall" || tmpStrValue == "absorbpercentallelements") {
  1875.             int16_t value = pugi::cast<int16_t>(valueAttribute.value());
  1876.             Abilities& abilities = it.getAbilities();
  1877.             for (size_t i = 0; i < COMBAT_COUNT; ++i) {
  1878.                 abilities.absorbPercent[i] += value;
  1879.             }
  1880.         }
  1881.         else if (tmpStrValue == "reflectpercentall" || tmpStrValue == "reflectpercentallelements") {
  1882.             int16_t value = pugi::cast<int16_t>(valueAttribute.value());
  1883.             Abilities& abilities = it.getAbilities();
  1884.             for (size_t i = 0; i < COMBAT_COUNT; i++) {
  1885.                 abilities.reflectPercent[i] += value;
  1886.             }
  1887.         }
  1888.         else if (tmpStrValue == "reflectbpercentelements") {
  1889.             int16_t value = pugi::cast<int16_t>(valueAttribute.value());
  1890.             Abilities& abilities = it.getAbilities();
  1891.             abilities.reflectPercent[combatTypeToIndex(COMBAT_ENERGYDAMAGE)] += value;
  1892.             abilities.reflectPercent[combatTypeToIndex(COMBAT_FIREDAMAGE)] += value;
  1893.             abilities.reflectPercent[combatTypeToIndex(COMBAT_EARTHDAMAGE)] += value;
  1894.             abilities.reflectPercent[combatTypeToIndex(COMBAT_ICEDAMAGE)] += value;
  1895.         }
  1896.         else if (tmpStrValue == "reflectpercentmagic") {
  1897.             int16_t value = pugi::cast<int16_t>(valueAttribute.value());
  1898.             Abilities& abilities = it.getAbilities();
  1899.             abilities.reflectPercent[combatTypeToIndex(COMBAT_ENERGYDAMAGE)] += value;
  1900.             abilities.reflectPercent[combatTypeToIndex(COMBAT_FIREDAMAGE)] += value;
  1901.             abilities.reflectPercent[combatTypeToIndex(COMBAT_EARTHDAMAGE)] += value;
  1902.             abilities.reflectPercent[combatTypeToIndex(COMBAT_ICEDAMAGE)] += value;
  1903.             abilities.reflectPercent[combatTypeToIndex(COMBAT_HOLYDAMAGE)] += value;
  1904.             abilities.reflectPercent[combatTypeToIndex(COMBAT_DEATHDAMAGE)] += value;
  1905.         }
  1906.         else if (tmpStrValue == "absorbpercentelements") {
  1907.             int16_t value = pugi::cast<int16_t>(valueAttribute.value());
  1908.             Abilities& abilities = it.getAbilities();
  1909.             abilities.absorbPercent[combatTypeToIndex(COMBAT_ENERGYDAMAGE)] += value;
  1910.             abilities.absorbPercent[combatTypeToIndex(COMBAT_FIREDAMAGE)] += value;
  1911.             abilities.absorbPercent[combatTypeToIndex(COMBAT_EARTHDAMAGE)] += value;
  1912.             abilities.absorbPercent[combatTypeToIndex(COMBAT_ICEDAMAGE)] += value;
  1913.         }
  1914.         else if (tmpStrValue == "absorbpercentmagic") {
  1915.             int16_t value = pugi::cast<int16_t>(valueAttribute.value());
  1916.             Abilities& abilities = it.getAbilities();
  1917.             abilities.absorbPercent[combatTypeToIndex(COMBAT_ENERGYDAMAGE)] += value;
  1918.             abilities.absorbPercent[combatTypeToIndex(COMBAT_FIREDAMAGE)] += value;
  1919.             abilities.absorbPercent[combatTypeToIndex(COMBAT_EARTHDAMAGE)] += value;
  1920.             abilities.absorbPercent[combatTypeToIndex(COMBAT_ICEDAMAGE)] += value;
  1921.             abilities.absorbPercent[combatTypeToIndex(COMBAT_HOLYDAMAGE)] += value;
  1922.             abilities.absorbPercent[combatTypeToIndex(COMBAT_DEATHDAMAGE)] += value;
  1923.         }
  1924.         else if (tmpStrValue == "absorbpercentenergy") {
  1925.             it.getAbilities().absorbPercent[combatTypeToIndex(COMBAT_ENERGYDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  1926.         }
  1927.         else if (tmpStrValue == "absorbpercentfire") {
  1928.             it.getAbilities().absorbPercent[combatTypeToIndex(COMBAT_FIREDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  1929.         }
  1930.         else if (tmpStrValue == "absorbpercentpoison" || tmpStrValue == "absorbpercentearth") {
  1931.             it.getAbilities().absorbPercent[combatTypeToIndex(COMBAT_EARTHDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  1932.         }
  1933.         else if (tmpStrValue == "absorbpercentice") {
  1934.             it.getAbilities().absorbPercent[combatTypeToIndex(COMBAT_ICEDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  1935.         }
  1936.         else if (tmpStrValue == "absorbpercentholy") {
  1937.             it.getAbilities().absorbPercent[combatTypeToIndex(COMBAT_HOLYDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  1938.         }
  1939.         else if (tmpStrValue == "absorbpercentdeath") {
  1940.             it.getAbilities().absorbPercent[combatTypeToIndex(COMBAT_DEATHDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  1941.         }
  1942.         else if (tmpStrValue == "absorbpercentlifedrain") {
  1943.             it.getAbilities().absorbPercent[combatTypeToIndex(COMBAT_LIFEDRAIN)] += pugi::cast<int16_t>(valueAttribute.value());
  1944.         }
  1945.         else if (tmpStrValue == "absorbpercentmanadrain") {
  1946.             it.getAbilities().absorbPercent[combatTypeToIndex(COMBAT_MANADRAIN)] += pugi::cast<int16_t>(valueAttribute.value());
  1947.         }
  1948.         else if (tmpStrValue == "absorbpercentdrown") {
  1949.             it.getAbilities().absorbPercent[combatTypeToIndex(COMBAT_DROWNDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  1950.         }
  1951.         else if (tmpStrValue == "absorbpercentphysical") {
  1952.             it.getAbilities().absorbPercent[combatTypeToIndex(COMBAT_PHYSICALDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  1953.         }
  1954.         else if (tmpStrValue == "absorbpercenthealing") {
  1955.             it.getAbilities().absorbPercent[combatTypeToIndex(COMBAT_HEALING)] += pugi::cast<int16_t>(valueAttribute.value());
  1956.         }
  1957.         else if (tmpStrValue == "reflectpercentenergy") {
  1958.             it.getAbilities().reflectPercent[combatTypeToIndex(COMBAT_ENERGYDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  1959.         }
  1960.         else if (tmpStrValue == "reflectpercentfire") {
  1961.             it.getAbilities().reflectPercent[combatTypeToIndex(COMBAT_FIREDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  1962.         }
  1963.         else if (tmpStrValue == "reflectpercentpoison" || tmpStrValue == "reflectpercentearth") {
  1964.             it.getAbilities().reflectPercent[combatTypeToIndex(COMBAT_EARTHDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  1965.         }
  1966.         else if (tmpStrValue == "reflectpercentice") {
  1967.             it.getAbilities().reflectPercent[combatTypeToIndex(COMBAT_ICEDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  1968.         }
  1969.         else if (tmpStrValue == "reflectpercentholy") {
  1970.             it.getAbilities().reflectPercent[combatTypeToIndex(COMBAT_HOLYDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  1971.         }
  1972.         else if (tmpStrValue == "reflectpercentdeath") {
  1973.             it.getAbilities().reflectPercent[combatTypeToIndex(COMBAT_DEATHDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  1974.         }
  1975.         else if (tmpStrValue == "reflectpercentlifedrain") {
  1976.             it.getAbilities().reflectPercent[combatTypeToIndex(COMBAT_LIFEDRAIN)] += pugi::cast<int16_t>(valueAttribute.value());
  1977.         }
  1978.         else if (tmpStrValue == "reflectpercentmanadrain") {
  1979.             it.getAbilities().reflectPercent[combatTypeToIndex(COMBAT_MANADRAIN)] += pugi::cast<int16_t>(valueAttribute.value());
  1980.         }
  1981.         else if (tmpStrValue == "reflectpercentphysical") {
  1982.             it.getAbilities().reflectPercent[combatTypeToIndex(COMBAT_PHYSICALDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  1983.         }
  1984.         else if (tmpStrValue == "suppressdrunk") {
  1985.             if (valueAttribute.as_bool()) {
  1986.                 it.getAbilities().conditionSuppressions |= CONDITION_DRUNK;
  1987.             }
  1988.         }
  1989.         else if (tmpStrValue == "suppressenergy") {
  1990.             if (valueAttribute.as_bool()) {
  1991.                 it.getAbilities().conditionSuppressions |= CONDITION_ENERGY;
  1992.             }
  1993.         }
  1994.         else if (tmpStrValue == "suppressfire") {
  1995.             if (valueAttribute.as_bool()) {
  1996.                 it.getAbilities().conditionSuppressions |= CONDITION_FIRE;
  1997.             }
  1998.         }
  1999.         else if (tmpStrValue == "suppresspoison") {
  2000.             if (valueAttribute.as_bool()) {
  2001.                 it.getAbilities().conditionSuppressions |= CONDITION_POISON;
  2002.             }
  2003.         }
  2004.         else if (tmpStrValue == "suppressdrown") {
  2005.             if (valueAttribute.as_bool()) {
  2006.                 it.getAbilities().conditionSuppressions |= CONDITION_DROWN;
  2007.             }
  2008.         }
  2009.         else if (tmpStrValue == "suppressphysical") {
  2010.             if (valueAttribute.as_bool()) {
  2011.                 it.getAbilities().conditionSuppressions |= CONDITION_BLEEDING;
  2012.             }
  2013.         }
  2014.         else if (tmpStrValue == "suppressfreeze") {
  2015.             if (valueAttribute.as_bool()) {
  2016.                 it.getAbilities().conditionSuppressions |= CONDITION_FREEZING;
  2017.             }
  2018.         }
  2019.         else if (tmpStrValue == "suppressdazzle") {
  2020.             if (valueAttribute.as_bool()) {
  2021.                 it.getAbilities().conditionSuppressions |= CONDITION_DAZZLED;
  2022.             }
  2023.         }
  2024.         else if (tmpStrValue == "suppresscurse") {
  2025.             if (valueAttribute.as_bool()) {
  2026.                 it.getAbilities().conditionSuppressions |= CONDITION_CURSED;
  2027.             }
  2028.         }
  2029.         else if (tmpStrValue == "field") {
  2030.             it.group = ITEM_GROUP_MAGICFIELD;
  2031.             it.type = ITEM_TYPE_MAGICFIELD;
  2032.             std::string constr;
  2033.  
  2034.             CombatType_t combatType = COMBAT_NONE;
  2035.             ConditionDamage* conditionDamage = nullptr;
  2036.  
  2037.             constr = asLowerCaseString(valueAttribute.as_string());
  2038.             tmpStrValue = constr;
  2039.  
  2040.             if (tmpStrValue == "fire") {
  2041.                 conditionDamage = new ConditionDamage(CONDITIONID_COMBAT, CONDITION_FIRE);
  2042.                 combatType = COMBAT_FIREDAMAGE;
  2043.             }
  2044.             else if (tmpStrValue == "energy") {
  2045.                 conditionDamage = new ConditionDamage(CONDITIONID_COMBAT, CONDITION_ENERGY);
  2046.                 combatType = COMBAT_ENERGYDAMAGE;
  2047.             }
  2048.             else if (tmpStrValue == "poison") {
  2049.                 conditionDamage = new ConditionDamage(CONDITIONID_COMBAT, CONDITION_POISON);
  2050.                 combatType = COMBAT_EARTHDAMAGE;
  2051.             }
  2052.             else if (tmpStrValue == "drown") {
  2053.                 conditionDamage = new ConditionDamage(CONDITIONID_COMBAT, CONDITION_DROWN);
  2054.                 combatType = COMBAT_DROWNDAMAGE;
  2055.             }
  2056.             else if (tmpStrValue == "physical") {
  2057.                 conditionDamage = new ConditionDamage(CONDITIONID_COMBAT, CONDITION_BLEEDING);
  2058.                 combatType = COMBAT_PHYSICALDAMAGE;
  2059.             }
  2060.             else {
  2061.                 std::cout << "[Warning - Items::parseItemNode] Unknown field value: " << valueAttribute.as_string() << std::endl;
  2062.             }
  2063.  
  2064.             if (combatType != COMBAT_NONE) {
  2065.                 it.combatType = combatType;
  2066.                 it.conditionDamage.reset(conditionDamage);
  2067.                 uint32_t ticks = 0;
  2068.                 int32_t damage = 0;
  2069.                 int32_t start = 0;
  2070.                 int32_t count = 1;
  2071.  
  2072.                 for (auto subAttributeNode : attributeNode.children()) {
  2073.                     pugi::xml_attribute subKeyAttribute = subAttributeNode.attribute("key");
  2074.                     if (!subKeyAttribute) {
  2075.                         continue;
  2076.                     }
  2077.                     if (constructTable) {
  2078.                         std::string skey = asLowerCaseString(subKeyAttribute.as_string());
  2079.                     }
  2080.  
  2081.                     pugi::xml_attribute subValueAttribute = subAttributeNode.attribute("value");
  2082.                     if (!subValueAttribute) {
  2083.                         continue;
  2084.                     }
  2085.                     if (constructTable) {
  2086.                         std::string svalue = subValueAttribute.as_string();
  2087.                     }
  2088.  
  2089.                     tmpStrValue = asLowerCaseString(subKeyAttribute.as_string());
  2090.                     if (tmpStrValue == "ticks") {
  2091.                         ticks = pugi::cast<uint32_t>(subValueAttribute.value());
  2092.                     }
  2093.                     else if (tmpStrValue == "count") {
  2094.                         count = std::max<int32_t>(1, pugi::cast<int32_t>(subValueAttribute.value()));
  2095.                     }
  2096.                     else if (tmpStrValue == "start") {
  2097.                         start = std::max<int32_t>(0, pugi::cast<int32_t>(subValueAttribute.value()));
  2098.                     }
  2099.                     else if (tmpStrValue == "damage") {
  2100.                         damage = -pugi::cast<int32_t>(subValueAttribute.value());
  2101.  
  2102.                         if (start > 0) {
  2103.                             std::list<int32_t> damageList;
  2104.                             ConditionDamage::generateDamageList(damage, start, damageList);
  2105.                             for (int32_t damageValue : damageList) {
  2106.                                 conditionDamage->addDamage(1, ticks, -damageValue);
  2107.                             }
  2108.  
  2109.                             start = 0;
  2110.                         }
  2111.                         else {
  2112.                             conditionDamage->addDamage(count, ticks, damage);
  2113.                         }
  2114.                     }
  2115.                 }
  2116.  
  2117.                 conditionDamage->setParam(CONDITION_PARAM_FIELD, 1);
  2118.  
  2119.                 if (conditionDamage->getTotalDamage() > 0) {
  2120.                     conditionDamage->setParam(CONDITION_PARAM_FORCEUPDATE, 1);
  2121.                 }
  2122.             }
  2123.         }
  2124.         else if (tmpStrValue == "replaceable") {
  2125.             it.replaceable = valueAttribute.as_bool();
  2126.         }
  2127.         else if (tmpStrValue == "partnerdirection") {
  2128.             it.bedPartnerDir = getDirection(valueAttribute.as_string());
  2129.         }
  2130.         else if (tmpStrValue == "leveldoor") {
  2131.             it.levelDoor = pugi::cast<uint32_t>(valueAttribute.value());
  2132.         }
  2133.         else if (tmpStrValue == "maletransformto" || tmpStrValue == "malesleeper") {
  2134.             uint16_t value = pugi::cast<uint16_t>(valueAttribute.value());
  2135.             it.transformToOnUse[PLAYERSEX_MALE] = value;
  2136.             ItemType& other = getItemType(value);
  2137.             if (other.transformToFree == 0) {
  2138.                 other.transformToFree = it.id;
  2139.             }
  2140.  
  2141.             if (it.transformToOnUse[PLAYERSEX_FEMALE] == 0) {
  2142.                 it.transformToOnUse[PLAYERSEX_FEMALE] = value;
  2143.             }
  2144.         }
  2145.         else if (tmpStrValue == "femaletransformto" || tmpStrValue == "femalesleeper") {
  2146.             uint16_t value = pugi::cast<uint16_t>(valueAttribute.value());
  2147.             it.transformToOnUse[PLAYERSEX_FEMALE] = value;
  2148.  
  2149.             ItemType& other = getItemType(value);
  2150.             if (other.transformToFree == 0) {
  2151.                 other.transformToFree = it.id;
  2152.             }
  2153.  
  2154.             if (it.transformToOnUse[PLAYERSEX_MALE] == 0) {
  2155.                 it.transformToOnUse[PLAYERSEX_MALE] = value;
  2156.             }
  2157.         }
  2158.         else if (tmpStrValue == "transformto") {
  2159.             it.transformToFree = pugi::cast<uint16_t>(valueAttribute.value());
  2160.         }
  2161.         else if (tmpStrValue == "destroyto") {
  2162.             it.destroyTo = pugi::cast<uint16_t>(valueAttribute.value());
  2163.         }
  2164.         else if (elementTypes[tmpStrValue]) {
  2165.             Abilities& abilities = it.getAbilities();
  2166.             abilities.elementDamage = pugi::cast<uint16_t>(valueAttribute.value());
  2167.             abilities.elementType = elementTypes[tmpStrValue];
  2168.         }
  2169.         /*else if (tmpStrValue == "elementearth") {
  2170.             Abilities& abilities = it.getAbilities();
  2171.             abilities.elementDamage = pugi::cast<uint16_t>(valueAttribute.value());
  2172.             abilities.elementType = COMBAT_EARTHDAMAGE;
  2173.         }
  2174.         else if (tmpStrValue == "elementfire") {
  2175.             Abilities& abilities = it.getAbilities();
  2176.             abilities.elementDamage = pugi::cast<uint16_t>(valueAttribute.value());
  2177.             abilities.elementType = COMBAT_FIREDAMAGE;
  2178.         }
  2179.         else if (tmpStrValue == "elementenergy") {
  2180.             Abilities& abilities = it.getAbilities();
  2181.             abilities.elementDamage = pugi::cast<uint16_t>(valueAttribute.value());
  2182.             abilities.elementType = COMBAT_ENERGYDAMAGE;
  2183.         }
  2184.         else if (tmpStrValue == "elementdeath") {
  2185.             Abilities& abilities = it.getAbilities();
  2186.             abilities.elementDamage = pugi::cast<uint16_t>(valueAttribute.value());
  2187.             abilities.elementType = COMBAT_DEATHDAMAGE;
  2188.         }
  2189.         else if (tmpStrValue == "elementholy") {
  2190.             Abilities& abilities = it.getAbilities();
  2191.             abilities.elementDamage = pugi::cast<uint16_t>(valueAttribute.value());
  2192.             abilities.elementType = COMBAT_HOLYDAMAGE;
  2193.         }*/
  2194.         else if (tmpStrValue == "walkstack") {
  2195.             it.walkStack = valueAttribute.as_bool();
  2196.         }
  2197.         else if (tmpStrValue == "blocking") {
  2198.             it.blockSolid = valueAttribute.as_bool();
  2199.         }
  2200.         else if (tmpStrValue == "allowdistread") {
  2201.             it.allowDistRead = booleanString(valueAttribute.as_string());
  2202.         }
  2203.         else {
  2204.             std::cout << "[Warning - Items::parseItemNode] Unknown key value: " << keyAttribute.as_string() << std::endl;
  2205.         }
  2206.     }
  2207.     if (constructTable) {
  2208.         parser += "\n\t\tattributes = {\n" + pattribute + "\t\t}\n\t},\n";
  2209.         out << parser;
  2210.     }
  2211.     //check bed items
  2212.     if ((it.transformToFree != 0 || it.transformToOnUse[PLAYERSEX_FEMALE] != 0 || it.transformToOnUse[PLAYERSEX_MALE] != 0) && it.type != ITEM_TYPE_BED) {
  2213.         std::cout << "[Warning - Items::parseItemNode] Item " << it.id << " is not set as a bed-type" << std::endl;
  2214.     }
  2215. }
  2216.  
  2217.  
  2218.  
  2219. ItemType& Items::getItemType(size_t id)
  2220. {
  2221.     if (id < items.size()) {
  2222.         return items[id];
  2223.     }
  2224.     return items.front();
  2225. }
  2226.  
  2227. const ItemType& Items::getItemType(size_t id) const
  2228. {
  2229.     if (id < items.size()) {
  2230.         return items[id];
  2231.     }
  2232.     return items.front();
  2233. }
  2234.  
  2235. const ItemType& Items::getItemIdByClientId(uint16_t spriteId) const
  2236. {
  2237.     auto it = reverseItemMap.find(spriteId);
  2238.     if (it != reverseItemMap.end()) {
  2239.         return getItemType(it->second);
  2240.     }
  2241.     return items.front();
  2242. }
  2243.  
  2244. uint16_t Items::getItemIdByName(const std::string& name)
  2245. {
  2246.     auto result = nameToItems.find(asLowerCaseString(name));
  2247.  
  2248.     if (result == nameToItems.end())
  2249.         return 0;
  2250.  
  2251.     return result->second;
  2252. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement