diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/server/game/AI/SmartScripts/SmartScriptMgr.cpp | 74 | ||||
| -rw-r--r-- | src/server/game/AuctionHouse/AuctionHouseMgr.cpp | 143 | ||||
| -rw-r--r-- | src/server/game/AuctionHouse/AuctionHouseMgr.h | 6 | ||||
| -rw-r--r-- | src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp | 1 | ||||
| -rw-r--r-- | src/server/game/Loot/LootMgr.cpp | 132 | ||||
| -rw-r--r-- | src/server/game/Loot/LootMgr.h | 23 | ||||
| -rw-r--r-- | src/server/game/Maps/TransportMgr.h | 2 | ||||
| -rw-r--r-- | src/server/game/Scripting/ScriptMgr.cpp | 10 | ||||
| -rw-r--r-- | src/server/game/Spells/SpellMgr.cpp | 5 | ||||
| -rw-r--r-- | src/server/game/World/World.cpp | 4 | ||||
| -rw-r--r-- | src/server/scripts/Spells/spell_holiday.cpp | 32 | ||||
| -rw-r--r-- | src/server/shared/Database/Implementation/CharacterDatabase.cpp | 3 | ||||
| -rw-r--r-- | src/server/shared/Database/Implementation/CharacterDatabase.h | 2 | ||||
| -rw-r--r-- | src/server/shared/Threading/ProducerConsumerQueue.h | 4 | ||||
| -rw-r--r-- | src/server/worldserver/Main.cpp | 15 |
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; |
