aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.cpp74
-rw-r--r--src/server/game/AuctionHouse/AuctionHouseMgr.cpp143
-rw-r--r--src/server/game/AuctionHouse/AuctionHouseMgr.h6
-rw-r--r--src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp1
-rw-r--r--src/server/game/Loot/LootMgr.cpp132
-rw-r--r--src/server/game/Loot/LootMgr.h23
-rw-r--r--src/server/game/Maps/TransportMgr.h2
-rw-r--r--src/server/game/Scripting/ScriptMgr.cpp10
-rw-r--r--src/server/game/Spells/SpellMgr.cpp5
-rw-r--r--src/server/game/World/World.cpp4
-rw-r--r--src/server/scripts/Spells/spell_holiday.cpp32
-rw-r--r--src/server/shared/Database/Implementation/CharacterDatabase.cpp3
-rw-r--r--src/server/shared/Database/Implementation/CharacterDatabase.h2
-rw-r--r--src/server/shared/Threading/ProducerConsumerQueue.h4
-rw-r--r--src/server/worldserver/Main.cpp15
15 files changed, 234 insertions, 222 deletions
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
index 0217a9c3fcd..a1f24952d8f 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
@@ -235,6 +235,31 @@ void SmartAIMgr::LoadSmartAIFromDB()
}
while (result->NextRow());
+ // TO-DO: Find better way
+ for (uint8 i = 0; i < SMART_SCRIPT_TYPE_MAX; i++)
+ {
+ for (auto itr = mEventMap[i].begin(); itr != mEventMap[i].end(); ++itr)
+ {
+ for (auto e : mEventMap[i][itr->first])
+ {
+ bool found = false;
+ if (e.link && e.link != e.event_id)
+ {
+ for (auto linked : mEventMap[i][itr->first])
+ {
+ if (linked.event_id == e.link)
+ if (linked.GetActionType() && linked.GetEventType() == SMART_EVENT_LINK)
+ found = true;
+ }
+
+ if (!found)
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Entry %d SourceType %u, Event %u, Link Event %u not found or invalid",
+ e.entryOrGuid, e.GetScriptType(), e.event_id, e.link);
+ }
+ }
+ }
+ }
+
TC_LOG_INFO("server.loading", ">> Loaded %u SmartAI scripts in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
UnLoadHelperStores();
@@ -675,6 +700,36 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
switch (e.GetActionType())
{
+ case SMART_ACTION_TALK:
+ {
+ if (e.GetScriptType() == SMART_SCRIPT_TYPE_CREATURE)
+ {
+ uint32 entry = 0;
+ if (e.entryOrGuid >= 0)
+ entry = e.entryOrGuid;
+ else
+ {
+ if (CreatureData const* creatureData = sObjectMgr->GetCreatureData(uint32(abs(e.entryOrGuid))))
+ entry = creatureData->id;
+ }
+
+ CreatureTextMap::const_iterator sList = sCreatureTextMgr->GetTextMap().find(entry);
+ if (sList == sCreatureTextMgr->GetTextMap().end())
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u could not find Text for Creature %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
+ return false;
+ }
+
+ CreatureTextHolder const& textHolder = sList->second;
+ CreatureTextHolder::const_iterator itr = textHolder.find(e.action.talk.textGroupID);
+ if (itr == textHolder.end())
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u could not find TextGroup %u for Creature %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.talk.textGroupID, entry);
+ return false;
+ }
+ }
+ break;
+ }
case SMART_ACTION_SET_FACTION:
if (e.action.faction.factionID && !sFactionTemplateStore.LookupEntry(e.action.faction.factionID))
{
@@ -749,8 +804,24 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
if (e.action.randomEmote.emote6 && !IsEmoteValid(e, e.action.randomEmote.emote6))
return false;
break;
- case SMART_ACTION_ADD_AURA:
case SMART_ACTION_CAST:
+ {
+ if (!IsSpellValid(e, e.action.cast.spell))
+ return false;
+
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(e.action.cast.spell);
+ for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j)
+ {
+ if (spellInfo->Effects[j].IsEffect(SPELL_EFFECT_KILL_CREDIT) || spellInfo->Effects[j].IsEffect(SPELL_EFFECT_KILL_CREDIT2))
+ {
+ if (spellInfo->Effects[j].TargetA.GetTarget() == TARGET_UNIT_CASTER)
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u Effect: SPELL_EFFECT_KILL_CREDIT: (SpellId: %u targetA: %u - targetB: %u) has invalid target for this Action",
+ e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.cast.spell, spellInfo->Effects[j].TargetA.GetTarget(), spellInfo->Effects[j].TargetB.GetTarget());
+ }
+ }
+ break;
+ }
+ case SMART_ACTION_ADD_AURA:
case SMART_ACTION_INVOKER_CAST:
if (!IsSpellValid(e, e.action.cast.spell))
return false;
@@ -1068,7 +1139,6 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
case SMART_ACTION_SET_NPC_FLAG:
case SMART_ACTION_ADD_NPC_FLAG:
case SMART_ACTION_REMOVE_NPC_FLAG:
- case SMART_ACTION_TALK:
case SMART_ACTION_SIMPLE_TALK:
case SMART_ACTION_CROSS_CAST:
case SMART_ACTION_CALL_RANDOM_TIMED_ACTIONLIST:
diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
index 7b1dda89869..8955fc9014f 100644
--- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
+++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
@@ -147,6 +147,11 @@ void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry* auction, SQLTransaction&
.AddItem(pItem)
.SendMailTo(trans, MailReceiver(bidder, auction->bidder), auction, MAIL_CHECK_MASK_COPIED);
}
+ else
+ {
+ // bidder doesn't exist, delete the item
+ sAuctionMgr->RemoveAItem(auction->itemGUIDLow, true);
+ }
}
void AuctionHouseMgr::SendAuctionSalePendingMail(AuctionEntry* auction, SQLTransaction& trans)
@@ -207,6 +212,11 @@ void AuctionHouseMgr::SendAuctionExpiredMail(AuctionEntry* auction, SQLTransacti
.AddItem(pItem)
.SendMailTo(trans, MailReceiver(owner, auction->owner), auction, MAIL_CHECK_MASK_COPIED, 0);
}
+ else
+ {
+ // owner doesn't exist, delete the item
+ sAuctionMgr->RemoveAItem(auction->itemGUIDLow, true);
+ }
}
//this function sends mail to old bidder
@@ -350,12 +360,19 @@ void AuctionHouseMgr::AddAItem(Item* it)
mAitems[it->GetGUIDLow()] = it;
}
-bool AuctionHouseMgr::RemoveAItem(uint32 id)
+bool AuctionHouseMgr::RemoveAItem(uint32 id, bool deleteItem)
{
ItemMap::iterator i = mAitems.find(id);
if (i == mAitems.end())
return false;
+ if (deleteItem)
+ {
+ SQLTransaction trans = SQLTransaction(nullptr);
+ i->second->FSetState(ITEM_REMOVED);
+ i->second->SaveToDB(trans);
+ }
+
mAitems.erase(i);
return true;
}
@@ -521,9 +538,15 @@ void AuctionHouseObject::BuildListAuctionItems(WorldPacket& data, Player* player
int loc_idx = player->GetSession()->GetSessionDbLocaleIndex();
int locdbc_idx = player->GetSession()->GetSessionDbcLocale();
+ time_t curTime = sWorld->GetGameTime();
+
for (AuctionEntryMap::const_iterator itr = AuctionsMap.begin(); itr != AuctionsMap.end(); ++itr)
{
AuctionEntry* Aentry = itr->second;
+ // Skip expired auctions
+ if (Aentry->expire_time < curTime)
+ continue;
+
Item* item = sAuctionMgr->GetAItem(Aentry->itemGUIDLow);
if (!item)
continue;
@@ -720,124 +743,6 @@ bool AuctionEntry::LoadFromDB(Field* fields)
}
return true;
}
-
-void AuctionHouseMgr::DeleteExpiredAuctionsAtStartup()
-{
- // Deletes expired auctions. Should be called at server start before loading auctions.
-
- // DO NOT USE after auctions are already loaded since this deletes from the DB
- // and assumes the auctions HAVE NOT been loaded into a list or AuctionEntryMap yet
-
- uint32 oldMSTime = getMSTime();
- uint32 expirecount = 0;
- time_t curTime = sWorld->GetGameTime();
-
- // Query the DB to see if there are any expired auctions
- PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_EXPIRED_AUCTIONS);
- stmt->setUInt32(0, (uint32)curTime+60);
- PreparedQueryResult expAuctions = CharacterDatabase.Query(stmt);
-
- if (!expAuctions)
- {
- TC_LOG_INFO("server.loading", ">> No expired auctions to delete");
-
- return;
- }
-
- do
- {
- Field* fields = expAuctions->Fetch();
-
- AuctionEntry* auction = new AuctionEntry();
-
- // Can't use LoadFromDB() because it assumes the auction map is loaded
- if (!auction->LoadFromFieldList(fields))
- {
- // For some reason the record in the DB is broken (possibly corrupt
- // faction info). Delete the object and move on.
- delete auction;
- continue;
- }
-
- SQLTransaction trans = CharacterDatabase.BeginTransaction();
-
- if (auction->bidder==0)
- {
- // Cancel the auction, there was no bidder
- sAuctionMgr->SendAuctionExpiredMail(auction, trans);
- }
- else
- {
- // Send the item to the winner and money to seller
- sAuctionMgr->SendAuctionSuccessfulMail(auction, trans);
- sAuctionMgr->SendAuctionWonMail(auction, trans);
- }
-
- // Call the appropriate AuctionHouseObject script
- // ** Do we need to do this while core is still loading? **
- sScriptMgr->OnAuctionExpire(GetAuctionsMap(auction->factionTemplateId), auction);
-
- // Delete the auction from the DB
- auction->DeleteFromDB(trans);
- CharacterDatabase.CommitTransaction(trans);
-
- // Release memory
- delete auction;
- ++expirecount;
-
- }
- while (expAuctions->NextRow());
-
- TC_LOG_INFO("server.loading", ">> Deleted %u expired auctions in %u ms", expirecount, GetMSTimeDiffToNow(oldMSTime));
-
-
-}
-
-bool AuctionEntry::LoadFromFieldList(Field* fields)
-{
- // Loads an AuctionEntry item from a field list. Unlike "LoadFromDB()", this one
- // does not require the AuctionEntryMap to have been loaded with items. It simply
- // acts as a wrapper to fill out an AuctionEntry struct from a field list
-
- Id = fields[0].GetUInt32();
- auctioneer = fields[1].GetUInt32();
- itemGUIDLow = fields[2].GetUInt32();
- itemEntry = fields[3].GetUInt32();
- itemCount = fields[4].GetUInt32();
- owner = fields[5].GetUInt32();
- buyout = fields[6].GetUInt32();
- expire_time = fields[7].GetUInt32();
- bidder = fields[8].GetUInt32();
- bid = fields[9].GetUInt32();
- startbid = fields[10].GetUInt32();
- deposit = fields[11].GetUInt32();
-
- CreatureData const* auctioneerData = sObjectMgr->GetCreatureData(auctioneer);
- if (!auctioneerData)
- {
- TC_LOG_ERROR("misc", "AuctionEntry::LoadFromFieldList() - Auction %u has not a existing auctioneer (GUID : %u)", Id, auctioneer);
- return false;
- }
-
- CreatureTemplate const* auctioneerInfo = sObjectMgr->GetCreatureTemplate(auctioneerData->id);
- if (!auctioneerInfo)
- {
- TC_LOG_ERROR("misc", "AuctionEntry::LoadFromFieldList() - Auction %u has not a existing auctioneer (GUID : %u Entry: %u)", Id, auctioneer, auctioneerData->id);
- return false;
- }
-
- factionTemplateId = auctioneerInfo->faction;
- auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntry(factionTemplateId);
-
- if (!auctionHouseEntry)
- {
- TC_LOG_ERROR("misc", "AuctionEntry::LoadFromFieldList() - Auction %u has auctioneer (GUID : %u Entry: %u) with wrong faction %u", Id, auctioneer, auctioneerData->id, factionTemplateId);
- return false;
- }
-
- return true;
-}
-
std::string AuctionEntry::BuildAuctionMailSubject(MailAuctionAnswers response) const
{
std::ostringstream strm;
diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.h b/src/server/game/AuctionHouse/AuctionHouseMgr.h
index 597da13cb1b..fc70946d6c4 100644
--- a/src/server/game/AuctionHouse/AuctionHouseMgr.h
+++ b/src/server/game/AuctionHouse/AuctionHouseMgr.h
@@ -87,7 +87,6 @@ struct AuctionEntry
void DeleteFromDB(SQLTransaction& trans) const;
void SaveToDB(SQLTransaction& trans) const;
bool LoadFromDB(Field* fields);
- bool LoadFromFieldList(Field* fields);
std::string BuildAuctionMailSubject(MailAuctionAnswers response) const;
static std::string BuildAuctionMailBody(uint32 lowGuid, uint32 bid, uint32 buyout, uint32 deposit, uint32 cut);
@@ -173,15 +172,12 @@ class AuctionHouseMgr
public:
- // Used primarily at server start to avoid loading a list of expired auctions
- void DeleteExpiredAuctionsAtStartup();
-
//load first auction items, because of check if item exists, when loading
void LoadAuctionItems();
void LoadAuctions();
void AddAItem(Item* it);
- bool RemoveAItem(uint32 id);
+ bool RemoveAItem(uint32 id, bool deleteItem = false);
void Update();
diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp
index 13aa1f22fa3..00e1a35973d 100644
--- a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp
+++ b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp
@@ -84,6 +84,7 @@ bool AuctionBotSeller::Initialize()
"SELECT `item` FROM `milling_loot_template` UNION "
"SELECT `item` FROM `pickpocketing_loot_template` UNION "
"SELECT `item` FROM `prospecting_loot_template` UNION "
+ "SELECT `item` FROM `reference_loot_template` UNION "
"SELECT `item` FROM `skinning_loot_template` UNION "
"SELECT `item` FROM `spell_loot_template`");
diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp
index f4f0979d091..fd9a91ebb6a 100644
--- a/src/server/game/Loot/LootMgr.cpp
+++ b/src/server/game/Loot/LootMgr.cpp
@@ -133,7 +133,7 @@ uint32 LootStore::LoadLootTable()
Clear();
// 0 1 2 3 4 5 6
- QueryResult result = WorldDatabase.PQuery("SELECT entry, item, ChanceOrQuestChance, lootmode, groupid, mincountOrRef, maxcount FROM %s", GetName());
+ QueryResult result = WorldDatabase.PQuery("SELECT Entry, Item, Reference, Chance, QuestRequired, LootMode, GroupId, MinCount, MaxCount FROM %s", GetName());
if (!result)
return 0;
@@ -146,25 +146,27 @@ uint32 LootStore::LoadLootTable()
uint32 entry = fields[0].GetUInt32();
uint32 item = fields[1].GetUInt32();
- float chanceOrQuestChance = fields[2].GetFloat();
- uint16 lootmode = fields[3].GetUInt16();
- uint8 group = fields[4].GetUInt8();
- int32 mincountOrRef = fields[5].GetInt32();
- int32 maxcount = fields[6].GetUInt8();
+ uint32 reference = fields[2].GetUInt32();
+ float chance = fields[3].GetFloat();
+ bool needsquest = fields[4].GetBool();
+ uint16 lootmode = fields[5].GetUInt16();
+ uint8 groupid = fields[6].GetUInt8();
+ int32 mincount = fields[7].GetUInt8();
+ int32 maxcount = fields[8].GetUInt8();
if (maxcount > std::numeric_limits<uint8>::max())
{
- TC_LOG_ERROR("sql.sql", "Table '%s' entry %d item %d: maxcount value (%u) to large. must be less %u - skipped", GetName(), entry, item, maxcount, std::numeric_limits<uint8>::max());
+ TC_LOG_ERROR("sql.sql", "Table '%s' Entry %d Item %d: MaxCount value (%u) to large. must be less %u - skipped", GetName(), entry, item, maxcount, std::numeric_limits<uint8>::max());
continue; // error already printed to log/console.
}
- if (group >= 1 << 7) // it stored in 7 bit field
+ if (groupid >= 1 << 7) // it stored in 7 bit field
{
- TC_LOG_ERROR("sql.sql", "Table '%s' entry %d item %d: group (%u) must be less %u - skipped", GetName(), entry, item, group, 1 << 7);
+ TC_LOG_ERROR("sql.sql", "Table '%s' Entry %d Item %d: GroupId (%u) must be less %u - skipped", GetName(), entry, item, groupid, 1 << 7);
return 0;
}
- LootStoreItem* storeitem = new LootStoreItem(item, chanceOrQuestChance, lootmode, group, mincountOrRef, maxcount);
+ LootStoreItem* storeitem = new LootStoreItem(item, reference, chance, needsquest, lootmode, groupid, mincount, maxcount);
if (!storeitem->IsValid(*this, entry)) // Validity checks
{
@@ -173,7 +175,7 @@ uint32 LootStore::LoadLootTable()
}
// Looking for the template of the entry
- // often entries are put together
+ // often entries are put together
if (m_LootTemplates.empty() || tab->first != entry)
{
// Searching the template (in case template Id changed)
@@ -267,12 +269,12 @@ void LootStore::ReportUnusedIds(LootIdSet const& lootIdSet) const
{
// all still listed ids isn't referenced
for (LootIdSet::const_iterator itr = lootIdSet.begin(); itr != lootIdSet.end(); ++itr)
- TC_LOG_ERROR("sql.sql", "Table '%s' entry %d isn't %s and not referenced from loot, and then useless.", GetName(), *itr, GetEntryName());
+ TC_LOG_ERROR("sql.sql", "Table '%s' Entry %d isn't %s and not referenced from loot, and thus useless.", GetName(), *itr, GetEntryName());
}
-void LootStore::ReportNotExistedId(uint32 id) const
+void LootStore::ReportNonExistingId(uint32 id) const
{
- TC_LOG_ERROR("sql.sql", "Table '%s' entry %d (%s) does not exist but used as loot id in DB.", GetName(), id, GetEntryName());
+ TC_LOG_ERROR("sql.sql", "Table '%s' Entry %d (%s) does not exist but is used as loot id in DB.", GetName(), id, GetEntryName());
}
//
@@ -286,7 +288,7 @@ bool LootStoreItem::Roll(bool rate) const
if (chance >= 100.0f)
return true;
- if (mincountOrRef < 0) // reference case
+ if (reference > 0) // reference case
return roll_chance_f(chance* (rate ? sWorld->getRate(RATE_DROP_ITEM_REFERENCED) : 1.0f));
ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(itemid);
@@ -299,47 +301,47 @@ bool LootStoreItem::Roll(bool rate) const
// Checks correctness of values
bool LootStoreItem::IsValid(LootStore const& store, uint32 entry) const
{
- if (mincountOrRef == 0)
+ if (mincount == 0)
{
- TC_LOG_ERROR("sql.sql", "Table '%s' entry %d item %d: wrong mincountOrRef (%d) - skipped", store.GetName(), entry, itemid, mincountOrRef);
+ TC_LOG_ERROR("sql.sql", "Table '%s' Entry %d Item %d: wrong MinCount (%d) - skipped", store.GetName(), entry, itemid, mincount);
return false;
}
- if (mincountOrRef > 0) // item (quest or non-quest) entry, maybe grouped
+ if (reference == 0) // item (quest or non-quest) entry, maybe grouped
{
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemid);
if (!proto)
{
- TC_LOG_ERROR("sql.sql", "Table '%s' entry %d item %d: item entry not listed in `item_template` - skipped", store.GetName(), entry, itemid);
+ TC_LOG_ERROR("sql.sql", "Table '%s' Entry %d Item %d: item entry not listed in `item_template` - skipped", store.GetName(), entry, itemid);
return false;
}
- if (chance == 0 && group == 0) // Zero chance is allowed for grouped entries only
+ if (chance == 0 && groupid == 0) // Zero chance is allowed for grouped entries only
{
- TC_LOG_ERROR("sql.sql", "Table '%s' entry %d item %d: equal-chanced grouped entry, but group not defined - skipped", store.GetName(), entry, itemid);
+ TC_LOG_ERROR("sql.sql", "Table '%s' Entry %d Item %d: equal-chanced grouped entry, but group not defined - skipped", store.GetName(), entry, itemid);
return false;
}
if (chance != 0 && chance < 0.000001f) // loot with low chance
{
- TC_LOG_ERROR("sql.sql", "Table '%s' entry %d item %d: low chance (%f) - skipped",
+ TC_LOG_ERROR("sql.sql", "Table '%s' Entry %d Item %d: low chance (%f) - skipped",
store.GetName(), entry, itemid, chance);
return false;
}
- if (maxcount < mincountOrRef) // wrong max count
+ if (maxcount < mincount) // wrong max count
{
- TC_LOG_ERROR("sql.sql", "Table '%s' entry %d item %d: max count (%u) less that min count (%i) - skipped", store.GetName(), entry, itemid, int32(maxcount), mincountOrRef);
+ TC_LOG_ERROR("sql.sql", "Table '%s' Entry %d Item %d: MaxCount (%u) less that MinCount (%i) - skipped", store.GetName(), entry, itemid, int32(maxcount), mincount);
return false;
}
}
- else // mincountOrRef < 0
+ else // if reference loot
{
if (needs_quest)
- TC_LOG_ERROR("sql.sql", "Table '%s' entry %d item %d: quest chance will be treated as non-quest chance", store.GetName(), entry, itemid);
+ TC_LOG_ERROR("sql.sql", "Table '%s' Entry %d Item %d: quest required will be ignored", store.GetName(), entry, itemid);
else if (chance == 0) // no chance for the reference
{
- TC_LOG_ERROR("sql.sql", "Table '%s' entry %d item %d: zero chance is specified for a reference, skipped", store.GetName(), entry, itemid);
+ TC_LOG_ERROR("sql.sql", "Table '%s' Entry %d Item %d: zero chance is specified for a reference, skipped", store.GetName(), entry, itemid);
return false;
}
}
@@ -417,7 +419,7 @@ void Loot::AddItem(LootStoreItem const& item)
if (!proto)
return;
- uint32 count = urand(item.mincountOrRef, item.maxcount);
+ uint32 count = urand(item.mincount, item.maxcount);
uint32 stacks = count / proto->GetMaxStackSize() + ((count % proto->GetMaxStackSize()) ? 1 : 0);
std::vector<LootItem>& lootItems = item.needs_quest ? quest_items : items;
@@ -1213,24 +1215,24 @@ void LootTemplate::LootGroup::CheckLootRefs(LootTemplateMap const& /*store*/, Lo
for (LootStoreItemList::const_iterator ieItr = ExplicitlyChanced.begin(); ieItr != ExplicitlyChanced.end(); ++ieItr)
{
LootStoreItem* item = *ieItr;
- if (item->mincountOrRef < 0)
+ if (item->reference > 0)
{
- if (!LootTemplates_Reference.GetLootFor(-item->mincountOrRef))
- LootTemplates_Reference.ReportNotExistedId(-item->mincountOrRef);
+ if (!LootTemplates_Reference.GetLootFor(item->reference))
+ LootTemplates_Reference.ReportNonExistingId(item->reference);
else if (ref_set)
- ref_set->erase(-item->mincountOrRef);
+ ref_set->erase(item->reference);
}
}
for (LootStoreItemList::const_iterator ieItr = EqualChanced.begin(); ieItr != EqualChanced.end(); ++ieItr)
{
LootStoreItem* item = *ieItr;
- if (item->mincountOrRef < 0)
+ if (item->reference > 0)
{
- if (!LootTemplates_Reference.GetLootFor(-item->mincountOrRef))
- LootTemplates_Reference.ReportNotExistedId(-item->mincountOrRef);
+ if (!LootTemplates_Reference.GetLootFor(item->reference))
+ LootTemplates_Reference.ReportNonExistingId(item->reference);
else if (ref_set)
- ref_set->erase(-item->mincountOrRef);
+ ref_set->erase(item->reference);
}
}
}
@@ -1251,16 +1253,16 @@ LootTemplate::~LootTemplate()
// Adds an entry to the group (at loading stage)
void LootTemplate::AddEntry(LootStoreItem* item)
{
- if (item->group > 0 && item->mincountOrRef > 0) // Group
+ if (item->groupid > 0 && item->reference == 0) // Group
{
- if (item->group >= Groups.size())
- Groups.resize(item->group, NULL); // Adds new group the the loot template if needed
- if (!Groups[item->group - 1])
- Groups[item->group - 1] = new LootGroup();
+ if (item->groupid >= Groups.size())
+ Groups.resize(item->groupid, NULL); // Adds new group the the loot template if needed
+ if (!Groups[item->groupid - 1])
+ Groups[item->groupid - 1] = new LootGroup();
- Groups[item->group-1]->AddEntry(item); // Adds new entry to the group
+ Groups[item->groupid - 1]->AddEntry(item); // Adds new entry to the group
}
- else // Non-grouped entries and references are stored together
+ else // Non-grouped entries and references are stored together
Entries.push_back(item);
}
@@ -1299,7 +1301,7 @@ void LootTemplate::Process(Loot& loot, bool rate, uint16 lootMode, uint8 groupId
if (!Groups[groupId - 1])
return;
- Groups[groupId-1]->Process(loot, lootMode);
+ Groups[groupId - 1]->Process(loot, lootMode);
return;
}
@@ -1313,15 +1315,15 @@ void LootTemplate::Process(Loot& loot, bool rate, uint16 lootMode, uint8 groupId
if (!item->Roll(rate))
continue; // Bad luck for the entry
- if (item->mincountOrRef < 0) // References processing
+ if (item->reference > 0) // References processing
{
- LootTemplate const* Referenced = LootTemplates_Reference.GetLootFor(-item->mincountOrRef);
+ LootTemplate const* Referenced = LootTemplates_Reference.GetLootFor(item->reference);
if (!Referenced)
continue; // Error message already printed at loading stage
uint32 maxcount = uint32(float(item->maxcount) * sWorld->getRate(RATE_DROP_ITEM_REFERENCED_AMOUNT));
for (uint32 loop = 0; loop < maxcount; ++loop) // Ref multiplicator
- Referenced->Process(loot, rate, lootMode, item->group);
+ Referenced->Process(loot, rate, lootMode, item->groupid);
}
else // Plain entries (not a reference, not grouped)
loot.AddItem(*item); // Chance is already checked, just add
@@ -1350,12 +1352,12 @@ bool LootTemplate::HasQuestDrop(LootTemplateMap const& store, uint8 groupId) con
for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i)
{
LootStoreItem* item = *i;
- if (item->mincountOrRef < 0) // References
+ if (item->reference > 0) // References
{
- LootTemplateMap::const_iterator Referenced = store.find(-item->mincountOrRef);
+ LootTemplateMap::const_iterator Referenced = store.find(item->reference);
if (Referenced == store.end())
continue; // Error message [should be] already printed at loading stage
- if (Referenced->second->HasQuestDrop(store, item->group))
+ if (Referenced->second->HasQuestDrop(store, item->groupid))
return true;
}
else if (item->needs_quest)
@@ -1382,19 +1384,19 @@ bool LootTemplate::HasQuestDropForPlayer(LootTemplateMap const& store, Player co
if (!Groups[groupId - 1])
return false;
- return Groups[groupId-1]->HasQuestDropForPlayer(player);
+ return Groups[groupId - 1]->HasQuestDropForPlayer(player);
}
// Checking non-grouped entries
for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i)
{
LootStoreItem* item = *i;
- if (item->mincountOrRef < 0) // References processing
+ if (item->reference > 0) // References processing
{
- LootTemplateMap::const_iterator Referenced = store.find(-item->mincountOrRef);
+ LootTemplateMap::const_iterator Referenced = store.find(item->reference);
if (Referenced == store.end())
continue; // Error message already printed at loading stage
- if (Referenced->second->HasQuestDropForPlayer(store, player, item->group))
+ if (Referenced->second->HasQuestDropForPlayer(store, player, item->groupid))
return true;
}
else if (player->HasQuestForItem(item->itemid))
@@ -1426,12 +1428,12 @@ void LootTemplate::CheckLootRefs(LootTemplateMap const& store, LootIdSet* ref_se
for (LootStoreItemList::const_iterator ieItr = Entries.begin(); ieItr != Entries.end(); ++ieItr)
{
LootStoreItem* item = *ieItr;
- if (item->mincountOrRef < 0)
+ if (item->reference > 0)
{
- if (!LootTemplates_Reference.GetLootFor(-item->mincountOrRef))
- LootTemplates_Reference.ReportNotExistedId(-item->mincountOrRef);
+ if (!LootTemplates_Reference.GetLootFor(item->reference))
+ LootTemplates_Reference.ReportNonExistingId(item->reference);
else if (ref_set)
- ref_set->erase(-item->mincountOrRef);
+ ref_set->erase(item->reference);
}
}
@@ -1501,7 +1503,7 @@ bool LootTemplate::addConditionItem(Condition* cond)
bool LootTemplate::isReference(uint32 id)
{
for (LootStoreItemList::const_iterator ieItr = Entries.begin(); ieItr != Entries.end(); ++ieItr)
- if ((*ieItr)->itemid == id && (*ieItr)->mincountOrRef < 0)
+ if ((*ieItr)->itemid == id && (*ieItr)->reference > 0)
return true;
return false;//not found or not reference
@@ -1523,7 +1525,7 @@ void LoadLootTemplates_Creature()
if (uint32 lootid = itr->second.lootid)
{
if (lootIdSet.find(lootid) == lootIdSet.end())
- LootTemplates_Creature.ReportNotExistedId(lootid);
+ LootTemplates_Creature.ReportNonExistingId(lootid);
else
lootIdSetUsed.insert(lootid);
}
@@ -1556,7 +1558,7 @@ void LoadLootTemplates_Disenchant()
if (uint32 lootid = itr->second.DisenchantID)
{
if (lootIdSet.find(lootid) == lootIdSet.end())
- LootTemplates_Disenchant.ReportNotExistedId(lootid);
+ LootTemplates_Disenchant.ReportNonExistingId(lootid);
else
lootIdSetUsed.insert(lootid);
}
@@ -1614,7 +1616,7 @@ void LoadLootTemplates_Gameobject()
if (uint32 lootid = itr->second.GetLootId())
{
if (lootIdSet.find(lootid) == lootIdSet.end())
- LootTemplates_Gameobject.ReportNotExistedId(lootid);
+ LootTemplates_Gameobject.ReportNonExistingId(lootid);
else
lootIdSetUsed.insert(lootid);
}
@@ -1701,7 +1703,7 @@ void LoadLootTemplates_Pickpocketing()
if (uint32 lootid = itr->second.pickpocketLootId)
{
if (lootIdSet.find(lootid) == lootIdSet.end())
- LootTemplates_Pickpocketing.ReportNotExistedId(lootid);
+ LootTemplates_Pickpocketing.ReportNonExistingId(lootid);
else
lootIdSetUsed.insert(lootid);
}
@@ -1788,7 +1790,7 @@ void LoadLootTemplates_Skinning()
if (uint32 lootid = itr->second.SkinLootId)
{
if (lootIdSet.find(lootid) == lootIdSet.end())
- LootTemplates_Skinning.ReportNotExistedId(lootid);
+ LootTemplates_Skinning.ReportNonExistingId(lootid);
else
lootIdSetUsed.insert(lootid);
}
@@ -1832,7 +1834,7 @@ void LoadLootTemplates_Spell()
// ignore 61756 (Northrend Inscription Research (FAST QA VERSION) for example
if (!(spellInfo->Attributes & SPELL_ATTR0_NOT_SHAPESHIFT) || (spellInfo->Attributes & SPELL_ATTR0_TRADESPELL))
{
- LootTemplates_Spell.ReportNotExistedId(spell_id);
+ LootTemplates_Spell.ReportNonExistingId(spell_id);
}
}
else
diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h
index 673e5b6841e..1685996fd03 100644
--- a/src/server/game/Loot/LootMgr.h
+++ b/src/server/game/Loot/LootMgr.h
@@ -125,19 +125,20 @@ class LootStore;
struct LootStoreItem
{
uint32 itemid; // id of the item
- float chance; // always positive, chance to drop for both quest and non-quest items, chance to be used for refs
- int32 mincountOrRef; // mincount for drop items (positive) or minus referenced TemplateleId (negative)
+ uint32 reference; // referenced TemplateleId
+ float chance; // chance to drop for both quest and non-quest items, chance to be used for refs
uint16 lootmode;
- uint8 group :7;
- bool needs_quest :1; // quest drop (negative ChanceOrQuestChance in DB)
- uint8 maxcount :8; // max drop count for the item (mincountOrRef positive) or Ref multiplicator (mincountOrRef negative)
+ bool needs_quest : 1; // quest drop (quest is required for item to drop)
+ uint8 groupid : 7;
+ uint8 mincount; // mincount for drop items
+ uint8 maxcount; // max drop count for the item mincount or Ref multiplicator
ConditionList conditions; // additional loot condition
- // Constructor, converting ChanceOrQuestChance -> (chance, needs_quest)
+ // Constructor
// displayid is filled in IsValid() which must be called after
- LootStoreItem(uint32 _itemid, float _chanceOrQuestChance, uint16 _lootmode, uint8 _group, int32 _mincountOrRef, uint8 _maxcount)
- : itemid(_itemid), chance(std::fabs(_chanceOrQuestChance)), mincountOrRef(_mincountOrRef), lootmode(_lootmode),
- group(_group), needs_quest(_chanceOrQuestChance < 0), maxcount(_maxcount)
+ LootStoreItem(uint32 _itemid, uint32 _reference, float _chance, bool _needs_quest, uint16 _lootmode, uint8 _groupid, int32 _mincount, uint8 _maxcount)
+ : itemid(_itemid), reference(_reference), chance(_chance), lootmode(_lootmode),
+ needs_quest(_needs_quest), groupid(_groupid), mincount(_mincount), maxcount(_maxcount)
{ }
bool Roll(bool rate) const; // Checks if the entry takes it's chance (at loot generation)
@@ -165,7 +166,7 @@ struct LootItem
bool canSave;
// Constructor, copies most fields from LootStoreItem, generates random count and random suffixes/properties
- // Should be called for non-reference LootStoreItem entries only (mincountOrRef > 0)
+ // Should be called for non-reference LootStoreItem entries only (reference = 0)
explicit LootItem(LootStoreItem const& li);
// Empty constructor for creating an empty LootItem to be filled in with DB data
@@ -215,7 +216,7 @@ class LootStore
uint32 LoadAndCollectLootIds(LootIdSet& ids_set);
void CheckLootRefs(LootIdSet* ref_set = NULL) const; // check existence reference and remove it from ref_set
void ReportUnusedIds(LootIdSet const& ids_set) const;
- void ReportNotExistedId(uint32 id) const;
+ void ReportNonExistingId(uint32 id) const;
bool HaveLootFor(uint32 loot_id) const { return m_LootTemplates.find(loot_id) != m_LootTemplates.end(); }
bool HaveQuestLootFor(uint32 loot_id) const;
diff --git a/src/server/game/Maps/TransportMgr.h b/src/server/game/Maps/TransportMgr.h
index 04c372cc526..2a956316be8 100644
--- a/src/server/game/Maps/TransportMgr.h
+++ b/src/server/game/Maps/TransportMgr.h
@@ -83,6 +83,8 @@ typedef std::map<uint32, TransportRotationEntry const*> TransportPathRotationCon
struct TransportAnimation
{
+ TransportAnimation() : TotalTime(0) { }
+
TransportPathContainer Path;
TransportPathRotationContainer Rotations;
uint32 TotalTime;
diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp
index 48981fde70b..be0bf1aa067 100644
--- a/src/server/game/Scripting/ScriptMgr.cpp
+++ b/src/server/game/Scripting/ScriptMgr.cpp
@@ -102,9 +102,13 @@ class ScriptRegistry
else
{
// The script uses a script name from database, but isn't assigned to anything.
- if (script->GetName().find("Smart") == std::string::npos)
- TC_LOG_ERROR("sql.sql", "Script named '%s' does not have a script name assigned in database.",
- script->GetName().c_str());
+ TC_LOG_ERROR("sql.sql", "Script named '%s' does not have a script name assigned in database.", script->GetName().c_str());
+
+ // Avoid calling "delete script;" because we are currently in the script constructor
+ // In a valid scenario this will not happen because every script has a name assigned in the database
+ // If that happens, it's acceptable to just leak a few bytes
+
+ return;
}
}
else
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index c35dc51b873..55d955428b1 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -3318,6 +3318,11 @@ void SpellMgr::LoadSpellInfoCorrections()
case 17364: // Stormstrike
spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS;
break;
+ case 51798: // Brewfest - Relay Race - Intro - Quest Complete
+ case 47134: // Quest Complete
+ //! HACK: This spell break quest complete for alliance and on retail not used °_O
+ spellInfo->Effects[EFFECT_0].Effect = 0;
+ break;
// ULDUAR SPELLS
//
case 62374: // Pursued (Flame Leviathan)
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 0462148129a..a197ea7caa8 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1607,10 +1607,6 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading Completed Achievements...");
sAchievementMgr->LoadCompletedAchievements();
- // Delete expired auctions before loading
- TC_LOG_INFO("server.loading", "Deleting expired auctions...");
- sAuctionMgr->DeleteExpiredAuctionsAtStartup();
-
///- Load dynamic data tables from the database
TC_LOG_INFO("server.loading", "Loading Item Auctions...");
sAuctionMgr->LoadAuctionItems();
diff --git a/src/server/scripts/Spells/spell_holiday.cpp b/src/server/scripts/Spells/spell_holiday.cpp
index e43249ff8aa..5c84f3045f8 100644
--- a/src/server/scripts/Spells/spell_holiday.cpp
+++ b/src/server/scripts/Spells/spell_holiday.cpp
@@ -430,9 +430,6 @@ class spell_winter_veil_px_238_winter_wondervolt : public SpellScriptLoader
{
OnEffectHitTarget += SpellEffectFn(spell_winter_veil_px_238_winter_wondervolt_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
-
- private:
-
};
SpellScript* GetSpellScript() const override
@@ -738,18 +735,37 @@ class spell_brewfest_dismount_ram : public SpellScriptLoader
enum RamBlub
{
+ // Horde
QUEST_BARK_FOR_DROHNS_DISTILLERY = 11407,
QUEST_BARK_FOR_TCHALIS_VOODOO_BREWERY = 11408,
+ // Alliance
+ QUEST_BARK_BARLEYBREW = 11293,
+ QUEST_BARK_FOR_THUNDERBREWS = 11294,
+
+ // Bark for Drohn's Distillery!
SAY_DROHN_DISTILLERY_1 = 23520,
SAY_DROHN_DISTILLERY_2 = 23521,
SAY_DROHN_DISTILLERY_3 = 23522,
SAY_DROHN_DISTILLERY_4 = 23523,
+ // Bark for T'chali's Voodoo Brewery!
SAY_TCHALIS_VOODOO_1 = 23524,
SAY_TCHALIS_VOODOO_2 = 23525,
SAY_TCHALIS_VOODOO_3 = 23526,
- SAY_TCHALIS_VOODOO_4 = 23527
+ SAY_TCHALIS_VOODOO_4 = 23527,
+
+ // Bark for the Barleybrews!
+ SAY_BARLEYBREW_1 = 23464,
+ SAY_BARLEYBREW_2 = 23465,
+ SAY_BARLEYBREW_3 = 23466,
+ SAY_BARLEYBREW_4 = 22941,
+
+ // Bark for the Thunderbrews!
+ SAY_THUNDERBREWS_1 = 23467,
+ SAY_THUNDERBREWS_2 = 23468,
+ SAY_THUNDERBREWS_3 = 23469,
+ SAY_THUNDERBREWS_4 = 22942
};
// 43259 Brewfest - Barker Bunny 1
@@ -784,6 +800,14 @@ class spell_brewfest_barker_bunny : public SpellScriptLoader
target->GetQuestStatus(QUEST_BARK_FOR_TCHALIS_VOODOO_BREWERY) == QUEST_STATUS_COMPLETE)
BroadcastTextId = RAND(SAY_TCHALIS_VOODOO_1, SAY_TCHALIS_VOODOO_2, SAY_TCHALIS_VOODOO_3, SAY_TCHALIS_VOODOO_4);
+ if (target->GetQuestStatus(QUEST_BARK_BARLEYBREW) == QUEST_STATUS_INCOMPLETE ||
+ target->GetQuestStatus(QUEST_BARK_BARLEYBREW) == QUEST_STATUS_COMPLETE)
+ BroadcastTextId = RAND(SAY_BARLEYBREW_1, SAY_BARLEYBREW_2, SAY_BARLEYBREW_3, SAY_BARLEYBREW_4);
+
+ if (target->GetQuestStatus(QUEST_BARK_FOR_THUNDERBREWS) == QUEST_STATUS_INCOMPLETE ||
+ target->GetQuestStatus(QUEST_BARK_FOR_THUNDERBREWS) == QUEST_STATUS_COMPLETE)
+ BroadcastTextId = RAND(SAY_THUNDERBREWS_1, SAY_THUNDERBREWS_2, SAY_THUNDERBREWS_3, SAY_THUNDERBREWS_4);
+
if (BroadcastTextId)
target->Talk(BroadcastTextId, CHAT_MSG_SAY, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), target);
}
diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
index 328a64dc5b3..e5e563071ec 100644
--- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
@@ -345,9 +345,6 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_INS_GM_SUBSURVEY, "INSERT INTO gm_subsurveys (surveyId, subsurveyId, rank, comment) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_LAG_REPORT, "INSERT INTO lag_reports (guid, lagType, mapId, posX, posY, posZ, latency, createTime) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
- // For loading and deleting expired auctions at startup
- PrepareStatement(CHAR_SEL_EXPIRED_AUCTIONS, "SELECT id, auctioneerguid, itemguid, itemEntry, count, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit FROM auctionhouse ah INNER JOIN item_instance ii ON ii.guid = ah.itemguid WHERE ah.time <= ?", CONNECTION_SYNCH);
-
// LFG Data
PrepareStatement(CHAR_INS_LFG_DATA, "INSERT INTO lfg_data (guid, dungeon, state) VALUES (?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_LFG_DATA, "DELETE FROM lfg_data WHERE guid = ?", CONNECTION_ASYNC);
diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h
index 19b5fef82eb..9bc11e3f525 100644
--- a/src/server/shared/Database/Implementation/CharacterDatabase.h
+++ b/src/server/shared/Database/Implementation/CharacterDatabase.h
@@ -304,8 +304,6 @@ enum CharacterDatabaseStatements
CHAR_INS_GM_SUBSURVEY,
CHAR_INS_LAG_REPORT,
- CHAR_SEL_EXPIRED_AUCTIONS,
-
CHAR_INS_CHARACTER,
CHAR_UPD_CHARACTER,
diff --git a/src/server/shared/Threading/ProducerConsumerQueue.h b/src/server/shared/Threading/ProducerConsumerQueue.h
index a76b8b0b5c0..d0b3631a9dd 100644
--- a/src/server/shared/Threading/ProducerConsumerQueue.h
+++ b/src/server/shared/Threading/ProducerConsumerQueue.h
@@ -82,7 +82,7 @@ public:
void Cancel()
{
- _queueLock.lock();
+ std::unique_lock<std::mutex> lock(_queueLock);
while (!_queue.empty())
{
@@ -95,8 +95,6 @@ public:
_shutdown = true;
- _queueLock.unlock();
-
_condition.notify_all();
}
diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp
index 07101e61eb6..bd028069c62 100644
--- a/src/server/worldserver/Main.cpp
+++ b/src/server/worldserver/Main.cpp
@@ -280,7 +280,20 @@ extern int main(int argc, char** argv)
if (cliThread != nullptr)
{
#ifdef _WIN32
- CancelSynchronousIo(cliThread->native_handle());
+ if (!CancelSynchronousIo(cliThread->native_handle()))
+ {
+ DWORD errorCode = GetLastError();
+ LPSTR errorBuffer;
+
+ DWORD formatReturnCode = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
+ nullptr, errorCode, 0, (LPTSTR)&errorBuffer, 0, nullptr);
+ if (!formatReturnCode)
+ errorBuffer = "Unknown error";
+
+ TC_LOG_ERROR("server.worldserver", "Error cancelling I/O of CliThread, error code %u, detail: %s",
+ errorCode, errorBuffer);
+ LocalFree(errorBuffer);
+ }
#endif
cliThread->join();
delete cliThread;