Advertisement
Guest User

Untitled

a guest
Sep 24th, 2014
245
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 37.23 KB | None | 0 0
  1. /**
  2. * The Forgotten Server - a free and open-source MMORPG server emulator
  3. * Copyright (C) 2014 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 "condition.h"
  25. #include "movement.h"
  26. #include "weapons.h"
  27.  
  28. #include "pugicast.h"
  29.  
  30. uint32_t Items::dwMajorVersion = 0;
  31. uint32_t Items::dwMinorVersion = 0;
  32. uint32_t Items::dwBuildNumber = 0;
  33.  
  34. extern MoveEvents* g_moveEvents;
  35. extern Weapons* g_weapons;
  36.  
  37. ItemType::ItemType()
  38. {
  39. abilities = nullptr;
  40. type = ITEM_TYPE_NONE;
  41. alwaysOnTopOrder = 0;
  42. rotateTo = 0;
  43. walkStack = true;
  44.  
  45. floorChangeDown = false;
  46. floorChangeNorth = false;
  47. floorChangeSouth = false;
  48. floorChangeSouthAlt = false;
  49. floorChangeEast = false;
  50. floorChangeEastAlt = false;
  51. floorChangeWest = false;
  52.  
  53. allowPickupable = false;
  54.  
  55. wieldInfo = 0;
  56. minReqLevel = 0;
  57. minReqMagicLevel = 0;
  58.  
  59. runeMagLevel = 0;
  60. runeLevel = 0;
  61.  
  62. speed = 0;
  63. id = 0;
  64. clientId = 0;
  65. maxItems = 8; // maximum size if this is a container
  66. weight = 0; // weight of the item, e.g. throwing distance depends on it
  67. showCount = true;
  68. weaponType = WEAPON_NONE;
  69. slotPosition = SLOTP_HAND;
  70. ammoType = AMMO_NONE;
  71. ammoAction = AMMOACTION_NONE;
  72. shootType = (ShootType_t)0;
  73. magicEffect = CONST_ME_NONE;
  74. attack = 0;
  75. defense = 0;
  76. extraDefense = 0;
  77. armor = 0;
  78. dual = 0;
  79. decayTo = -1;
  80. decayTime = 0;
  81. stopTime = false;
  82. corpseType = RACE_NONE;
  83. fluidSource = FLUID_NONE;
  84.  
  85. lightLevel = 0;
  86. lightColor = 0;
  87.  
  88. maxTextLen = 0;
  89. canWriteText = false;
  90. writeOnceItemId = 0;
  91.  
  92. transformEquipTo = 0;
  93. transformDeEquipTo = 0;
  94. showDuration = false;
  95. showCharges = false;
  96. showAttributes = false;
  97. charges = 0;
  98. hitChance = 0;
  99. maxHitChance = -1;
  100. breakChance = -1;
  101. shootRange = 1;
  102.  
  103. condition = nullptr;
  104. combatType = COMBAT_NONE;
  105.  
  106. replaceable = true;
  107.  
  108. bedPartnerDir = NORTH;
  109. transformToOnUse[PLAYERSEX_MALE] = 0;
  110. transformToOnUse[PLAYERSEX_FEMALE] = 0;
  111. transformToFree = 0;
  112.  
  113. levelDoor = 0;
  114.  
  115. wareId = 0;
  116. }
  117.  
  118. ItemType::~ItemType()
  119. {
  120. delete condition;
  121. delete abilities;
  122. }
  123.  
  124. Items::Items()
  125. {
  126. items.reserve(30000);
  127. }
  128.  
  129. Items::~Items()
  130. {
  131. clear();
  132. }
  133.  
  134. void Items::clear()
  135. {
  136. items.clear();
  137. }
  138.  
  139. bool Items::reload()
  140. {
  141. clear();
  142. loadFromOtb("data/items/items.otb");
  143.  
  144. if (!loadFromXml()) {
  145. return false;
  146. }
  147.  
  148. g_moveEvents->reload();
  149. g_weapons->reload();
  150. g_weapons->loadDefaults();
  151. return true;
  152. }
  153.  
  154. int32_t Items::loadFromOtb(const std::string& file)
  155. {
  156. FileLoader f;
  157. if (!f.openFile(file.c_str(), "OTBI")) {
  158. return f.getError();
  159. }
  160.  
  161. uint32_t type;
  162. NODE node = f.getChildNode(NO_NODE, type);
  163.  
  164. PropStream props;
  165. if (f.getProps(node, props)) {
  166. //4 byte flags
  167. //attributes
  168. //0x01 = version data
  169. uint32_t flags;
  170. if (!props.GET_ULONG(flags)) {
  171. return ERROR_INVALID_FORMAT;
  172. }
  173.  
  174. uint8_t attr;
  175. if (!props.GET_VALUE(attr)) {
  176. return ERROR_INVALID_FORMAT;
  177. }
  178.  
  179. if (attr == ROOT_ATTR_VERSION) {
  180. uint16_t datalen;
  181. if (!props.GET_VALUE(datalen)) {
  182. return ERROR_INVALID_FORMAT;
  183. }
  184.  
  185. if (datalen != sizeof(VERSIONINFO)) {
  186. return ERROR_INVALID_FORMAT;
  187. }
  188.  
  189. VERSIONINFO* vi;
  190. if (!props.GET_STRUCT(vi)) {
  191. return ERROR_INVALID_FORMAT;
  192. }
  193.  
  194. Items::dwMajorVersion = vi->dwMajorVersion; //items otb format file version
  195. Items::dwMinorVersion = vi->dwMinorVersion; //client version
  196. Items::dwBuildNumber = vi->dwBuildNumber; //revision
  197. }
  198. }
  199.  
  200. if (Items::dwMajorVersion == 0xFFFFFFFF) {
  201. std::cout << "[Warning - Items::loadFromOtb] items.otb using generic client version." << std::endl;
  202. } else if (Items::dwMajorVersion != 3) {
  203. std::cout << "Old version detected, a newer version of items.otb is required." << std::endl;
  204. return ERROR_INVALID_FORMAT;
  205. } else if (Items::dwMinorVersion < CLIENT_VERSION_1035) {
  206. std::cout << "A newer version of items.otb is required." << std::endl;
  207. return ERROR_INVALID_FORMAT;
  208. }
  209.  
  210. node = f.getChildNode(node, type);
  211. while (node != NO_NODE) {
  212. PropStream stream;
  213. if (!f.getProps(node, stream)) {
  214. return f.getError();
  215. }
  216.  
  217. uint32_t flags;
  218. if (!stream.GET_VALUE(flags)) {
  219. return ERROR_INVALID_FORMAT;
  220. }
  221.  
  222. uint16_t serverId = 0;
  223. uint16_t clientId = 0;
  224. uint16_t speed = 0;
  225. uint16_t lightLevel = 0;
  226. uint16_t lightColor = 0;
  227. uint16_t wareId = 0;
  228. uint8_t alwaysOnTopOrder = 0;
  229.  
  230. uint8_t attrib;
  231. while (stream.GET_VALUE(attrib)) {
  232. uint16_t datalen;
  233. if (!stream.GET_VALUE(datalen)) {
  234. return ERROR_INVALID_FORMAT;
  235. }
  236.  
  237. switch (attrib) {
  238. case ITEM_ATTR_SERVERID: {
  239. if (datalen != sizeof(uint16_t)) {
  240. return ERROR_INVALID_FORMAT;
  241. }
  242.  
  243. if (!stream.GET_USHORT(serverId)) {
  244. return ERROR_INVALID_FORMAT;
  245. }
  246.  
  247. if (serverId > 30000 && serverId < 30100) {
  248. serverId -= 30000;
  249. }
  250. break;
  251. }
  252.  
  253. case ITEM_ATTR_CLIENTID: {
  254. if (datalen != sizeof(uint16_t)) {
  255. return ERROR_INVALID_FORMAT;
  256. }
  257.  
  258. if (!stream.GET_USHORT(clientId)) {
  259. return ERROR_INVALID_FORMAT;
  260. }
  261. break;
  262. }
  263.  
  264. case ITEM_ATTR_SPEED: {
  265. if (datalen != sizeof(uint16_t)) {
  266. return ERROR_INVALID_FORMAT;
  267. }
  268.  
  269. if (!stream.GET_USHORT(speed)) {
  270. return ERROR_INVALID_FORMAT;
  271. }
  272. break;
  273. }
  274.  
  275. case ITEM_ATTR_LIGHT2: {
  276. if (datalen != sizeof(lightBlock2)) {
  277. return ERROR_INVALID_FORMAT;
  278. }
  279.  
  280. lightBlock2* lb2;
  281. if (!stream.GET_STRUCT(lb2)) {
  282. return ERROR_INVALID_FORMAT;
  283. }
  284.  
  285. lightLevel = lb2->lightLevel;
  286. lightColor = lb2->lightColor;
  287. break;
  288. }
  289.  
  290. case ITEM_ATTR_TOPORDER: {
  291. if (datalen != sizeof(uint8_t)) {
  292. return ERROR_INVALID_FORMAT;
  293. }
  294.  
  295. if (!stream.GET_UCHAR(alwaysOnTopOrder)) {
  296. return ERROR_INVALID_FORMAT;
  297. }
  298. break;
  299. }
  300.  
  301. case ITEM_ATTR_WAREID: {
  302. if (datalen != sizeof(uint16_t)) {
  303. return ERROR_INVALID_FORMAT;
  304. }
  305.  
  306. if (!stream.GET_USHORT(wareId)) {
  307. return ERROR_INVALID_FORMAT;
  308. }
  309. break;
  310. }
  311.  
  312. default: {
  313. //skip unknown attributes
  314. if (!stream.SKIP_N(datalen)) {
  315. return ERROR_INVALID_FORMAT;
  316. }
  317. break;
  318. }
  319. }
  320. }
  321.  
  322. if (reverseItemMap.find(clientId) == reverseItemMap.end()) {
  323. reverseItemMap[clientId] = serverId;
  324. }
  325.  
  326. // store the found item
  327. if (serverId >= items.size()) {
  328. items.resize(serverId + 1);
  329. }
  330. ItemType& iType = items[serverId];
  331.  
  332. iType.group = (itemgroup_t)type;
  333. switch (type) {
  334. case ITEM_GROUP_CONTAINER:
  335. iType.type = ITEM_TYPE_CONTAINER;
  336. break;
  337. case ITEM_GROUP_DOOR:
  338. //not used
  339. iType.type = ITEM_TYPE_DOOR;
  340. break;
  341. case ITEM_GROUP_MAGICFIELD:
  342. //not used
  343. iType.type = ITEM_TYPE_MAGICFIELD;
  344. break;
  345. case ITEM_GROUP_TELEPORT:
  346. //not used
  347. iType.type = ITEM_TYPE_TELEPORT;
  348. break;
  349. case ITEM_GROUP_NONE:
  350. case ITEM_GROUP_GROUND:
  351. case ITEM_GROUP_SPLASH:
  352. case ITEM_GROUP_FLUID:
  353. case ITEM_GROUP_CHARGES:
  354. case ITEM_GROUP_DEPRECATED:
  355. break;
  356. default:
  357. return ERROR_INVALID_FORMAT;
  358. }
  359.  
  360. iType.blockSolid = hasBitSet(FLAG_BLOCK_SOLID, flags);
  361. iType.blockProjectile = hasBitSet(FLAG_BLOCK_PROJECTILE, flags);
  362. iType.blockPathFind = hasBitSet(FLAG_BLOCK_PATHFIND, flags);
  363. iType.hasHeight = hasBitSet(FLAG_HAS_HEIGHT, flags);
  364. iType.useable = hasBitSet(FLAG_USEABLE, flags);
  365. iType.pickupable = hasBitSet(FLAG_PICKUPABLE, flags);
  366. iType.moveable = hasBitSet(FLAG_MOVEABLE, flags);
  367. iType.stackable = hasBitSet(FLAG_STACKABLE, flags);
  368.  
  369. iType.alwaysOnTop = hasBitSet(FLAG_ALWAYSONTOP, flags);
  370. iType.isVertical = hasBitSet(FLAG_VERTICAL, flags);
  371. iType.isHorizontal = hasBitSet(FLAG_HORIZONTAL, flags);
  372. iType.isHangable = hasBitSet(FLAG_HANGABLE, flags);
  373. iType.allowDistRead = hasBitSet(FLAG_ALLOWDISTREAD, flags);
  374. iType.rotable = hasBitSet(FLAG_ROTABLE, flags);
  375. iType.canReadText = hasBitSet(FLAG_READABLE, flags);
  376. iType.lookThrough = hasBitSet(FLAG_LOOKTHROUGH, flags);
  377. iType.isAnimation = hasBitSet(FLAG_ANIMATION, flags);
  378. // iType.walkStack = !hasBitSet(FLAG_FULLTILE, flags);
  379.  
  380. iType.id = serverId;
  381. iType.clientId = clientId;
  382. iType.speed = speed;
  383. iType.lightLevel = lightLevel;
  384. iType.lightColor = lightColor;
  385. iType.wareId = wareId;
  386. iType.alwaysOnTopOrder = alwaysOnTopOrder;
  387.  
  388. node = f.getNextNode(node, type);
  389. }
  390.  
  391. items.shrink_to_fit();
  392. return ERROR_NONE;
  393. }
  394.  
  395. bool Items::loadFromXml()
  396. {
  397. pugi::xml_document doc;
  398. pugi::xml_parse_result result = doc.load_file("data/items/items.xml");
  399. if (!result) {
  400. std::cout << "[Error - Items::loadFromXml] Failed to load data/items/items.xml: " << result.description() << std::endl;
  401. return false;
  402. }
  403.  
  404. for (pugi::xml_node itemNode = doc.child("items").first_child(); itemNode; itemNode = itemNode.next_sibling()) {
  405. pugi::xml_attribute idAttribute = itemNode.attribute("id");
  406. if (idAttribute) {
  407. parseItemNode(itemNode, pugi::cast<uint32_t>(idAttribute.value()));
  408. } else {
  409. pugi::xml_attribute fromIdAttribute = itemNode.attribute("fromid");
  410. if (fromIdAttribute) {
  411. pugi::xml_attribute toIdAttribute = itemNode.attribute("toid");
  412. if (toIdAttribute) {
  413. uint16_t id = pugi::cast<uint16_t>(fromIdAttribute.value());
  414. uint16_t toId = pugi::cast<uint16_t>(toIdAttribute.value());
  415. while (id <= toId) {
  416. parseItemNode(itemNode, id++);
  417. }
  418. } else {
  419. std::cout << "[Warning - Items::loadFromXml] fromid (" << fromIdAttribute.value() << ") without toid" << std::endl;
  420. }
  421. } else {
  422. std::cout << "[Warning - Items::loadFromXml] No itemid found" << std::endl;
  423. }
  424. }
  425. }
  426. return true;
  427. }
  428.  
  429. void Items::parseItemNode(const pugi::xml_node& itemNode, uint32_t id)
  430. {
  431. if (id > 30000 && id < 30100) {
  432. id -= 30000;
  433.  
  434. if (id >= items.size()) {
  435. items.resize(id + 1);
  436. }
  437. ItemType& iType = items[id];
  438. iType.id = id;
  439. }
  440.  
  441. ItemType& it = getItemType(id);
  442. if (it.id == 0) {
  443. return;
  444. }
  445.  
  446. it.name = itemNode.attribute("name").as_string();
  447.  
  448. pugi::xml_attribute articleAttribute = itemNode.attribute("article");
  449. if (articleAttribute) {
  450. it.article = articleAttribute.as_string();
  451. }
  452.  
  453. pugi::xml_attribute pluralAttribute = itemNode.attribute("plural");
  454. if (pluralAttribute) {
  455. it.pluralName = pluralAttribute.as_string();
  456. }
  457.  
  458. for (pugi::xml_node attributeNode = itemNode.first_child(); attributeNode; attributeNode = attributeNode.next_sibling()) {
  459. pugi::xml_attribute keyAttribute = attributeNode.attribute("key");
  460. if (!keyAttribute) {
  461. continue;
  462. }
  463.  
  464. pugi::xml_attribute valueAttribute = attributeNode.attribute("value");
  465. if (!valueAttribute) {
  466. continue;
  467. }
  468.  
  469. std::string tmpStrValue = asLowerCaseString(keyAttribute.as_string());
  470. if (tmpStrValue == "type") {
  471. tmpStrValue = asLowerCaseString(valueAttribute.as_string());
  472. if (tmpStrValue == "key") {
  473. it.type = ITEM_TYPE_KEY;
  474. } else if (tmpStrValue == "magicfield") {
  475. it.type = ITEM_TYPE_MAGICFIELD;
  476. } else if (tmpStrValue == "container") {
  477. it.group = ITEM_GROUP_CONTAINER;
  478. it.type = ITEM_TYPE_CONTAINER;
  479. } else if (tmpStrValue == "depot") {
  480. it.type = ITEM_TYPE_DEPOT;
  481. } else if (tmpStrValue == "mailbox") {
  482. it.type = ITEM_TYPE_MAILBOX;
  483. } else if (tmpStrValue == "trashholder") {
  484. it.type = ITEM_TYPE_TRASHHOLDER;
  485. } else if (tmpStrValue == "teleport") {
  486. it.type = ITEM_TYPE_TELEPORT;
  487. } else if (tmpStrValue == "door") {
  488. it.type = ITEM_TYPE_DOOR;
  489. } else if (tmpStrValue == "bed") {
  490. it.type = ITEM_TYPE_BED;
  491. } else if (tmpStrValue == "rune") {
  492. it.type = ITEM_TYPE_RUNE;
  493. } else {
  494. std::cout << "[Warning - Items::parseItemNode] Unknown type: " << valueAttribute.as_string() << std::endl;
  495. }
  496. } else if (tmpStrValue == "description") {
  497. it.description = valueAttribute.as_string();
  498. } else if (tmpStrValue == "runespellname") {
  499. it.runeSpellName = valueAttribute.as_string();
  500. } else if (tmpStrValue == "weight") {
  501. it.weight = pugi::cast<uint32_t>(valueAttribute.value()) / 100.f;
  502. } else if (tmpStrValue == "showcount") {
  503. it.showCount = valueAttribute.as_bool();
  504. } else if (tmpStrValue == "armor") {
  505. it.armor = pugi::cast<int32_t>(valueAttribute.value());
  506. } else if (tmpStrValue == "defense") {
  507. it.defense = pugi::cast<int32_t>(valueAttribute.value());
  508. } else if (tmpStrValue == "extradef") {
  509. it.extraDefense = pugi::cast<int32_t>(valueAttribute.value());
  510. } else if (tmpStrValue == "attack") {
  511. it.attack = pugi::cast<int32_t>(valueAttribute.value());
  512. } else if (tmpStrValue == "dual") {
  513. if (readXMLInteger(itemAttributesNode, "value", intValue))
  514. it.dual = intValue;
  515. } else if (tmpStrValue == "rotateto") {
  516. it.rotateTo = pugi::cast<int32_t>(valueAttribute.value());
  517. } else if (tmpStrValue == "moveable" || tmpStrValue == "movable") {
  518. it.moveable = valueAttribute.as_bool();
  519. } else if (tmpStrValue == "blockprojectile") {
  520. it.blockProjectile = valueAttribute.as_bool();
  521. } else if (tmpStrValue == "allowpickupable" || tmpStrValue == "pickupable") {
  522. it.allowPickupable = valueAttribute.as_bool();
  523. } else if (tmpStrValue == "floorchange") {
  524. tmpStrValue = asLowerCaseString(valueAttribute.as_string());
  525. if (tmpStrValue == "down") {
  526. it.floorChangeDown = true;
  527. } else if (tmpStrValue == "north") {
  528. it.floorChangeNorth = true;
  529. } else if (tmpStrValue == "south") {
  530. it.floorChangeSouth = true;
  531. } else if (tmpStrValue == "southalt" || tmpStrValue == "southex") {
  532. it.floorChangeSouthAlt = true;
  533. } else if (tmpStrValue == "west") {
  534. it.floorChangeWest = true;
  535. } else if (tmpStrValue == "east") {
  536. it.floorChangeEast = true;
  537. } else if (tmpStrValue == "eastalt" || tmpStrValue == "eastex") {
  538. it.floorChangeEastAlt = true;
  539. } else {
  540. std::cout << "[Warning - Items::parseItemNode] Unknown floorChange: " << valueAttribute.as_string() << std::endl;
  541. }
  542. } else if (tmpStrValue == "corpsetype") {
  543. tmpStrValue = asLowerCaseString(valueAttribute.as_string());
  544. if (tmpStrValue == "venom") {
  545. it.corpseType = RACE_VENOM;
  546. } else if (tmpStrValue == "blood") {
  547. it.corpseType = RACE_BLOOD;
  548. } else if (tmpStrValue == "undead") {
  549. it.corpseType = RACE_UNDEAD;
  550. } else if (tmpStrValue == "fire") {
  551. it.corpseType = RACE_FIRE;
  552. } else if (tmpStrValue == "energy") {
  553. it.corpseType = RACE_ENERGY;
  554. } else {
  555. std::cout << "[Warning - Items::parseItemNode] Unknown corpseType: " << valueAttribute.as_string() << std::endl;
  556. }
  557. } else if (tmpStrValue == "containersize") {
  558. it.maxItems = pugi::cast<uint16_t>(valueAttribute.value());
  559. } else if (tmpStrValue == "fluidsource") {
  560. tmpStrValue = asLowerCaseString(valueAttribute.as_string());
  561. if (tmpStrValue == "water") {
  562. it.fluidSource = FLUID_WATER;
  563. } else if (tmpStrValue == "blood") {
  564. it.fluidSource = FLUID_BLOOD;
  565. } else if (tmpStrValue == "beer") {
  566. it.fluidSource = FLUID_BEER;
  567. } else if (tmpStrValue == "slime") {
  568. it.fluidSource = FLUID_SLIME;
  569. } else if (tmpStrValue == "lemonade") {
  570. it.fluidSource = FLUID_LEMONADE;
  571. } else if (tmpStrValue == "milk") {
  572. it.fluidSource = FLUID_MILK;
  573. } else if (tmpStrValue == "mana") {
  574. it.fluidSource = FLUID_MANA;
  575. } else if (tmpStrValue == "life") {
  576. it.fluidSource = FLUID_LIFE;
  577. } else if (tmpStrValue == "oil") {
  578. it.fluidSource = FLUID_OIL;
  579. } else if (tmpStrValue == "urine") {
  580. it.fluidSource = FLUID_URINE;
  581. } else if (tmpStrValue == "coconut") {
  582. it.fluidSource = FLUID_COCONUTMILK;
  583. } else if (tmpStrValue == "wine") {
  584. it.fluidSource = FLUID_WINE;
  585. } else if (tmpStrValue == "mud") {
  586. it.fluidSource = FLUID_MUD;
  587. } else if (tmpStrValue == "fruitjuice") {
  588. it.fluidSource = FLUID_FRUITJUICE;
  589. } else if (tmpStrValue == "lava") {
  590. it.fluidSource = FLUID_LAVA;
  591. } else if (tmpStrValue == "rum") {
  592. it.fluidSource = FLUID_RUM;
  593. } else if (tmpStrValue == "swamp") {
  594. it.fluidSource = FLUID_SWAMP;
  595. } else if (tmpStrValue == "tea") {
  596. it.fluidSource = FLUID_TEA;
  597. } else if (tmpStrValue == "mead") {
  598. it.fluidSource = FLUID_MEAD;
  599. } else {
  600. std::cout << "[Warning - Items::parseItemNode] Unknown fluidSource: " << valueAttribute.as_string() << std::endl;
  601. }
  602. } else if (tmpStrValue == "readable") {
  603. it.canReadText = valueAttribute.as_bool();
  604. } else if (tmpStrValue == "writeable") {
  605. it.canWriteText = valueAttribute.as_bool();
  606. it.canReadText = it.canWriteText;
  607. } else if (tmpStrValue == "maxtextlen") {
  608. it.maxTextLen = pugi::cast<uint16_t>(valueAttribute.value());
  609. } else if (tmpStrValue == "writeonceitemid") {
  610. it.writeOnceItemId = pugi::cast<uint16_t>(valueAttribute.value());
  611. } else if (tmpStrValue == "weapontype") {
  612. tmpStrValue = asLowerCaseString(valueAttribute.as_string());
  613. if (tmpStrValue == "sword") {
  614. it.weaponType = WEAPON_SWORD;
  615. } else if (tmpStrValue == "club") {
  616. it.weaponType = WEAPON_CLUB;
  617. } else if (tmpStrValue == "axe") {
  618. it.weaponType = WEAPON_AXE;
  619. } else if (tmpStrValue == "shield") {
  620. it.weaponType = WEAPON_SHIELD;
  621. } else if (tmpStrValue == "distance") {
  622. it.weaponType = WEAPON_DISTANCE;
  623. } else if (tmpStrValue == "wand") {
  624. it.weaponType = WEAPON_WAND;
  625. } else if (tmpStrValue == "ammunition") {
  626. it.weaponType = WEAPON_AMMO;
  627. } else {
  628. std::cout << "[Warning - Items::parseItemNode] Unknown weaponType: " << valueAttribute.as_string() << std::endl;
  629. }
  630. } else if (tmpStrValue == "slottype") {
  631. tmpStrValue = asLowerCaseString(valueAttribute.as_string());
  632. if (tmpStrValue == "head") {
  633. it.slotPosition |= SLOTP_HEAD;
  634. } else if (tmpStrValue == "body") {
  635. it.slotPosition |= SLOTP_ARMOR;
  636. } else if (tmpStrValue == "legs") {
  637. it.slotPosition |= SLOTP_LEGS;
  638. } else if (tmpStrValue == "feet") {
  639. it.slotPosition |= SLOTP_FEET;
  640. } else if (tmpStrValue == "backpack") {
  641. it.slotPosition |= SLOTP_BACKPACK;
  642. } else if (tmpStrValue == "two-handed") {
  643. it.slotPosition |= SLOTP_TWO_HAND;
  644. } else if (tmpStrValue == "right-hand") {
  645. it.slotPosition &= ~SLOTP_LEFT;
  646. } else if (tmpStrValue == "left-hand") {
  647. it.slotPosition &= ~SLOTP_RIGHT;
  648. } else if (tmpStrValue == "necklace") {
  649. it.slotPosition |= SLOTP_NECKLACE;
  650. } else if (tmpStrValue == "ring") {
  651. it.slotPosition |= SLOTP_RING;
  652. } else if (tmpStrValue == "ammo") {
  653. it.slotPosition |= SLOTP_AMMO;
  654. } else if (tmpStrValue == "hand") {
  655. it.slotPosition |= SLOTP_HAND;
  656. } else {
  657. std::cout << "[Warning - Items::parseItemNode] Unknown slotType: " << valueAttribute.as_string() << std::endl;
  658. }
  659. } else if (tmpStrValue == "ammotype") {
  660. it.ammoType = getAmmoType(valueAttribute.as_string());
  661. if (it.ammoType == AMMO_NONE) {
  662. std::cout << "[Warning - Items::parseItemNode] Unknown ammoType: " << valueAttribute.as_string() << std::endl;
  663. }
  664. } else if (tmpStrValue == "shoottype") {
  665. ShootType_t shoot = getShootType(valueAttribute.as_string());
  666. if (shoot != CONST_ANI_UNK) {
  667. it.shootType = shoot;
  668. } else {
  669. std::cout << "[Warning - Items::parseItemNode] Unknown shootType: " << valueAttribute.as_string() << std::endl;
  670. }
  671. } else if (tmpStrValue == "effect") {
  672. MagicEffectClasses effect = getMagicEffect(valueAttribute.as_string());
  673. if (effect != CONST_ME_UNK) {
  674. it.magicEffect = effect;
  675. } else {
  676. std::cout << "[Warning - Items::parseItemNode] Unknown effect: " << valueAttribute.as_string() << std::endl;
  677. }
  678. } else if (tmpStrValue == "range") {
  679. it.shootRange = pugi::cast<int32_t>(valueAttribute.value());
  680. } else if (tmpStrValue == "stopduration") {
  681. it.stopTime = valueAttribute.as_bool();
  682. } else if (tmpStrValue == "decayto") {
  683. it.decayTo = pugi::cast<int32_t>(valueAttribute.value());
  684. } else if (tmpStrValue == "transformequipto") {
  685. it.transformEquipTo = pugi::cast<uint16_t>(valueAttribute.value());
  686. } else if (tmpStrValue == "transformdeequipto") {
  687. it.transformDeEquipTo = pugi::cast<uint16_t>(valueAttribute.value());
  688. } else if (tmpStrValue == "duration") {
  689. it.decayTime = pugi::cast<uint32_t>(valueAttribute.value());
  690. } else if (tmpStrValue == "showduration") {
  691. it.showDuration = valueAttribute.as_bool();
  692. } else if (tmpStrValue == "charges") {
  693. it.charges = pugi::cast<uint32_t>(valueAttribute.value());
  694. } else if (tmpStrValue == "showcharges") {
  695. it.showCharges = valueAttribute.as_bool();
  696. } else if (tmpStrValue == "showattributes") {
  697. it.showAttributes = valueAttribute.as_bool();
  698. } else if (tmpStrValue == "breakchance") {
  699. it.breakChance = std::min<uint32_t>(100, pugi::cast<uint32_t>(valueAttribute.value()));
  700. } else if (tmpStrValue == "ammoaction") {
  701. it.ammoAction = getAmmoAction(valueAttribute.as_string());
  702. if (it.ammoAction == AMMOACTION_NONE) {
  703. std::cout << "[Warning - Items::parseItemNode] Unknown ammoAction " << valueAttribute.as_string() << std::endl;
  704. }
  705. } else if (tmpStrValue == "hitchance") {
  706. it.hitChance = std::min<int32_t>(100, std::max<int32_t>(-100, pugi::cast<int32_t>(valueAttribute.value())));
  707. } else if (tmpStrValue == "maxhitchance") {
  708. it.maxHitChance = std::min<uint32_t>(100, pugi::cast<uint32_t>(valueAttribute.value()));
  709. } else if (tmpStrValue == "invisible") {
  710. it.getAbilities()->invisible = valueAttribute.as_bool();
  711. } else if (tmpStrValue == "speed") {
  712. it.getAbilities()->speed = pugi::cast<int32_t>(valueAttribute.value());
  713. } else if (tmpStrValue == "healthgain") {
  714. Abilities* abilities = it.getAbilities();
  715. abilities->regeneration = true;
  716. abilities->healthGain = pugi::cast<uint32_t>(valueAttribute.value());
  717. } else if (tmpStrValue == "healthticks") {
  718. Abilities* abilities = it.getAbilities();
  719. abilities->regeneration = true;
  720. abilities->healthTicks = pugi::cast<uint32_t>(valueAttribute.value());
  721. } else if (tmpStrValue == "managain") {
  722. Abilities* abilities = it.getAbilities();
  723. abilities->regeneration = true;
  724. abilities->manaGain = pugi::cast<uint32_t>(valueAttribute.value());
  725. } else if (tmpStrValue == "manaticks") {
  726. Abilities* abilities = it.getAbilities();
  727. abilities->regeneration = true;
  728. abilities->manaTicks = pugi::cast<uint32_t>(valueAttribute.value());
  729. } else if (tmpStrValue == "manashield") {
  730. it.getAbilities()->manaShield = valueAttribute.as_bool();
  731. } else if (tmpStrValue == "skillsword") {
  732. it.getAbilities()->skills[SKILL_SWORD] = pugi::cast<int32_t>(valueAttribute.value());
  733. } else if (tmpStrValue == "skillaxe") {
  734. it.getAbilities()->skills[SKILL_AXE] = pugi::cast<int32_t>(valueAttribute.value());
  735. } else if (tmpStrValue == "skillclub") {
  736. it.getAbilities()->skills[SKILL_CLUB] = pugi::cast<int32_t>(valueAttribute.value());
  737. } else if (tmpStrValue == "skilldist") {
  738. it.getAbilities()->skills[SKILL_DISTANCE] = pugi::cast<int32_t>(valueAttribute.value());
  739. } else if (tmpStrValue == "skillfish") {
  740. it.getAbilities()->skills[SKILL_FISHING] = pugi::cast<int32_t>(valueAttribute.value());
  741. } else if (tmpStrValue == "skillshield") {
  742. it.getAbilities()->skills[SKILL_SHIELD] = pugi::cast<int32_t>(valueAttribute.value());
  743. } else if (tmpStrValue == "skillfist") {
  744. it.getAbilities()->skills[SKILL_FIST] = pugi::cast<int32_t>(valueAttribute.value());
  745. } else if (tmpStrValue == "maxhitpoints") {
  746. it.getAbilities()->stats[STAT_MAXHITPOINTS] = pugi::cast<int32_t>(valueAttribute.value());
  747. } else if (tmpStrValue == "maxhitpointspercent") {
  748. it.getAbilities()->statsPercent[STAT_MAXHITPOINTS] = pugi::cast<int32_t>(valueAttribute.value());
  749. } else if (tmpStrValue == "maxmanapoints") {
  750. it.getAbilities()->stats[STAT_MAXMANAPOINTS] = pugi::cast<int32_t>(valueAttribute.value());
  751. } else if (tmpStrValue == "maxmanapointspercent") {
  752. it.getAbilities()->statsPercent[STAT_MAXMANAPOINTS] = pugi::cast<int32_t>(valueAttribute.value());
  753. } else if (tmpStrValue == "soulpoints") {
  754. it.getAbilities()->stats[STAT_SOULPOINTS] = pugi::cast<int32_t>(valueAttribute.value());
  755. } else if (tmpStrValue == "soulpointspercent") {
  756. it.getAbilities()->statsPercent[STAT_SOULPOINTS] = pugi::cast<int32_t>(valueAttribute.value());
  757. } else if (tmpStrValue == "magicpoints" || tmpStrValue == "magiclevelpoints") {
  758. it.getAbilities()->stats[STAT_MAGICPOINTS] = pugi::cast<int32_t>(valueAttribute.value());
  759. } else if (tmpStrValue == "magicpointspercent") {
  760. it.getAbilities()->statsPercent[STAT_MAGICPOINTS] = pugi::cast<int32_t>(valueAttribute.value());
  761. } else if (tmpStrValue == "fieldabsorbpercentenergy") {
  762. it.getAbilities()->fieldAbsorbPercent[combatTypeToIndex(COMBAT_ENERGYDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  763. } else if (tmpStrValue == "fieldabsorbpercentfire") {
  764. it.getAbilities()->fieldAbsorbPercent[combatTypeToIndex(COMBAT_FIREDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  765. } else if (tmpStrValue == "fieldabsorbpercentpoison" || tmpStrValue == "fieldabsorpercentearth") {
  766. it.getAbilities()->fieldAbsorbPercent[combatTypeToIndex(COMBAT_EARTHDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  767. } else if (tmpStrValue == "absorbpercentall" || tmpStrValue == "absorbpercentallelements") {
  768. int16_t value = pugi::cast<int16_t>(valueAttribute.value());
  769. Abilities* abilities = it.getAbilities();
  770. for (uint32_t i = COMBAT_FIRST; i <= COMBAT_COUNT; i++) {
  771. abilities->absorbPercent[i] += value;
  772. }
  773. } else if (tmpStrValue == "absorbpercentelements") {
  774. int16_t value = pugi::cast<int16_t>(valueAttribute.value());
  775. Abilities* abilities = it.getAbilities();
  776. abilities->absorbPercent[combatTypeToIndex(COMBAT_ENERGYDAMAGE)] += value;
  777. abilities->absorbPercent[combatTypeToIndex(COMBAT_FIREDAMAGE)] += value;
  778. abilities->absorbPercent[combatTypeToIndex(COMBAT_EARTHDAMAGE)] += value;
  779. abilities->absorbPercent[combatTypeToIndex(COMBAT_ICEDAMAGE)] += value;
  780. } else if (tmpStrValue == "absorbpercentmagic") {
  781. int16_t value = pugi::cast<int16_t>(valueAttribute.value());
  782. Abilities* abilities = it.getAbilities();
  783. abilities->absorbPercent[combatTypeToIndex(COMBAT_ENERGYDAMAGE)] += value;
  784. abilities->absorbPercent[combatTypeToIndex(COMBAT_FIREDAMAGE)] += value;
  785. abilities->absorbPercent[combatTypeToIndex(COMBAT_EARTHDAMAGE)] += value;
  786. abilities->absorbPercent[combatTypeToIndex(COMBAT_ICEDAMAGE)] += value;
  787. abilities->absorbPercent[combatTypeToIndex(COMBAT_HOLYDAMAGE)] += value;
  788. abilities->absorbPercent[combatTypeToIndex(COMBAT_DEATHDAMAGE)] += value;
  789. } else if (tmpStrValue == "absorbpercentenergy") {
  790. it.getAbilities()->absorbPercent[combatTypeToIndex(COMBAT_ENERGYDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  791. } else if (tmpStrValue == "absorbpercentfire") {
  792. it.getAbilities()->absorbPercent[combatTypeToIndex(COMBAT_FIREDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  793. } else if (tmpStrValue == "absorbpercentpoison" || tmpStrValue == "absorbpercentearth") {
  794. it.getAbilities()->absorbPercent[combatTypeToIndex(COMBAT_EARTHDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  795. } else if (tmpStrValue == "absorbpercentice") {
  796. it.getAbilities()->absorbPercent[combatTypeToIndex(COMBAT_ICEDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  797. } else if (tmpStrValue == "absorbpercentholy") {
  798. it.getAbilities()->absorbPercent[combatTypeToIndex(COMBAT_HOLYDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  799. } else if (tmpStrValue == "absorbpercentdeath") {
  800. it.getAbilities()->absorbPercent[combatTypeToIndex(COMBAT_DEATHDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  801. } else if (tmpStrValue == "absorbpercentlifedrain") {
  802. it.getAbilities()->absorbPercent[combatTypeToIndex(COMBAT_LIFEDRAIN)] += pugi::cast<int16_t>(valueAttribute.value());
  803. } else if (tmpStrValue == "absorbpercentmanadrain") {
  804. it.getAbilities()->absorbPercent[combatTypeToIndex(COMBAT_MANADRAIN)] += pugi::cast<int16_t>(valueAttribute.value());
  805. } else if (tmpStrValue == "absorbpercentdrown") {
  806. it.getAbilities()->absorbPercent[combatTypeToIndex(COMBAT_DROWNDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  807. } else if (tmpStrValue == "absorbpercentphysical") {
  808. it.getAbilities()->absorbPercent[combatTypeToIndex(COMBAT_PHYSICALDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  809. } else if (tmpStrValue == "absorbpercenthealing") {
  810. it.getAbilities()->absorbPercent[combatTypeToIndex(COMBAT_HEALING)] += pugi::cast<int16_t>(valueAttribute.value());
  811. } else if (tmpStrValue == "absorbpercentundefined") {
  812. it.getAbilities()->absorbPercent[combatTypeToIndex(COMBAT_UNDEFINEDDAMAGE)] += pugi::cast<int16_t>(valueAttribute.value());
  813. } else if (tmpStrValue == "suppressdrunk") {
  814. if (valueAttribute.as_bool()) {
  815. it.getAbilities()->conditionSuppressions |= CONDITION_DRUNK;
  816. }
  817. } else if (tmpStrValue == "suppressenergy") {
  818. if (valueAttribute.as_bool()) {
  819. it.getAbilities()->conditionSuppressions |= CONDITION_ENERGY;
  820. }
  821. } else if (tmpStrValue == "suppressfire") {
  822. if (valueAttribute.as_bool()) {
  823. it.getAbilities()->conditionSuppressions |= CONDITION_FIRE;
  824. }
  825. } else if (tmpStrValue == "suppresspoison") {
  826. if (valueAttribute.as_bool()) {
  827. it.getAbilities()->conditionSuppressions |= CONDITION_POISON;
  828. }
  829. } else if (tmpStrValue == "suppressdrown") {
  830. if (valueAttribute.as_bool()) {
  831. it.getAbilities()->conditionSuppressions |= CONDITION_DROWN;
  832. }
  833. } else if (tmpStrValue == "suppressphysical") {
  834. if (valueAttribute.as_bool()) {
  835. it.getAbilities()->conditionSuppressions |= CONDITION_BLEEDING;
  836. }
  837. } else if (tmpStrValue == "suppressfreeze") {
  838. if (valueAttribute.as_bool()) {
  839. it.getAbilities()->conditionSuppressions |= CONDITION_FREEZING;
  840. }
  841. } else if (tmpStrValue == "suppressdazzle") {
  842. if (valueAttribute.as_bool()) {
  843. it.getAbilities()->conditionSuppressions |= CONDITION_DAZZLED;
  844. }
  845. } else if (tmpStrValue == "suppresscurse") {
  846. if (valueAttribute.as_bool()) {
  847. it.getAbilities()->conditionSuppressions |= CONDITION_CURSED;
  848. }
  849. } else if (tmpStrValue == "field") {
  850. it.group = ITEM_GROUP_MAGICFIELD;
  851. it.type = ITEM_TYPE_MAGICFIELD;
  852.  
  853. CombatType_t combatType = COMBAT_NONE;
  854. ConditionDamage* conditionDamage = nullptr;
  855.  
  856. tmpStrValue = asLowerCaseString(valueAttribute.as_string());
  857. if (tmpStrValue == "fire") {
  858. conditionDamage = new ConditionDamage(CONDITIONID_COMBAT, CONDITION_FIRE);
  859. combatType = COMBAT_FIREDAMAGE;
  860. } else if (tmpStrValue == "energy") {
  861. conditionDamage = new ConditionDamage(CONDITIONID_COMBAT, CONDITION_ENERGY);
  862. combatType = COMBAT_ENERGYDAMAGE;
  863. } else if (tmpStrValue == "poison") {
  864. conditionDamage = new ConditionDamage(CONDITIONID_COMBAT, CONDITION_POISON);
  865. combatType = COMBAT_EARTHDAMAGE;
  866. } else if (tmpStrValue == "drown") {
  867. conditionDamage = new ConditionDamage(CONDITIONID_COMBAT, CONDITION_DROWN);
  868. combatType = COMBAT_DROWNDAMAGE;
  869. } else if (tmpStrValue == "physical") {
  870. conditionDamage = new ConditionDamage(CONDITIONID_COMBAT, CONDITION_BLEEDING);
  871. combatType = COMBAT_PHYSICALDAMAGE;
  872. } else {
  873. std::cout << "[Warning - Items::parseItemNode] Unknown field value: " << valueAttribute.as_string() << std::endl;
  874. }
  875.  
  876. if (combatType != COMBAT_NONE) {
  877. it.combatType = combatType;
  878. it.condition = conditionDamage;
  879. uint32_t ticks = 0;
  880. int32_t damage = 0;
  881. int32_t start = 0;
  882. int32_t count = 1;
  883.  
  884. for (pugi::xml_node subAttributeNode = attributeNode.first_child(); subAttributeNode; subAttributeNode = subAttributeNode.next_sibling()) {
  885. pugi::xml_attribute subKeyAttribute = subAttributeNode.attribute("key");
  886. if (!subKeyAttribute) {
  887. continue;
  888. }
  889.  
  890. pugi::xml_attribute subValueAttribute = subAttributeNode.attribute("value");
  891. if (!subValueAttribute) {
  892. continue;
  893. }
  894.  
  895. tmpStrValue = asLowerCaseString(subKeyAttribute.as_string());
  896. if (tmpStrValue == "ticks") {
  897. ticks = pugi::cast<uint32_t>(subValueAttribute.value());
  898. } else if (tmpStrValue == "count") {
  899. count = std::max<int32_t>(1, pugi::cast<int32_t>(subValueAttribute.value()));
  900. } else if (tmpStrValue == "start") {
  901. start = std::max<int32_t>(0, pugi::cast<int32_t>(subValueAttribute.value()));
  902. } else if (tmpStrValue == "damage") {
  903. damage = -pugi::cast<int32_t>(subValueAttribute.value());
  904.  
  905. if (start > 0) {
  906. std::list<int32_t> damageList;
  907. ConditionDamage::generateDamageList(damage, start, damageList);
  908. for (int32_t damageValue : damageList) {
  909. conditionDamage->addDamage(1, ticks, -damageValue);
  910. }
  911.  
  912. start = 0;
  913. } else {
  914. conditionDamage->addDamage(count, ticks, damage);
  915. }
  916. }
  917. }
  918.  
  919. conditionDamage->setParam(CONDITION_PARAM_FIELD, 1);
  920.  
  921. if (conditionDamage->getTotalDamage() > 0) {
  922. conditionDamage->setParam(CONDITION_PARAM_FORCEUPDATE, 1);
  923. }
  924. }
  925. } else if (tmpStrValue == "replaceable") {
  926. it.replaceable = valueAttribute.as_bool();
  927. } else if (tmpStrValue == "partnerdirection") {
  928. it.bedPartnerDir = getDirection(valueAttribute.as_string());
  929. } else if (tmpStrValue == "leveldoor") {
  930. it.levelDoor = pugi::cast<uint32_t>(valueAttribute.value());
  931. } else if (tmpStrValue == "maletransformto" || tmpStrValue == "malesleeper") {
  932. uint16_t value = pugi::cast<uint16_t>(valueAttribute.value());
  933. it.transformToOnUse[PLAYERSEX_MALE] = value;
  934. ItemType& other = getItemType(value);
  935. if (other.transformToFree == 0) {
  936. other.transformToFree = it.id;
  937. }
  938.  
  939. if (it.transformToOnUse[PLAYERSEX_FEMALE] == 0) {
  940. it.transformToOnUse[PLAYERSEX_FEMALE] = value;
  941. }
  942. } else if (tmpStrValue == "femaletransformto" || tmpStrValue == "femalesleeper") {
  943. uint16_t value = pugi::cast<uint16_t>(valueAttribute.value());
  944. it.transformToOnUse[PLAYERSEX_FEMALE] = value;
  945.  
  946. ItemType& other = getItemType(value);
  947. if (other.transformToFree == 0) {
  948. other.transformToFree = it.id;
  949. }
  950.  
  951. if (it.transformToOnUse[PLAYERSEX_MALE] == 0) {
  952. it.transformToOnUse[PLAYERSEX_MALE] = value;
  953. }
  954. } else if (tmpStrValue == "transformto") {
  955. it.transformToFree = pugi::cast<uint16_t>(valueAttribute.value());
  956. } else if (tmpStrValue == "elementice") {
  957. Abilities* abilities = it.getAbilities();
  958. abilities->elementDamage = pugi::cast<int16_t>(valueAttribute.value());
  959. abilities->elementType = COMBAT_ICEDAMAGE;
  960. } else if (tmpStrValue == "elementearth") {
  961. Abilities* abilities = it.getAbilities();
  962. abilities->elementDamage = pugi::cast<int16_t>(valueAttribute.value());
  963. abilities->elementType = COMBAT_EARTHDAMAGE;
  964. } else if (tmpStrValue == "elementfire") {
  965. Abilities* abilities = it.getAbilities();
  966. abilities->elementDamage = pugi::cast<int16_t>(valueAttribute.value());
  967. abilities->elementType = COMBAT_FIREDAMAGE;
  968. } else if (tmpStrValue == "elementenergy") {
  969. Abilities* abilities = it.getAbilities();
  970. abilities->elementDamage = pugi::cast<int16_t>(valueAttribute.value());
  971. abilities->elementType = COMBAT_ENERGYDAMAGE;
  972. } else if (tmpStrValue == "walkstack") {
  973. it.walkStack = valueAttribute.as_bool();
  974. } else if (tmpStrValue == "alwaysontop") {
  975. it.alwaysOnTop = booleanString(valueAttribute.as_string());
  976. } else if (tmpStrValue == "toporder") {
  977. it.alwaysOnTopOrder = pugi::cast<uint16_t>(valueAttribute.value());
  978. } else if (tmpStrValue == "blocking") {
  979. it.blockSolid = valueAttribute.as_bool();
  980. } else if (tmpStrValue == "allowdistread") {
  981. it.allowDistRead = booleanString(valueAttribute.as_string());
  982. } else {
  983. std::cout << "[Warning - Items::parseItemNode] Unknown key value: " << keyAttribute.as_string() << std::endl;
  984. }
  985. }
  986.  
  987. //check bed items
  988. if ((it.transformToFree != 0 || it.transformToOnUse[PLAYERSEX_FEMALE] != 0 || it.transformToOnUse[PLAYERSEX_MALE] != 0) && it.type != ITEM_TYPE_BED) {
  989. std::cout << "[Warning - Items::parseItemNode] Item " << it.id << " is not set as a bed-type" << std::endl;
  990. }
  991. }
  992.  
  993. ItemType& Items::getItemType(size_t id)
  994. {
  995. if (id < items.size()) {
  996. return items[id];
  997. }
  998. return items.front();
  999. }
  1000.  
  1001. const ItemType& Items::getItemType(size_t id) const
  1002. {
  1003. if (id < items.size()) {
  1004. return items[id];
  1005. }
  1006. return items.front();
  1007. }
  1008.  
  1009. const ItemType& Items::getItemIdByClientId(uint16_t spriteId) const
  1010. {
  1011. auto it = reverseItemMap.find(spriteId);
  1012. if (it != reverseItemMap.end()) {
  1013. return getItemType(it->second);
  1014. }
  1015. return items.front();
  1016. }
  1017.  
  1018. uint16_t Items::getItemIdByName(const std::string& name)
  1019. {
  1020. if (name.empty()) {
  1021. return 0;
  1022. }
  1023.  
  1024. const char* itemName = name.c_str();
  1025. for (size_t i = 100, size = items.size(); i < size; ++i) {
  1026. if (strcasecmp(itemName, items[i].name.c_str()) == 0) {
  1027. return i;
  1028. }
  1029. }
  1030. return 0;
  1031. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement