Advertisement
Guest User

Untitled

a guest
May 14th, 2014
192
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 27.74 KB | None | 0 0
  1. diff --git a/src/server/game/Entities/Item/ItemPrototype.h b/src/server/game/Entities/Item/ItemPrototype.h
  2. index 5088a30..f83078b 100755
  3. --- a/src/server/game/Entities/Item/ItemPrototype.h
  4. +++ b/src/server/game/Entities/Item/ItemPrototype.h
  5. @@ -743,6 +743,7 @@ struct ItemTemplate
  6.  
  7. // Benchmarked: Faster than std::map (insert/find)
  8. typedef UNORDERED_MAP<uint32, ItemTemplate> ItemTemplateContainer;
  9. +typedef UNORDERED_MAP<uint32, std::map<uint32, int32> > ItemFakeStatContainer; // custom
  10.  
  11. struct ItemLocale
  12. {
  13. diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
  14. index 3b51411..8380965 100755
  15. --- a/src/server/game/Entities/Player/Player.cpp
  16. +++ b/src/server/game/Entities/Player/Player.cpp
  17. @@ -7737,6 +7737,10 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply
  18. if (only_level_scale && !ssv)
  19. return;
  20.  
  21. + uint32 lowGUID = 0;
  22. + if(Item* invItem = GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
  23. + if(sObjectMgr->_itemFakeStatStore.find(invItem->GetGUIDLow()) != sObjectMgr->_itemFakeStatStore.end())
  24. + lowGUID = invItem->GetGUIDLow();
  25. for (uint8 i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
  26. {
  27. uint32 statType = 0;
  28. @@ -7755,6 +7759,8 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply
  29. continue;
  30. statType = proto->ItemStat[i].ItemStatType;
  31. val = proto->ItemStat[i].ItemStatValue;
  32. + if(lowGUID && sObjectMgr->_itemFakeStatStore[lowGUID].find(i) != sObjectMgr->_itemFakeStatStore[lowGUID].end())
  33. + val += sObjectMgr->_itemFakeStatStore[lowGUID][i];
  34. }
  35.  
  36. if (val == 0)
  37. diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
  38. index fcc0315..2e3adff 100755
  39. --- a/src/server/game/Globals/ObjectMgr.h
  40. +++ b/src/server/game/Globals/ObjectMgr.h
  41. @@ -1145,6 +1145,8 @@ class ObjectMgr
  42. void LoadFactionChangeSpells();
  43. void LoadFactionChangeReputations();
  44.  
  45. + ItemFakeStatContainer _itemFakeStatStore; // custom
  46. +
  47. private:
  48. // first free id for selected id type
  49. uint32 _auctionId;
  50. diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp
  51. index ed5b563..f4a7ef4 100755
  52. --- a/src/server/game/Scripting/ScriptLoader.cpp
  53. +++ b/src/server/game/Scripting/ScriptLoader.cpp
  54. @@ -1249,6 +1249,7 @@ void AddBattlegroundScripts()
  55. #ifdef SCRIPTS
  56. /* This is where custom scripts' loading functions should be declared. */
  57.  
  58. +void AddSC_REFORGER_NPC();
  59. #endif
  60.  
  61. void AddCustomScripts()
  62. @@ -1256,5 +1257,6 @@ void AddCustomScripts()
  63. #ifdef SCRIPTS
  64. /* This is where custom scripts should be added. */
  65.  
  66. + AddSC_REFORGER_NPC();
  67. #endif
  68. }
  69. diff --git a/src/server/scripts/Custom/CMakeLists.txt b/src/server/scripts/Custom/CMakeLists.txt
  70. index 62abde2..f3302dc 100644
  71. --- a/src/server/scripts/Custom/CMakeLists.txt
  72. +++ b/src/server/scripts/Custom/CMakeLists.txt
  73. @@ -10,6 +10,7 @@
  74.  
  75. set(scripts_STAT_SRCS
  76. ${scripts_STAT_SRCS}
  77. + Custom/Reforging.cpp
  78. )
  79.  
  80. message(" -> Prepared: Custom")
  81. diff --git a/src/server/scripts/Custom/Reforging.cpp b/src/server/scripts/Custom/Reforging.cpp
  82. new file mode 100644
  83. index 0000000..fcd4a39
  84. --- /dev/null
  85. +++ b/src/server/scripts/Custom/Reforging.cpp
  86. @@ -0,0 +1,526 @@
  87. +#include "ScriptPCH.h"
  88. +struct accepted_stat_format {uint32 stat_type; char* stat_name; int32 base_stat_change; };
  89. +
  90. +// ########################################################################################
  91. +// Reforging config
  92. +// ########################################################################################
  93. +static const uint32 tokenEntry = 49426; // token entry
  94. +static const uint8 maxTokenAmount = 3; // max token cost (multiplies the max stat amount also)
  95. +static const uint8 maxReforges = 3; // maximum reforges for one item
  96. +static const bool send_cache_packets = true; // change player cache?
  97. +
  98. +static const accepted_stat_format accepted_stat_types[] =
  99. +{
  100. + // See ItemPrototype.h for ItemModType definitions. You can add more rows for more stats.
  101. + {ITEM_MOD_HEALTH, "Health", 5000},
  102. + {ITEM_MOD_STRENGTH, "Strength", 250},
  103. + {ITEM_MOD_INTELLECT, "Intellect", 250},
  104. + {ITEM_MOD_AGILITY, "Agility", 100},
  105. + {ITEM_MOD_SPIRIT, "Spirit", 250},
  106. + {ITEM_MOD_STAMINA, "Stamina", 500},
  107. + {ITEM_MOD_ATTACK_POWER, "Attack power", 500},
  108. + {ITEM_MOD_SPELL_POWER, "Spell power", 500},
  109. +};
  110. +
  111. +// ########################################################################################
  112. +
  113. +static const uint32 accepted_stat_types_max = sizeof(accepted_stat_types) / sizeof(accepted_stat_format);
  114. +struct playerItems_format {uint32 Entry, lowGUID;};
  115. +static UNORDERED_MAP<uint32, std::vector<playerItems_format> > playerItems;
  116. +
  117. +static const void SendReforgePackets(Player* player)
  118. +{
  119. + if(!send_cache_packets)
  120. + return;
  121. +
  122. + uint32 pGUID = player->GetGUIDLow();
  123. + if(playerItems.find(pGUID) == playerItems.end())
  124. + return;
  125. +
  126. + for (std::vector<playerItems_format>::iterator it = playerItems[pGUID].begin(); it != playerItems[pGUID].end(); it++)
  127. + {
  128. + // See how enchanthing is done
  129. + // Update player cache (self only) pure visual.
  130. + // HandleItemQuerySingleOpcode copy paste:
  131. + const ItemTemplate* proto = sObjectMgr->GetItemTemplate(it->Entry);
  132. + std::string Name = proto->Name1;
  133. + std::string Description = proto->Description;
  134. + int loc_idx = player->GetSession()->GetSessionDbLocaleIndex();
  135. + if (loc_idx >= 0)
  136. + {
  137. + if (ItemLocale const* il = sObjectMgr->GetItemLocale(proto->ItemId))
  138. + {
  139. + ObjectMgr::GetLocaleString(il->Name, loc_idx, Name);
  140. + ObjectMgr::GetLocaleString(il->Description, loc_idx, Description);
  141. + }
  142. + }
  143. + WorldPacket data(SMSG_ITEM_QUERY_SINGLE_RESPONSE, 600);
  144. + data << proto->ItemId;
  145. + data << proto->Class;
  146. + data << proto->SubClass;
  147. + data << int32(proto->Unk0);
  148. + data << Name;
  149. + data << uint8(0x00);
  150. + data << uint8(0x00);
  151. + data << uint8(0x00);
  152. + data << proto->DisplayInfoID;
  153. + data << proto->Quality;
  154. + data << proto->Flags;
  155. + data << proto->Flags2;
  156. + data << proto->BuyPrice;
  157. + data << proto->SellPrice;
  158. + data << proto->InventoryType;
  159. + data << proto->AllowableClass;
  160. + data << proto->AllowableRace;
  161. + data << proto->ItemLevel;
  162. + data << proto->RequiredLevel;
  163. + data << proto->RequiredSkill;
  164. + data << proto->RequiredSkillRank;
  165. + data << proto->RequiredSpell;
  166. + data << proto->RequiredHonorRank;
  167. + data << proto->RequiredCityRank;
  168. + data << proto->RequiredReputationFaction;
  169. + data << proto->RequiredReputationRank;
  170. + data << int32(proto->MaxCount);
  171. + data << int32(proto->Stackable);
  172. + data << proto->ContainerSlots;
  173. + data << proto->StatsCount;
  174. + for (uint32 i = 0; i < proto->StatsCount; ++i)
  175. + {
  176. + data << proto->ItemStat[i].ItemStatType;
  177. + if(sObjectMgr->_itemFakeStatStore[it->lowGUID].find(i) != sObjectMgr->_itemFakeStatStore[it->lowGUID].end())
  178. + data << proto->ItemStat[i].ItemStatValue + sObjectMgr->_itemFakeStatStore[it->lowGUID][i];
  179. + else
  180. + data << proto->ItemStat[i].ItemStatValue;
  181. + }
  182. + data << proto->ScalingStatDistribution;
  183. + data << proto->ScalingStatValue;
  184. + for (int i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
  185. + {
  186. + data << proto->Damage[i].DamageMin;
  187. + data << proto->Damage[i].DamageMax;
  188. + data << proto->Damage[i].DamageType;
  189. + }
  190. + data << proto->Armor;
  191. + data << proto->HolyRes;
  192. + data << proto->FireRes;
  193. + data << proto->NatureRes;
  194. + data << proto->FrostRes;
  195. + data << proto->ShadowRes;
  196. + data << proto->ArcaneRes;
  197. + data << proto->Delay;
  198. + data << proto->AmmoType;
  199. + data << proto->RangedModRange;
  200. + for (int s = 0; s < MAX_ITEM_PROTO_SPELLS; ++s)
  201. + {
  202. + SpellInfo const* spell = sSpellMgr->GetSpellInfo(proto->Spells[s].SpellId);
  203. + if (spell)
  204. + {
  205. + bool db_data = proto->Spells[s].SpellCooldown >= 0 || proto->Spells[s].SpellCategoryCooldown >= 0;
  206. + data << proto->Spells[s].SpellId;
  207. + data << proto->Spells[s].SpellTrigger;
  208. + data << uint32(-abs(proto->Spells[s].SpellCharges));
  209. + if (db_data)
  210. + {
  211. + data << uint32(proto->Spells[s].SpellCooldown);
  212. + data << uint32(proto->Spells[s].SpellCategory);
  213. + data << uint32(proto->Spells[s].SpellCategoryCooldown);
  214. + }
  215. + else
  216. + {
  217. + data << uint32(spell->RecoveryTime);
  218. + data << uint32(spell->Category);
  219. + data << uint32(spell->CategoryRecoveryTime);
  220. + }
  221. + }
  222. + else
  223. + {
  224. + data << uint32(0);
  225. + data << uint32(0);
  226. + data << uint32(0);
  227. + data << uint32(-1);
  228. + data << uint32(0);
  229. + data << uint32(-1);
  230. + }
  231. + }
  232. + data << proto->Bonding;
  233. + data << Description;
  234. + data << proto->PageText;
  235. + data << proto->LanguageID;
  236. + data << proto->PageMaterial;
  237. + data << proto->StartQuest;
  238. + data << proto->LockID;
  239. + data << int32(proto->Material);
  240. + data << proto->Sheath;
  241. + data << proto->RandomProperty;
  242. + data << proto->RandomSuffix;
  243. + data << proto->Block;
  244. + data << proto->ItemSet;
  245. + data << proto->MaxDurability;
  246. + data << proto->Area;
  247. + data << proto->Map;
  248. + data << proto->BagFamily;
  249. + data << proto->TotemCategory;
  250. + for (int s = 0; s < MAX_ITEM_PROTO_SOCKETS; ++s)
  251. + {
  252. + data << proto->Socket[s].Color;
  253. + data << proto->Socket[s].Content;
  254. + }
  255. + data << proto->socketBonus;
  256. + data << proto->GemProperties;
  257. + data << proto->RequiredDisenchantSkill;
  258. + data << proto->ArmorDamageModifier;
  259. + data << proto->Duration;
  260. + data << proto->ItemLimitCategory;
  261. + data << proto->HolidayId;
  262. + player->GetSession()->SendPacket(&data);
  263. + }
  264. +}
  265. +
  266. +class REFORGING_DATA_HANDLER : public PlayerScript
  267. +{
  268. +public:
  269. + REFORGING_DATA_HANDLER() : PlayerScript("REFORGING_DATA_HANDLER")
  270. + {
  271. + // DB cleanup on startup
  272. + CharacterDatabase.Execute("DELETE FROM custom_reforges WHERE NOT EXISTS (SELECT 1 FROM item_instance WHERE item_instance.guid = custom_reforges.iGUID)");
  273. + }
  274. +
  275. + // Called when a player logs out.
  276. + void OnLogout(Player* player)
  277. + {
  278. + DeleteSavedReforges(player->GetGUIDLow()); // delete stored reforges from the player (not DB)
  279. + }
  280. +
  281. + void OnLogin(Player* player)
  282. + {
  283. + uint32 pGUID = player->GetGUIDLow();
  284. +
  285. + DeleteSavedReforges(pGUID); // delete saved reforges from the player before loading them
  286. + QueryResult result = CharacterDatabase.PQuery("SELECT `iGUID`, `stat_count_id`, `stat_diff`, `Entry` FROM `custom_reforges` WHERE pGUID = %u and EXISTS (SELECT 1 FROM item_instance WHERE item_instance.guid = custom_reforges.iGUID)", pGUID);
  287. + if (result)
  288. + {
  289. + UNORDERED_MAP<uint32, std::map<uint32, int32> > stat_temp_container; // iGUID <stat_count, stat_diff>
  290. + std::set<uint32> sent_error_message;
  291. + do
  292. + {
  293. + uint32 lowGUID = (*result)[0].GetUInt32();
  294. + if(sObjectMgr->_itemFakeStatStore.find(lowGUID) != sObjectMgr->_itemFakeStatStore.end() && sObjectMgr->_itemFakeStatStore[lowGUID].size() >= maxReforges)
  295. + {
  296. + if(sent_error_message.find(lowGUID) != sent_error_message.end())
  297. + continue;
  298. + sLog->outErrorDb("Too many reforges for item lowGUID %u, ignoring extra reforges.", lowGUID);
  299. + sent_error_message.insert(lowGUID);
  300. + }
  301. + else
  302. + {
  303. + stat_temp_container[lowGUID][(*result)[1].GetUInt32()] = (*result)[2].GetInt32();
  304. + playerItems_format temp = {(*result)[3].GetUInt32(), lowGUID}; // temp var so we can insert our stuff
  305. + playerItems[pGUID].push_back(temp);
  306. + }
  307. + } while (result->NextRow());
  308. +
  309. + // apply stat changes for all reforged items equipped and save them to container
  310. + for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; slot++)
  311. + {
  312. + if(Item* invItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
  313. + {
  314. + uint32 invGUID = invItem->GetGUIDLow();
  315. + if(stat_temp_container.find(invGUID) != stat_temp_container.end())
  316. + {
  317. + player->_ApplyItemMods(invItem, slot, false);
  318. + for(std::map<uint32, int32>::iterator stat_count_id = stat_temp_container[invGUID].begin(); stat_count_id != stat_temp_container[invGUID].end(); stat_count_id++)
  319. + {
  320. + sObjectMgr->_itemFakeStatStore[invGUID][stat_count_id->first] = stat_count_id->second;
  321. + }
  322. + player->_ApplyItemMods(invItem, slot, true);
  323. + stat_temp_container.erase(invGUID); // saved reforges for this item, delete from temp
  324. + }
  325. + }
  326. + }
  327. +
  328. + // save the rest of the player's reforges to the container if more exist
  329. + if(!stat_temp_container.empty())
  330. + {
  331. + for(UNORDERED_MAP<uint32, std::map<uint32, int32> >::iterator iGUID = stat_temp_container.begin(); iGUID != stat_temp_container.end(); iGUID++)
  332. + {
  333. + for(std::map<uint32, int32>::iterator stat_count_id = iGUID->second.begin(); stat_count_id != iGUID->second.end(); stat_count_id++)
  334. + {
  335. + sObjectMgr->_itemFakeStatStore[iGUID->first][stat_count_id->first] = stat_count_id->second;
  336. + }
  337. + }
  338. + }
  339. + }
  340. +
  341. + SendReforgePackets(player);
  342. + }
  343. +
  344. +private:
  345. +
  346. + void DeleteSavedReforges(uint32 pGUID)
  347. + {
  348. + if(playerItems.find(pGUID) == playerItems.end())
  349. + return; // Already empty!
  350. + for (std::vector<playerItems_format>::iterator it = playerItems[pGUID].begin(); it != playerItems[pGUID].end(); it++)
  351. + {
  352. + if(sObjectMgr->_itemFakeStatStore.find(it->lowGUID) != sObjectMgr->_itemFakeStatStore.end())
  353. + sObjectMgr->_itemFakeStatStore.erase(it->lowGUID);
  354. + }
  355. + playerItems.erase(pGUID);
  356. + }
  357. +};
  358. +
  359. +class REFORGER_NPC : public CreatureScript
  360. +{
  361. +public:
  362. + REFORGER_NPC() : CreatureScript("REFORGER_NPC")
  363. + {
  364. + for(uint32 i = 0; i < accepted_stat_types_max; i++)
  365. + {
  366. + stat_format temp = {accepted_stat_types[i].stat_name, accepted_stat_types[i].base_stat_change};
  367. + stat_types[accepted_stat_types[i].stat_type] = temp;
  368. + }
  369. + }
  370. +
  371. + bool OnGossipHello(Player* player, Creature* creature)
  372. + {
  373. + if(selectedItem.find(player->GetGUIDLow()) != selectedItem.end())
  374. + selectedItem.erase(player->GetGUIDLow());
  375. +
  376. + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_BATTLE, "Select equipped item in slot:", MAIN_MENU, 0);
  377. + for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; slot++)
  378. + {
  379. + if(Item* invItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
  380. + if(IsReforgable(invItem, player))
  381. + if(char* slotname = GetSlotName(slot, player->GetSession()))
  382. + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_TRAINER, slotname, SELECT_STAT_INCREASE, slot);
  383. + }
  384. + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Update menu", MAIN_MENU, 0);
  385. + player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
  386. + return true;
  387. + }
  388. +
  389. + bool OnGossipSelect(Player* player, Creature* creature, uint32 sender, uint32 action)
  390. + {
  391. + player->PlayerTalkClass->ClearMenus();
  392. + switch(sender)
  393. + {
  394. + case MAIN_MENU: OnGossipHello(player, creature); break;
  395. + case SELECT_STAT_INCREASE:
  396. + // action = slot
  397. + if (Item* invItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, action))
  398. + {
  399. + if(IsReforgable(invItem, player))
  400. + {
  401. + selectedItem[player->GetGUIDLow()] = invItem;
  402. + const ItemTemplate* proto = invItem->GetTemplate();
  403. + char label[250];
  404. +
  405. + snprintf(label, 250, "Selected item:\n%s", invItem->GetTemplate()->Name1.c_str());
  406. + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_BATTLE, label, sender, action);
  407. + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_BATTLE, "Select stat to increase:", sender, action);
  408. + bool hasfakestats = ((sObjectMgr->_itemFakeStatStore.find(invItem->GetGUIDLow()) != sObjectMgr->_itemFakeStatStore.end()) ? true : false);
  409. + for (uint32 i = 0; i < proto->StatsCount; ++i)
  410. + {
  411. + if(hasfakestats && sObjectMgr->_itemFakeStatStore[invItem->GetGUIDLow()].find(i) != sObjectMgr->_itemFakeStatStore[invItem->GetGUIDLow()].end())
  412. + continue; // already modded this stat, skip.
  413. + if(char* stat_name = GetStatName(proto->ItemStat[i].ItemStatType))
  414. + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_TRAINER, stat_name, SELECT_TOKEN_COST, i);
  415. + }
  416. + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_TALK, "Back..", MAIN_MENU, 0);
  417. + player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
  418. + }
  419. + else
  420. + {
  421. + player->GetSession()->SendNotification("Item not reforgable");
  422. + OnGossipHello(player, creature);
  423. + }
  424. + }
  425. + else
  426. + {
  427. + player->GetSession()->SendNotification("No item selected");
  428. + OnGossipHello(player, creature);
  429. + }
  430. + break;
  431. + case SELECT_TOKEN_COST:
  432. + // action = stat_count_id
  433. + {
  434. + Item* invItem = selectedItem[player->GetGUIDLow()];
  435. + if (invItem && invItem->IsInWorld() && IsReforgable(invItem, player))
  436. + {
  437. + const ItemTemplate* proto = invItem->GetTemplate();
  438. + char label[250];
  439. + char popup[250];
  440. +
  441. + snprintf(label, 250, "Selected item:\n%s", invItem->GetTemplate()->Name1.c_str());
  442. + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_BATTLE, label, sender, action);
  443. + snprintf(label, 250, "Selected stat: %s", stat_types[proto->ItemStat[action].ItemStatType].stat_name);
  444. + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_BATTLE, label, sender, action);
  445. + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_BATTLE, "Select amount to increase:", sender, action);
  446. + for (uint32 i = 1; i <= maxTokenAmount; ++i)
  447. + {
  448. + snprintf(label, 250, "Increase by %i for %u x %s", stat_types[proto->ItemStat[action].ItemStatType].stat_base_value*i, i, GetItemName(tokenEntry, player->GetSession()).c_str());
  449. + snprintf(popup, 250, "Are you sure?\nThe item is set untradeable and non-refundable\n\nCosts %u x %s", i, GetItemName(tokenEntry, player->GetSession()).c_str());
  450. + player->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_TRAINER, label, i, action, popup, 0, false); // sender = token_count, action = stat_count_id
  451. + }
  452. + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_TALK, "Back..", SELECT_STAT_INCREASE, invItem->GetSlot());
  453. + player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
  454. + }
  455. + else
  456. + {
  457. + player->GetSession()->SendNotification("Invalid item selected");
  458. + OnGossipHello(player, creature);
  459. + }
  460. + }
  461. + break;
  462. + default: // Reforge
  463. + // sender = token_count, action = stat_count_id
  464. + {
  465. + Item* invItem = selectedItem[player->GetGUIDLow()];
  466. + if (invItem && invItem->IsInWorld() && IsReforgable(invItem, player))
  467. + {
  468. + if(sender && sender <= maxTokenAmount)
  469. + {
  470. + if(player->HasItemCount(tokenEntry, sender))
  471. + {
  472. + player->DestroyItemCount(tokenEntry, sender, true);
  473. + UpdatePlayerReforgeStats(invItem, player, action, sender);
  474. + }
  475. + else
  476. + {
  477. + player->GetSession()->SendNotification("Not enough tokens");
  478. + OnGossipSelect(player, creature, SELECT_TOKEN_COST, action);
  479. + return true;
  480. + }
  481. + }
  482. + else
  483. + player->GetSession()->SendNotification("Invalid token count");
  484. + }
  485. + else
  486. + player->GetSession()->SendNotification("Invalid item selected");
  487. + OnGossipHello(player, creature);
  488. + }
  489. + }
  490. + return true;
  491. + }
  492. +
  493. +private:
  494. +
  495. + enum Senders
  496. + {
  497. + MAIN_MENU = GOSSIP_ACTION_INFO_DEF+1,
  498. + SELECT_ITEM,
  499. + SELECT_STAT_INCREASE,
  500. + SELECT_TOKEN_COST,
  501. + REFORGE,
  502. + };
  503. +
  504. + struct stat_format {char* stat_name; int32 stat_base_value; };
  505. + UNORDERED_MAP<uint32, struct stat_format> stat_types;
  506. + UNORDERED_MAP<uint32, Item*> selectedItem;
  507. +
  508. + char* GetStatName(uint32 stat_type)
  509. + {
  510. + if(stat_types.find(stat_type) != stat_types.end())
  511. + return stat_types[stat_type].stat_name;
  512. + return NULL;
  513. + }
  514. +
  515. + char * GetSlotName(uint8 slot, WorldSession* session)
  516. + {
  517. + switch (slot)
  518. + {
  519. + case EQUIPMENT_SLOT_HEAD : return "Head";
  520. + case EQUIPMENT_SLOT_NECK : return "Neck";
  521. + case EQUIPMENT_SLOT_SHOULDERS : return "Shoulders";
  522. + case EQUIPMENT_SLOT_BODY : return "Shirt";
  523. + case EQUIPMENT_SLOT_CHEST : return "Chest";
  524. + case EQUIPMENT_SLOT_WAIST : return "Waist";
  525. + case EQUIPMENT_SLOT_LEGS : return "Legs";
  526. + case EQUIPMENT_SLOT_FEET : return "Feet";
  527. + case EQUIPMENT_SLOT_WRISTS : return "Wrists";
  528. + case EQUIPMENT_SLOT_HANDS : return "Hands";
  529. + case EQUIPMENT_SLOT_FINGER1 : return "Right finger";
  530. + case EQUIPMENT_SLOT_FINGER2 : return "left finger";
  531. + case EQUIPMENT_SLOT_TRINKET1 : return "Right trinket";
  532. + case EQUIPMENT_SLOT_TRINKET2 : return "Left trinket";
  533. + case EQUIPMENT_SLOT_BACK : return "Back";
  534. + case EQUIPMENT_SLOT_MAINHAND : return "Main hand";
  535. + case EQUIPMENT_SLOT_OFFHAND : return "Off hand";
  536. + case EQUIPMENT_SLOT_RANGED : return "Ranged";
  537. + case EQUIPMENT_SLOT_TABARD : return "Tabard";
  538. + default: return NULL;
  539. + }
  540. + }
  541. +
  542. + std::string GetItemName(uint32 entry, WorldSession* session)
  543. + {
  544. + const ItemTemplate* itemTemplate = sObjectMgr->GetItemTemplate(entry);
  545. + std::string name = itemTemplate->Name1;
  546. + int loc_idx = session->GetSessionDbLocaleIndex();
  547. + if (loc_idx >= 0)
  548. + if (ItemLocale const* il = sObjectMgr->GetItemLocale(itemTemplate->ItemId))
  549. + sObjectMgr->GetLocaleString(il->Name, loc_idx, name);
  550. + return name;
  551. + }
  552. +
  553. + bool IsReforgable(Item* invItem, Player* player)
  554. + {
  555. + if(invItem->IsEquipped() && invItem->GetOwnerGUID() == player->GetGUID())
  556. + {
  557. + if(sObjectMgr->_itemFakeStatStore.find(invItem->GetGUIDLow()) != sObjectMgr->_itemFakeStatStore.end())
  558. + if(sObjectMgr->_itemFakeStatStore[invItem->GetGUIDLow()].size() >= maxReforges)
  559. + return false;
  560. + const ItemTemplate* proto = invItem->GetTemplate();
  561. + // block heirlooms necessary? probably. (their stats are handled differently)
  562. + if(proto->Quality != ITEM_QUALITY_HEIRLOOM && proto->StatsCount > 0)
  563. + {
  564. + for (uint32 i = 0; i < proto->StatsCount; ++i)
  565. + {
  566. + if(stat_types.find(proto->ItemStat[i].ItemStatType) == stat_types.end())
  567. + continue;
  568. + if(proto->ItemStat[i].ItemStatValue == 0)
  569. + continue;
  570. + if(sObjectMgr->_itemFakeStatStore.find(invItem->GetGUIDLow()) != sObjectMgr->_itemFakeStatStore.end())
  571. + {
  572. + if(sObjectMgr->_itemFakeStatStore[invItem->GetGUIDLow()].find(i) == sObjectMgr->_itemFakeStatStore[invItem->GetGUIDLow()].end())
  573. + return true; // found a stat that is not increased yet and is accepted by the script
  574. + }
  575. + else
  576. + return true; // the item is not reforged yet and a good stat was found
  577. + }
  578. + }
  579. + }
  580. + return false;
  581. + }
  582. +
  583. + void UpdatePlayerReforgeStats(Item* invItem, Player* player, uint32 stat_count_id, uint32 token_count)
  584. + {
  585. + const ItemTemplate* proto = invItem->GetTemplate();
  586. + uint32 stat_diff = stat_types[proto->ItemStat[stat_count_id].ItemStatType].stat_base_value * token_count;
  587. + uint32 guidlow = invItem->GetGUIDLow();
  588. +
  589. + // non tradeable and refundable
  590. + invItem->SetNotRefundable(player);
  591. + invItem->SetBinding(true);
  592. +
  593. + // Update player stats
  594. + player->_ApplyItemMods(invItem, invItem->GetSlot(), false);
  595. + sObjectMgr->_itemFakeStatStore[guidlow][stat_count_id] = stat_diff; // save to container for item stats applying (used a lot)
  596. + playerItems_format temp = {invItem->GetEntry(), guidlow}; // temp var so we can insert our stuff to playerItems_format
  597. + playerItems[player->GetGUIDLow()].push_back(temp); // save entry and guid of the item so we can delete the item data on logout
  598. + player->_ApplyItemMods(invItem, invItem->GetSlot(), true);
  599. +
  600. + // save to DB
  601. + player->SaveToDB(); // save player to DB too, since if a crash comes by, he will get a free reforge and no token removing is saved.
  602. + CharacterDatabase.PExecute("REPLACE INTO `custom_reforges` (`pGUID`, `Entry`, `iGUID`, `stat_count_id`, `stat_diff`) VALUES (%u, %u, %u, %u, %i)", player->GetGUIDLow(), invItem->GetEntry(), guidlow, stat_count_id, stat_diff);
  603. +
  604. + SendReforgePackets(player);
  605. + }
  606. +};
  607. +
  608. +void AddSC_REFORGER_NPC()
  609. +{
  610. + new REFORGER_NPC;
  611. + new REFORGING_DATA_HANDLER;
  612. +}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement