aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/Define.h2
-rw-r--r--src/server/authserver/authserver.conf.dist1
-rw-r--r--src/server/database/CMakeLists.txt4
-rw-r--r--src/server/database/Database/DatabaseWorkerPool.h4
-rw-r--r--src/server/database/Database/Field.cpp13
-rw-r--r--src/server/database/Database/Field.h80
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.cpp7
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.h29
-rw-r--r--src/server/database/Database/Implementation/LoginDatabase.h28
-rw-r--r--src/server/database/Database/Implementation/WorldDatabase.h28
-rw-r--r--src/server/database/Database/QueryResult.cpp117
-rw-r--r--src/server/database/Database/QueryResult.h11
-rw-r--r--src/server/database/Updater/DBUpdater.cpp125
-rw-r--r--src/server/database/Updater/DBUpdater.h14
-rw-r--r--src/server/game/AI/CoreAI/UnitAI.cpp8
-rw-r--r--src/server/game/AI/CoreAI/UnitAI.h4
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.cpp48
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.h4
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp8
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.cpp1
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.h3
-rw-r--r--src/server/game/AuctionHouse/AuctionHouseMgr.cpp86
-rw-r--r--src/server/game/AuctionHouse/AuctionHouseMgr.h16
-rw-r--r--src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp12
-rw-r--r--src/server/game/Battlefield/Battlefield.cpp2
-rw-r--r--src/server/game/Battlegrounds/Battleground.cpp9
-rw-r--r--src/server/game/Entities/Corpse/Corpse.cpp17
-rw-r--r--src/server/game/Entities/Corpse/Corpse.h1
-rw-r--r--src/server/game/Entities/GameObject/GameObject.h1
-rw-r--r--src/server/game/Entities/Object/Object.cpp2
-rw-r--r--src/server/game/Entities/Player/Player.cpp84
-rw-r--r--src/server/game/Entities/Player/Player.h44
-rw-r--r--src/server/game/Entities/Transport/Transport.cpp3
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp8
-rwxr-xr-xsrc/server/game/Entities/Vehicle/Vehicle.cpp6
-rw-r--r--src/server/game/Entities/Vehicle/VehicleDefines.h3
-rw-r--r--src/server/game/Globals/ObjectAccessor.cpp188
-rw-r--r--src/server/game/Globals/ObjectAccessor.h118
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp16
-rw-r--r--src/server/game/Globals/ObjectMgr.h7
-rw-r--r--src/server/game/Grids/ObjectGridLoader.cpp56
-rw-r--r--src/server/game/Handlers/AuctionHouseHandler.cpp30
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp15
-rw-r--r--src/server/game/Handlers/DuelHandler.cpp3
-rw-r--r--src/server/game/Handlers/MiscHandler.cpp1
-rw-r--r--src/server/game/Handlers/MovementHandler.cpp4
-rw-r--r--src/server/game/Handlers/NPCHandler.cpp10
-rw-r--r--src/server/game/Handlers/QueryHandler.cpp27
-rw-r--r--src/server/game/Maps/Map.cpp116
-rw-r--r--src/server/game/Maps/Map.h24
-rw-r--r--src/server/game/Maps/MapManager.cpp7
-rw-r--r--src/server/game/Miscellaneous/Language.h4
-rw-r--r--src/server/game/Server/WorldSession.cpp28
-rw-r--r--src/server/game/Spells/SpellHistory.cpp17
-rw-r--r--src/server/game/Spells/SpellHistory.h1
-rw-r--r--src/server/game/Tickets/TicketMgr.cpp18
-rw-r--r--src/server/game/Tickets/TicketMgr.h5
-rw-r--r--src/server/game/World/World.cpp12
-rw-r--r--src/server/game/World/World.h3
-rw-r--r--src/server/scripts/Commands/cs_gobject.cpp55
-rw-r--r--src/server/scripts/Commands/cs_instance.cpp4
-rw-r--r--src/server/scripts/Commands/cs_misc.cpp8
-rw-r--r--src/server/scripts/Commands/cs_server.cpp2
-rw-r--r--src/server/scripts/Commands/cs_ticket.cpp5
-rw-r--r--src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp4
-rw-r--r--src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_vaelastrasz.cpp4
-rw-r--r--src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp37
-rw-r--r--src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp42
-rw-r--r--src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp4
-rw-r--r--src/server/scripts/Kalimdor/BlackfathomDeeps/blackfathom_deeps.cpp2
-rw-r--r--src/server/scripts/Kalimdor/zone_azshara.cpp2
-rw-r--r--src/server/scripts/Kalimdor/zone_azuremyst_isle.cpp2
-rw-r--r--src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp4
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp65
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp6
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp4
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp4
-rw-r--r--src/server/scripts/Northrend/zone_grizzly_hills.cpp2
-rw-r--r--src/server/scripts/Northrend/zone_storm_peaks.cpp8
-rw-r--r--src/server/scripts/Northrend/zone_zuldrak.cpp4
-rw-r--r--src/server/scripts/Outland/BlackTemple/black_temple.cpp44
-rw-r--r--src/server/scripts/Outland/BlackTemple/boss_illidan.cpp2
-rw-r--r--src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp4
-rw-r--r--src/server/worldserver/Main.cpp1
-rw-r--r--src/server/worldserver/worldserver.conf.dist8
85 files changed, 962 insertions, 908 deletions
diff --git a/src/common/Define.h b/src/common/Define.h
index 97e07cef8b3..7332bdc4cff 100644
--- a/src/common/Define.h
+++ b/src/common/Define.h
@@ -33,6 +33,8 @@
# endif
# if defined(HELGRIND)
# include <valgrind/helgrind.h>
+# undef _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE
+# undef _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER
# define _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(A) ANNOTATE_HAPPENS_BEFORE(A)
# define _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(A) ANNOTATE_HAPPENS_AFTER(A)
# endif
diff --git a/src/server/authserver/authserver.conf.dist b/src/server/authserver/authserver.conf.dist
index 437ec221e94..1b10fa4e31d 100644
--- a/src/server/authserver/authserver.conf.dist
+++ b/src/server/authserver/authserver.conf.dist
@@ -155,6 +155,7 @@ LoginDatabase.WorkerThreads = 1
# 1 - (Enabled)
Wrong.Password.Login.Logging = 0
+
#
###################################################################################################
diff --git a/src/server/database/CMakeLists.txt b/src/server/database/CMakeLists.txt
index 2375f18d7b5..19fa0ee0acf 100644
--- a/src/server/database/CMakeLists.txt
+++ b/src/server/database/CMakeLists.txt
@@ -8,7 +8,9 @@
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-find_package(MySQL REQUIRED)
+if (NOT MYSQL_FOUND)
+ message(SEND_ERROR "MySQL wasn't found on your system but it's required to build the servers!")
+endif()
if( USE_COREPCH )
include_directories(${CMAKE_CURRENT_BINARY_DIR})
diff --git a/src/server/database/Database/DatabaseWorkerPool.h b/src/server/database/Database/DatabaseWorkerPool.h
index 6a0cf71cca6..32837daf5da 100644
--- a/src/server/database/Database/DatabaseWorkerPool.h
+++ b/src/server/database/Database/DatabaseWorkerPool.h
@@ -428,10 +428,12 @@ class DatabaseWorkerPool
Other
*/
+ typedef typename T::Statements PreparedStatementIndex;
+
//! Automanaged (internally) pointer to a prepared statement object for usage in upper level code.
//! Pointer is deleted in this->DirectExecute(PreparedStatement*), this->Query(PreparedStatement*) or PreparedStatementTask::~PreparedStatementTask.
//! This object is not tied to the prepared statement on the MySQL context yet until execution.
- PreparedStatement* GetPreparedStatement(uint32 index)
+ PreparedStatement* GetPreparedStatement(PreparedStatementIndex index)
{
return new PreparedStatement(index);
}
diff --git a/src/server/database/Database/Field.cpp b/src/server/database/Database/Field.cpp
index 89195b699b7..f7794bd8975 100644
--- a/src/server/database/Database/Field.cpp
+++ b/src/server/database/Database/Field.cpp
@@ -30,18 +30,11 @@ Field::~Field()
CleanUp();
}
-void Field::SetByteValue(const void* newValue, const size_t newSize, enum_field_types newType, uint32 length)
+void Field::SetByteValue(void* newValue, enum_field_types newType, uint32 length)
{
- if (data.value)
- CleanUp();
-
// This value stores raw bytes that have to be explicitly cast later
- if (newValue)
- {
- data.value = new char[newSize];
- memcpy(data.value, newValue, newSize);
- data.length = length;
- }
+ data.value = newValue;
+ data.length = length;
data.type = newType;
data.raw = true;
}
diff --git a/src/server/database/Database/Field.h b/src/server/database/Database/Field.h
index 1bbd264482f..42a842e6283 100644
--- a/src/server/database/Database/Field.h
+++ b/src/server/database/Database/Field.h
@@ -29,6 +29,8 @@ class Field
friend class PreparedResultSet;
public:
+ Field();
+ ~Field();
bool GetBool() const // Wrapper, actually gets integer
{
@@ -43,7 +45,8 @@ class Field
#ifdef TRINITY_DEBUG
if (!IsType(MYSQL_TYPE_TINY))
{
- TC_LOG_WARN("sql.sql", "Warning: GetUInt8() on non-tinyint field. Using type: %s.", FieldTypeToString(data.type));
+ TC_LOG_WARN("sql.sql", "Warning: GetUInt8() on non-tinyint field %s.%s (%s.%s) at index %u. Using type: %s.",
+ meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type);
return 0;
}
#endif
@@ -61,7 +64,8 @@ class Field
#ifdef TRINITY_DEBUG
if (!IsType(MYSQL_TYPE_TINY))
{
- TC_LOG_WARN("sql.sql", "Warning: GetInt8() on non-tinyint field. Using type: %s.", FieldTypeToString(data.type));
+ TC_LOG_WARN("sql.sql", "Warning: GetInt8() on non-tinyint field %s.%s (%s.%s) at index %u. Using type: %s.",
+ meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type);
return 0;
}
#endif
@@ -79,7 +83,8 @@ class Field
#ifdef TRINITY_DEBUG
if (!IsType(MYSQL_TYPE_SHORT) && !IsType(MYSQL_TYPE_YEAR))
{
- TC_LOG_WARN("sql.sql", "Warning: GetUInt16() on non-smallint field. Using type: %s.", FieldTypeToString(data.type));
+ TC_LOG_WARN("sql.sql", "Warning: GetUInt16() on non-smallint field %s.%s (%s.%s) at index %u. Using type: %s.",
+ meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type);
return 0;
}
#endif
@@ -97,7 +102,8 @@ class Field
#ifdef TRINITY_DEBUG
if (!IsType(MYSQL_TYPE_SHORT) && !IsType(MYSQL_TYPE_YEAR))
{
- TC_LOG_WARN("sql.sql", "Warning: GetInt16() on non-smallint field. Using type: %s.", FieldTypeToString(data.type));
+ TC_LOG_WARN("sql.sql", "Warning: GetInt16() on non-smallint field %s.%s (%s.%s) at index %u. Using type: %s.",
+ meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type);
return 0;
}
#endif
@@ -115,7 +121,8 @@ class Field
#ifdef TRINITY_DEBUG
if (!IsType(MYSQL_TYPE_INT24) && !IsType(MYSQL_TYPE_LONG))
{
- TC_LOG_WARN("sql.sql", "Warning: GetUInt32() on non-(medium)int field. Using type: %s.", FieldTypeToString(data.type));
+ TC_LOG_WARN("sql.sql", "Warning: GetUInt32() on non-(medium)int field %s.%s (%s.%s) at index %u. Using type: %s.",
+ meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type);
return 0;
}
#endif
@@ -133,7 +140,8 @@ class Field
#ifdef TRINITY_DEBUG
if (!IsType(MYSQL_TYPE_INT24) && !IsType(MYSQL_TYPE_LONG))
{
- TC_LOG_WARN("sql.sql", "Warning: GetInt32() on non-(medium)int field. Using type: %s.", FieldTypeToString(data.type));
+ TC_LOG_WARN("sql.sql", "Warning: GetInt32() on non-(medium)int field %s.%s (%s.%s) at index %u. Using type: %s.",
+ meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type);
return 0;
}
#endif
@@ -151,7 +159,8 @@ class Field
#ifdef TRINITY_DEBUG
if (!IsType(MYSQL_TYPE_LONGLONG) && !IsType(MYSQL_TYPE_BIT))
{
- TC_LOG_WARN("sql.sql", "Warning: GetUInt64() on non-bigint field. Using type: %s.", FieldTypeToString(data.type));
+ TC_LOG_WARN("sql.sql", "Warning: GetUInt64() on non-bigint field %s.%s (%s.%s) at index %u. Using type: %s.",
+ meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type);
return 0;
}
#endif
@@ -169,7 +178,8 @@ class Field
#ifdef TRINITY_DEBUG
if (!IsType(MYSQL_TYPE_LONGLONG) && !IsType(MYSQL_TYPE_BIT))
{
- TC_LOG_WARN("sql.sql", "Warning: GetInt64() on non-bigint field. Using type: %s.", FieldTypeToString(data.type));
+ TC_LOG_WARN("sql.sql", "Warning: GetInt64() on non-bigint field %s.%s (%s.%s) at index %u. Using type: %s.",
+ meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type);
return 0;
}
#endif
@@ -187,7 +197,8 @@ class Field
#ifdef TRINITY_DEBUG
if (!IsType(MYSQL_TYPE_FLOAT))
{
- TC_LOG_WARN("sql.sql", "Warning: GetFloat() on non-float field. Using type: %s.", FieldTypeToString(data.type));
+ TC_LOG_WARN("sql.sql", "Warning: GetFloat() on non-float field %s.%s (%s.%s) at index %u. Using type: %s.",
+ meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type);
return 0.0f;
}
#endif
@@ -205,7 +216,8 @@ class Field
#ifdef TRINITY_DEBUG
if (!IsType(MYSQL_TYPE_DOUBLE))
{
- TC_LOG_WARN("sql.sql", "Warning: GetDouble() on non-double field. Using type: %s.", FieldTypeToString(data.type));
+ TC_LOG_WARN("sql.sql", "Warning: GetDouble() on non-double field %s.%s (%s.%s) at index %u. Using type: %s.",
+ meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type);
return 0.0f;
}
#endif
@@ -223,7 +235,8 @@ class Field
#ifdef TRINITY_DEBUG
if (IsNumeric())
{
- TC_LOG_WARN("sql.sql", "Error: GetCString() on numeric field. Using type: %s.", FieldTypeToString(data.type));
+ TC_LOG_WARN("sql.sql", "Error: GetCString() on numeric field %s.%s (%s.%s) at index %u. Using type: %s.",
+ meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type);
return NULL;
}
#endif
@@ -236,14 +249,11 @@ class Field
if (!data.value)
return "";
- if (data.raw)
- {
- char const* string = GetCString();
- if (!string)
- string = "";
- return std::string(string, data.length);
- }
- return std::string((char*)data.value);
+ char const* string = GetCString();
+ if (!string)
+ return "";
+
+ return std::string(string, data.length);
}
bool IsNull() const
@@ -251,10 +261,17 @@ class Field
return data.value == NULL;
}
- protected:
- Field();
- ~Field();
+ struct Metadata
+ {
+ char const* TableName;
+ char const* TableAlias;
+ char const* Name;
+ char const* Alias;
+ char const* Type;
+ uint32 Index;
+ };
+ protected:
#pragma pack(push, 1)
struct
{
@@ -265,12 +282,14 @@ class Field
} data;
#pragma pack(pop)
- void SetByteValue(void const* newValue, size_t const newSize, enum_field_types newType, uint32 length);
+ void SetByteValue(void* newValue, enum_field_types newType, uint32 length);
void SetStructuredValue(char* newValue, enum_field_types newType);
void CleanUp()
{
- delete[] ((char*)data.value);
+ // Field does not own the data if fetched with prepared statement
+ if (!data.raw)
+ delete[] ((char*)data.value);
data.value = NULL;
}
@@ -375,6 +394,19 @@ class Field
default: return "-Unknown-";
}
}
+
+ void SetMetadata(MYSQL_FIELD* field, uint32 fieldIndex)
+ {
+ meta.TableName = field->org_table;
+ meta.TableAlias = field->table;
+ meta.Name = field->org_name;
+ meta.Alias = field->name;
+ meta.Type = FieldTypeToString(field->type);
+ meta.Index = fieldIndex;
+ }
+
+ Metadata meta;
+
#endif
};
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp
index 6494f92b522..14e7571dd42 100644
--- a/src/server/database/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp
@@ -127,8 +127,8 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_SEL_CHARACTER_ACTIONS_SPEC, "SELECT button, action, type FROM character_action WHERE guid = ? AND spec = ? ORDER BY button", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_MAILITEMS, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, item_guid, itemEntry, owner_guid FROM mail_items mi JOIN item_instance ii ON mi.item_guid = ii.guid WHERE mail_id = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_AUCTION_ITEMS, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, itemguid, itemEntry FROM auctionhouse ah JOIN item_instance ii ON ah.itemguid = ii.guid", CONNECTION_SYNCH);
- PrepareStatement(CHAR_SEL_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", CONNECTION_SYNCH);
- PrepareStatement(CHAR_INS_AUCTION, "INSERT INTO auctionhouse (id, auctioneerguid, itemguid, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_SEL_AUCTIONS, "SELECT id, houseid, itemguid, itemEntry, count, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit FROM auctionhouse ah INNER JOIN item_instance ii ON ii.guid = ah.itemguid", CONNECTION_SYNCH);
+ PrepareStatement(CHAR_INS_AUCTION, "INSERT INTO auctionhouse (id, houseid, itemguid, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_AUCTION, "DELETE FROM auctionhouse WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_AUCTION_BID, "UPDATE auctionhouse SET buyguid = ?, lastbid = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_MAIL, "INSERT INTO mail(id, messageType, stationery, mailTemplateId, sender, receiver, subject, body, has_items, expire_time, deliver_time, money, cod, checked) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
@@ -320,6 +320,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_INS_CORPSE, "INSERT INTO corpse (guid, posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, guildId, flags, dynFlags, time, corpseType, instanceId, phaseMask) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CORPSE, "DELETE FROM corpse WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CORPSES_FROM_MAP, "DELETE FROM corpse WHERE mapId = ? AND instanceId = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_SEL_CORPSE_LOCATION, "SELECT mapId, posX, posY, posZ, orientation FROM corpse WHERE guid = ?", CONNECTION_ASYNC);
// Creature respawn
PrepareStatement(CHAR_SEL_CREATURE_RESPAWNS, "SELECT guid, respawnTime FROM creature_respawn WHERE mapId = ? AND instanceId = ?", CONNECTION_SYNCH);
@@ -336,7 +337,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
// GM Tickets
PrepareStatement(CHAR_SEL_GM_TICKETS, "SELECT id, playerGuid, name, description, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, needMoreHelp FROM gm_ticket", CONNECTION_SYNCH);
- PrepareStatement(CHAR_REP_GM_TICKET, "REPLACE INTO gm_ticket (id, playerGuid, name, description, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, needMoreHelp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_REP_GM_TICKET, "REPLACE INTO gm_ticket (id, playerGuid, name, description, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, needMoreHelp, resolvedBy) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_GM_TICKET, "DELETE FROM gm_ticket WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_PLAYER_GM_TICKETS, "DELETE FROM gm_ticket WHERE playerGuid = ?", CONNECTION_ASYNC);
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.h b/src/server/database/Database/Implementation/CharacterDatabase.h
index a7ab5d00cb3..c76c584a0a8 100644
--- a/src/server/database/Database/Implementation/CharacterDatabase.h
+++ b/src/server/database/Database/Implementation/CharacterDatabase.h
@@ -21,19 +21,6 @@
#include "DatabaseWorkerPool.h"
#include "MySQLConnection.h"
-class CharacterDatabaseConnection : public MySQLConnection
-{
- public:
- //- Constructors for sync and async connections
- CharacterDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo) { }
- CharacterDatabaseConnection(ProducerConsumerQueue<SQLOperation*>* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo) { }
-
- //- Loads database type specific prepared statements
- void DoPrepareStatements() override;
-};
-
-typedef DatabaseWorkerPool<CharacterDatabaseConnection> CharacterDatabaseWorkerPool;
-
enum CharacterDatabaseStatements
{
/* Naming standard for defines:
@@ -282,6 +269,7 @@ enum CharacterDatabaseStatements
CHAR_INS_CORPSE,
CHAR_DEL_CORPSE,
CHAR_DEL_CORPSES_FROM_MAP,
+ CHAR_SEL_CORPSE_LOCATION,
CHAR_SEL_CREATURE_RESPAWNS,
CHAR_REP_CREATURE_RESPAWN,
@@ -546,4 +534,19 @@ enum CharacterDatabaseStatements
MAX_CHARACTERDATABASE_STATEMENTS
};
+class CharacterDatabaseConnection : public MySQLConnection
+{
+public:
+ typedef CharacterDatabaseStatements Statements;
+
+ //- Constructors for sync and async connections
+ CharacterDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo) { }
+ CharacterDatabaseConnection(ProducerConsumerQueue<SQLOperation*>* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo) { }
+
+ //- Loads database type specific prepared statements
+ void DoPrepareStatements() override;
+};
+
+typedef DatabaseWorkerPool<CharacterDatabaseConnection> CharacterDatabaseWorkerPool;
+
#endif
diff --git a/src/server/database/Database/Implementation/LoginDatabase.h b/src/server/database/Database/Implementation/LoginDatabase.h
index 7f6cffa520f..79b7a53cb6e 100644
--- a/src/server/database/Database/Implementation/LoginDatabase.h
+++ b/src/server/database/Database/Implementation/LoginDatabase.h
@@ -21,19 +21,6 @@
#include "DatabaseWorkerPool.h"
#include "MySQLConnection.h"
-class LoginDatabaseConnection : public MySQLConnection
-{
- public:
- //- Constructors for sync and async connections
- LoginDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo) { }
- LoginDatabaseConnection(ProducerConsumerQueue<SQLOperation*>* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo) { }
-
- //- Loads database type specific prepared statements
- void DoPrepareStatements() override;
-};
-
-typedef DatabaseWorkerPool<LoginDatabaseConnection> LoginDatabaseWorkerPool;
-
enum LoginDatabaseStatements
{
/* Naming standard for defines:
@@ -133,4 +120,19 @@ enum LoginDatabaseStatements
MAX_LOGINDATABASE_STATEMENTS
};
+class LoginDatabaseConnection : public MySQLConnection
+{
+public:
+ typedef LoginDatabaseStatements Statements;
+
+ //- Constructors for sync and async connections
+ LoginDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo) { }
+ LoginDatabaseConnection(ProducerConsumerQueue<SQLOperation*>* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo) { }
+
+ //- Loads database type specific prepared statements
+ void DoPrepareStatements() override;
+};
+
+typedef DatabaseWorkerPool<LoginDatabaseConnection> LoginDatabaseWorkerPool;
+
#endif
diff --git a/src/server/database/Database/Implementation/WorldDatabase.h b/src/server/database/Database/Implementation/WorldDatabase.h
index 36fd6fbb186..c5475835fbd 100644
--- a/src/server/database/Database/Implementation/WorldDatabase.h
+++ b/src/server/database/Database/Implementation/WorldDatabase.h
@@ -21,19 +21,6 @@
#include "DatabaseWorkerPool.h"
#include "MySQLConnection.h"
-class WorldDatabaseConnection : public MySQLConnection
-{
- public:
- //- Constructors for sync and async connections
- WorldDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo) { }
- WorldDatabaseConnection(ProducerConsumerQueue<SQLOperation*>* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo) { }
-
- //- Loads database type specific prepared statements
- void DoPrepareStatements() override;
-};
-
-typedef DatabaseWorkerPool<WorldDatabaseConnection> WorldDatabaseWorkerPool;
-
enum WorldDatabaseStatements
{
/* Naming standard for defines:
@@ -116,4 +103,19 @@ enum WorldDatabaseStatements
MAX_WORLDDATABASE_STATEMENTS
};
+class WorldDatabaseConnection : public MySQLConnection
+{
+public:
+ typedef WorldDatabaseStatements Statements;
+
+ //- Constructors for sync and async connections
+ WorldDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo) { }
+ WorldDatabaseConnection(ProducerConsumerQueue<SQLOperation*>* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo) { }
+
+ //- Loads database type specific prepared statements
+ void DoPrepareStatements() override;
+};
+
+typedef DatabaseWorkerPool<WorldDatabaseConnection> WorldDatabaseWorkerPool;
+
#endif
diff --git a/src/server/database/Database/QueryResult.cpp b/src/server/database/Database/QueryResult.cpp
index 02352f221a0..983ffee24c4 100644
--- a/src/server/database/Database/QueryResult.cpp
+++ b/src/server/database/Database/QueryResult.cpp
@@ -26,7 +26,10 @@ _result(result),
_fields(fields)
{
_currentRow = new Field[_fieldCount];
- ASSERT(_currentRow);
+#ifdef TRINITY_DEBUG
+ for (uint32 i = 0; i < _fieldCount; i++)
+ _currentRow[i].SetMetadata(&_fields[i], i);
+#endif
}
PreparedResultSet::PreparedResultSet(MYSQL_STMT* stmt, MYSQL_RES *result, uint64 rowCount, uint32 fieldCount) :
@@ -35,11 +38,11 @@ m_rowPosition(0),
m_fieldCount(fieldCount),
m_rBind(NULL),
m_stmt(stmt),
-m_res(result),
+m_metadataResult(result),
m_isNull(NULL),
m_length(NULL)
{
- if (!m_res)
+ if (!m_metadataResult)
return;
if (m_stmt->bind_result_done)
@@ -66,50 +69,52 @@ m_length(NULL)
return;
}
+ m_rowCount = mysql_stmt_num_rows(m_stmt);
+
//- This is where we prepare the buffer based on metadata
- uint32 i = 0;
- MYSQL_FIELD* field = mysql_fetch_field(m_res);
- while (field)
+ MYSQL_FIELD* field = mysql_fetch_fields(m_metadataResult);
+ std::size_t rowSize = 0;
+ for (uint32 i = 0; i < m_fieldCount; ++i)
{
- size_t size = Field::SizeForType(field);
+ size_t size = Field::SizeForType(&field[i]);
+ rowSize += size;
- m_rBind[i].buffer_type = field->type;
- m_rBind[i].buffer = malloc(size);
- memset(m_rBind[i].buffer, 0, size);
+ m_rBind[i].buffer_type = field[i].type;
m_rBind[i].buffer_length = size;
m_rBind[i].length = &m_length[i];
m_rBind[i].is_null = &m_isNull[i];
m_rBind[i].error = NULL;
- m_rBind[i].is_unsigned = field->flags & UNSIGNED_FLAG;
+ m_rBind[i].is_unsigned = field[i].flags & UNSIGNED_FLAG;
+ }
- ++i;
- field = mysql_fetch_field(m_res);
+ char* dataBuffer = new char[rowSize * m_rowCount];
+ for (uint32 i = 0, offset = 0; i < m_fieldCount; ++i)
+ {
+ m_rBind[i].buffer = dataBuffer + offset;
+ offset += m_rBind[i].buffer_length;
}
//- This is where we bind the bind the buffer to the statement
if (mysql_stmt_bind_result(m_stmt, m_rBind))
{
TC_LOG_WARN("sql.sql", "%s:mysql_stmt_bind_result, cannot bind result from MySQL server. Error: %s", __FUNCTION__, mysql_stmt_error(m_stmt));
- delete[] m_rBind;
+ mysql_stmt_free_result(m_stmt);
+ CleanUp();
delete[] m_isNull;
delete[] m_length;
return;
}
- m_rowCount = mysql_stmt_num_rows(m_stmt);
-
- m_rows.resize(uint32(m_rowCount));
+ m_rows.resize(uint32(m_rowCount) * m_fieldCount);
while (_NextRow())
{
- m_rows[uint32(m_rowPosition)] = new Field[m_fieldCount];
- for (uint64 fIndex = 0; fIndex < m_fieldCount; ++fIndex)
+ for (uint32 fIndex = 0; fIndex < m_fieldCount; ++fIndex)
{
+ unsigned long buffer_length = m_rBind[fIndex].buffer_length;
+ unsigned long fetched_length = *m_rBind[fIndex].length;
if (!*m_rBind[fIndex].is_null)
- m_rows[uint32(m_rowPosition)][fIndex].SetByteValue(m_rBind[fIndex].buffer,
- m_rBind[fIndex].buffer_length,
- m_rBind[fIndex].buffer_type,
- *m_rBind[fIndex].length);
- else
+ {
+ void* buffer = m_stmt->bind[fIndex].buffer;
switch (m_rBind[fIndex].buffer_type)
{
case MYSQL_TYPE_TINY_BLOB:
@@ -118,24 +123,44 @@ m_length(NULL)
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_STRING:
case MYSQL_TYPE_VAR_STRING:
- m_rows[uint32(m_rowPosition)][fIndex].SetByteValue("",
- m_rBind[fIndex].buffer_length,
- m_rBind[fIndex].buffer_type,
- *m_rBind[fIndex].length);
- break;
+ // warning - the string will not be null-terminated if there is no space for it in the buffer
+ // when mysql_stmt_fetch returned MYSQL_DATA_TRUNCATED
+ // we cannot blindly null-terminate the data either as it may be retrieved as binary blob and not specifically a string
+ // in this case using Field::GetCString will result in garbage
+ // TODO: remove Field::GetCString and use boost::string_ref (currently proposed for TS as string_view, maybe in C++17)
+ if (fetched_length < buffer_length)
+ *((char*)buffer + fetched_length) = '\0';
+ break;
default:
- m_rows[uint32(m_rowPosition)][fIndex].SetByteValue(nullptr,
- m_rBind[fIndex].buffer_length,
- m_rBind[fIndex].buffer_type,
- *m_rBind[fIndex].length);
+ break;
}
+
+ m_rows[uint32(m_rowPosition) * m_fieldCount + fIndex].SetByteValue(
+ buffer,
+ m_rBind[fIndex].buffer_type,
+ fetched_length);
+
+ // move buffer pointer to next part
+ m_stmt->bind[fIndex].buffer = (char*)buffer + rowSize;
+ }
+ else
+ {
+ m_rows[uint32(m_rowPosition) * m_fieldCount + fIndex].SetByteValue(
+ nullptr,
+ m_rBind[fIndex].buffer_type,
+ *m_rBind[fIndex].length);
+ }
+
+#ifdef TRINITY_DEBUG
+ m_rows[uint32(m_rowPosition) * m_fieldCount + fIndex].SetMetadata(&field[fIndex], fIndex);
+#endif
}
m_rowPosition++;
}
m_rowPosition = 0;
/// All data is buffered, let go of mysql c api structures
- CleanUp();
+ mysql_stmt_free_result(m_stmt);
}
ResultSet::~ResultSet()
@@ -145,8 +170,7 @@ ResultSet::~ResultSet()
PreparedResultSet::~PreparedResultSet()
{
- for (uint32 i = 0; i < uint32(m_rowCount); ++i)
- delete[] m_rows[i];
+ CleanUp();
}
bool ResultSet::NextRow()
@@ -207,18 +231,13 @@ void ResultSet::CleanUp()
void PreparedResultSet::CleanUp()
{
- /// More of the in our code allocated sources are deallocated by the poorly documented mysql c api
- if (m_res)
- mysql_free_result(m_res);
+ if (m_metadataResult)
+ mysql_free_result(m_metadataResult);
- FreeBindBuffer();
- mysql_stmt_free_result(m_stmt);
-
- delete[] m_rBind;
-}
-
-void PreparedResultSet::FreeBindBuffer()
-{
- for (uint32 i = 0; i < m_fieldCount; ++i)
- free (m_rBind[i].buffer);
+ if (m_rBind)
+ {
+ delete[](char*)m_rBind->buffer;
+ delete[] m_rBind;
+ m_rBind = nullptr;
+ }
}
diff --git a/src/server/database/Database/QueryResult.h b/src/server/database/Database/QueryResult.h
index a61fb6331c1..0447ecaae5a 100644
--- a/src/server/database/Database/QueryResult.h
+++ b/src/server/database/Database/QueryResult.h
@@ -73,18 +73,18 @@ class PreparedResultSet
Field* Fetch() const
{
ASSERT(m_rowPosition < m_rowCount);
- return m_rows[uint32(m_rowPosition)];
+ return const_cast<Field*>(&m_rows[uint32(m_rowPosition) * m_fieldCount]);
}
- const Field & operator [] (uint32 index) const
+ Field const& operator[](uint32 index) const
{
ASSERT(m_rowPosition < m_rowCount);
ASSERT(index < m_fieldCount);
- return m_rows[uint32(m_rowPosition)][index];
+ return m_rows[uint32(m_rowPosition) * m_fieldCount + index];
}
protected:
- std::vector<Field*> m_rows;
+ std::vector<Field> m_rows;
uint64 m_rowCount;
uint64 m_rowPosition;
uint32 m_fieldCount;
@@ -92,12 +92,11 @@ class PreparedResultSet
private:
MYSQL_BIND* m_rBind;
MYSQL_STMT* m_stmt;
- MYSQL_RES* m_res;
+ MYSQL_RES* m_metadataResult; ///< Field metadata, returned by mysql_stmt_result_metadata
my_bool* m_isNull;
unsigned long* m_length;
- void FreeBindBuffer();
void CleanUp();
bool _NextRow();
diff --git a/src/server/database/Updater/DBUpdater.cpp b/src/server/database/Updater/DBUpdater.cpp
index ebdd6604fef..d90d71c5594 100644
--- a/src/server/database/Updater/DBUpdater.cpp
+++ b/src/server/database/Updater/DBUpdater.cpp
@@ -26,6 +26,8 @@
#include <iostream>
#include <unordered_map>
#include <boost/process.hpp>
+#include <boost/iostreams/stream.hpp>
+#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/system/system_error.hpp>
@@ -33,24 +35,64 @@ using namespace boost::process;
using namespace boost::process::initializers;
using namespace boost::iostreams;
-template<class T>
-std::string DBUpdater<T>::GetSourceDirectory()
+std::string DBUpdaterUtil::GetMySqlCli()
{
- std::string const entry = sConfigMgr->GetStringDefault("Updates.SourcePath", "");
- if (!entry.empty())
- return entry;
+ if (!corrected_path().empty())
+ return corrected_path();
else
- return GitRevision::GetSourceDirectory();
+ {
+ std::string const entry = sConfigMgr->GetStringDefault("Updates.MySqlCLIPath", "");
+ if (!entry.empty())
+ return entry;
+ else
+ return GitRevision::GetMySQLExecutable();
+ }
+}
+
+bool DBUpdaterUtil::CheckExecutable()
+{
+ boost::filesystem::path exe(GetMySqlCli());
+ if (!exists(exe))
+ {
+ exe.clear();
+
+ try
+ {
+ exe = search_path("mysql");
+ }
+ catch (std::runtime_error&)
+ {
+ }
+
+ if (!exe.empty() && exists(exe))
+ {
+ // Correct the path to the cli
+ corrected_path() = absolute(exe).generic_string();
+ return true;
+ }
+
+ TC_LOG_FATAL("sql.updates", "Didn't find executeable mysql binary at \'%s\' or in path, correct the path in the *.conf (\"Updates.MySqlCLIPath\").",
+ absolute(exe).generic_string().c_str());
+
+ return false;
+ }
+ return true;
+}
+
+std::string& DBUpdaterUtil::corrected_path()
+{
+ static std::string path;
+ return path;
}
template<class T>
-std::string DBUpdater<T>::GetMySqlCli()
+std::string DBUpdater<T>::GetSourceDirectory()
{
- std::string const entry = sConfigMgr->GetStringDefault("Updates.MySqlCLIPath", "");
+ std::string const entry = sConfigMgr->GetStringDefault("Updates.SourcePath", "");
if (!entry.empty())
return entry;
else
- return GitRevision::GetMySQLExecutable();
+ return GitRevision::GetSourceDirectory();
}
// Auth Database
@@ -145,36 +187,6 @@ BaseLocation DBUpdater<T>::GetBaseLocationType()
}
template<class T>
-bool DBUpdater<T>::CheckExecutable()
-{
- DBUpdater<T>::Path const exe(DBUpdater<T>::GetMySqlCli());
- if (!exists(exe))
- {
- // Check for mysql in path
- std::vector<std::string> args = {"--version"};
- uint32 ret;
- try
- {
- child c = execute(run_exe("mysql"), set_args(args), throw_on_error(), close_stdout());
- ret = wait_for_exit(c);
- }
- catch (boost::system::system_error&)
- {
- ret = EXIT_FAILURE;
- }
-
- if (ret == EXIT_FAILURE)
- {
- TC_LOG_FATAL("sql.updates", "Didn't find executeable mysql binary at \'%s\', correct the path in the *.conf (\"Updates.MySqlCLIPath\").",
- absolute(exe).generic_string().c_str());
-
- return false;
- }
- }
- return true;
-}
-
-template<class T>
bool DBUpdater<T>::Create(DatabaseWorkerPool<T>& pool)
{
TC_LOG_INFO("sql.updates", "Database \"%s\" does not exist, do you want to create it? [yes (default) / no]: ",
@@ -222,7 +234,7 @@ bool DBUpdater<T>::Create(DatabaseWorkerPool<T>& pool)
template<class T>
bool DBUpdater<T>::Update(DatabaseWorkerPool<T>& pool)
{
- if (!DBUpdater<T>::CheckExecutable())
+ if (!DBUpdaterUtil::CheckExecutable())
return false;
TC_LOG_INFO("sql.updates", "Updating %s database...", DBUpdater<T>::GetTableName().c_str());
@@ -273,7 +285,7 @@ bool DBUpdater<T>::Populate(DatabaseWorkerPool<T>& pool)
return true;
}
- if (!DBUpdater<T>::CheckExecutable())
+ if (!DBUpdaterUtil::CheckExecutable())
return false;
TC_LOG_INFO("sql.updates", "Database %s is empty, auto populating it...", DBUpdater<T>::GetTableName().c_str());
@@ -346,7 +358,10 @@ void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& hos
std::string const& password, std::string const& port_or_socket, std::string const& database, Path const& path)
{
std::vector<std::string> args;
- args.reserve(7);
+ args.reserve(8);
+
+ // args[0] represents the program name
+ args.push_back("mysql");
// CLI Client connection info
args.push_back("-h" + host);
@@ -391,9 +406,29 @@ void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& hos
uint32 ret;
try
{
- child c = execute(run_exe(DBUpdater<T>::GetMySqlCli().empty() ? "mysql" :
- boost::filesystem::absolute(DBUpdater<T>::GetMySqlCli()).generic_string()),
- set_args(args), bind_stdin(source), throw_on_error());
+ boost::process::pipe outPipe = create_pipe();
+ boost::process::pipe errPipe = create_pipe();
+
+ child c = execute(run_exe(
+ boost::filesystem::absolute(DBUpdaterUtil::GetMySqlCli()).generic_string()),
+ set_args(args), bind_stdin(source), throw_on_error(),
+ bind_stdout(file_descriptor_sink(outPipe.sink, close_handle)),
+ bind_stderr(file_descriptor_sink(errPipe.sink, close_handle)));
+
+ file_descriptor_source mysqlOutfd(outPipe.source, close_handle);
+ file_descriptor_source mysqlErrfd(errPipe.source, close_handle);
+
+ stream<file_descriptor_source> mysqlOutStream(mysqlOutfd);
+ stream<file_descriptor_source> mysqlErrStream(mysqlErrfd);
+
+ std::stringstream out;
+ std::stringstream err;
+
+ copy(mysqlOutStream, out);
+ copy(mysqlErrStream, err);
+
+ TC_LOG_INFO("sql.updates", "%s", out.str().c_str());
+ TC_LOG_ERROR("sql.updates", "%s", err.str().c_str());
ret = wait_for_exit(c);
}
diff --git a/src/server/database/Updater/DBUpdater.h b/src/server/database/Updater/DBUpdater.h
index a2b12bed235..c8aa5d69fbc 100644
--- a/src/server/database/Updater/DBUpdater.h
+++ b/src/server/database/Updater/DBUpdater.h
@@ -54,6 +54,17 @@ struct UpdateResult
size_t archived;
};
+class DBUpdaterUtil
+{
+public:
+ static std::string GetMySqlCli();
+
+ static bool CheckExecutable();
+
+private:
+ static std::string& corrected_path();
+};
+
template <class T>
class DBUpdater
{
@@ -79,9 +90,6 @@ public:
static bool Populate(DatabaseWorkerPool<T>& pool);
private:
- static std::string GetMySqlCli();
- static bool CheckExecutable();
-
static QueryResult Retrieve(DatabaseWorkerPool<T>& pool, std::string const& query);
static void Apply(DatabaseWorkerPool<T>& pool, std::string const& query);
static void ApplyFile(DatabaseWorkerPool<T>& pool, Path const& path);
diff --git a/src/server/game/AI/CoreAI/UnitAI.cpp b/src/server/game/AI/CoreAI/UnitAI.cpp
index 5aa6ea8ea7a..f0d9d34db69 100644
--- a/src/server/game/AI/CoreAI/UnitAI.cpp
+++ b/src/server/game/AI/CoreAI/UnitAI.cpp
@@ -29,7 +29,15 @@
void UnitAI::AttackStart(Unit* victim)
{
if (victim && me->Attack(victim, true))
+ {
+ // Clear distracted state on attacking
+ if (me->HasUnitState(UNIT_STATE_DISTRACTED))
+ {
+ me->ClearUnitState(UNIT_STATE_DISTRACTED);
+ me->GetMotionMaster()->Clear();
+ }
me->GetMotionMaster()->MoveChase(victim);
+ }
}
void UnitAI::AttackStartCaster(Unit* victim, float dist)
diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h
index 1939c96dac9..c93ed0db008 100644
--- a/src/server/game/AI/CoreAI/UnitAI.h
+++ b/src/server/game/AI/CoreAI/UnitAI.h
@@ -255,8 +255,8 @@ class UnitAI
static void FillAISpellInfo();
virtual void sGossipHello(Player* /*player*/) { }
- virtual void sGossipSelect(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/) { }
- virtual void sGossipSelectCode(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/, char const* /*code*/) { }
+ virtual void sGossipSelect(Player* /*player*/, uint32 /*menuId*/, uint32 /*gossipListId*/) { }
+ virtual void sGossipSelectCode(Player* /*player*/, uint32 /*menuId*/, uint32 /*gossipListId*/, char const* /*code*/) { }
virtual void sQuestAccept(Player* /*player*/, Quest const* /*quest*/) { }
virtual void sQuestSelect(Player* /*player*/, Quest const* /*quest*/) { }
virtual void sQuestReward(Player* /*player*/, Quest const* /*quest*/, uint32 /*opt*/) { }
diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp
index 1a51bb2d897..46cf934356d 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.cpp
+++ b/src/server/game/AI/SmartScripts/SmartAI.cpp
@@ -208,7 +208,7 @@ void SmartAI::EndPath(bool fail)
if (targets->size() == 1 && GetScript()->IsPlayer((*targets->begin())))
{
Player* player = (*targets->begin())->ToPlayer();
- if (!fail && player->IsAtGroupRewardDistance(me) && !player->GetCorpse())
+ if (!fail && player->IsAtGroupRewardDistance(me) && !player->HasCorpse())
player->GroupEventHappens(mEscortQuestID, me);
if (fail && player->GetQuestStatus(mEscortQuestID) == QUEST_STATUS_INCOMPLETE)
@@ -220,7 +220,7 @@ void SmartAI::EndPath(bool fail)
{
Player* groupGuy = groupRef->GetSource();
- if (!fail && groupGuy->IsAtGroupRewardDistance(me) && !groupGuy->GetCorpse())
+ if (!fail && groupGuy->IsAtGroupRewardDistance(me) && !groupGuy->HasCorpse())
groupGuy->AreaExploredOrEventHappens(mEscortQuestID);
if (fail && groupGuy->GetQuestStatus(mEscortQuestID) == QUEST_STATUS_INCOMPLETE)
groupGuy->FailQuest(mEscortQuestID);
@@ -233,7 +233,7 @@ void SmartAI::EndPath(bool fail)
if (GetScript()->IsPlayer((*iter)))
{
Player* player = (*iter)->ToPlayer();
- if (!fail && player->IsAtGroupRewardDistance(me) && !player->GetCorpse())
+ if (!fail && player->IsAtGroupRewardDistance(me) && !player->HasCorpse())
player->AreaExploredOrEventHappens(mEscortQuestID);
if (fail && player->GetQuestStatus(mEscortQuestID) == QUEST_STATUS_INCOMPLETE)
player->FailQuest(mEscortQuestID);
@@ -453,45 +453,15 @@ void SmartAI::MoveInLineOfSight(Unit* who)
GetScript()->OnMoveInLineOfSight(who);
- if (me->HasReactState(REACT_PASSIVE) || AssistPlayerInCombat(who))
+ if (AssistPlayerInCombat(who))
return;
- if (!CanAIAttack(who))
- return;
-
- if (!me->CanStartAttack(who, false))
- return;
-
- if (me->IsHostileTo(who))
- {
- float fAttackRadius = me->GetAttackDistance(who);
- if (me->IsWithinDistInMap(who, fAttackRadius) && me->IsWithinLOSInMap(who))
- {
- if (!me->GetVictim())
- {
- // Clear distracted state on combat
- if (me->HasUnitState(UNIT_STATE_DISTRACTED))
- {
- me->ClearUnitState(UNIT_STATE_DISTRACTED);
- me->GetMotionMaster()->Clear();
- }
-
- AttackStart(who);
- }
- else/* if (me->GetMap()->IsDungeon())*/
- {
- who->SetInCombatWith(me);
- me->AddThreat(who, 0.0f);
- }
- }
- }
+ CreatureAI::MoveInLineOfSight(who);
}
bool SmartAI::CanAIAttack(const Unit* /*who*/) const
{
- if (me->GetReactState() == REACT_PASSIVE)
- return false;
- return true;
+ return !(me->HasReactState(REACT_PASSIVE));
}
bool SmartAI::AssistPlayerInCombat(Unit* who)
@@ -728,12 +698,12 @@ void SmartAI::sGossipHello(Player* player)
GetScript()->ProcessEventsFor(SMART_EVENT_GOSSIP_HELLO, player);
}
-void SmartAI::sGossipSelect(Player* player, uint32 sender, uint32 action)
+void SmartAI::sGossipSelect(Player* player, uint32 menuId, uint32 gossipListId)
{
- GetScript()->ProcessEventsFor(SMART_EVENT_GOSSIP_SELECT, player, sender, action);
+ GetScript()->ProcessEventsFor(SMART_EVENT_GOSSIP_SELECT, player, menuId, gossipListId);
}
-void SmartAI::sGossipSelectCode(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/, const char* /*code*/) { }
+void SmartAI::sGossipSelectCode(Player* /*player*/, uint32 /*menuId*/, uint32 /*gossipListId*/, const char* /*code*/) { }
void SmartAI::sQuestAccept(Player* player, Quest const* quest)
{
diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h
index 1e287cd5b9e..ea03a821846 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.h
+++ b/src/server/game/AI/SmartScripts/SmartAI.h
@@ -175,8 +175,8 @@ class SmartAI : public CreatureAI
void SetInvincibilityHpLevel(uint32 level) { mInvincibilityHpLevel = level; }
void sGossipHello(Player* player) override;
- void sGossipSelect(Player* player, uint32 sender, uint32 action) override;
- void sGossipSelectCode(Player* player, uint32 sender, uint32 action, const char* code) override;
+ void sGossipSelect(Player* player, uint32 menuId, uint32 gossipListId) override;
+ void sGossipSelectCode(Player* player, uint32 menuId, uint32 gossipListId, const char* code) override;
void sQuestAccept(Player* player, Quest const* quest) override;
//void sQuestSelect(Player* player, Quest const* quest) override;
void sQuestReward(Player* player, Quest const* quest, uint32 opt) override;
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index 4b43ac889c5..efee565e151 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -1136,6 +1136,14 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
me->GetMotionMaster()->MovePoint(SMART_RANDOM_POINT, x, y, z);
break;
}
+ case SMART_ACTION_RISE_UP:
+ {
+ if (!me)
+ break;
+
+ me->GetMotionMaster()->MovePoint(SMART_RANDOM_POINT, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + (float)e.action.moveRandom.distance);
+ break;
+ }
case SMART_ACTION_SET_VISIBILITY:
{
if (me)
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
index 6ccc581c54e..f0e3c3caff6 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
@@ -1198,6 +1198,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
case SMART_ACTION_ADD_GO_FLAG:
case SMART_ACTION_REMOVE_GO_FLAG:
case SMART_ACTION_SUMMON_CREATURE_GROUP:
+ case SMART_ACTION_RISE_UP:
break;
default:
TC_LOG_ERROR("sql.sql", "SmartAIMgr: Not handled action_type(%u), event_type(%u), Entry %d SourceType %u Event %u, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
index 60a4ce5e8ed..2f9b032c14c 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
@@ -539,8 +539,9 @@ enum SMART_ACTION
SMART_ACTION_GAME_EVENT_STOP = 111, // GameEventId
SMART_ACTION_GAME_EVENT_START = 112, // GameEventId
SMART_ACTION_START_CLOSEST_WAYPOINT = 113, // wp1, wp2, wp3, wp4, wp5, wp6, wp7
+ SMART_ACTION_RISE_UP = 114, // distance
- SMART_ACTION_END = 114
+ SMART_ACTION_END = 115
};
struct SmartAction
diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
index 265eb6f38ba..1809e306a45 100644
--- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
+++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
@@ -61,12 +61,25 @@ AuctionHouseObject* AuctionHouseMgr::GetAuctionsMap(uint32 factionTemplateId)
return &mNeutralAuctions;
}
+AuctionHouseObject* AuctionHouseMgr::GetAuctionsMapByHouseId(uint8 auctionHouseId)
+{
+ if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
+ return &mNeutralAuctions;
+
+ switch(auctionHouseId)
+ {
+ case AUCTIONHOUSE_ALLIANCE : return &mAllianceAuctions;
+ case AUCTIONHOUSE_HORDE : return &mHordeAuctions;
+ default : return &mNeutralAuctions;
+ }
+}
+
uint32 AuctionHouseMgr::GetAuctionDeposit(AuctionHouseEntry const* entry, uint32 time, Item* pItem, uint32 count)
{
uint32 MSV = pItem->GetTemplate()->SellPrice;
if (MSV <= 0)
- return AH_MINIMUM_DEPOSIT;
+ return AH_MINIMUM_DEPOSIT * sWorld->getRate(RATE_AUCTION_DEPOSIT);
float multiplier = CalculatePct(float(entry->depositPercent), 3);
uint32 timeHr = (((time / 60) / 60) / 12);
@@ -77,8 +90,8 @@ uint32 AuctionHouseMgr::GetAuctionDeposit(AuctionHouseEntry const* entry, uint32
TC_LOG_DEBUG("auctionHouse", "Multiplier: %f", multiplier);
TC_LOG_DEBUG("auctionHouse", "Deposit: %u", deposit);
- if (deposit < AH_MINIMUM_DEPOSIT)
- return AH_MINIMUM_DEPOSIT;
+ if (deposit < AH_MINIMUM_DEPOSIT * sWorld->getRate(RATE_AUCTION_DEPOSIT))
+ return AH_MINIMUM_DEPOSIT * sWorld->getRate(RATE_AUCTION_DEPOSIT);
else
return deposit;
}
@@ -342,7 +355,7 @@ void AuctionHouseMgr::LoadAuctions()
continue;
}
- GetAuctionsMap(aItem->factionTemplateId)->AddAuction(aItem);
+ GetAuctionsMapByHouseId(aItem->houseId)->AddAuction(aItem);
++count;
} while (result->NextRow());
@@ -385,44 +398,32 @@ void AuctionHouseMgr::Update()
AuctionHouseEntry const* AuctionHouseMgr::GetAuctionHouseEntry(uint32 factionTemplateId)
{
- uint32 houseid = 7; // goblin auction house
+ uint32 houseid = AUCTIONHOUSE_NEUTRAL; // goblin auction house
if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
{
// FIXME: found way for proper auctionhouse selection by another way
// AuctionHouse.dbc have faction field with _player_ factions associated with auction house races.
// but no easy way convert creature faction to player race faction for specific city
- switch (factionTemplateId)
- {
- case 12: houseid = 1; break; // human
- case 29: houseid = 6; break; // orc, and generic for horde
- case 55: houseid = 2; break; // dwarf, and generic for alliance
- case 68: houseid = 4; break; // undead
- case 80: houseid = 3; break; // n-elf
- case 104: houseid = 5; break; // trolls
- case 120: houseid = 7; break; // booty bay, neutral
- case 474: houseid = 7; break; // gadgetzan, neutral
- case 855: houseid = 7; break; // everlook, neutral
- case 1604: houseid = 6; break; // b-elfs,
- default: // for unknown case
- {
- FactionTemplateEntry const* u_entry = sFactionTemplateStore.LookupEntry(factionTemplateId);
- if (!u_entry)
- houseid = 7; // goblin auction house
- else if (u_entry->ourMask & FACTION_MASK_ALLIANCE)
- houseid = 1; // human auction house
- else if (u_entry->ourMask & FACTION_MASK_HORDE)
- houseid = 6; // orc auction house
- else
- houseid = 7; // goblin auction house
- break;
- }
- }
+ FactionTemplateEntry const* u_entry = sFactionTemplateStore.LookupEntry(factionTemplateId);
+ if (!u_entry)
+ houseid = AUCTIONHOUSE_NEUTRAL; // goblin auction house
+ else if (u_entry->ourMask & FACTION_MASK_ALLIANCE)
+ houseid = AUCTIONHOUSE_ALLIANCE; // human auction house
+ else if (u_entry->ourMask & FACTION_MASK_HORDE)
+ houseid = AUCTIONHOUSE_HORDE; // orc auction house
+ else
+ houseid = AUCTIONHOUSE_NEUTRAL; // goblin auction house
}
return sAuctionHouseStore.LookupEntry(houseid);
}
+AuctionHouseEntry const* AuctionHouseMgr::GetAuctionHouseEntryFromHouse(uint8 houseId)
+{
+ return (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) ? sAuctionHouseStore.LookupEntry(AUCTIONHOUSE_NEUTRAL) : sAuctionHouseStore.LookupEntry(houseId);
+}
+
void AuctionHouseObject::AddAuction(AuctionEntry* auction)
{
ASSERT(auction);
@@ -687,7 +688,7 @@ void AuctionEntry::SaveToDB(SQLTransaction& trans) const
{
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_AUCTION);
stmt->setUInt32(0, Id);
- stmt->setUInt32(1, auctioneer);
+ stmt->setUInt8(1, houseId);
stmt->setUInt32(2, itemGUIDLow);
stmt->setUInt32(3, owner);
stmt->setUInt32(4, buyout);
@@ -702,7 +703,7 @@ void AuctionEntry::SaveToDB(SQLTransaction& trans) const
bool AuctionEntry::LoadFromDB(Field* fields)
{
Id = fields[0].GetUInt32();
- auctioneer = fields[1].GetUInt32();
+ houseId = fields[1].GetUInt8();
itemGUIDLow = fields[2].GetUInt32();
itemEntry = fields[3].GetUInt32();
itemCount = fields[4].GetUInt32();
@@ -714,25 +715,10 @@ bool AuctionEntry::LoadFromDB(Field* fields)
startbid = fields[10].GetUInt32();
deposit = fields[11].GetUInt32();
- CreatureData const* auctioneerData = sObjectMgr->GetCreatureData(auctioneer);
- if (!auctioneerData)
- {
- TC_LOG_ERROR("misc", "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", "Auction %u has not a existing auctioneer (GUID : %u Entry: %u)", Id, auctioneer, auctioneerData->id);
- return false;
- }
-
- factionTemplateId = auctioneerInfo->faction;
- auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntry(factionTemplateId);
+ auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntryFromHouse(houseId);
if (!auctionHouseEntry)
{
- TC_LOG_ERROR("misc", "Auction %u has auctioneer (GUID : %u Entry: %u) with wrong faction %u", Id, auctioneer, auctioneerData->id, factionTemplateId);
+ TC_LOG_ERROR("misc", "Auction %u has invalid house id %u", Id, houseId);
return false;
}
diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.h b/src/server/game/AuctionHouse/AuctionHouseMgr.h
index d67c8143996..f05d8583329 100644
--- a/src/server/game/AuctionHouse/AuctionHouseMgr.h
+++ b/src/server/game/AuctionHouse/AuctionHouseMgr.h
@@ -61,10 +61,17 @@ enum MailAuctionAnswers
AUCTION_SALE_PENDING = 6
};
+enum AuctionHouses
+{
+ AUCTIONHOUSE_ALLIANCE = 2,
+ AUCTIONHOUSE_HORDE = 6,
+ AUCTIONHOUSE_NEUTRAL = 7
+};
+
struct AuctionEntry
{
uint32 Id;
- uint32 auctioneer; // creature low guid
+ uint8 houseId;
uint32 itemGUIDLow;
uint32 itemEntry;
uint32 itemCount;
@@ -76,11 +83,9 @@ struct AuctionEntry
uint32 bidder;
uint32 deposit; //deposit can be calculated only when creating auction
AuctionHouseEntry const* auctionHouseEntry; // in AuctionHouse.dbc
- uint32 factionTemplateId;
// helpers
- uint32 GetHouseId() const { return auctionHouseEntry->houseId; }
- uint32 GetHouseFaction() const { return auctionHouseEntry->faction; }
+ uint8 GetHouseId() const { return houseId; }
uint32 GetAuctionCut() const;
uint32 GetAuctionOutBid() const;
bool BuildAuctionInfo(WorldPacket & data) const;
@@ -148,6 +153,7 @@ class AuctionHouseMgr
typedef std::unordered_map<uint32, Item*> ItemMap;
AuctionHouseObject* GetAuctionsMap(uint32 factionTemplateId);
+ AuctionHouseObject* GetAuctionsMapByHouseId(uint8 auctionHouseId);
AuctionHouseObject* GetBidsMap(uint32 factionTemplateId);
Item* GetAItem(uint32 id)
@@ -169,7 +175,7 @@ class AuctionHouseMgr
static uint32 GetAuctionDeposit(AuctionHouseEntry const* entry, uint32 time, Item* pItem, uint32 count);
static AuctionHouseEntry const* GetAuctionHouseEntry(uint32 factionTemplateId);
-
+ static AuctionHouseEntry const* GetAuctionHouseEntryFromHouse(uint8 houseId);
public:
//load first auction items, because of check if item exists, when loading
diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp
index e6164b77005..22dc5bb0bd0 100644
--- a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp
+++ b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp
@@ -906,15 +906,17 @@ void AuctionBotSeller::AddNewAuctions(SellerConfiguration& config)
items = sAuctionBotConfig->GetItemPerCycleNormal();
uint32 houseid = 0;
- uint32 auctioneer = 0;
switch (config.GetHouseType())
{
case AUCTION_HOUSE_ALLIANCE:
- houseid = 1; auctioneer = 79707; break;
+ houseid = AUCTIONHOUSE_ALLIANCE;
+ break;
case AUCTION_HOUSE_HORDE:
- houseid = 6; auctioneer = 4656; break;
+ houseid = AUCTIONHOUSE_HORDE;
+ break;
default:
- houseid = 7; auctioneer = 23442; break;
+ houseid = AUCTIONHOUSE_NEUTRAL;
+ break;
}
AuctionHouseEntry const* ahEntry = sAuctionHouseStore.LookupEntry(houseid);
@@ -995,7 +997,7 @@ void AuctionBotSeller::AddNewAuctions(SellerConfiguration& config)
auctionEntry->itemEntry = item->GetEntry();
auctionEntry->startbid = bidPrice;
auctionEntry->buyout = buyoutPrice;
- auctionEntry->auctioneer = auctioneer;
+ auctionEntry->houseId = houseid;
auctionEntry->bidder = 0;
auctionEntry->bid = 0;
auctionEntry->deposit = sAuctionMgr->GetAuctionDeposit(ahEntry, etime, item, stackCount);
diff --git a/src/server/game/Battlefield/Battlefield.cpp b/src/server/game/Battlefield/Battlefield.cpp
index 46181011719..d22ac0ea5d5 100644
--- a/src/server/game/Battlefield/Battlefield.cpp
+++ b/src/server/game/Battlefield/Battlefield.cpp
@@ -695,7 +695,7 @@ void BfGraveyard::Resurrect()
player->CastSpell(player, 6962, true);
player->CastSpell(player, SPELL_SPIRIT_HEAL_MANA, true);
- sObjectAccessor->ConvertCorpseForPlayer(player->GetGUID());
+ player->SpawnCorpseBones(false);
}
m_ResurrectQueue.clear();
diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp
index 2b4d5a4df5e..ad8a7b9e729 100644
--- a/src/server/game/Battlegrounds/Battleground.cpp
+++ b/src/server/game/Battlegrounds/Battleground.cpp
@@ -367,7 +367,7 @@ inline void Battleground::_ProcessResurrect(uint32 diff)
player->ResurrectPlayer(1.0f);
player->CastSpell(player, 6962, true);
player->CastSpell(player, SPELL_SPIRIT_HEAL_MANA, true);
- sObjectAccessor->ConvertCorpseForPlayer(*itr);
+ player->SpawnCorpseBones(false);
}
m_ResurrectQueue.clear();
}
@@ -889,8 +889,11 @@ void Battleground::RemovePlayerAtLeave(ObjectGuid guid, bool Transport, bool Sen
player->SpawnCorpseBones();
}
}
- else // try to resurrect the offline player. If he is alive nothing will happen
- sObjectAccessor->ConvertCorpseForPlayer(guid);
+ else
+ {
+ SQLTransaction trans(nullptr);
+ Player::OfflineResurrect(guid, trans);
+ }
RemovePlayer(player, guid, team); // BG subclass specific code
diff --git a/src/server/game/Entities/Corpse/Corpse.cpp b/src/server/game/Entities/Corpse/Corpse.cpp
index 11c0885beef..360cfdf1ae3 100644
--- a/src/server/game/Entities/Corpse/Corpse.cpp
+++ b/src/server/game/Entities/Corpse/Corpse.cpp
@@ -22,6 +22,7 @@
#include "UpdateMask.h"
#include "ObjectAccessor.h"
#include "DatabaseEnv.h"
+#include "World.h"
Corpse::Corpse(CorpseType type) : WorldObject(type != CORPSE_BONES), m_type(type)
{
@@ -138,10 +139,14 @@ void Corpse::DeleteBonesFromWorld()
void Corpse::DeleteFromDB(SQLTransaction& trans)
{
- PreparedStatement* stmt = NULL;
- stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CORPSE);
- stmt->setUInt32(0, GetOwnerGUID().GetCounter());
- trans->Append(stmt);
+ DeleteFromDB(GetOwnerGUID(), trans);
+}
+
+void Corpse::DeleteFromDB(ObjectGuid const& ownerGuid, SQLTransaction& trans)
+{
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CORPSE);
+ stmt->setUInt32(0, ownerGuid.GetCounter());
+ CharacterDatabase.ExecuteOrAppend(trans, stmt);
}
bool Corpse::LoadCorpseFromDB(uint32 guid, Field* fields)
@@ -193,6 +198,10 @@ bool Corpse::LoadCorpseFromDB(uint32 guid, Field* fields)
bool Corpse::IsExpired(time_t t) const
{
+ // Deleted character
+ if (!sWorld->GetCharacterNameData(GetOwnerGUID()))
+ return true;
+
if (m_type == CORPSE_BONES)
return m_time < t - 60 * MINUTE;
else
diff --git a/src/server/game/Entities/Corpse/Corpse.h b/src/server/game/Entities/Corpse/Corpse.h
index c3a693d30d3..eeb22a064ba 100644
--- a/src/server/game/Entities/Corpse/Corpse.h
+++ b/src/server/game/Entities/Corpse/Corpse.h
@@ -63,6 +63,7 @@ class Corpse : public WorldObject, public GridObject<Corpse>
void DeleteBonesFromWorld();
void DeleteFromDB(SQLTransaction& trans);
+ static void DeleteFromDB(ObjectGuid const& ownerGuid, SQLTransaction& trans);
ObjectGuid GetOwnerGUID() const { return GetGuidValue(CORPSE_FIELD_OWNER); }
diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h
index 26c712730cd..b91f1b6eeee 100644
--- a/src/server/game/Entities/GameObject/GameObject.h
+++ b/src/server/game/Entities/GameObject/GameObject.h
@@ -843,6 +843,7 @@ class GameObject : public WorldObject, public GridObject<GameObject>, public Map
float GetStationaryY() const override { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetPositionY(); return GetPositionY(); }
float GetStationaryZ() const override { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetPositionZ(); return GetPositionZ(); }
float GetStationaryO() const override { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetOrientation(); return GetOrientation(); }
+ void RelocateStationaryPosition(float x, float y, float z, float o) { m_stationaryPosition.Relocate(x, y, z, o); }
float GetInteractionDistance();
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index f5af3556332..21a65440a55 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -1743,7 +1743,7 @@ void WorldObject::SendObjectDeSpawnAnim(ObjectGuid guid)
void WorldObject::SetMap(Map* map)
{
ASSERT(map);
- ASSERT(!IsInWorld() || GetTypeId() == TYPEID_CORPSE);
+ ASSERT(!IsInWorld());
if (m_currMap == map) // command add npc: first create, than loadfromdb
return;
if (m_currMap)
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index b5d3ebaa562..1be3c2454b2 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -2022,6 +2022,8 @@ bool Player::BuildEnumData(PreparedQueryResult result, WorldPacket* data)
uint32 charFlags = 0;
uint32 playerFlags = fields[14].GetUInt32();
+ if (atLoginFlags & AT_LOGIN_RESURRECT)
+ playerFlags &= ~PLAYER_FLAGS_GHOST;
if (playerFlags & PLAYER_FLAGS_HIDE_HELM)
charFlags |= CHARACTER_FLAG_HIDE_HELM;
if (playerFlags & PLAYER_FLAGS_HIDE_CLOAK)
@@ -4537,10 +4539,6 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
charDelete_method = CHAR_DELETE_REMOVE;
}
- // convert corpse to bones if exist (to prevent exiting Corpse in World without DB entry)
- // bones will be deleted by corpse/bones deleting thread shortly
- sObjectAccessor->ConvertCorpseForPlayer(playerguid);
-
if (uint32 guildId = GetGuildIdFromDB(playerguid))
if (Guild* guild = sGuildMgr->GetGuildById(guildId))
guild->DeleteMember(playerguid, false, false, true);
@@ -4841,6 +4839,8 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
stmt->setUInt32(0, guid);
trans->Append(stmt);
+ Corpse::DeleteFromDB(playerguid, trans);
+
CharacterDatabase.CommitTransaction(trans);
break;
}
@@ -4940,18 +4940,17 @@ void Player::BuildPlayerRepop()
// there must be SMSG.FORCE_RUN_SPEED_CHANGE, SMSG.FORCE_SWIM_SPEED_CHANGE, SMSG.MOVE_WATER_WALK
// there must be SMSG.STOP_MIRROR_TIMER
- // there we must send 888 opcode
- // the player cannot have a corpse already, only bones which are not returned by GetCorpse
- if (GetCorpse())
+ // the player cannot have a corpse already on current map, only bones which are not returned by GetCorpse
+ WorldLocation corpseLocation = GetCorpseLocation();
+ if (corpseLocation.GetMapId() == GetMapId())
{
TC_LOG_ERROR("entities.player", "BuildPlayerRepop: player %s(%d) already has a corpse", GetName().c_str(), GetGUID().GetCounter());
return;
}
// create a corpse and place it at the player's location
- CreateCorpse();
- Corpse* corpse = GetCorpse();
+ Corpse* corpse = CreateCorpse();
if (!corpse)
{
TC_LOG_ERROR("entities.player", "Error creating corpse for Player %s [%u]", GetName().c_str(), GetGUID().GetCounter());
@@ -5093,7 +5092,16 @@ void Player::KillPlayer()
UpdateObjectVisibility();
}
-void Player::CreateCorpse()
+void Player::OfflineResurrect(ObjectGuid const& guid, SQLTransaction& trans)
+{
+ Corpse::DeleteFromDB(guid, trans);
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG);
+ stmt->setUInt16(0, uint16(AT_LOGIN_RESURRECT));
+ stmt->setUInt64(1, guid.GetCounter());
+ CharacterDatabase.ExecuteOrAppend(trans, stmt);
+}
+
+Corpse* Player::CreateCorpse()
{
// prevent existence 2 corpse for player
SpawnCorpseBones();
@@ -5106,9 +5114,11 @@ void Player::CreateCorpse()
if (!corpse->Create(GetMap()->GenerateLowGuid<HighGuid::Corpse>(), this))
{
delete corpse;
- return;
+ return nullptr;
}
+ _corpseLocation.WorldRelocate(*this);
+
_uf = GetUInt32Value(UNIT_FIELD_BYTES_0);
_pb = GetUInt32Value(PLAYER_BYTES);
_pb2 = GetUInt32Value(PLAYER_BYTES_2);
@@ -5159,19 +5169,21 @@ void Player::CreateCorpse()
corpse->SaveToDB();
// register for player, but not show
- sObjectAccessor->AddCorpse(corpse);
+ GetMap()->AddCorpse(corpse);
+ return corpse;
}
-void Player::SpawnCorpseBones()
+void Player::SpawnCorpseBones(bool triggerSave /*= true*/)
{
- if (sObjectAccessor->ConvertCorpseForPlayer(GetGUID()))
- if (!GetSession()->PlayerLogoutWithSave()) // at logout we will already store the player
- SaveToDB(); // prevent loading as ghost without corpse
+ _corpseLocation.WorldRelocate();
+ if (GetMap()->ConvertCorpseToBones(GetGUID()))
+ if (triggerSave && !GetSession()->PlayerLogoutWithSave()) // at logout we will already store the player
+ SaveToDB(); // prevent loading as ghost without corpse
}
Corpse* Player::GetCorpse() const
{
- return sObjectAccessor->GetCorpseForPlayerGUID(GetGUID());
+ return GetMap()->GetCorpseByPlayer(GetGUID());
}
void Player::DurabilityLossAll(double percent, bool inventory)
@@ -7598,6 +7610,20 @@ void Player::DuelComplete(DuelCompleteType type)
duel->opponent->SetGuidValue(PLAYER_DUEL_ARBITER, ObjectGuid::Empty);
duel->opponent->SetUInt32Value(PLAYER_DUEL_TEAM, 0);
+ if (sWorld->getBoolConfig(CONFIG_RESET_COOLDOWN_AFTER_DUEL) &&
+ type != DUEL_INTERRUPTED)
+ {
+ if (!HasCoolDownBeforeDuel())
+ RemoveArenaSpellCooldowns(true);
+ else
+ ChatHandler(GetSession()).PSendSysMessage(LANG_COOLDOWN_NOT_RESET_AFTER_DUEL);
+
+ if (!duel->opponent->HasCoolDownBeforeDuel())
+ duel->opponent->RemoveArenaSpellCooldowns(true);
+ else
+ ChatHandler(duel->opponent->GetSession()).PSendSysMessage(LANG_COOLDOWN_NOT_RESET_AFTER_DUEL);
+ }
+
delete duel->opponent->duel;
duel->opponent->duel = NULL;
delete duel;
@@ -8580,9 +8606,11 @@ void Player::RemovedInsignia(Player* looterPlr)
RepopAtGraveyard();
}
+ _corpseLocation.WorldRelocate();
+
// We have to convert player corpse to bones, not to be able to resurrect there
// SpawnCorpseBones isn't handy, 'cos it saves player while he in BG
- Corpse* bones = sObjectAccessor->ConvertCorpseForPlayer(GetGUID(), true);
+ Corpse* bones = GetMap()->ConvertCorpseToBones(GetGUID(), true);
if (!bones)
return;
@@ -17910,18 +17938,24 @@ void Player::_LoadGlyphAuras()
}
}
-void Player::LoadCorpse()
+void Player::LoadCorpse(PreparedQueryResult result)
{
- if (IsAlive())
- sObjectAccessor->ConvertCorpseForPlayer(GetGUID());
- else
+ if (IsAlive() || HasAtLoginFlag(AT_LOGIN_RESURRECT))
+ SpawnCorpseBones(false);
+
+ if (!IsAlive())
{
- if (Corpse* corpse = GetCorpse())
- ApplyModFlag(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTE_RELEASE_TIMER, corpse && !sMapStore.LookupEntry(corpse->GetMapId())->Instanceable());
+ if (result && !HasAtLoginFlag(AT_LOGIN_RESURRECT))
+ {
+ Field* fields = result->Fetch();
+ _corpseLocation.WorldRelocate(fields[0].GetUInt16(), fields[1].GetFloat(), fields[2].GetFloat(), fields[3].GetFloat(), fields[4].GetFloat());
+ ApplyModFlag(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTE_RELEASE_TIMER, !sMapStore.LookupEntry(_corpseLocation.GetMapId())->Instanceable());
+ }
else
- //Prevent Dead Player login without corpse
ResurrectPlayer(0.5f);
}
+
+ RemoveAtLoginFlag(AT_LOGIN_RESURRECT);
}
void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff)
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 94d0fa5697c..0c1fdd8f03d 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -27,6 +27,7 @@
#include "PetDefines.h"
#include "QuestDef.h"
#include "SpellMgr.h"
+#include "SpellHistory.h"
#include "Unit.h"
#include <limits>
@@ -284,7 +285,7 @@ struct PvPInfo
struct DuelInfo
{
- DuelInfo() : initiator(NULL), opponent(NULL), startTimer(0), startTime(0), outOfBound(0), isMounted(false) { }
+ DuelInfo() : initiator(NULL), opponent(NULL), startTimer(0), startTime(0), outOfBound(0), isMounted(false), hasCoolDownBeforeDuel(false) { }
Player* initiator;
Player* opponent;
@@ -292,6 +293,7 @@ struct DuelInfo
time_t startTime;
time_t outOfBound;
bool isMounted;
+ bool hasCoolDownBeforeDuel;
};
struct Areas
@@ -503,15 +505,16 @@ enum PlayerExtraFlags
// 2^n values
enum AtLoginFlags
{
- AT_LOGIN_NONE = 0x00,
- AT_LOGIN_RENAME = 0x01,
- AT_LOGIN_RESET_SPELLS = 0x02,
- AT_LOGIN_RESET_TALENTS = 0x04,
- AT_LOGIN_CUSTOMIZE = 0x08,
- AT_LOGIN_RESET_PET_TALENTS = 0x10,
- AT_LOGIN_FIRST = 0x20,
- AT_LOGIN_CHANGE_FACTION = 0x40,
- AT_LOGIN_CHANGE_RACE = 0x80
+ AT_LOGIN_NONE = 0x000,
+ AT_LOGIN_RENAME = 0x001,
+ AT_LOGIN_RESET_SPELLS = 0x002,
+ AT_LOGIN_RESET_TALENTS = 0x004,
+ AT_LOGIN_CUSTOMIZE = 0x008,
+ AT_LOGIN_RESET_PET_TALENTS = 0x010,
+ AT_LOGIN_FIRST = 0x020,
+ AT_LOGIN_CHANGE_FACTION = 0x040,
+ AT_LOGIN_CHANGE_RACE = 0x080,
+ AT_LOGIN_RESURRECT = 0x100,
};
typedef std::map<uint32, QuestStatusData> QuestStatusMap;
@@ -819,6 +822,7 @@ enum PlayerLoginQueryIndex
PLAYER_LOGIN_QUERY_LOAD_INSTANCE_LOCK_TIMES = 30,
PLAYER_LOGIN_QUERY_LOAD_SEASONAL_QUEST_STATUS = 31,
PLAYER_LOGIN_QUERY_LOAD_MONTHLY_QUEST_STATUS = 32,
+ PLAYER_LOGIN_QUERY_LOAD_CORPSE_LOCATION = 33,
MAX_PLAYER_LOGIN_QUERY
};
@@ -1343,7 +1347,7 @@ class Player : public Unit, public GridObject<Player>
void AddItemDurations(Item* item);
void RemoveItemDurations(Item* item);
void SendItemDurations();
- void LoadCorpse();
+ void LoadCorpse(PreparedQueryResult result);
void LoadPet();
bool AddItem(uint32 itemId, uint32 count);
@@ -1835,17 +1839,20 @@ class Player : public Unit, public GridObject<Player>
bool UpdatePosition(const Position &pos, bool teleport = false) { return UpdatePosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teleport); }
void UpdateUnderwaterState(Map* m, float x, float y, float z) override;
- void SendMessageToSet(WorldPacket* data, bool self) override {SendMessageToSetInRange(data, GetVisibilityRange(), self); }// overwrite Object::SendMessageToSet
- void SendMessageToSetInRange(WorldPacket* data, float fist, bool self) override;// overwrite Object::SendMessageToSetInRange
+ void SendMessageToSet(WorldPacket* data, bool self) override { SendMessageToSetInRange(data, GetVisibilityRange(), self); }
+ void SendMessageToSetInRange(WorldPacket* data, float dist, bool self) override;
void SendMessageToSetInRange(WorldPacket* data, float dist, bool self, bool own_team_only);
void SendMessageToSet(WorldPacket* data, Player const* skipped_rcvr) override;
void SendTeleportAckPacket();
Corpse* GetCorpse() const;
- void SpawnCorpseBones();
- void CreateCorpse();
+ void SpawnCorpseBones(bool triggerSave = true);
+ Corpse* CreateCorpse();
void KillPlayer();
+ static void OfflineResurrect(ObjectGuid const& guid, SQLTransaction& trans);
+ bool HasCorpse() const { return _corpseLocation.GetMapId() != MAPID_INVALID; }
+ WorldLocation GetCorpseLocation() const { return _corpseLocation; }
uint32 GetResurrectionSpellId();
void ResurrectPlayer(float restore_percent, bool applySickness = false);
void BuildPlayerRepop();
@@ -1877,7 +1884,7 @@ class Player : public Unit, public GridObject<Player>
void UpdateWeaponSkill (WeaponAttackType attType);
void UpdateCombatSkills(Unit* victim, WeaponAttackType attType, bool defence);
- void SetSkill(uint16 id, uint16 step, uint16 currVal, uint16 maxVal);
+ void SetSkill(uint16 id, uint16 step, uint16 newVal, uint16 maxVal);
uint16 GetMaxSkillValue(uint32 skill) const; // max + perm. bonus + temp bonus
uint16 GetPureMaxSkillValue(uint32 skill) const; // max
uint16 GetSkillValue(uint32 skill) const; // skill value + perm. bonus + temp bonus
@@ -1941,6 +1948,9 @@ class Player : public Unit, public GridObject<Player>
void SetHonorPoints(uint32 value);
void SetArenaPoints(uint32 value);
+ bool HasCoolDownBeforeDuel() const { return duel->hasCoolDownBeforeDuel; }
+ void UpdateHasCoolDownBeforeDuel() { duel->hasCoolDownBeforeDuel = GetSpellHistory()->GetArenaCooldownsSize() > 0; }
+
//End of PvP System
void SetDrunkValue(uint8 newDrunkValue, uint32 itemId = 0);
@@ -2624,6 +2634,8 @@ class Player : public Unit, public GridObject<Player>
uint32 _pendingBindTimer;
uint32 _activeCheats;
+
+ WorldLocation _corpseLocation;
};
void AddItemsSetItem(Player* player, Item* item);
diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp
index 9cd3945d44d..144805b88b5 100644
--- a/src/server/game/Entities/Transport/Transport.cpp
+++ b/src/server/game/Entities/Transport/Transport.cpp
@@ -100,7 +100,6 @@ bool Transport::Create(uint32 guidlow, uint32 entry, uint32 mapid, float x, floa
void Transport::CleanupsBeforeDelete(bool finalCleanup /*= true*/)
{
- HashMapHolder<Transport>::Remove(this);
UnloadStaticPassengers();
while (!_passengers.empty())
{
@@ -352,6 +351,7 @@ GameObject* Transport::CreateGOPassenger(uint32 guid, GameObjectData const* data
go->m_movementInfo.transport.pos.Relocate(x, y, z, o);
CalculatePassengerPosition(x, y, z, &o);
go->Relocate(x, y, z, o);
+ go->RelocateStationaryPosition(x, y, z, o);
if (!go->IsPositionValid())
{
@@ -704,6 +704,7 @@ void Transport::UpdatePassengerPositions(PassengerSet& passengers)
break;
case TYPEID_GAMEOBJECT:
GetMap()->GameObjectRelocation(passenger->ToGameObject(), x, y, z, o, false);
+ passenger->ToGameObject()->RelocateStationaryPosition(x, y, z, o);
break;
case TYPEID_DYNAMICOBJECT:
GetMap()->DynamicObjectRelocation(passenger->ToDynObject(), x, y, z, o);
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 3938b8d7278..f085bab165a 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -721,7 +721,7 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
if (!victim->ToCreature()->hasLootRecipient())
victim->ToCreature()->SetLootRecipient(this);
- if (IsControlledByPlayer())
+ if (IsControlledByPlayer() || (ToTempSummon() && ToTempSummon()->GetSummoner() && ToTempSummon()->GetSummoner()->GetTypeId() == TYPEID_PLAYER))
victim->ToCreature()->LowerPlayerDamageReq(health < damage ? health : damage);
}
@@ -16975,6 +16975,12 @@ void Unit::_EnterVehicle(Vehicle* vehicle, int8 seatId, AuraApplication const* a
}
}
+ // If vehicle flag for fixed position set (cannons), or if the following hardcoded units, then set state rooted
+ // 30236 | Argent Cannon
+ // 39759 | Tankbuster Cannon
+ if ((vehicle->GetVehicleInfo()->m_flags & VEHICLE_FLAG_FIXED_POSITION) || vehicle->GetBase()->GetEntry() == 30236 || vehicle->GetBase()->GetEntry() == 39759)
+ SetControlled(true, UNIT_STATE_ROOT);
+
ASSERT(!m_vehicle);
(void)vehicle->AddPassenger(this, seatId);
}
diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp
index fcb74424eb1..982b931fd4f 100755
--- a/src/server/game/Entities/Vehicle/Vehicle.cpp
+++ b/src/server/game/Entities/Vehicle/Vehicle.cpp
@@ -192,6 +192,12 @@ void Vehicle::ApplyAllImmunities()
_me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, true);
}
+ // If vehicle flag for fixed position set (cannons), or if the following hardcoded units, then set state rooted
+ // 30236 | Argent Cannon
+ // 39759 | Tankbuster Cannon
+ if ((GetVehicleInfo()->m_flags & VEHICLE_FLAG_FIXED_POSITION) || GetBase()->GetEntry() == 30236 || GetBase()->GetEntry() == 39759)
+ _me->SetControlled(true, UNIT_STATE_ROOT);
+
// Different immunities for vehicles goes below
switch (GetVehicleInfo()->m_ID)
{
diff --git a/src/server/game/Entities/Vehicle/VehicleDefines.h b/src/server/game/Entities/Vehicle/VehicleDefines.h
index c00bc429f38..3726e9ddf8f 100644
--- a/src/server/game/Entities/Vehicle/VehicleDefines.h
+++ b/src/server/game/Entities/Vehicle/VehicleDefines.h
@@ -44,7 +44,8 @@ enum VehicleFlags
VEHICLE_FLAG_FULLSPEEDPITCHING = 0x00000020, // Sets MOVEFLAG2_FULLSPEEDPITCHING
VEHICLE_FLAG_CUSTOM_PITCH = 0x00000040, // If set use pitchMin and pitchMax from DBC, otherwise pitchMin = -pi/2, pitchMax = pi/2
VEHICLE_FLAG_ADJUST_AIM_ANGLE = 0x00000400, // Lua_IsVehicleAimAngleAdjustable
- VEHICLE_FLAG_ADJUST_AIM_POWER = 0x00000800 // Lua_IsVehicleAimPowerAdjustable
+ VEHICLE_FLAG_ADJUST_AIM_POWER = 0x00000800, // Lua_IsVehicleAimPowerAdjustable
+ VEHICLE_FLAG_FIXED_POSITION = 0x00200000 // Used for cannons, when they should be rooted
};
enum VehicleSpells
diff --git a/src/server/game/Globals/ObjectAccessor.cpp b/src/server/game/Globals/ObjectAccessor.cpp
index f5e9b6bb5b7..ca974ba9a37 100644
--- a/src/server/game/Globals/ObjectAccessor.cpp
+++ b/src/server/game/Globals/ObjectAccessor.cpp
@@ -34,10 +34,6 @@
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/locks.hpp>
-ObjectAccessor::ObjectAccessor() { }
-
-ObjectAccessor::~ObjectAccessor() { }
-
WorldObject* ObjectAccessor::GetWorldObject(WorldObject const& p, ObjectGuid const& guid)
{
switch (guid.GetHigh())
@@ -210,6 +206,11 @@ Player* ObjectAccessor::FindConnectedPlayerByName(std::string const& name)
return NULL;
}
+HashMapHolder<Player>::MapType const& ObjectAccessor::GetPlayers()
+{
+ return HashMapHolder<Player>::GetContainer();
+}
+
void ObjectAccessor::SaveAllPlayers()
{
boost::shared_lock<boost::shared_mutex> lock(*HashMapHolder<Player>::GetLock());
@@ -219,185 +220,6 @@ void ObjectAccessor::SaveAllPlayers()
itr->second->SaveToDB();
}
-Corpse* ObjectAccessor::GetCorpseForPlayerGUID(ObjectGuid const& guid)
-{
- boost::shared_lock<boost::shared_mutex> lock(_corpseLock);
-
- Player2CorpsesMapType::iterator iter = i_player2corpse.find(guid);
- if (iter == i_player2corpse.end())
- return NULL;
-
- ASSERT(iter->second->GetType() != CORPSE_BONES);
-
- return iter->second;
-}
-
-void ObjectAccessor::RemoveCorpse(Corpse* corpse)
-{
- ASSERT(corpse && corpse->GetType() != CORPSE_BONES);
-
- boost::upgrade_lock<boost::shared_mutex> lock(_corpseLock);
-
- /// @todo more works need to be done for corpse and other world object
- if (Map* map = corpse->FindMap())
- {
- corpse->DestroyForNearbyPlayers();
- if (corpse->IsInGrid())
- map->RemoveFromMap(corpse, false);
- else
- {
- corpse->RemoveFromWorld();
- corpse->ResetMap();
- }
- }
- else
- corpse->RemoveFromWorld();
-
- // Critical section
- {
- boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
-
- Player2CorpsesMapType::iterator iter = i_player2corpse.find(corpse->GetOwnerGUID());
- if (iter == i_player2corpse.end()) /// @todo Fix this
- return;
-
- // build mapid*cellid -> guid_set map
- CellCoord cellCoord = Trinity::ComputeCellCoord(corpse->GetPositionX(), corpse->GetPositionY());
- sObjectMgr->DeleteCorpseCellData(corpse->GetMapId(), cellCoord.GetId(), corpse->GetOwnerGUID().GetCounter());
-
- i_player2corpse.erase(iter);
- }
-}
-
-void ObjectAccessor::AddCorpse(Corpse* corpse)
-{
- ASSERT(corpse && corpse->GetType() != CORPSE_BONES);
-
- // Critical section
- {
- boost::unique_lock<boost::shared_mutex> lock(_corpseLock);
-
- ASSERT(i_player2corpse.find(corpse->GetOwnerGUID()) == i_player2corpse.end());
- i_player2corpse[corpse->GetOwnerGUID()] = corpse;
-
- // build mapid*cellid -> guid_set map
- CellCoord cellCoord = Trinity::ComputeCellCoord(corpse->GetPositionX(), corpse->GetPositionY());
- sObjectMgr->AddCorpseCellData(corpse->GetMapId(), cellCoord.GetId(), corpse->GetOwnerGUID().GetCounter(), corpse->GetInstanceId());
- }
-}
-
-void ObjectAccessor::AddCorpsesToGrid(GridCoord const& gridpair, GridType& grid, Map* map)
-{
- boost::shared_lock<boost::shared_mutex> lock(_corpseLock);
-
- for (Player2CorpsesMapType::iterator iter = i_player2corpse.begin(); iter != i_player2corpse.end(); ++iter)
- {
- // We need this check otherwise a corpose may be added to a grid twice
- if (iter->second->IsInGrid())
- continue;
-
- if (iter->second->GetGridCoord() == gridpair)
- {
- // verify, if the corpse in our instance (add only corpses which are)
- if (map->Instanceable())
- {
- if (iter->second->GetInstanceId() == map->GetInstanceId())
- grid.AddWorldObject(iter->second);
- }
- else
- grid.AddWorldObject(iter->second);
- }
- }
-}
-
-Corpse* ObjectAccessor::ConvertCorpseForPlayer(ObjectGuid const& player_guid, bool insignia /*=false*/)
-{
- Corpse* corpse = GetCorpseForPlayerGUID(player_guid);
- if (!corpse)
- {
- //in fact this function is called from several places
- //even when player doesn't have a corpse, not an error
- return NULL;
- }
-
- TC_LOG_DEBUG("misc", "Deleting Corpse and spawned bones.");
-
- // Map can be NULL
- Map* map = corpse->FindMap();
-
- // remove corpse from player_guid -> corpse map and from current map
- RemoveCorpse(corpse);
-
- // remove corpse from DB
- SQLTransaction trans = CharacterDatabase.BeginTransaction();
- corpse->DeleteFromDB(trans);
- CharacterDatabase.CommitTransaction(trans);
-
- Corpse* bones = NULL;
- // create the bones only if the map and the grid is loaded at the corpse's location
- // ignore bones creating option in case insignia
-
- if (map && (insignia ||
- (map->IsBattlegroundOrArena() ? sWorld->getBoolConfig(CONFIG_DEATH_BONES_BG_OR_ARENA) : sWorld->getBoolConfig(CONFIG_DEATH_BONES_WORLD))) &&
- !map->IsRemovalGrid(corpse->GetPositionX(), corpse->GetPositionY()))
- {
- // Create bones, don't change Corpse
- bones = new Corpse;
- bones->Create(corpse->GetGUID().GetCounter(), map);
-
- for (uint8 i = OBJECT_FIELD_TYPE + 1; i < CORPSE_END; ++i) // don't overwrite guid and object type
- bones->SetUInt32Value(i, corpse->GetUInt32Value(i));
-
- bones->SetGridCoord(corpse->GetGridCoord());
- // bones->m_time = m_time; // don't overwrite time
- // bones->m_type = m_type; // don't overwrite type
- bones->Relocate(corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetOrientation());
- bones->SetPhaseMask(corpse->GetPhaseMask(), false);
-
- bones->SetUInt32Value(CORPSE_FIELD_FLAGS, CORPSE_FLAG_UNK2 | CORPSE_FLAG_BONES);
- bones->SetGuidValue(CORPSE_FIELD_OWNER, ObjectGuid::Empty);
-
- for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i)
- {
- if (corpse->GetUInt32Value(CORPSE_FIELD_ITEM + i))
- bones->SetUInt32Value(CORPSE_FIELD_ITEM + i, 0);
- }
-
- // add bones in grid store if grid loaded where corpse placed
- map->AddToMap(bones);
- }
-
- // all references to the corpse should be removed at this point
- delete corpse;
-
- return bones;
-}
-
-void ObjectAccessor::RemoveOldCorpses()
-{
- time_t now = time(NULL);
- Player2CorpsesMapType::iterator next;
- for (Player2CorpsesMapType::iterator itr = i_player2corpse.begin(); itr != i_player2corpse.end(); itr = next)
- {
- next = itr;
- ++next;
-
- if (!itr->second->IsExpired(now))
- continue;
-
- ConvertCorpseForPlayer(itr->first);
- }
-}
-
-void ObjectAccessor::UnloadAll()
-{
- for (Player2CorpsesMapType::const_iterator itr = i_player2corpse.begin(); itr != i_player2corpse.end(); ++itr)
- {
- itr->second->RemoveFromWorld();
- delete itr->second;
- }
-}
-
/// Define the static members of HashMapHolder
template <class T> typename HashMapHolder<T>::MapType HashMapHolder<T>::_objectMap;
diff --git a/src/server/game/Globals/ObjectAccessor.h b/src/server/game/Globals/ObjectAccessor.h
index 54e2a7298ef..d5fb8564b96 100644
--- a/src/server/game/Globals/ObjectAccessor.h
+++ b/src/server/game/Globals/ObjectAccessor.h
@@ -85,85 +85,47 @@ class HashMapHolder
static MapType _objectMap;
};
-class ObjectAccessor
+namespace ObjectAccessor
{
- private:
- ObjectAccessor();
- ~ObjectAccessor();
- ObjectAccessor(const ObjectAccessor&);
- ObjectAccessor& operator=(const ObjectAccessor&);
-
- public:
- /// @todo: Override these template functions for each holder type and add assertions
-
- static ObjectAccessor* instance()
- {
- static ObjectAccessor instance;
- return &instance;
- }
-
- // these functions return objects only if in map of specified object
- static WorldObject* GetWorldObject(WorldObject const&, ObjectGuid const&);
- static Object* GetObjectByTypeMask(WorldObject const&, ObjectGuid const&, uint32 typemask);
- static Corpse* GetCorpse(WorldObject const& u, ObjectGuid const& guid);
- static GameObject* GetGameObject(WorldObject const& u, ObjectGuid const& guid);
- static Transport* GetTransport(WorldObject const& u, ObjectGuid const& guid);
- static DynamicObject* GetDynamicObject(WorldObject const& u, ObjectGuid const& guid);
- static Unit* GetUnit(WorldObject const&, ObjectGuid const& guid);
- static Creature* GetCreature(WorldObject const& u, ObjectGuid const& guid);
- static Pet* GetPet(WorldObject const&, ObjectGuid const& guid);
- static Player* GetPlayer(Map const*, ObjectGuid const& guid);
- static Player* GetPlayer(WorldObject const&, ObjectGuid const& guid);
- static Creature* GetCreatureOrPetOrVehicle(WorldObject const&, ObjectGuid const&);
-
- // these functions return objects if found in whole world
- // ACCESS LIKE THAT IS NOT THREAD SAFE
- static Player* FindPlayer(ObjectGuid const&);
- static Player* FindPlayerByName(std::string const& name);
-
- // this returns Player even if he is not in world, for example teleporting
- static Player* FindConnectedPlayer(ObjectGuid const&);
- static Player* FindConnectedPlayerByName(std::string const& name);
-
- // when using this, you must use the hashmapholder's lock
- static HashMapHolder<Player>::MapType const& GetPlayers()
- {
- return HashMapHolder<Player>::GetContainer();
- }
-
- template<class T> static void AddObject(T* object)
- {
- HashMapHolder<T>::Insert(object);
- }
-
- template<class T> static void RemoveObject(T* object)
- {
- HashMapHolder<T>::Remove(object);
- }
-
- static void SaveAllPlayers();
-
- //non-static functions
-
- //Thread safe
- Corpse* GetCorpseForPlayerGUID(ObjectGuid const& guid);
- void RemoveCorpse(Corpse* corpse);
- void AddCorpse(Corpse* corpse);
- void AddCorpsesToGrid(GridCoord const& gridpair, GridType& grid, Map* map);
- Corpse* ConvertCorpseForPlayer(ObjectGuid const& player_guid, bool insignia = false);
-
- //Thread unsafe
- void RemoveOldCorpses();
- void UnloadAll();
-
- private:
- typedef std::unordered_map<ObjectGuid, Corpse*> Player2CorpsesMapType;
- typedef std::unordered_map<Player*, UpdateData>::value_type UpdateDataValueType;
-
- Player2CorpsesMapType i_player2corpse;
-
- boost::shared_mutex _corpseLock;
+ // these functions return objects only if in map of specified object
+ WorldObject* GetWorldObject(WorldObject const&, ObjectGuid const&);
+ Object* GetObjectByTypeMask(WorldObject const&, ObjectGuid const&, uint32 typemask);
+ Corpse* GetCorpse(WorldObject const& u, ObjectGuid const& guid);
+ GameObject* GetGameObject(WorldObject const& u, ObjectGuid const& guid);
+ Transport* GetTransport(WorldObject const& u, ObjectGuid const& guid);
+ DynamicObject* GetDynamicObject(WorldObject const& u, ObjectGuid const& guid);
+ Unit* GetUnit(WorldObject const&, ObjectGuid const& guid);
+ Creature* GetCreature(WorldObject const& u, ObjectGuid const& guid);
+ Pet* GetPet(WorldObject const&, ObjectGuid const& guid);
+ Player* GetPlayer(Map const*, ObjectGuid const& guid);
+ Player* GetPlayer(WorldObject const&, ObjectGuid const& guid);
+ Creature* GetCreatureOrPetOrVehicle(WorldObject const&, ObjectGuid const&);
+
+ // these functions return objects if found in whole world
+ // ACCESS LIKE THAT IS NOT THREAD SAFE
+ Player* FindPlayer(ObjectGuid const&);
+ Player* FindPlayerByName(std::string const& name);
+
+ // this returns Player even if he is not in world, for example teleporting
+ Player* FindConnectedPlayer(ObjectGuid const&);
+ Player* FindConnectedPlayerByName(std::string const& name);
+
+ // when using this, you must use the hashmapholder's lock
+ HashMapHolder<Player>::MapType const& GetPlayers();
+
+ template<class T>
+ void AddObject(T* object)
+ {
+ HashMapHolder<T>::Insert(object);
+ }
+
+ template<class T>
+ void RemoveObject(T* object)
+ {
+ HashMapHolder<T>::Remove(object);
+ }
+
+ void SaveAllPlayers();
};
-#define sObjectAccessor ObjectAccessor::instance()
#endif
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 4bf86facbef..b5d8d08a6a4 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -7358,20 +7358,6 @@ void ObjectMgr::DeleteGOData(uint32 guid)
_gameObjectDataStore.erase(guid);
}
-void ObjectMgr::AddCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid, uint32 instance)
-{
- // corpses are always added to spawn mode 0 and they are spawned by their instance id
- CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(mapid, 0)][cellid];
- cell_guids.corpses[player_guid] = instance;
-}
-
-void ObjectMgr::DeleteCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid)
-{
- // corpses are always added to spawn mode 0 and they are spawned by their instance id
- CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(mapid, 0)][cellid];
- cell_guids.corpses.erase(player_guid);
-}
-
void ObjectMgr::LoadQuestRelationsHelper(QuestRelations& map, QuestRelationsReverse* reverseMap, std::string const& table, bool starter, bool go)
{
uint32 oldMSTime = getMSTime();
@@ -8590,7 +8576,7 @@ void ObjectMgr::LoadScriptNames()
do
{
- _scriptNamesStore.emplace_back((*result)[0].GetCString());
+ _scriptNamesStore.push_back((*result)[0].GetString());
}
while (result->NextRow());
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index b9d755636cd..462370001dd 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -445,13 +445,11 @@ struct BroadcastText
typedef std::unordered_map<uint32, BroadcastText> BroadcastTextContainer;
-typedef std::set<uint32> CellGuidSet;
-typedef std::map<uint32/*player guid*/, uint32/*instance*/> CellCorpseSet;
+typedef std::set<ObjectGuid::LowType> CellGuidSet;
struct CellObjectGuids
{
CellGuidSet creatures;
CellGuidSet gameobjects;
- CellCorpseSet corpses;
};
typedef std::unordered_map<uint32/*cell_id*/, CellObjectGuids> CellObjectGuidsMap;
typedef std::unordered_map<uint32/*(mapid, spawnMode) pair*/, CellObjectGuidsMap> MapObjectGuids;
@@ -1219,9 +1217,6 @@ class ObjectMgr
LocaleConstant GetDBCLocaleIndex() const { return DBCLocaleIndex; }
void SetDBCLocaleIndex(LocaleConstant locale) { DBCLocaleIndex = locale; }
- void AddCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid, uint32 instance);
- void DeleteCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid);
-
// grid objects
void AddCreatureToGrid(uint32 guid, CreatureData const* data);
void RemoveCreatureFromGrid(uint32 guid, CreatureData const* data);
diff --git a/src/server/game/Grids/ObjectGridLoader.cpp b/src/server/game/Grids/ObjectGridLoader.cpp
index d0ae90d002f..de0ab490e9c 100644
--- a/src/server/game/Grids/ObjectGridLoader.cpp
+++ b/src/server/game/Grids/ObjectGridLoader.cpp
@@ -62,7 +62,7 @@ class ObjectWorldLoader
{
public:
explicit ObjectWorldLoader(ObjectGridLoader& gloader)
- : i_cell(gloader.i_cell), i_map(gloader.i_map), i_corpses (0)
+ : i_cell(gloader.i_cell), i_map(gloader.i_map), i_grid(gloader.i_grid), i_corpses(gloader.i_corpses)
{ }
void Visit(CorpseMapType &m);
@@ -72,8 +72,9 @@ class ObjectWorldLoader
private:
Cell i_cell;
Map* i_map;
+ NGridType& i_grid;
public:
- uint32 i_corpses;
+ uint32& i_corpses;
};
template<class T> void ObjectGridLoader::SetObjectCell(T* /*obj*/, CellCoord const& /*cellCoord*/) { }
@@ -129,38 +130,6 @@ void LoadHelper(CellGuidSet const& guid_set, CellCoord &cell, GridRefManager<T>
}
}
-void LoadHelper(CellCorpseSet const& cell_corpses, CellCoord &cell, CorpseMapType &m, uint32 &count, Map* map)
-{
- if (cell_corpses.empty())
- return;
-
- for (CellCorpseSet::const_iterator itr = cell_corpses.begin(); itr != cell_corpses.end(); ++itr)
- {
- if (itr->second != map->GetInstanceId())
- continue;
-
- ObjectGuid player_guid(HighGuid::Player, itr->first);
-
- Corpse* obj = sObjectAccessor->GetCorpseForPlayerGUID(player_guid);
- if (!obj)
- continue;
-
- /// @todo this is a hack
- // corpse's map should be reset when the map is unloaded
- // but it may still exist when the grid is unloaded but map is not
- // in that case map == currMap
- obj->SetMap(map);
-
- if (obj->IsInGrid())
- {
- obj->AddToWorld();
- continue;
- }
-
- AddObjectHelper(cell, m, count, map, obj);
- }
-}
-
void ObjectGridLoader::Visit(GameObjectMapType &m)
{
CellCoord cellCoord = i_cell.GetCellCoord();
@@ -175,22 +144,28 @@ void ObjectGridLoader::Visit(CreatureMapType &m)
LoadHelper(cell_guids.creatures, cellCoord, m, i_creatures, i_map);
}
-void ObjectWorldLoader::Visit(CorpseMapType &m)
+void ObjectWorldLoader::Visit(CorpseMapType& /*m*/)
{
CellCoord cellCoord = i_cell.GetCellCoord();
- // corpses are always added to spawn mode 0 and they are spawned by their instance id
- CellObjectGuids const& cell_guids = sObjectMgr->GetCellObjectGuids(i_map->GetId(), 0, cellCoord.GetId());
- LoadHelper(cell_guids.corpses, cellCoord, m, i_corpses, i_map);
+ if (std::unordered_set<Corpse*> const* corpses = i_map->GetCorpsesInCell(cellCoord.GetId()))
+ {
+ for (Corpse* corpse : *corpses)
+ {
+ corpse->AddToWorld();
+ i_grid.GetGridType(i_cell.CellX(), i_cell.CellY()).AddWorldObject(corpse);
+ ++i_corpses;
+ }
+ }
}
void ObjectGridLoader::LoadN(void)
{
i_gameObjects = 0; i_creatures = 0; i_corpses = 0;
i_cell.data.Part.cell_y = 0;
- for (unsigned int x=0; x < MAX_NUMBER_OF_CELLS; ++x)
+ for (uint32 x = 0; x < MAX_NUMBER_OF_CELLS; ++x)
{
i_cell.data.Part.cell_x = x;
- for (unsigned int y=0; y < MAX_NUMBER_OF_CELLS; ++y)
+ for (uint32 y = 0; y < MAX_NUMBER_OF_CELLS; ++y)
{
i_cell.data.Part.cell_y = y;
@@ -205,7 +180,6 @@ void ObjectGridLoader::LoadN(void)
ObjectWorldLoader worker(*this);
TypeContainerVisitor<ObjectWorldLoader, WorldTypeMapContainer> visitor(worker);
i_grid.VisitGrid(x, y, visitor);
- i_corpses += worker.i_corpses;
}
}
}
diff --git a/src/server/game/Handlers/AuctionHouseHandler.cpp b/src/server/game/Handlers/AuctionHouseHandler.cpp
index aa51b19a659..0293901c9e3 100644
--- a/src/server/game/Handlers/AuctionHouseHandler.cpp
+++ b/src/server/game/Handlers/AuctionHouseHandler.cpp
@@ -154,7 +154,6 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData)
return;
}
-
Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer, UNIT_NPC_FLAG_AUCTIONEER);
if (!creature)
{
@@ -259,9 +258,26 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData)
AuctionEntry* AH = new AuctionEntry();
if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
- AH->auctioneer = 23442; ///@TODO - HARDCODED DB GUID, BAD BAD BAD
+ AH->houseId = AUCTIONHOUSE_NEUTRAL;
else
- AH->auctioneer = auctioneer.GetCounter();
+ {
+ CreatureData const* auctioneerData = sObjectMgr->GetCreatureData(creature->GetSpawnId());
+ if (!auctioneerData)
+ {
+ TC_LOG_ERROR("misc", "Data for auctioneer not found (%s)", auctioneer.ToString().c_str());
+ return;
+ }
+
+ CreatureTemplate const* auctioneerInfo = sObjectMgr->GetCreatureTemplate(auctioneerData->id);
+ if (!auctioneerInfo)
+ {
+ TC_LOG_ERROR("misc", "Non existing auctioneer (%s)", auctioneer.ToString().c_str());
+ return;
+ }
+
+ const AuctionHouseEntry* AHEntry = sAuctionMgr->GetAuctionHouseEntry(auctioneerInfo->faction);
+ AH->houseId = AHEntry->houseId;
+ }
// Required stack size of auction matches to current item stack size, just move item to auctionhouse
if (itemsCount == 1 && item->GetCount() == count[0])
@@ -285,8 +301,8 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData)
AH->deposit = deposit;
AH->auctionHouseEntry = auctionHouseEntry;
- TC_LOG_INFO("network", "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) to auctioneer %u with count %u with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u",
- _player->GetName().c_str(), _player->GetGUID().GetCounter(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetGUID().GetCounter(), AH->auctioneer, item->GetCount(), bid, buyout, auctionTime, AH->GetHouseId());
+ TC_LOG_INFO("network", "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) with count %u with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u",
+ _player->GetName().c_str(), _player->GetGUID().GetCounter(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetGUID().GetCounter(), item->GetCount(), bid, buyout, auctionTime, AH->GetHouseId());
sAuctionMgr->AddAItem(item);
auctionHouse->AddAuction(AH);
@@ -333,8 +349,8 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData)
AH->deposit = deposit;
AH->auctionHouseEntry = auctionHouseEntry;
- TC_LOG_INFO("network", "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) to auctioneer %u with count %u with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u",
- _player->GetName().c_str(), _player->GetGUID().GetCounter(), newItem->GetTemplate()->Name1.c_str(), newItem->GetEntry(), newItem->GetGUID().GetCounter(), AH->auctioneer, newItem->GetCount(), bid, buyout, auctionTime, AH->GetHouseId());
+ TC_LOG_INFO("network", "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) with count %u with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u",
+ _player->GetName().c_str(), _player->GetGUID().GetCounter(), newItem->GetTemplate()->Name1.c_str(), newItem->GetEntry(), newItem->GetGUID().GetCounter(), newItem->GetCount(), bid, buyout, auctionTime, AH->GetHouseId());
sAuctionMgr->AddAItem(newItem);
auctionHouse->AddAuction(AH);
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index 61b2837dc10..ba22ab6aa07 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -203,6 +203,10 @@ bool LoginQueryHolder::Initialize()
stmt->setUInt32(0, m_accountId);
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_INSTANCE_LOCK_TIMES, stmt);
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CORPSE_LOCATION);
+ stmt->setUInt64(0, lowGuid);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_CORPSE_LOCATION, stmt);
+
return res;
}
@@ -892,7 +896,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder)
pCurrChar->TeleportTo(pCurrChar->m_homebindMapId, pCurrChar->m_homebindX, pCurrChar->m_homebindY, pCurrChar->m_homebindZ, pCurrChar->GetOrientation());
}
- sObjectAccessor->AddObject(pCurrChar);
+ ObjectAccessor::AddObject(pCurrChar);
//TC_LOG_DEBUG("Player %s added to Map.", pCurrChar->GetName().c_str());
pCurrChar->SendInitialPacketsAfterAddToMap();
@@ -923,7 +927,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder)
sSocialMgr->SendFriendStatus(pCurrChar, FRIEND_ONLINE, pCurrChar->GetGUID().GetCounter(), true);
// Place character in world (and load zone) before some object loading
- pCurrChar->LoadCorpse();
+ pCurrChar->LoadCorpse(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CORPSE_LOCATION));
// setting Ghost+speed if dead
if (pCurrChar->m_deathState != ALIVE)
@@ -1672,11 +1676,11 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData)
}
}
- // resurrect the character in case he's dead
- sObjectAccessor->ConvertCorpseForPlayer(factionChangeInfo.Guid);
-
SQLTransaction trans = CharacterDatabase.BeginTransaction();
+ // resurrect the character in case he's dead
+ Player::OfflineResurrect(factionChangeInfo.Guid, trans);
+
CharacterDatabase.EscapeString(factionChangeInfo.Name);
Player::Customize(&factionChangeInfo, trans);
@@ -1820,6 +1824,7 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData)
trans->Append(stmt);
}
+ /// @todo: make this part async
if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD))
{
// Reset guild
diff --git a/src/server/game/Handlers/DuelHandler.cpp b/src/server/game/Handlers/DuelHandler.cpp
index 2f39a91afbe..6e8ff5547d7 100644
--- a/src/server/game/Handlers/DuelHandler.cpp
+++ b/src/server/game/Handlers/DuelHandler.cpp
@@ -43,6 +43,9 @@ void WorldSession::HandleDuelAcceptedOpcode(WorldPacket& recvPacket)
TC_LOG_DEBUG("network", "Player 1 is: %u (%s)", player->GetGUID().GetCounter(), player->GetName().c_str());
TC_LOG_DEBUG("network", "Player 2 is: %u (%s)", plTarget->GetGUID().GetCounter(), plTarget->GetName().c_str());
+ player->UpdateHasCoolDownBeforeDuel();
+ plTarget->UpdateHasCoolDownBeforeDuel();
+
time_t now = time(NULL);
player->duel->startTimer = now;
plTarget->duel->startTimer = now;
diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp
index 51f7e3f840a..2eebbfc1004 100644
--- a/src/server/game/Handlers/MiscHandler.cpp
+++ b/src/server/game/Handlers/MiscHandler.cpp
@@ -741,7 +741,6 @@ void WorldSession::HandleReclaimCorpseOpcode(WorldPacket& recvData)
return;
Corpse* corpse = _player->GetCorpse();
-
if (!corpse)
return;
diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp
index 518baa42e97..84816bf3f33 100644
--- a/src/server/game/Handlers/MovementHandler.cpp
+++ b/src/server/game/Handlers/MovementHandler.cpp
@@ -142,8 +142,8 @@ void WorldSession::HandleMoveWorldportAckOpcode()
}
// resurrect character at enter into instance where his corpse exist after add to map
- Corpse* corpse = GetPlayer()->GetCorpse();
- if (corpse && corpse->GetType() != CORPSE_BONES && corpse->GetMapId() == GetPlayer()->GetMapId())
+ Corpse* corpse = GetPlayer()->GetMap()->GetCorpseByPlayer(GetPlayer()->GetGUID());
+ if (corpse && corpse->GetType() != CORPSE_BONES)
{
if (mEntry->IsDungeon())
{
diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp
index 14436a864f9..f8d7f73e077 100644
--- a/src/server/game/Handlers/NPCHandler.cpp
+++ b/src/server/game/Handlers/NPCHandler.cpp
@@ -403,10 +403,12 @@ void WorldSession::SendSpiritResurrect()
// get corpse nearest graveyard
WorldSafeLocsEntry const* corpseGrave = NULL;
- Corpse* corpse = _player->GetCorpse();
- if (corpse)
- corpseGrave = sObjectMgr->GetClosestGraveYard(
- corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetMapId(), _player->GetTeam());
+ WorldLocation corpseLocation = _player->GetCorpseLocation();
+ if (_player->HasCorpse())
+ {
+ corpseGrave = sObjectMgr->GetClosestGraveYard(corpseLocation.GetPositionX(), corpseLocation.GetPositionY(),
+ corpseLocation.GetPositionZ(), corpseLocation.GetMapId(), _player->GetTeam());
+ }
// now can spawn bones
_player->SpawnCorpseBones();
diff --git a/src/server/game/Handlers/QueryHandler.cpp b/src/server/game/Handlers/QueryHandler.cpp
index 906c3017100..6d896bee26c 100644
--- a/src/server/game/Handlers/QueryHandler.cpp
+++ b/src/server/game/Handlers/QueryHandler.cpp
@@ -218,11 +218,7 @@ void WorldSession::HandleGameObjectQueryOpcode(WorldPacket& recvData)
void WorldSession::HandleCorpseQueryOpcode(WorldPacket & /*recvData*/)
{
- TC_LOG_DEBUG("network", "WORLD: Received MSG_CORPSE_QUERY");
-
- Corpse* corpse = GetPlayer()->GetCorpse();
-
- if (!corpse)
+ if (!_player->HasCorpse())
{
WorldPacket data(MSG_CORPSE_QUERY, 1);
data << uint8(0); // corpse not found
@@ -230,24 +226,25 @@ void WorldSession::HandleCorpseQueryOpcode(WorldPacket & /*recvData*/)
return;
}
- uint32 mapid = corpse->GetMapId();
- float x = corpse->GetPositionX();
- float y = corpse->GetPositionY();
- float z = corpse->GetPositionZ();
- uint32 corpsemapid = mapid;
+ WorldLocation corpseLocation = _player->GetCorpseLocation();
+ uint32 corpseMapID = corpseLocation.GetMapId();
+ uint32 mapID = corpseLocation.GetMapId();
+ float x = corpseLocation.GetPositionX();
+ float y = corpseLocation.GetPositionY();
+ float z = corpseLocation.GetPositionZ();
// if corpse at different map
- if (mapid != _player->GetMapId())
+ if (mapID != _player->GetMapId())
{
// search entrance map for proper show entrance
- if (MapEntry const* corpseMapEntry = sMapStore.LookupEntry(mapid))
+ if (MapEntry const* corpseMapEntry = sMapStore.LookupEntry(mapID))
{
if (corpseMapEntry->IsDungeon() && corpseMapEntry->entrance_map >= 0)
{
// if corpse map have entrance
if (Map const* entranceMap = sMapMgr->CreateBaseMap(corpseMapEntry->entrance_map))
{
- mapid = corpseMapEntry->entrance_map;
+ mapID = corpseMapEntry->entrance_map;
x = corpseMapEntry->entrance_x;
y = corpseMapEntry->entrance_y;
z = entranceMap->GetHeight(GetPlayer()->GetPhaseMask(), x, y, MAX_HEIGHT);
@@ -258,11 +255,11 @@ void WorldSession::HandleCorpseQueryOpcode(WorldPacket & /*recvData*/)
WorldPacket data(MSG_CORPSE_QUERY, 1+(6*4));
data << uint8(1); // corpse found
- data << int32(mapid);
+ data << int32(mapID);
data << float(x);
data << float(y);
data << float(z);
- data << int32(corpsemapid);
+ data << int32(corpseMapID);
data << uint32(0); // unknown
SendPacket(&data);
}
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index b50099b9787..2af77ffdec3 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -50,9 +50,9 @@ GridState* si_GridStates[MAX_GRID_STATE];
Map::~Map()
{
- sScriptMgr->OnDestroyMap(this);
+ // UnloadAll must be called before deleting the map
- UnloadAll();
+ sScriptMgr->OnDestroyMap(this);
while (!i_worldObjects.empty())
{
@@ -400,11 +400,18 @@ void Map::DeleteFromWorld(T* obj)
template<>
void Map::DeleteFromWorld(Player* player)
{
- sObjectAccessor->RemoveObject(player);
+ ObjectAccessor::RemoveObject(player);
RemoveUpdateObject(player); /// @todo I do not know why we need this, it should be removed in ~Object anyway
delete player;
}
+template<>
+void Map::DeleteFromWorld(Transport* transport)
+{
+ ObjectAccessor::RemoveObject(transport);
+ delete transport;
+}
+
void Map::EnsureGridCreated(const GridCoord &p)
{
std::lock_guard<std::mutex> lock(_gridLock);
@@ -468,8 +475,6 @@ bool Map::EnsureGridLoaded(const Cell &cell)
ObjectGridLoader loader(*grid, this, cell);
loader.LoadN();
- // Add resurrectable corpses to world object list in grid
- sObjectAccessor->AddCorpsesToGrid(GridCoord(cell.GridX(), cell.GridY()), grid->GetGridType(cell.CellX(), cell.CellY()), this);
Balance();
return true;
}
@@ -507,6 +512,9 @@ bool Map::AddPlayerToMap(Player* player)
player->m_clientGUIDs.clear();
player->UpdateObjectVisibility(false);
+ if (player->IsAlive())
+ ConvertCorpseToBones(player->GetGUID());
+
sScriptMgr->OnPlayerEnterMap(this, player);
return true;
}
@@ -2610,7 +2618,7 @@ void Map::SendObjectUpdates()
_updateObjects.erase(_updateObjects.begin());
obj->BuildUpdate(update_players);
}
-
+
WorldPacket packet; // here we allocate a std::vector with a size of 0x10000
for (UpdateDataMapType::iterator iter = update_players.begin(); iter != update_players.end(); ++iter)
{
@@ -3530,7 +3538,6 @@ void Map::LoadCorpseData()
if (!result)
return;
- uint32 count = 0;
do
{
Field* fields = result->Fetch();
@@ -3550,8 +3557,8 @@ void Map::LoadCorpseData()
continue;
}
- sObjectAccessor->AddCorpse(corpse);
- ++count;
+ AddCorpse(corpse);
+
} while (result->NextRow());
}
@@ -3564,6 +3571,97 @@ void Map::DeleteCorpseData()
CharacterDatabase.Execute(stmt);
}
+void Map::AddCorpse(Corpse* corpse)
+{
+ corpse->SetMap(this);
+
+ CellCoord cellCoord = Trinity::ComputeCellCoord(corpse->GetPositionX(), corpse->GetPositionY());
+ _corpsesByCell[cellCoord.GetId()].insert(corpse);
+ _corpsesByPlayer[corpse->GetOwnerGUID()] = corpse;
+}
+
+void Map::RemoveCorpse(Corpse* corpse)
+{
+ ASSERT(corpse && corpse->GetType() != CORPSE_BONES);
+
+ corpse->DestroyForNearbyPlayers();
+ if (corpse->IsInGrid())
+ RemoveFromMap(corpse, false);
+ else
+ {
+ corpse->RemoveFromWorld();
+ corpse->ResetMap();
+ }
+
+ CellCoord cellCoord = Trinity::ComputeCellCoord(corpse->GetPositionX(), corpse->GetPositionY());
+ _corpsesByCell[cellCoord.GetId()].erase(corpse);
+ _corpsesByPlayer.erase(corpse->GetOwnerGUID());
+}
+
+Corpse* Map::ConvertCorpseToBones(ObjectGuid const& ownerGuid, bool insignia /*= false*/)
+{
+ Corpse* corpse = GetCorpseByPlayer(ownerGuid);
+ if (!corpse)
+ return nullptr;
+
+ RemoveCorpse(corpse);
+
+ // remove corpse from DB
+ SQLTransaction trans = CharacterDatabase.BeginTransaction();
+ corpse->DeleteFromDB(trans);
+ CharacterDatabase.CommitTransaction(trans);
+
+ Corpse* bones = NULL;
+
+ // create the bones only if the map and the grid is loaded at the corpse's location
+ // ignore bones creating option in case insignia
+ if ((insignia ||
+ (IsBattlegroundOrArena() ? sWorld->getBoolConfig(CONFIG_DEATH_BONES_BG_OR_ARENA) : sWorld->getBoolConfig(CONFIG_DEATH_BONES_WORLD))) &&
+ !IsRemovalGrid(corpse->GetPositionX(), corpse->GetPositionY()))
+ {
+ // Create bones, don't change Corpse
+ bones = new Corpse();
+ bones->Create(corpse->GetGUID().GetCounter(), this);
+
+ for (uint8 i = OBJECT_FIELD_TYPE + 1; i < CORPSE_END; ++i) // don't overwrite guid and object type
+ bones->SetUInt32Value(i, corpse->GetUInt32Value(i));
+
+ bones->SetGridCoord(corpse->GetGridCoord());
+ bones->Relocate(corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetOrientation());
+ bones->SetPhaseMask(corpse->GetPhaseMask(), false);
+
+ bones->SetUInt32Value(CORPSE_FIELD_FLAGS, CORPSE_FLAG_UNK2 | CORPSE_FLAG_BONES);
+ bones->SetGuidValue(CORPSE_FIELD_OWNER, ObjectGuid::Empty);
+
+ for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i)
+ if (corpse->GetUInt32Value(CORPSE_FIELD_ITEM + i))
+ bones->SetUInt32Value(CORPSE_FIELD_ITEM + i, 0);
+
+ // add bones in grid store if grid loaded where corpse placed
+ AddToMap(bones);
+ }
+
+ // all references to the corpse should be removed at this point
+ delete corpse;
+
+ return bones;
+}
+
+void Map::RemoveOldCorpses()
+{
+ time_t now = time(nullptr);
+
+ std::vector<ObjectGuid> corpses;
+ corpses.reserve(_corpsesByPlayer.size());
+
+ for (auto const& p : _corpsesByPlayer)
+ if (p.second->IsExpired(now))
+ corpses.push_back(p.first);
+
+ for (ObjectGuid const& ownerGuid : corpses)
+ ConvertCorpseToBones(ownerGuid);
+}
+
void Map::SendZoneDynamicInfo(Player* player)
{
uint32 zoneId = GetZoneId(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ());
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index 9b5e67cdfaf..2ba5e10c82c 100644
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -459,6 +459,24 @@ class Map : public GridRefManager<NGridType>
typedef std::unordered_multimap<ObjectGuid::LowType, GameObject*> GameObjectBySpawnIdContainer;
GameObjectBySpawnIdContainer& GetGameObjectBySpawnIdStore() { return _gameobjectBySpawnIdStore; }
+ std::unordered_set<Corpse*> const* GetCorpsesInCell(uint32 cellId) const
+ {
+ auto itr = _corpsesByCell.find(cellId);
+ if (itr != _corpsesByCell.end())
+ return &itr->second;
+
+ return nullptr;
+ }
+
+ Corpse* GetCorpseByPlayer(ObjectGuid const& ownerGuid) const
+ {
+ auto itr = _corpsesByPlayer.find(ownerGuid);
+ if (itr != _corpsesByPlayer.end())
+ return itr->second;
+
+ return nullptr;
+ }
+
MapInstanced* ToMapInstanced() { if (Instanceable()) return reinterpret_cast<MapInstanced*>(this); return NULL; }
MapInstanced const* ToMapInstanced() const { if (Instanceable()) return reinterpret_cast<MapInstanced const*>(this); return NULL; }
@@ -508,6 +526,10 @@ class Map : public GridRefManager<NGridType>
void LoadCorpseData();
void DeleteCorpseData();
+ void AddCorpse(Corpse* corpse);
+ void RemoveCorpse(Corpse* corpse);
+ Corpse* ConvertCorpseToBones(ObjectGuid const& ownerGuid, bool insignia = false);
+ void RemoveOldCorpses();
static void DeleteRespawnTimesInDB(uint16 mapId, uint32 instanceId);
@@ -709,6 +731,8 @@ class Map : public GridRefManager<NGridType>
MapStoredObjectTypesContainer _objectsStore;
CreatureBySpawnIdContainer _creatureBySpawnIdStore;
GameObjectBySpawnIdContainer _gameobjectBySpawnIdStore;
+ std::unordered_map<uint32/*cellId*/, std::unordered_set<Corpse*>> _corpsesByCell;
+ std::unordered_map<ObjectGuid, Corpse*> _corpsesByPlayer;
std::unordered_set<Object*> _updateObjects;
};
diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp
index 82be6336dc6..0e7f9dbb611 100644
--- a/src/server/game/Maps/MapManager.cpp
+++ b/src/server/game/Maps/MapManager.cpp
@@ -164,10 +164,10 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck)
if (!player->IsAlive())
{
- if (Corpse* corpse = player->GetCorpse())
+ if (player->HasCorpse())
{
// let enter in ghost mode in instance that connected to inner instance with corpse
- uint32 corpseMap = corpse->GetMapId();
+ uint32 corpseMap = player->GetCorpseLocation().GetMapId();
do
{
if (corpseMap == mapid)
@@ -184,9 +184,8 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck)
TC_LOG_DEBUG("maps", "MAP: Player '%s' does not have a corpse in instance '%s' and cannot enter.", player->GetName().c_str(), mapName);
return false;
}
+
TC_LOG_DEBUG("maps", "MAP: Player '%s' has corpse in instance '%s' and can enter.", player->GetName().c_str(), mapName);
- player->ResurrectPlayer(0.5f, false);
- player->SpawnCorpseBones();
}
else
TC_LOG_DEBUG("maps", "Map::CanPlayerEnter - player '%s' is dead but does not have a corpse!", player->GetName().c_str());
diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h
index a4ba9866064..d374c8c509a 100644
--- a/src/server/game/Miscellaneous/Language.h
+++ b/src/server/game/Miscellaneous/Language.h
@@ -1202,6 +1202,8 @@ enum TrinityStrings
LANG_BAN_ACCOUNT_YOUPERMBANNEDMESSAGE_WORLD = 11007,
LANG_NPCINFO_INHABIT_TYPE = 11008,
- LANG_NPCINFO_FLAGS_EXTRA = 11009
+ LANG_NPCINFO_FLAGS_EXTRA = 11009,
+
+ LANG_COOLDOWN_NOT_RESET_AFTER_DUEL = 11010
};
#endif
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index e6896003175..45a816eda9b 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -709,7 +709,7 @@ void WorldSession::LoadAccountData(PreparedQueryResult result, uint32 mask)
void WorldSession::SetAccountData(AccountDataType type, time_t tm, std::string const& data)
{
uint32 id = 0;
- uint32 index = 0;
+ CharacterDatabaseStatements index;
if ((1 << type) & GLOBAL_CACHE_MASK)
{
id = GetAccountId();
@@ -840,13 +840,33 @@ void WorldSession::ReadMovementInfo(WorldPacket &data, MovementInfo* mi)
mi->RemoveMovementFlag((maskToRemove));
#endif
-
/*! This must be a packet spoofing attempt. MOVEMENTFLAG_ROOT sent from the client is not valid
in conjunction with any of the moving movement flags such as MOVEMENTFLAG_FORWARD.
It will freeze clients that receive this player's movement info.
*/
- REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_ROOT),
- MOVEMENTFLAG_ROOT);
+ // Only adjust movement flag removal for vehicles with the VEHICLE_FLAG_FIXED_POSITION flag, or the hard coded exceptions below:
+ // 30236 | Argent Cannon
+ // 39759 | Tankbuster Cannon
+ if (GetPlayer()->GetVehicleBase() && ((GetPlayer()->GetVehicle()->GetVehicleInfo()->m_flags & VEHICLE_FLAG_FIXED_POSITION) || GetPlayer()->GetVehicleBase()->GetEntry() == 30236 || GetPlayer()->GetVehicleBase()->GetEntry() == 39759))
+ {
+ // Actually players in rooted vehicles still send commands, don't clear root for these!
+ // Check specifically for the following conditions:
+ // MOVEMENTFLAG_ROOT + no other flags (0x800)
+ // MOVEMENTFLAG_ROOT + MOVEMENTFLAG_LEFT (0x810)
+ // MOVEMENTFLAG_ROOT + MOVEMENTFLAG_RIGHT (0x820)
+ // MOVEMENTFLAG_ROOT + MOVEMENTFLAG_PITCH_UP (0x840)
+ // MOVEMENTFLAG_ROOT + MOVEMENTFLAG_PITCH_DOWN (0x880)
+ // If none of these are true, clear the root
+ if (mi->HasMovementFlag(MOVEMENTFLAG_ROOT) && mi->HasMovementFlag(MOVEMENTFLAG_LEFT | MOVEMENTFLAG_RIGHT | MOVEMENTFLAG_PITCH_UP | MOVEMENTFLAG_PITCH_DOWN))
+ REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_ROOT),
+ MOVEMENTFLAG_MASK_MOVING);
+ }
+ else
+ {
+ // Only remove here for non vehicles
+ REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_ROOT),
+ MOVEMENTFLAG_ROOT);
+ }
//! Cannot hover without SPELL_AURA_HOVER
REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_HOVER) && !GetPlayer()->HasAuraType(SPELL_AURA_HOVER),
diff --git a/src/server/game/Spells/SpellHistory.cpp b/src/server/game/Spells/SpellHistory.cpp
index 09e3be690b1..208b4cf7ed9 100644
--- a/src/server/game/Spells/SpellHistory.cpp
+++ b/src/server/game/Spells/SpellHistory.cpp
@@ -637,6 +637,23 @@ void SpellHistory::BuildCooldownPacket(WorldPacket& data, uint8 flags, PacketCoo
}
}
+uint16 SpellHistory::GetArenaCooldownsSize()
+{
+ uint16 count = 0;
+
+ for (auto itr = _spellCooldowns.begin(); itr != _spellCooldowns.end();)
+ {
+ SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first);
+
+ if (spellInfo->RecoveryTime < 10 * MINUTE * IN_MILLISECONDS &&
+ spellInfo->CategoryRecoveryTime < 10 * MINUTE * IN_MILLISECONDS)
+ ++count;
+ ++itr;
+ }
+
+ return count;
+}
+
template void SpellHistory::LoadFromDB<Player>(PreparedQueryResult cooldownsResult);
template void SpellHistory::LoadFromDB<Pet>(PreparedQueryResult cooldownsResult);
template void SpellHistory::SaveToDB<Player>(SQLTransaction& trans);
diff --git a/src/server/game/Spells/SpellHistory.h b/src/server/game/Spells/SpellHistory.h
index f1533d57aef..4d0642d644e 100644
--- a/src/server/game/Spells/SpellHistory.h
+++ b/src/server/game/Spells/SpellHistory.h
@@ -117,6 +117,7 @@ public:
void BuildCooldownPacket(WorldPacket& data, uint8 flags, uint32 spellId, uint32 cooldown) const;
CooldownStorageType::size_type GetCooldownsSizeForPacket() const { return _spellCooldowns.size(); }
+ uint16 GetArenaCooldownsSize();
private:
Player* GetPlayerOwner() const;
diff --git a/src/server/game/Tickets/TicketMgr.cpp b/src/server/game/Tickets/TicketMgr.cpp
index a51c9fb16d2..dbf66c6bd71 100644
--- a/src/server/game/Tickets/TicketMgr.cpp
+++ b/src/server/game/Tickets/TicketMgr.cpp
@@ -75,8 +75,8 @@ bool GmTicket::LoadFromDB(Field* fields)
void GmTicket::SaveToDB(SQLTransaction& trans) const
{
- // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
- // ticketId, guid, name, message, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, completed, escalated, viewed
+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
+ // id, playerGuid, name, description, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, needMoreHelp, resolvedBy
uint8 index = 0;
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GM_TICKET);
stmt->setUInt32( index, _id);
@@ -97,6 +97,7 @@ void GmTicket::SaveToDB(SQLTransaction& trans) const
stmt->setUInt8 (++index, uint8(_escalatedStatus));
stmt->setBool (++index, _viewed);
stmt->setBool (++index, _needMoreHelp);
+ stmt->setInt32 (++index, int32(_resolvedBy.GetCounter()));
CharacterDatabase.ExecuteOrAppend(trans, stmt);
}
@@ -361,6 +362,19 @@ void TicketMgr::CloseTicket(uint32 ticketId, ObjectGuid source)
}
}
+void TicketMgr::ResolveAndCloseTicket(uint32 ticketId, ObjectGuid source)
+{
+ if (GmTicket* ticket = GetTicket(ticketId))
+ {
+ SQLTransaction trans = SQLTransaction(nullptr);
+ ticket->SetClosedBy(source);
+ ticket->SetResolvedBy(source);
+ if (source)
+ --_openTicketCount;
+ ticket->SaveToDB(trans);
+ }
+}
+
void TicketMgr::RemoveTicket(uint32 ticketId)
{
if (GmTicket* ticket = GetTicket(ticketId))
diff --git a/src/server/game/Tickets/TicketMgr.h b/src/server/game/Tickets/TicketMgr.h
index e9892c22edc..f7d3178978f 100644
--- a/src/server/game/Tickets/TicketMgr.h
+++ b/src/server/game/Tickets/TicketMgr.h
@@ -119,6 +119,7 @@ public:
_escalatedStatus = TICKET_ASSIGNED;
}
void SetClosedBy(ObjectGuid value) { _closedBy = value; }
+ void SetResolvedBy(ObjectGuid value) { _resolvedBy = value; }
void SetCompleted() { _completed = true; }
void SetMessage(std::string const& message)
{
@@ -158,7 +159,8 @@ private:
std::string _message;
uint64 _createTime;
uint64 _lastModifiedTime;
- ObjectGuid _closedBy; // 0 = Open, -1 = Console, playerGuid = player abandoned ticket, other = GM who closed it.
+ ObjectGuid _closedBy; // 0 = Open, -1 = Console, playerGuid = player abandoned ticket or read the GM response message, other = GM who closed it.
+ ObjectGuid _resolvedBy; // 0 = Open, -1 = Resolved by Console, GM who resolved it by closing or completing the ticket.
ObjectGuid _assignedTo;
std::string _comment;
bool _completed;
@@ -216,6 +218,7 @@ public:
void AddTicket(GmTicket* ticket);
void CloseTicket(uint32 ticketId, ObjectGuid source);
+ void ResolveAndCloseTicket(uint32 ticketId, ObjectGuid source); // used when GM resolves a ticket by simply closing it
void RemoveTicket(uint32 ticketId);
bool GetStatus() const { return _status; }
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index ce1837fbc86..85e79168b71 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1190,6 +1190,7 @@ void World::LoadConfigSettings(bool reload)
m_int_configs[CONFIG_MAX_WHO] = sConfigMgr->GetIntDefault("MaxWhoListReturns", 49);
m_bool_configs[CONFIG_START_ALL_SPELLS] = sConfigMgr->GetBoolDefault("PlayerStart.AllSpells", false);
m_int_configs[CONFIG_HONOR_AFTER_DUEL] = sConfigMgr->GetIntDefault("HonorPointsAfterDuel", 0);
+ m_bool_configs[CONFIG_RESET_COOLDOWN_AFTER_DUEL] = sConfigMgr->GetBoolDefault("ResetCoolDownAfterDuel", 0);
m_bool_configs[CONFIG_START_ALL_EXPLORED] = sConfigMgr->GetBoolDefault("PlayerStart.MapsExplored", false);
m_bool_configs[CONFIG_START_ALL_REP] = sConfigMgr->GetBoolDefault("PlayerStart.AllReputation", false);
m_bool_configs[CONFIG_ALWAYS_MAXSKILL] = sConfigMgr->GetBoolDefault("AlwaysMaxWeaponSkill", false);
@@ -2150,7 +2151,10 @@ void World::Update(uint32 diff)
if (m_timers[WUPDATE_CORPSES].Passed())
{
m_timers[WUPDATE_CORPSES].Reset();
- sObjectAccessor->RemoveOldCorpses();
+ sMapMgr->DoForAllMaps([](Map* map)
+ {
+ map->RemoveOldCorpses();
+ });
}
///- Process Game events when necessary
@@ -3264,3 +3268,9 @@ void World::ReloadRBAC()
if (WorldSession* session = itr->second)
session->InvalidateRBACData();
}
+
+void World::RemoveOldCorpses()
+{
+ m_timers[WUPDATE_CORPSES].SetCurrent(m_timers[WUPDATE_CORPSES].GetInterval());
+}
+
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index af89adcb04e..1f71975cde2 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -161,6 +161,7 @@ enum WorldBoolConfigs
CONFIG_ALLOW_TRACK_BOTH_RESOURCES,
CONFIG_CALCULATE_CREATURE_ZONE_AREA_DATA,
CONFIG_CALCULATE_GAMEOBJECT_ZONE_AREA_DATA,
+ CONFIG_RESET_COOLDOWN_AFTER_DUEL,
BOOL_CONFIG_VALUE_COUNT
};
@@ -761,6 +762,8 @@ class World
void ReloadRBAC();
+ void RemoveOldCorpses();
+
protected:
void _UpdateGameTime();
// callback for UpdateRealmCharacters
diff --git a/src/server/scripts/Commands/cs_gobject.cpp b/src/server/scripts/Commands/cs_gobject.cpp
index 591f797bfee..0a45506c736 100644
--- a/src/server/scripts/Commands/cs_gobject.cpp
+++ b/src/server/scripts/Commands/cs_gobject.cpp
@@ -166,6 +166,8 @@ public:
// fill the gameobject data and save to the db
object->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), player->GetPhaseMaskForSpawn());
+ guidLow = object->GetSpawnId();
+
// delete the old object and do a clean load from DB with a fresh new GameObject instance.
// this is required to avoid weird behavior and memory leaks
delete object;
@@ -426,16 +428,26 @@ public:
o = player->GetOrientation();
}
+ Map* map = object->GetMap();
+
object->Relocate(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), o);
object->UpdateRotationFields();
- object->DestroyForNearbyPlayers();
- object->UpdateObjectVisibility();
-
object->SaveToDB();
- object->Refresh();
- handler->PSendSysMessage(LANG_COMMAND_TURNOBJMESSAGE, object->GetGUID().GetCounter(), object->GetGOInfo()->name.c_str(), object->GetGUID().GetCounter(), o);
+ // Generate a completely new spawn with new guid
+ // 3.3.5a client caches recently deleted objects and brings them back to life
+ // when CreateObject block for this guid is received again
+ // however it entirely skips parsing that block and only uses already known location
+ object->Delete();
+
+ object = new GameObject();
+ if (!object->LoadGameObjectFromDB(guidLow, map))
+ {
+ delete object;
+ return false;
+ }
+ handler->PSendSysMessage(LANG_COMMAND_TURNOBJMESSAGE, object->GetSpawnId(), object->GetGOInfo()->name.c_str(), object->GetSpawnId());
return true;
}
@@ -468,21 +480,20 @@ public:
char* toY = strtok(NULL, " ");
char* toZ = strtok(NULL, " ");
+ float x, y, z;
if (!toX)
{
Player* player = handler->GetSession()->GetPlayer();
- object->Relocate(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), object->GetOrientation());
- object->DestroyForNearbyPlayers();
- object->UpdateObjectVisibility();
+ player->GetPosition(x, y, z);
}
else
{
if (!toY || !toZ)
return false;
- float x = (float)atof(toX);
- float y = (float)atof(toY);
- float z = (float)atof(toZ);
+ x = (float)atof(toX);
+ y = (float)atof(toY);
+ z = (float)atof(toZ);
if (!MapManager::IsValidMapCoord(object->GetMapId(), x, y, z))
{
@@ -490,17 +501,27 @@ public:
handler->SetSentErrorMessage(true);
return false;
}
-
- object->Relocate(x, y, z, object->GetOrientation());
- object->DestroyForNearbyPlayers();
- object->UpdateObjectVisibility();
}
+ Map* map = object->GetMap();
+
+ object->Relocate(x, y, z, object->GetOrientation());
object->SaveToDB();
- object->Refresh();
- handler->PSendSysMessage(LANG_COMMAND_MOVEOBJMESSAGE, object->GetGUID().GetCounter(), object->GetGOInfo()->name.c_str(), object->GetGUID().GetCounter());
+ // Generate a completely new spawn with new guid
+ // 3.3.5a client caches recently deleted objects and brings them back to life
+ // when CreateObject block for this guid is received again
+ // however it entirely skips parsing that block and only uses already known location
+ object->Delete();
+
+ object = new GameObject();
+ if (!object->LoadGameObjectFromDB(guidLow, map))
+ {
+ delete object;
+ return false;
+ }
+ handler->PSendSysMessage(LANG_COMMAND_MOVEOBJMESSAGE, object->GetSpawnId(), object->GetGOInfo()->name.c_str(), object->GetSpawnId());
return true;
}
diff --git a/src/server/scripts/Commands/cs_instance.cpp b/src/server/scripts/Commands/cs_instance.cpp
index 78c8f970f52..c960d3f3753 100644
--- a/src/server/scripts/Commands/cs_instance.cpp
+++ b/src/server/scripts/Commands/cs_instance.cpp
@@ -217,7 +217,7 @@ public:
{
playerName = param3;
if (normalizePlayerName(playerName))
- player = sObjectAccessor->FindPlayerByName(playerName);
+ player = ObjectAccessor::FindPlayerByName(playerName);
}
if (!player)
@@ -283,7 +283,7 @@ public:
{
playerName = param2;
if (normalizePlayerName(playerName))
- player = sObjectAccessor->FindPlayerByName(playerName);
+ player = ObjectAccessor::FindPlayerByName(playerName);
}
if (!player)
diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp
index dfb1d84c6cc..21a55b1558a 100644
--- a/src/server/scripts/Commands/cs_misc.cpp
+++ b/src/server/scripts/Commands/cs_misc.cpp
@@ -600,8 +600,10 @@ public:
target->SaveToDB();
}
else
- // will resurrected at login without corpse
- sObjectAccessor->ConvertCorpseForPlayer(targetGuid);
+ {
+ SQLTransaction trans(nullptr);
+ Player::OfflineResurrect(targetGuid, trans);
+ }
return true;
}
@@ -820,7 +822,7 @@ public:
// Save all players in the world
static bool HandleSaveAllCommand(ChatHandler* handler, char const* /*args*/)
{
- sObjectAccessor->SaveAllPlayers();
+ ObjectAccessor::SaveAllPlayers();
handler->SendSysMessage(LANG_PLAYERS_SAVED);
return true;
}
diff --git a/src/server/scripts/Commands/cs_server.cpp b/src/server/scripts/Commands/cs_server.cpp
index 6fa84d1bc75..fe5ae940f88 100644
--- a/src/server/scripts/Commands/cs_server.cpp
+++ b/src/server/scripts/Commands/cs_server.cpp
@@ -100,7 +100,7 @@ public:
// Triggering corpses expire check in world
static bool HandleServerCorpsesCommand(ChatHandler* /*handler*/, char const* /*args*/)
{
- sObjectAccessor->RemoveOldCorpses();
+ sWorld->RemoveOldCorpses();
return true;
}
diff --git a/src/server/scripts/Commands/cs_ticket.cpp b/src/server/scripts/Commands/cs_ticket.cpp
index b609dfe18dd..f7634381fc9 100644
--- a/src/server/scripts/Commands/cs_ticket.cpp
+++ b/src/server/scripts/Commands/cs_ticket.cpp
@@ -153,7 +153,7 @@ public:
return true;
}
- sTicketMgr->CloseTicket(ticket->GetId(), player ? player->GetGUID() : ObjectGuid(uint64(-1)));
+ sTicketMgr->ResolveAndCloseTicket(ticket->GetId(), player ? player->GetGUID() : ObjectGuid(uint64(-1)));
sTicketMgr->UpdateLastChange();
std::string msg = ticket->FormatMessageString(*handler, player ? player->GetName().c_str() : "Console", NULL, NULL, NULL, NULL);
@@ -248,7 +248,10 @@ public:
if (Player* player = ticket->GetPlayer())
ticket->SendResponse(player->GetSession());
+ Player* gm = handler->GetSession() ? handler->GetSession()->GetPlayer() : nullptr;
+
SQLTransaction trans = SQLTransaction(NULL);
+ ticket->SetResolvedBy(gm ? gm->GetGUID() : ObjectGuid(uint64(-1)));
ticket->SetCompleted();
ticket->SaveToDB(trans);
diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp
index 51e1bf67f16..a89571e8197 100644
--- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp
+++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp
@@ -367,9 +367,9 @@ public:
}
}
- void sGossipSelect(Player* player, uint32 sender, uint32 action) override
+ void sGossipSelect(Player* player, uint32 menuId, uint32 gossipListId) override
{
- if (sender == GOSSIP_ID && action == GOSSIP_OPTION_ID)
+ if (menuId == GOSSIP_ID && gossipListId == GOSSIP_OPTION_ID)
{
player->CLOSE_GOSSIP_MENU();
Talk(SAY_GAMESBEGIN_1);
diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_vaelastrasz.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_vaelastrasz.cpp
index 636554a0ae4..76ab4736275 100644
--- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_vaelastrasz.cpp
+++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_vaelastrasz.cpp
@@ -221,9 +221,9 @@ public:
DoMeleeAttackIfReady();
}
- void sGossipSelect(Player* player, uint32 sender, uint32 action) override
+ void sGossipSelect(Player* player, uint32 menuId, uint32 gossipListId) override
{
- if (sender == GOSSIP_ID && action == 0)
+ if (menuId == GOSSIP_ID && gossipListId == 0)
{
player->CLOSE_GOSSIP_MENU();
BeginSpeech(player);
diff --git a/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp b/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp
index f3c59654295..87945ccf916 100644
--- a/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp
+++ b/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp
@@ -25,7 +25,6 @@ EndScriptData */
/* ContentData
npc_barnes
-npc_berthold
npc_image_of_medivh
EndContentData */
@@ -416,41 +415,6 @@ public:
};
/*###
-# npc_berthold
-####*/
-
-#define GOSSIP_ITEM_TELEPORT "Teleport me to the Guardian's Library"
-
-class npc_berthold : public CreatureScript
-{
-public:
- npc_berthold() : CreatureScript("npc_berthold") { }
-
- bool OnGossipSelect(Player* player, Creature* /*creature*/, uint32 /*sender*/, uint32 action) override
- {
- player->PlayerTalkClass->ClearMenus();
- if (action == GOSSIP_ACTION_INFO_DEF + 1)
- player->CastSpell(player, SPELL_TELEPORT, true);
-
- player->CLOSE_GOSSIP_MENU();
- return true;
- }
-
- bool OnGossipHello(Player* player, Creature* creature) override
- {
- if (InstanceScript* instance = creature->GetInstanceScript())
- {
- // Check if Shade of Aran event is done
- if (instance->GetData(TYPE_ARAN) == DONE)
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TELEPORT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
- }
-
- player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID());
- return true;
- }
-};
-
-/*###
# npc_image_of_medivh
####*/
@@ -668,6 +632,5 @@ public:
void AddSC_karazhan()
{
new npc_barnes();
- new npc_berthold();
new npc_image_of_medivh();
}
diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp
index b37d505d766..9747d31952b 100644
--- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp
+++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp
@@ -729,13 +729,19 @@ class npc_dark_rider_of_acherus : public CreatureScript
## npc_salanar_the_horseman
######*/
-enum Spells_Salanar
+enum SalanarTheHorseman
{
- SPELL_REALM_OF_SHADOWS = 52693,
+ GOSSIP_SALANAR_MENU = 9739,
+ GOSSIP_SALANAR_OPTION = 0,
+ SALANAR_SAY = 0,
+ QUEST_INTO_REALM_OF_SHADOWS = 12687,
+ NPC_DARK_RIDER_OF_ACHERUS = 28654,
+ NPC_SALANAR_IN_REALM_OF_SHADOWS = 28788,
SPELL_EFFECT_STOLEN_HORSE = 52263,
SPELL_DELIVER_STOLEN_HORSE = 52264,
SPELL_CALL_DARK_RIDER = 52266,
- SPELL_EFFECT_OVERTAKE = 52349
+ SPELL_EFFECT_OVERTAKE = 52349,
+ SPELL_REALM_OF_SHADOWS = 52693
};
class npc_salanar_the_horseman : public CreatureScript
@@ -743,15 +749,19 @@ class npc_salanar_the_horseman : public CreatureScript
public:
npc_salanar_the_horseman() : CreatureScript("npc_salanar_the_horseman") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_salanar_the_horsemanAI(creature);
- }
-
struct npc_salanar_the_horsemanAI : public ScriptedAI
{
npc_salanar_the_horsemanAI(Creature* creature) : ScriptedAI(creature) { }
+ void sGossipSelect(Player* player, uint32 menuId, uint32 gossipListId) override
+ {
+ if (menuId == GOSSIP_SALANAR_MENU && gossipListId == GOSSIP_SALANAR_OPTION)
+ {
+ player->CastSpell(player, SPELL_REALM_OF_SHADOWS, true);
+ player->PlayerTalkClass->SendCloseGossip();
+ }
+ }
+
void SpellHit(Unit* caster, const SpellInfo* spell) override
{
if (spell->Id == SPELL_DELIVER_STOLEN_HORSE)
@@ -766,7 +776,7 @@ public:
caster->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
caster->setFaction(35);
DoCast(caster, SPELL_CALL_DARK_RIDER, true);
- if (Creature* Dark_Rider = me->FindNearestCreature(28654, 15))
+ if (Creature* Dark_Rider = me->FindNearestCreature(NPC_DARK_RIDER_OF_ACHERUS, 15))
ENSURE_AI(npc_dark_rider_of_acherus::npc_dark_rider_of_acherusAI, Dark_Rider->AI())->InitDespawnHorse(caster);
}
}
@@ -784,10 +794,11 @@ public:
{
if (Player* player = charmer->ToPlayer())
{
- // for quest Into the Realm of Shadows(12687)
- if (me->GetEntry() == 28788 && player->GetQuestStatus(12687) == QUEST_STATUS_INCOMPLETE)
+ // for quest Into the Realm of Shadows(QUEST_INTO_REALM_OF_SHADOWS)
+ if (me->GetEntry() == NPC_SALANAR_IN_REALM_OF_SHADOWS && player->GetQuestStatus(QUEST_INTO_REALM_OF_SHADOWS) == QUEST_STATUS_INCOMPLETE)
{
- player->GroupEventHappens(12687, me);
+ player->GroupEventHappens(QUEST_INTO_REALM_OF_SHADOWS, me);
+ Talk(SALANAR_SAY);
charmer->RemoveAurasDueToSpell(SPELL_EFFECT_OVERTAKE);
if (Creature* creature = who->ToCreature())
{
@@ -796,14 +807,17 @@ public:
}
}
- if (player->HasAura(SPELL_REALM_OF_SHADOWS))
- player->RemoveAurasDueToSpell(SPELL_REALM_OF_SHADOWS);
+ player->RemoveAurasDueToSpell(SPELL_REALM_OF_SHADOWS);
}
}
}
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return new npc_salanar_the_horsemanAI(creature);
+ }
};
/*######
diff --git a/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp b/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp
index 3b52e6775b2..1927b0f9829 100644
--- a/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp
+++ b/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp
@@ -268,9 +268,9 @@ class npc_harrison_jones : public CreatureScript
void EnterCombat(Unit* /*who*/) override { }
- void sGossipSelect(Player* player, uint32 sender, uint32 action) override
+ void sGossipSelect(Player* player, uint32 menuId, uint32 gossipListId) override
{
- if (me->GetCreatureTemplate()->GossipMenuId == sender && !action)
+ if (me->GetCreatureTemplate()->GossipMenuId == menuId && !gossipListId)
{
player->CLOSE_GOSSIP_MENU();
me->SetFacingToObject(player);
diff --git a/src/server/scripts/Kalimdor/BlackfathomDeeps/blackfathom_deeps.cpp b/src/server/scripts/Kalimdor/BlackfathomDeeps/blackfathom_deeps.cpp
index 8d9406adee1..ab7509c7a2b 100644
--- a/src/server/scripts/Kalimdor/BlackfathomDeeps/blackfathom_deeps.cpp
+++ b/src/server/scripts/Kalimdor/BlackfathomDeeps/blackfathom_deeps.cpp
@@ -226,7 +226,7 @@ public:
}
}
- void sGossipSelect(Player* player, uint32 /*sender*/, uint32 /*action*/) override
+ void sGossipSelect(Player* player, uint32 /*menuId*/, uint32 /*gossipListId*/) override
{
DoCast(player, SPELL_TELEPORT_DARNASSUS);
}
diff --git a/src/server/scripts/Kalimdor/zone_azshara.cpp b/src/server/scripts/Kalimdor/zone_azshara.cpp
index 6727aa69552..d6aa943123b 100644
--- a/src/server/scripts/Kalimdor/zone_azshara.cpp
+++ b/src/server/scripts/Kalimdor/zone_azshara.cpp
@@ -345,7 +345,7 @@ public:
}
}
- void sGossipSelect(Player* player, uint32 /*sender*/, uint32 /*action*/) override
+ void sGossipSelect(Player* player, uint32 /*menuId*/, uint32 /*gossipListId*/) override
{
player->CLOSE_GOSSIP_MENU();
me->CastSpell(player, SPELL_GIVE_SOUTHFURY_MOONSTONE, true);
diff --git a/src/server/scripts/Kalimdor/zone_azuremyst_isle.cpp b/src/server/scripts/Kalimdor/zone_azuremyst_isle.cpp
index 388834d1eff..52e32d3d37c 100644
--- a/src/server/scripts/Kalimdor/zone_azuremyst_isle.cpp
+++ b/src/server/scripts/Kalimdor/zone_azuremyst_isle.cpp
@@ -230,7 +230,7 @@ public:
Talk(ATTACK_YELL, who);
}
- void sGossipSelect(Player* player, uint32 /*sender*/, uint32 /*action*/) override
+ void sGossipSelect(Player* player, uint32 /*menuId*/, uint32 /*gossipListId*/) override
{
player->CLOSE_GOSSIP_MENU();
me->setFaction(FACTION_HOSTILE);
diff --git a/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp b/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp
index 427d4bae217..c4ab8f76487 100644
--- a/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp
+++ b/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp
@@ -541,7 +541,7 @@ public:
case PHASE_PLANT_FIRST_DETONATE: // first explosives detonate finish
for (GuidList::iterator itr = _explosivesGuids.begin(); itr != _explosivesGuids.end(); ++itr)
{
- if (GameObject* explosive = sObjectAccessor->GetGameObject(*me, *itr))
+ if (GameObject* explosive = ObjectAccessor::GetGameObject(*me, *itr))
me->RemoveGameObject(explosive, true);
}
_explosivesGuids.clear();
@@ -638,7 +638,7 @@ public:
case PHASE_PLANT_SECOND_DETONATE: // second explosives detonate finish
for (GuidList::iterator itr = _explosivesGuids.begin(); itr != _explosivesGuids.end(); ++itr)
{
- if (GameObject* explosive = sObjectAccessor->GetGameObject(*me, *itr))
+ if (GameObject* explosive = ObjectAccessor::GetGameObject(*me, *itr))
me->RemoveGameObject(explosive, true);
}
_explosivesGuids.clear();
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp
index 943be27943d..365e0a1588d 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp
@@ -203,6 +203,9 @@ enum Misc
{
DATA_MADE_A_MESS = 45374613, // 4537, 4613 are achievement IDs
FACTION_SCOURGE = 974,
+
+ GOSSIP_MENU_MURADIN_BRONZEBEARD = 10934,
+ GOSSIP_MENU_HIGH_OVERLORD_SAURFANG = 10952
};
enum MovePoints
@@ -634,6 +637,15 @@ class npc_high_overlord_saurfang_icc : public CreatureScript
_events.Reset();
}
+ void sGossipSelect(Player* player, uint32 menuId, uint32 /*gossipListId*/) override
+ {
+ if (menuId == GOSSIP_MENU_HIGH_OVERLORD_SAURFANG)
+ {
+ player->PlayerTalkClass->SendCloseGossip();
+ DoAction(ACTION_START_EVENT);
+ }
+ }
+
void DoAction(int32 action) override
{
switch (action)
@@ -798,28 +810,6 @@ class npc_high_overlord_saurfang_icc : public CreatureScript
std::list<Creature*> _guardList;
};
- bool OnGossipHello(Player* player, Creature* creature) override
- {
- InstanceScript* instance = creature->GetInstanceScript();
- if (instance && instance->GetBossState(DATA_DEATHBRINGER_SAURFANG) != DONE)
- {
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "We are ready to go, High Overlord. The Lich King must fall!", 631, -ACTION_START_EVENT);
- player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
- }
-
- return true;
- }
-
- bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
- {
- player->PlayerTalkClass->ClearMenus();
- player->CLOSE_GOSSIP_MENU();
- if (action == -ACTION_START_EVENT)
- creature->AI()->DoAction(ACTION_START_EVENT);
-
- return true;
- }
-
CreatureAI* GetAI(Creature* creature) const override
{
return GetIcecrownCitadelAI<npc_high_overlord_saurfangAI>(creature);
@@ -843,6 +833,15 @@ class npc_muradin_bronzebeard_icc : public CreatureScript
_events.Reset();
}
+ void sGossipSelect(Player* player, uint32 menuId, uint32 /*gossipListId*/) override
+ {
+ if (menuId == GOSSIP_MENU_MURADIN_BRONZEBEARD)
+ {
+ player->PlayerTalkClass->SendCloseGossip();
+ DoAction(ACTION_START_EVENT);
+ }
+ }
+
void DoAction(int32 action) override
{
switch (action)
@@ -946,28 +945,6 @@ class npc_muradin_bronzebeard_icc : public CreatureScript
std::list<Creature*> _guardList;
};
- bool OnGossipHello(Player* player, Creature* creature) override
- {
- InstanceScript* instance = creature->GetInstanceScript();
- if (instance && instance->GetBossState(DATA_DEATHBRINGER_SAURFANG) != DONE)
- {
- player->ADD_GOSSIP_ITEM(0, "Let it begin...", 631, -ACTION_START_EVENT + 1);
- player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
- }
-
- return true;
- }
-
- bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
- {
- player->PlayerTalkClass->ClearMenus();
- player->CLOSE_GOSSIP_MENU();
- if (action == -ACTION_START_EVENT + 1)
- creature->AI()->DoAction(ACTION_START_EVENT);
-
- return true;
- }
-
CreatureAI* GetAI(Creature* creature) const override
{
return GetIcecrownCitadelAI<npc_muradin_bronzebeard_iccAI>(creature);
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp
index 78730b535aa..babd444288f 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp
@@ -961,7 +961,7 @@ class npc_high_overlord_saurfang_igb : public CreatureScript
}
}
- void sGossipSelect(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/) override
+ void sGossipSelect(Player* /*player*/, uint32 /*menuId*/, uint32 /*gossipListId*/) override
{
me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
me->GetTransport()->EnableMovement(true);
@@ -1229,7 +1229,7 @@ class npc_muradin_bronzebeard_igb : public CreatureScript
}
}
- void sGossipSelect(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/) override
+ void sGossipSelect(Player* /*player*/, uint32 /*menuId*/, uint32 /*gossipListId*/) override
{
me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
me->GetTransport()->EnableMovement(true);
@@ -1394,7 +1394,7 @@ class npc_zafod_boombox : public CreatureScript
me->SetReactState(REACT_PASSIVE);
}
- void sGossipSelect(Player* player, uint32 /*sender*/, uint32 /*action*/) override
+ void sGossipSelect(Player* player, uint32 /*menuId*/, uint32 /*gossipListId*/) override
{
player->AddItem(ITEM_GOBLIN_ROCKET_PACK, 1);
player->PlayerTalkClass->SendCloseGossip();
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp
index 6c512546a24..4fadc0bf8fa 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp
@@ -1199,9 +1199,9 @@ class npc_tirion_fordring_tft : public CreatureScript
SetEquipmentSlots(true); // remove glow on ashbringer
}
- void sGossipSelect(Player* /*player*/, uint32 sender, uint32 action) override
+ void sGossipSelect(Player* /*player*/, uint32 menuId, uint32 gossipListId) override
{
- if (me->GetCreatureTemplate()->GossipMenuId == sender && !action)
+ if (me->GetCreatureTemplate()->GossipMenuId == menuId && !gossipListId)
{
_events.SetPhase(PHASE_INTRO);
me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp
index 59c28cd3a5a..6f07a88536d 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp
@@ -1508,9 +1508,9 @@ class npc_observation_ring_keeper : public CreatureScript
DoCast(SPELL_KEEPER_ACTIVE);
}
- void sGossipSelect(Player* player, uint32 sender, uint32 /*action*/) override
+ void sGossipSelect(Player* player, uint32 menuId, uint32 /*gossipListId*/) override
{
- if (sender != 10333)
+ if (menuId != 10333)
return;
me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
diff --git a/src/server/scripts/Northrend/zone_grizzly_hills.cpp b/src/server/scripts/Northrend/zone_grizzly_hills.cpp
index 83fd3859716..54b06260e78 100644
--- a/src/server/scripts/Northrend/zone_grizzly_hills.cpp
+++ b/src/server/scripts/Northrend/zone_grizzly_hills.cpp
@@ -762,7 +762,7 @@ public:
}
}
- void sGossipSelect(Player* player, uint32 /*sender*/, uint32 /*action*/) override
+ void sGossipSelect(Player* player, uint32 /*menuId*/, uint32 /*gossipListId*/) override
{
DoCast(player, SPELL_SUMMON_ASHWOOD_BRAND);
}
diff --git a/src/server/scripts/Northrend/zone_storm_peaks.cpp b/src/server/scripts/Northrend/zone_storm_peaks.cpp
index 25bf4826000..e86e907b550 100644
--- a/src/server/scripts/Northrend/zone_storm_peaks.cpp
+++ b/src/server/scripts/Northrend/zone_storm_peaks.cpp
@@ -85,13 +85,13 @@ public:
DoMeleeAttackIfReady();
}
- void sGossipSelect(Player* player, uint32 sender, uint32 action) override
+ void sGossipSelect(Player* player, uint32 menuId, uint32 gossipListId) override
{
- if (sender == GOSSIP_ID && action == GOSSIP_OPTION_ID)
+ if (menuId == GOSSIP_ID && gossipListId == GOSSIP_OPTION_ID)
{
player->CLOSE_GOSSIP_MENU();
me->setFaction(113);
- npc_escortAI::Start(true, true, player->GetGUID());
+ Start(true, true, player->GetGUID());
}
}
};
@@ -476,7 +476,7 @@ public:
objectCounter = 0;
}
- void sGossipSelect(Player* player, uint32 /*sender*/, uint32 /*action*/) override
+ void sGossipSelect(Player* player, uint32 /*menuId*/, uint32 /*gossipListId*/) override
{
player->CLOSE_GOSSIP_MENU();
playerGUID = player->GetGUID();
diff --git a/src/server/scripts/Northrend/zone_zuldrak.cpp b/src/server/scripts/Northrend/zone_zuldrak.cpp
index 91c796a6e69..e36930f5745 100644
--- a/src/server/scripts/Northrend/zone_zuldrak.cpp
+++ b/src/server/scripts/Northrend/zone_zuldrak.cpp
@@ -267,7 +267,7 @@ public:
return;
}
- void sGossipSelect(Player* player, uint32 /*sender*/, uint32 /*action*/) override
+ void sGossipSelect(Player* player, uint32 /*menuId*/, uint32 /*gossipListId*/) override
{
_events.ScheduleEvent(EVENT_RECRUIT_1, 100);
player->CLOSE_GOSSIP_MENU();
@@ -552,7 +552,7 @@ public:
}
}
- void sGossipSelect(Player* player, uint32 /*sender*/, uint32 /*action*/) override
+ void sGossipSelect(Player* player, uint32 /*menuId*/, uint32 /*gossipListId*/) override
{
player->CLOSE_GOSSIP_MENU();
DoCast(player, SPELL_ALCHEMIST_APPRENTICE_INVISBUFF);
diff --git a/src/server/scripts/Outland/BlackTemple/black_temple.cpp b/src/server/scripts/Outland/BlackTemple/black_temple.cpp
index 764cd9594ea..f044fcef5c7 100644
--- a/src/server/scripts/Outland/BlackTemple/black_temple.cpp
+++ b/src/server/scripts/Outland/BlackTemple/black_temple.cpp
@@ -15,22 +15,12 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/*
-Name: Black_Temple
-Complete: 100%
-Comment: Spirit of Olum: Player Teleporter to Seer Kanai Teleport after defeating Naj'entus and Supremus.
-*/
-
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
-#include "ScriptedGossip.h"
#include "black_temple.h"
-#include "Player.h"
enum Spells
{
- // Spirit of Olum
- SPELL_TELEPORT = 41566,
// Wrathbone Flayer
SPELL_CLEAVE = 15496,
SPELL_IGNORED = 39544,
@@ -53,36 +43,6 @@ enum Events
};
// ########################################################
-// Spirit of Olum
-// ########################################################
-
-class npc_spirit_of_olum : public CreatureScript
-{
-public:
- npc_spirit_of_olum() : CreatureScript("npc_spirit_of_olum") { }
-
- struct npc_spirit_of_olumAI : public ScriptedAI
- {
- npc_spirit_of_olumAI(Creature* creature) : ScriptedAI(creature) { }
-
- void sGossipSelect(Player* player, uint32 /*sender*/, uint32 action) override
- {
- if (action == 1)
- {
- player->CLOSE_GOSSIP_MENU();
- player->InterruptNonMeleeSpells(false);
- player->CastSpell(player, SPELL_TELEPORT, false);
- }
- }
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_spirit_of_olumAI(creature);
- }
-};
-
-// ########################################################
// Wrathbone Flayer
// ########################################################
@@ -123,7 +83,6 @@ public:
void UpdateAI(uint32 diff) override
{
-
if (!_enteredCombat)
{
_events.Update(diff);
@@ -215,12 +174,11 @@ public:
CreatureAI* GetAI(Creature* creature) const override
{
- return GetInstanceAI<npc_wrathbone_flayerAI>(creature);
+ return GetBlackTempleAI<npc_wrathbone_flayerAI>(creature);
}
};
void AddSC_black_temple()
{
- new npc_spirit_of_olum();
new npc_wrathbone_flayer();
}
diff --git a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp
index 7cc460d4548..f8c031f69e7 100644
--- a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp
+++ b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp
@@ -1779,7 +1779,7 @@ public:
DoMeleeAttackIfReady();
}
- void sGossipSelect(Player* player, uint32 /*sender*/, uint32 /*action*/) override
+ void sGossipSelect(Player* player, uint32 /*menuId*/, uint32 /*gossipListId*/) override
{
player->CLOSE_GOSSIP_MENU();
EnterPhase(PHASE_CHANNEL);
diff --git a/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp b/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp
index e4369f0348d..25ff1bf9536 100644
--- a/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp
+++ b/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp
@@ -519,9 +519,9 @@ public:
DoMeleeAttackIfReady();
}
- void sGossipSelect(Player* player, uint32 /*sender*/, uint32 action) override
+ void sGossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override
{
- if (action == 0)
+ if (gossipListId == 0)
{
player->CLOSE_GOSSIP_MENU();
StartChannel = true;
diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp
index cf33ba300f7..ab132621437 100644
--- a/src/server/worldserver/Main.cpp
+++ b/src/server/worldserver/Main.cpp
@@ -256,7 +256,6 @@ extern int main(int argc, char** argv)
sInstanceSaveMgr->Unload();
sOutdoorPvPMgr->Die();
sMapMgr->UnloadAll(); // unload all grids (including locked in memory)
- sObjectAccessor->UnloadAll(); // unload 'i_player2corpse' storage and remove from world
sScriptMgr->Unload();
// set server offline
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index b4a7e7a4864..1689f05966a 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -2605,6 +2605,14 @@ PlayerStart.MapsExplored = 0
HonorPointsAfterDuel = 0
#
+# ResetCoolDownAfterDuel
+# Description: Reset all cooldowns after duel, but only if player has no cooldowns before the duel.
+# Default: 0 - (Disabled)
+# 1 - (Enabled)
+
+ResetCoolDownAfterDuel = 0
+
+#
# AlwaysMaxWeaponSkill
# Description: Players will automatically gain max weapon/defense skill when logging in,
# or leveling.