[0169] Implemented vendors selling currencies.

Also fix crash from recent master merge.

Signed-off-by: Yaki Khadafi <ElSolDolLo@gmail.com>
This commit is contained in:
Yaki Khadafi 2012-08-24 15:09:34 +03:00 committed by Antz
parent d4af997fbd
commit 6dd0ba1d14
23 changed files with 550 additions and 194 deletions

View file

@ -3406,8 +3406,8 @@ INSERT INTO `mangos_string` VALUES
(206,'Item \'%i\' \'%s\' added to list with maxcount \'%i\' and incrtime \'%i\' and extendedcost \'%i\'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (206,'Item \'%i\' \'%s\' added to list with maxcount \'%i\' and incrtime \'%i\' and extendedcost \'%i\'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(207,'Item \'%i\' not found in database.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (207,'Item \'%i\' not found in database.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(208,'Item \'%i\' \'%s\' deleted from vendor list',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (208,'Item \'%i\' \'%s\' deleted from vendor list',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(209,'Item \'%i\' not found in vendor list.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (209,'Item \'%i\' (isCurrency: %u) not found in vendor list.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(210,'Item \'%i\' (with extended cost %i) already in vendor list.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (210,'Item \'%i\' (isCurrency: %u, with extended cost %i) already in vendor list.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(211,'Spells of %s reset.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (211,'Spells of %s reset.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(212,'Spells of %s will reset at next login.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (212,'Spells of %s will reset at next login.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(213,'Talents of %s reset.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (213,'Talents of %s reset.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
@ -3466,6 +3466,7 @@ INSERT INTO `mangos_string` VALUES
(266,'Nothing found!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (266,'Nothing found!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(267,'Object not found!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (267,'Object not found!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(268,'Creature not found!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (268,'Creature not found!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(269,'Currency \'%i\' not found.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(270,'Creature Removed',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (270,'Creature Removed',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(271,'Creature moved.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (271,'Creature moved.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(272,'Creature (GUID:%u) must be on the same map as player!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (272,'Creature (GUID:%u) must be on the same map as player!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
@ -3479,6 +3480,7 @@ INSERT INTO `mangos_string` VALUES
(280,'Vendor has too many items (max 128)',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (280,'Vendor has too many items (max 128)',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(281,'You can\'t kick self, logout instead',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (281,'You can\'t kick self, logout instead',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(282,'Player %s kicked.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (282,'Player %s kicked.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(283,'Meta currency \'%i\' is not allowed in vendors.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(284,'Accepting Whisper: %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (284,'Accepting Whisper: %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(285,'Accepting Whisper: ON',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (285,'Accepting Whisper: ON',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(286,'Accepting Whisper: OFF',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (286,'Accepting Whisper: OFF',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
@ -4080,6 +4082,8 @@ INSERT INTO `mangos_string` VALUES
(1506,'Current phase = %u',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (1506,'Current phase = %u',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(1507,'Combat-Movement is %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (1507,'Combat-Movement is %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(1508,'Melee attacking is %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (1508,'Melee attacking is %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(1509,'Can\'t add item %u to vendor with unknown item type %u',,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(1510,'Currency %u has maxCount = 0, but for currencies maxCount = buyCount, so it can\'t be 0 or less than that\'s currency precision (%u).',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(1600,'|cffffff00Northpass Tower has been taken by the Horde!|r',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (1600,'|cffffff00Northpass Tower has been taken by the Horde!|r',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(1601,'|cffffff00Northpass Tower has been taken by the Alliance!|r',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (1601,'|cffffff00Northpass Tower has been taken by the Alliance!|r',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(1602,'|cffffff00Crown Guard Tower has been taken by the Horde!|r',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (1602,'|cffffff00Crown Guard Tower has been taken by the Horde!|r',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
@ -4346,8 +4350,8 @@ UNLOCK TABLES;
DROP TABLE IF EXISTS `npc_vendor`; DROP TABLE IF EXISTS `npc_vendor`;
CREATE TABLE `npc_vendor` ( CREATE TABLE `npc_vendor` (
`entry` mediumint(8) unsigned NOT NULL default '0', `entry` mediumint(8) unsigned NOT NULL default '0',
`item` mediumint(8) unsigned NOT NULL default '0', `item` mediumint(8) NOT NULL default '0',
`maxcount` tinyint(3) unsigned NOT NULL default '0', `maxcount` smallint(5) unsigned NOT NULL default '0',
`incrtime` int(10) unsigned NOT NULL default '0', `incrtime` int(10) unsigned NOT NULL default '0',
`ExtendedCost` mediumint(8) unsigned NOT NULL default '0', `ExtendedCost` mediumint(8) unsigned NOT NULL default '0',
PRIMARY KEY (`entry`,`item`,`ExtendedCost`) PRIMARY KEY (`entry`,`item`,`ExtendedCost`)
@ -4369,8 +4373,8 @@ UNLOCK TABLES;
DROP TABLE IF EXISTS `npc_vendor_template`; DROP TABLE IF EXISTS `npc_vendor_template`;
CREATE TABLE `npc_vendor_template` ( CREATE TABLE `npc_vendor_template` (
`entry` mediumint(8) unsigned NOT NULL default '0', `entry` mediumint(8) unsigned NOT NULL default '0',
`item` mediumint(8) unsigned NOT NULL default '0', `item` mediumint(8) NOT NULL default '0',
`maxcount` tinyint(3) unsigned NOT NULL default '0', `maxcount` smallint(3) unsigned NOT NULL default '0',
`incrtime` int(10) unsigned NOT NULL default '0', `incrtime` int(10) unsigned NOT NULL default '0',
`ExtendedCost` mediumint(8) unsigned NOT NULL default '0', `ExtendedCost` mediumint(8) unsigned NOT NULL default '0',
PRIMARY KEY (`entry`,`item`,`ExtendedCost`) PRIMARY KEY (`entry`,`item`,`ExtendedCost`)

View file

@ -0,0 +1,4 @@
ALTER TABLE db_version CHANGE COLUMN required_0168_xxxxx_01_mangos_playercreateinfo_spell required_0169_xxxxx_01_mangos_npc_vendor bit;
ALTER TABLE `npc_vendor` MODIFY COLUMN `item` mediumint(8) NOT NULL DEFAULT '0';
ALTER TABLE `npc_vendor` MODIFY COLUMN `maxcount` smallint(5) unsigned NOT NULL default '0';

View file

@ -0,0 +1,4 @@
ALTER TABLE db_version CHANGE COLUMN required_0169_xxxxx_01_mangos_npc_vendor required_0169_xxxxx_02_mangos_npc_vendor_template bit;
ALTER TABLE `npc_vendor_template` MODIFY COLUMN `item` mediumint(8) NOT NULL DEFAULT '0';
ALTER TABLE `npc_vendor_template` MODIFY COLUMN `maxcount` smallint(5) unsigned NOT NULL default '0';

View file

@ -0,0 +1,9 @@
ALTER TABLE db_version CHANGE COLUMN required_0169_xxxxx_02_mangos_npc_vendor_template required_0169_xxxxx_03_mangos_mangos_string bit;
REPLACE INTO `mangos_string` (`entry`, `content_default`) VALUES
(209, 'Item \'%i\' (isCurrency: %u) not found in vendor list.'),
(210, 'Item \'%i\' (isCurrency: %u, with extended cost %i) already in vendor list.'),
(269, 'Currency \'%i\' not found.'),
(283, 'Meta currency \'%i\' is not allowed in vendors.'),
(1509, 'Can\'t add item %u to vendor with unknown item type %u'),
(1510, 'Currency %u has maxCount = 0, but for currencies maxCount = buyCount, so it can\'t be 0 or less than that\'s currency precision (%u).');

View file

@ -0,0 +1,6 @@
ALTER TABLE db_version CHANGE COLUMN required_0169_xxxxx_03_mangos_mangos_string required_0169_xxxxx_04_mangos_command bit;
DELETE FROM `command` WHERE `name` IN ('npc addcurrency', 'npc delcurrency');
INSERT INTO `command` VALUES
('npc addcurrency',2,'Syntax: .npc addcurrency #currencyId #buycount #extendedcost\r\n\r\nAdd currency #currencyId to item list of selected vendor. '),
('npc delcurrency',2,'Syntax: .npc delcurrency #currencyId\r\n\r\nRemove currency #currencyId from item list of selected vendor.');

View file

@ -45,6 +45,7 @@
// |color|Hareatrigger_target:id|h[name]|h|r // |color|Hareatrigger_target:id|h[name]|h|r
// |color|Hcreature:creature_guid|h[name]|h|r // |color|Hcreature:creature_guid|h[name]|h|r
// |color|Hcreature_entry:creature_id|h[name]|h|r // |color|Hcreature_entry:creature_id|h[name]|h|r
// |color|Hcurrency:currency_id||h[name]|h|r
// |color|Henchant:recipe_spell_id|h[prof_name: recipe_name]|h|r - client, at shift click in recipes list dialog // |color|Henchant:recipe_spell_id|h[prof_name: recipe_name]|h|r - client, at shift click in recipes list dialog
// |color|Hgameevent:id|h[name]|h|r // |color|Hgameevent:id|h[name]|h|r
// |color|Hgameobject:go_guid|h[name]|h|r // |color|Hgameobject:go_guid|h[name]|h|r
@ -438,6 +439,7 @@ ChatCommand* ChatHandler::getCommandTable()
static ChatCommand npcCommandTable[] = static ChatCommand npcCommandTable[] =
{ {
{ "add", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcAddCommand, "", NULL }, { "add", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcAddCommand, "", NULL },
{ "addcurrency", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcAddVendorCurrencyCommand,"", NULL },
{ "additem", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcAddVendorItemCommand, "", NULL }, { "additem", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcAddVendorItemCommand, "", NULL },
{ "addmove", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcAddMoveCommand, "", NULL }, { "addmove", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcAddMoveCommand, "", NULL },
{ "aiinfo", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcAIInfoCommand, "", NULL }, { "aiinfo", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcAIInfoCommand, "", NULL },
@ -445,6 +447,7 @@ ChatCommand* ChatHandler::getCommandTable()
{ "changeentry", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcChangeEntryCommand, "", NULL }, { "changeentry", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcChangeEntryCommand, "", NULL },
{ "changelevel", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcChangeLevelCommand, "", NULL }, { "changelevel", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcChangeLevelCommand, "", NULL },
{ "delete", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcDeleteCommand, "", NULL }, { "delete", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcDeleteCommand, "", NULL },
{ "delcurrency", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcDelVendorCurrencyCommand,"", NULL },
{ "delitem", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcDelVendorItemCommand, "", NULL }, { "delitem", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcDelVendorItemCommand, "", NULL },
{ "factionid", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcFactionIdCommand, "", NULL }, { "factionid", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcFactionIdCommand, "", NULL },
{ "flag", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcFlagCommand, "", NULL }, { "flag", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcFlagCommand, "", NULL },
@ -1447,6 +1450,7 @@ bool ChatHandler::isValidChatMessage(const char* message)
/* /*
valid examples: valid examples:
|cff00aa00|Hcurrency:391|h[Ðåêîìåíäàòåëüíûé çíà÷îê Òîë Áàðàäà]|h|r
|cffa335ee|Hitem:812:0:0:0:0:0:0:0:70|h[Glowing Brightwood Staff]|h|r |cffa335ee|Hitem:812:0:0:0:0:0:0:0:70|h[Glowing Brightwood Staff]|h|r
|cff808080|Hquest:2278:47|h[The Platinum Discs]|h|r |cff808080|Hquest:2278:47|h[The Platinum Discs]|h|r
|cffffd000|Htrade:4037:1:150:1:6AAAAAAAAAAAAAAAAAAAAAAOAADAAAAAAAAAAAAAAAAIAAAAAAAAA|h[Engineering]|h|r |cffffd000|Htrade:4037:1:150:1:6AAAAAAAAAAAAAAAAAAAAAAOAADAAAAAAAAAAAAAAAAIAAAAAAAAA|h[Engineering]|h|r
@ -1506,6 +1510,7 @@ bool ChatHandler::isValidChatMessage(const char* message)
uint32 color = 0; uint32 color = 0;
CurrencyTypesEntry const* linkedCurrency = NULL;
ItemPrototype const* linkedItem = NULL; ItemPrototype const* linkedItem = NULL;
Quest const* linkedQuest = NULL; Quest const* linkedQuest = NULL;
SpellEntry const* linkedSpell = NULL; SpellEntry const* linkedSpell = NULL;
@ -1517,6 +1522,7 @@ bool ChatHandler::isValidChatMessage(const char* message)
{ {
if (validSequence == validSequenceIterator) if (validSequence == validSequenceIterator)
{ {
linkedCurrency = NULL;
linkedItem = NULL; linkedItem = NULL;
linkedQuest = NULL; linkedQuest = NULL;
linkedSpell = NULL; linkedSpell = NULL;
@ -1606,7 +1612,26 @@ bool ChatHandler::isValidChatMessage(const char* message)
if (reader.eof()) // : must be if (reader.eof()) // : must be
return false; return false;
if (strcmp(buffer, "item") == 0) if (strcmp(buffer, "currency") == 0)
{
if (color != CHAT_LINK_COLOR_CURRENCY)
return false;
uint32 currencyEntry = 0;
// read currency entry
char c = reader.peek();
while (c >= '0' && c <= '9')
{
reader.ignore(1);
currencyEntry *= 10;
currencyEntry += c - '0';
c = reader.peek();
}
linkedCurrency = sCurrencyTypesStore.LookupEntry(currencyEntry);
if (!linkedCurrency)
return false;
}
else if (strcmp(buffer, "item") == 0)
{ {
// read item entry // read item entry
reader.getline(buffer, 256, ':'); reader.getline(buffer, 256, ':');
@ -1886,7 +1911,24 @@ bool ChatHandler::isValidChatMessage(const char* message)
return false; return false;
// verify the link name // verify the link name
if (linkedSpell) if (linkedCurrency)
{
if (linkedCurrency->ID == CURRENCY_CONQUEST_ARENA_META || linkedCurrency->ID == CURRENCY_CONQUEST_BG_META)
return false;
bool foundName = false;
for (uint8 i = 0; i < MAX_LOCALE; ++i)
{
if (*linkedCurrency->name[i] && strcmp(linkedCurrency->name[i], buffer) == 0)
{
foundName = true;
break;
}
}
if (!foundName)
return false;
}
else if (linkedSpell)
{ {
// spells with that flag have a prefix of "$PROFESSION: " // spells with that flag have a prefix of "$PROFESSION: "
if (linkedSpell->HasAttribute(SPELL_ATTR_TRADESPELL)) if (linkedSpell->HasAttribute(SPELL_ATTR_TRADESPELL))

View file

@ -339,12 +339,14 @@ class MANGOS_DLL_SPEC ChatHandler
//-----------------------Npc Commands----------------------- //-----------------------Npc Commands-----------------------
bool HandleNpcAddCommand(char* args); bool HandleNpcAddCommand(char* args);
bool HandleNpcAddMoveCommand(char* args); bool HandleNpcAddMoveCommand(char* args);
bool HandleNpcAddVendorCurrencyCommand(char* args);
bool HandleNpcAddVendorItemCommand(char* args); bool HandleNpcAddVendorItemCommand(char* args);
bool HandleNpcAIInfoCommand(char* args); bool HandleNpcAIInfoCommand(char* args);
bool HandleNpcAllowMovementCommand(char* args); bool HandleNpcAllowMovementCommand(char* args);
bool HandleNpcChangeEntryCommand(char* args); bool HandleNpcChangeEntryCommand(char* args);
bool HandleNpcChangeLevelCommand(char* args); bool HandleNpcChangeLevelCommand(char* args);
bool HandleNpcDeleteCommand(char* args); bool HandleNpcDeleteCommand(char* args);
bool HandleNpcDelVendorCurrencyCommand(char* args);
bool HandleNpcDelVendorItemCommand(char* args); bool HandleNpcDelVendorItemCommand(char* args);
bool HandleNpcFactionIdCommand(char* args); bool HandleNpcFactionIdCommand(char* args);
bool HandleNpcFlagCommand(char* args); bool HandleNpcFlagCommand(char* args);

View file

@ -67,13 +67,13 @@ TrainerSpell const* TrainerSpellData::Find(uint32 spell_id) const
return NULL; return NULL;
} }
bool VendorItemData::RemoveItem(uint32 item_id) bool VendorItemData::RemoveItem(uint32 item_id, uint8 type)
{ {
bool found = false; bool found = false;
for (VendorItemList::iterator i = m_items.begin(); i != m_items.end();) for (VendorItemList::iterator i = m_items.begin(); i != m_items.end();)
{ {
// can have many examples // can have many examples
if ((*i)->item == item_id) if ((*i)->item == item_id && (*i)->type == type)
{ {
i = m_items.erase(i); i = m_items.erase(i);
found = true; found = true;
@ -85,10 +85,10 @@ bool VendorItemData::RemoveItem(uint32 item_id)
return found; return found;
} }
VendorItem const* VendorItemData::FindItemCostPair(uint32 item_id, uint32 extendedCost) const VendorItem const* VendorItemData::FindItemCostPair(uint32 item_id, uint8 type, uint32 extendedCost) const
{ {
for (VendorItemList::const_iterator i = m_items.begin(); i != m_items.end(); ++i) for (VendorItemList::const_iterator i = m_items.begin(); i != m_items.end(); ++i)
if ((*i)->item == item_id && (*i)->ExtendedCost == extendedCost) if ((*i)->item == item_id && (*i)->ExtendedCost == extendedCost && (*i)->type == type)
return *i; return *i;
return NULL; return NULL;
} }
@ -2544,6 +2544,8 @@ void Creature::SetWalk(bool enable)
else else
m_movementInfo.RemoveMovementFlag(MOVEFLAG_WALK_MODE); m_movementInfo.RemoveMovementFlag(MOVEFLAG_WALK_MODE);
if (IsInWorld())
{
WorldPacket data(enable ? SMSG_SPLINE_MOVE_SET_WALK_MODE : SMSG_SPLINE_MOVE_SET_RUN_MODE, 9); WorldPacket data(enable ? SMSG_SPLINE_MOVE_SET_WALK_MODE : SMSG_SPLINE_MOVE_SET_RUN_MODE, 9);
if (enable) if (enable)
{ {
@ -2558,6 +2560,7 @@ void Creature::SetWalk(bool enable)
SendMessageToSet(&data, true); SendMessageToSet(&data, true);
} }
}
void Creature::SetLevitate(bool enable) void Creature::SetLevitate(bool enable)
{ {
@ -2566,6 +2569,8 @@ void Creature::SetLevitate(bool enable)
else else
m_movementInfo.RemoveMovementFlag(MOVEFLAG_LEVITATING); m_movementInfo.RemoveMovementFlag(MOVEFLAG_LEVITATING);
if (IsInWorld())
{
WorldPacket data(enable ? SMSG_SPLINE_MOVE_GRAVITY_DISABLE : SMSG_SPLINE_MOVE_GRAVITY_ENABLE, 9); WorldPacket data(enable ? SMSG_SPLINE_MOVE_GRAVITY_DISABLE : SMSG_SPLINE_MOVE_GRAVITY_ENABLE, 9);
if (enable) if (enable)
{ {
@ -2580,6 +2585,7 @@ void Creature::SetLevitate(bool enable)
SendMessageToSet(&data, true); SendMessageToSet(&data, true);
} }
}
void Creature::SetRoot(bool enable) void Creature::SetRoot(bool enable)
{ {
@ -2588,6 +2594,8 @@ void Creature::SetRoot(bool enable)
else else
m_movementInfo.RemoveMovementFlag(MOVEFLAG_ROOT); m_movementInfo.RemoveMovementFlag(MOVEFLAG_ROOT);
if (IsInWorld())
{
WorldPacket data(enable ? SMSG_SPLINE_MOVE_ROOT : SMSG_SPLINE_MOVE_UNROOT, 9); WorldPacket data(enable ? SMSG_SPLINE_MOVE_ROOT : SMSG_SPLINE_MOVE_UNROOT, 9);
if (enable) if (enable)
{ {
@ -2602,6 +2610,7 @@ void Creature::SetRoot(bool enable)
SendMessageToSet(&data, true); SendMessageToSet(&data, true);
} }
}
void Creature::SetWaterWalk(bool enable) void Creature::SetWaterWalk(bool enable)
{ {
@ -2610,6 +2619,8 @@ void Creature::SetWaterWalk(bool enable)
else else
m_movementInfo.RemoveMovementFlag(MOVEFLAG_WATERWALKING); m_movementInfo.RemoveMovementFlag(MOVEFLAG_WATERWALKING);
if (IsInWorld())
{
WorldPacket data(enable ? SMSG_SPLINE_MOVE_WATER_WALK : SMSG_SPLINE_MOVE_LAND_WALK, 9); WorldPacket data(enable ? SMSG_SPLINE_MOVE_WATER_WALK : SMSG_SPLINE_MOVE_LAND_WALK, 9);
if (enable) if (enable)
{ {
@ -2624,4 +2635,4 @@ void Creature::SetWaterWalk(bool enable)
SendMessageToSet(&data, true); SendMessageToSet(&data, true);
} }
}

View file

@ -310,15 +310,27 @@ enum SelectFlags
}; };
// Vendors // Vendors
enum
{
VENDOR_ITEM_TYPE_NONE = 0,
VENDOR_ITEM_TYPE_ITEM = 1,
VENDOR_ITEM_TYPE_CURRENCY = 2,
VENDOR_ITEM_TYPE_MAX = 3,
};
struct VendorItem struct VendorItem
{ {
VendorItem(uint32 _item, uint32 _maxcount, uint32 _incrtime, uint32 _ExtendedCost) VendorItem(uint32 _item, uint8 _type, uint32 _maxcount, uint32 _incrtime, uint32 _ExtendedCost)
: item(_item), maxcount(_maxcount), incrtime(_incrtime), ExtendedCost(_ExtendedCost) {} : item(_item), type(_type), maxcount(_maxcount), incrtime(_incrtime), ExtendedCost(_ExtendedCost) {}
uint32 item; uint32 item;
uint32 maxcount; // 0 for infinity item amount uint8 type;
uint32 maxcount; // 0 for infinity item amount, for type = VENDOR_ITEM_TYPE_CURRENCY, maxcount = currency count
uint32 incrtime; // time for restore items amount if maxcount != 0 uint32 incrtime; // time for restore items amount if maxcount != 0
uint32 ExtendedCost; // index in ItemExtendedCost.dbc uint32 ExtendedCost; // index in ItemExtendedCost.dbc
bool IsCurrency() const { return type == VENDOR_ITEM_TYPE_CURRENCY; }
}; };
typedef std::vector<VendorItem*> VendorItemList; typedef std::vector<VendorItem*> VendorItemList;
@ -333,12 +345,12 @@ struct VendorItemData
} }
bool Empty() const { return m_items.empty(); } bool Empty() const { return m_items.empty(); }
uint8 GetItemCount() const { return m_items.size(); } uint8 GetItemCount() const { return m_items.size(); }
void AddItem(uint32 item, uint32 maxcount, uint32 ptime, uint32 ExtendedCost) void AddItem(uint32 item, uint8 type, uint32 maxcount, uint32 ptime, uint32 ExtendedCost)
{ {
m_items.push_back(new VendorItem(item, maxcount, ptime, ExtendedCost)); m_items.push_back(new VendorItem(item, type, maxcount, ptime, ExtendedCost));
} }
bool RemoveItem(uint32 item_id); bool RemoveItem(uint32 item_id, uint8 type);
VendorItem const* FindItemCostPair(uint32 item_id, uint32 extendedCost) const; VendorItem const* FindItemCostPair(uint32 item_id, uint8 type, uint32 extendedCost) const;
void Clear() void Clear()
{ {

View file

@ -386,6 +386,17 @@ enum CurrencyFlags
CURRENCY_FLAG_HAS_SEASON_COUNT = 0x80, // guessed CURRENCY_FLAG_HAS_SEASON_COUNT = 0x80, // guessed
}; };
enum Currencies
{
CURRENCY_NONE = 0,
CURRENCY_CONQUEST_POINTS = 390,
CURRENCY_HONOR_POINTS = 392,
CURRENCY_JUSTICE_POINTS = 395,
CURRENCY_VALOR_POINTS = 396,
CURRENCY_CONQUEST_ARENA_META = 483,
CURRENCY_CONQUEST_BG_META = 484,
};
enum ItemEnchantmentType enum ItemEnchantmentType
{ {
ITEM_ENCHANTMENT_TYPE_NONE = 0, ITEM_ENCHANTMENT_TYPE_NONE = 0,

View file

@ -811,7 +811,7 @@ struct CurrencyTypesEntry
{ {
uint32 ID; // 0 uint32 ID; // 0
//uint32 Category; // 1 //uint32 Category; // 1
//char* name; // 2 DBCString name; // 2
//char* iconName; // 3 //char* iconName; // 3
//uint32 unk4; // 4 //uint32 unk4; // 4
//uint32 unk5; // 5 //uint32 unk5; // 5
@ -819,7 +819,7 @@ struct CurrencyTypesEntry
uint32 TotalCount; // 7 uint32 TotalCount; // 7
uint32 WeekCount; // 8 uint32 WeekCount; // 8
uint32 Flags; // 9 uint32 Flags; // 9
//char* description; // 10 //DBCString description; // 10
bool HasPrecision() const { return Flags & CURRENCY_FLAG_HAS_PRECISION; } bool HasPrecision() const { return Flags & CURRENCY_FLAG_HAS_PRECISION; }
bool HasSeasonCount() const { return Flags & CURRENCY_FLAG_HAS_SEASON_COUNT; } bool HasSeasonCount() const { return Flags & CURRENCY_FLAG_HAS_SEASON_COUNT; }

View file

@ -43,7 +43,7 @@ const char CreatureFamilyfmt[]="nfifiiiiixsx";
const char CreatureSpellDatafmt[]="niiiixxxx"; const char CreatureSpellDatafmt[]="niiiixxxx";
const char DungeonEncounterfmt[]="niiiisxx"; const char DungeonEncounterfmt[]="niiiisxx";
const char CreatureTypefmt[]="nxx"; const char CreatureTypefmt[]="nxx";
const char CurrencyTypesfmt[]="nxxxxxxiiix"; const char CurrencyTypesfmt[]="nxsxxxxiiix";
const char DurabilityCostsfmt[]="niiiiiiiiiiiiiiiiiiiiiiiiiiiii"; const char DurabilityCostsfmt[]="niiiiiiiiiiiiiiiiiiiiiiiiiiiii";
const char DurabilityQualityfmt[]="nf"; const char DurabilityQualityfmt[]="nf";
const char EmotesEntryfmt[]="nxxiiixx"; const char EmotesEntryfmt[]="nxxiiixx";

View file

@ -483,15 +483,15 @@ void WorldSession::HandleBuybackItem(WorldPacket& recv_data)
_player->SendBuyError(BUY_ERR_CANT_FIND_ITEM, pCreature, 0, 0); _player->SendBuyError(BUY_ERR_CANT_FIND_ITEM, pCreature, 0, 0);
} }
void WorldSession::HandleBuyItemInSlotOpcode(WorldPacket& recv_data) void WorldSession::HandleBuyItemOpcode(WorldPacket& recv_data)
{ {
DEBUG_LOG("WORLD: Received CMSG_BUY_ITEM_IN_SLOT"); ObjectGuid vendorGuid, bagGuid;
ObjectGuid vendorGuid;
ObjectGuid bagGuid;
uint32 item, slot, count; uint32 item, slot, count;
uint8 bagslot; uint8 type, bagSlot;
recv_data >> vendorGuid >> item >> slot >> bagGuid >> bagslot >> count; recv_data >> vendorGuid >> type >> item >> slot >> count >> bagGuid >> bagSlot;
DEBUG_LOG("WORLD: Received CMSG_BUY_ITEM, vendorguid: %s, type: %u, item: %u, slot: %u, count: %u, bagGuid: %s, bagSlog: %u",
vendorGuid.GetString().c_str(), type, item, slot, count, bagGuid.GetString().c_str(), bagSlot);
// client side expected counting from 1, and we send to client vendorslot+1 already // client side expected counting from 1, and we send to client vendorslot+1 already
if (slot > 0) if (slot > 0)
@ -499,6 +499,12 @@ void WorldSession::HandleBuyItemInSlotOpcode(WorldPacket& recv_data)
else else
return; // cheating return; // cheating
switch(type)
{
case VENDOR_ITEM_TYPE_NONE:
break;
case VENDOR_ITEM_TYPE_ITEM:
{
uint8 bag = NULL_BAG; // init for case invalid bagGUID uint8 bag = NULL_BAG; // init for case invalid bagGUID
// find bag slot by bag guid // find bag slot by bag guid
@ -519,29 +525,15 @@ void WorldSession::HandleBuyItemInSlotOpcode(WorldPacket& recv_data)
} }
} }
// bag not found, cheating? GetPlayer()->BuyItemFromVendorSlot(vendorGuid, slot, item, count, bag, bagSlot);
if (bag == NULL_BAG) break;
return;
GetPlayer()->BuyItemFromVendorSlot(vendorGuid, slot, item, count, bag, bagslot);
} }
case VENDOR_ITEM_TYPE_CURRENCY:
void WorldSession::HandleBuyItemOpcode(WorldPacket& recv_data)
{ {
DEBUG_LOG("WORLD: Received CMSG_BUY_ITEM"); GetPlayer()->BuyCurrencyFromVendorSlot(vendorGuid, slot, item, count);
ObjectGuid vendorGuid, otherGuid; break;
uint32 item, slot, count; }
uint8 unk1, unk2; }
recv_data >> vendorGuid >> unk1 >> item >> slot >> count >> otherGuid >> unk2;
// client side expected counting from 1, and we send to client vendorslot+1 already
if (slot > 0)
--slot;
else
return; // cheating
GetPlayer()->BuyItemFromVendorSlot(vendorGuid, slot, item, count, NULL_BAG, NULL_SLOT);
} }
void WorldSession::HandleListInventoryOpcode(WorldPacket& recv_data) void WorldSession::HandleListInventoryOpcode(WorldPacket& recv_data)
@ -597,10 +589,15 @@ void WorldSession::SendListInventory(ObjectGuid vendorguid)
if (crItem) if (crItem)
{ {
uint32 itemId = crItem->item; uint32 price, displayId, buyCount, maxDurability;
ItemPrototype const* pProto = ObjectMgr::GetItemPrototype(itemId); int32 maxCount;
if (pProto)
if (crItem->type == VENDOR_ITEM_TYPE_ITEM)
{ {
ItemPrototype const * pProto = ObjectMgr::GetItemPrototype(crItem->item);
if (!pProto)
continue;
if (!_player->isGameMaster()) if (!_player->isGameMaster())
{ {
// class wrong item skip only for bindable case // class wrong item skip only for bindable case
@ -625,35 +622,60 @@ void WorldSession::SendListInventory(ObjectGuid vendorguid)
if (pProto->RequiredReputationFaction && uint32(_player->GetReputationRank(pProto->RequiredReputationFaction)) >= pProto->RequiredReputationRank) if (pProto->RequiredReputationFaction && uint32(_player->GetReputationRank(pProto->RequiredReputationFaction)) >= pProto->RequiredReputationRank)
{ {
// checked at convert data loading as existed // checked at convert data loading as existed
if (uint32 newItemId = sObjectMgr.GetItemConvert(itemId, _player->getRaceMask())) if (uint32 newItemId = sObjectMgr.GetItemConvert(crItem->item, _player->getRaceMask()))
pProto = ObjectMgr::GetItemPrototype(newItemId); pProto = ObjectMgr::GetItemPrototype(newItemId);
} }
} }
++count; ++count;
if (count >= MAX_VENDOR_ITEMS) if (count >= MAX_VENDOR_ITEMS)
break; break;
// reputation discount
maxDurability = pProto->MaxDurability;
price = (crItem->ExtendedCost == 0 || pProto->Flags2 & ITEM_FLAG2_EXT_COST_REQUIRES_GOLD) ? uint32(floor(pProto->BuyPrice * discountMod)) : 0;
displayId = pProto->DisplayInfoID;
maxCount = crItem->maxcount <= 0 ? -1 : int32(pCreature->GetVendorItemCurrentCount(crItem));
buyCount = pProto->BuyCount;
}
else if (crItem->type == VENDOR_ITEM_TYPE_CURRENCY)
{
CurrencyTypesEntry const * pCurrency = sCurrencyTypesStore.LookupEntry(crItem->item);
if (!pCurrency)
continue;
if (pCurrency->ID == CURRENCY_CONQUEST_ARENA_META || pCurrency->ID == CURRENCY_CONQUEST_BG_META)
continue;
++count;
if (count >= MAX_VENDOR_ITEMS)
break;
maxDurability = 0;
price = 0;
displayId = 0;
maxCount = -1;
buyCount = crItem->maxcount;
}
else
continue;
bitFlags.push_back(crItem->ExtendedCost == 0); bitFlags.push_back(crItem->ExtendedCost == 0);
bitFlags.push_back(true); // unk bitFlags.push_back(true); // unk
// reputation discount
uint32 price = (crItem->ExtendedCost == 0 || pProto->Flags2 & ITEM_FLAG2_EXT_COST_REQUIRES_GOLD) ? uint32(floor(pProto->BuyPrice * discountMod)) : 0;
buffer << uint32(vendorslot + 1); // client size expected counting from 1 buffer << uint32(vendorslot + 1); // client size expected counting from 1
buffer << uint32(pProto->MaxDurability); buffer << uint32(maxDurability);
if (crItem->ExtendedCost) if (crItem->ExtendedCost)
buffer << uint32(crItem->ExtendedCost); buffer << uint32(crItem->ExtendedCost);
buffer << uint32(itemId); buffer << uint32(crItem->item);
buffer << uint32(1); // type == item buffer << uint32(crItem->type);
buffer << uint32(price); buffer << uint32(price);
buffer << uint32(pProto->DisplayInfoID); buffer << uint32(displayId);
buffer << uint32(crItem->maxcount <= 0 ? 0xFFFFFFFF : pCreature->GetVendorItemCurrentCount(crItem)); buffer << int32(maxCount);
buffer << uint32(pProto->BuyCount); buffer << uint32(buyCount);
}
} }
} }

View file

@ -257,7 +257,7 @@ enum MangosStrings
LANG_COMMAND_TARGETOBJNOTFOUND = 266, LANG_COMMAND_TARGETOBJNOTFOUND = 266,
LANG_COMMAND_GOOBJNOTFOUND = 267, LANG_COMMAND_GOOBJNOTFOUND = 267,
LANG_COMMAND_GOCREATNOTFOUND = 268, LANG_COMMAND_GOCREATNOTFOUND = 268,
// 269, not used LANG_CURRENCY_NOT_FOUND = 269,
LANG_COMMAND_DELCREATMESSAGE = 270, LANG_COMMAND_DELCREATMESSAGE = 270,
LANG_COMMAND_CREATUREMOVED = 271, LANG_COMMAND_CREATUREMOVED = 271,
LANG_COMMAND_CREATUREATSAMEMAP = 272, LANG_COMMAND_CREATUREATSAMEMAP = 272,
@ -271,7 +271,7 @@ enum MangosStrings
LANG_COMMAND_ADDVENDORITEMITEMS = 280, LANG_COMMAND_ADDVENDORITEMITEMS = 280,
LANG_COMMAND_KICKSELF = 281, LANG_COMMAND_KICKSELF = 281,
LANG_COMMAND_KICKMESSAGE = 282, LANG_COMMAND_KICKMESSAGE = 282,
// 283, not used LANG_VENDOR_META_CURRENCY_NOT_ALLOWED = 283,
LANG_COMMAND_WHISPERACCEPTING = 284, LANG_COMMAND_WHISPERACCEPTING = 284,
LANG_COMMAND_WHISPERON = 285, LANG_COMMAND_WHISPERON = 285,
LANG_COMMAND_WHISPEROFF = 286, LANG_COMMAND_WHISPEROFF = 286,
@ -965,6 +965,8 @@ enum MangosStrings
LANG_NPC_EVENTAI_PHASE = 1506, LANG_NPC_EVENTAI_PHASE = 1506,
LANG_NPC_EVENTAI_MOVE = 1507, LANG_NPC_EVENTAI_MOVE = 1507,
LANG_NPC_EVENTAI_COMBAT = 1508, LANG_NPC_EVENTAI_COMBAT = 1508,
LANG_VENDOR_WRONG_ITEM_TYPE = 1509,
LANG_VENDOR_WRONG_CURRENCY_MAXCOUNT = 1510,
// Room for more Level 2 1509-1599 not used // Room for more Level 2 1509-1599 not used
// Outdoor PvP // Outdoor PvP

View file

@ -1600,6 +1600,43 @@ bool ChatHandler::HandleNpcAddCommand(char* args)
return true; return true;
} }
// add currency in vendorlist
bool ChatHandler::HandleNpcAddVendorCurrencyCommand(char* args)
{
uint32 currencyId;
if (!ExtractUint32KeyFromLink(&args, "Hcurrency", currencyId))
{
SendSysMessage(LANG_COMMAND_NEEDITEMSEND);
SetSentErrorMessage(true);
return false;
}
uint32 maxcount;
if (!ExtractUInt32(&args, maxcount))
return false;
uint32 extendedcost;
if (!ExtractUInt32(&args, extendedcost))
return false;
Creature* vendor = getSelectedCreature();
uint32 vendor_entry = vendor ? vendor->GetEntry() : 0;
if (!sObjectMgr.IsVendorItemValid(false, "npc_vendor", vendor_entry, currencyId, VENDOR_ITEM_TYPE_CURRENCY, maxcount, 0, extendedcost, m_session->GetPlayer()))
{
SetSentErrorMessage(true);
return false;
}
sObjectMgr.AddVendorItem(vendor_entry, currencyId, VENDOR_ITEM_TYPE_CURRENCY, maxcount, 0, extendedcost);
std::string name = sCurrencyTypesStore.LookupEntry(currencyId)->name[0];
PSendSysMessage(LANG_ITEM_ADDED_TO_LIST, currencyId, name.c_str(), maxcount, 0, extendedcost);
return true;
}
// add item in vendorlist // add item in vendorlist
bool ChatHandler::HandleNpcAddVendorItemCommand(char* args) bool ChatHandler::HandleNpcAddVendorItemCommand(char* args)
{ {
@ -1627,17 +1664,52 @@ bool ChatHandler::HandleNpcAddVendorItemCommand(char* args)
uint32 vendor_entry = vendor ? vendor->GetEntry() : 0; uint32 vendor_entry = vendor ? vendor->GetEntry() : 0;
if (!sObjectMgr.IsVendorItemValid(false, "npc_vendor", vendor_entry, itemId, maxcount, incrtime, extendedcost, m_session->GetPlayer())) if (!sObjectMgr.IsVendorItemValid(false, "npc_vendor", vendor_entry, itemId, VENDOR_ITEM_TYPE_ITEM, maxcount, incrtime, extendedcost, m_session->GetPlayer()))
{ {
SetSentErrorMessage(true); SetSentErrorMessage(true);
return false; return false;
} }
sObjectMgr.AddVendorItem(vendor_entry, itemId, maxcount, incrtime, extendedcost); sObjectMgr.AddVendorItem(vendor_entry, itemId, VENDOR_ITEM_TYPE_ITEM, maxcount, incrtime, extendedcost);
ItemPrototype const* pProto = ObjectMgr::GetItemPrototype(itemId); std::string name = ObjectMgr::GetItemPrototype(itemId)->Name1;
PSendSysMessage(LANG_ITEM_ADDED_TO_LIST, itemId, pProto->Name1, maxcount, incrtime, extendedcost); PSendSysMessage(LANG_ITEM_ADDED_TO_LIST, itemId, name.c_str(), maxcount, incrtime, extendedcost);
return true;
}
// del currency from vendor list
bool ChatHandler::HandleNpcDelVendorCurrencyCommand(char* args)
{
if (!*args)
return false;
Creature* vendor = getSelectedCreature();
if (!vendor || !vendor->isVendor())
{
SendSysMessage(LANG_COMMAND_VENDORSELECTION);
SetSentErrorMessage(true);
return false;
}
uint32 itemId;
if (!ExtractUint32KeyFromLink(&args, "Hcurrency", itemId))
{
SendSysMessage(LANG_COMMAND_NEEDITEMSEND);
SetSentErrorMessage(true);
return false;
}
if (!sObjectMgr.RemoveVendorItem(vendor->GetEntry(), itemId, VENDOR_ITEM_TYPE_CURRENCY))
{
PSendSysMessage(LANG_ITEM_NOT_IN_LIST, itemId, true);
SetSentErrorMessage(true);
return false;
}
std::string name = sCurrencyTypesStore.LookupEntry(itemId)->name[0];
PSendSysMessage(LANG_ITEM_DELETED_FROM_LIST, itemId, name.c_str());
return true; return true;
} }
@ -1663,16 +1735,16 @@ bool ChatHandler::HandleNpcDelVendorItemCommand(char* args)
return false; return false;
} }
if (!sObjectMgr.RemoveVendorItem(vendor->GetEntry(), itemId)) if (!sObjectMgr.RemoveVendorItem(vendor->GetEntry(), itemId, VENDOR_ITEM_TYPE_ITEM))
{ {
PSendSysMessage(LANG_ITEM_NOT_IN_LIST, itemId); PSendSysMessage(LANG_ITEM_NOT_IN_LIST, itemId, false);
SetSentErrorMessage(true); SetSentErrorMessage(true);
return false; return false;
} }
ItemPrototype const* pProto = ObjectMgr::GetItemPrototype(itemId); std::string name = ObjectMgr::GetItemPrototype(itemId)->Name1;
PSendSysMessage(LANG_ITEM_DELETED_FROM_LIST, itemId, pProto->Name1); PSendSysMessage(LANG_ITEM_DELETED_FROM_LIST, itemId, name.c_str());
return true; return true;
} }

View file

@ -8746,17 +8746,18 @@ void ObjectMgr::LoadVendors(char const* tableName, bool isTemplates)
Field* fields = result->Fetch(); Field* fields = result->Fetch();
uint32 entry = fields[0].GetUInt32(); uint32 entry = fields[0].GetUInt32();
uint32 item_id = fields[1].GetUInt32(); uint32 item_id = abs(fields[1].GetInt32());
uint8 type = fields[1].GetInt32() > 0 ? VENDOR_ITEM_TYPE_ITEM : VENDOR_ITEM_TYPE_CURRENCY;
uint32 maxcount = fields[2].GetUInt32(); uint32 maxcount = fields[2].GetUInt32();
uint32 incrtime = fields[3].GetUInt32(); uint32 incrtime = fields[3].GetUInt32();
uint32 ExtendedCost = fields[4].GetUInt32(); uint32 ExtendedCost = fields[4].GetUInt32();
if (!IsVendorItemValid(isTemplates, tableName, entry, item_id, maxcount, incrtime, ExtendedCost, NULL, &skip_vendors)) if (!IsVendorItemValid(isTemplates, tableName, entry, item_id, type, maxcount, incrtime, ExtendedCost, NULL, &skip_vendors))
continue; continue;
VendorItemData& vList = vendorList[entry]; VendorItemData& vList = vendorList[entry];
vList.AddItem(item_id, maxcount, incrtime, ExtendedCost); vList.AddItem(item_id, type, maxcount, incrtime, ExtendedCost);
++count; ++count;
} }
@ -9183,30 +9184,31 @@ void ObjectMgr::LoadGossipMenus()
sLog.outErrorDb("Table `gossip_scripts` contains unused script, id %u.", *itr); sLog.outErrorDb("Table `gossip_scripts` contains unused script, id %u.", *itr);
} }
void ObjectMgr::AddVendorItem(uint32 entry, uint32 item, uint32 maxcount, uint32 incrtime, uint32 extendedcost) void ObjectMgr::AddVendorItem(uint32 entry, uint32 item, uint8 type, uint32 maxcount, uint32 incrtime, uint32 extendedcost)
{ {
VendorItemData& vList = m_mCacheVendorItemMap[entry]; VendorItemData& vList = m_mCacheVendorItemMap[entry];
vList.AddItem(item, maxcount, incrtime, extendedcost); vList.AddItem(item, type, maxcount, incrtime, extendedcost);
WorldDatabase.PExecuteLog("INSERT INTO npc_vendor (entry,item,maxcount,incrtime,extendedcost) VALUES('%u','%u','%u','%u','%u')", entry, item, maxcount, incrtime, extendedcost); WorldDatabase.PExecuteLog("INSERT INTO npc_vendor (entry,item,maxcount,incrtime,extendedcost) VALUES('%u','%i','%u','%u','%u')", entry, type == VENDOR_ITEM_TYPE_CURRENCY ? -int32(item) : item, maxcount, incrtime, extendedcost);
} }
bool ObjectMgr::RemoveVendorItem(uint32 entry, uint32 item) bool ObjectMgr::RemoveVendorItem(uint32 entry, uint32 item, uint8 type)
{ {
CacheVendorItemMap::iterator iter = m_mCacheVendorItemMap.find(entry); CacheVendorItemMap::iterator iter = m_mCacheVendorItemMap.find(entry);
if (iter == m_mCacheVendorItemMap.end()) if (iter == m_mCacheVendorItemMap.end())
return false; return false;
if (!iter->second.RemoveItem(item)) if (!iter->second.RemoveItem(item, type))
return false; return false;
WorldDatabase.PExecuteLog("DELETE FROM npc_vendor WHERE entry='%u' AND item='%u'", entry, item); WorldDatabase.PExecuteLog("DELETE FROM npc_vendor WHERE entry='%u' AND item='%i'", entry, type == VENDOR_ITEM_TYPE_CURRENCY ? -int32(item) : item);
return true; return true;
} }
bool ObjectMgr::IsVendorItemValid(bool isTemplate, char const* tableName, uint32 vendor_entry, uint32 item_id, uint32 maxcount, uint32 incrtime, uint32 ExtendedCost, Player* pl, std::set<uint32>* skip_vendors) const bool ObjectMgr::IsVendorItemValid(bool isTemplate, char const* tableName, uint32 vendor_entry, uint32 item_id, uint8 type, uint32 maxcount, uint32 incrtime, uint32 ExtendedCost, Player* pl, std::set<uint32>* skip_vendors) const
{ {
char const* idStr = isTemplate ? "vendor template" : "vendor"; char const* idStr = isTemplate ? "vendor template" : "vendor";
char const* nameStr = type == VENDOR_ITEM_TYPE_CURRENCY ? "Currency" : "Item";
CreatureInfo const* cInfo = NULL; CreatureInfo const* cInfo = NULL;
if (!isTemplate) if (!isTemplate)
@ -9237,33 +9239,72 @@ bool ObjectMgr::IsVendorItemValid(bool isTemplate, char const* tableName, uint32
} }
} }
CurrencyTypesEntry const * currencyEntry;
if (type == VENDOR_ITEM_TYPE_ITEM)
{
if (!GetItemPrototype(item_id)) if (!GetItemPrototype(item_id))
{ {
if (pl) if (pl)
ChatHandler(pl).PSendSysMessage(LANG_ITEM_NOT_FOUND, item_id); ChatHandler(pl).PSendSysMessage(LANG_ITEM_NOT_FOUND, item_id);
else else
sLog.outErrorDb("Table `%s` for %s %u contain nonexistent item (%u), ignoring", sLog.outErrorDb("Table `%s` for %s %u contains nonexistent item (%u), ignoring",
tableName, idStr, vendor_entry, item_id); tableName, idStr, vendor_entry, item_id);
return false; return false;
} }
}
else if (type == VENDOR_ITEM_TYPE_CURRENCY)
{
currencyEntry = sCurrencyTypesStore.LookupEntry(item_id);
if (!currencyEntry)
{
if (pl)
ChatHandler(pl).PSendSysMessage(LANG_CURRENCY_NOT_FOUND, item_id);
else
sLog.outErrorDb("Table `%s` for %s %u contains nonexistent currency (%u), ignoring",
tableName, idStr, vendor_entry, item_id);
return false;
}
else
{
if (currencyEntry->ID == CURRENCY_CONQUEST_ARENA_META || currencyEntry->ID == CURRENCY_CONQUEST_BG_META)
{
if (pl)
ChatHandler(pl).PSendSysMessage(LANG_VENDOR_META_CURRENCY_NOT_ALLOWED, item_id);
else
sLog.outErrorDb("Table `%s` for %s %u contains not allowed meta currency (%u), ignoring",
tableName, idStr, vendor_entry, item_id);
return false;
}
}
}
else
{
if (pl)
ChatHandler(pl).PSendSysMessage(LANG_VENDOR_WRONG_ITEM_TYPE, item_id, type);
else
sLog.outErrorDb("Table `%s` for %s %u contains nonexistent vendor item type %u (entry %u), ignoring",
tableName, idStr, vendor_entry, type, item_id);
}
if (ExtendedCost && !sItemExtendedCostStore.LookupEntry(ExtendedCost)) if (ExtendedCost && !sItemExtendedCostStore.LookupEntry(ExtendedCost))
{ {
if (pl) if (pl)
ChatHandler(pl).PSendSysMessage(LANG_EXTENDED_COST_NOT_EXIST, ExtendedCost); ChatHandler(pl).PSendSysMessage(LANG_EXTENDED_COST_NOT_EXIST, ExtendedCost);
else else
sLog.outErrorDb("Table `%s` contain item (Entry: %u) with wrong ExtendedCost (%u) for %s %u, ignoring", sLog.outErrorDb("Table `%s` contains %s (Entry: %u) with wrong ExtendedCost (%u) for %s %u, ignoring",
tableName, item_id, ExtendedCost, idStr, vendor_entry); tableName, nameStr, item_id, ExtendedCost, idStr, vendor_entry);
return false; return false;
} }
if (type == VENDOR_ITEM_TYPE_ITEM)
{
if (maxcount > 0 && incrtime == 0) if (maxcount > 0 && incrtime == 0)
{ {
if (pl) if (pl)
ChatHandler(pl).PSendSysMessage("MaxCount!=0 (%u) but IncrTime==0", maxcount); ChatHandler(pl).PSendSysMessage("MaxCount!=0 (%u) but IncrTime==0", maxcount);
else else
sLog.outErrorDb("Table `%s` has `maxcount` (%u) for item %u of %s %u but `incrtime`=0, ignoring", sLog.outErrorDb("Table `%s` has `maxcount` (%u) for %s %u of %s %u but `incrtime`=0, ignoring",
tableName, maxcount, item_id, idStr, vendor_entry); tableName, maxcount, nameStr, item_id, idStr, vendor_entry);
return false; return false;
} }
else if (maxcount == 0 && incrtime > 0) else if (maxcount == 0 && incrtime > 0)
@ -9271,10 +9312,23 @@ bool ObjectMgr::IsVendorItemValid(bool isTemplate, char const* tableName, uint32
if (pl) if (pl)
ChatHandler(pl).PSendSysMessage("MaxCount==0 but IncrTime<>=0"); ChatHandler(pl).PSendSysMessage("MaxCount==0 but IncrTime<>=0");
else else
sLog.outErrorDb("Table `%s` has `maxcount`=0 for item %u of %s %u but `incrtime`<>0, ignoring", sLog.outErrorDb("Table `%s` has `maxcount`=0 for %s %u of %s %u but `incrtime`<>0, ignoring",
tableName, item_id, idStr, vendor_entry); tableName, nameStr, item_id, idStr, vendor_entry);
return false; return false;
} }
}
else if (type == VENDOR_ITEM_TYPE_CURRENCY)
{
if (maxcount < uint32(currencyEntry->GetPrecision()))
{
if (pl)
ChatHandler(pl).PSendSysMessage(LANG_VENDOR_WRONG_CURRENCY_MAXCOUNT, item_id, uint32(currencyEntry->GetPrecision()));
else
sLog.outErrorDb("Table `%s` contains %s (Entry: %u) with too low maxcount. Maxcount for currencies is buycount, so it can't be 0 or less than that's currency precision (%u), ignoring",
tableName, nameStr, item_id, uint32(currencyEntry->GetPrecision()));
return false;
}
}
VendorItemData const* vItems = isTemplate ? GetNpcVendorTemplateItemList(vendor_entry) : GetNpcVendorItemList(vendor_entry); VendorItemData const* vItems = isTemplate ? GetNpcVendorTemplateItemList(vendor_entry) : GetNpcVendorItemList(vendor_entry);
VendorItemData const* tItems = isTemplate ? NULL : GetNpcVendorTemplateItemList(vendor_entry); VendorItemData const* tItems = isTemplate ? NULL : GetNpcVendorTemplateItemList(vendor_entry);
@ -9282,30 +9336,30 @@ bool ObjectMgr::IsVendorItemValid(bool isTemplate, char const* tableName, uint32
if (!vItems && !tItems) if (!vItems && !tItems)
return true; // later checks for non-empty lists return true; // later checks for non-empty lists
if (vItems && vItems->FindItemCostPair(item_id, ExtendedCost)) if (vItems && vItems->FindItemCostPair(item_id, type, ExtendedCost))
{ {
if (pl) if (pl)
ChatHandler(pl).PSendSysMessage(LANG_ITEM_ALREADY_IN_LIST, item_id, ExtendedCost); ChatHandler(pl).PSendSysMessage(LANG_ITEM_ALREADY_IN_LIST, item_id, type == VENDOR_ITEM_TYPE_CURRENCY, ExtendedCost);
else else
sLog.outErrorDb("Table `%s` has duplicate items %u (with extended cost %u) for %s %u, ignoring", sLog.outErrorDb("Table `%s` has duplicate %s %u (with extended cost %u) for %s %u, ignoring",
tableName, item_id, ExtendedCost, idStr, vendor_entry); tableName, nameStr, item_id, ExtendedCost, idStr, vendor_entry);
return false; return false;
} }
if (!isTemplate) if (!isTemplate)
{ {
if (tItems && tItems->FindItemCostPair(item_id, ExtendedCost)) if (tItems && tItems->FindItemCostPair(item_id, type, ExtendedCost))
{ {
if (pl) if (pl)
ChatHandler(pl).PSendSysMessage(LANG_ITEM_ALREADY_IN_LIST, item_id, ExtendedCost); ChatHandler(pl).PSendSysMessage(LANG_ITEM_ALREADY_IN_LIST, item_id, type == VENDOR_ITEM_TYPE_CURRENCY, ExtendedCost);
else else
{ {
if (!cInfo->vendorId) if (!cInfo->vendorId)
sLog.outErrorDb("Table `%s` has duplicate items %u (with extended cost %u) for %s %u, ignoring", sLog.outErrorDb("Table `%s` has duplicate %s %u (with extended cost %u) for %s %u, ignoring",
tableName, item_id, ExtendedCost, idStr, vendor_entry); tableName, nameStr, item_id, ExtendedCost, idStr, vendor_entry);
else else
sLog.outErrorDb("Table `%s` has duplicate items %u (with extended cost %u) for %s %u (or possible in vendor template %u), ignoring", sLog.outErrorDb("Table `%s` has duplicate %s %u (with extended cost %u) for %s %u (or possible in vendor template %u), ignoring",
tableName, item_id, ExtendedCost, idStr, vendor_entry, cInfo->vendorId); tableName, nameStr, item_id, ExtendedCost, idStr, vendor_entry, cInfo->vendorId);
} }
return false; return false;
} }
@ -9319,7 +9373,7 @@ bool ObjectMgr::IsVendorItemValid(bool isTemplate, char const* tableName, uint32
if (pl) if (pl)
ChatHandler(pl).SendSysMessage(LANG_COMMAND_ADDVENDORITEMITEMS); ChatHandler(pl).SendSysMessage(LANG_COMMAND_ADDVENDORITEMITEMS);
else else
sLog.outErrorDb("Table `%s` has too many items (%u >= %i) for %s %u, ignoring", sLog.outErrorDb("Table `%s` has too many entries (%u >= %i) for %s %u, ignoring",
tableName, countItems, MAX_VENDOR_ITEMS, idStr, vendor_entry); tableName, countItems, MAX_VENDOR_ITEMS, idStr, vendor_entry);
return false; return false;
} }

View file

@ -1017,9 +1017,9 @@ class ObjectMgr
return &iter->second; return &iter->second;
} }
void AddVendorItem(uint32 entry, uint32 item, uint32 maxcount, uint32 incrtime, uint32 ExtendedCost); void AddVendorItem(uint32 entry, uint32 item, uint8 type, uint32 maxcount, uint32 incrtime, uint32 ExtendedCost);
bool RemoveVendorItem(uint32 entry, uint32 item); bool RemoveVendorItem(uint32 entry, uint32 item, uint8 type);
bool IsVendorItemValid(bool isTemplate, char const* tableName, uint32 vendor_entry, uint32 item, uint32 maxcount, uint32 ptime, uint32 ExtendedCost, Player* pl = NULL, std::set<uint32>* skip_vendors = NULL) const; bool IsVendorItemValid(bool isTemplate, char const* tableName, uint32 vendor_entry, uint32 item, uint8 type, uint32 maxcount, uint32 ptime, uint32 ExtendedCost, Player* pl = NULL, std::set<uint32>* skip_vendors = NULL) const;
int GetOrNewIndexForLocale(LocaleConstant loc); int GetOrNewIndexForLocale(LocaleConstant loc);

View file

@ -19635,6 +19635,106 @@ bool Player::BuyItemFromVendorSlot(ObjectGuid vendorGuid, uint32 vendorslot, uin
return crItem->maxcount != 0; return crItem->maxcount != 0;
} }
bool Player::BuyCurrencyFromVendorSlot(ObjectGuid vendorGuid, uint32 vendorslot, uint32 currencyId, uint8 count)
{
// cheating attempt
if (count < 1) count = 1;
if (!isAlive())
return false;
CurrencyTypesEntry const* pCurrency = sCurrencyTypesStore.LookupEntry(currencyId);
if (!pCurrency)
return false;
if (currencyId == CURRENCY_CONQUEST_ARENA_META || currencyId == CURRENCY_CONQUEST_BG_META)
return false;
Creature* pCreature = GetNPCIfCanInteractWith(vendorGuid, UNIT_NPC_FLAG_VENDOR);
if (!pCreature)
{
DEBUG_LOG("WORLD: BuyCurrencyFromVendorSlot - %s not found or you can't interact with him.", vendorGuid.GetString().c_str());
return false;
}
VendorItemData const* vItems = pCreature->GetVendorItems();
VendorItemData const* tItems = pCreature->GetVendorTemplateItems();
if ((!vItems || vItems->Empty()) && (!tItems || tItems->Empty()))
return false;
uint32 vCount = vItems ? vItems->GetItemCount() : 0;
uint32 tCount = tItems ? tItems->GetItemCount() : 0;
if (vendorslot >= vCount + tCount)
return false;
VendorItem const* crItem = vendorslot < vCount ? vItems->GetItem(vendorslot) : tItems->GetItem(vendorslot - vCount);
if (!crItem) // store diff item (cheating)
return false;
if (crItem->item != currencyId) // store diff item (cheating)
return false;
if (crItem->maxcount != count)
{
DEBUG_LOG("WORLD: BuyCurrencyFromVendorSlot - %s: count (%u) != crItem->maxcount (%u) for currency %u and player %s.",
vendorGuid.GetString().c_str(), count, crItem->maxcount, currencyId, GetGuidStr().c_str());
count = crItem->maxcount;
}
if (uint32 extendedCostId = crItem->ExtendedCost)
{
ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(extendedCostId);
if (!iece)
{
sLog.outError("WORLD: BuyCurrencyFromVendorSlot: Currency %u have wrong ExtendedCost field value %u for %s", currencyId, extendedCostId, vendorGuid.GetString().c_str());
return false;
}
// honor points price
if (GetHonorPoints() < (iece->reqhonorpoints * count))
{
SendEquipError(EQUIP_ERR_NOT_ENOUGH_HONOR_POINTS, NULL, NULL);
return false;
}
// arena points price
if (GetArenaPoints() < (iece->reqarenapoints * count))
{
SendEquipError(EQUIP_ERR_NOT_ENOUGH_ARENA_POINTS, NULL, NULL);
return false;
}
// item base price
for (uint8 i = 0; i < MAX_EXTENDED_COST_ITEMS; ++i)
{
if (iece->reqitem[i] && !HasItemCount(iece->reqitem[i], iece->reqitemcount[i] * count))
{
SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, NULL, NULL);
return false;
}
}
// check for personal arena rating requirement
if (GetMaxPersonalArenaRatingRequirement(iece->reqarenaslot) < iece->reqpersonalarenarating)
{
// probably not the proper equip err
SendEquipError(EQUIP_ERR_CANT_EQUIP_RANK, NULL, NULL);
return false;
}
}
// TODO: check if player already has maximum currency
// TODO: modify currency
DEBUG_LOG("WORLD: BuyCurrencyFromVendorSlot - %s: Player %s buys currency %u amount %u.",
vendorGuid.GetString().c_str(), GetGuidStr().c_str(), currencyId, count);
return true;
}
uint32 Player::GetMaxPersonalArenaRatingRequirement(uint32 minarenaslot) uint32 Player::GetMaxPersonalArenaRatingRequirement(uint32 minarenaslot)
{ {
// returns the maximal personal arena rating that can be used to purchase items requiring this condition // returns the maximal personal arena rating that can be used to purchase items requiring this condition

View file

@ -1286,6 +1286,7 @@ class MANGOS_DLL_SPEC Player : public Unit
} }
void SendNewItem(Item* item, uint32 count, bool received, bool created, bool broadcast = false); void SendNewItem(Item* item, uint32 count, bool received, bool created, bool broadcast = false);
bool BuyItemFromVendorSlot(ObjectGuid vendorGuid, uint32 vendorslot, uint32 item, uint8 count, uint8 bag, uint8 slot); bool BuyItemFromVendorSlot(ObjectGuid vendorGuid, uint32 vendorslot, uint32 item, uint8 count, uint8 bag, uint8 slot);
bool BuyCurrencyFromVendorSlot(ObjectGuid vendorGuid, uint32 vendorslot, uint32 currencyId, uint8 count);
float GetReputationPriceDiscount(Creature const* pCreature) const; float GetReputationPriceDiscount(Creature const* pCreature) const;

View file

@ -2758,6 +2758,7 @@ enum ChatMsg
enum ChatLinkColors enum ChatLinkColors
{ {
CHAT_LINK_COLOR_CURRENCY = 0xff00aa00, // green
CHAT_LINK_COLOR_TRADE = 0xffffd000, // orange CHAT_LINK_COLOR_TRADE = 0xffffd000, // orange
CHAT_LINK_COLOR_TALENT = 0xff4e96f7, // blue CHAT_LINK_COLOR_TALENT = 0xff4e96f7, // blue
CHAT_LINK_COLOR_SPELL = 0xff71d5ff, // bright blue CHAT_LINK_COLOR_SPELL = 0xff71d5ff, // bright blue

View file

@ -639,7 +639,6 @@ class MANGOS_DLL_SPEC WorldSession
void HandleDestroyItemOpcode(WorldPacket& recvPacket); void HandleDestroyItemOpcode(WorldPacket& recvPacket);
void HandleAutoEquipItemOpcode(WorldPacket& recvPacket); void HandleAutoEquipItemOpcode(WorldPacket& recvPacket);
void HandleSellItemOpcode(WorldPacket& recvPacket); void HandleSellItemOpcode(WorldPacket& recvPacket);
void HandleBuyItemInSlotOpcode(WorldPacket& recvPacket);
void HandleBuyItemOpcode(WorldPacket& recvPacket); void HandleBuyItemOpcode(WorldPacket& recvPacket);
void HandleListInventoryOpcode(WorldPacket& recvPacket); void HandleListInventoryOpcode(WorldPacket& recvPacket);
void HandleAutoStoreBagItemOpcode(WorldPacket& recvPacket); void HandleAutoStoreBagItemOpcode(WorldPacket& recvPacket);

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__ #ifndef __REVISION_NR_H__
#define __REVISION_NR_H__ #define __REVISION_NR_H__
#define REVISION_NR "0168" #define REVISION_NR "0169"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__

View file

@ -1,6 +1,6 @@
#ifndef __REVISION_SQL_H__ #ifndef __REVISION_SQL_H__
#define __REVISION_SQL_H__ #define __REVISION_SQL_H__
#define REVISION_DB_CHARACTERS "required_0099_xxxxx_01_characters_character_phase_data" #define REVISION_DB_CHARACTERS "required_0099_xxxxx_01_characters_character_phase_data"
#define REVISION_DB_MANGOS "required_0168_xxxxx_01_mangos_playercreateinfo_spell" #define REVISION_DB_MANGOS "required_0169_xxxxx_04_mangos_command"
#define REVISION_DB_REALMD "required_0014_xxxxx_01_realmd_account_access" #define REVISION_DB_REALMD "required_0014_xxxxx_01_realmd_account_access"
#endif // __REVISION_SQL_H__ #endif // __REVISION_SQL_H__