aboutsummaryrefslogtreecommitdiff
path: root/src/game
diff options
context:
space:
mode:
Diffstat (limited to 'src/game')
-rw-r--r--src/game/AccountMgr.cpp50
-rw-r--r--src/game/AchievementMgr.cpp109
-rw-r--r--src/game/AchievementMgr.h19
-rw-r--r--src/game/AggressorAI.cpp55
-rw-r--r--src/game/AggressorAI.h14
-rw-r--r--src/game/ArenaTeam.cpp283
-rw-r--r--src/game/ArenaTeam.h62
-rw-r--r--src/game/AuctionHouseBot.cpp1634
-rw-r--r--src/game/AuctionHouseBot.h1048
-rw-r--r--src/game/AuctionHouseHandler.cpp2
-rw-r--r--src/game/BattleGround.cpp37
-rw-r--r--src/game/BattleGround.h23
-rw-r--r--src/game/BattleGroundAB.cpp45
-rw-r--r--src/game/BattleGroundAB.h8
-rw-r--r--src/game/BattleGroundAV.cpp216
-rw-r--r--src/game/BattleGroundBE.cpp3
-rw-r--r--src/game/BattleGroundEY.cpp14
-rw-r--r--src/game/BattleGroundEY.h3
-rw-r--r--src/game/BattleGroundHandler.cpp3
-rw-r--r--src/game/BattleGroundMgr.cpp4
-rw-r--r--src/game/BattleGroundSA.cpp3
-rw-r--r--src/game/BattleGroundWS.cpp3
-rw-r--r--src/game/BattleGroundWS.h2
-rw-r--r--src/game/CMakeLists.txt3
-rw-r--r--src/game/Channel.cpp131
-rw-r--r--src/game/Channel.h4
-rw-r--r--src/game/ChannelHandler.cpp6
-rw-r--r--src/game/ChannelMgr.cpp97
-rw-r--r--src/game/ChannelMgr.h76
-rw-r--r--src/game/CharacterHandler.cpp95
-rw-r--r--src/game/Chat.cpp19
-rw-r--r--src/game/Chat.h20
-rw-r--r--src/game/ChatHandler.cpp15
-rw-r--r--src/game/Corpse.cpp21
-rw-r--r--src/game/Corpse.h11
-rw-r--r--src/game/Creature.cpp55
-rw-r--r--src/game/Creature.h19
-rw-r--r--src/game/CreatureAI.cpp22
-rw-r--r--src/game/CreatureAI.h1
-rw-r--r--src/game/CreatureAIImpl.h5
-rw-r--r--src/game/CreatureAISelector.cpp6
-rw-r--r--src/game/CreatureEventAI.cpp49
-rw-r--r--src/game/CreatureEventAI.h19
-rw-r--r--src/game/CreatureEventAIMgr.cpp23
-rw-r--r--src/game/DBCStores.cpp3
-rw-r--r--src/game/DBCStores.h1
-rw-r--r--src/game/DBCStructure.h26
-rw-r--r--src/game/Debugcmds.cpp307
-rw-r--r--src/game/DestinationHolderImp.h2
-rw-r--r--src/game/DynamicObject.cpp5
-rw-r--r--src/game/FleeingMovementGenerator.cpp1
-rw-r--r--src/game/Formulas.h2
-rw-r--r--src/game/GameEventMgr.cpp15
-rw-r--r--src/game/GameObject.cpp236
-rw-r--r--src/game/GameObject.h172
-rw-r--r--src/game/GridDefines.h5
-rw-r--r--src/game/GridNotifiers.h61
-rw-r--r--src/game/GridNotifiersImpl.h24
-rw-r--r--src/game/Group.cpp4
-rw-r--r--src/game/Guild.cpp268
-rw-r--r--src/game/Guild.h4
-rw-r--r--src/game/GuildHandler.cpp4
-rw-r--r--src/game/Item.cpp12
-rw-r--r--src/game/ItemHandler.cpp28
-rw-r--r--src/game/LFGHandler.cpp10
-rw-r--r--src/game/Language.h16
-rw-r--r--src/game/Level0.cpp17
-rw-r--r--src/game/Level1.cpp87
-rw-r--r--src/game/Level2.cpp163
-rw-r--r--src/game/Level3.cpp641
-rw-r--r--src/game/LootHandler.cpp4
-rw-r--r--src/game/LootMgr.cpp10
-rw-r--r--src/game/Mail.cpp75
-rw-r--r--src/game/Makefile.am6
-rw-r--r--src/game/Map.cpp1028
-rw-r--r--src/game/Map.h66
-rw-r--r--src/game/MapInstanced.cpp69
-rw-r--r--src/game/MapInstanced.h5
-rw-r--r--src/game/MapManager.cpp32
-rw-r--r--src/game/MapManager.h5
-rw-r--r--src/game/MiscHandler.cpp86
-rw-r--r--src/game/MovementHandler.cpp52
-rw-r--r--src/game/NPCHandler.cpp4
-rw-r--r--src/game/Object.cpp112
-rw-r--r--src/game/Object.h49
-rw-r--r--src/game/ObjectAccessor.cpp18
-rw-r--r--src/game/ObjectAccessor.h31
-rw-r--r--src/game/ObjectGridLoader.cpp2
-rw-r--r--src/game/ObjectMgr.cpp180
-rw-r--r--src/game/ObjectMgr.h14
-rw-r--r--src/game/Opcodes.cpp4
-rw-r--r--src/game/Opcodes.h6
-rw-r--r--src/game/OutdoorPvP.cpp3
-rw-r--r--src/game/OutdoorPvPNA.cpp2
-rw-r--r--src/game/OutdoorPvPSI.cpp8
-rw-r--r--src/game/Pet.cpp187
-rw-r--r--src/game/Pet.h10
-rw-r--r--src/game/PetAI.cpp56
-rw-r--r--src/game/PetAI.h3
-rw-r--r--src/game/PetHandler.cpp75
-rw-r--r--src/game/Player.cpp2048
-rw-r--r--src/game/Player.h172
-rw-r--r--src/game/PlayerDump.cpp67
-rw-r--r--src/game/PointMovementGenerator.cpp4
-rw-r--r--src/game/PoolHandler.cpp3
-rw-r--r--src/game/QueryHandler.cpp40
-rw-r--r--src/game/QuestDef.h4
-rw-r--r--src/game/QuestHandler.cpp78
-rw-r--r--src/game/ReputationMgr.cpp4
-rw-r--r--src/game/ReputationMgr.h7
-rw-r--r--src/game/ScriptCalls.cpp1
-rw-r--r--src/game/ScriptCalls.h2
-rw-r--r--src/game/SharedDefines.h433
-rw-r--r--src/game/SkillDiscovery.cpp22
-rw-r--r--src/game/SocialMgr.cpp20
-rw-r--r--src/game/Spell.cpp705
-rw-r--r--src/game/Spell.h14
-rw-r--r--src/game/SpellAuraDefines.h10
-rw-r--r--src/game/SpellAuras.cpp1812
-rw-r--r--src/game/SpellAuras.h11
-rw-r--r--src/game/SpellEffects.cpp1062
-rw-r--r--src/game/SpellHandler.cpp76
-rw-r--r--src/game/SpellMgr.cpp645
-rw-r--r--src/game/SpellMgr.h208
-rw-r--r--src/game/StatSystem.cpp7
-rw-r--r--src/game/TargetedMovementGenerator.cpp4
-rw-r--r--src/game/TaxiHandler.cpp6
-rw-r--r--src/game/TemporarySummon.cpp23
-rw-r--r--src/game/TemporarySummon.h3
-rw-r--r--src/game/ThreatManager.cpp27
-rw-r--r--src/game/ThreatManager.h5
-rw-r--r--src/game/Totem.cpp11
-rw-r--r--src/game/Totem.h2
-rw-r--r--src/game/Transports.cpp20
-rw-r--r--src/game/Transports.h15
-rw-r--r--src/game/Unit.cpp1487
-rw-r--r--src/game/Unit.h106
-rw-r--r--src/game/UnitAI.cpp6
-rw-r--r--src/game/UnitAI.h3
-rw-r--r--src/game/UpdateData.cpp2
-rw-r--r--src/game/Vehicle.cpp51
-rw-r--r--src/game/WaypointMovementGenerator.cpp2
-rw-r--r--src/game/World.cpp988
-rw-r--r--src/game/World.h42
-rw-r--r--src/game/WorldSession.cpp25
-rw-r--r--src/game/WorldSession.h1
-rw-r--r--src/game/WorldSocket.cpp19
-rw-r--r--src/game/pchdef.h4
148 files changed, 11124 insertions, 7836 deletions
diff --git a/src/game/AccountMgr.cpp b/src/game/AccountMgr.cpp
index 66660766dae..74bc4cd2dcc 100644
--- a/src/game/AccountMgr.cpp
+++ b/src/game/AccountMgr.cpp
@@ -26,7 +26,7 @@
#include "Player.h"
#include "Util.h"
-extern DatabaseType LoginDatabase;
+extern DatabaseType loginDatabase;
INSTANTIATE_SINGLETON_1(AccountMgr);
@@ -44,26 +44,26 @@ AccountOpResult AccountMgr::CreateAccount(std::string username, std::string pass
normalizeString(username);
normalizeString(password);
- LoginDatabase.escape_string(username);
- LoginDatabase.escape_string(password);
+ loginDatabase.escape_string(username);
+ loginDatabase.escape_string(password);
- QueryResult *result = LoginDatabase.PQuery("SELECT 1 FROM account WHERE username = '%s'", username.c_str());
+ QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE username = '%s'", username.c_str());
if(result)
{
delete result;
return AOR_NAME_ALREDY_EXIST; // username does already exist
}
- if(!LoginDatabase.PExecute("INSERT INTO account(username,sha_pass_hash,joindate) VALUES('%s',SHA1(CONCAT('%s',':','%s')),NOW())", username.c_str(), username.c_str(), password.c_str()))
+ if(!loginDatabase.PExecute("INSERT INTO account(username,sha_pass_hash,joindate) VALUES('%s',SHA1(CONCAT('%s',':','%s')),NOW())", username.c_str(), username.c_str(), password.c_str()))
return AOR_DB_INTERNAL_ERROR; // unexpected error
- LoginDatabase.Execute("INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM realmlist,account LEFT JOIN realmcharacters ON acctid=account.id WHERE acctid IS NULL");
+ loginDatabase.Execute("INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM realmlist,account LEFT JOIN realmcharacters ON acctid=account.id WHERE acctid IS NULL");
return AOR_OK; // everything's fine
}
AccountOpResult AccountMgr::DeleteAccount(uint32 accid)
{
- QueryResult *result = LoginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid);
+ QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid);
if(!result)
return AOR_NAME_NOT_EXIST; // account doesn't exist
delete result;
@@ -78,7 +78,7 @@ AccountOpResult AccountMgr::DeleteAccount(uint32 accid)
uint64 guid = MAKE_NEW_GUID(guidlo, 0, HIGHGUID_PLAYER);
// kick if player currently
- if(Player* p = ObjectAccessor::FindPlayer(guid))
+ if(Player* p = ObjectAccessor::GetObjectInWorld(guid, (Player*)NULL))
{
WorldSession* s = p->GetSession();
s->KickPlayer(); // mark session to remove at next session list update
@@ -94,13 +94,13 @@ AccountOpResult AccountMgr::DeleteAccount(uint32 accid)
// table realm specific but common for all characters of account for realm
CharacterDatabase.PExecute("DELETE FROM character_tutorial WHERE account = '%u'",accid);
- LoginDatabase.BeginTransaction();
+ loginDatabase.BeginTransaction();
bool res =
- LoginDatabase.PExecute("DELETE FROM account WHERE id='%d'", accid) &&
- LoginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid='%d'", accid);
+ loginDatabase.PExecute("DELETE FROM account WHERE id='%d'", accid) &&
+ loginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid='%d'", accid);
- LoginDatabase.CommitTransaction();
+ loginDatabase.CommitTransaction();
if(!res)
return AOR_DB_INTERNAL_ERROR; // unexpected error;
@@ -110,7 +110,7 @@ AccountOpResult AccountMgr::DeleteAccount(uint32 accid)
AccountOpResult AccountMgr::ChangeUsername(uint32 accid, std::string new_uname, std::string new_passwd)
{
- QueryResult *result = LoginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid);
+ QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid);
if(!result)
return AOR_NAME_NOT_EXIST; // account doesn't exist
delete result;
@@ -124,9 +124,9 @@ AccountOpResult AccountMgr::ChangeUsername(uint32 accid, std::string new_uname,
normalizeString(new_uname);
normalizeString(new_passwd);
- LoginDatabase.escape_string(new_uname);
- LoginDatabase.escape_string(new_passwd);
- if(!LoginDatabase.PExecute("UPDATE account SET username='%s',sha_pass_hash=SHA1(CONCAT('%s',':','%s')) WHERE id='%d'", new_uname.c_str(), new_uname.c_str(), new_passwd.c_str(), accid))
+ loginDatabase.escape_string(new_uname);
+ loginDatabase.escape_string(new_passwd);
+ if(!loginDatabase.PExecute("UPDATE account SET username='%s',sha_pass_hash=SHA1(CONCAT('%s',':','%s')) WHERE id='%d'", new_uname.c_str(), new_uname.c_str(), new_passwd.c_str(), accid))
return AOR_DB_INTERNAL_ERROR; // unexpected error
return AOR_OK;
@@ -134,7 +134,7 @@ AccountOpResult AccountMgr::ChangeUsername(uint32 accid, std::string new_uname,
AccountOpResult AccountMgr::ChangePassword(uint32 accid, std::string new_passwd)
{
- QueryResult *result = LoginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid);
+ QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid);
if(!result)
return AOR_NAME_NOT_EXIST; // account doesn't exist
delete result;
@@ -144,8 +144,8 @@ AccountOpResult AccountMgr::ChangePassword(uint32 accid, std::string new_passwd)
normalizeString(new_passwd);
- LoginDatabase.escape_string(new_passwd);
- if(!LoginDatabase.PExecute("UPDATE account SET sha_pass_hash=SHA1(CONCAT(username,':','%s')) WHERE id='%d'", new_passwd.c_str(), accid))
+ loginDatabase.escape_string(new_passwd);
+ if(!loginDatabase.PExecute("UPDATE account SET sha_pass_hash=SHA1(CONCAT(username,':','%s')) WHERE id='%d'", new_passwd.c_str(), accid))
return AOR_DB_INTERNAL_ERROR; // unexpected error
return AOR_OK;
@@ -153,8 +153,8 @@ AccountOpResult AccountMgr::ChangePassword(uint32 accid, std::string new_passwd)
uint32 AccountMgr::GetId(std::string username)
{
- LoginDatabase.escape_string(username);
- QueryResult *result = LoginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'", username.c_str());
+ loginDatabase.escape_string(username);
+ QueryResult *result = loginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'", username.c_str());
if(!result)
return 0;
else
@@ -167,7 +167,7 @@ uint32 AccountMgr::GetId(std::string username)
uint32 AccountMgr::GetSecurity(uint32 acc_id)
{
- QueryResult *result = LoginDatabase.PQuery("SELECT gmlevel FROM account WHERE id = '%u'", acc_id);
+ QueryResult *result = loginDatabase.PQuery("SELECT gmlevel FROM account WHERE id = '%u'", acc_id);
if(result)
{
uint32 sec = (*result)[0].GetUInt32();
@@ -180,7 +180,7 @@ uint32 AccountMgr::GetSecurity(uint32 acc_id)
bool AccountMgr::GetName(uint32 acc_id, std::string &name)
{
- QueryResult *result = LoginDatabase.PQuery("SELECT username FROM account WHERE id = '%u'", acc_id);
+ QueryResult *result = loginDatabase.PQuery("SELECT username FROM account WHERE id = '%u'", acc_id);
if(result)
{
name = (*result)[0].GetCppString();
@@ -194,9 +194,9 @@ bool AccountMgr::GetName(uint32 acc_id, std::string &name)
bool AccountMgr::CheckPassword(uint32 accid, std::string passwd)
{
normalizeString(passwd);
- LoginDatabase.escape_string(passwd);
+ loginDatabase.escape_string(passwd);
- QueryResult *result = LoginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d' AND sha_pass_hash=SHA1(CONCAT(username,':','%s'))", accid, passwd.c_str());
+ QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d' AND sha_pass_hash=SHA1(CONCAT(username,':','%s'))", accid, passwd.c_str());
if (result)
{
delete result;
diff --git a/src/game/AchievementMgr.cpp b/src/game/AchievementMgr.cpp
index e86fb543ed5..09ae58eea8d 100644
--- a/src/game/AchievementMgr.cpp
+++ b/src/game/AchievementMgr.cpp
@@ -35,6 +35,9 @@
#include "ProgressBar.h"
#include "SpellMgr.h"
+#include "MapManager.h"
+#include "BattleGround.h"
+#include "BattleGroundAB.h"
INSTANTIATE_SINGLETON_1(AchievementGlobalMgr);
@@ -81,11 +84,13 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
switch(criteria->requiredType)
{
case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE:
- case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST: // only hardcoded list
+ case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG:
case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING:
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST: // only hardcoded list
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL:
case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA:
case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE:
+ case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL:
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE:
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2:
break;
@@ -139,7 +144,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD:
if (player_dead.own_team_flag > 1)
{
- sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) have wrong boolean value1 (%u).",
+ sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD (%u) have wrong boolean value1 (%u).",
criteria->ID, criteria->requiredType,dataType,player_dead.own_team_flag);
return false;
}
@@ -228,10 +233,12 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
if (!sHolidaysStore.LookupEntry(holiday.id))
{
sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY (%u) have unknown holiday in value1 (%u), ignore.",
- criteria->ID, criteria->requiredType,dataType,drunk.state);
+ criteria->ID, criteria->requiredType,dataType,holiday.id);
return false;
}
return true;
+ case ACHIEVEMENT_CRITERIA_DATA_TYPE_BG_LOSS_TEAM_SCORE:
+ return true; // not check correctness node indexes
default:
sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) have data for not supported data type (%u), ignore.", criteria->ID, criteria->requiredType,dataType);
return false;
@@ -300,6 +307,13 @@ bool AchievementCriteriaData::Meets(Player const* source, Unit const* target, ui
return Player::GetDrunkenstateByValue(source->GetDrunkValue()) >= drunk.state;
case ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY:
return IsHolidayActive(HolidayIds(holiday.id));
+ case ACHIEVEMENT_CRITERIA_DATA_TYPE_BG_LOSS_TEAM_SCORE:
+ {
+ BattleGround* bg = source->GetBattleGround();
+ if(!bg)
+ return false;
+ return bg->IsTeamScoreInRange(source->GetTeam()==ALLIANCE ? HORDE : ALLIANCE,bg_loss_team_score.min_score,bg_loss_team_score.max_score);
+ }
}
return false;
}
@@ -535,7 +549,7 @@ void AchievementMgr::LoadFromDB(QueryResult *achievementResult, QueryResult *cri
if (!criteria)
{
// we will remove not existed criteria for all characters
- sLog.outError("Not existed achievement creataria %u data removed from table `character_achievement_progress`.",id);
+ sLog.outError("Not existed achievement criteria %u data removed from table `character_achievement_progress`.",id);
CharacterDatabase.PExecute("DELETE FROM character_achievement_progress WHERE criteria = %u",id);
continue;
}
@@ -678,7 +692,6 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
// std. case: increment at 1
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST:
case ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS:
- case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL:
case ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL:
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED:
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED:
@@ -719,6 +732,54 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
// specialized cases
+ case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG:
+ {
+ // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
+ if (!miscvalue1)
+ continue;
+ if (achievementCriteria->win_bg.bgMapID != GetPlayer()->GetMapId())
+ continue;
+
+ if (achievementCriteria->win_bg.additionalRequirement1_type)
+ {
+ // those requirements couldn't be found in the dbc
+ AchievementCriteriaDataSet const* data = achievementmgr.GetCriteriaDataSet(achievementCriteria);
+ if (!data || !data->Meets(GetPlayer(),unit))
+ continue;
+ }
+ // some hardcoded requirements
+ else
+ {
+ BattleGround* bg = GetPlayer()->GetBattleGround();
+ if (!bg)
+ continue;
+
+ switch(achievementCriteria->referredAchievement)
+ {
+ case 161: // AB, Overcome a 500 resource disadvantage
+ {
+ if (bg->GetTypeID() != BATTLEGROUND_AB)
+ continue;
+ if(!((BattleGroundAB*)bg)->IsTeamScores500disadvantage(GetPlayer()->GetTeam()))
+ continue;
+ break;
+ }
+ case 156: // AB, win while controlling all 5 flags (all nodes)
+ case 784: // EY, win while holding 4 bases (all nodes)
+ {
+ if(!bg->IsAllNodesConrolledByTeam(GetPlayer()->GetTeam()))
+ continue;
+ break;
+ }
+ case 1762: // SA, win without losing any siege vehicles
+ case 2192: // SA, win without losing any siege vehicles
+ continue; // not implemented
+ }
+ }
+
+ SetCriteriaProgress(achievementCriteria, miscvalue1, PROGRESS_ACCUMULATE);
+ break;
+ }
case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE:
{
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
@@ -827,8 +888,8 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
if(!miscvalue1)
continue;
- Map const* map = GetPlayer()->GetMap();
- if(!map->IsDungeon())
+ Map const* map = GetPlayer()->IsInWorld() ? GetPlayer()->GetMap() : MapManager::Instance().FindMap(GetPlayer()->GetMapId(), GetPlayer()->GetInstanceId());
+ if(!map || !map->IsDungeon())
continue;
// search case
@@ -1194,6 +1255,24 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
SetCriteriaProgress(achievementCriteria, spellCount);
break;
}
+ case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL:
+ // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
+ if(!miscvalue1)
+ continue;
+
+ if(achievementCriteria->win_duel.duelCount)
+ {
+ // those requirements couldn't be found in the dbc
+ AchievementCriteriaDataSet const* data = achievementmgr.GetCriteriaDataSet(achievementCriteria);
+ if(!data)
+ continue;
+
+ if(!data->Meets(GetPlayer(),unit))
+ continue;
+ }
+
+ SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
+ break;
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION:
SetCriteriaProgress(achievementCriteria, GetPlayer()->GetReputationMgr().GetReveredFactionCount());
break;
@@ -1270,7 +1349,6 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_RATING:
break;
// FIXME: not triggered in code as result, need to implement
- case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG:
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY:
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID:
case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE:
@@ -1298,7 +1376,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
if(IsCompletedCriteria(achievementCriteria,achievement))
CompletedCriteriaFor(achievement);
- // check again the completeness for SUMM and REQ COUNT achievements,
+ // check again the completeness for SUMM and REQ COUNT achievements,
// as they don't depend on the completed criteria but on the sum of the progress of each individual criteria
if (achievement->flags & ACHIEVEMENT_FLAG_SUMM)
{
@@ -1339,6 +1417,8 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve
switch(achievementCriteria->requiredType)
{
+ case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG:
+ return progress->counter >= achievementCriteria->win_bg.winCount;
case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE:
return progress->counter >= achievementCriteria->kill_creature.creatureCount;
case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL:
@@ -1430,7 +1510,6 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve
return progress->counter >= achievementCriteria->learn_skill_line.spellCount;
case ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL:
return progress->counter >= achievementCriteria->honorable_kill.killCount;
-
// handle all statistic-only criteria here
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND:
case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP:
@@ -1514,7 +1593,7 @@ bool AchievementMgr::IsCompletedAchievement(AchievementEntry const* entry)
return false;
}
- // Default case - need complete all or
+ // Default case - need complete all or
bool completed_all = true;
for(AchievementCriteriaEntryList::const_iterator itr = cList->begin(); itr != cList->end(); ++itr)
{
@@ -1844,6 +1923,10 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData()
switch(criteria->requiredType)
{
+ case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG:
+ if(!criteria->win_bg.additionalRequirement1_type)
+ continue;
+ break;
case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE:
break; // any cases
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST:
@@ -1878,6 +1961,10 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData()
if(criteria->do_emote.count==0)
continue;
break;
+ case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL: // skip statistics
+ if(criteria->win_duel.duelCount==0)
+ continue;
+ break;
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2: // any cases
break;
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE: // need skip generic cases
diff --git a/src/game/AchievementMgr.h b/src/game/AchievementMgr.h
index 9a3ff496e7b..5020539bb5c 100644
--- a/src/game/AchievementMgr.h
+++ b/src/game/AchievementMgr.h
@@ -51,17 +51,18 @@ enum AchievementCriteriaDataType
ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA = 6, // area id 0
ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA = 7, // spell_id effect_idx
ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE = 8, // minvalue value provided with achievement update must be not less that limit
- ACHIEVEMENT_CRITERIA_DATA_TYPE_T_LEVEL = 9, // minlevel minlevel of target
- ACHIEVEMENT_CRITERIA_DATA_TYPE_T_GENDER = 10,// gender 0=male; 1=female
+ ACHIEVEMENT_CRITERIA_DATA_TYPE_T_LEVEL = 9, // minlevel minlevel of target
+ ACHIEVEMENT_CRITERIA_DATA_TYPE_T_GENDER = 10,// gender 0=male; 1=female
ACHIEVEMENT_CRITERIA_DATA_TYPE_DISABLED = 11,// used to prevent achievement creteria complete if not all requirement implemented and listed in table
ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY = 12,// difficulty normal/heroic difficulty for current event map
ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT = 13,// count "with less than %u people in the zone"
ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM = 14,// team HORDE(67), ALLIANCE(469)
ACHIEVEMENT_CRITERIA_DATA_TYPE_S_DRUNK = 15,// drunken_state 0 (enum DrunkenState) of player
ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY = 16,// holiday_id 0 event in holiday time
+ ACHIEVEMENT_CRITERIA_DATA_TYPE_BG_LOSS_TEAM_SCORE = 17,// min_score max_score player's team win bg and opposition team have team score in range
};
-#define MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE 17 // maximum value in AchievementCriteriaDataType enum
+#define MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE 18 // maximum value in AchievementCriteriaDataType enum
class Player;
class Unit;
@@ -141,11 +142,17 @@ struct AchievementCriteriaData
{
uint32 state;
} drunk;
- // ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY
+ // ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY = 16
struct
{
- uint16 id;
+ uint32 id;
} holiday;
+ // ACHIEVEMENT_CRITERIA_DATA_TYPE_BG_LOSS_TEAM_SCORE= 17
+ struct
+ {
+ uint32 min_score;
+ uint32 max_score;
+ } bg_loss_team_score;
// ...
struct
{
@@ -227,6 +234,7 @@ class AchievementMgr
void SaveToDB();
void ResetAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1=0, uint32 miscvalue2=0);
void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1=0, uint32 miscvalue2=0, Unit *unit=NULL, uint32 time=0);
+ void CompletedAchievement(AchievementEntry const* entry);
void CheckAllAchievementCriteria();
void SendAllAchievementData();
void SendRespondInspectAchievements(Player* player);
@@ -238,7 +246,6 @@ class AchievementMgr
void SendCriteriaUpdate(uint32 id, CriteriaProgress const* progress);
void SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint32 changeValue, ProgressType ptype = PROGRESS_SET);
void CompletedCriteriaFor(AchievementEntry const* achievement);
- void CompletedAchievement(AchievementEntry const* entry);
bool IsCompletedCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement);
bool IsCompletedAchievement(AchievementEntry const* entry);
void CompleteAchievementsWithRefs(AchievementEntry const* entry);
diff --git a/src/game/AggressorAI.cpp b/src/game/AggressorAI.cpp
index d827e3e2672..3050c772e28 100644
--- a/src/game/AggressorAI.cpp
+++ b/src/game/AggressorAI.cpp
@@ -91,3 +91,58 @@ void SpellAI::UpdateAI(const uint32 diff)
else
DoMeleeAttackIfReady();
}
+
+void SpellCasterAI::InitializeAI()
+{
+ SpellAI::InitializeAI();
+ float m_attackDist = 30.0f;
+ for(SpellVct::iterator itr = spells.begin(); itr != spells.end(); ++itr)
+ {
+ if (AISpellInfo[*itr].condition == AICOND_COMBAT && m_attackDist > GetAISpellInfo(*itr)->maxRange)
+ m_attackDist = GetAISpellInfo(*itr)->maxRange;
+ }
+ if (m_attackDist == 30.0f)
+ m_attackDist = MELEE_RANGE;
+}
+
+void SpellCasterAI::EnterCombat(Unit *who)
+{
+ if (spells.empty())
+ return;
+
+ uint32 spell = rand() % spells.size();
+ uint32 count = 0;
+ for(SpellVct::iterator itr = spells.begin(); itr != spells.end(); ++itr, ++count)
+ {
+ if(AISpellInfo[*itr].condition == AICOND_AGGRO)
+ me->CastSpell(who, *itr, false);
+ else if (AISpellInfo[*itr].condition == AICOND_COMBAT)
+ {
+ uint32 cooldown = GetAISpellInfo(*itr)->realCooldown;
+ if (count == spell)
+ {
+ DoCast(spells[spell]);
+ cooldown += me->GetCurrentSpellCastTime(*itr);
+ }
+ events.ScheduleEvent(*itr, cooldown);
+ }
+ }
+}
+
+void SpellCasterAI::UpdateAI(const uint32 diff)
+{
+ if(!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ if(me->hasUnitState(UNIT_STAT_CASTING))
+ return;
+
+ if(uint32 spellId = events.ExecuteEvent())
+ {
+ DoCast(spellId);
+ uint32 casttime = me->GetCurrentSpellCastTime(spellId);
+ events.ScheduleEvent(spellId, (casttime ? casttime : 500) + GetAISpellInfo(spellId)->realCooldown);
+ }
+}
diff --git a/src/game/AggressorAI.h b/src/game/AggressorAI.h
index 2c43ccf82b7..cec11c0fb22 100644
--- a/src/game/AggressorAI.h
+++ b/src/game/AggressorAI.h
@@ -48,9 +48,21 @@ class TRINITY_DLL_SPEC SpellAI : public CreatureAI
void JustDied(Unit *killer);
void UpdateAI(const uint32 diff);
static int Permissible(const Creature *);
- private:
+ protected:
EventMap events;
SpellVct spells;
};
+class TRINITY_DLL_SPEC SpellCasterAI : public SpellAI
+{
+ public:
+ explicit SpellCasterAI(Creature *c) : SpellAI(c) {m_attackDist = MELEE_RANGE;}
+ void InitializeAI();
+ void AttackStart(Unit * victim){SpellAI::AttackStartCaster(victim, m_attackDist);}
+ void UpdateAI(const uint32 diff);
+ void EnterCombat(Unit *who);
+ private:
+ float m_attackDist;
+};
+
#endif
diff --git a/src/game/ArenaTeam.cpp b/src/game/ArenaTeam.cpp
index 23050dcf25c..22d121c38c1 100644
--- a/src/game/ArenaTeam.cpp
+++ b/src/game/ArenaTeam.cpp
@@ -20,6 +20,7 @@
#include "WorldPacket.h"
#include "ArenaTeam.h"
+#include "World.h"
void ArenaTeamMember::ModifyPersonalRating(Player* plr, int32 mod, uint32 slot)
{
@@ -32,21 +33,24 @@ void ArenaTeamMember::ModifyPersonalRating(Player* plr, int32 mod, uint32 slot)
ArenaTeam::ArenaTeam()
{
- Id = 0;
- Type = 0;
- Name = "";
- CaptainGuid = 0;
- BackgroundColor = 0; // background
- EmblemStyle = 0; // icon
- EmblemColor = 0; // icon color
- BorderStyle = 0; // border
- BorderColor = 0; // border color
- stats.games_week = 0;
- stats.games_season = 0;
- stats.rank = 0;
- stats.rating = ARENA_NEW_TEAM_RATING;
- stats.wins_week = 0;
- stats.wins_season = 0;
+ m_TeamId = 0;
+ m_Type = 0;
+ m_Name = "";
+ m_CaptainGuid = 0;
+ m_BackgroundColor = 0; // background
+ m_EmblemStyle = 0; // icon
+ m_EmblemColor = 0; // icon color
+ m_BorderStyle = 0; // border
+ m_BorderColor = 0; // border color
+ m_stats.games_week = 0;
+ m_stats.games_season = 0;
+ m_stats.rank = 0;
+ if (sWorld.getConfig(CONFIG_ARENA_SEASON_ID) >= 6)
+ m_stats.rating = 0;
+ else
+ m_stats.rating = 1500;
+ m_stats.wins_week = 0;
+ m_stats.wins_season = 0;
}
ArenaTeam::~ArenaTeam()
@@ -62,27 +66,27 @@ bool ArenaTeam::Create(uint64 captainGuid, uint32 type, std::string ArenaTeamNam
sLog.outDebug("GUILD: creating arena team %s to leader: %u", ArenaTeamName.c_str(), GUID_LOPART(captainGuid));
- CaptainGuid = captainGuid;
- Name = ArenaTeamName;
- Type = type;
+ m_CaptainGuid = captainGuid;
+ m_Name = ArenaTeamName;
+ m_Type = type;
- Id = objmgr.GenerateArenaTeamId();
+ m_TeamId = objmgr.GenerateArenaTeamId();
// ArenaTeamName already assigned to ArenaTeam::name, use it to encode string for DB
CharacterDatabase.escape_string(ArenaTeamName);
CharacterDatabase.BeginTransaction();
- // CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid='%u'", Id); - MAX(arenateam)+1 not exist
- CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid='%u'", Id);
+ // CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid='%u'", m_TeamId); - MAX(arenateam)+1 not exist
+ CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid='%u'", m_TeamId);
CharacterDatabase.PExecute("INSERT INTO arena_team (arenateamid,name,captainguid,type,BackgroundColor,EmblemStyle,EmblemColor,BorderStyle,BorderColor) "
"VALUES('%u','%s','%u','%u','%u','%u','%u','%u','%u')",
- Id, ArenaTeamName.c_str(), GUID_LOPART(CaptainGuid), Type, BackgroundColor, EmblemStyle, EmblemColor, BorderStyle, BorderColor);
+ m_TeamId, ArenaTeamName.c_str(), GUID_LOPART(m_CaptainGuid), m_Type, m_BackgroundColor, m_EmblemStyle, m_EmblemColor, m_BorderStyle, m_BorderColor);
CharacterDatabase.PExecute("INSERT INTO arena_team_stats (arenateamid, rating, games, wins, played, wins2, rank) VALUES "
- "('%u', '%u', '%u', '%u', '%u', '%u', '%u')", Id, stats.rating, stats.games_week, stats.wins_week, stats.games_season, stats.wins_season, stats.rank);
+ "('%u', '%u', '%u', '%u', '%u', '%u', '%u')", m_TeamId, m_stats.rating, m_stats.games_week, m_stats.wins_week, m_stats.games_season, m_stats.wins_season, m_stats.rank);
CharacterDatabase.CommitTransaction();
- AddMember(CaptainGuid);
+ AddMember(m_CaptainGuid);
sLog.outArena("New ArenaTeam created [Id: %u] [Type: %u] [Captain GUID: %u]", GetId(), GetType(), GetCaptain());
return true;
}
@@ -139,19 +143,29 @@ bool ArenaTeam::AddMember(const uint64& PlayerGuid)
newmember.games_week = 0;
newmember.wins_season = 0;
newmember.wins_week = 0;
- newmember.personal_rating = AREAN_NEW_PERSONAL_RATING;
- members.push_back(newmember);
+ if (sWorld.getConfig(CONFIG_ARENA_SEASON_ID) >= 6)
+ {
+ if (m_stats.rating < 1000)
+ newmember.personal_rating = m_stats.rating;
+ else
+ newmember.personal_rating = 1000;
+ }
+ else
+ {
+ newmember.personal_rating = 1500;
+ }
+ m_members.push_back(newmember);
- CharacterDatabase.PExecute("INSERT INTO arena_team_member (arenateamid, guid, personal_rating) VALUES ('%u', '%u', '%u')", Id, GUID_LOPART(newmember.guid), newmember.personal_rating );
+ CharacterDatabase.PExecute("INSERT INTO arena_team_member (arenateamid, guid, personal_rating) VALUES ('%u', '%u', '%u')", m_TeamId, GUID_LOPART(newmember.guid), newmember.personal_rating );
if(pl)
{
- pl->SetInArenaTeam(Id, GetSlot());
+ pl->SetInArenaTeam(m_TeamId, GetSlot());
pl->SetArenaTeamIdInvited(0);
pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5, newmember.personal_rating );
// hide promote/remove buttons
- if(CaptainGuid != PlayerGuid)
+ if(m_CaptainGuid != PlayerGuid)
pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + 1, 1);
sLog.outArena("Player: %s [GUID: %u] joined arena team type: %u [Id: %u].", pl->GetName(), pl->GetGUIDLow(), GetType(), GetId());
}
@@ -167,15 +181,15 @@ bool ArenaTeam::LoadArenaTeamFromDB(uint32 ArenaTeamId)
Field *fields = result->Fetch();
- Id = fields[0].GetUInt32();
- Name = fields[1].GetCppString();
- CaptainGuid = MAKE_NEW_GUID(fields[2].GetUInt32(), 0, HIGHGUID_PLAYER);
- Type = fields[3].GetUInt32();
- BackgroundColor = fields[4].GetUInt32();
- EmblemStyle = fields[5].GetUInt32();
- EmblemColor = fields[6].GetUInt32();
- BorderStyle = fields[7].GetUInt32();
- BorderColor = fields[8].GetUInt32();
+ m_TeamId = fields[0].GetUInt32();
+ m_Name = fields[1].GetCppString();
+ m_CaptainGuid = MAKE_NEW_GUID(fields[2].GetUInt32(), 0, HIGHGUID_PLAYER);
+ m_Type = fields[3].GetUInt32();
+ m_BackgroundColor = fields[4].GetUInt32();
+ m_EmblemStyle = fields[5].GetUInt32();
+ m_EmblemColor = fields[6].GetUInt32();
+ m_BorderStyle = fields[7].GetUInt32();
+ m_BorderColor = fields[8].GetUInt32();
delete result;
@@ -207,12 +221,12 @@ void ArenaTeam::LoadStatsFromDB(uint32 ArenaTeamId)
Field *fields = result->Fetch();
- stats.rating = fields[0].GetUInt32();
- stats.games_week = fields[1].GetUInt32();
- stats.wins_week = fields[2].GetUInt32();
- stats.games_season = fields[3].GetUInt32();
- stats.wins_season = fields[4].GetUInt32();
- stats.rank = fields[5].GetUInt32();
+ m_stats.rating = fields[0].GetUInt32();
+ m_stats.games_week = fields[1].GetUInt32();
+ m_stats.wins_week = fields[2].GetUInt32();
+ m_stats.games_season = fields[3].GetUInt32();
+ m_stats.wins_season = fields[4].GetUInt32();
+ m_stats.rank = fields[5].GetUInt32();
delete result;
}
@@ -239,7 +253,7 @@ void ArenaTeam::LoadMembersFromDB(uint32 ArenaTeamId)
newmember.personal_rating = fields[5].GetUInt32();
newmember.name = fields[6].GetCppString();
newmember.Class = fields[7].GetUInt8();
- members.push_back(newmember);
+ m_members.push_back(newmember);
}while( result->NextRow() );
delete result;
}
@@ -252,10 +266,10 @@ void ArenaTeam::SetCaptain(const uint64& guid)
oldcaptain->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 1);
// set new captain
- CaptainGuid = guid;
+ m_CaptainGuid = guid;
// update database
- CharacterDatabase.PExecute("UPDATE arena_team SET captainguid = '%u' WHERE arenateamid = '%u'", GUID_LOPART(guid), Id);
+ CharacterDatabase.PExecute("UPDATE arena_team SET captainguid = '%u' WHERE arenateamid = '%u'", GUID_LOPART(guid), m_TeamId);
// enable remove/promote buttons
Player *newcaptain = objmgr.GetPlayer(guid);
@@ -268,11 +282,11 @@ void ArenaTeam::SetCaptain(const uint64& guid)
void ArenaTeam::DelMember(uint64 guid)
{
- for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ for (MemberList::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
{
if (itr->guid == guid)
{
- members.erase(itr);
+ m_members.erase(itr);
break;
}
}
@@ -300,21 +314,21 @@ void ArenaTeam::Disband(WorldSession *session)
session->BuildArenaTeamEventPacket(&data, ERR_ARENA_TEAM_DISBANDED_S, 2, session->GetPlayerName(), GetName(), "");
BroadcastPacket(&data);
- while (!members.empty())
+ while (!m_members.empty())
{
// Removing from members is done in DelMember.
- DelMember(members.front().guid);
+ DelMember(m_members.front().guid);
}
if(Player *player = session->GetPlayer())
sLog.outArena("Player: %s [GUID: %u] disbanded arena team type: %u [Id: %u].", player->GetName(), player->GetGUIDLow(), GetType(), GetId());
CharacterDatabase.BeginTransaction();
- CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid = '%u'", Id);
- CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u'", Id); //< this should be alredy done by calling DelMember(memberGuids[j]); for each member
- CharacterDatabase.PExecute("DELETE FROM arena_team_stats WHERE arenateamid = '%u'", Id);
+ CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid = '%u'", m_TeamId);
+ CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u'", m_TeamId); //< this should be alredy done by calling DelMember(memberGuids[j]); for each member
+ CharacterDatabase.PExecute("DELETE FROM arena_team_stats WHERE arenateamid = '%u'", m_TeamId);
CharacterDatabase.CommitTransaction();
- objmgr.RemoveArenaTeam(Id);
+ objmgr.RemoveArenaTeam(m_TeamId);
}
void ArenaTeam::Roster(WorldSession *session)
@@ -324,12 +338,12 @@ void ArenaTeam::Roster(WorldSession *session)
uint8 unk308 = 0;
WorldPacket data(SMSG_ARENA_TEAM_ROSTER, 100);
- data << uint32(GetId()); // arena team id
+ data << uint32(GetId()); // team id
data << uint8(unk308); // 308 unknown value but affect packet structure
data << uint32(GetMembersSize()); // members count
data << uint32(GetType()); // arena team type?
- for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
+ for (MemberList::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
{
pl = objmgr.GetPlayer(itr->guid);
@@ -361,11 +375,11 @@ void ArenaTeam::Query(WorldSession *session)
data << uint32(GetId()); // team id
data << GetName(); // team name
data << uint32(GetType()); // arena team type (2=2x2, 3=3x3 or 5=5x5)
- data << uint32(BackgroundColor); // background color
- data << uint32(EmblemStyle); // emblem style
- data << uint32(EmblemColor); // emblem color
- data << uint32(BorderStyle); // border style
- data << uint32(BorderColor); // border color
+ data << uint32(m_BackgroundColor); // background color
+ data << uint32(m_EmblemStyle); // emblem style
+ data << uint32(m_EmblemColor); // emblem color
+ data << uint32(m_BorderStyle); // border style
+ data << uint32(m_BorderColor); // border color
session->SendPacket(&data);
sLog.outDebug("WORLD: Sent SMSG_ARENA_TEAM_QUERY_RESPONSE");
}
@@ -373,13 +387,13 @@ void ArenaTeam::Query(WorldSession *session)
void ArenaTeam::Stats(WorldSession *session)
{
WorldPacket data(SMSG_ARENA_TEAM_STATS, 4*7);
- data << uint32(GetId()); // arena team id
- data << uint32(stats.rating); // rating
- data << uint32(stats.games_week); // games this week
- data << uint32(stats.wins_week); // wins this week
- data << uint32(stats.games_season); // played this season
- data << uint32(stats.wins_season); // wins this season
- data << uint32(stats.rank); // rank
+ data << uint32(GetId()); // team id
+ data << uint32(m_stats.rating); // rating
+ data << uint32(m_stats.games_week); // games this week
+ data << uint32(m_stats.wins_week); // wins this week
+ data << uint32(m_stats.games_season); // played this season
+ data << uint32(m_stats.wins_season); // wins this season
+ data << uint32(m_stats.rank); // rank
session->SendPacket(&data);
}
@@ -387,7 +401,7 @@ void ArenaTeam::NotifyStatsChanged()
{
// this is called after a rated match ended
// updates arena team stats for every member of the team (not only the ones who participated!)
- for(MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
+ for(MemberList::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
{
Player * plr = objmgr.GetPlayer(itr->guid);
if(plr)
@@ -405,9 +419,9 @@ void ArenaTeam::InspectStats(WorldSession *session, uint64 guid)
data << uint64(guid); // player guid
data << uint8(GetSlot()); // slot (0...2)
data << uint32(GetId()); // arena team id
- data << uint32(stats.rating); // rating
- data << uint32(stats.games_season); // season played
- data << uint32(stats.wins_season); // season wins
+ data << uint32(m_stats.rating); // rating
+ data << uint32(m_stats.games_season); // season played
+ data << uint32(m_stats.wins_season); // season wins
data << uint32(member->games_season); // played (count of all games, that the inspected member participated...)
data << uint32(member->personal_rating); // personal rating
session->SendPacket(&data);
@@ -415,13 +429,13 @@ void ArenaTeam::InspectStats(WorldSession *session, uint64 guid)
void ArenaTeam::SetEmblem(uint32 backgroundColor, uint32 emblemStyle, uint32 emblemColor, uint32 borderStyle, uint32 borderColor)
{
- BackgroundColor = backgroundColor;
- EmblemStyle = emblemStyle;
- EmblemColor = emblemColor;
- BorderStyle = borderStyle;
- BorderColor = borderColor;
+ m_BackgroundColor = backgroundColor;
+ m_EmblemStyle = emblemStyle;
+ m_EmblemColor = emblemColor;
+ m_BorderStyle = borderStyle;
+ m_BorderColor = borderColor;
- CharacterDatabase.PExecute("UPDATE arena_team SET BackgroundColor='%u', EmblemStyle='%u', EmblemColor='%u', BorderStyle='%u', BorderColor='%u' WHERE arenateamid='%u'", BackgroundColor, EmblemStyle, EmblemColor, BorderStyle, BorderColor, Id);
+ CharacterDatabase.PExecute("UPDATE arena_team SET BackgroundColor='%u', EmblemStyle='%u', EmblemColor='%u', BorderStyle='%u', BorderColor='%u' WHERE arenateamid='%u'", m_BackgroundColor, m_EmblemStyle, m_EmblemColor, m_BorderStyle, m_BorderColor, m_TeamId);
}
void ArenaTeam::SetStats(uint32 stat_type, uint32 value)
@@ -429,27 +443,27 @@ void ArenaTeam::SetStats(uint32 stat_type, uint32 value)
switch(stat_type)
{
case STAT_TYPE_RATING:
- stats.rating = value;
+ m_stats.rating = value;
CharacterDatabase.PExecute("UPDATE arena_team_stats SET rating = '%u' WHERE arenateamid = '%u'", value, GetId());
break;
case STAT_TYPE_GAMES_WEEK:
- stats.games_week = value;
+ m_stats.games_week = value;
CharacterDatabase.PExecute("UPDATE arena_team_stats SET games = '%u' WHERE arenateamid = '%u'", value, GetId());
break;
case STAT_TYPE_WINS_WEEK:
- stats.wins_week = value;
+ m_stats.wins_week = value;
CharacterDatabase.PExecute("UPDATE arena_team_stats SET wins = '%u' WHERE arenateamid = '%u'", value, GetId());
break;
case STAT_TYPE_GAMES_SEASON:
- stats.games_season = value;
+ m_stats.games_season = value;
CharacterDatabase.PExecute("UPDATE arena_team_stats SET played = '%u' WHERE arenateamid = '%u'", value, GetId());
break;
case STAT_TYPE_WINS_SEASON:
- stats.wins_season = value;
+ m_stats.wins_season = value;
CharacterDatabase.PExecute("UPDATE arena_team_stats SET wins2 = '%u' WHERE arenateamid = '%u'", value, GetId());
break;
case STAT_TYPE_RANK:
- stats.rank = value;
+ m_stats.rank = value;
CharacterDatabase.PExecute("UPDATE arena_team_stats SET rank = '%u' WHERE arenateamid = '%u'", value, GetId());
break;
default:
@@ -460,7 +474,7 @@ void ArenaTeam::SetStats(uint32 stat_type, uint32 value)
void ArenaTeam::BroadcastPacket(WorldPacket *packet)
{
- for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
+ for (MemberList::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
{
Player *player = objmgr.GetPlayer(itr->guid);
if(player)
@@ -484,7 +498,7 @@ uint8 ArenaTeam::GetSlotByType( uint32 type )
bool ArenaTeam::HaveMember( const uint64& guid ) const
{
- for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
+ for (MemberList::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
if(itr->guid == guid)
return true;
@@ -496,17 +510,18 @@ uint32 ArenaTeam::GetPoints(uint32 MemberRating)
// returns how many points would be awarded with this team type with this rating
float points;
- uint32 rating = MemberRating + 150 < stats.rating ? MemberRating : stats.rating;
+ uint32 rating = MemberRating + 150 < m_stats.rating ? MemberRating : m_stats.rating;
if(rating<=1500)
- points = (float)rating * 0.22f + 14.0f;
+ // points = (float)1500 * 0.22f + 14.0f;
+ points = 344.0f; // 3.1 change - teams with rating below 1500 get arena points for 1500 rating
else
points = 1511.26f / (1.0f + 1639.28f * exp(-0.00412f * (float)rating));
// type penalties for <5v5 teams
- if(Type == ARENA_TEAM_2v2)
+ if(m_Type == ARENA_TEAM_2v2)
points *= 0.76f;
- else if(Type == ARENA_TEAM_3v3)
+ else if(m_Type == ARENA_TEAM_3v3)
points *= 0.88f;
return (uint32) points;
@@ -516,31 +531,43 @@ float ArenaTeam::GetChanceAgainst(uint32 own_rating, uint32 enemy_rating)
{
// returns the chance to win against a team with the given rating, used in the rating adjustment calculation
// ELO system
+
+ if (sWorld.getConfig(CONFIG_ARENA_SEASON_ID) >= 6)
+ if (enemy_rating < 1300)
+ enemy_rating = 1300;
return 1.0f/(1.0f+exp(log(10.0f)*(float)((float)enemy_rating - (float)own_rating)/400.0f));
}
+void ArenaTeam::FinishGame(int32 mod)
+{
+ if (int32(m_stats.rating) + mod < 0)
+ m_stats.rating = 0;
+ else
+ m_stats.rating += mod;
+
+ m_stats.games_week += 1;
+ m_stats.games_season += 1;
+ // update team's rank
+ m_stats.rank = 1;
+ ObjectMgr::ArenaTeamMap::const_iterator i = objmgr.GetArenaTeamMapBegin();
+ for ( ; i != objmgr.GetArenaTeamMapEnd(); ++i)
+ {
+ if (i->second->GetType() == m_Type && i->second->GetStats().rating > m_stats.rating)
+ ++m_stats.rank;
+ }
+}
+
int32 ArenaTeam::WonAgainst(uint32 againstRating)
{
// called when the team has won
//'chance' calculation - to beat the opponent
- float chance = GetChanceAgainst(stats.rating,againstRating);
+ float chance = GetChanceAgainst(m_stats.rating, againstRating);
// calculate the rating modification (ELO system with k=32)
int32 mod = (int32)floor(32.0f * (1.0f - chance));
// modify the team stats accordingly
- int32 newTeamRating = (int32)stats.rating + mod;
- stats.rating = newTeamRating > 0 ? newTeamRating : 0;
- stats.games_week += 1;
- stats.wins_week += 1;
- stats.games_season += 1;
- stats.wins_season += 1;
- //update team's rank
- stats.rank = 1;
- ObjectMgr::ArenaTeamMap::const_iterator i = objmgr.GetArenaTeamMapBegin();
- for ( ; i != objmgr.GetArenaTeamMapEnd(); ++i)
- {
- if (i->second->GetType() == this->Type && i->second->GetStats().rating > stats.rating)
- ++stats.rank;
- }
+ FinishGame(mod);
+ m_stats.wins_week += 1;
+ m_stats.wins_season += 1;
// return the rating change, used to display it on the results screen
return mod;
@@ -550,23 +577,11 @@ int32 ArenaTeam::LostAgainst(uint32 againstRating)
{
// called when the team has lost
//'chance' calculation - to loose to the opponent
- float chance = GetChanceAgainst(stats.rating,againstRating);
+ float chance = GetChanceAgainst(m_stats.rating, againstRating);
// calculate the rating modification (ELO system with k=32)
int32 mod = (int32)ceil(32.0f * (0.0f - chance));
// modify the team stats accordingly
- int32 newTeamRating = (int32)stats.rating + mod;
- stats.rating = newTeamRating > 0 ? newTeamRating : 0;
- stats.games_week += 1;
- stats.games_season += 1;
- //update team's rank
-
- stats.rank = 1;
- ObjectMgr::ArenaTeamMap::const_iterator i = objmgr.GetArenaTeamMapBegin();
- for ( ; i != objmgr.GetArenaTeamMapEnd(); ++i)
- {
- if (i->second->GetType() == this->Type && i->second->GetStats().rating > stats.rating)
- ++stats.rank;
- }
+ FinishGame(mod);
// return the rating change, used to display it on the results screen
return mod;
@@ -575,7 +590,7 @@ int32 ArenaTeam::LostAgainst(uint32 againstRating)
void ArenaTeam::MemberLost(Player * plr, uint32 againstRating)
{
// called for each participant of a match after losing
- for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ for(MemberList::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
{
if(itr->guid == plr->GetGUID())
{
@@ -597,7 +612,7 @@ void ArenaTeam::MemberLost(Player * plr, uint32 againstRating)
void ArenaTeam::OfflineMemberLost(uint64 guid, uint32 againstRating)
{
// called for offline player after ending rated arena match!
- for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ for(MemberList::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
{
if(itr->guid == guid)
{
@@ -619,7 +634,7 @@ void ArenaTeam::OfflineMemberLost(uint64 guid, uint32 againstRating)
void ArenaTeam::MemberWon(Player * plr, uint32 againstRating)
{
// called for each participant after winning a match
- for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ for(MemberList::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
{
if(itr->guid == plr->GetGUID())
{
@@ -645,17 +660,17 @@ void ArenaTeam::UpdateArenaPointsHelper(std::map<uint32, uint32>& PlayerPoints)
// called after a match has ended and the stats are already modified
// helper function for arena point distribution (this way, when distributing, no actual calculation is required, just a few comparisons)
// 10 played games per week is a minimum
- if (stats.games_week < 10)
+ if (m_stats.games_week < 10)
return;
// to get points, a player has to participate in at least 30% of the matches
- uint32 min_plays = (uint32) ceil(stats.games_week * 0.3);
- for(MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
+ uint32 min_plays = (uint32) ceil(m_stats.games_week * 0.3);
+ for(MemberList::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
{
// the player participated in enough games, update his points
uint32 points_to_add = 0;
if (itr->games_week >= min_plays)
points_to_add = GetPoints(itr->personal_rating);
- // OBSOLETE : CharacterDatabase.PExecute("UPDATE arena_team_member SET points_to_add = '%u' WHERE arenateamid = '%u' AND guid = '%u'", points_to_add, Id, itr->guid);
+ // OBSOLETE : CharacterDatabase.PExecute("UPDATE arena_team_member SET points_to_add = '%u' WHERE arenateamid = '%u' AND guid = '%u'", points_to_add, m_TeamId, itr->guid);
std::map<uint32, uint32>::iterator plr_itr = PlayerPoints.find(GUID_LOPART(itr->guid));
if (plr_itr != PlayerPoints.end())
@@ -674,19 +689,19 @@ void ArenaTeam::SaveToDB()
// save team and member stats to db
// called after a match has ended, or when calculating arena_points
CharacterDatabase.BeginTransaction();
- CharacterDatabase.PExecute("UPDATE arena_team_stats SET rating = '%u',games = '%u',played = '%u',rank = '%u',wins = '%u',wins2 = '%u' WHERE arenateamid = '%u'", stats.rating, stats.games_week, stats.games_season, stats.rank, stats.wins_week, stats.wins_season, GetId());
- for(MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
+ CharacterDatabase.PExecute("UPDATE arena_team_stats SET rating = '%u',games = '%u',played = '%u',rank = '%u',wins = '%u',wins2 = '%u' WHERE arenateamid = '%u'", m_stats.rating, m_stats.games_week, m_stats.games_season, m_stats.rank, m_stats.wins_week, m_stats.wins_season, GetId());
+ for(MemberList::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
{
- CharacterDatabase.PExecute("UPDATE arena_team_member SET played_week = '%u', wons_week = '%u', played_season = '%u', wons_season = '%u', personal_rating = '%u' WHERE arenateamid = '%u' AND guid = '%u'", itr->games_week, itr->wins_week, itr->games_season, itr->wins_season, itr->personal_rating, Id, GUID_LOPART(itr->guid));
+ CharacterDatabase.PExecute("UPDATE arena_team_member SET played_week = '%u', wons_week = '%u', played_season = '%u', wons_season = '%u', personal_rating = '%u' WHERE arenateamid = '%u' AND guid = '%u'", itr->games_week, itr->wins_week, itr->games_season, itr->wins_season, itr->personal_rating, m_TeamId, GUID_LOPART(itr->guid));
}
CharacterDatabase.CommitTransaction();
}
void ArenaTeam::FinishWeek()
{
- stats.games_week = 0; // played this week
- stats.wins_week = 0; // wins this week
- for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ m_stats.games_week = 0; // played this week
+ m_stats.wins_week = 0; // wins this week
+ for(MemberList::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
{
itr->games_week = 0;
itr->wins_week = 0;
@@ -695,7 +710,7 @@ void ArenaTeam::FinishWeek()
bool ArenaTeam::IsFighting() const
{
- for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
+ for (MemberList::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
{
if (Player *p = objmgr.GetPlayer(itr->guid))
{
diff --git a/src/game/ArenaTeam.h b/src/game/ArenaTeam.h
index 2dc5b45e880..dbeac2f09f0 100644
--- a/src/game/ArenaTeam.h
+++ b/src/game/ArenaTeam.h
@@ -85,9 +85,6 @@ enum ArenaTeamTypes
ARENA_TEAM_5v5 = 5
};
-#define ARENA_NEW_TEAM_RATING 0
-#define AREAN_NEW_PERSONAL_RATING 0
-
struct ArenaTeamMember
{
uint64 guid;
@@ -120,26 +117,26 @@ class ArenaTeam
ArenaTeam();
~ArenaTeam();
- bool Create(uint64 CaptainGuid, uint32 type, std::string ArenaTeamName);
+ bool Create(uint64 captainGuid, uint32 type, std::string ArenaTeamName);
void Disband(WorldSession *session);
typedef std::list<ArenaTeamMember> MemberList;
- uint32 GetId() const { return Id; }
- uint32 GetType() const { return Type; }
+ uint32 GetId() const { return m_TeamId; }
+ uint32 GetType() const { return m_Type; }
uint8 GetSlot() const { return GetSlotByType(GetType()); }
static uint8 GetSlotByType(uint32 type);
- const uint64& GetCaptain() const { return CaptainGuid; }
- std::string GetName() const { return Name; }
- const ArenaTeamStats& GetStats() const { return stats; }
+ const uint64& GetCaptain() const { return m_CaptainGuid; }
+ std::string GetName() const { return m_Name; }
+ const ArenaTeamStats& GetStats() const { return m_stats; }
void SetStats(uint32 stat_type, uint32 value);
- uint32 GetRating() const { return stats.rating; }
+ uint32 GetRating() const { return m_stats.rating; }
- uint32 GetEmblemStyle() const { return EmblemStyle; }
- uint32 GetEmblemColor() const { return EmblemColor; }
- uint32 GetBorderStyle() const { return BorderStyle; }
- uint32 GetBorderColor() const { return BorderColor; }
- uint32 GetBackgroundColor() const { return BackgroundColor; }
+ uint32 GetEmblemStyle() const { return m_EmblemStyle; }
+ uint32 GetEmblemColor() const { return m_EmblemColor; }
+ uint32 GetBorderStyle() const { return m_BorderStyle; }
+ uint32 GetBorderColor() const { return m_BorderColor; }
+ uint32 GetBackgroundColor() const { return m_BackgroundColor; }
void SetCaptain(const uint64& guid);
bool AddMember(const uint64& PlayerGuid);
@@ -150,15 +147,15 @@ class ArenaTeam
void SetEmblem(uint32 backgroundColor, uint32 emblemStyle, uint32 emblemColor, uint32 borderStyle, uint32 borderColor);
- size_t GetMembersSize() const { return members.size(); }
- bool Empty() const { return members.empty(); }
- MemberList::iterator membersBegin() { return members.begin(); }
- MemberList::iterator membersEnd() { return members.end(); }
+ size_t GetMembersSize() const { return m_members.size(); }
+ bool Empty() const { return m_members.empty(); }
+ MemberList::iterator m_membersBegin() { return m_members.begin(); }
+ MemberList::iterator m_membersEnd() { return m_members.end(); }
bool HaveMember(const uint64& guid) const;
ArenaTeamMember* GetMember(const uint64& guid)
{
- for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ for (MemberList::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
if(itr->guid == guid)
return &(*itr);
@@ -167,7 +164,7 @@ class ArenaTeam
ArenaTeamMember* GetMember(const std::string& name)
{
- for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ for (MemberList::iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
if(itr->name == name)
return &(*itr);
@@ -202,22 +199,23 @@ class ArenaTeam
void NotifyStatsChanged();
void FinishWeek();
+ void FinishGame(int32 mod);
protected:
- uint32 Id;
- uint32 Type;
- std::string Name;
- uint64 CaptainGuid;
+ uint32 m_TeamId;
+ uint32 m_Type;
+ std::string m_Name;
+ uint64 m_CaptainGuid;
- uint32 BackgroundColor; // ARGB format
- uint32 EmblemStyle; // icon id
- uint32 EmblemColor; // ARGB format
- uint32 BorderStyle; // border image id
- uint32 BorderColor; // ARGB format
+ uint32 m_BackgroundColor; // ARGB format
+ uint32 m_EmblemStyle; // icon id
+ uint32 m_EmblemColor; // ARGB format
+ uint32 m_BorderStyle; // border image id
+ uint32 m_BorderColor; // ARGB format
- MemberList members;
- ArenaTeamStats stats;
+ MemberList m_members;
+ ArenaTeamStats m_stats;
};
#endif
diff --git a/src/game/AuctionHouseBot.cpp b/src/game/AuctionHouseBot.cpp
index c2af4c92c15..3e53f3f4e9b 100644
--- a/src/game/AuctionHouseBot.cpp
+++ b/src/game/AuctionHouseBot.cpp
@@ -1,73 +1,83 @@
-#include <vector>
-#include <iostream>
-#include "time.h"
-
-#include "ObjectMgr.h"
-#include "World.h"
-#include "WorldSession.h"
-#include "Config/ConfigEnv.h"
-#include "Database/DatabaseEnv.h"
-
#include "AuctionHouseBot.h"
+#include "ObjectMgr.h"
#include "AuctionHouseMgr.h"
-#include "Bag.h"
-#include "Item.h"
-#include "Log.h"
-#include "Player.h"
+
+#include "Policies/SingletonImp.h"
+INSTANTIATE_SINGLETON_1(AuctionHouseBot);
using namespace std;
-static bool debug_Out = sConfig.GetBoolDefault("AuctionHouseBot.DEBUG", false);
-
-static vector<uint32> npcItems;
-static vector<uint32> lootItems;
-static vector<uint32> greyTradeGoodsBin;
-static vector<uint32> whiteTradeGoodsBin;
-static vector<uint32> greenTradeGoodsBin;
-static vector<uint32> blueTradeGoodsBin;
-static vector<uint32> purpleTradeGoodsBin;
-static vector<uint32> orangeTradeGoodsBin;
-static vector<uint32> yellowTradeGoodsBin;
-static vector<uint32> greyItemsBin;
-static vector<uint32> whiteItemsBin;
-static vector<uint32> greenItemsBin;
-static vector<uint32> blueItemsBin;
-static vector<uint32> purpleItemsBin;
-static vector<uint32> orangeItemsBin;
-static vector<uint32> yellowItemsBin;
-
-static bool AHBSeller = 0;
-static bool AHBBuyer = 0;
-
-static bool Vendor_Items = 0;
-static bool Loot_Items = 0;
-static bool Other_Items = 0;
-
-static bool No_Bind = 0;
-static bool Bind_When_Picked_Up = 0;
-static bool Bind_When_Equipped = 0;
-static bool Bind_When_Use = 0;
-static bool Bind_Quest_Item = 0;
-
-static AHBConfig AllianceConfig = AHBConfig(2);
-static AHBConfig HordeConfig = AHBConfig(6);
-static AHBConfig NeutralConfig = AHBConfig(7);
-time_t _lastrun_a;
-time_t _lastrun_h;
-time_t _lastrun_n;
-
-///////////////////////////////////////////////////////////////////////////////
-//
-///////////////////////////////////////////////////////////////////////////////
-static inline uint32 minValue(uint32 a, uint32 b)
+AuctionHouseBot::AuctionHouseBot()
+{
+ debug_Out = false;
+
+ AHBSeller = false;
+ AHBBuyer = false;
+
+ //Begin Filters
+
+ Vendor_Items = false;
+ Loot_Items = false;
+ Other_Items = false;
+
+ No_Bind = false;
+ Bind_When_Picked_Up = false;
+ Bind_When_Equipped = false;
+ Bind_When_Use = false;
+ Bind_Quest_Item = false;
+
+ DisableBeta_PTR_Unused = false;
+ DisablePermEnchant = false;
+ DisableConjured = false;
+ DisableGems = false;
+ DisableMoney = false;
+ DisableMoneyLoot = false;
+ DisableLootable = false;
+ DisableKeys = false;
+ DisableDuration = false;
+ DisableBOP_Or_Quest_NoReqLevel = false;
+
+ DisableWarriorItems = false;
+ DisablePaladinItems = false;
+ DisableHunterItems = false;
+ DisableRogueItems = false;
+ DisablePriestItems = false;
+ DisableDKItems = false;
+ DisableShamanItems = false;
+ DisableMageItems = false;
+ DisableWarlockItems = false;
+ DisableUnusedClassItems = false;
+ DisableDruidItems = false;
+
+ DisableItemsBelowLevel = 0;
+ DisableItemsAboveLevel = 0;
+ DisableTGsBelowLevel = 0;
+ DisableTGsAboveLevel = 0;
+ DisableItemsBelowGUID = 0;
+ DisableItemsAboveGUID = 0;
+ DisableTGsBelowGUID = 0;
+ DisableTGsAboveGUID = 0;
+ DisableItemsBelowReqLevel = 0;
+ DisableItemsAboveReqLevel = 0;
+ DisableTGsBelowReqLevel = 0;
+ DisableTGsAboveReqLevel = 0;
+ DisableItemsBelowReqSkillRank = 0;
+ DisableItemsAboveReqSkillRank = 0;
+ DisableTGsBelowReqSkillRank = 0;
+ DisableTGsAboveReqSkillRank = 0;
+
+ //End Filters
+
+ AllianceConfig = AHBConfig(2);
+ HordeConfig = AHBConfig(6);
+ NeutralConfig = AHBConfig(7);
+}
+
+AuctionHouseBot::~AuctionHouseBot()
{
- return a <= b ? a : b;
}
-///////////////////////////////////////////////////////////////////////////////
-//
-///////////////////////////////////////////////////////////////////////////////
-static void addNewAuctions(Player *AHBplayer, AHBConfig *config)
+void AuctionHouseBot::addNewAuctions(Player *AHBplayer, AHBConfig *config)
{
if (!AHBSeller)
return;
@@ -78,19 +88,26 @@ static void addNewAuctions(Player *AHBplayer, AHBConfig *config)
uint32 maxItems = config->GetMaxItems();
uint32 auctions = auctionHouse->Getcount();
uint32 AuctioneerGUID = 0;
- switch (config->GetAHID()){
- case 2:
- AuctioneerGUID = 79707; //Human in stormwind.
- case 6:
- AuctioneerGUID = 4656; //orc in Orgrimmar
- case 7:
- AuctioneerGUID = 23442; //goblin in GZ
- default:
- AuctioneerGUID = 23442; //default to neutral 7
+ switch (config->GetAHID())
+ {
+ case 2:
+ AuctioneerGUID = 79707; //Human in stormwind.
+ break;
+ case 6:
+ AuctioneerGUID = 4656; //orc in Orgrimmar
+ break;
+ case 7:
+ AuctioneerGUID = 23442; //goblin in GZ
+ break;
+ default:
+ if (debug_Out) sLog.outError("GetAHID() - Default switch reached");
+ AuctioneerGUID = 23442; //default to neutral 7
+ break;
}
if (auctions >= minItems)
- return;
+ return;
+
if (auctions <= maxItems)
{
if ((maxItems - auctions) > ItemsPerCycle)
@@ -113,9 +130,9 @@ static void addNewAuctions(Player *AHBplayer, AHBConfig *config)
uint32 orangeIcount = config->GetPercents(AHB_ORANGE_I);
uint32 yellowIcount = config->GetPercents(AHB_YELLOW_I);
uint32 total = greyTGcount + whiteTGcount + greenTGcount + blueTGcount
- + purpleTGcount + orangeTGcount + yellowTGcount
- + whiteIcount + greenIcount + blueIcount + purpleIcount
- + orangeIcount + yellowIcount;
+ + purpleTGcount + orangeTGcount + yellowTGcount
+ + whiteIcount + greenIcount + blueIcount + purpleIcount
+ + orangeIcount + yellowIcount;
uint32 greyTGoods = 0;
uint32 whiteTGoods = 0;
@@ -133,74 +150,71 @@ static void addNewAuctions(Player *AHBplayer, AHBConfig *config)
uint32 orangeItems = 0;
uint32 yellowItems = 0;
- for (AuctionHouseObject::AuctionEntryMap::iterator itr = auctionHouse->GetAuctionsBegin();itr != auctionHouse->GetAuctionsEnd();++itr)
+ for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = auctionHouse->GetAuctionsBegin();itr != auctionHouse->GetAuctionsEnd();++itr)
{
AuctionEntry *Aentry = itr->second;
Item *item = auctionmgr.GetAItem(Aentry->item_guidlow);
- if( item )
+ if (item)
{
ItemPrototype const *prototype = item->GetProto();
- if( prototype )
+ if (prototype)
{
switch (prototype->Quality)
{
- case 0:
+ case 0:
if (prototype->Class == ITEM_CLASS_TRADE_GOODS)
- ++greyTGoods;
+ ++greyTGoods;
else
- ++greyItems;
+ ++greyItems;
break;
-
- case 1:
+ case 1:
if (prototype->Class == ITEM_CLASS_TRADE_GOODS)
- ++whiteTGoods;
+ ++whiteTGoods;
else
- ++whiteItems;
+ ++whiteItems;
break;
-
- case 2:
+ case 2:
if (prototype->Class == ITEM_CLASS_TRADE_GOODS)
- ++greenTGoods;
+ ++greenTGoods;
else
- ++greenItems;
+ ++greenItems;
break;
-
- case 3:
+ case 3:
if (prototype->Class == ITEM_CLASS_TRADE_GOODS)
- ++blueTGoods;
+ ++blueTGoods;
else
- ++blueItems;
+ ++blueItems;
break;
-
- case 4:
+ case 4:
if (prototype->Class == ITEM_CLASS_TRADE_GOODS)
- ++purpleTGoods;
+ ++purpleTGoods;
else
- ++purpleItems;
+ ++purpleItems;
break;
-
- case 5:
+ case 5:
if (prototype->Class == ITEM_CLASS_TRADE_GOODS)
- ++orangeTGoods;
+ ++orangeTGoods;
else
- ++orangeItems;
+ ++orangeItems;
break;
-
- case 6:
+ case 6:
if (prototype->Class == ITEM_CLASS_TRADE_GOODS)
- ++yellowTGoods;
+ ++yellowTGoods;
else
- ++yellowItems;
+ ++yellowItems;
break;
}
}
}
}
+
// only insert a few at a time, so as not to peg the processor
for (uint32 cnt = 1;cnt <= items;cnt++)
{
uint32 itemID = 0;
- while (itemID == 0)
+ uint32 loopBreaker = 0;
+ uint32 itemColor = 99;
+ while (itemID == 0 && loopBreaker < 50)
{
uint32 choice = urand(0, 13);
switch (choice)
@@ -208,269 +222,224 @@ static void addNewAuctions(Player *AHBplayer, AHBConfig *config)
case 0:
{
if ((greyItemsBin.size() > 0) && (greyItems < greyIcount))
- {
- itemID = greyItemsBin[urand(0, greyItemsBin.size() - 1)];
- ++greyItems;
- break;
- }
+ itemID = greyItemsBin[urand(0, greyItemsBin.size() - 1)];
+ else continue;
+ break;
}
case 1:
{
if ((whiteItemsBin.size() > 0) && (whiteItems < whiteIcount))
- {
- itemID = whiteItemsBin[urand(0, whiteItemsBin.size() - 1)];
- ++whiteItems;
- break;
- }
+ itemID = whiteItemsBin[urand(0, whiteItemsBin.size() - 1)];
+ else continue;
+ break;
}
case 2:
{
if ((greenItemsBin.size() > 0) && (greenItems < greenIcount))
- {
- itemID = greenItemsBin[urand(0, greenItemsBin.size() - 1)];
- ++greenItems;
- break;
- }
+ itemID = greenItemsBin[urand(0, greenItemsBin.size() - 1)];
+ else continue;
+ break;
}
case 3:
{
if ((blueItemsBin.size() > 0) && (blueItems < blueIcount))
- {
- itemID = blueItemsBin[urand(0, blueItemsBin.size() - 1)];
- ++blueItems;
- break;
- }
+ itemID = blueItemsBin[urand(0, blueItemsBin.size() - 1)];
+ else continue;
+ break;
}
case 4:
{
if ((purpleItemsBin.size() > 0) && (purpleItems < purpleIcount))
- {
itemID = purpleItemsBin[urand(0, purpleItemsBin.size() - 1)];
- ++purpleItems;
- break;
- }
+ else continue;
+ break;
}
case 5:
{
if ((orangeItemsBin.size() > 0) && (orangeItems < orangeIcount))
- {
itemID = orangeItemsBin[urand(0, orangeItemsBin.size() - 1)];
- ++orangeItems;
- break;
- }
+ else continue;
+ break;
}
case 6:
{
if ((yellowItemsBin.size() > 0) && (yellowItems < yellowIcount))
- {
itemID = yellowItemsBin[urand(0, yellowItemsBin.size() - 1)];
- ++yellowItems;
- break;
- }
+ else continue;
+ break;
}
case 7:
{
if ((greyTradeGoodsBin.size() > 0) && (greyTGoods < greyTGcount))
- {
- itemID = whiteTradeGoodsBin[urand(0, whiteTradeGoodsBin.size() - 1)];
- ++greyTGoods;
- break;
- }
+ itemID = greyTradeGoodsBin[urand(0, greyTradeGoodsBin.size() - 1)];
+ else continue;
+ break;
}
case 8:
{
if ((whiteTradeGoodsBin.size() > 0) && (whiteTGoods < whiteTGcount))
- {
- itemID = whiteTradeGoodsBin[urand(0, whiteTradeGoodsBin.size() - 1)];
- ++whiteTGoods;
- break;
- }
+ itemID = whiteTradeGoodsBin[urand(0, whiteTradeGoodsBin.size() - 1)];
+ else continue;
+ break;
}
case 9:
{
if ((greenTradeGoodsBin.size() > 0) && (greenTGoods < greenTGcount))
- {
- itemID = greenTradeGoodsBin[urand(0, greenTradeGoodsBin.size() - 1)];
- ++greenTGoods;
- break;
- }
+ itemID = greenTradeGoodsBin[urand(0, greenTradeGoodsBin.size() - 1)];
+ else continue;
+ break;
}
case 10:
{
if ((blueTradeGoodsBin.size() > 0) && (blueTGoods < blueTGcount))
- {
- itemID = blueTradeGoodsBin[urand(0, blueTradeGoodsBin.size() - 1)];
- ++blueTGoods;
- break;
- }
+ itemID = blueTradeGoodsBin[urand(0, blueTradeGoodsBin.size() - 1)];
+ else continue;
+ break;
}
case 11:
{
if ((purpleTradeGoodsBin.size() > 0) && (purpleTGoods < purpleTGcount))
- {
- itemID = purpleTradeGoodsBin[urand(0, purpleTradeGoodsBin.size() - 1)];
- ++purpleTGoods;
- break;
- }
+ itemID = purpleTradeGoodsBin[urand(0, purpleTradeGoodsBin.size() - 1)];
+ else continue;
+ break;
}
case 12:
{
if ((orangeTradeGoodsBin.size() > 0) && (orangeTGoods < orangeTGcount))
- {
- itemID = orangeTradeGoodsBin[urand(0, orangeTradeGoodsBin.size() - 1)];
- ++orangeTGoods;
- break;
- }
+ itemID = orangeTradeGoodsBin[urand(0, orangeTradeGoodsBin.size() - 1)];
+ else continue;
+ break;
}
case 13:
{
if ((yellowTradeGoodsBin.size() > 0) && (yellowTGoods < yellowTGcount))
- {
- itemID = yellowTradeGoodsBin[urand(0, yellowTradeGoodsBin.size() - 1)];
- ++yellowTGoods;
- break;
- }
+ itemID = yellowTradeGoodsBin[urand(0, yellowTradeGoodsBin.size() - 1)];
+ else continue;
+ break;
}
default:
{
+ if (debug_Out) sLog.outError("AuctionHouseBot: itemID Switch - Default Reached");
break;
}
+ ++loopBreaker;
}
- }
-
- ItemPrototype const* prototype = objmgr.GetItemPrototype(itemID);
- if (prototype == NULL)
- {
- sLog.outString("AuctionHouseBot: Huh?!?! prototype == NULL");
- continue;
- }
-
- Item* item = Item::CreateItem(itemID, 1, AHBplayer);
- item->AddToUpdateQueueOf(AHBplayer);
- if (item == NULL)
- {
- sLog.outString("AuctionHouseBot: Item::CreateItem() returned NULL");
- break;
- }
-
- uint32 randomPropertyId = Item::GenerateItemRandomPropertyId(itemID);
- if (randomPropertyId != 0)
- item->SetItemRandomProperties(randomPropertyId);
-
- uint32 buyoutPrice;
- uint32 bidPrice = 0;
- uint32 stackCount = urand(1, item->GetMaxStackCount());
-
- switch (SellMethod)
- {
- case 0:
- buyoutPrice = prototype->SellPrice * item->GetCount();
- break;
- case 1:
- buyoutPrice = prototype->BuyPrice * item->GetCount();
- break;
- default:
- buyoutPrice = 0;
- break;
- }
-
- switch (prototype->Quality)
- {
- case 0:
- if (config->GetMaxStack(AHB_GREY) != 0)
+ if (itemID == 0)
{
- stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_GREY)));
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item::CreateItem() - ItemID is 0");
+ continue;
}
- buyoutPrice *= urand(config->GetMinPrice(AHB_GREY), config->GetMaxPrice(AHB_GREY)) * stackCount;
- buyoutPrice /= 100;
- bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_GREY), config->GetMaxBidPrice(AHB_GREY));
- bidPrice /= 100;
- break;
- case 1:
- if (config->GetMaxStack(AHB_WHITE) != 0)
+ ItemPrototype const* prototype = objmgr.GetItemPrototype(itemID);
+ if (prototype == NULL)
{
- stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_WHITE)));
+ if (debug_Out) sLog.outError("AuctionHouseBot: Huh?!?! prototype == NULL");
+ continue;
}
- buyoutPrice *= urand(config->GetMinPrice(AHB_WHITE), config->GetMaxPrice(AHB_WHITE)) * stackCount;
- buyoutPrice /= 100;
- bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_WHITE), config->GetMaxBidPrice(AHB_WHITE));
- bidPrice /= 100;
- break;
- case 2:
- if (config->GetMaxStack(AHB_GREEN) != 0)
+ Item* item = Item::CreateItem(itemID, 1, AHBplayer);
+ item->AddToUpdateQueueOf(AHBplayer);
+ if (item == NULL)
{
- stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_GREEN)));
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item::CreateItem() returned NULL");
+ break;
}
- buyoutPrice *= urand(config->GetMinPrice(AHB_GREEN), config->GetMaxPrice(AHB_GREEN)) * stackCount;
- buyoutPrice /= 100;
- bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_GREEN), config->GetMaxBidPrice(AHB_GREEN));
- bidPrice /= 100;
- break;
- case 3:
- if (config->GetMaxStack(AHB_BLUE) != 0)
- {
- stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_BLUE)));
- }
- buyoutPrice *= urand(config->GetMinPrice(AHB_BLUE), config->GetMaxPrice(AHB_BLUE)) * stackCount;
- buyoutPrice /= 100;
- bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_BLUE), config->GetMaxBidPrice(AHB_BLUE));
- bidPrice /= 100;
- break;
+ uint32 randomPropertyId = Item::GenerateItemRandomPropertyId(itemID);
+ if (randomPropertyId != 0)
+ item->SetItemRandomProperties(randomPropertyId);
- case 4:
- if (config->GetMaxStack(AHB_PURPLE) != 0)
- {
- stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_PURPLE)));
- }
- buyoutPrice *= urand(config->GetMinPrice(AHB_PURPLE), config->GetMaxPrice(AHB_PURPLE)) * stackCount;
- buyoutPrice /= 100;
- bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_PURPLE), config->GetMaxBidPrice(AHB_PURPLE));
- bidPrice /= 100;
- break;
- case 5:
- if (config->GetMaxStack(AHB_ORANGE) != 0)
+ uint64 buyoutPrice = 0;
+ uint64 bidPrice = 0;
+ uint32 stackCount = 1;
+
+ switch (SellMethod)
{
- stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_ORANGE)));
+ case 0:
+ buyoutPrice = prototype->SellPrice;
+ break;
+ case 1:
+ buyoutPrice = prototype->BuyPrice;
+ break;
}
- buyoutPrice *= urand(config->GetMinPrice(AHB_ORANGE), config->GetMaxPrice(AHB_ORANGE)) * stackCount;
- buyoutPrice /= 100;
- bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_ORANGE), config->GetMaxBidPrice(AHB_ORANGE));
- bidPrice /= 100;
- break;
- case 6:
- if (config->GetMaxStack(AHB_YELLOW) != 0)
+
+ switch (prototype->Quality)
{
- stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_YELLOW)));
+ case AHB_GREY:
+ if (config->GetMaxStack(AHB_GREY) > 1 && item->GetMaxStackCount() > 1)
+ stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_GREY)));
+ else
+ stackCount = 1;
+ buyoutPrice *= urand(config->GetMinPrice(AHB_GREY), config->GetMaxPrice(AHB_GREY));
+ buyoutPrice /= 100;
+ bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_GREY), config->GetMaxBidPrice(AHB_GREY));
+ bidPrice /= 100;
+ break;
+ case AHB_WHITE:
+ if (config->GetMaxStack(AHB_WHITE) > 1 && item->GetMaxStackCount() > 1)
+ stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_WHITE)));
+ else
+ stackCount = 1;
+ buyoutPrice *= urand(config->GetMinPrice(AHB_WHITE), config->GetMaxPrice(AHB_WHITE));
+ buyoutPrice /= 100;
+ bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_WHITE), config->GetMaxBidPrice(AHB_WHITE));
+ bidPrice /= 100;
+ break;
+ case AHB_GREEN:
+ if (config->GetMaxStack(AHB_GREEN) > 1 && item->GetMaxStackCount() > 1)
+ stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_GREEN)));
+ else
+ stackCount = 1;
+ buyoutPrice *= urand(config->GetMinPrice(AHB_GREEN), config->GetMaxPrice(AHB_GREEN));
+ buyoutPrice /= 100;
+ bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_GREEN), config->GetMaxBidPrice(AHB_GREEN));
+ bidPrice /= 100;
+ break;
+ case AHB_BLUE:
+ if (config->GetMaxStack(AHB_BLUE) > 1 && item->GetMaxStackCount() > 1)
+ stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_BLUE)));
+ else
+ stackCount = 1;
+ buyoutPrice *= urand(config->GetMinPrice(AHB_BLUE), config->GetMaxPrice(AHB_BLUE));
+ buyoutPrice /= 100;
+ bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_BLUE), config->GetMaxBidPrice(AHB_BLUE));
+ bidPrice /= 100;
+ break;
+ case AHB_PURPLE:
+ if (config->GetMaxStack(AHB_PURPLE) > 1 && item->GetMaxStackCount() > 1)
+ stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_PURPLE)));
+ else
+ stackCount = 1;
+ buyoutPrice *= urand(config->GetMinPrice(AHB_PURPLE), config->GetMaxPrice(AHB_PURPLE));
+ buyoutPrice /= 100;
+ bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_PURPLE), config->GetMaxBidPrice(AHB_PURPLE));
+ bidPrice /= 100;
+ break;
+ case AHB_ORANGE:
+ if (config->GetMaxStack(AHB_ORANGE) > 1 && item->GetMaxStackCount() > 1)
+ stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_ORANGE)));
+ else
+ stackCount = 1;
+ buyoutPrice *= urand(config->GetMinPrice(AHB_ORANGE), config->GetMaxPrice(AHB_ORANGE));
+ buyoutPrice /= 100;
+ bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_ORANGE), config->GetMaxBidPrice(AHB_ORANGE));
+ bidPrice /= 100;
+ break;
+ case AHB_YELLOW:
+ if (config->GetMaxStack(AHB_YELLOW) > 1 && item->GetMaxStackCount() > 1)
+ stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_YELLOW)));
+ else
+ stackCount = 1;
+ buyoutPrice *= urand(config->GetMinPrice(AHB_YELLOW), config->GetMaxPrice(AHB_YELLOW));
+ buyoutPrice /= 100;
+ bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_YELLOW), config->GetMaxBidPrice(AHB_YELLOW));
+ bidPrice /= 100;
+ break;
}
- buyoutPrice *= urand(config->GetMinPrice(AHB_YELLOW), config->GetMaxPrice(AHB_YELLOW)) * stackCount;
- buyoutPrice /= 100;
- bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_YELLOW), config->GetMaxBidPrice(AHB_YELLOW));
- bidPrice /= 100;
- break;
- }
-
- if(auctionmgr.GetAItem(GUID_LOPART(item->GetGUID())))
- {
- sLog.outError("Item %u not found", item->GetEntry());
- break;
- }
- if(!item->CanBeTraded())
- {
- sLog.outError("Item %u can't be traded", item->GetEntry());
- break;
- }
- if (item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_CONJURED) || item->GetUInt32Value(ITEM_FIELD_DURATION))
- {
- sLog.outError("Item %u is conjured or has a duration", item->GetEntry());
- break;
- }
- uint32 etime = urand(1,3);
- switch(etime)
- {
+ uint32 etime = urand(1,3);
+ switch(etime)
+ {
case 1:
etime = 43200;
break;
@@ -483,91 +452,144 @@ static void addNewAuctions(Player *AHBplayer, AHBConfig *config)
default:
etime = 86400;
break;
+ }
+ item->SetCount(stackCount);
+
+ uint32 dep = auctionmgr.GetAuctionDeposit(ahEntry, etime, item);
+
+ AuctionEntry* auctionEntry = new AuctionEntry;
+ auctionEntry->Id = objmgr.GenerateAuctionID();
+ auctionEntry->auctioneer = AuctioneerGUID;
+ auctionEntry->item_guidlow = item->GetGUIDLow();
+ auctionEntry->item_template = item->GetEntry();
+ auctionEntry->owner = AHBplayer->GetGUIDLow();
+ auctionEntry->startbid = bidPrice * stackCount;
+ auctionEntry->buyout = buyoutPrice * stackCount;
+ auctionEntry->bidder = 0;
+ auctionEntry->bid = 0;
+ auctionEntry->deposit = dep;
+ auctionEntry->expire_time = (time_t) etime + time(NULL);
+ auctionEntry->auctionHouseEntry = ahEntry;
+ item->SaveToDB();
+ item->RemoveFromUpdateQueueOf(AHBplayer);
+ auctionmgr.AddAItem(item);
+ auctionHouse->AddAuction(auctionEntry);
+ auctionEntry->SaveToDB();
+
+ switch(itemColor)
+ {
+ case 0:
+ ++greyItems;
+ break;
+ case 1:
+ ++whiteItems;
+ break;
+ case 2:
+ ++greenItems;
+ break;
+ case 3:
+ ++blueItems;
+ break;
+ case 4:
+ ++purpleItems;
+ break;
+ case 5:
+ ++orangeItems;
+ break;
+ case 6:
+ ++yellowItems;
+ break;
+ case 7:
+ ++greyTGoods;
+ break;
+ case 8:
+ ++whiteTGoods;
+ break;
+ case 9:
+ ++greenTGoods;
+ break;
+ case 10:
+ ++blueTGoods;
+ break;
+ case 11:
+ ++purpleTGoods;
+ break;
+ case 12:
+ ++orangeTGoods;
+ break;
+ case 13:
+ ++yellowTGoods;
+ break;
+ default:
+ break;
+ }
}
- uint32 dep = auctionmgr.GetAuctionDeposit( ahEntry, etime, item );
-
- item->SetCount(stackCount);
-
- AuctionEntry* auctionEntry = new AuctionEntry;
- auctionEntry->Id = objmgr.GenerateAuctionID();
- auctionEntry->auctioneer = AuctioneerGUID;
- auctionEntry->item_guidlow = item->GetGUIDLow();
- auctionEntry->item_template = item->GetEntry();
- auctionEntry->owner = AHBplayer->GetGUIDLow();
- auctionEntry->startbid = bidPrice;
- auctionEntry->buyout = buyoutPrice;
- auctionEntry->bidder = 0;
- auctionEntry->bid = 0;
- auctionEntry->deposit = dep;
- auctionEntry->expire_time = (time_t) etime + time(NULL);
- auctionEntry->auctionHouseEntry = ahEntry;
- item->SaveToDB();
- item->RemoveFromUpdateQueueOf(AHBplayer);
- auctionmgr.AddAItem(item);
- auctionHouse->AddAuction(auctionEntry);
- auctionEntry->SaveToDB();
}
}
-
-static void addNewAuctionBuyerBotBid(Player *AHBplayer, AHBConfig *config, WorldSession *session)
+void AuctionHouseBot::addNewAuctionBuyerBotBid(Player *AHBplayer, AHBConfig *config, WorldSession *session)
{
if (!AHBBuyer)
return;
// Fetches content of selected AH
AuctionHouseObject* auctionHouse = auctionmgr.GetAuctionsMap(config->GetAHFID());
- AuctionHouseObject::AuctionEntryMap::iterator itr;
-
- itr = auctionHouse->GetAuctionsBegin();
vector<uint32> possibleBids;
- while (itr != auctionHouse->GetAuctionsEnd())
+ for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = auctionHouse->GetAuctionsBegin();itr != auctionHouse->GetAuctionsEnd();++itr)
{
- AuctionHouseObject::AuctionEntryMap::iterator tmp = itr;
- ++itr;
// Check if the auction is ours
// if it is, we skip this iteration.
- if(tmp->second->owner == AHBplayerGUID)
+ if (itr->second->owner == AHBplayerGUID)
{
continue;
}
// Check that we haven't bidded in this auction already.
- if(tmp->second->bidder != AHBplayerGUID)
+ if (itr->second->bidder != AHBplayerGUID)
{
- uint32 tmpdata = tmp->second->Id;
+ uint32 tmpdata = itr->second->Id;
possibleBids.push_back(tmpdata);
}
}
- uint32 bids = config->GetBidsPerInterval();
- for (uint32 count = 0; count < bids; ++count)
+ for (uint32 count = 1;count < config->GetBidsPerInterval();++count)
{
// Do we have anything to bid? If not, stop here.
- if(possibleBids.empty())
- return;
+ if (possibleBids.empty())
+ {
+ count = config->GetBidsPerInterval();
+ continue;
+ }
// Choose random auction from possible auctions
uint32 vectorPos = urand(0, possibleBids.size() - 1);
vector<uint32>::iterator iter = possibleBids.begin();
advance(iter, vectorPos);
+
// from auctionhousehandler.cpp, creates auction pointer & player pointer
AuctionEntry* auction = auctionHouse->GetAuction(*iter);
- // Erase the auction from the vector to prevent bidding on item in next itteration.
+
+ // Erase the auction from the vector to prevent bidding on item in next iteration.
possibleBids.erase(iter);
+ if (!auction)
+ {
+ if (debug_Out) sLog.outError("Item doesn't exist, perhaps bought already?");
+ continue;
+ }
+
// get exact item information
Item *pItem = auctionmgr.GetAItem(auction->item_guidlow);
if (!pItem)
{
- sLog.outError("Item doesn't exists, perhaps bought already?");
- return;
+ if (debug_Out) sLog.outError("Item doesn't exist, perhaps bought already?");
+ continue;
}
// get item prototype
ItemPrototype const* prototype = objmgr.GetItemPrototype(auction->item_template);
// check which price we have to use, startbid or if it is bidded already
- if(debug_Out)
+ if (debug_Out)
{
sLog.outError("Auction Number: %u", auction->Id);
sLog.outError("Item Template: %u", auction->item_template);
@@ -577,17 +599,15 @@ static void addNewAuctionBuyerBotBid(Player *AHBplayer, AHBConfig *config, World
}
uint32 currentprice;
- if(auction->bid)
+ if (auction->bid)
{
currentprice = auction->bid;
- if(debug_Out)
- {sLog.outError("Current Price: %u", auction->bid);}
+ if (debug_Out) sLog.outError("Current Price: %u", auction->bid);
}
else
{
currentprice = auction->startbid;
- if(debug_Out)
- {sLog.outError("Current Price: %u", auction->startbid);}
+ if (debug_Out) sLog.outError("Current Price: %u", auction->startbid);
}
// Prepare portion from maximum bid
@@ -595,7 +615,7 @@ static void addNewAuctionBuyerBotBid(Player *AHBplayer, AHBConfig *config, World
double tmprate = static_cast<double>(tmprate2);
double bidrate = tmprate / 100;
long double bidMax = 0;
- if(debug_Out)
+ if (debug_Out)
{
sLog.outError("tmprate: %f", tmprate);
sLog.outError("bidrate: %f", bidrate);
@@ -604,140 +624,135 @@ static void addNewAuctionBuyerBotBid(Player *AHBplayer, AHBConfig *config, World
// check that bid has acceptable value and take bid based on vendorprice, stacksize and quality
switch (BuyMethod)
{
- case 0:
+ case 0:
{
switch (prototype->Quality)
{
- case 0:
- if(currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREY))
- bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREY);
- break;
- case 1:
- if(currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_WHITE))
- bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_WHITE);
- break;
- case 2:
- if(currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREEN))
- bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREEN);
- break;
- case 3:
- if(currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_BLUE))
- bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_BLUE);
- break;
- case 4:
- if(currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_PURPLE))
- bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_PURPLE);
- case 5:
- if(currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_ORANGE))
- bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_ORANGE);
- case 6:
- if(currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_YELLOW))
- bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_YELLOW);
- break;
- default:
- // quality is something it shouldn't be, let's get out of here
- if(debug_Out)
- sLog.outError("bidMax(fail): %f", bidMax);
- return;
+ case 0:
+ if (currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREY))
+ bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREY);
+ break;
+ case 1:
+ if (currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_WHITE))
+ bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_WHITE);
+ break;
+ case 2:
+ if (currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREEN))
+ bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREEN);
+ break;
+ case 3:
+ if (currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_BLUE))
+ bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_BLUE);
+ break;
+ case 4:
+ if (currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_PURPLE))
+ bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_PURPLE);
+ case 5:
+ if (currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_ORANGE))
+ bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_ORANGE);
+ case 6:
+ if (currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_YELLOW))
+ bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_YELLOW);
+ break;
+ default:
+ // quality is something it shouldn't be, let's get out of here
+ if (debug_Out) sLog.outError("bidMax(fail): %f", bidMax);
+ continue;
+ break;
}
break;
}
- case 1:
+ case 1:
{
switch (prototype->Quality)
{
- case 0:
- if(currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREY))
- bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREY);
- break;
- case 1:
- if(currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_WHITE))
- bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_WHITE);
- break;
- case 2:
- if(currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREEN))
- bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREEN);
- break;
- case 3:
- if(currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_BLUE))
- bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_BLUE);
- break;
- case 4:
- if(currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_PURPLE))
- bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_PURPLE);
- case 5:
- if(currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_ORANGE))
- bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_ORANGE);
- case 6:
- if(currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_YELLOW))
- bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_YELLOW);
- break;
- default:
- // quality is something it shouldn't be, let's get out of here
- if(debug_Out)
- sLog.outError("bidMax(fail): %f", bidMax);
- return;
+ case 0:
+ if (currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREY))
+ bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREY);
+ break;
+ case 1:
+ if (currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_WHITE))
+ bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_WHITE);
+ break;
+ case 2:
+ if (currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREEN))
+ bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREEN);
+ break;
+ case 3:
+ if (currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_BLUE))
+ bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_BLUE);
+ break;
+ case 4:
+ if (currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_PURPLE))
+ bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_PURPLE);
+ case 5:
+ if (currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_ORANGE))
+ bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_ORANGE);
+ case 6:
+ if (currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_YELLOW))
+ bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_YELLOW);
+ break;
+ default:
+ // quality is something it shouldn't be, let's get out of here
+ if (debug_Out) sLog.outError("bidMax(fail): %f", bidMax);
+ continue;
+ break;
}
break;
}
- default:
- bidMax = 0;
- break;
}
- if(debug_Out)
- sLog.outError("bidMax(succeed): %f", bidMax);
+ if (debug_Out) sLog.outError("bidMax(succeed): %f", bidMax);
// check some special items, and do recalculating to their prices
switch (prototype->Class)
{
// ammo
- case 6:
- bidMax = 0;
- break;
- default:
- break;
+ case 6:
+ bidMax = 0;
+ break;
+ default:
+ break;
}
- if(bidMax == 0)
+ if (bidMax == 0)
{
// quality check failed to get bidmax, let's get out of here
- return;
+ continue;
}
// Calculate our bid
- long double bidvalue = currentprice + ( (bidMax - currentprice) * bidrate);
+ long double bidvalue = currentprice + ((bidMax - currentprice) * bidrate);
// Convert to uint32
uint32 bidprice = static_cast<uint32>(bidvalue);
- if(debug_Out)
+ if (debug_Out)
{
sLog.outError("bidprice: %u", bidprice);
sLog.outError("bidvalue: %f", bidvalue);
}
// Check our bid is high enough to be valid. If not, correct it to minimum.
- if((currentprice + auction->GetAuctionOutBid()) > bidprice)
+ if ((currentprice + auction->GetAuctionOutBid()) > bidprice)
{
bidprice = currentprice + auction->GetAuctionOutBid();
- if(debug_Out)
- sLog.outError("bidprice(>): %u", bidprice);
+ if (debug_Out) sLog.outError("bidprice(>): %u", bidprice);
}
- // Check wether we do normal bid, or buyout
+ // Check whether we do normal bid, or buyout
if ((bidprice < auction->buyout) || (auction->buyout == 0))
{
if (auction->bidder > 0)
{
- if ( auction->bidder == AHBplayer->GetGUIDLow() )
+ if (auction->bidder == AHBplayer->GetGUIDLow())
{
- //pl->ModifyMoney( -int32(price - auction->bid));
+ //pl->ModifyMoney(-int32(price - auction->bid));
}
else
{
// mail to last bidder and return money
- session->SendAuctionOutbiddedMail( auction , bidprice );
- //pl->ModifyMoney( -int32(price) );
+ session->SendAuctionOutbiddedMail(auction , bidprice);
+ //pl->ModifyMoney(-int32(price));
}
}
@@ -750,24 +765,24 @@ static void addNewAuctionBuyerBotBid(Player *AHBplayer, AHBConfig *config, World
else
{
//buyout
- if (AHBplayer->GetGUIDLow() == auction->bidder )
+ if (AHBplayer->GetGUIDLow() == auction->bidder)
{
//pl->ModifyMoney(-int32(auction->buyout - auction->bid));
}
else
{
//pl->ModifyMoney(-int32(auction->buyout));
- if ( auction->bidder )
+ if (auction->bidder)
{
- session->SendAuctionOutbiddedMail( auction, auction->buyout );
+ session->SendAuctionOutbiddedMail(auction, auction->buyout);
}
}
auction->bidder = AHBplayer->GetGUIDLow();
auction->bid = auction->buyout;
// Send mails to buyer & seller
- auctionmgr.SendAuctionSuccessfulMail( auction );
- auctionmgr.SendAuctionWonMail( auction );
+ auctionmgr.SendAuctionSuccessfulMail(auction);
+ auctionmgr.SendAuctionWonMail(auction);
// Remove item from auctionhouse
auctionmgr.RemoveAItem(auction->item_guidlow);
@@ -779,21 +794,20 @@ static void addNewAuctionBuyerBotBid(Player *AHBplayer, AHBConfig *config, World
}
}
}
-///////////////////////////////////////////////////////////////////////////////
-//
-///////////////////////////////////////////////////////////////////////////////
-void AuctionHouseBot()
+
+void AuctionHouseBot::Update()
{
time_t _newrun = time(NULL);
if ((!AHBSeller) && (!AHBBuyer))
- return;
+ return;
WorldSession _session(AHBplayerAccount, NULL, SEC_PLAYER, true, 0, LOCALE_enUS);
Player _AHBplayer(&_session);
_AHBplayer.MinimalLoadFromDB(NULL, AHBplayerGUID);
ObjectAccessor::Instance().AddObject(&_AHBplayer);
- if(!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
+ // Add New Bids
+ if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
{
addNewAuctions(&_AHBplayer, &AllianceConfig);
if (((_newrun - _lastrun_a) > (AllianceConfig.GetBiddingInterval() * 60)) && (AllianceConfig.GetBidsPerInterval() > 0))
@@ -801,6 +815,7 @@ void AuctionHouseBot()
addNewAuctionBuyerBotBid(&_AHBplayer, &AllianceConfig, &_session);
_lastrun_a = _newrun;
}
+
addNewAuctions(&_AHBplayer, &HordeConfig);
if (((_newrun - _lastrun_h) > (HordeConfig.GetBiddingInterval() *60)) && (HordeConfig.GetBidsPerInterval() > 0))
{
@@ -808,6 +823,7 @@ void AuctionHouseBot()
_lastrun_h = _newrun;
}
}
+
addNewAuctions(&_AHBplayer, &NeutralConfig);
if (((_newrun - _lastrun_n) > (NeutralConfig.GetBiddingInterval() * 60)) && (NeutralConfig.GetBidsPerInterval() > 0))
{
@@ -816,75 +832,128 @@ void AuctionHouseBot()
}
ObjectAccessor::Instance().RemoveObject(&_AHBplayer);
}
-///////////////////////////////////////////////////////////////////////////////
-//
-///////////////////////////////////////////////////////////////////////////////
-void AuctionHouseBotInit()
+
+void AuctionHouseBot::Initialize()
{
+ debug_Out = sConfig.GetBoolDefault("AuctionHouseBot.DEBUG", false);
+
AHBSeller = sConfig.GetBoolDefault("AuctionHouseBot.EnableSeller", false);
AHBBuyer = sConfig.GetBoolDefault("AuctionHouseBot.EnableBuyer", false);
+ SellMethod = sConfig.GetBoolDefault("AuctionHouseBot.UseBuyPriceForSeller", false);
+ BuyMethod = sConfig.GetBoolDefault("AuctionHouseBot.UseBuyPriceForBuyer", false);
+
+ AHBplayerAccount = sConfig.GetIntDefault("AuctionHouseBot.Account", 0);
+ AHBplayerGUID = sConfig.GetIntDefault("AuctionHouseBot.GUID", 0);
+ ItemsPerCycle = sConfig.GetIntDefault("AuctionHouseBot.ItemsPerCycle", 200);
+
+
+ //Begin Filters
+
+ Vendor_Items = sConfig.GetBoolDefault("AuctionHouseBot.VendorItems", false);
+ Loot_Items = sConfig.GetBoolDefault("AuctionHouseBot.LootItems", true);
+ Other_Items = sConfig.GetBoolDefault("AuctionHouseBot.OtherItems", false);
+
No_Bind = sConfig.GetBoolDefault("AuctionHouseBot.No_Bind", true);
Bind_When_Picked_Up = sConfig.GetBoolDefault("AuctionHouseBot.Bind_When_Picked_Up", false);
Bind_When_Equipped = sConfig.GetBoolDefault("AuctionHouseBot.Bind_When_Equipped", true);
Bind_When_Use = sConfig.GetBoolDefault("AuctionHouseBot.Bind_When_Use", true);
Bind_Quest_Item = sConfig.GetBoolDefault("AuctionHouseBot.Bind_Quest_Item", false);
- if(!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
+ DisableBeta_PTR_Unused = sConfig.GetBoolDefault("AuctionHouseBot.DisableBeta_PTR_Unused", false);
+ DisablePermEnchant = sConfig.GetBoolDefault("AuctionHouseBot.DisablePermEnchant", false);
+ DisableConjured = sConfig.GetBoolDefault("AuctionHouseBot.DisableConjured", false);
+ DisableGems = sConfig.GetBoolDefault("AuctionHouseBot.DisableGems", false);
+ DisableMoney = sConfig.GetBoolDefault("AuctionHouseBot.DisableMoney", false);
+ DisableMoneyLoot = sConfig.GetBoolDefault("AuctionHouseBot.DisableMoneyLoot", false);
+ DisableLootable = sConfig.GetBoolDefault("AuctionHouseBot.DisableLootable", false);
+ DisableKeys = sConfig.GetBoolDefault("AuctionHouseBot.DisableKeys", false);
+ DisableDuration = sConfig.GetBoolDefault("AuctionHouseBot.DisableDuration", false);
+ DisableBOP_Or_Quest_NoReqLevel = sConfig.GetBoolDefault("AuctionHouseBot.DisableBOP_Or_Quest_NoReqLevel", false);
+
+ DisableWarriorItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableWarriorItems", false);
+ DisablePaladinItems = sConfig.GetBoolDefault("AuctionHouseBot.DisablePaladinItems", false);
+ DisableHunterItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableHunterItems", false);
+ DisableRogueItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableRogueItems", false);
+ DisablePriestItems = sConfig.GetBoolDefault("AuctionHouseBot.DisablePriestItems", false);
+ DisableDKItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableDKItems", false);
+ DisableShamanItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableShamanItems", false);
+ DisableMageItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableMageItems", false);
+ DisableWarlockItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableWarlockItems", false);
+ DisableUnusedClassItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableUnusedClassItems", false);
+ DisableDruidItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableDruidItems", false);
+
+ DisableItemsBelowLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsBelowLevel", 0);
+ DisableItemsAboveLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsAboveLevel", 0);
+ DisableTGsBelowLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsBelowLevel", 0);
+ DisableTGsAboveLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsAboveLevel", 0);
+ DisableItemsBelowGUID = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsBelowGUID", 0);
+ DisableItemsAboveGUID = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsAboveGUID", 0);
+ DisableTGsBelowGUID = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsBelowGUID", 0);
+ DisableTGsAboveGUID = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsAboveGUID", 0);
+ DisableItemsBelowReqLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsBelowReqLevel", 0);
+ DisableItemsAboveReqLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsAboveReqLevel", 0);
+ DisableTGsBelowReqLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsBelowReqLevel", 0);
+ DisableTGsAboveReqLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsAboveReqLevel", 0);
+ DisableItemsBelowReqSkillRank = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsBelowReqSkillRank", 0);
+ DisableItemsAboveReqSkillRank = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsAboveReqSkillRank", 0);
+ DisableTGsBelowReqSkillRank = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsBelowReqSkillRank", 0);
+ DisableTGsAboveReqSkillRank = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsAboveReqSkillRank", 0);
+
+ //End Filters
+
+ if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
{
- AuctionHouseBotLoadValues(&AllianceConfig);
- AuctionHouseBotLoadValues(&HordeConfig);
+ LoadValues(&AllianceConfig);
+ LoadValues(&HordeConfig);
}
- AuctionHouseBotLoadValues(&NeutralConfig);
+ LoadValues(&NeutralConfig);
if (AHBSeller)
{
- Vendor_Items = sConfig.GetBoolDefault("AuctionHouseBot.VendorItems", false);
- Loot_Items = sConfig.GetBoolDefault("AuctionHouseBot.LootItems", true);
- Other_Items = sConfig.GetBoolDefault("AuctionHouseBot.OtherItems", false);
-
QueryResult* results = (QueryResult*) NULL;
char npcQuery[] = "SELECT distinct `item` FROM `npc_vendor`";
results = WorldDatabase.PQuery(npcQuery);
if (results != NULL)
{
- do
- {
- Field* fields = results->Fetch();
- npcItems.push_back(fields[0].GetUInt32());
+ do
+ {
+ Field* fields = results->Fetch();
+ npcItems.push_back(fields[0].GetUInt32());
- } while (results->NextRow());
+ } while (results->NextRow());
- delete results;
+ delete results;
}
else
{
- sLog.outString("AuctionHouseBot: \"%s\" failed", npcQuery);
+ if (debug_Out) sLog.outString("AuctionHouseBot: \"%s\" failed", npcQuery);
}
char lootQuery[] = "SELECT `item` FROM `creature_loot_template` UNION "
- "SELECT `item` FROM `disenchant_loot_template` UNION "
- "SELECT `item` FROM `fishing_loot_template` UNION "
- "SELECT `item` FROM `gameobject_loot_template` UNION "
- "SELECT `item` FROM `item_loot_template` UNION "
- "SELECT `item` FROM `pickpocketing_loot_template` UNION "
- "SELECT `item` FROM `prospecting_loot_template` UNION "
- "SELECT `item` FROM `skinning_loot_template`";
+ "SELECT `item` FROM `disenchant_loot_template` UNION "
+ "SELECT `item` FROM `fishing_loot_template` UNION "
+ "SELECT `item` FROM `gameobject_loot_template` UNION "
+ "SELECT `item` FROM `item_loot_template` UNION "
+ "SELECT `item` FROM `milling_loot_template` UNION "
+ "SELECT `item` FROM `pickpocketing_loot_template` UNION "
+ "SELECT `item` FROM `prospecting_loot_template` UNION "
+ "SELECT `item` FROM `skinning_loot_template`";
results = WorldDatabase.PQuery(lootQuery);
if (results != NULL)
{
- do
- {
- Field* fields = results->Fetch();
- lootItems.push_back(fields[0].GetUInt32());
+ do
+ {
+ Field* fields = results->Fetch();
+ lootItems.push_back(fields[0].GetUInt32());
- } while (results->NextRow());
+ } while (results->NextRow());
- delete results;
+ delete results;
}
else
{
- sLog.outString("AuctionHouseBot: \"%s\" failed", lootQuery);
+ if (debug_Out) sLog.outString("AuctionHouseBot: \"%s\" failed", lootQuery);
}
for (uint32 itemID = 0; itemID < sItemStorage.MaxEntry; itemID++)
@@ -892,7 +961,7 @@ void AuctionHouseBotInit()
ItemPrototype const* prototype = objmgr.GetItemPrototype(itemID);
if (prototype == NULL)
- continue;
+ continue;
switch (prototype->Bonding)
{
@@ -931,13 +1000,10 @@ void AuctionHouseBotInit()
if (prototype->BuyPrice == 0)
continue;
break;
- default:
- continue;
- break;
}
if ((prototype->Quality < 0) || (prototype->Quality > 6))
- continue;
+ continue;
if (Vendor_Items == 0)
{
@@ -945,12 +1011,12 @@ void AuctionHouseBotInit()
for (unsigned int i = 0; (i < npcItems.size()) && (!isVendorItem); i++)
{
- if (itemID == npcItems[i])
- isVendorItem = true;
+ if (itemID == npcItems[i])
+ isVendorItem = true;
}
if (isVendorItem)
- continue;
+ continue;
}
if (Loot_Items == 0)
@@ -959,12 +1025,12 @@ void AuctionHouseBotInit()
for (unsigned int i = 0; (i < lootItems.size()) && (!isLootItem); i++)
{
- if (itemID == lootItems[i])
- isLootItem = true;
+ if (itemID == lootItems[i])
+ isLootItem = true;
}
if (isLootItem)
- continue;
+ continue;
}
if (Other_Items == 0)
@@ -974,92 +1040,349 @@ void AuctionHouseBotInit()
for (unsigned int i = 0; (i < npcItems.size()) && (!isVendorItem); i++)
{
- if (itemID == npcItems[i])
- isVendorItem = true;
+ if (itemID == npcItems[i])
+ isVendorItem = true;
}
for (unsigned int i = 0; (i < lootItems.size()) && (!isLootItem); i++)
{
- if (itemID == lootItems[i])
- isLootItem = true;
+ if (itemID == lootItems[i])
+ isLootItem = true;
}
if ((!isLootItem) && (!isVendorItem))
continue;
}
+ //TODO:Make list of items and create a vector
+ // Disable PTR/Beta/Unused items
+ if ((DisableBeta_PTR_Unused) && ((prototype->ItemId == 21878) || (prototype->ItemId == 27774) || (prototype->ItemId == 27811) || (prototype->ItemId == 28117) || (prototype->ItemId == 28112)))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (PTR/Beta/Unused Item)", prototype->ItemId);
+ continue;
+ }
+
+ // Disable permanent enchants items
+ if ((DisablePermEnchant) && (prototype->Class == ITEM_CLASS_PERMANENT))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Permanent Enchant Item)", prototype->ItemId);
+ continue;
+ }
+
+ // Disable conjured items
+ if ((DisableConjured) && (prototype->IsConjuredConsumable()))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Conjured Consumable)", prototype->ItemId);
+ continue;
+ }
+
+ // Disable gems
+ if ((DisableGems) && (prototype->Class == ITEM_CLASS_GEM))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Gem)", prototype->ItemId);
+ continue;
+ }
+
+ // Disable money
+ if ((DisableMoney) && (prototype->Class == ITEM_CLASS_MONEY))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Money)", prototype->ItemId);
+ continue;
+ }
+
+ // Disable moneyloot
+ if ((DisableMoneyLoot) && (prototype->MinMoneyLoot > 0))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (MoneyLoot)", prototype->ItemId);
+ continue;
+ }
+
+ // Disable lootable items
+ if ((DisableLootable) && (prototype->Flags & 4))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Lootable Item)", prototype->ItemId);
+ continue;
+ }
+
+ // Disable Keys
+ if ((DisableKeys) && (prototype->Class == ITEM_CLASS_KEY))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Quest Item)", prototype->ItemId);
+ continue;
+ }
+
+ // Disable items with duration
+ if ((DisableDuration) && (prototype->Duration > 0))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Has a Duration)", prototype->ItemId);
+ continue;
+ }
+
+ // Disable items which are BOP or Quest Items and have a required level lower than the item level
+ if ((DisableBOP_Or_Quest_NoReqLevel) && ((prototype->Bonding == BIND_WHEN_PICKED_UP || prototype->Bonding == BIND_QUEST_ITEM) && (prototype->RequiredLevel < prototype->ItemLevel)))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (BOP or BQI and Required Level is less than Item Level)", prototype->ItemId);
+ continue;
+ }
+
+ // Disable items specifically for Warrior
+ if ((DisableWarriorItems) && (prototype->AllowableClass == 1))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Warrior Item)", prototype->ItemId);
+ continue;
+ }
+
+ // Disable items specifically for Paladin
+ if ((DisablePaladinItems) && (prototype->AllowableClass == 2))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Paladin Item)", prototype->ItemId);
+ continue;
+ }
+
+ // Disable items specifically for Hunter
+ if ((DisableHunterItems) && (prototype->AllowableClass == 4))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Hunter Item)", prototype->ItemId);
+ continue;
+ }
+
+ // Disable items specifically for Rogue
+ if ((DisableRogueItems) && (prototype->AllowableClass == 8))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Rogue Item)", prototype->ItemId);
+ continue;
+ }
+
+ // Disable items specifically for Priest
+ if ((DisablePriestItems) && (prototype->AllowableClass == 16))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Priest Item)", prototype->ItemId);
+ continue;
+ }
+
+ // Disable items specifically for DK
+ if ((DisableDKItems) && (prototype->AllowableClass == 32))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (DK Item)", prototype->ItemId);
+ continue;
+ }
+
+ // Disable items specifically for Shaman
+ if ((DisableShamanItems) && (prototype->AllowableClass == 64))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Shaman Item)", prototype->ItemId);
+ continue;
+ }
+
+ // Disable items specifically for Mage
+ if ((DisableMageItems) && (prototype->AllowableClass == 128))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Mage Item)", prototype->ItemId);
+ continue;
+ }
+
+ // Disable items specifically for Warlock
+ if ((DisableWarlockItems) && (prototype->AllowableClass == 256))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Warlock Item)", prototype->ItemId);
+ continue;
+ }
+
+ // Disable items specifically for Unused Class
+ if ((DisableUnusedClassItems) && (prototype->AllowableClass == 512))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Unused Item)", prototype->ItemId);
+ continue;
+ }
+
+ // Disable items specifically for Druid
+ if ((DisableDruidItems) && (prototype->AllowableClass == 1024))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Druid Item)", prototype->ItemId);
+ continue;
+ }
+
+ // Disable Items below level X
+ if ((DisableItemsBelowLevel) && (prototype->Class != ITEM_CLASS_TRADE_GOODS) && (prototype->ItemLevel < DisableItemsBelowLevel))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Item Level = %u)", prototype->ItemId, prototype->ItemLevel);
+ continue;
+ }
+
+ // Disable Items above level X
+ if ((DisableItemsAboveLevel) && (prototype->Class != ITEM_CLASS_TRADE_GOODS) && (prototype->ItemLevel > DisableItemsAboveLevel))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Item Level = %u)", prototype->ItemId, prototype->ItemLevel);
+ continue;
+ }
+
+ // Disable Trade Goods below level X
+ if ((DisableTGsBelowLevel) && (prototype->Class == ITEM_CLASS_TRADE_GOODS) && (prototype->ItemLevel < DisableTGsBelowLevel))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Trade Good %u disabled (Trade Good Level = %u)", prototype->ItemId, prototype->ItemLevel);
+ continue;
+ }
+
+ // Disable Trade Goods above level X
+ if ((DisableTGsAboveLevel) && (prototype->Class == ITEM_CLASS_TRADE_GOODS) && (prototype->ItemLevel > DisableTGsAboveLevel))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Trade Good %u disabled (Trade Good Level = %u)", prototype->ItemId, prototype->ItemLevel);
+ continue;
+ }
+
+ // Disable Items below GUID X
+ if ((DisableItemsBelowGUID) && (prototype->Class != ITEM_CLASS_TRADE_GOODS) && (prototype->ItemId < DisableItemsBelowGUID))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Item Level = %u)", prototype->ItemId, prototype->ItemLevel);
+ continue;
+ }
+
+ // Disable Items above GUID X
+ if ((DisableItemsAboveGUID) && (prototype->Class != ITEM_CLASS_TRADE_GOODS) && (prototype->ItemId > DisableItemsAboveGUID))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Item Level = %u)", prototype->ItemId, prototype->ItemLevel);
+ continue;
+ }
+
+ // Disable Trade Goods below GUID X
+ if ((DisableTGsBelowGUID) && (prototype->Class == ITEM_CLASS_TRADE_GOODS) && (prototype->ItemId < DisableTGsBelowGUID))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Trade Good Level = %u)", prototype->ItemId, prototype->ItemLevel);
+ continue;
+ }
+
+ // Disable Trade Goods above GUID X
+ if ((DisableTGsAboveGUID) && (prototype->Class == ITEM_CLASS_TRADE_GOODS) && (prototype->ItemId > DisableTGsAboveGUID))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Trade Good Level = %u)", prototype->ItemId, prototype->ItemLevel);
+ continue;
+ }
+
+ // Disable Items for level lower than X
+ if ((DisableItemsBelowReqLevel) && (prototype->RequiredLevel < DisableItemsBelowReqLevel))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (RequiredLevel = %u)", prototype->ItemId, prototype->RequiredLevel);
+ continue;
+ }
+
+ // Disable Items for level higher than X
+ if ((DisableItemsAboveReqLevel) && (prototype->RequiredLevel > DisableItemsAboveReqLevel))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (RequiredLevel = %u)", prototype->ItemId, prototype->RequiredLevel);
+ continue;
+ }
+
+ // Disable Trade Goods for level lower than X
+ if ((DisableTGsBelowReqLevel) && (prototype->RequiredLevel < DisableTGsBelowReqLevel))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Trade Good %u disabled (RequiredLevel = %u)", prototype->ItemId, prototype->RequiredLevel);
+ continue;
+ }
+
+ // Disable Trade Goods for level higher than X
+ if ((DisableTGsAboveReqLevel) && (prototype->RequiredLevel > DisableTGsAboveReqLevel))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Trade Good %u disabled (RequiredLevel = %u)", prototype->ItemId, prototype->RequiredLevel);
+ continue;
+ }
+
+ // Disable Items that require skill lower than X
+ if ((DisableItemsBelowReqSkillRank) && (prototype->RequiredSkillRank < DisableItemsBelowReqSkillRank))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (RequiredSkillRank = %u)", prototype->ItemId, prototype->RequiredSkillRank);
+ continue;
+ }
+
+ // Disable Items that require skill higher than X
+ if ((DisableItemsAboveReqSkillRank) && (prototype->RequiredSkillRank > DisableItemsAboveReqSkillRank))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (RequiredSkillRank = %u)", prototype->ItemId, prototype->RequiredSkillRank);
+ continue;
+ }
+
+ // Disable Trade Goods that require skill lower than X
+ if ((DisableTGsBelowReqSkillRank) && (prototype->RequiredSkillRank < DisableTGsBelowReqSkillRank))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (RequiredSkillRank = %u)", prototype->ItemId, prototype->RequiredSkillRank);
+ continue;
+ }
+
+ // Disable Trade Goods that require skill higher than X
+ if ((DisableTGsAboveReqSkillRank) && (prototype->RequiredSkillRank > DisableTGsAboveReqSkillRank))
+ {
+ if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (RequiredSkillRank = %u)", prototype->ItemId, prototype->RequiredSkillRank);
+ continue;
+ }
+
switch (prototype->Quality)
{
- case 0:
+ case 0:
if (prototype->Class == ITEM_CLASS_TRADE_GOODS)
- greyTradeGoodsBin.push_back(itemID);
+ greyTradeGoodsBin.push_back(itemID);
else
- greyItemsBin.push_back(itemID);
+ greyItemsBin.push_back(itemID);
break;
- case 1:
+ case 1:
if (prototype->Class == ITEM_CLASS_TRADE_GOODS)
- whiteTradeGoodsBin.push_back(itemID);
+ whiteTradeGoodsBin.push_back(itemID);
else
- whiteItemsBin.push_back(itemID);
+ whiteItemsBin.push_back(itemID);
break;
- case 2:
+ case 2:
if (prototype->Class == ITEM_CLASS_TRADE_GOODS)
- greenTradeGoodsBin.push_back(itemID);
+ greenTradeGoodsBin.push_back(itemID);
else
- greenItemsBin.push_back(itemID);
+ greenItemsBin.push_back(itemID);
break;
- case 3:
+ case 3:
if (prototype->Class == ITEM_CLASS_TRADE_GOODS)
- blueTradeGoodsBin.push_back(itemID);
+ blueTradeGoodsBin.push_back(itemID);
else
- blueItemsBin.push_back(itemID);
+ blueItemsBin.push_back(itemID);
break;
- case 4:
+ case 4:
if (prototype->Class == ITEM_CLASS_TRADE_GOODS)
- purpleTradeGoodsBin.push_back(itemID);
+ purpleTradeGoodsBin.push_back(itemID);
else
- purpleItemsBin.push_back(itemID);
+ purpleItemsBin.push_back(itemID);
break;
- case 5:
+ case 5:
if (prototype->Class == ITEM_CLASS_TRADE_GOODS)
- orangeTradeGoodsBin.push_back(itemID);
+ orangeTradeGoodsBin.push_back(itemID);
else
- orangeItemsBin.push_back(itemID);
+ orangeItemsBin.push_back(itemID);
break;
- case 6:
+ case 6:
if (prototype->Class == ITEM_CLASS_TRADE_GOODS)
- yellowTradeGoodsBin.push_back(itemID);
+ yellowTradeGoodsBin.push_back(itemID);
else
- yellowItemsBin.push_back(itemID);
+ yellowItemsBin.push_back(itemID);
break;
}
}
- if (
- (greyTradeGoodsBin.size() == 0) &&
- (whiteTradeGoodsBin.size() == 0) &&
- (greenTradeGoodsBin.size() == 0) &&
- (blueTradeGoodsBin.size() == 0) &&
- (purpleTradeGoodsBin.size() == 0) &&
- (orangeTradeGoodsBin.size() == 0) &&
- (yellowTradeGoodsBin.size() == 0) &&
- (greyItemsBin.size() == 0) &&
- (whiteItemsBin.size() == 0) &&
- (greenItemsBin.size() == 0) &&
- (blueItemsBin.size() == 0) &&
- (purpleItemsBin.size() == 0) &&
- (orangeItemsBin.size() == 0) &&
- (yellowItemsBin.size() == 0)
- )
+ if ((greyTradeGoodsBin.size() == 0) &&
+ (whiteTradeGoodsBin.size() == 0) &&
+ (greenTradeGoodsBin.size() == 0) &&
+ (blueTradeGoodsBin.size() == 0) &&
+ (purpleTradeGoodsBin.size() == 0) &&
+ (orangeTradeGoodsBin.size() == 0) &&
+ (yellowTradeGoodsBin.size() == 0) &&
+ (greyItemsBin.size() == 0) &&
+ (whiteItemsBin.size() == 0) &&
+ (greenItemsBin.size() == 0) &&
+ (blueItemsBin.size() == 0) &&
+ (purpleItemsBin.size() == 0) &&
+ (orangeItemsBin.size() == 0) &&
+ (yellowItemsBin.size() == 0))
{
- sLog.outString("AuctionHouseBot: No items");
- AHBSeller = 0;
+ sLog.outString("AuctionHouseBot: No items");
+ AHBSeller = 0;
}
-
sLog.outString("AuctionHouseBot:");
sLog.outString("loaded %u grey trade goods", greyTradeGoodsBin.size());
sLog.outString("loaded %u white trade goods", whiteTradeGoodsBin.size());
@@ -1078,9 +1401,9 @@ void AuctionHouseBotInit()
}
sLog.outString("AuctionHouseBot by Paradox (original by ChrisK) has been loaded.");
sLog.outString("AuctionHouseBot now includes AHBuyer by Kerbe and Paradox");
-
}
-void AuctionHouseBotCommands(uint32 command, uint32 ahMapID, uint32 col, char* args)
+
+void AuctionHouseBot::Commands(uint32 command, uint32 ahMapID, uint32 col, char* args)
{
AHBConfig *config;
switch (ahMapID)
@@ -1133,32 +1456,33 @@ void AuctionHouseBotCommands(uint32 command, uint32 ahMapID, uint32 col, char* a
while (itr != auctionHouse->GetAuctionsEnd())
{
- if (itr->second->owner == AHBplayerGUID)
- itr->second->expire_time = sWorld.GetGameTime();
+ if (itr->second->owner == AHBplayerGUID)
+ itr->second->expire_time = sWorld.GetGameTime();
- ++itr;
+ ++itr;
}
- }break;
+ }
+ break;
case 1: //min items
{
char * param1 = strtok(args, " ");
uint32 minItems = (uint32) strtoul(param1, NULL, 0);
CharacterDatabase.PExecute("UPDATE auctionhousebot SET minitems = '%u' WHERE auctionhouse = '%u'", minItems, ahMapID);
config->SetMinItems(minItems);
- }break;
+ }
+ break;
case 2: //max items
{
char * param1 = strtok(args, " ");
uint32 maxItems = (uint32) strtoul(param1, NULL, 0);
CharacterDatabase.PExecute("UPDATE auctionhousebot SET maxitems = '%u' WHERE auctionhouse = '%u'", maxItems, ahMapID);
config->SetMaxItems(maxItems);
- }break;
+ }
+ break;
case 3: //min time Deprecated (Place holder for future commands)
- {
- }break;
+ break;
case 4: //max time Deprecated (Place holder for future commands)
- {
- }break;
+ break;
case 5: //percentages
{
char * param1 = strtok(args, " ");
@@ -1207,77 +1531,89 @@ void AuctionHouseBotCommands(uint32 command, uint32 ahMapID, uint32 col, char* a
CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentyellowitems = '%u' WHERE auctionhouse = '%u'", yellowi, ahMapID);
CharacterDatabase.CommitTransaction();
config->SetPercentages(greytg, whitetg, greentg, bluetg, purpletg, orangetg, yellowtg, greyi, whitei, greeni, bluei, purplei, orangei, yellowi);
- }break;
+ }
+ break;
case 6: //min prices
{
char * param1 = strtok(args, " ");
uint32 minPrice = (uint32) strtoul(param1, NULL, 0);
CharacterDatabase.PExecute("UPDATE auctionhousebot SET minprice%s = '%u' WHERE auctionhouse = '%u'",color.c_str(), minPrice, ahMapID);
config->SetMinPrice(col, minPrice);
- }break;
+ }
+ break;
case 7: //max prices
{
char * param1 = strtok(args, " ");
uint32 maxPrice = (uint32) strtoul(param1, NULL, 0);
CharacterDatabase.PExecute("UPDATE auctionhousebot SET maxprice%s = '%u' WHERE auctionhouse = '%u'",color.c_str(), maxPrice, ahMapID);
config->SetMaxPrice(col, maxPrice);
- }break;
+ }
+ break;
case 8: //min bid price
{
char * param1 = strtok(args, " ");
uint32 minBidPrice = (uint32) strtoul(param1, NULL, 0);
CharacterDatabase.PExecute("UPDATE auctionhousebot SET minbidprice%s = '%u' WHERE auctionhouse = '%u'",color.c_str(), minBidPrice, ahMapID);
config->SetMinBidPrice(col, minBidPrice);
- }break;
+ }
+ break;
case 9: //max bid price
{
char * param1 = strtok(args, " ");
uint32 maxBidPrice = (uint32) strtoul(param1, NULL, 0);
CharacterDatabase.PExecute("UPDATE auctionhousebot SET maxbidprice%s = '%u' WHERE auctionhouse = '%u'",color.c_str(), maxBidPrice, ahMapID);
config->SetMaxBidPrice(col, maxBidPrice);
- }break;
+ }
+ break;
case 10: //max stacks
{
char * param1 = strtok(args, " ");
uint32 maxStack = (uint32) strtoul(param1, NULL, 0);
CharacterDatabase.PExecute("UPDATE auctionhousebot SET maxstack%s = '%u' WHERE auctionhouse = '%u'",color.c_str(), maxStack, ahMapID);
config->SetMaxStack(col, maxStack);
- }break;
+ }
+ break;
case 11: //buyer bid prices
{
char * param1 = strtok(args, " ");
uint32 buyerPrice = (uint32) strtoul(param1, NULL, 0);
CharacterDatabase.PExecute("UPDATE auctionhousebot SET buyerprice%s = '%u' WHERE auctionhouse = '%u'",color.c_str(), buyerPrice, ahMapID);
config->SetBuyerPrice(col, buyerPrice);
- }break;
+ }
+ break;
case 12: //buyer bidding interval
{
char * param1 = strtok(args, " ");
uint32 bidInterval = (uint32) strtoul(param1, NULL, 0);
CharacterDatabase.PExecute("UPDATE auctionhousebot SET buyerbiddinginterval = '%u' WHERE auctionhouse = '%u'", bidInterval, ahMapID);
config->SetBiddingInterval(bidInterval);
- }break;
+ }
+ break;
case 13: //buyer bids per interval
{
char * param1 = strtok(args, " ");
uint32 bidsPerInterval = (uint32) strtoul(param1, NULL, 0);
CharacterDatabase.PExecute("UPDATE auctionhousebot SET buyerbidsperinterval = '%u' WHERE auctionhouse = '%u'", bidsPerInterval, ahMapID);
config->SetBidsPerInterval(bidsPerInterval);
- }break;
+ }
+ break;
default:
break;
}
}
-void AuctionHouseBotLoadValues(AHBConfig *config)
+
+void AuctionHouseBot::LoadValues(AHBConfig *config)
{
if (AHBSeller)
{
//load min and max items
config->SetMinItems(CharacterDatabase.PQuery("SELECT minitems FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
config->SetMaxItems(CharacterDatabase.PQuery("SELECT maxitems FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("minItems = %u", config->GetMinItems());
- sLog.outError("maxItems = %u", config->GetMaxItems());}
+ if (debug_Out)
+ {
+ sLog.outError("minItems = %u", config->GetMinItems());
+ sLog.outError("maxItems = %u", config->GetMaxItems());
+ }
//load percentages
uint32 greytg = CharacterDatabase.PQuery("SELECT percentgreytradegoods FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32();
uint32 whitetg = CharacterDatabase.PQuery("SELECT percentwhitetradegoods FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32();
@@ -1294,7 +1630,7 @@ void AuctionHouseBotLoadValues(AHBConfig *config)
uint32 orangei = CharacterDatabase.PQuery("SELECT percentorangeitems FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32();
uint32 yellowi = CharacterDatabase.PQuery("SELECT percentyellowitems FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32();
config->SetPercentages(greytg, whitetg, greentg, bluetg, purpletg, orangetg, yellowtg, greyi, whitei, greeni, bluei, purplei, orangei, yellowi);
- if(debug_Out)
+ if (debug_Out)
{
sLog.outError("percentGreyTradeGoods = %u", config->GetPercentages(AHB_GREY_TG));
sLog.outError("percentWhiteTradeGoods = %u", config->GetPercentages(AHB_WHITE_TG));
@@ -1314,104 +1650,160 @@ void AuctionHouseBotLoadValues(AHBConfig *config)
//load min and max prices
config->SetMinPrice(AHB_GREY, CharacterDatabase.PQuery("SELECT minpricegrey FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
config->SetMaxPrice(AHB_GREY, CharacterDatabase.PQuery("SELECT maxpricegrey FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("minPriceGrey = %u", config->GetMinPrice(AHB_GREY));
- sLog.outError("maxPriceGrey = %u", config->GetMaxPrice(AHB_GREY));}
+ if (debug_Out)
+ {
+ sLog.outError("minPriceGrey = %u", config->GetMinPrice(AHB_GREY));
+ sLog.outError("maxPriceGrey = %u", config->GetMaxPrice(AHB_GREY));
+ }
config->SetMinPrice(AHB_WHITE, CharacterDatabase.PQuery("SELECT minpricewhite FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
config->SetMaxPrice(AHB_WHITE, CharacterDatabase.PQuery("SELECT maxpricewhite FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("minPriceWhite = %u", config->GetMinPrice(AHB_WHITE));
- sLog.outError("maxPriceWhite = %u", config->GetMaxPrice(AHB_WHITE));}
+ if (debug_Out)
+ {
+ sLog.outError("minPriceWhite = %u", config->GetMinPrice(AHB_WHITE));
+ sLog.outError("maxPriceWhite = %u", config->GetMaxPrice(AHB_WHITE));
+ }
config->SetMinPrice(AHB_GREEN, CharacterDatabase.PQuery("SELECT minpricegreen FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
config->SetMaxPrice(AHB_GREEN, CharacterDatabase.PQuery("SELECT maxpricegreen FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("minPriceGreen = %u", config->GetMinPrice(AHB_GREEN));
- sLog.outError("maxPriceGreen = %u", config->GetMaxPrice(AHB_GREEN));}
+ if (debug_Out)
+ {
+ sLog.outError("minPriceGreen = %u", config->GetMinPrice(AHB_GREEN));
+ sLog.outError("maxPriceGreen = %u", config->GetMaxPrice(AHB_GREEN));
+ }
config->SetMinPrice(AHB_BLUE, CharacterDatabase.PQuery("SELECT minpriceblue FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
config->SetMaxPrice(AHB_BLUE, CharacterDatabase.PQuery("SELECT maxpriceblue FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("minPriceBlue = %u", config->GetMinPrice(AHB_BLUE));
- sLog.outError("maxPriceBlue = %u", config->GetMaxPrice(AHB_BLUE));}
+ if (debug_Out)
+ {
+ sLog.outError("minPriceBlue = %u", config->GetMinPrice(AHB_BLUE));
+ sLog.outError("maxPriceBlue = %u", config->GetMaxPrice(AHB_BLUE));
+ }
config->SetMinPrice(AHB_PURPLE, CharacterDatabase.PQuery("SELECT minpricepurple FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
config->SetMaxPrice(AHB_PURPLE, CharacterDatabase.PQuery("SELECT maxpricepurple FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("minPricePurple = %u", config->GetMinPrice(AHB_PURPLE));
- sLog.outError("maxPricePurple = %u", config->GetMaxPrice(AHB_PURPLE));}
+ if (debug_Out)
+ {
+ sLog.outError("minPricePurple = %u", config->GetMinPrice(AHB_PURPLE));
+ sLog.outError("maxPricePurple = %u", config->GetMaxPrice(AHB_PURPLE));
+ }
config->SetMinPrice(AHB_ORANGE, CharacterDatabase.PQuery("SELECT minpriceorange FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
config->SetMaxPrice(AHB_ORANGE, CharacterDatabase.PQuery("SELECT maxpriceorange FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("minPriceOrange = %u", config->GetMinPrice(AHB_ORANGE));
- sLog.outError("maxPriceOrange = %u", config->GetMaxPrice(AHB_ORANGE));}
+ if (debug_Out)
+ {
+ sLog.outError("minPriceOrange = %u", config->GetMinPrice(AHB_ORANGE));
+ sLog.outError("maxPriceOrange = %u", config->GetMaxPrice(AHB_ORANGE));
+ }
config->SetMinPrice(AHB_YELLOW, CharacterDatabase.PQuery("SELECT minpriceyellow FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
config->SetMaxPrice(AHB_YELLOW, CharacterDatabase.PQuery("SELECT maxpriceyellow FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("minPriceYellow = %u", config->GetMinPrice(AHB_YELLOW));
- sLog.outError("maxPriceYellow = %u", config->GetMaxPrice(AHB_YELLOW));}
+ if (debug_Out)
+ {
+ sLog.outError("minPriceYellow = %u", config->GetMinPrice(AHB_YELLOW));
+ sLog.outError("maxPriceYellow = %u", config->GetMaxPrice(AHB_YELLOW));
+ }
//load min and max bid prices
config->SetMinBidPrice(AHB_GREY, CharacterDatabase.PQuery("SELECT minbidpricegrey FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError(",minBidPriceGrey = %u", config->GetMinBidPrice(AHB_GREY));}
+ if (debug_Out)
+ {
+ sLog.outError("minBidPriceGrey = %u", config->GetMinBidPrice(AHB_GREY));
+ }
config->SetMaxBidPrice(AHB_GREY, CharacterDatabase.PQuery("SELECT maxbidpricegrey FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("maxBidPriceGrey = %u", config->GetMaxBidPrice(AHB_GREY));}
+ if (debug_Out)
+ {
+ sLog.outError("maxBidPriceGrey = %u", config->GetMaxBidPrice(AHB_GREY));
+ }
config->SetMinBidPrice(AHB_WHITE, CharacterDatabase.PQuery("SELECT minbidpricewhite FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError(",minBidPriceWhite = %u", config->GetMinBidPrice(AHB_WHITE));}
+ if (debug_Out)
+ {
+ sLog.outError("minBidPriceWhite = %u", config->GetMinBidPrice(AHB_WHITE));
+ }
config->SetMaxBidPrice(AHB_WHITE, CharacterDatabase.PQuery("SELECT maxbidpricewhite FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("maxBidPriceWhite = %u", config->GetMaxBidPrice(AHB_WHITE));}
+ if (debug_Out)
+ {
+ sLog.outError("maxBidPriceWhite = %u", config->GetMaxBidPrice(AHB_WHITE));
+ }
config->SetMinBidPrice(AHB_GREEN, CharacterDatabase.PQuery("SELECT minbidpricegreen FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("minBidPriceGreen = %u", config->GetMinBidPrice(AHB_GREEN));}
+ if (debug_Out)
+ {
+ sLog.outError("minBidPriceGreen = %u", config->GetMinBidPrice(AHB_GREEN));
+ }
config->SetMaxBidPrice(AHB_GREEN, CharacterDatabase.PQuery("SELECT maxbidpricegreen FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("maxBidPriceGreen = %u", config->GetMaxBidPrice(AHB_GREEN));}
+ if (debug_Out)
+ {
+ sLog.outError("maxBidPriceGreen = %u", config->GetMaxBidPrice(AHB_GREEN));
+ }
config->SetMinBidPrice(AHB_BLUE, CharacterDatabase.PQuery("SELECT minbidpriceblue FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("minBidPriceBlue = %u", config->GetMinBidPrice(AHB_BLUE));}
+ if (debug_Out)
+ {
+ sLog.outError("minBidPriceBlue = %u", config->GetMinBidPrice(AHB_BLUE));
+ }
config->SetMaxBidPrice(AHB_BLUE, CharacterDatabase.PQuery("SELECT maxbidpriceblue FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("maxBidPriceBlue = %u", config->GetMinBidPrice(AHB_BLUE));}
+ if (debug_Out)
+ {
+ sLog.outError("maxBidPriceBlue = %u", config->GetMinBidPrice(AHB_BLUE));
+ }
config->SetMinBidPrice(AHB_PURPLE, CharacterDatabase.PQuery("SELECT minbidpricepurple FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("minBidPricePurple = %u", config->GetMinBidPrice(AHB_PURPLE));}
+ if (debug_Out)
+ {
+ sLog.outError("minBidPricePurple = %u", config->GetMinBidPrice(AHB_PURPLE));
+ }
config->SetMaxBidPrice(AHB_PURPLE, CharacterDatabase.PQuery("SELECT maxbidpricepurple FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("maxBidPricePurple = %u", config->GetMaxBidPrice(AHB_PURPLE));}
+ if (debug_Out)
+ {
+ sLog.outError("maxBidPricePurple = %u", config->GetMaxBidPrice(AHB_PURPLE));
+ }
config->SetMinBidPrice(AHB_ORANGE, CharacterDatabase.PQuery("SELECT minbidpriceorange FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("minBidPriceOrange = %u", config->GetMinBidPrice(AHB_ORANGE));}
+ if (debug_Out)
+ {
+ sLog.outError("minBidPriceOrange = %u", config->GetMinBidPrice(AHB_ORANGE));
+ }
config->SetMaxBidPrice(AHB_ORANGE, CharacterDatabase.PQuery("SELECT maxbidpriceorange FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("maxBidPriceOrange = %u", config->GetMaxBidPrice(AHB_ORANGE));}
+ if (debug_Out)
+ {
+ sLog.outError("maxBidPriceOrange = %u", config->GetMaxBidPrice(AHB_ORANGE));
+ }
config->SetMinBidPrice(AHB_YELLOW, CharacterDatabase.PQuery("SELECT minbidpriceyellow FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("minBidPriceYellow = %u", config->GetMinBidPrice(AHB_YELLOW));}
+ if (debug_Out)
+ {
+ sLog.outError("minBidPriceYellow = %u", config->GetMinBidPrice(AHB_YELLOW));
+ }
config->SetMaxBidPrice(AHB_YELLOW, CharacterDatabase.PQuery("SELECT maxbidpriceyellow FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("maxBidPriceYellow = %u", config->GetMaxBidPrice(AHB_YELLOW));}
+ if (debug_Out)
+ {
+ sLog.outError("maxBidPriceYellow = %u", config->GetMaxBidPrice(AHB_YELLOW));
+ }
//load max stacks
config->SetMaxStack(AHB_GREY, CharacterDatabase.PQuery("SELECT maxstackgrey FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("maxStackGrey = %u", config->GetMaxStack(AHB_GREY));}
+ if (debug_Out)
+ {
+ sLog.outError("maxStackGrey = %u", config->GetMaxStack(AHB_GREY));
+ }
config->SetMaxStack(AHB_WHITE, CharacterDatabase.PQuery("SELECT maxstackwhite FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("maxStackWhite = %u", config->GetMaxStack(AHB_WHITE));}
+ if (debug_Out)
+ {
+ sLog.outError("maxStackWhite = %u", config->GetMaxStack(AHB_WHITE));
+ }
config->SetMaxStack(AHB_GREEN, CharacterDatabase.PQuery("SELECT maxstackgreen FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("maxStackGreen = %u", config->GetMaxStack(AHB_GREEN));}
+ if (debug_Out)
+ {
+ sLog.outError("maxStackGreen = %u", config->GetMaxStack(AHB_GREEN));
+ }
config->SetMaxStack(AHB_BLUE, CharacterDatabase.PQuery("SELECT maxstackblue FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("maxStackBlue = %u", config->GetMaxStack(AHB_BLUE));}
+ if (debug_Out)
+ {
+ sLog.outError("maxStackBlue = %u", config->GetMaxStack(AHB_BLUE));
+ }
config->SetMaxStack(AHB_PURPLE, CharacterDatabase.PQuery("SELECT maxstackpurple FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("maxStackPurple = %u", config->GetMaxStack(AHB_PURPLE));}
+ if (debug_Out)
+ {
+ sLog.outError("maxStackPurple = %u", config->GetMaxStack(AHB_PURPLE));
+ }
config->SetMaxStack(AHB_ORANGE, CharacterDatabase.PQuery("SELECT maxstackorange FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("maxStackOrange = %u", config->GetMaxStack(AHB_ORANGE));}
+ if (debug_Out)
+ {
+ sLog.outError("maxStackOrange = %u", config->GetMaxStack(AHB_ORANGE));
+ }
config->SetMaxStack(AHB_YELLOW, CharacterDatabase.PQuery("SELECT maxstackyellow FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("maxStackYellow = %u", config->GetMaxStack(AHB_YELLOW));}
+ if (debug_Out)
+ {
+ sLog.outError("maxStackYellow = %u", config->GetMaxStack(AHB_YELLOW));
+ }
}
if (AHBBuyer)
{
@@ -1423,7 +1815,7 @@ void AuctionHouseBotLoadValues(AHBConfig *config)
config->SetBuyerPrice(AHB_PURPLE, CharacterDatabase.PQuery("SELECT buyerpricepurple FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
config->SetBuyerPrice(AHB_ORANGE, CharacterDatabase.PQuery("SELECT buyerpriceorange FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
config->SetBuyerPrice(AHB_YELLOW, CharacterDatabase.PQuery("SELECT buyerpriceyellow FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
+ if (debug_Out)
{
sLog.outError("buyerPriceGrey = %u", config->GetBuyerPrice(AHB_GREY));
sLog.outError("buyerPriceWhite = %u", config->GetBuyerPrice(AHB_WHITE));
@@ -1435,11 +1827,15 @@ void AuctionHouseBotLoadValues(AHBConfig *config)
}
//load bidding interval
config->SetBiddingInterval(CharacterDatabase.PQuery("SELECT buyerbiddinginterval FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("buyerBiddingInterval = %u", config->GetBiddingInterval());}
+ if (debug_Out)
+ {
+ sLog.outError("buyerBiddingInterval = %u", config->GetBiddingInterval());
+ }
//load bids per interval
config->SetBidsPerInterval(CharacterDatabase.PQuery("SELECT buyerbidsperinterval FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32());
- if(debug_Out)
- {sLog.outError("buyerBidsPerInterval = %u", config->GetBidsPerInterval());}
+ if (debug_Out)
+ {
+ sLog.outError("buyerBidsPerInterval = %u", config->GetBidsPerInterval());
+ }
}
}
diff --git a/src/game/AuctionHouseBot.h b/src/game/AuctionHouseBot.h
index 906a857d206..df7e842ad4f 100644
--- a/src/game/AuctionHouseBot.h
+++ b/src/game/AuctionHouseBot.h
@@ -1,10 +1,9 @@
#ifndef AUCTION_HOUSE_BOT_H
#define AUCTION_HOUSE_BOT_H
-#include "Common.h"
+#include "World.h"
#include "Config/ConfigEnv.h"
-
-#include "Log.h"
+#include "ace/Vector_T.h"
#define AHB_GREY 0
#define AHB_WHITE 1
@@ -27,153 +26,149 @@
#define AHB_PURPLE_I 11
#define AHB_ORANGE_I 12
#define AHB_YELLOW_I 13
-#define AHBplayerAccount sConfig.GetIntDefault("AuctionHouseBot.Account", 0)
-#define AHBplayerGUID sConfig.GetIntDefault("AuctionHouseBot.GUID", 0)
-#define ItemsPerCycle sConfig.GetIntDefault("AuctionHouseBot.ItemsPerCycle", 200)
-#define SellMethod sConfig.GetIntDefault("AuctionHouseBot.UseBuyPriceForSeller", 1)
-#define BuyMethod sConfig.GetIntDefault("AuctionHouseBot.UseBuyPriceForBuyer", 0)
class AHBConfig
{
- private:
- uint32 AHID;
- uint32 AHFID;
- uint32 minItems;
- uint32 maxItems;
- uint32 percentGreyTradeGoods;
- uint32 percentWhiteTradeGoods;
- uint32 percentGreenTradeGoods;
- uint32 percentBlueTradeGoods;
- uint32 percentPurpleTradeGoods;
- uint32 percentOrangeTradeGoods;
- uint32 percentYellowTradeGoods;
- uint32 percentGreyItems;
- uint32 percentWhiteItems;
- uint32 percentGreenItems;
- uint32 percentBlueItems;
- uint32 percentPurpleItems;
- uint32 percentOrangeItems;
- uint32 percentYellowItems;
- uint32 minPriceGrey;
- uint32 maxPriceGrey;
- uint32 minBidPriceGrey;
- uint32 maxBidPriceGrey;
- uint32 maxStackGrey;
- uint32 minPriceWhite;
- uint32 maxPriceWhite;
- uint32 minBidPriceWhite;
- uint32 maxBidPriceWhite;
- uint32 maxStackWhite;
- uint32 minPriceGreen;
- uint32 maxPriceGreen;
- uint32 minBidPriceGreen;
- uint32 maxBidPriceGreen;
- uint32 maxStackGreen;
- uint32 minPriceBlue;
- uint32 maxPriceBlue;
- uint32 minBidPriceBlue;
- uint32 maxBidPriceBlue;
- uint32 maxStackBlue;
- uint32 minPricePurple;
- uint32 maxPricePurple;
- uint32 minBidPricePurple;
- uint32 maxBidPricePurple;
- uint32 maxStackPurple;
- uint32 minPriceOrange;
- uint32 maxPriceOrange;
- uint32 minBidPriceOrange;
- uint32 maxBidPriceOrange;
- uint32 maxStackOrange;
- uint32 minPriceYellow;
- uint32 maxPriceYellow;
- uint32 minBidPriceYellow;
- uint32 maxBidPriceYellow;
- uint32 maxStackYellow;
+private:
+ uint32 AHID;
+ uint32 AHFID;
+ uint32 minItems;
+ uint32 maxItems;
+ uint32 percentGreyTradeGoods;
+ uint32 percentWhiteTradeGoods;
+ uint32 percentGreenTradeGoods;
+ uint32 percentBlueTradeGoods;
+ uint32 percentPurpleTradeGoods;
+ uint32 percentOrangeTradeGoods;
+ uint32 percentYellowTradeGoods;
+ uint32 percentGreyItems;
+ uint32 percentWhiteItems;
+ uint32 percentGreenItems;
+ uint32 percentBlueItems;
+ uint32 percentPurpleItems;
+ uint32 percentOrangeItems;
+ uint32 percentYellowItems;
+ uint32 minPriceGrey;
+ uint32 maxPriceGrey;
+ uint32 minBidPriceGrey;
+ uint32 maxBidPriceGrey;
+ uint32 maxStackGrey;
+ uint32 minPriceWhite;
+ uint32 maxPriceWhite;
+ uint32 minBidPriceWhite;
+ uint32 maxBidPriceWhite;
+ uint32 maxStackWhite;
+ uint32 minPriceGreen;
+ uint32 maxPriceGreen;
+ uint32 minBidPriceGreen;
+ uint32 maxBidPriceGreen;
+ uint32 maxStackGreen;
+ uint32 minPriceBlue;
+ uint32 maxPriceBlue;
+ uint32 minBidPriceBlue;
+ uint32 maxBidPriceBlue;
+ uint32 maxStackBlue;
+ uint32 minPricePurple;
+ uint32 maxPricePurple;
+ uint32 minBidPricePurple;
+ uint32 maxBidPricePurple;
+ uint32 maxStackPurple;
+ uint32 minPriceOrange;
+ uint32 maxPriceOrange;
+ uint32 minBidPriceOrange;
+ uint32 maxBidPriceOrange;
+ uint32 maxStackOrange;
+ uint32 minPriceYellow;
+ uint32 maxPriceYellow;
+ uint32 minBidPriceYellow;
+ uint32 maxBidPriceYellow;
+ uint32 maxStackYellow;
+
+ uint32 buyerPriceGrey;
+ uint32 buyerPriceWhite;
+ uint32 buyerPriceGreen;
+ uint32 buyerPriceBlue;
+ uint32 buyerPricePurple;
+ uint32 buyerPriceOrange;
+ uint32 buyerPriceYellow;
+ uint32 buyerBiddingInterval;
+ uint32 buyerBidsPerInterval;
- uint32 buyerPriceGrey;
- uint32 buyerPriceWhite;
- uint32 buyerPriceGreen;
- uint32 buyerPriceBlue;
- uint32 buyerPricePurple;
- uint32 buyerPriceOrange;
- uint32 buyerPriceYellow;
- uint32 buyerBiddingInterval;
- uint32 buyerBidsPerInterval;
+ uint32 greytgp;
+ uint32 whitetgp;
+ uint32 greentgp;
+ uint32 bluetgp;
+ uint32 purpletgp;
+ uint32 orangetgp;
+ uint32 yellowtgp;
+ uint32 greyip;
+ uint32 whiteip;
+ uint32 greenip;
+ uint32 blueip;
+ uint32 purpleip;
+ uint32 orangeip;
+ uint32 yellowip;
- uint32 greytgp;
- uint32 whitetgp;
- uint32 greentgp;
- uint32 bluetgp;
- uint32 purpletgp;
- uint32 orangetgp;
- uint32 yellowtgp;
- uint32 greyip;
- uint32 whiteip;
- uint32 greenip;
- uint32 blueip;
- uint32 purpleip;
- uint32 orangeip;
- uint32 yellowip;
- public:
+public:
AHBConfig(uint32 ahid)
- {
- AHID = ahid;
- switch(ahid)
- {
- case 2:
- AHFID = 55;
- break;
- case 6:
+ {
+ AHID = ahid;
+ switch(ahid)
+ {
+ case 2:
+ AHFID = 55;
+ break;
+ case 6:
AHFID = 29;
- break;
- case 7:
+ break;
+ case 7:
AHFID = 120;
- break;
- default:
+ break;
+ default:
AHFID = 120;
- break;
- }
- }
- AHBConfig()
- {
- }
- uint32 GetAHID()
- {
- return AHID;
- }
- uint32 GetAHFID()
- {
- return AHFID;
- }
- void SetMinItems(uint32 value)
- {
- minItems = value;
- }
- uint32 GetMinItems()
- {
+ break;
+ }
+ }
+ AHBConfig()
+ {
+ }
+ uint32 GetAHID()
+ {
+ return AHID;
+ }
+ uint32 GetAHFID()
+ {
+ return AHFID;
+ }
+ void SetMinItems(uint32 value)
+ {
+ minItems = value;
+ }
+ uint32 GetMinItems()
+ {
if ((minItems == 0) && (maxItems))
return maxItems;
else if ((maxItems) && (minItems > maxItems))
return maxItems;
else
return minItems;
- }
- void SetMaxItems(uint32 value)
- {
- maxItems = value;
- CalculatePercents();
- }
- uint32 GetMaxItems()
- {
+ }
+ void SetMaxItems(uint32 value)
+ {
+ maxItems = value;
+ CalculatePercents();
+ }
+ uint32 GetMaxItems()
+ {
return maxItems;
- }
- void SetPercentages(uint32 greytg, uint32 whitetg, uint32 greentg, uint32 bluetg, uint32 purpletg, uint32 orangetg, uint32 yellowtg, uint32 greyi, uint32 whitei, uint32 greeni, uint32 bluei, uint32 purplei, uint32 orangei, uint32 yellowi)
- {
+ }
+ void SetPercentages(uint32 greytg, uint32 whitetg, uint32 greentg, uint32 bluetg, uint32 purpletg, uint32 orangetg, uint32 yellowtg, uint32 greyi, uint32 whitei, uint32 greeni, uint32 bluei, uint32 purplei, uint32 orangei, uint32 yellowi)
+ {
uint32 totalPercent = greytg + whitetg + greentg + bluetg + purpletg + orangetg + yellowtg + greyi + whitei + greeni + bluei + purplei + orangei + yellowi;
if (totalPercent == 0)
{
- maxItems = 0;
+ maxItems = 0;
}
else if (totalPercent != 100)
{
@@ -207,92 +202,92 @@ class AHBConfig
percentOrangeItems = orangei;
percentYellowItems = yellowi;
CalculatePercents();
- }
- uint32 GetPercentages(uint32 color)
- {
- switch(color)
- {
- case AHB_GREY_TG:
+ }
+ uint32 GetPercentages(uint32 color)
+ {
+ switch(color)
+ {
+ case AHB_GREY_TG:
return percentGreyTradeGoods;
- break;
- case AHB_WHITE_TG:
+ break;
+ case AHB_WHITE_TG:
return percentWhiteTradeGoods;
- break;
- case AHB_GREEN_TG:
+ break;
+ case AHB_GREEN_TG:
return percentGreenTradeGoods;
- break;
- case AHB_BLUE_TG:
+ break;
+ case AHB_BLUE_TG:
return percentBlueTradeGoods;
- break;
- case AHB_PURPLE_TG:
+ break;
+ case AHB_PURPLE_TG:
return percentPurpleTradeGoods;
- break;
- case AHB_ORANGE_TG:
+ break;
+ case AHB_ORANGE_TG:
return percentOrangeTradeGoods;
- break;
- case AHB_YELLOW_TG:
+ break;
+ case AHB_YELLOW_TG:
return percentYellowTradeGoods;
- break;
- case AHB_GREY_I:
+ break;
+ case AHB_GREY_I:
return percentGreyItems;
- break;
- case AHB_WHITE_I:
+ break;
+ case AHB_WHITE_I:
return percentWhiteItems;
- break;
- case AHB_GREEN_I:
+ break;
+ case AHB_GREEN_I:
return percentGreenItems;
- break;
- case AHB_BLUE_I:
+ break;
+ case AHB_BLUE_I:
return percentBlueItems;
- break;
- case AHB_PURPLE_I:
+ break;
+ case AHB_PURPLE_I:
return percentPurpleItems;
- break;
- case AHB_ORANGE_I:
+ break;
+ case AHB_ORANGE_I:
return percentOrangeItems;
- break;
- case AHB_YELLOW_I:
+ break;
+ case AHB_YELLOW_I:
return percentYellowItems;
- break;
- default:
+ break;
+ default:
return 0;
- break;
- }
- }
- void SetMinPrice(uint32 color, uint32 value)
- {
- switch(color)
- {
- case AHB_GREY:
+ break;
+ }
+ }
+ void SetMinPrice(uint32 color, uint32 value)
+ {
+ switch(color)
+ {
+ case AHB_GREY:
minPriceGrey = value;
- break;
- case AHB_WHITE:
+ break;
+ case AHB_WHITE:
minPriceWhite = value;
- break;
- case AHB_GREEN:
+ break;
+ case AHB_GREEN:
minPriceGreen = value;
- break;
- case AHB_BLUE:
+ break;
+ case AHB_BLUE:
minPriceBlue = value;
- break;
- case AHB_PURPLE:
+ break;
+ case AHB_PURPLE:
minPricePurple = value;
- break;
- case AHB_ORANGE:
+ break;
+ case AHB_ORANGE:
minPriceOrange = value;
- break;
- case AHB_YELLOW:
+ break;
+ case AHB_YELLOW:
minPriceYellow = value;
- break;
- default:
- break;
- }
- }
- uint32 GetMinPrice(uint32 color)
- {
- switch(color)
- {
- case AHB_GREY:
+ break;
+ default:
+ break;
+ }
+ }
+ uint32 GetMinPrice(uint32 color)
+ {
+ switch(color)
+ {
+ case AHB_GREY:
{
if (minPriceGrey == 0)
return 100;
@@ -302,7 +297,7 @@ class AHBConfig
return minPriceGrey;
break;
}
- case AHB_WHITE:
+ case AHB_WHITE:
{
if (minPriceWhite == 0)
return 150;
@@ -312,7 +307,7 @@ class AHBConfig
return minPriceWhite;
break;
}
- case AHB_GREEN:
+ case AHB_GREEN:
{
if (minPriceGreen == 0)
return 200;
@@ -322,7 +317,7 @@ class AHBConfig
return minPriceGreen;
break;
}
- case AHB_BLUE:
+ case AHB_BLUE:
{
if (minPriceBlue == 0)
return 250;
@@ -332,7 +327,7 @@ class AHBConfig
return minPriceBlue;
break;
}
- case AHB_PURPLE:
+ case AHB_PURPLE:
{
if (minPricePurple == 0)
return 300;
@@ -342,7 +337,7 @@ class AHBConfig
return minPricePurple;
break;
}
- case AHB_ORANGE:
+ case AHB_ORANGE:
{
if (minPriceOrange == 0)
return 400;
@@ -352,7 +347,7 @@ class AHBConfig
return minPriceOrange;
break;
}
- case AHB_YELLOW:
+ case AHB_YELLOW:
{
if (minPriceYellow == 0)
return 500;
@@ -362,47 +357,47 @@ class AHBConfig
return minPriceYellow;
break;
}
- default:
- {
- return 0;
- break;
- }
+ default:
+ {
+ return 0;
+ break;
+ }
}
- }
- void SetMaxPrice(uint32 color, uint32 value)
- {
- switch(color)
- {
- case AHB_GREY:
+ }
+ void SetMaxPrice(uint32 color, uint32 value)
+ {
+ switch(color)
+ {
+ case AHB_GREY:
maxPriceGrey = value;
- break;
- case AHB_WHITE:
+ break;
+ case AHB_WHITE:
maxPriceWhite = value;
- break;
- case AHB_GREEN:
+ break;
+ case AHB_GREEN:
maxPriceGreen = value;
- break;
- case AHB_BLUE:
+ break;
+ case AHB_BLUE:
maxPriceBlue = value;
- break;
- case AHB_PURPLE:
+ break;
+ case AHB_PURPLE:
maxPricePurple = value;
- break;
- case AHB_ORANGE:
+ break;
+ case AHB_ORANGE:
maxPriceOrange = value;
- break;
- case AHB_YELLOW:
+ break;
+ case AHB_YELLOW:
maxPriceYellow = value;
- break;
- default:
- break;
- }
- }
- uint32 GetMaxPrice(uint32 color)
- {
- switch(color)
- {
- case AHB_GREY:
+ break;
+ default:
+ break;
+ }
+ }
+ uint32 GetMaxPrice(uint32 color)
+ {
+ switch(color)
+ {
+ case AHB_GREY:
{
if (maxPriceGrey == 0)
return 150;
@@ -410,7 +405,7 @@ class AHBConfig
return maxPriceGrey;
break;
}
- case AHB_WHITE:
+ case AHB_WHITE:
{
if (maxPriceWhite == 0)
return 250;
@@ -418,7 +413,7 @@ class AHBConfig
return maxPriceWhite;
break;
}
- case AHB_GREEN:
+ case AHB_GREEN:
{
if (maxPriceGreen == 0)
return 300;
@@ -426,7 +421,7 @@ class AHBConfig
return maxPriceGreen;
break;
}
- case AHB_BLUE:
+ case AHB_BLUE:
{
if (maxPriceBlue == 0)
return 350;
@@ -434,7 +429,7 @@ class AHBConfig
return maxPriceBlue;
break;
}
- case AHB_PURPLE:
+ case AHB_PURPLE:
{
if (maxPricePurple == 0)
return 450;
@@ -442,7 +437,7 @@ class AHBConfig
return maxPricePurple;
break;
}
- case AHB_ORANGE:
+ case AHB_ORANGE:
{
if (maxPriceOrange == 0)
return 550;
@@ -450,7 +445,7 @@ class AHBConfig
return maxPriceOrange;
break;
}
- case AHB_YELLOW:
+ case AHB_YELLOW:
{
if (maxPriceYellow == 0)
return 650;
@@ -458,47 +453,47 @@ class AHBConfig
return maxPriceYellow;
break;
}
- default:
- {
- return 0;
- break;
- }
+ default:
+ {
+ return 0;
+ break;
+ }
}
- }
- void SetMinBidPrice(uint32 color, uint32 value)
- {
- switch(color)
- {
- case AHB_GREY:
+ }
+ void SetMinBidPrice(uint32 color, uint32 value)
+ {
+ switch(color)
+ {
+ case AHB_GREY:
minBidPriceGrey = value;
- break;
- case AHB_WHITE:
+ break;
+ case AHB_WHITE:
minBidPriceWhite = value;
- break;
- case AHB_GREEN:
+ break;
+ case AHB_GREEN:
minBidPriceGreen = value;
- break;
- case AHB_BLUE:
+ break;
+ case AHB_BLUE:
minBidPriceBlue = value;
- break;
- case AHB_PURPLE:
+ break;
+ case AHB_PURPLE:
minBidPricePurple = value;
- break;
- case AHB_ORANGE:
+ break;
+ case AHB_ORANGE:
minBidPriceOrange = value;
- break;
- case AHB_YELLOW:
+ break;
+ case AHB_YELLOW:
minBidPriceYellow = value;
- break;
- default:
- break;
- }
- }
- uint32 GetMinBidPrice(uint32 color)
- {
- switch(color)
- {
- case AHB_GREY:
+ break;
+ default:
+ break;
+ }
+ }
+ uint32 GetMinBidPrice(uint32 color)
+ {
+ switch(color)
+ {
+ case AHB_GREY:
{
if (minBidPriceGrey > 100)
return 100;
@@ -506,7 +501,7 @@ class AHBConfig
return minBidPriceGrey;
break;
}
- case AHB_WHITE:
+ case AHB_WHITE:
{
if (minBidPriceWhite > 100)
return 100;
@@ -514,7 +509,7 @@ class AHBConfig
return minBidPriceWhite;
break;
}
- case AHB_GREEN:
+ case AHB_GREEN:
{
if (minBidPriceGreen > 100)
return 100;
@@ -522,7 +517,7 @@ class AHBConfig
return minBidPriceGreen;
break;
}
- case AHB_BLUE:
+ case AHB_BLUE:
{
if (minBidPriceBlue > 100)
return 100;
@@ -530,7 +525,7 @@ class AHBConfig
return minBidPriceBlue;
break;
}
- case AHB_PURPLE:
+ case AHB_PURPLE:
{
if (minBidPricePurple > 100)
return 100;
@@ -538,7 +533,7 @@ class AHBConfig
return minBidPricePurple;
break;
}
- case AHB_ORANGE:
+ case AHB_ORANGE:
{
if (minBidPriceOrange > 100)
return 100;
@@ -546,7 +541,7 @@ class AHBConfig
return minBidPriceOrange;
break;
}
- case AHB_YELLOW:
+ case AHB_YELLOW:
{
if (minBidPriceYellow > 100)
return 100;
@@ -554,47 +549,47 @@ class AHBConfig
return minBidPriceYellow;
break;
}
- default:
- {
- return 0;
- break;
- }
- }
- }
- void SetMaxBidPrice(uint32 color, uint32 value)
- {
- switch(color)
- {
- case AHB_GREY:
+ default:
+ {
+ return 0;
+ break;
+ }
+ }
+ }
+ void SetMaxBidPrice(uint32 color, uint32 value)
+ {
+ switch(color)
+ {
+ case AHB_GREY:
maxBidPriceGrey = value;
- break;
- case AHB_WHITE:
+ break;
+ case AHB_WHITE:
maxBidPriceWhite = value;
- break;
- case AHB_GREEN:
+ break;
+ case AHB_GREEN:
maxBidPriceGreen = value;
- break;
- case AHB_BLUE:
+ break;
+ case AHB_BLUE:
maxBidPriceBlue = value;
- break;
- case AHB_PURPLE:
+ break;
+ case AHB_PURPLE:
maxBidPricePurple = value;
- break;
- case AHB_ORANGE:
+ break;
+ case AHB_ORANGE:
maxBidPriceOrange = value;
- break;
- case AHB_YELLOW:
+ break;
+ case AHB_YELLOW:
maxBidPriceYellow = value;
- break;
- default:
- break;
- }
- }
- uint32 GetMaxBidPrice(uint32 color)
- {
- switch(color)
- {
- case AHB_GREY:
+ break;
+ default:
+ break;
+ }
+ }
+ uint32 GetMaxBidPrice(uint32 color)
+ {
+ switch(color)
+ {
+ case AHB_GREY:
{
if (maxBidPriceGrey > 100)
return 100;
@@ -602,7 +597,7 @@ class AHBConfig
return maxBidPriceGrey;
break;
}
- case AHB_WHITE:
+ case AHB_WHITE:
{
if (maxBidPriceWhite > 100)
return 100;
@@ -610,7 +605,7 @@ class AHBConfig
return maxBidPriceWhite;
break;
}
- case AHB_GREEN:
+ case AHB_GREEN:
{
if (maxBidPriceGreen > 100)
return 100;
@@ -618,7 +613,7 @@ class AHBConfig
return maxBidPriceGreen;
break;
}
- case AHB_BLUE:
+ case AHB_BLUE:
{
if (maxBidPriceBlue > 100)
return 100;
@@ -626,7 +621,7 @@ class AHBConfig
return maxBidPriceBlue;
break;
}
- case AHB_PURPLE:
+ case AHB_PURPLE:
{
if (maxBidPricePurple > 100)
return 100;
@@ -634,7 +629,7 @@ class AHBConfig
return maxBidPricePurple;
break;
}
- case AHB_ORANGE:
+ case AHB_ORANGE:
{
if (maxBidPriceOrange > 100)
return 100;
@@ -642,7 +637,7 @@ class AHBConfig
return maxBidPriceOrange;
break;
}
- case AHB_YELLOW:
+ case AHB_YELLOW:
{
if (maxBidPriceYellow > 100)
return 100;
@@ -650,157 +645,157 @@ class AHBConfig
return maxBidPriceYellow;
break;
}
- default:
- {
- return 0;
- break;
- }
- }
- }
- void SetMaxStack(uint32 color, uint32 value)
- {
- switch(color)
- {
- case AHB_GREY:
+ default:
+ {
+ return 0;
+ break;
+ }
+ }
+ }
+ void SetMaxStack(uint32 color, uint32 value)
+ {
+ switch(color)
+ {
+ case AHB_GREY:
maxStackGrey = value;
- break;
- case AHB_WHITE:
+ break;
+ case AHB_WHITE:
maxStackWhite = value;
- break;
- case AHB_GREEN:
+ break;
+ case AHB_GREEN:
maxStackGreen = value;
- break;
- case AHB_BLUE:
+ break;
+ case AHB_BLUE:
maxStackBlue = value;
- break;
- case AHB_PURPLE:
+ break;
+ case AHB_PURPLE:
maxStackPurple = value;
- break;
- case AHB_ORANGE:
+ break;
+ case AHB_ORANGE:
maxStackOrange = value;
- break;
- case AHB_YELLOW:
+ break;
+ case AHB_YELLOW:
maxStackYellow = value;
- break;
- default:
- break;
- }
- }
- uint32 GetMaxStack(uint32 color)
- {
- switch(color)
- {
- case AHB_GREY:
+ break;
+ default:
+ break;
+ }
+ }
+ uint32 GetMaxStack(uint32 color)
+ {
+ switch(color)
+ {
+ case AHB_GREY:
{
return maxStackGrey;
break;
}
- case AHB_WHITE:
+ case AHB_WHITE:
{
return maxStackWhite;
break;
}
- case AHB_GREEN:
+ case AHB_GREEN:
{
return maxStackGreen;
break;
}
- case AHB_BLUE:
+ case AHB_BLUE:
{
return maxStackBlue;
break;
}
- case AHB_PURPLE:
+ case AHB_PURPLE:
{
return maxStackPurple;
break;
}
- case AHB_ORANGE:
+ case AHB_ORANGE:
{
return maxStackOrange;
break;
}
- case AHB_YELLOW:
+ case AHB_YELLOW:
{
return maxStackYellow;
break;
}
- default:
- {
- return 0;
- break;
- }
- }
- }
- void SetBuyerPrice(uint32 color, uint32 value)
- {
- switch(color)
- {
- case AHB_GREY:
+ default:
+ {
+ return 0;
+ break;
+ }
+ }
+ }
+ void SetBuyerPrice(uint32 color, uint32 value)
+ {
+ switch(color)
+ {
+ case AHB_GREY:
buyerPriceGrey = value;
- break;
- case AHB_WHITE:
+ break;
+ case AHB_WHITE:
buyerPriceWhite = value;
- break;
- case AHB_GREEN:
+ break;
+ case AHB_GREEN:
buyerPriceGreen = value;
- break;
- case AHB_BLUE:
+ break;
+ case AHB_BLUE:
buyerPriceBlue = value;
- break;
- case AHB_PURPLE:
+ break;
+ case AHB_PURPLE:
buyerPricePurple = value;
- break;
- case AHB_ORANGE:
+ break;
+ case AHB_ORANGE:
buyerPriceOrange = value;
- break;
- case AHB_YELLOW:
+ break;
+ case AHB_YELLOW:
buyerPriceYellow = value;
- break;
- default:
- break;
- }
- }
- uint32 GetBuyerPrice(uint32 color)
- {
- switch(color)
- {
- case AHB_GREY:
+ break;
+ default:
+ break;
+ }
+ }
+ uint32 GetBuyerPrice(uint32 color)
+ {
+ switch(color)
+ {
+ case AHB_GREY:
return buyerPriceGrey;
- break;
- case AHB_WHITE:
+ break;
+ case AHB_WHITE:
return buyerPriceWhite;
- break;
- case AHB_GREEN:
+ break;
+ case AHB_GREEN:
return buyerPriceGreen;
- break;
- case AHB_BLUE:
+ break;
+ case AHB_BLUE:
return buyerPriceBlue;
- break;
- case AHB_PURPLE:
+ break;
+ case AHB_PURPLE:
return buyerPricePurple;
- break;
- case AHB_ORANGE:
+ break;
+ case AHB_ORANGE:
return buyerPriceOrange;
- break;
- case AHB_YELLOW:
+ break;
+ case AHB_YELLOW:
return buyerPriceYellow;
- break;
- default:
- return 0;
- break;
- }
- }
- void SetBiddingInterval(uint32 value)
- {
- buyerBiddingInterval = value;
- }
- uint32 GetBiddingInterval()
- {
- return buyerBiddingInterval;
- }
- void CalculatePercents()
- {
+ break;
+ default:
+ return 0;
+ break;
+ }
+ }
+ void SetBiddingInterval(uint32 value)
+ {
+ buyerBiddingInterval = value;
+ }
+ uint32 GetBiddingInterval()
+ {
+ return buyerBiddingInterval;
+ }
+ void CalculatePercents()
+ {
greytgp = (uint32) (((double)percentGreyTradeGoods / 100.0) * maxItems);
whitetgp = (uint32) (((double)percentWhiteTradeGoods / 100.0) * maxItems);
greentgp = (uint32) (((double)percentGreenTradeGoods / 100.0) * maxItems);
@@ -828,72 +823,177 @@ class AHBConfig
{
whiteip += diff;
}
- }
- uint32 GetPercents(uint32 color)
- {
- switch(color)
- {
- case AHB_GREY_TG:
+ }
+ uint32 GetPercents(uint32 color)
+ {
+ switch(color)
+ {
+ case AHB_GREY_TG:
return greytgp;
- break;
- case AHB_WHITE_TG:
+ break;
+ case AHB_WHITE_TG:
return whitetgp;
- break;
- case AHB_GREEN_TG:
+ break;
+ case AHB_GREEN_TG:
return greentgp;
- break;
- case AHB_BLUE_TG:
+ break;
+ case AHB_BLUE_TG:
return bluetgp;
- break;
- case AHB_PURPLE_TG:
+ break;
+ case AHB_PURPLE_TG:
return purpletgp;
- break;
- case AHB_ORANGE_TG:
+ break;
+ case AHB_ORANGE_TG:
return orangetgp;
- break;
- case AHB_YELLOW_TG:
+ break;
+ case AHB_YELLOW_TG:
return yellowtgp;
- break;
- case AHB_GREY_I:
- return greyip;
- break;
- case AHB_WHITE_I:
+ break;
+ case AHB_GREY_I:
+ return greyip;
+ break;
+ case AHB_WHITE_I:
return whiteip;
- break;
- case AHB_GREEN_I:
+ break;
+ case AHB_GREEN_I:
return greenip;
- break;
- case AHB_BLUE_I:
+ break;
+ case AHB_BLUE_I:
return blueip;
- break;
- case AHB_PURPLE_I:
+ break;
+ case AHB_PURPLE_I:
return purpleip;
- break;
- case AHB_ORANGE_I:
+ break;
+ case AHB_ORANGE_I:
return orangeip;
- break;
- case AHB_YELLOW_I:
+ break;
+ case AHB_YELLOW_I:
return yellowip;
- break;
- default:
- return 0;
- break;
- }
- }
- void SetBidsPerInterval(uint32 value)
- {
- buyerBidsPerInterval = value;
- }
- uint32 GetBidsPerInterval()
- {
- return buyerBidsPerInterval;
- }
- ~AHBConfig()
- {
- }
+ break;
+ default:
+ return 0;
+ break;
+ }
+ }
+ void SetBidsPerInterval(uint32 value)
+ {
+ buyerBidsPerInterval = value;
+ }
+ uint32 GetBidsPerInterval()
+ {
+ return buyerBidsPerInterval;
+ }
+ ~AHBConfig()
+ {
+ }
};
-void AuctionHouseBot();
-void AuctionHouseBotInit();
-void AuctionHouseBotLoadValues(AHBConfig*);
-void AuctionHouseBotCommands(uint32, uint32, uint32, char*);
+class AuctionHouseBot
+{
+private:
+ ACE_Vector<uint32> npcItems;
+ ACE_Vector<uint32> lootItems;
+ ACE_Vector<uint32> greyTradeGoodsBin;
+ ACE_Vector<uint32> whiteTradeGoodsBin;
+ ACE_Vector<uint32> greenTradeGoodsBin;
+ ACE_Vector<uint32> blueTradeGoodsBin;
+ ACE_Vector<uint32> purpleTradeGoodsBin;
+ ACE_Vector<uint32> orangeTradeGoodsBin;
+ ACE_Vector<uint32> yellowTradeGoodsBin;
+ ACE_Vector<uint32> greyItemsBin;
+ ACE_Vector<uint32> whiteItemsBin;
+ ACE_Vector<uint32> greenItemsBin;
+ ACE_Vector<uint32> blueItemsBin;
+ ACE_Vector<uint32> purpleItemsBin;
+ ACE_Vector<uint32> orangeItemsBin;
+ ACE_Vector<uint32> yellowItemsBin;
+
+ bool debug_Out;
+
+ bool AHBSeller;
+ bool AHBBuyer;
+ bool BuyMethod;
+ bool SellMethod;
+
+ uint32 AHBplayerAccount;
+ uint32 AHBplayerGUID;
+ uint32 ItemsPerCycle;
+
+ //Begin Filters
+
+ bool Vendor_Items;
+ bool Loot_Items;
+ bool Other_Items;
+
+ bool No_Bind;
+ bool Bind_When_Picked_Up;
+ bool Bind_When_Equipped;
+ bool Bind_When_Use;
+ bool Bind_Quest_Item;
+
+ bool DisableBeta_PTR_Unused;
+ bool DisablePermEnchant;
+ bool DisableConjured;
+ bool DisableGems;
+ bool DisableMoney;
+ bool DisableMoneyLoot;
+ bool DisableLootable;
+ bool DisableKeys;
+ bool DisableDuration;
+ bool DisableBOP_Or_Quest_NoReqLevel;
+
+ bool DisableWarriorItems;
+ bool DisablePaladinItems;
+ bool DisableHunterItems;
+ bool DisableRogueItems;
+ bool DisablePriestItems;
+ bool DisableDKItems;
+ bool DisableShamanItems;
+ bool DisableMageItems;
+ bool DisableWarlockItems;
+ bool DisableUnusedClassItems;
+ bool DisableDruidItems;
+
+ uint32 DisableItemsBelowLevel;
+ uint32 DisableItemsAboveLevel;
+ uint32 DisableTGsBelowLevel;
+ uint32 DisableTGsAboveLevel;
+ uint32 DisableItemsBelowGUID;
+ uint32 DisableItemsAboveGUID;
+ uint32 DisableTGsBelowGUID;
+ uint32 DisableTGsAboveGUID;
+ uint32 DisableItemsBelowReqLevel;
+ uint32 DisableItemsAboveReqLevel;
+ uint32 DisableTGsBelowReqLevel;
+ uint32 DisableTGsAboveReqLevel;
+ uint32 DisableItemsBelowReqSkillRank;
+ uint32 DisableItemsAboveReqSkillRank;
+ uint32 DisableTGsBelowReqSkillRank;
+ uint32 DisableTGsAboveReqSkillRank;
+
+ //End Filters
+
+ AHBConfig AllianceConfig;
+ AHBConfig HordeConfig;
+ AHBConfig NeutralConfig;
+
+ time_t _lastrun_a;
+ time_t _lastrun_h;
+ time_t _lastrun_n;
+
+ inline uint32 minValue(uint32 a, uint32 b) { return a <= b ? a : b; };
+ void addNewAuctions(Player *AHBplayer, AHBConfig *config);
+ void addNewAuctionBuyerBotBid(Player *AHBplayer, AHBConfig *config, WorldSession *session);
+
+public:
+ AuctionHouseBot();
+ ~AuctionHouseBot();
+ void Update();
+ void Initialize();
+ void LoadValues(AHBConfig*);
+ void Commands(uint32, uint32, uint32, char*);
+ uint32 GetAHBplayerGUID() { return AHBplayerGUID; };
+};
+
+#define auctionbot Trinity::Singleton<AuctionHouseBot>::Instance()
+
#endif
diff --git a/src/game/AuctionHouseHandler.cpp b/src/game/AuctionHouseHandler.cpp
index d1f399bf570..9962a16bc77 100644
--- a/src/game/AuctionHouseHandler.cpp
+++ b/src/game/AuctionHouseHandler.cpp
@@ -127,7 +127,7 @@ void WorldSession::SendAuctionOutbiddedMail(AuctionEntry *auction, uint32 newPri
msgAuctionOutbiddedSubject << auction->item_template << ":0:" << AUCTION_OUTBIDDED;
if (oldBidder && !_player)
- oldBidder->GetSession()->SendAuctionBidderNotification( auction->GetHouseId(), auction->Id, AHBplayerGUID, newPrice, auction->GetAuctionOutBid(), auction->item_template);
+ oldBidder->GetSession()->SendAuctionBidderNotification( auction->GetHouseId(), auction->Id, auctionbot.GetAHBplayerGUID(), newPrice, auction->GetAuctionOutBid(), auction->item_template);
if (oldBidder && _player)
oldBidder->GetSession()->SendAuctionBidderNotification( auction->GetHouseId(), auction->Id, _player->GetGUID(), newPrice, auction->GetAuctionOutBid(), auction->item_template);
diff --git a/src/game/BattleGround.cpp b/src/game/BattleGround.cpp
index 71062657c0b..709cac492d5 100644
--- a/src/game/BattleGround.cpp
+++ b/src/game/BattleGround.cpp
@@ -182,6 +182,9 @@ BattleGround::BattleGround()
m_PlayersCount[BG_TEAM_ALLIANCE] = 0;
m_PlayersCount[BG_TEAM_HORDE] = 0;
+ m_TeamScores[BG_TEAM_ALLIANCE] = 0;
+ m_TeamScores[BG_TEAM_HORDE] = 0;
+
m_PrematureCountDown = false;
m_PrematureCountDown = 0;
@@ -204,16 +207,13 @@ BattleGround::~BattleGround()
// (this is done automatically in mapmanager update, when the instance is reset after the reset time)
int size = m_BgCreatures.size();
for(int i = 0; i < size; ++i)
- {
DelCreature(i);
- }
+
size = m_BgObjects.size();
for(int i = 0; i < size; ++i)
- {
DelObject(i);
- }
- if(GetInstanceID()) // not spam by useless queries in case BG templates
+ if (GetInstanceID()) // not spam by useless queries in case BG templates
{
// delete creature and go respawn times
WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE instance = '%u'",GetInstanceID());
@@ -230,6 +230,9 @@ BattleGround::~BattleGround()
((BattleGroundMap*)map)->SetUnload();
// remove from bg free slot queue
this->RemoveFromBGFreeSlotQueue();
+
+ for(BattleGroundScoreMap::const_iterator itr = m_PlayerScores.begin(); itr != m_PlayerScores.end(); ++itr)
+ delete itr->second;
}
void BattleGround::Update(uint32 diff)
@@ -473,7 +476,7 @@ void BattleGround::Update(uint32 diff)
void BattleGround::SetTeamStartLoc(uint32 TeamID, float X, float Y, float Z, float O)
{
- uint8 idx = GetTeamIndexByTeamId(TeamID);
+ BattleGroundTeamId idx = GetTeamIndexByTeamId(TeamID);
m_TeamStartLocX[idx] = X;
m_TeamStartLocY[idx] = Y;
m_TeamStartLocZ[idx] = Z;
@@ -759,6 +762,7 @@ void BattleGround::EndBattleGround(uint32 winner)
{
RewardMark(plr,ITEM_WINNER_COUNT);
RewardQuestComplete(plr);
+ plr->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_BG, 1);
}
else if(winner)
RewardMark(plr,ITEM_LOSER_COUNT);
@@ -843,7 +847,7 @@ void BattleGround::RewardMark(Player *plr,uint32 count)
void BattleGround::RewardSpellCast(Player *plr, uint32 spell_id)
{
// 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
- if (plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
+ if (plr->HasAura(SPELL_AURA_PLAYER_INACTIVE))
return;
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id);
@@ -859,7 +863,7 @@ void BattleGround::RewardSpellCast(Player *plr, uint32 spell_id)
void BattleGround::RewardItem(Player *plr, uint32 item_id, uint32 count)
{
// 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
- if (plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
+ if (plr->HasAura(SPELL_AURA_PLAYER_INACTIVE))
return;
ItemPosCountVec dest;
@@ -963,7 +967,7 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac
participant = true;
}
- std::map<uint64, BattleGroundScore*>::iterator itr2 = m_PlayerScores.find(guid);
+ BattleGroundScoreMap::iterator itr2 = m_PlayerScores.find(guid);
if (itr2 != m_PlayerScores.end())
{
delete itr2->second; // delete player's score
@@ -1105,7 +1109,12 @@ void BattleGround::Reset()
m_InBGFreeSlotQueue = false;
m_Players.clear();
+
+ for(BattleGroundScoreMap::const_iterator itr = m_PlayerScores.begin(); itr != m_PlayerScores.end(); ++itr)
+ delete itr->second;
m_PlayerScores.clear();
+
+ ResetBGSubclass();
}
void BattleGround::StartBattleGround()
@@ -1342,7 +1351,7 @@ bool BattleGround::HasFreeSlots() const
void BattleGround::UpdatePlayerScore(Player *Source, uint32 type, uint32 value)
{
//this procedure is called from virtual function implemented in bg subclass
- std::map<uint64, BattleGroundScore*>::const_iterator itr = m_PlayerScores.find(Source->GetGUID());
+ BattleGroundScoreMap::const_iterator itr = m_PlayerScores.find(Source->GetGUID());
if(itr == m_PlayerScores.end()) // player not found...
return;
@@ -1609,8 +1618,6 @@ bool BattleGround::DelCreature(uint32 type)
sLog.outError("Can't find creature guid: %u",GUID_LOPART(m_BgCreatures[type]));
return false;
}
- //TODO: only delete creature after not in combat
- cr->CleanupsBeforeDelete();
cr->AddObjectToRemoveList();
m_BgCreatures[type] = 0;
return true;
@@ -1876,3 +1883,9 @@ WorldSafeLocsEntry const* BattleGround::GetClosestGraveYard( Player* player )
{
return objmgr.GetClosestGraveYard( player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetMapId(), player->GetTeam() );
}
+
+bool BattleGround::IsTeamScoreInRange(uint32 team, uint32 minScore, uint32 maxScore) const
+{
+ BattleGroundTeamId team_idx = GetTeamIndexByTeamId(team);
+ return m_TeamScores[team_idx] >= minScore && m_TeamScores[team_idx] <= maxScore;
+}
diff --git a/src/game/BattleGround.h b/src/game/BattleGround.h
index 509ba6eb972..4ed660a3595 100644
--- a/src/game/BattleGround.h
+++ b/src/game/BattleGround.h
@@ -297,6 +297,13 @@ class BattleGround
virtual void Reset(); // resets all common properties for battlegrounds, must be implemented and called in BG subclass
virtual void StartingEventCloseDoors() {}
virtual void StartingEventOpenDoors() {}
+ virtual void ResetBGSubclass() // must be implemented in BG subclass
+ {
+ }
+
+ /* achievement req. */
+ virtual bool IsAllNodesConrolledByTeam(uint32 /*team*/) const { return false; }
+ bool IsTeamScoreInRange(uint32 team, uint32 minScore, uint32 maxScore) const;
/* Battleground */
// Get methods:
@@ -377,8 +384,9 @@ class BattleGround
BattleGroundPlayerMap const& GetPlayers() const { return m_Players; }
uint32 GetPlayersSize() const { return m_Players.size(); }
- std::map<uint64, BattleGroundScore*>::const_iterator GetPlayerScoresBegin() const { return m_PlayerScores.begin(); }
- std::map<uint64, BattleGroundScore*>::const_iterator GetPlayerScoresEnd() const { return m_PlayerScores.end(); }
+ typedef std::map<uint64, BattleGroundScore*> BattleGroundScoreMap;
+ BattleGroundScoreMap::const_iterator GetPlayerScoresBegin() const { return m_PlayerScores.begin(); }
+ BattleGroundScoreMap::const_iterator GetPlayerScoresEnd() const { return m_PlayerScores.end(); }
uint32 GetPlayerScoresSize() const { return m_PlayerScores.size(); }
uint32 GetReviveQueueSize() const { return m_ReviveQueue.size(); }
@@ -397,7 +405,7 @@ class BattleGround
void SetTeamStartLoc(uint32 TeamID, float X, float Y, float Z, float O);
void GetTeamStartLoc(uint32 TeamID, float &X, float &Y, float &Z, float &O) const
{
- uint8 idx = GetTeamIndexByTeamId(TeamID);
+ BattleGroundTeamId idx = GetTeamIndexByTeamId(TeamID);
X = m_TeamStartLocX[idx];
Y = m_TeamStartLocY[idx];
Z = m_TeamStartLocZ[idx];
@@ -441,7 +449,7 @@ class BattleGround
virtual void UpdatePlayerScore(Player *Source, uint32 type, uint32 value);
- uint8 GetTeamIndexByTeamId(uint32 Team) const { return Team == ALLIANCE ? BG_TEAM_ALLIANCE : BG_TEAM_HORDE; }
+ static BattleGroundTeamId GetTeamIndexByTeamId(uint32 Team) { return Team == ALLIANCE ? BG_TEAM_ALLIANCE : BG_TEAM_HORDE; }
uint32 GetPlayersCountByTeam(uint32 Team) const { return m_PlayersCount[GetTeamIndexByTeamId(Team)]; }
uint32 GetAlivePlayersCountByTeam(uint32 Team) const; // used in arenas to correctly handle death in spirit of redemption / last stand etc. (killer = killed) cases
void UpdatePlayersCountByTeam(uint32 Team, bool remove)
@@ -514,14 +522,17 @@ class BattleGround
void SetDeleteThis() {m_SetDeleteThis = true;}
+ /* virtual score-array - get's used in bg-subclasses */
+ int32 m_TeamScores[BG_TEAMS_COUNT];
+
protected:
//this method is called, when BG cannot spawn its own spirit guide, or something is wrong, It correctly ends BattleGround
void EndNow();
void PlayerAddedToBGCheckIfBGIsRunning(Player* plr);
/* Scorekeeping */
- // Player scores
- std::map<uint64, BattleGroundScore*> m_PlayerScores;
+
+ BattleGroundScoreMap m_PlayerScores; // Player scores
// must be implemented in BG subclass
virtual void RemovePlayer(Player * /*player*/, uint64 /*guid*/) {}
diff --git a/src/game/BattleGroundAB.cpp b/src/game/BattleGroundAB.cpp
index f5fba6f4186..70709af42ad 100644
--- a/src/game/BattleGroundAB.cpp
+++ b/src/game/BattleGroundAB.cpp
@@ -161,6 +161,18 @@ void BattleGroundAB::Update(uint32 diff)
}
}
+ // achievements flags
+ if (m_TeamScores[BG_TEAM_ALLIANCE] > m_TeamScores[BG_TEAM_HORDE])
+ {
+ if (m_TeamScores[BG_TEAM_ALLIANCE] - m_TeamScores[BG_TEAM_HORDE] >= 500)
+ m_TeamScores500disadvantage[BG_TEAM_HORDE] = true;
+ }
+ else
+ {
+ if (m_TeamScores[BG_TEAM_HORDE] - m_TeamScores[BG_TEAM_ALLIANCE] >= 500)
+ m_TeamScores500disadvantage[BG_TEAM_ALLIANCE] = true;
+ }
+
// Test win condition
if (m_TeamScores[BG_TEAM_ALLIANCE] >= BG_AB_MAX_TEAM_SCORE)
EndBattleGround(ALLIANCE);
@@ -428,7 +440,7 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ
return;
}
- uint8 teamIndex = GetTeamIndexByTeamId(source->GetTeam());
+ BattleGroundTeamId teamIndex = GetTeamIndexByTeamId(source->GetTeam());
// Check if player really could use this banner, not cheated
if (!(m_Nodes[node] == 0 || teamIndex == m_Nodes[node]%2))
@@ -474,7 +486,7 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ
m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
// FIXME: node names not localized
- if (teamIndex == 0)
+ if (teamIndex == BG_TEAM_ALLIANCE)
SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node));
else
SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node));
@@ -491,15 +503,15 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ
_CreateBanner(node, BG_AB_NODE_TYPE_OCCUPIED, teamIndex, true);
_SendNodeUpdate(node);
m_NodeTimers[node] = 0;
- _NodeOccupied(node,(teamIndex == 0) ? ALLIANCE:HORDE);
+ _NodeOccupied(node,(teamIndex == BG_TEAM_ALLIANCE) ? ALLIANCE:HORDE);
// FIXME: node names not localized
- if (teamIndex == 0)
+ if (teamIndex == BG_TEAM_ALLIANCE)
SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node));
else
SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node));
}
- sound = (teamIndex == 0) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE;
+ sound = (teamIndex == BG_TEAM_ALLIANCE) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE;
}
// If node is occupied, change to enemy-contested
else
@@ -516,19 +528,19 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ
m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
// FIXME: node names not localized
- if (teamIndex == 0)
+ if (teamIndex == BG_TEAM_ALLIANCE)
SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node));
else
SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node));
- sound = (teamIndex == 0) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE;
+ sound = (teamIndex == BG_TEAM_ALLIANCE) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE;
}
// If node is occupied again, send "X has taken the Y" msg.
if (m_Nodes[node] >= BG_AB_NODE_TYPE_OCCUPIED)
{
// FIXME: team and node names not localized
- if (teamIndex == 0)
+ if (teamIndex == BG_TEAM_ALLIANCE)
SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_ALLIANCE, NULL, LANG_BG_AB_ALLY, _GetNodeNameId(node));
else
SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_HORDE, NULL, LANG_BG_AB_HORDE, _GetNodeNameId(node));
@@ -591,6 +603,8 @@ void BattleGroundAB::Reset()
bool isBGWeekend = false; //TODO FIXME - call sBattleGroundMgr.IsBGWeekend(m_TypeID); - you must also implement that call!
m_HonorTics = (isBGWeekend) ? BG_AB_ABBGWeekendHonorTicks : BG_AB_NotABBGWeekendHonorTicks;
m_ReputationTics = (isBGWeekend) ? BG_AB_ABBGWeekendReputationTicks : BG_AB_NotABBGWeekendReputationTicks;
+ m_TeamScores500disadvantage[BG_TEAM_ALLIANCE] = false;
+ m_TeamScores500disadvantage[BG_TEAM_HORDE] = false;
for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
{
@@ -621,7 +635,7 @@ void BattleGroundAB::EndBattleGround(uint32 winner)
WorldSafeLocsEntry const* BattleGroundAB::GetClosestGraveYard(Player* player)
{
- uint8 teamIndex = GetTeamIndexByTeamId(player->GetTeam());
+ BattleGroundTeamId teamIndex = GetTeamIndexByTeamId(player->GetTeam());
// Is there any occupied node for this team?
std::vector<uint8> nodes;
@@ -660,8 +674,7 @@ WorldSafeLocsEntry const* BattleGroundAB::GetClosestGraveYard(Player* player)
void BattleGroundAB::UpdatePlayerScore(Player *Source, uint32 type, uint32 value)
{
- std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID());
-
+ BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID());
if( itr == m_PlayerScores.end() ) // player not found...
return;
@@ -679,3 +692,13 @@ void BattleGroundAB::UpdatePlayerScore(Player *Source, uint32 type, uint32 value
}
}
+bool BattleGroundAB::IsAllNodesConrolledByTeam(uint32 team) const
+{
+ uint32 count = 0;
+ for(int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
+ if (team == ALLIANCE && m_Nodes[i] == BG_AB_NODE_STATUS_ALLY_OCCUPIED ||
+ team == HORDE && m_Nodes[i] == BG_AB_NODE_STATUS_HORDE_OCCUPIED)
+ ++count;
+
+ return count == BG_AB_DYNAMIC_NODES_COUNT;
+}
diff --git a/src/game/BattleGroundAB.h b/src/game/BattleGroundAB.h
index 1c4a6d3b738..1a940a041d4 100644
--- a/src/game/BattleGroundAB.h
+++ b/src/game/BattleGroundAB.h
@@ -262,6 +262,9 @@ class BattleGroundAB : public BattleGround
/* Nodes occupying */
virtual void EventPlayerClickedOnFlag(Player *source, GameObject* target_obj);
+ /* achievement req. */
+ bool IsAllNodesConrolledByTeam(uint32 team) const; // overwrited
+ bool IsTeamScores500disadvantage(uint32 team) const { return m_TeamScores500disadvantage[GetTeamIndexByTeamId(team)]; }
private:
/* Gameobject spawning/despawning */
void _CreateBanner(uint8 node, uint8 type, uint8 teamIndex, bool delay);
@@ -285,15 +288,14 @@ class BattleGroundAB : public BattleGround
uint8 m_prevNodes[BG_AB_DYNAMIC_NODES_COUNT];
BG_AB_BannerTimer m_BannerTimers[BG_AB_DYNAMIC_NODES_COUNT];
uint32 m_NodeTimers[BG_AB_DYNAMIC_NODES_COUNT];
- uint32 m_TeamScores[BG_TEAMS_COUNT];
uint32 m_lastTick[BG_TEAMS_COUNT];
uint32 m_HonorScoreTics[BG_TEAMS_COUNT];
uint32 m_ReputationScoreTics[BG_TEAMS_COUNT];
bool m_IsInformedNearVictory;
uint32 m_HonorTics;
uint32 m_ReputationTics;
-
-
+ // need for achievements
+ bool m_TeamScores500disadvantage[BG_TEAMS_COUNT];
};
#endif
diff --git a/src/game/BattleGroundAV.cpp b/src/game/BattleGroundAV.cpp
index a93b304e2b9..4778bdb2384 100644
--- a/src/game/BattleGroundAV.cpp
+++ b/src/game/BattleGroundAV.cpp
@@ -34,11 +34,10 @@ BattleGroundAV::BattleGroundAV()
m_BgObjects.resize(BG_AV_OBJECT_MAX);
m_BgCreatures.resize(AV_CPLACE_MAX+AV_STATICCPLACE_MAX);
- //TODO FIX ME!
- m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_EY_START_TWO_MINUTES;
- m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_EY_START_ONE_MINUTE;
- m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_EY_START_HALF_MINUTE;
- m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_EY_HAS_BEGUN;
+ m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_AV_START_TWO_MINUTES;
+ m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_AV_START_ONE_MINUTE;
+ m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_AV_START_HALF_MINUTE;
+ m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_AV_HAS_BEGUN;
}
BattleGroundAV::~BattleGroundAV()
@@ -300,117 +299,8 @@ Creature* BattleGroundAV::AddAVCreature(uint16 cinfoid, uint16 type )
void BattleGroundAV::Update(uint32 diff)
{
BattleGround::Update(diff);
- if (GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize())
- {
- ModifyStartDelayTime(diff);
-
- if (!(m_Events & 0x01))
- {
- m_Events |= 0x01;
-
- if(!SetupBattleGround())
- {
- EndNow();
- return;
- }
- uint16 i;
- sLog.outDebug("Alterac Valley: entering state STATUS_WAIT_JOIN ...");
- // Initial Nodes
- for(i = 0; i < BG_AV_OBJECT_MAX; i++)
- SpawnBGObject(i, RESPAWN_ONE_DAY);
- for(i = BG_AV_OBJECT_FLAG_A_FIRSTAID_STATION; i <= BG_AV_OBJECT_FLAG_A_STONEHEART_GRAVE ; i++){
- SpawnBGObject(BG_AV_OBJECT_AURA_A_FIRSTAID_STATION+3*i,RESPAWN_IMMEDIATELY);
- SpawnBGObject(i, RESPAWN_IMMEDIATELY);
- }
- for(i = BG_AV_OBJECT_FLAG_A_DUNBALDAR_SOUTH; i <= BG_AV_OBJECT_FLAG_A_STONEHEART_BUNKER ; i++)
- SpawnBGObject(i, RESPAWN_IMMEDIATELY);
- for(i = BG_AV_OBJECT_FLAG_H_ICEBLOOD_GRAVE; i <= BG_AV_OBJECT_FLAG_H_FROSTWOLF_WTOWER ; i++){
- SpawnBGObject(i, RESPAWN_IMMEDIATELY);
- if(i<=BG_AV_OBJECT_FLAG_H_FROSTWOLF_HUT)
- SpawnBGObject(BG_AV_OBJECT_AURA_H_FIRSTAID_STATION+3*GetNodeThroughObject(i),RESPAWN_IMMEDIATELY);
- }
- for(i = BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH; i <= BG_AV_OBJECT_TFLAG_A_STONEHEART_BUNKER; i+=2)
- {
- SpawnBGObject(i, RESPAWN_IMMEDIATELY); //flag
- SpawnBGObject(i+16, RESPAWN_IMMEDIATELY); //aura
- }
- for(i = BG_AV_OBJECT_TFLAG_H_ICEBLOOD_TOWER; i <= BG_AV_OBJECT_TFLAG_H_FROSTWOLF_WTOWER; i+=2)
- {
- SpawnBGObject(i, RESPAWN_IMMEDIATELY); //flag
- SpawnBGObject(i+16, RESPAWN_IMMEDIATELY); //aura
- }
- //snowfall and the doors
- for(i = BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE; i <= BG_AV_OBJECT_DOOR_A; i++)
- SpawnBGObject(i, RESPAWN_IMMEDIATELY);
- SpawnBGObject(BG_AV_OBJECT_AURA_N_SNOWFALL_GRAVE,RESPAWN_IMMEDIATELY);
-
- //creatures
- sLog.outDebug("BG_AV start poputlating nodes");
- for(BG_AV_Nodes i= BG_AV_NODES_FIRSTAID_STATION; i < BG_AV_NODES_MAX; ++i )
- {
- if(m_Nodes[i].Owner)
- PopulateNode(i);
- }
- //all creatures which don't get despawned through the script are static
- sLog.outDebug("BG_AV: start spawning static creatures");
- for(i=0; i < AV_STATICCPLACE_MAX; i++ )
- AddAVCreature(0,i+AV_CPLACE_MAX);
- //mainspiritguides:
- sLog.outDebug("BG_AV: start spawning spiritguides creatures");
- AddSpiritGuide(7, BG_AV_CreaturePos[7][0], BG_AV_CreaturePos[7][1], BG_AV_CreaturePos[7][2], BG_AV_CreaturePos[7][3], ALLIANCE);
- AddSpiritGuide(8, BG_AV_CreaturePos[8][0], BG_AV_CreaturePos[8][1], BG_AV_CreaturePos[8][2], BG_AV_CreaturePos[8][3], HORDE);
- //spawn the marshals (those who get deleted, if a tower gets destroyed)
- sLog.outDebug("BG_AV: start spawning marshal creatures");
- for(i=AV_NPC_A_MARSHAL_SOUTH; i<= AV_NPC_H_MARSHAL_WTOWER; i++)
- AddAVCreature(i,AV_CPLACE_A_MARSHAL_SOUTH+(i-AV_NPC_A_MARSHAL_SOUTH));
-
- AddAVCreature(AV_NPC_HERALD,AV_CPLACE_HERALD);
- DoorClose(BG_AV_OBJECT_DOOR_A);
- DoorClose(BG_AV_OBJECT_DOOR_H);
-
- SetStartDelayTime(BG_START_DELAY_2M);
- }
- // After 1 minute, warning is signalled
- else if (GetStartDelayTime() <= BG_START_DELAY_1M && !(m_Events & 0x04))
- {
- m_Events |= 0x04;
- SendMessageToAll(LANG_BG_AV_ONEMINTOSTART, CHAT_MSG_BG_SYSTEM_NEUTRAL);
- }
- // After 1,5 minute, warning is signalled
- else if (GetStartDelayTime() <= BG_START_DELAY_1M + BG_START_DELAY_30S && !(m_Events & 0x08))
- {
- m_Events |= 0x08;
- SendMessageToAll(LANG_BG_AV_HALFMINTOSTART, CHAT_MSG_BG_SYSTEM_NEUTRAL);
- }
- // After 2 minutes, gates OPEN ! x)
- else if (GetStartDelayTime() <= 0 && !(m_Events & 0x10))
- {
- UpdateWorldState(AV_SHOW_H_SCORE, 1);
- UpdateWorldState(AV_SHOW_A_SCORE, 1);
- m_Events |= 0x10;
-
- SendMessageToAll(LANG_BG_AV_STARTED, CHAT_MSG_BG_SYSTEM_NEUTRAL);
- PlaySoundToAll(SOUND_BG_START);
- SetStatus(STATUS_IN_PROGRESS);
-
- sLog.outDebug("BG_AV: start spawning mine stuff");
- for(uint16 i= BG_AV_OBJECT_MINE_SUPPLY_N_MIN; i<=BG_AV_OBJECT_MINE_SUPPLY_N_MAX;i++)
- SpawnBGObject(i,RESPAWN_IMMEDIATELY);
- for(uint16 i= BG_AV_OBJECT_MINE_SUPPLY_S_MIN; i<=BG_AV_OBJECT_MINE_SUPPLY_S_MAX;i++)
- SpawnBGObject(i,RESPAWN_IMMEDIATELY);
- for(uint8 mine = AV_NORTH_MINE; mine <= AV_SOUTH_MINE; mine++) //mine population
- ChangeMineOwner(mine, AV_NEUTRAL_TEAM,true);
- DoorOpen(BG_AV_OBJECT_DOOR_H);
- DoorOpen(BG_AV_OBJECT_DOOR_A);
-
-
- for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
- if(Player* plr = objmgr.GetPlayer(itr->first))
- plr->RemoveAurasDueToSpell(SPELL_PREPARATION);
- }
- }
- else if(GetStatus() == STATUS_IN_PROGRESS)
+ if(GetStatus() == STATUS_IN_PROGRESS)
{
for(uint8 i=0; i<=1;i++)//0=alliance, 1=horde
{
@@ -470,10 +360,25 @@ void BattleGroundAV::Update(uint32 diff)
void BattleGroundAV::StartingEventCloseDoors()
{
+ DoorClose(BG_AV_OBJECT_DOOR_A);
+ DoorClose(BG_AV_OBJECT_DOOR_H);
}
void BattleGroundAV::StartingEventOpenDoors()
{
+ sLog.outDebug("BG_AV: start spawning mine stuff");
+ for(uint16 i= BG_AV_OBJECT_MINE_SUPPLY_N_MIN; i<=BG_AV_OBJECT_MINE_SUPPLY_N_MAX;i++)
+ SpawnBGObject(i,RESPAWN_IMMEDIATELY);
+ for(uint16 i= BG_AV_OBJECT_MINE_SUPPLY_S_MIN; i<=BG_AV_OBJECT_MINE_SUPPLY_S_MAX;i++)
+ SpawnBGObject(i,RESPAWN_IMMEDIATELY);
+ for(uint8 mine = AV_NORTH_MINE; mine <= AV_SOUTH_MINE; mine++) //mine population
+ ChangeMineOwner(mine, AV_NEUTRAL_TEAM,true);
+
+ UpdateWorldState(AV_SHOW_H_SCORE, 1);
+ UpdateWorldState(AV_SHOW_A_SCORE, 1);
+
+ DoorOpen(BG_AV_OBJECT_DOOR_H);
+ DoorOpen(BG_AV_OBJECT_DOOR_A);
}
void BattleGroundAV::AddPlayer(Player *plr)
@@ -584,8 +489,7 @@ void BattleGroundAV::HandleAreaTrigger(Player *Source, uint32 Trigger)
void BattleGroundAV::UpdatePlayerScore(Player* Source, uint32 type, uint32 value)
{
- std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID());
-
+ BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID());
if(itr == m_PlayerScores.end()) // player not found...
return;
@@ -1234,7 +1138,7 @@ bool BattleGroundAV::SetupBattleGround()
return false;
}
-//spawn node-objects
+ //spawn node-objects
for (uint8 i = BG_AV_NODES_FIRSTAID_STATION ; i < BG_AV_NODES_MAX; ++i)
{
if( i <= BG_AV_NODES_FROSTWOLF_HUT )
@@ -1345,6 +1249,58 @@ bool BattleGroundAV::SetupBattleGround()
return false;
}
}
+
+ uint16 i;
+ sLog.outDebug("Alterac Valley: entering state STATUS_WAIT_JOIN ...");
+ // Initial Nodes
+ for(i = 0; i < BG_AV_OBJECT_MAX; i++)
+ SpawnBGObject(i, RESPAWN_ONE_DAY);
+ for(i = BG_AV_OBJECT_FLAG_A_FIRSTAID_STATION; i <= BG_AV_OBJECT_FLAG_A_STONEHEART_GRAVE ; i++){
+ SpawnBGObject(BG_AV_OBJECT_AURA_A_FIRSTAID_STATION+3*i,RESPAWN_IMMEDIATELY);
+ SpawnBGObject(i, RESPAWN_IMMEDIATELY);
+ }
+ for(i = BG_AV_OBJECT_FLAG_A_DUNBALDAR_SOUTH; i <= BG_AV_OBJECT_FLAG_A_STONEHEART_BUNKER ; i++)
+ SpawnBGObject(i, RESPAWN_IMMEDIATELY);
+ for(i = BG_AV_OBJECT_FLAG_H_ICEBLOOD_GRAVE; i <= BG_AV_OBJECT_FLAG_H_FROSTWOLF_WTOWER ; i++){
+ SpawnBGObject(i, RESPAWN_IMMEDIATELY);
+ if(i<=BG_AV_OBJECT_FLAG_H_FROSTWOLF_HUT)
+ SpawnBGObject(BG_AV_OBJECT_AURA_H_FIRSTAID_STATION+3*GetNodeThroughObject(i),RESPAWN_IMMEDIATELY);
+ }
+ for(i = BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH; i <= BG_AV_OBJECT_TFLAG_A_STONEHEART_BUNKER; i+=2)
+ {
+ SpawnBGObject(i, RESPAWN_IMMEDIATELY); //flag
+ SpawnBGObject(i+16, RESPAWN_IMMEDIATELY); //aura
+ }
+ for(i = BG_AV_OBJECT_TFLAG_H_ICEBLOOD_TOWER; i <= BG_AV_OBJECT_TFLAG_H_FROSTWOLF_WTOWER; i+=2)
+ {
+ SpawnBGObject(i, RESPAWN_IMMEDIATELY); //flag
+ SpawnBGObject(i+16, RESPAWN_IMMEDIATELY); //aura
+ }
+ //snowfall and the doors
+ for(i = BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE; i <= BG_AV_OBJECT_DOOR_A; i++)
+ SpawnBGObject(i, RESPAWN_IMMEDIATELY);
+ SpawnBGObject(BG_AV_OBJECT_AURA_N_SNOWFALL_GRAVE,RESPAWN_IMMEDIATELY);
+
+ //creatures
+ sLog.outDebug("BG_AV start poputlating nodes");
+ for(BG_AV_Nodes i= BG_AV_NODES_FIRSTAID_STATION; i < BG_AV_NODES_MAX; ++i )
+ {
+ if(m_Nodes[i].Owner)
+ PopulateNode(i);
+ }
+ //all creatures which don't get despawned through the script are static
+ sLog.outDebug("BG_AV: start spawning static creatures");
+ for(i=0; i < AV_STATICCPLACE_MAX; i++ )
+ AddAVCreature(0,i+AV_CPLACE_MAX);
+ //mainspiritguides:
+ sLog.outDebug("BG_AV: start spawning spiritguides creatures");
+ AddSpiritGuide(7, BG_AV_CreaturePos[7][0], BG_AV_CreaturePos[7][1], BG_AV_CreaturePos[7][2], BG_AV_CreaturePos[7][3], ALLIANCE);
+ AddSpiritGuide(8, BG_AV_CreaturePos[8][0], BG_AV_CreaturePos[8][1], BG_AV_CreaturePos[8][2], BG_AV_CreaturePos[8][3], HORDE);
+ //spawn the marshals (those who get deleted, if a tower gets destroyed)
+ sLog.outDebug("BG_AV: start spawning marshal creatures");
+ for(i=AV_NPC_A_MARSHAL_SOUTH; i<= AV_NPC_H_MARSHAL_WTOWER; i++)
+ AddAVCreature(i,AV_CPLACE_A_MARSHAL_SOUTH+(i-AV_NPC_A_MARSHAL_SOUTH));
+ AddAVCreature(AV_NPC_HERALD,AV_CPLACE_HERALD);
return true;
}
@@ -1378,10 +1334,26 @@ const char* BattleGroundAV::GetNodeName(BG_AV_Nodes node)
void BattleGroundAV::AssaultNode(BG_AV_Nodes node, uint16 team)
{
- assert(m_Nodes[node].TotalOwner != team);
- assert(m_Nodes[node].Owner != team);
- assert(m_Nodes[node].State != POINT_DESTROYED);
- assert(m_Nodes[node].State != POINT_ASSAULTED || !m_Nodes[node].TotalOwner ); //only assault an assaulted node if no totalowner exists
+ if (m_Nodes[node].TotalOwner == team)
+ {
+ sLog.outCrash("Assaulting team is TotalOwner of node");
+ assert (false);
+ }
+ if (m_Nodes[node].Owner == team)
+ {
+ sLog.outCrash("Assaulting team is owner of node");
+ assert (false);
+ }
+ if (m_Nodes[node].State == POINT_DESTROYED)
+ {
+ sLog.outCrash("Destroyed node is being assaulted");
+ assert (false);
+ }
+ if (m_Nodes[node].State == POINT_ASSAULTED && m_Nodes[node].TotalOwner) //only assault an assaulted node if no totalowner exists
+ {
+ sLog.outCrash("Assault on an not assaulted node with total owner");
+ assert (false);
+ }
//the timer gets another time, if the previous owner was 0==Neutral
m_Nodes[node].Timer = (m_Nodes[node].PrevOwner)? BG_AV_CAPTIME : BG_AV_SNOWFALL_FIRSTCAP;
m_Nodes[node].PrevOwner = m_Nodes[node].Owner;
diff --git a/src/game/BattleGroundBE.cpp b/src/game/BattleGroundBE.cpp
index d58c2250948..05475328b01 100644
--- a/src/game/BattleGroundBE.cpp
+++ b/src/game/BattleGroundBE.cpp
@@ -182,8 +182,7 @@ bool BattleGroundBE::SetupBattleGround()
void BattleGroundBE::UpdatePlayerScore(Player* Source, uint32 type, uint32 value)
{
- std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID());
-
+ BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID());
if(itr == m_PlayerScores.end()) // player not found...
return;
diff --git a/src/game/BattleGroundEY.cpp b/src/game/BattleGroundEY.cpp
index 9b54ecce643..78654677230 100644
--- a/src/game/BattleGroundEY.cpp
+++ b/src/game/BattleGroundEY.cpp
@@ -128,7 +128,7 @@ void BattleGroundEY::StartingEventOpenDoors()
void BattleGroundEY::AddPoints(uint32 Team, uint32 Points)
{
- uint8 team_index = GetTeamIndexByTeamId(Team);
+ BattleGroundTeamId team_index = GetTeamIndexByTeamId(Team);
m_TeamScores[team_index] += Points;
m_HonorScoreTics[team_index] += Points;
if (m_HonorScoreTics[team_index] >= m_HonorTics )
@@ -788,8 +788,7 @@ void BattleGroundEY::EventPlayerCapturedFlag(Player *Source, uint32 BgObjectType
void BattleGroundEY::UpdatePlayerScore(Player *Source, uint32 type, uint32 value)
{
- std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID());
-
+ BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID());
if(itr == m_PlayerScores.end()) // player not found
return;
@@ -908,3 +907,12 @@ WorldSafeLocsEntry const *BattleGroundEY::GetClosestGraveYard(Player* player)
return nearestEntry;
}
+bool BattleGroundEY::IsAllNodesConrolledByTeam(uint32 team) const
+{
+ uint32 count = 0;
+ for(int i = 0; i < EY_POINTS_MAX; ++i)
+ if (m_PointOwnedByTeam[i] == team && m_PointState[i] == EY_POINT_UNDER_CONTROL)
+ ++count;
+
+ return count == EY_POINTS_MAX;
+}
diff --git a/src/game/BattleGroundEY.h b/src/game/BattleGroundEY.h
index a22d6ecc6db..3385a06bfb0 100644
--- a/src/game/BattleGroundEY.h
+++ b/src/game/BattleGroundEY.h
@@ -350,6 +350,8 @@ class BattleGroundEY : public BattleGround
virtual void EventPlayerClickedOnFlag(Player *Source, GameObject* target_obj);
virtual void EventPlayerDroppedFlag(Player *Source);
+ /* achievement req. */
+ bool IsAllNodesConrolledByTeam(uint32 team) const;
private:
void EventPlayerCapturedFlag(Player *Source, uint32 BgObjectType);
void EventTeamCapturedPoint(Player *Source, uint32 Point);
@@ -369,7 +371,6 @@ class BattleGroundEY : public BattleGround
void RemovePoint(uint32 TeamID, uint32 Points = 1) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] -= Points; }
void SetTeamPoint(uint32 TeamID, uint32 Points = 0) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] = Points; }
- uint32 m_TeamScores[2];
uint32 m_HonorScoreTics[2];
uint32 m_TeamPointsCount[2];
diff --git a/src/game/BattleGroundHandler.cpp b/src/game/BattleGroundHandler.cpp
index c8bc2bc4ecf..497db2ceadd 100644
--- a/src/game/BattleGroundHandler.cpp
+++ b/src/game/BattleGroundHandler.cpp
@@ -448,7 +448,8 @@ void WorldSession::HandleBattleFieldPortOpcode( WorldPacket &recv_data )
if (_player->isInFlight())
{
_player->GetMotionMaster()->MovementExpired();
- _player->m_taxi.ClearTaxiDestinations();
+ _player->CleanupAfterTaxiFlight();
+
}
sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType());
diff --git a/src/game/BattleGroundMgr.cpp b/src/game/BattleGroundMgr.cpp
index 371c204717d..d70aa52a018 100644
--- a/src/game/BattleGroundMgr.cpp
+++ b/src/game/BattleGroundMgr.cpp
@@ -1349,7 +1349,7 @@ void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
*data << (int32)(bg->GetPlayerScoresSize());
- for(std::map<uint64, BattleGroundScore*>::const_iterator itr = bg->GetPlayerScoresBegin(); itr != bg->GetPlayerScoresEnd(); ++itr)
+ for(BattleGround::BattleGroundScoreMap::const_iterator itr = bg->GetPlayerScoresBegin(); itr != bg->GetPlayerScoresEnd(); ++itr)
{
*data << (uint64)itr->first;
*data << (int32)itr->second->KillingBlows;
@@ -1474,6 +1474,8 @@ BattleGround * BattleGroundMgr::GetBattleGroundThroughClientInstance(uint32 inst
BattleGround * BattleGroundMgr::GetBattleGround(uint32 InstanceID, BattleGroundTypeId bgTypeId)
{
+ if (!InstanceID)
+ return NULL;
//search if needed
BattleGroundSet::iterator itr;
if (bgTypeId == BATTLEGROUND_TYPE_NONE)
diff --git a/src/game/BattleGroundSA.cpp b/src/game/BattleGroundSA.cpp
index 5f20950070d..acf16ad3af0 100644
--- a/src/game/BattleGroundSA.cpp
+++ b/src/game/BattleGroundSA.cpp
@@ -72,8 +72,7 @@ void BattleGroundSA::HandleAreaTrigger(Player * /*Source*/, uint32 /*Trigger*/)
void BattleGroundSA::UpdatePlayerScore(Player* Source, uint32 type, uint32 value)
{
- std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID());
-
+ BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID());
if(itr == m_PlayerScores.end()) // player not found...
return;
diff --git a/src/game/BattleGroundWS.cpp b/src/game/BattleGroundWS.cpp
index c4a2402ad67..81080284b9d 100644
--- a/src/game/BattleGroundWS.cpp
+++ b/src/game/BattleGroundWS.cpp
@@ -719,8 +719,7 @@ void BattleGroundWS::HandleKillPlayer(Player *player, Player *killer)
void BattleGroundWS::UpdatePlayerScore(Player *Source, uint32 type, uint32 value)
{
- std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID());
-
+ BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID());
if(itr == m_PlayerScores.end()) // player not found
return;
diff --git a/src/game/BattleGroundWS.h b/src/game/BattleGroundWS.h
index 7395c3a5bb9..16631afecdc 100644
--- a/src/game/BattleGroundWS.h
+++ b/src/game/BattleGroundWS.h
@@ -200,12 +200,10 @@ class BattleGroundWS : public BattleGround
void AddPoint(uint32 TeamID, uint32 Points = 1) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] += Points; }
void SetTeamPoint(uint32 TeamID, uint32 Points = 0) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] = Points; }
void RemovePoint(uint32 TeamID, uint32 Points = 1) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] -= Points; }
-
private:
uint64 m_FlagKeepers[2]; // 0 - alliance, 1 - horde
uint64 m_DroppedFlagGUID[2];
uint8 m_FlagState[2]; // for checking flag state
- uint32 m_TeamScores[2];
int32 m_FlagsTimer[2];
int32 m_FlagsDropTimer[2];
diff --git a/src/game/CMakeLists.txt b/src/game/CMakeLists.txt
index bb05b4d6076..7132d89d983 100644
--- a/src/game/CMakeLists.txt
+++ b/src/game/CMakeLists.txt
@@ -56,8 +56,9 @@ SET(game_STAT_SRCS
Channel.cpp
Channel.h
ChannelHandler.cpp
- ChannelMgr.h
CharacterHandler.cpp
+ ChannelMgr.h
+ ChannelMgr.cpp
Chat.cpp
Chat.h
ChatHandler.cpp
diff --git a/src/game/Channel.cpp b/src/game/Channel.cpp
index 9bb3463dbdb..ae7e4d17352 100644
--- a/src/game/Channel.cpp
+++ b/src/game/Channel.cpp
@@ -23,9 +23,10 @@
#include "SocialMgr.h"
#include "World.h"
-Channel::Channel(const std::string& name, uint32 channel_id)
-: m_announce(true), m_moderate(false), m_name(name), m_flags(0), m_channelId(channel_id), m_ownerGUID(0)
+Channel::Channel(const std::string& name, uint32 channel_id, uint32 Team)
+ : m_name(name), m_announce(true), m_moderate(false), m_channelId(channel_id), m_ownerGUID(0), m_password(""), m_flags(0)
{
+ m_Team = Team;
// set special flags if built-in channel
ChatChannelsEntry const* ch = GetChannelEntryFor(channel_id);
if(ch) // it's built-in channel
@@ -45,10 +46,54 @@ Channel::Channel(const std::string& name, uint32 channel_id)
m_flags |= CHANNEL_FLAG_LFG;
else // for all other channels
m_flags |= CHANNEL_FLAG_NOT_LFG;
+ m_IsSaved = false;
}
else // it's custom channel
{
m_flags |= CHANNEL_FLAG_CUSTOM;
+ //load not built in channel if saved
+ QueryResult *result = CharacterDatabase.PQuery("SELECT m_name, m_team, m_ownerGUID, m_announce, m_moderate, m_password, BannedList FROM channels WHERE m_name = '%s' AND m_team = '%u'", name.c_str(), m_Team);
+ if (result)//load
+ {
+ Field *fields = result->Fetch();
+ const char* db_name = fields[0].GetString();
+ uint32 db_team = fields[1].GetUInt32();
+ uint64 db_owner = fields[2].GetUInt64();
+ bool db_announce = fields[3].GetBool();
+ bool db_moderate = fields[4].GetBool();
+ const char* db_password = fields[5].GetString();
+ const char* db_BannedList = fields[6].GetString();
+
+ m_ownerGUID = db_owner;
+ m_announce = db_announce;
+ m_moderate = db_moderate;
+ m_password = db_password;
+ m_IsSaved = true;
+
+ if(db_BannedList)
+ {
+ Tokens tokens = StrSplit(db_BannedList, " ");
+ Tokens::iterator iter;
+ for (iter = tokens.begin();iter != tokens.end(); ++iter)
+ {
+ uint64 banned_guid = atol((*iter).c_str());
+ if(banned_guid)
+ {
+ sLog.outDebug("Channel(%s) loaded banned guid: %u",name.c_str(), banned_guid);
+ banned.insert(banned_guid);
+ }
+ }
+ }
+ }else{//save
+ std::ostringstream ss;
+ ss << "INSERT INTO channels (m_name,m_team,m_ownerGUID,m_announce,m_moderate,m_password) VALUES ('"
+ << name.c_str() << "','" << m_Team << "','0','1','0','')";
+ if(CharacterDatabase.PExecute( ss.str( ).c_str( ) ))
+ {
+ sLog.outDebug("New Channel(%s) saved", name.c_str());
+ m_IsSaved = true;
+ }
+ }
}
}
@@ -120,6 +165,10 @@ void Channel::Join(uint64 p, const char *pass)
if(!IsConstant() && !m_ownerGUID)
{
SetOwner(p, (players.size() > 1 ? true : false));
+ players[p].SetModerator(true);
+ }else if(!IsConstant() && m_ownerGUID && plr && m_ownerGUID == plr->GetGUID())
+ {
+ SetOwner(p, (players.size() > 1 ? true : false));
players[p].SetModerator(true);
}
}
@@ -161,7 +210,7 @@ void Channel::Leave(uint64 p, bool send)
LeaveNotify(p);
- if(changeowner)
+ if(changeowner && !m_IsSaved)
{
uint64 newowner = !players.empty() ? players.begin()->second.player : 0;
SetOwner(newowner);
@@ -213,6 +262,23 @@ void Channel::KickOrBan(uint64 good, const char *badname, bool ban)
{
banned.insert(bad->GetGUID());
MakePlayerBanned(&data, bad->GetGUID(), good);
+ //save banlist
+ if(m_IsSaved)
+ {
+ std::ostringstream banlist;
+ BannedList::iterator iter;
+ for (iter = banned.begin();iter != banned.end(); ++iter)
+ {
+ banlist << (*iter) << " ";
+ }
+ std::ostringstream ss;
+ ss << "UPDATE channels SET BannedList = '" << banlist.str().c_str() << "' WHERE m_name = '"<<m_name.c_str()<<"' AND m_team = '"<<m_Team<<"'";
+ if(CharacterDatabase.PExecute( ss.str( ).c_str( ) ))
+ {
+ sLog.outDebug("Channel(%s) BannedList saved", m_name.c_str());
+ }
+ }
+
}
else
MakePlayerKicked(&data, bad->GetGUID(), good);
@@ -265,6 +331,22 @@ void Channel::UnBan(uint64 good, const char *badname)
WorldPacket data;
MakePlayerUnbanned(&data, bad->GetGUID(), good);
SendToAll(&data);
+ //save banlist
+ if(m_IsSaved)
+ {
+ std::ostringstream banlist;
+ BannedList::iterator iter;
+ for (iter = banned.begin();iter != banned.end(); ++iter)
+ {
+ banlist << (*iter) << " ";
+ }
+ std::ostringstream ss;
+ ss << "UPDATE channels SET BannedList = '" << banlist.str().c_str() << "' WHERE m_name = '"<<m_name.c_str()<<"' AND m_team = '"<<m_Team<<"'";
+ if(CharacterDatabase.PExecute( ss.str( ).c_str( ) ))
+ {
+ sLog.outDebug("Channel(%s) BannedList saved", m_name.c_str());
+ }
+ }
}
}
}
@@ -295,6 +377,15 @@ void Channel::Password(uint64 p, const char *pass)
WorldPacket data;
MakePasswordChanged(&data, p);
SendToAll(&data);
+ if(m_IsSaved)
+ {
+ std::ostringstream ss;
+ ss << "UPDATE channels SET m_password = '" << pass << "' WHERE m_name = '"<<m_name.c_str()<<"' AND m_team = '"<<m_Team<<"'";
+ if(CharacterDatabase.PExecute( ss.str( ).c_str( ) ))
+ {
+ sLog.outDebug("Channel(%s) password saved", m_name.c_str());
+ }
+ }
}
}
@@ -448,7 +539,7 @@ void Channel::List(Player* player)
size_t pos = data.wpos();
data << uint32(0); // size of list, placeholder
- bool gmInWhoList = sWorld.getConfig(CONFIG_GM_IN_WHO_LIST) || player->GetSession()->GetSecurity() > SEC_PLAYER;
+ uint32 gmLevelInWhoList = sWorld.getConfig(CONFIG_GM_LEVEL_IN_WHO_LIST);
uint32 count = 0;
for(PlayerList::const_iterator i = players.begin(); i != players.end(); ++i)
@@ -457,7 +548,8 @@ void Channel::List(Player* player)
// PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters
// MODERATOR, GAME MASTER, ADMINISTRATOR can see all
- if (plr && ( plr->GetSession()->GetSecurity() == SEC_PLAYER || (gmInWhoList && plr->IsVisibleGloballyFor(player))))
+ if (plr && (player->GetSession()->GetSecurity() > SEC_PLAYER || plr->GetSession()->GetSecurity() <= gmLevelInWhoList) &&
+ plr->IsVisibleGloballyFor(player))
{
data << uint64(i->first);
data << uint8(i->second.flags); // flags seems to be changed...
@@ -500,6 +592,16 @@ void Channel::Announce(uint64 p)
else
MakeAnnouncementsOff(&data, p);
SendToAll(&data);
+ if(m_IsSaved)
+ {
+ std::ostringstream ss;
+ ss << "UPDATE channels SET m_announce = '" << m_announce << "' WHERE m_name = '"<<m_name.c_str()<<"' AND m_team = '"<<m_Team<<"'";
+ if(CharacterDatabase.PExecute( ss.str( ).c_str( ) ))
+ {
+ sLog.outDebug("Channel(%s) announce saved", m_name.c_str());
+ }
+ }
+
}
}
@@ -532,6 +634,15 @@ void Channel::Moderate(uint64 p)
else
MakeModerationOff(&data, p);
SendToAll(&data);
+ if(m_IsSaved)
+ {
+ std::ostringstream ss;
+ ss << "UPDATE channels SET m_moderate = '" << m_moderate << "' WHERE m_name = '"<<m_name.c_str()<<"' AND m_team = '"<<m_Team<<"'";
+ if(CharacterDatabase.PExecute( ss.str( ).c_str( ) ))
+ {
+ sLog.outDebug("Channel(%s) moderate saved", m_name.c_str());
+ }
+ }
}
}
@@ -659,6 +770,16 @@ void Channel::SetOwner(uint64 guid, bool exclaim)
MakeOwnerChanged(&data, m_ownerGUID);
SendToAll(&data);
}
+ if(m_IsSaved)
+ {
+ std::ostringstream ss;
+ ss << "UPDATE channels SET m_ownerGUID = '" << guid << "' WHERE m_name = '"<<m_name.c_str()<<"' AND m_team = '"<<m_Team<<"'";
+ if(CharacterDatabase.PExecute( ss.str( ).c_str( ) ))
+ {
+ sLog.outDebug("Channel(%s) owner saved", m_name.c_str());
+ }
+ }
+
}
}
diff --git a/src/game/Channel.h b/src/game/Channel.h
index c2dd5ecd3ac..69a1e2f66f6 100644
--- a/src/game/Channel.h
+++ b/src/game/Channel.h
@@ -158,6 +158,7 @@ class Channel
uint8 m_flags;
uint32 m_channelId;
uint64 m_ownerGUID;
+ bool m_IsSaved;
private:
// initial packet data (notify type and channel name)
@@ -243,7 +244,8 @@ class Channel
}
public:
- Channel(const std::string& name, uint32 channel_id);
+ uint32 m_Team;
+ Channel(const std::string& name, uint32 channel_id, uint32 Team = 0);
std::string GetName() const { return m_name; }
uint32 GetChannelId() const { return m_channelId; }
bool IsConstant() const { return m_channelId != 0; }
diff --git a/src/game/ChannelHandler.cpp b/src/game/ChannelHandler.cpp
index 45cdf8c20b2..e3c10afe81f 100644
--- a/src/game/ChannelHandler.cpp
+++ b/src/game/ChannelHandler.cpp
@@ -24,9 +24,6 @@
#include "ObjectMgr.h" // for normalizePlayerName
#include "ChannelMgr.h"
-INSTANTIATE_SINGLETON_1( AllianceChannelMgr );
-INSTANTIATE_SINGLETON_1( HordeChannelMgr );
-
void WorldSession::HandleJoinChannel(WorldPacket& recvPacket)
{
sLog.outDebug("Opcode %u", recvPacket.GetOpcode());
@@ -48,8 +45,11 @@ void WorldSession::HandleJoinChannel(WorldPacket& recvPacket)
recvPacket >> pass;
if(ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
+ {
+ cMgr->team = _player->GetTeam();
if(Channel *chn = cMgr->GetJoinChannel(channelname, channel_id))
chn->Join(_player->GetGUID(), pass.c_str());
+ }
}
void WorldSession::HandleLeaveChannel(WorldPacket& recvPacket)
diff --git a/src/game/ChannelMgr.cpp b/src/game/ChannelMgr.cpp
new file mode 100644
index 00000000000..09d172155cc
--- /dev/null
+++ b/src/game/ChannelMgr.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "ChannelMgr.h"
+#include "Policies/SingletonImp.h"
+#include "World.h"
+
+INSTANTIATE_SINGLETON_1( AllianceChannelMgr );
+INSTANTIATE_SINGLETON_1( HordeChannelMgr );
+
+ChannelMgr* channelMgr(uint32 team)
+{
+ if (sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL))
+ return &MaNGOS::Singleton<AllianceChannelMgr>::Instance(); // cross-faction
+
+ if(team == ALLIANCE)
+ return &MaNGOS::Singleton<AllianceChannelMgr>::Instance();
+ if(team == HORDE)
+ return &MaNGOS::Singleton<HordeChannelMgr>::Instance();
+
+ return NULL;
+}
+
+ChannelMgr::~ChannelMgr()
+{
+ for(ChannelMap::iterator itr = channels.begin();itr!=channels.end(); ++itr)
+ delete itr->second;
+
+ channels.clear();
+}
+
+Channel *ChannelMgr::GetJoinChannel(std::string name, uint32 channel_id)
+{
+ if (channels.find(name) == channels.end())
+ {
+ Channel *nchan = new Channel(name,channel_id, team);
+ channels[name] = nchan;
+ }
+
+ return channels[name];
+}
+
+Channel *ChannelMgr::GetChannel(std::string name, Player *p, bool pkt)
+{
+ ChannelMap::const_iterator i = channels.find(name);
+
+ if(i == channels.end())
+ {
+ if(pkt)
+ {
+ WorldPacket data;
+ MakeNotOnPacket(&data,name);
+ p->GetSession()->SendPacket(&data);
+ }
+
+ return NULL;
+ }
+ else
+ return i->second;
+}
+
+void ChannelMgr::LeftChannel(std::string name)
+{
+ ChannelMap::const_iterator i = channels.find(name);
+
+ if(i == channels.end())
+ return;
+
+ Channel* channel = i->second;
+
+ if(channel->GetNumPlayers() == 0 && !channel->IsConstant())
+ {
+ channels.erase(name);
+ delete channel;
+ }
+}
+
+void ChannelMgr::MakeNotOnPacket(WorldPacket *data, std::string name)
+{
+ data->Initialize(SMSG_CHANNEL_NOTIFY, (1+10)); // we guess size
+ (*data) << (uint8)0x05 << name;
+}
diff --git a/src/game/ChannelMgr.h b/src/game/ChannelMgr.h
index aeecfbfa541..f65a8520648 100644
--- a/src/game/ChannelMgr.h
+++ b/src/game/ChannelMgr.h
@@ -17,8 +17,12 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef TRINITYCORE_CHANNELMGR_H
-#define TRINITYCORE_CHANNELMGR_H
+#ifndef MANGOSSERVER_CHANNELMGR_H
+#define MANGOSSERVER_CHANNELMGR_H
+
+#include "Common.h"
+#include "Channel.h"
+#include "Policies/Singleton.h"
#include <map>
#include <string>
@@ -31,75 +35,23 @@
class ChannelMgr
{
public:
+ uint32 team;
typedef std::map<std::string,Channel *> ChannelMap;
- ChannelMgr() {}
- ~ChannelMgr()
- {
- for(ChannelMap::const_iterator itr = channels.begin();itr!=channels.end(); ++itr)
- delete itr->second;
- channels.clear();
- }
- Channel *GetJoinChannel(const std::string& name, uint32 channel_id)
- {
- if (channels.find(name) == channels.end())
- {
- Channel *nchan = new Channel(name,channel_id);
- channels[name] = nchan;
- }
- return channels[name];
- }
- Channel *GetChannel(const std::string& name, Player *p)
- {
- ChannelMap::const_iterator i = channels.find(name);
-
- if(i == channels.end())
- {
- WorldPacket data;
- MakeNotOnPacket(&data,name);
- p->GetSession()->SendPacket(&data);
- return NULL;
- }
- else
- return i->second;
- }
- void LeftChannel(const std::string& name)
- {
- ChannelMap::const_iterator i = channels.find(name);
+ ChannelMgr() {team = 0;}
+ ~ChannelMgr();
- if(i == channels.end())
- return;
-
- Channel* channel = i->second;
-
- if(channel->GetNumPlayers() == 0 && !channel->IsConstant())
- {
- channels.erase(name);
- delete channel;
- }
- }
+ Channel *GetJoinChannel(std::string name, uint32 channel_id);
+ Channel *GetChannel(std::string name, Player *p, bool pkt = true);
+ void LeftChannel(std::string name);
private:
ChannelMap channels;
- void MakeNotOnPacket(WorldPacket *data, const std::string& name)
- {
- data->Initialize(SMSG_CHANNEL_NOTIFY, (1+10)); // we guess size
- (*data) << (uint8)0x05 << name;
- }
+ void MakeNotOnPacket(WorldPacket *data, std::string name);
};
class AllianceChannelMgr : public ChannelMgr {};
class HordeChannelMgr : public ChannelMgr {};
-inline ChannelMgr* channelMgr(uint32 team)
-{
- if (sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL))
- //For Test,No Seprate Faction
- return &Trinity::Singleton<AllianceChannelMgr>::Instance();
+ChannelMgr* channelMgr(uint32 team);
- if(team==ALLIANCE)
- return &Trinity::Singleton<AllianceChannelMgr>::Instance();
- if(team==HORDE)
- return &Trinity::Singleton<HordeChannelMgr>::Instance();
- return NULL;
-}
#endif
diff --git a/src/game/CharacterHandler.cpp b/src/game/CharacterHandler.cpp
index 84b830651e7..056bcd816e0 100644
--- a/src/game/CharacterHandler.cpp
+++ b/src/game/CharacterHandler.cpp
@@ -64,7 +64,7 @@ bool LoginQueryHolder::Initialize()
// NOTE: all fields in `characters` must be read to prevent lost character data at next save in case wrong DB structure.
// !!! NOTE: including unused `zone`,`online`
- res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADFROM, "SELECT guid, account, data, name, race, class, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty, arena_pending_points,bgid,bgteam,bgmap,bgx,bgy,bgz,bgo,instance_id FROM characters WHERE guid = '%u'", GUID_LOPART(m_guid));
+ res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADFROM, "SELECT guid, account, data, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty, arena_pending_points,instance_id,bgteam,bgmap,bgx,bgy,bgz,bgo FROM characters WHERE guid = '%u'", GUID_LOPART(m_guid));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGROUP, "SELECT leaderGuid FROM group_member WHERE memberGuid ='%u'", GUID_LOPART(m_guid));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES, "SELECT id, permanent, map, difficulty, resettime FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = '%u'", GUID_LOPART(m_guid));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADAURAS, "SELECT caster_guid,spell,effect_mask,stackcount,amount0, amount1, amount2 ,maxduration,remaintime,remaincharges FROM character_aura WHERE guid = '%u'", GUID_LOPART(m_guid));
@@ -73,7 +73,7 @@ bool LoginQueryHolder::Initialize()
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS,"SELECT quest,time FROM character_queststatus_daily WHERE guid = '%u'", GUID_LOPART(m_guid));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADREPUTATION, "SELECT faction,standing,flags FROM character_reputation WHERE guid = '%u'", GUID_LOPART(m_guid));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADINVENTORY, "SELECT data,bag,slot,item,item_template FROM character_inventory JOIN item_instance ON character_inventory.item = item_instance.guid WHERE character_inventory.guid = '%u' ORDER BY bag,slot", GUID_LOPART(m_guid));
- res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADACTIONS, "SELECT button,action,type,misc FROM character_action WHERE guid = '%u' ORDER BY button", GUID_LOPART(m_guid));
+ res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADACTIONS, "SELECT button,action,type FROM character_action WHERE guid = '%u' ORDER BY button", GUID_LOPART(m_guid));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADMAILCOUNT, "SELECT COUNT(id) FROM mail WHERE receiver = '%u' AND (checked & 1)=0 AND deliver_time <= '" UI64FMTD "'", GUID_LOPART(m_guid),(uint64)time(NULL));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADMAILDATE, "SELECT MIN(deliver_time) FROM mail WHERE receiver = '%u' AND (checked & 1)=0", GUID_LOPART(m_guid));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSOCIALLIST, "SELECT friend,flags,note FROM character_social WHERE guid = '%u' LIMIT 255", GUID_LOPART(m_guid));
@@ -123,7 +123,7 @@ class CharacterHandler
void WorldSession::HandleCharEnum(QueryResult * result)
{
// keys can be non cleared if player open realm list and close it by 'cancel'
- LoginDatabase.PExecute("UPDATE account SET v = '0', s = '0' WHERE id = '%u'", GetAccountId());
+ loginDatabase.PExecute("UPDATE account SET v = '0', s = '0' WHERE id = '%u'", GetAccountId());
WorldPacket data(SMSG_CHAR_ENUM, 100); // we guess size
@@ -133,21 +133,15 @@ void WorldSession::HandleCharEnum(QueryResult * result)
if( result )
{
- Player *plr = new Player(this);
do
{
uint32 guidlow = (*result)[0].GetUInt32();
sLog.outDetail("Loading char guid %u from account %u.",guidlow,GetAccountId());
-
- if(plr->MinimalLoadFromDB( result, guidlow ))
- {
- plr->BuildEnumData( result, &data );
+ if(Player::BuildEnumData(result, &data))
++num;
- }
}
while( result->NextRow() );
- delete plr;
delete result;
}
@@ -162,19 +156,23 @@ void WorldSession::HandleCharEnumOpcode( WorldPacket & /*recv_data*/ )
CharacterDatabase.AsyncPQuery(&chrHandler, &CharacterHandler::HandleCharEnumCallback, GetAccountId(),
!sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) ?
// ------- Query Without Declined Names --------
- // 0 1 2 3 4 5 6 7 8
- "SELECT characters.guid, characters.data, characters.name, characters.position_x, characters.position_y, characters.position_z, characters.map, characters.totaltime, characters.leveltime, "
- // 9 10 11 12 13 14
- "characters.at_login, characters.zone, character_pet.entry, character_pet.modelid, character_pet.level, guild_member.guildid "
+ // 0 1 2 3 4 5 6 7
+ "SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.playerBytes, characters.playerBytes2, characters.level, "
+ // 8 9 10 11 12 13 14
+ "characters.zone, characters.map, characters.position_x, characters.position_y, characters.position_z, guild_member.guildid, characters.playerFlags, "
+ // 15 16 17 18 19
+ "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.data "
"FROM characters LEFT JOIN character_pet ON characters.guid=character_pet.owner AND character_pet.slot='%u' "
"LEFT JOIN guild_member ON characters.guid = guild_member.guid "
"WHERE characters.account = '%u' ORDER BY characters.guid"
:
// --------- Query With Declined Names ---------
- // 0 1 2 3 4 5 6 7 8
- "SELECT characters.guid, characters.data, characters.name, characters.position_x, characters.position_y, characters.position_z, characters.map, characters.totaltime, characters.leveltime, "
- // 9 10 11 12 13 14 15
- "characters.at_login, characters.zone, character_pet.entry, character_pet.modelid, character_pet.level, guild_member.guildid, character_declinedname.genitive "
+ // 0 1 2 3 4 5 6 7
+ "SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.playerBytes, characters.playerBytes2, characters.level, "
+ // 8 9 10 11 12 13 14
+ "characters.zone, characters.map, characters.position_x, characters.position_y, characters.position_z, guild_member.guildid, characters.playerFlags, "
+ // 15 16 17 18 19 20
+ "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.data, character_declinedname.genitive "
"FROM characters LEFT JOIN character_pet ON characters.guid = character_pet.owner AND character_pet.slot='%u' "
"LEFT JOIN character_declinedname ON characters.guid = character_declinedname.guid "
"LEFT JOIN guild_member ON characters.guid = guild_member.guid "
@@ -251,38 +249,39 @@ void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data )
}
// prevent character creating with invalid name
- if(!normalizePlayerName(name))
+ if (!normalizePlayerName(name))
{
- data << (uint8)CHAR_NAME_INVALID_CHARACTER;
+ data << (uint8)CHAR_NAME_NO_NAME;
SendPacket( &data );
sLog.outError("Account:[%d] but tried to Create character with empty [name] ",GetAccountId());
return;
}
// check name limitations
- if(!ObjectMgr::IsValidName(name,true))
+ uint8 res = ObjectMgr::CheckPlayerName(name,true);
+ if (res != CHAR_NAME_SUCCESS)
{
- data << (uint8)CHAR_NAME_INVALID_CHARACTER;
+ data << uint8(res);
SendPacket( &data );
return;
}
- if(GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(name))
+ if (GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(name))
{
data << (uint8)CHAR_NAME_RESERVED;
SendPacket( &data );
return;
}
- if(objmgr.GetPlayerGUIDByName(name))
+ if (objmgr.GetPlayerGUIDByName(name))
{
data << (uint8)CHAR_CREATE_NAME_IN_USE;
SendPacket( &data );
return;
}
- QueryResult *resultacct = LoginDatabase.PQuery("SELECT SUM(numchars) FROM realmcharacters WHERE acctid = '%d'", GetAccountId());
- if ( resultacct )
+ QueryResult *resultacct = loginDatabase.PQuery("SELECT SUM(numchars) FROM realmcharacters WHERE acctid = '%d'", GetAccountId());
+ if (resultacct)
{
Field *fields=resultacct->Fetch();
uint32 acctcharcount = fields[0].GetUInt32();
@@ -340,7 +339,7 @@ void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data )
if(!AllowTwoSideAccounts || skipCinematics == 1 || class_ == CLASS_DEATH_KNIGHT)
{
- QueryResult *result2 = CharacterDatabase.PQuery("SELECT guid,race,class FROM characters WHERE account = '%u' %s",
+ QueryResult *result2 = CharacterDatabase.PQuery("SELECT level,race,class FROM characters WHERE account = '%u' %s",
GetAccountId(), (skipCinematics == 1 || class_ == CLASS_DEATH_KNIGHT) ? "" : "LIMIT 1");
if(result2)
{
@@ -367,8 +366,7 @@ void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data )
if(!have_req_level_for_heroic)
{
- uint32 acc_guid = field[0].GetUInt32();
- uint32 acc_level = Player::GetUInt32ValueFromDB(UNIT_FIELD_LEVEL,acc_guid);
+ uint32 acc_level = field[0].GetUInt32();
if(acc_level >= req_level_for_heroic)
have_req_level_for_heroic = true;
}
@@ -422,8 +420,7 @@ void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data )
if(!have_req_level_for_heroic)
{
- uint32 acc_guid = field[0].GetUInt32();
- uint32 acc_level = Player::GetUInt32ValueFromDB(UNIT_FIELD_LEVEL,acc_guid);
+ uint32 acc_level = field[0].GetUInt32();
if(acc_level >= req_level_for_heroic)
have_req_level_for_heroic = true;
}
@@ -464,8 +461,8 @@ void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data )
pNewChar->SaveToDB();
charcount+=1;
- LoginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid= '%d' AND realmid = '%d'", GetAccountId(), realmID);
- LoginDatabase.PExecute("INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (%u, %u, %u)", charcount, GetAccountId(), realmID);
+ loginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid= '%d' AND realmid = '%d'", GetAccountId(), realmID);
+ loginDatabase.PExecute("INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (%u, %u, %u)", charcount, GetAccountId(), realmID);
delete pNewChar; // created only to call SaveToDB()
@@ -739,7 +736,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder)
pCurrChar->SendInitialPacketsAfterAddToMap();
CharacterDatabase.PExecute("UPDATE characters SET online = 1 WHERE guid = '%u'", pCurrChar->GetGUIDLow());
- LoginDatabase.PExecute("UPDATE account SET online = 1 WHERE id = '%u'", GetAccountId());
+ loginDatabase.PExecute("UPDATE account SET online = 1 WHERE id = '%u'", GetAccountId());
pCurrChar->SetInGameTime( getMSTime() );
// announce group about member online (must be after add to player list to receive announce to self)
@@ -815,6 +812,10 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder)
SendDoFlight( mountDisplayId, path, startNode );
}
+ // reset for all pets before pet loading
+ if(pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS))
+ Pet::resetTalentsForAllPetsOf(pCurrChar);
+
// Load pet if any (if player not alive and in taxi flight or another then pet will remember as temporary unsummoned)
pCurrChar->LoadPet();
@@ -835,6 +836,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder)
if(pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_TALENTS))
{
pCurrChar->resetTalents(true);
+ pCurrChar->SendTalentsInfoData(false); // original talents send already in to SendInitialPacketsBeforeAddToMap, resend reset state
SendNotification(LANG_RESET_TALENTS);
}
@@ -852,6 +854,9 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder)
sLog.outChar("Account: %d (IP: %s) Login Character:[%s] (guid:%u)",
GetAccountId(),IP_str.c_str(),pCurrChar->GetName() ,pCurrChar->GetGUIDLow());
+ if(!pCurrChar->IsStandState() && !pCurrChar->hasUnitState(UNIT_STAT_STUNNED))
+ pCurrChar->SetStandState(UNIT_STAND_STATE_STAND);
+
m_playerLoading = false;
delete holder;
}
@@ -985,7 +990,7 @@ void WorldSession::HandleCharRenameOpcode(WorldPacket& recv_data)
recv_data >> newname;
// prevent character rename to invalid name
- if(!normalizePlayerName(newname))
+ if (!normalizePlayerName(newname))
{
WorldPacket data(SMSG_CHAR_RENAME, 1);
data << uint8(CHAR_NAME_NO_NAME);
@@ -993,16 +998,17 @@ void WorldSession::HandleCharRenameOpcode(WorldPacket& recv_data)
return;
}
- if(!ObjectMgr::IsValidName(newname, true))
+ uint8 res = ObjectMgr::CheckPlayerName(newname,true);
+ if (res != CHAR_NAME_SUCCESS)
{
WorldPacket data(SMSG_CHAR_RENAME, 1);
- data << uint8(CHAR_NAME_INVALID_CHARACTER);
+ data << uint8(res);
SendPacket( &data );
return;
}
// check name limitations
- if(GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(newname))
+ if (GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(newname))
{
WorldPacket data(SMSG_CHAR_RENAME, 1);
data << uint8(CHAR_NAME_RESERVED);
@@ -1258,7 +1264,7 @@ void WorldSession::HandleCharCustomize(WorldPacket& recv_data)
}
// prevent character rename to invalid name
- if(!normalizePlayerName(newname))
+ if (!normalizePlayerName(newname))
{
WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
data << uint8(CHAR_NAME_NO_NAME);
@@ -1266,16 +1272,17 @@ void WorldSession::HandleCharCustomize(WorldPacket& recv_data)
return;
}
- if(!ObjectMgr::IsValidName(newname,true))
+ uint8 res = ObjectMgr::CheckPlayerName(newname,true);
+ if (res != CHAR_NAME_SUCCESS)
{
WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
- data << uint8(CHAR_NAME_INVALID_CHARACTER);
+ data << uint8(res);
SendPacket( &data );
return;
}
// check name limitations
- if(GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(newname))
+ if (GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(newname))
{
WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
data << uint8(CHAR_NAME_RESERVED);
@@ -1284,9 +1291,9 @@ void WorldSession::HandleCharCustomize(WorldPacket& recv_data)
}
// character with this name already exist
- if(uint64 newguid = objmgr.GetPlayerGUIDByName(newname))
+ if (uint64 newguid = objmgr.GetPlayerGUIDByName(newname))
{
- if(newguid != guid)
+ if (newguid != guid)
{
WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
data << uint8(CHAR_CREATE_NAME_IN_USE);
diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp
index d1e85f6baa0..06822627460 100644
--- a/src/game/Chat.cpp
+++ b/src/game/Chat.cpp
@@ -154,19 +154,21 @@ ChatCommand * ChatHandler::getCommandTable()
{ "anim", SEC_GAMEMASTER, false, &ChatHandler::HandleDebugAnimCommand, "", NULL },
{ "arena", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugArenaCommand, "", NULL },
{ "bg", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugBattlegroundCommand, "", NULL },
- { "getitemstate", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugGetItemState, "", NULL },
- { "lootrecipient", SEC_GAMEMASTER, false, &ChatHandler::HandleDebugGetLootRecipient, "", NULL },
- { "getvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugGetValue, "", NULL },
- { "Mod32Value", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugMod32Value, "", NULL },
+ { "getitemstate", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugGetItemStateCommand, "", NULL },
+ { "lootrecipient", SEC_GAMEMASTER, false, &ChatHandler::HandleDebugGetLootRecipientCommand, "", NULL },
+ { "getvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugGetValueCommand, "", NULL },
+ { "Mod32Value", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugMod32ValueCommand, "", NULL },
{ "play", SEC_MODERATOR, false, NULL, "", debugPlayCommandTable },
{ "send", SEC_ADMINISTRATOR, false, NULL, "", debugSendCommandTable },
+ { "setaurastate", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetAuraStateCommand, "", NULL },
{ "setitemflag", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetItemFlagCommand, "", NULL },
- { "setvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetValue, "", NULL },
+ { "setvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetValueCommand, "", NULL },
{ "spawnvehicle", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSpawnVehicle, "", NULL },
{ "setvid", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetVehicleId, "", NULL },
{ "entervehicle", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugEnterVehicle, "", NULL },
{ "uws", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugUpdateWorldStateCommand, "", NULL },
- { "update", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugUpdate, "", NULL },
+ { "update", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugUpdateCommand, "", NULL },
+ { "itemexpire", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugItemExpireCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
@@ -371,6 +373,7 @@ ChatCommand * ChatHandler::getCommandTable()
{ "tame", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcTameCommand, "", NULL },
{ "setdeathstate", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSetDeathStateCommand, "", NULL },
{ "addformation", SEC_MODERATOR, false, &ChatHandler::HandleNpcAddFormationCommand, "", NULL },
+ { "setlink", SEC_MODERATOR, false, &ChatHandler::HandleNpcSetLinkCommand, "", NULL },
//{ TODO: fix or remove this commands
{ "addweapon", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcAddWeaponCommand, "", NULL },
@@ -477,7 +480,6 @@ ChatCommand * ChatHandler::getCommandTable()
{ "skill_extra_item_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSkillExtraItemTemplateCommand, "", NULL },
{ "skill_fishing_base_level", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSkillFishingBaseLevelCommand, "", NULL },
{ "skinning_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesSkinningCommand, "", NULL },
- { "spell_affect", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellAffectCommand, "", NULL },
{ "spell_required", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellRequiredCommand, "", NULL },
{ "spell_area", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellAreaCommand, "", NULL },
{ "spell_bonus_data", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellBonusesCommand, "", NULL },
@@ -546,7 +548,6 @@ ChatCommand * ChatHandler::getCommandTable()
{
{ "cancel", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerShutDownCancelCommand,"", NULL },
{ "" , SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerShutDownCommand, "", NULL },
- { "setlink", SEC_MODERATOR, false, &ChatHandler::HandleNpcSetLinkCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
@@ -627,7 +628,7 @@ ChatCommand * ChatHandler::getCommandTable()
{ "go", SEC_MODERATOR, false, NULL, "", goCommandTable },
{ "learn", SEC_MODERATOR, false, NULL, "", learnCommandTable },
{ "modify", SEC_MODERATOR, false, NULL, "", modifyCommandTable },
- { "debug", SEC_MODERATOR, false, NULL, "", debugCommandTable },
+ { "debug", SEC_MODERATOR, true, NULL, "", debugCommandTable },
{ "tele", SEC_MODERATOR, true, NULL, "", teleCommandTable },
{ "character", SEC_GAMEMASTER, false, NULL, "", characterCommandTable},
{ "event", SEC_GAMEMASTER, false, NULL, "", eventCommandTable },
diff --git a/src/game/Chat.h b/src/game/Chat.h
index b970628f94f..ee01b7b61f4 100644
--- a/src/game/Chat.h
+++ b/src/game/Chat.h
@@ -138,16 +138,19 @@ class ChatHandler
bool HandleDebugAnimCommand(const char* args);
bool HandleDebugArenaCommand(const char * args);
bool HandleDebugBattlegroundCommand(const char * args);
- bool HandleDebugGetItemState(const char * args);
- bool HandleDebugGetLootRecipient(const char * args);
- bool HandleDebugGetValue(const char* args);
- bool HandleDebugMod32Value(const char* args);
- bool HandleDebugSetValue(const char* args);
+ bool HandleDebugGetItemStateCommand(const char * args);
+ bool HandleDebugGetLootRecipientCommand(const char * args);
+ bool HandleDebugGetValueCommand(const char* args);
+ bool HandleDebugMod32ValueCommand(const char* args);
+ bool HandleDebugSetAuraStateCommand(const char * args);
bool HandleDebugSetItemFlagCommand(const char * args);
+ bool HandleDebugItemExpireCommand(const char * args);
bool HandleDebugSetVehicleId(const char * args);
- bool HandleDebugSpawnVehicle(const char * args);
bool HandleDebugEnterVehicle(const char * args);
- bool HandleDebugUpdate(const char* args);
+ bool HandleDebugSetValueCommand(const char* args);
+ bool HandleDebugSpawnVehicle(const char * args);
+ bool HandleDebugSpellCheckCommand(const char* args);
+ bool HandleDebugUpdateCommand(const char* args);
bool HandleDebugUpdateWorldStateCommand(const char* args);
bool HandleDebugSet32Bit(const char* args);
@@ -397,7 +400,6 @@ class ChatHandler
bool HandleReloadSkillDiscoveryTemplateCommand(const char* args);
bool HandleReloadSkillExtraItemTemplateCommand(const char* args);
bool HandleReloadSkillFishingBaseLevelCommand(const char* args);
- bool HandleReloadSpellAffectCommand(const char* args);
bool HandleReloadSpellRequiredCommand(const char* args);
bool HandleReloadSpellAreaCommand(const char* args);
bool HandleReloadSpellElixirCommand(const char* args);
@@ -562,7 +564,7 @@ class ChatHandler
bool HandleQuestRemove(const char * args);
bool HandleQuestComplete(const char * args);*/
- bool HandleSet32Bit(const char* args);
+ //bool HandleSet32Bit(const char* args);
bool HandleSaveAllCommand(const char* args);
Player* getSelectedPlayer();
diff --git a/src/game/ChatHandler.cpp b/src/game/ChatHandler.cpp
index ae9da2d9fe5..6fdf9f0b222 100644
--- a/src/game/ChatHandler.cpp
+++ b/src/game/ChatHandler.cpp
@@ -155,6 +155,15 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
GetPlayer()->UpdateSpeakTime();
}
+ if (GetPlayer()->HasAura(1852) && type != CHAT_MSG_WHISPER)
+ {
+ std::string msg="";
+ recv_data >> msg;
+
+ SendNotification(GetTrinityString(LANG_GM_SILENCE), GetPlayer()->GetName());
+ return;
+ }
+
switch(type)
{
case CHAT_MSG_SAY:
@@ -231,6 +240,12 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
}
}
+ if (GetPlayer()->HasAura(1852) && !player->isGameMaster())
+ {
+ SendNotification(GetTrinityString(LANG_GM_SILENCE), GetPlayer()->GetName());
+ return;
+ }
+
GetPlayer()->Whisper(msg, lang,player->GetGUID());
} break;
diff --git a/src/game/Corpse.cpp b/src/game/Corpse.cpp
index 9fe54be1bec..83d21bb3b14 100644
--- a/src/game/Corpse.cpp
+++ b/src/game/Corpse.cpp
@@ -39,6 +39,8 @@ Corpse::Corpse(CorpseType type) : WorldObject()
m_type = type;
+ m_mapId = 0;
+
m_time = time(NULL);
lootForBody = false;
@@ -74,9 +76,11 @@ bool Corpse::Create( uint32 guidlow )
bool Corpse::Create( uint32 guidlow, Player *owner)
{
- SetInstanceId(owner->GetInstanceId());
+ ASSERT(owner);
- WorldObject::_Create(guidlow, HIGHGUID_CORPSE, owner->GetMapId(), owner->GetPhaseMask());
+ //we need to assign owner's map for corpse
+ //in other way we will get a crash in Corpse::SaveToDB()
+ SetMap(owner->GetMap());
Relocate(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ(), owner->GetOrientation());
@@ -87,6 +91,8 @@ bool Corpse::Create( uint32 guidlow, Player *owner)
return false;
}
+ WorldObject::_Create(guidlow, HIGHGUID_CORPSE, owner->GetPhaseMask());
+
SetFloatValue( OBJECT_FIELD_SCALE_X, 1 );
SetUInt64Value( CORPSE_FIELD_OWNER, owner->GetGUID() );
@@ -146,6 +152,7 @@ void Corpse::DeleteFromDB()
CharacterDatabase.PExecute("DELETE FROM corpse WHERE player = '%d' AND corpse_type <> '0'", GUID_LOPART(GetOwnerGUID()));
}
+/*
bool Corpse::LoadFromDB(uint32 guid, QueryResult *result, uint32 InstanceId)
{
bool external = (result != NULL);
@@ -173,7 +180,7 @@ bool Corpse::LoadFromDB(uint32 guid, QueryResult *result, uint32 InstanceId)
delete result;
return true;
-}
+}*/
bool Corpse::LoadFromDB(uint32 guid, Field *fields)
{
@@ -183,7 +190,6 @@ bool Corpse::LoadFromDB(uint32 guid, Field *fields)
float positionY = fields[1].GetFloat();
float positionZ = fields[2].GetFloat();
float ort = fields[3].GetFloat();
- uint32 mapid = fields[4].GetUInt32();
Object::_Create(guid, 0, HIGHGUID_CORPSE);
@@ -193,6 +199,9 @@ bool Corpse::LoadFromDB(uint32 guid, Field *fields)
return false;
}
+ SetMapId(fields[4].GetUInt32());
+ SetInstanceId(fields[8].GetUInt32());
+
m_time = time_t(fields[6].GetUInt64());
m_type = CorpseType(fields[7].GetUInt32());
@@ -202,15 +211,11 @@ bool Corpse::LoadFromDB(uint32 guid, Field *fields)
return false;
}
- uint32 instanceid = fields[8].GetUInt32();
uint32 phaseMask = fields[9].GetUInt32();
// overwrite possible wrong/corrupted guid
SetUInt64Value(OBJECT_FIELD_GUID, MAKE_NEW_GUID(guid, 0, HIGHGUID_CORPSE));
- // place
- SetInstanceId(instanceid);
- SetMapId(mapid);
SetPhaseMask(phaseMask, false);
Relocate(positionX, positionY, positionZ, ort);
diff --git a/src/game/Corpse.h b/src/game/Corpse.h
index da3511abfbb..ee6556e3436 100644
--- a/src/game/Corpse.h
+++ b/src/game/Corpse.h
@@ -61,12 +61,19 @@ class Corpse : public WorldObject
bool Create( uint32 guidlow, Player *owner );
void SaveToDB();
- bool LoadFromDB(uint32 guid, QueryResult *result, uint32 InstanceId);
+ //bool LoadFromDB(uint32 guid, QueryResult *result, uint32 InstanceId);
bool LoadFromDB(uint32 guid, Field *fields);
void DeleteBonesFromWorld();
void DeleteFromDB();
+ void SetMap (Map * map) {WorldObject::SetMap(map); m_mapId = map->GetId(); SetInstanceId(map->GetInstanceId());}
+ // Used to check object existence in unloaded grids
+ uint32 GetMapId() const {return m_mapId;}
+ void SetMapId (uint32 id) {m_mapId = id;}
+ uint32 GetInstanceId() const {return m_instanceId;}
+ void SetInstanceId (uint32 id) {m_instanceId = id;}
+
uint64 const& GetOwnerGUID() const { return GetUInt64Value(CORPSE_FIELD_OWNER); }
time_t const& GetGhostTime() const { return m_time; }
@@ -95,6 +102,8 @@ class Corpse : public WorldObject
CorpseType m_type;
time_t m_time;
GridPair m_grid; // gride for corpse position for fast search
+ uint32 m_mapId; // map id for fast corpse check at packet requests and in other situations with unloaded map of corpse.
+ uint32 m_instanceId;
};
#endif
diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp
index 50fa95337f6..fc2185bb5a8 100644
--- a/src/game/Creature.cpp
+++ b/src/game/Creature.cpp
@@ -691,17 +691,18 @@ void Creature::Motion_Initialize()
bool Creature::Create(uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint32 team, float x, float y, float z, float ang, const CreatureData *data)
{
+ ASSERT(map);
+ SetMap(map);
+ SetPhaseMask(phaseMask,false);
+
Relocate(x, y, z, ang);
+
if(!IsPositionValid())
{
sLog.outError("Creature (guidlow %d, entry %d) not loaded. Suggested coordinates isn't valid (X: %f Y: %f)",guidlow,Entry,x,y);
return false;
}
- SetMapId(map->GetId());
- SetInstanceId(map->GetInstanceId());
- SetPhaseMask(phaseMask,false);
-
//oX = x; oY = y; dX = x; dY = y; m_moveTime = 0; m_startMove = 0;
const bool bResult = CreateFromProto(guidlow, Entry, team, data);
@@ -1392,7 +1393,7 @@ void Creature::SelectLevel(const CreatureInfo *cinfo)
//damage
- float damagemod = _GetDamageMod(rank);
+ float damagemod = 1.0f;//_GetDamageMod(rank);
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, cinfo->mindmg * damagemod);
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, cinfo->maxdmg * damagemod);
@@ -2055,7 +2056,7 @@ void Creature::CallAssistance()
TypeContainerVisitor<Trinity::CreatureListSearcher<Trinity::AnyAssistCreatureInRangeCheck>, GridTypeMapContainer > grid_creature_searcher(searcher);
CellLock<GridReadGuard> cell_lock(cell, p);
- cell_lock->Visit(cell_lock, grid_creature_searcher, *MapManager::Instance().GetMap(GetMapId(), this));
+ cell_lock->Visit(cell_lock, grid_creature_searcher, *GetMap());
}
if (!assistList.empty())
@@ -2102,6 +2103,10 @@ bool Creature::CanAssistTo(const Unit* u, const Unit* enemy, bool checkfaction /
if (!isAlive())
return false;
+ // we don't need help from non-combatant ;)
+ if (isCivilian())
+ return false;
+
// skip fighting creature
if (isInCombat())
return false;
@@ -2262,6 +2267,43 @@ void Creature::SendZoneUnderAttackMessage(Player* attacker)
sWorld.SendGlobalMessage(&data,NULL,(enemy_team==ALLIANCE ? HORDE : ALLIANCE));
}
+void Creature::SetInCombatWithZone()
+{
+ if (!CanHaveThreatList())
+ {
+ sLog.outError("Creature entry %u call SetInCombatWithZone but creature cannot have threat list.", GetEntry());
+ return;
+ }
+
+ Map* pMap = GetMap();
+
+ if (!pMap->IsDungeon())
+ {
+ sLog.outError("Creature entry %u call SetInCombatWithZone for map (id: %u) that isn't an instance.", GetEntry(), pMap->GetId());
+ return;
+ }
+
+ Map::PlayerList const &PlList = pMap->GetPlayers();
+
+ if (PlList.isEmpty())
+ return;
+
+ for(Map::PlayerList::const_iterator i = PlList.begin(); i != PlList.end(); ++i)
+ {
+ if (Player* pPlayer = i->getSource())
+ {
+ if (pPlayer->isGameMaster())
+ continue;
+
+ if (pPlayer->isAlive())
+ {
+ pPlayer->SetInCombatWith(this);
+ AddThreat(pPlayer, 0.0f);
+ }
+ }
+ }
+}
+
void Creature::_AddCreatureSpellCooldown(uint32 spell_id, time_t end_time)
{
m_CreatureSpellCooldowns[spell_id] = end_time;
@@ -2540,3 +2582,4 @@ time_t Creature::GetLinkedCreatureRespawnTime() const
return 0;
}
+
diff --git a/src/game/Creature.h b/src/game/Creature.h
index f29982436d5..d291aaf9db0 100644
--- a/src/game/Creature.h
+++ b/src/game/Creature.h
@@ -150,6 +150,7 @@ enum CreatureFlagsExtra
CREATURE_FLAG_EXTRA_WORLDEVENT = 0x00004000, // custom flag for world event creatures (left room for merging)
//CREATURE_FLAG_EXTRA_CHARM_AI = 0x00008000, // use ai when charmed
CREATURE_FLAG_EXTRA_NO_CRIT = 0x00020000, // creature can't do critical strikes
+ CREATURE_FLAG_EXTRA_NO_SKILLGAIN = 0x00040000, // creature won't increase weapon skills
};
enum SummonMask
@@ -163,6 +164,7 @@ enum SummonMask
SUMMON_MASK_VEHICLE = 0x00000020,
SUMMON_MASK_PUPPET = 0x00000040,
SUMMON_MASK_HUNTER_PET = 0x00000080,
+ SUMMON_MASK_CONTROLABLE_GUARDIAN = 0x00000100,
};
// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform
@@ -172,13 +174,14 @@ enum SummonMask
#pragma pack(push,1)
#endif
+#define MAX_KILL_CREDIT 2
+
// from `creature_template` table
struct CreatureInfo
{
uint32 Entry;
uint32 HeroicEntry;
- uint32 unk1;
- uint32 unk2;
+ uint32 KillCredit[MAX_KILL_CREDIT];
uint32 DisplayID_A[2];
uint32 DisplayID_H[2];
char* Name;
@@ -319,7 +322,7 @@ struct CreatureData
struct CreatureDataAddonAura
{
- uint16 spell_id;
+ uint32 spell_id;
uint8 effect_idx;
};
@@ -692,6 +695,8 @@ class TRINITY_DLL_SPEC Creature : public Unit
void SendZoneUnderAttackMessage(Player* attacker);
+ void SetInCombatWithZone();
+
bool hasQuest(uint32 quest_id) const;
bool hasInvolvedQuest(uint32 quest_id) const;
@@ -700,10 +705,10 @@ class TRINITY_DLL_SPEC Creature : public Unit
virtual uint8 GetPetAutoSpellSize() const { return CREATURE_MAX_SPELLS; }
virtual uint32 GetPetAutoSpellOnPos(uint8 pos) const
{
- if (pos >= CREATURE_MAX_SPELLS || m_charmInfo->GetCharmSpell(pos)->active != ACT_ENABLED)
+ if (pos >= CREATURE_MAX_SPELLS || m_charmInfo->GetCharmSpell(pos)->GetType() != ACT_ENABLED)
return 0;
else
- return m_charmInfo->GetCharmSpell(pos)->spellId;
+ return m_charmInfo->GetCharmSpell(pos)->GetAction();
}
void SetHomePosition(float x, float y, float z, float ori) { mHome_X = x; mHome_Y = y; mHome_Z = z; mHome_O = ori;}
@@ -734,10 +739,11 @@ class TRINITY_DLL_SPEC Creature : public Unit
}
void ResetPlayerDamageReq() { m_PlayerDamageReq = GetHealth() / 2; }
uint32 m_PlayerDamageReq;
-
+
void SetOriginalEntry(uint32 entry) { m_originalEntry = entry; }
static float _GetDamageMod(int32 Rank);
+
protected:
bool CreateFromProto(uint32 guidlow,uint32 Entry,uint32 team, const CreatureData *data = NULL);
bool InitEntry(uint32 entry, uint32 team=ALLIANCE, const CreatureData* data=NULL);
@@ -751,7 +757,6 @@ class TRINITY_DLL_SPEC Creature : public Unit
uint32 m_lootMoney;
uint64 m_lootRecipient;
- uint32 m_unDamageByPlayers;
/// Timers
uint32 m_deathTimer; // (msecs)timer for death or corpse disappearance
diff --git a/src/game/CreatureAI.cpp b/src/game/CreatureAI.cpp
index 9f06ca38b56..165bb2411ec 100644
--- a/src/game/CreatureAI.cpp
+++ b/src/game/CreatureAI.cpp
@@ -91,6 +91,13 @@ void CreatureAI::DoZoneInCombat(Creature* creature)
pPlayer->SetInCombatWith(creature);
creature->AddThreat(pPlayer, 0.0f);
}
+
+ for(Unit::ControlList::const_iterator itr = pPlayer->m_Controlled.begin(); itr != pPlayer->m_Controlled.end(); ++itr)
+ {
+ creature->SetInCombatWith(*itr);
+ (*itr)->SetInCombatWith(creature);
+ creature->AddThreat(*itr, 0.0f);
+ }
}
}
}
@@ -148,7 +155,6 @@ bool CreatureAI::UpdateVictim()
{
if(!me->isInCombat())
return false;
-
if(Unit *victim = me->SelectVictim())
AttackStart(victim);
return me->getVictim();
@@ -194,10 +200,16 @@ void CreatureAI::EnterEvadeMode()
if(!_EnterEvadeMode())
return;
- if(Unit *owner = me->GetCharmerOrOwner())
- me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE, MOTION_SLOT_IDLE);
- else
- me->GetMotionMaster()->MoveTargetedHome();
+ if(!me->m_Vehicle) // otherwise me will be in evade mode forever
+ {
+ if(Unit *owner = me->GetCharmerOrOwner())
+ {
+ me->GetMotionMaster()->Clear(false);
+ me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, m_creature->GetFollowAngle(), MOTION_SLOT_ACTIVE);
+ }
+ else
+ me->GetMotionMaster()->MoveTargetedHome();
+ }
Reset();
}
diff --git a/src/game/CreatureAI.h b/src/game/CreatureAI.h
index 91fabe30448..061b3d273c2 100644
--- a/src/game/CreatureAI.h
+++ b/src/game/CreatureAI.h
@@ -115,6 +115,7 @@ class TRINITY_DLL_SPEC CreatureAI : public UnitAI
// Called when the creature is target of hostile action: swing, hostile spell landed, fear/etc)
//virtual void AttackedBy(Unit* attacker);
+ virtual bool IsEscorted () {return false;}
// Called when creature is spawned or respawned (for reseting variables)
virtual void JustRespawned() { Reset(); }
diff --git a/src/game/CreatureAIImpl.h b/src/game/CreatureAIImpl.h
index f6653ce40f7..bcedd108d44 100644
--- a/src/game/CreatureAIImpl.h
+++ b/src/game/CreatureAIImpl.h
@@ -246,10 +246,13 @@ enum AICondition
struct AISpellInfoType
{
- AISpellInfoType() : target(AITARGET_SELF), condition(AICOND_COMBAT), cooldown(AI_DEFAULT_COOLDOWN) {}
+ AISpellInfoType() : target(AITARGET_SELF), condition(AICOND_COMBAT)
+ , cooldown(AI_DEFAULT_COOLDOWN), realCooldown(0), maxRange(0.0f){}
AITarget target;
AICondition condition;
uint32 cooldown;
+ uint32 realCooldown;
+ float maxRange;
};
TRINITY_DLL_SPEC AISpellInfoType * GetAISpellInfo(uint32 i);
diff --git a/src/game/CreatureAISelector.cpp b/src/game/CreatureAISelector.cpp
index 65e50a2e41b..68055bcddd3 100644
--- a/src/game/CreatureAISelector.cpp
+++ b/src/game/CreatureAISelector.cpp
@@ -54,13 +54,13 @@ namespace FactorySelector
// select by NPC flags
if(!ai_factory)
{
- if(creature->isGuardian() && ((Guardian*)creature)->GetOwner()->GetTypeId() == TYPEID_PLAYER)
+ if(creature->HasSummonMask(SUMMON_MASK_CONTROLABLE_GUARDIAN) && ((Guardian*)creature)->GetOwner()->GetTypeId() == TYPEID_PLAYER)
ai_factory = ai_registry.GetRegistryItem("PetAI");
else if(creature->isVehicle() || creature->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK))
ai_factory = ai_registry.GetRegistryItem("NullCreatureAI");
else if(creature->isGuard())
ai_factory = ai_registry.GetRegistryItem("GuardAI");
- else if(creature->isGuardian())
+ else if(creature->HasSummonMask(SUMMON_MASK_CONTROLABLE_GUARDIAN))
ai_factory = ai_registry.GetRegistryItem("PetAI");
else if(creature->isTotem())
ai_factory = ai_registry.GetRegistryItem("TotemAI");
@@ -71,7 +71,7 @@ namespace FactorySelector
else
ai_factory = ai_registry.GetRegistryItem("NullCreatureAI");
}
- else if(creature->GetCreatureType() == CREATURE_TYPE_CRITTER)
+ else if(creature->GetCreatureType() == CREATURE_TYPE_CRITTER && !creature->HasSummonMask(SUMMON_MASK_GUARDIAN))
ai_factory = ai_registry.GetRegistryItem("CritterAI");
}
diff --git a/src/game/CreatureEventAI.cpp b/src/game/CreatureEventAI.cpp
index 0393c30e7d3..5c425217844 100644
--- a/src/game/CreatureEventAI.cpp
+++ b/src/game/CreatureEventAI.cpp
@@ -30,6 +30,7 @@
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "InstanceData.h"
+#include "SpellMgr.h"
bool CreatureEventAIHolder::UpdateRepeatTimer( Creature* creature, uint32 repeatMin, uint32 repeatMax )
{
@@ -95,6 +96,8 @@ CreatureEventAI::CreatureEventAI(Creature *c ) : CreatureAI(c)
AttackDistance = 0.0f;
AttackAngle = 0.0f;
+ InvinceabilityHpLevel = 0;
+
//Handle Spawned Events
if (!bEmptyList)
{
@@ -113,13 +116,6 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction
if (pHolder.Event.event_inverse_phase_mask & (1 << Phase))
return false;
- //Store random here so that all random actions match up
- uint32 rnd = rand();
-
- //Return if chance for event is not met
- if (pHolder.Event.event_chance <= rnd % 100)
- return false;
-
CreatureEventAI_Event const& event = pHolder.Event;
//Check event conditions based on the event type, also reset events
@@ -331,6 +327,13 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction
if (!(pHolder.Event.event_flags & EFLAG_REPEATABLE))
pHolder.Enabled = false;
+ //Store random here so that all random actions match up
+ uint32 rnd = rand();
+
+ //Return if chance for event is not met
+ if (pHolder.Event.event_chance <= rnd % 100)
+ return false;
+
//Process actions
for (uint32 j = 0; j < MAX_ACTIONS; j++)
ProcessAction(pHolder.Event.action[j], rnd, pHolder.Event.event_id, pActionInvoker);
@@ -746,15 +749,10 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(),NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
break;
case ACTION_T_ZONE_COMBAT_PULSE:
- if (!m_creature->isInCombat() || !m_creature->GetMap()->IsDungeon())
- {
-
- sLog.outErrorDb("CreatureEventAI: Event %d ACTION_T_ZONE_COMBAT_PULSE on creature out of combat or in non-dungeon map. Creature %d", EventId, m_creature->GetEntry());
- return;
- }
-
- DoZoneInCombat(m_creature);
+ {
+ m_creature->SetInCombatWithZone();
break;
+ }
case ACTION_T_CALL_FOR_HELP:
{
m_creature->CallForHelp(action.call_for_help.radius);
@@ -796,6 +794,14 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
m_creature->ForcedDespawn();
break;
}
+ case ACTION_T_SET_INVINCIBILITY_HP_LEVEL:
+ {
+ if(action.invincibility_hp_level.is_percent)
+ InvinceabilityHpLevel = m_creature->GetMaxHealth()*action.invincibility_hp_level.hp_level/100;
+ else
+ InvinceabilityHpLevel = action.invincibility_hp_level.hp_level;
+ break;
+ }
}
}
@@ -1302,7 +1308,7 @@ bool CreatureEventAI::CanCast(Unit* Target, SpellEntry const *Spell, bool Trigge
return false;
//Check for power
- if (!Triggered && me->GetPower((Powers)Spell->powerType) < Spell->manaCost)
+ if (!Triggered && me->GetPower((Powers)Spell->powerType) < CalculatePowerCost(Spell, me, GetSpellSchoolMask(Spell)))
return false;
SpellRangeEntry const *TempRange = NULL;
@@ -1342,6 +1348,17 @@ void CreatureEventAI::ReceiveEmote(Player* pPlayer, uint32 text_emote)
}
}
+void CreatureEventAI::DamageTaken( Unit* done_by, uint32& damage )
+{
+ if(InvinceabilityHpLevel > 0 && m_creature->GetHealth() < InvinceabilityHpLevel+damage)
+ {
+ if(m_creature->GetHealth() <= InvinceabilityHpLevel)
+ damage = 0;
+ else
+ damage = m_creature->GetHealth() - InvinceabilityHpLevel;
+ }
+}
+
bool CreatureEventAI::SpawnedEventConditionsCheck(CreatureEventAI_Event const& event)
{
if(event.event_type != EVENT_T_SPAWNED)
diff --git a/src/game/CreatureEventAI.h b/src/game/CreatureEventAI.h
index ad3827ef75d..7882e7542ec 100644
--- a/src/game/CreatureEventAI.h
+++ b/src/game/CreatureEventAI.h
@@ -113,6 +113,7 @@ enum EventAI_ActionType
ACTION_T_FORCE_DESPAWN = 41, // No Params
ACTION_T_END = 105,
+ ACTION_T_SET_INVINCIBILITY_HP_LEVEL = 42, // MinHpValue, format(0-flat,1-percent from max health)
};
enum Target
@@ -379,6 +380,12 @@ struct CreatureEventAI_Action
{
uint32 sheath;
} set_sheath;
+ // ACTION_T_SET_INVINCIBILITY_HP_LEVEL = 42
+ struct
+ {
+ uint32 hp_level;
+ uint32 is_percent;
+ } invincibility_hp_level;
// RAW
struct
{
@@ -581,6 +588,7 @@ class TRINITY_DLL_SPEC CreatureEventAI : public CreatureAI
void AttackStart(Unit *who);
void MoveInLineOfSight(Unit *who);
void SpellHit(Unit* pUnit, const SpellEntry* pSpell);
+ void DamageTaken(Unit* done_by, uint32& damage);
void UpdateAI(const uint32 diff);
void ReceiveEmote(Player* pPlayer, uint32 text_emote);
static int Permissible(const Creature *);
@@ -608,10 +616,11 @@ class TRINITY_DLL_SPEC CreatureEventAI : public CreatureAI
bool bEmptyList;
//Variables used by Events themselves
- uint8 Phase; //Current phase, max 32 phases
- bool CombatMovementEnabled; //If we allow targeted movment gen (movement twoards top threat)
- bool MeleeEnabled; //If we allow melee auto attack
- float AttackDistance; //Distance to attack from
- float AttackAngle; //Angle of attack
+ uint8 Phase; // Current phase, max 32 phases
+ bool CombatMovementEnabled; // If we allow targeted movment gen (movement twoards top threat)
+ bool MeleeEnabled; // If we allow melee auto attack
+ float AttackDistance; // Distance to attack from
+ float AttackAngle; // Angle of attack
+ uint32 InvinceabilityHpLevel; // Minimal health level allowed at damage apply
};
#endif
diff --git a/src/game/CreatureEventAIMgr.cpp b/src/game/CreatureEventAIMgr.cpp
index 38cc84177e4..901ec541455 100644
--- a/src/game/CreatureEventAIMgr.cpp
+++ b/src/game/CreatureEventAIMgr.cpp
@@ -39,7 +39,7 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Texts()
objmgr.LoadTrinityStrings(WorldDatabase,"creature_ai_texts",MIN_CREATURE_AI_TEXT_STRING_ID,MAX_CREATURE_AI_TEXT_STRING_ID);
// Gather Additional data from EventAI Texts
- QueryResult *result = WorldDatabase.PQuery("SELECT entry, sound, type, language, emote FROM creature_ai_texts");
+ QueryResult *result = WorldDatabase.Query("SELECT entry, sound, type, language, emote FROM creature_ai_texts");
sLog.outString("Loading EventAI Texts additional data...");
if (result)
@@ -117,8 +117,8 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Summons()
//Drop Existing EventSummon Map
m_CreatureEventAI_Summon_Map.clear();
- //Gather additional data for EventAI
- QueryResult *result = WorldDatabase.PQuery("SELECT id, position_x, position_y, position_z, orientation, spawntimesecs FROM creature_ai_summons");
+ // Gather additional data for EventAI
+ QueryResult *result = WorldDatabase.Query("SELECT id, position_x, position_y, position_z, orientation, spawntimesecs FROM creature_ai_summons");
if (result)
{
barGoLink bar(result->GetRowCount());
@@ -169,8 +169,8 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
//Drop Existing EventAI List
m_CreatureEventAI_Event_Map.clear();
- //Gather event data
- QueryResult *result = WorldDatabase.PQuery("SELECT id, creature_id, event_type, event_inverse_phase_mask, event_chance, event_flags, "
+ // Gather event data
+ QueryResult *result = WorldDatabase.Query("SELECT id, creature_id, event_type, event_inverse_phase_mask, event_chance, event_flags, "
"event_param1, event_param2, event_param3, event_param4, "
"action1_type, action1_param1, action1_param2, action1_param3, "
"action2_type, action2_param1, action2_param2, action2_param3, "
@@ -473,9 +473,8 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
action.morph.modelId = 0;
}
}
-
- break;
}
+ break;
case ACTION_T_SOUND:
if (!sSoundEntriesStore.LookupEntry(action.sound.soundId))
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant SoundID %u.", i, j+1, action.sound.soundId);
@@ -662,6 +661,16 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
action.set_sheath.sheath = SHEATH_STATE_UNARMED;
}
break;
+ case ACTION_T_SET_INVINCIBILITY_HP_LEVEL:
+ if(action.invincibility_hp_level.is_percent)
+ {
+ if(action.invincibility_hp_level.hp_level > 100)
+ {
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses wrong percent value %u.", i, j+1, action.invincibility_hp_level.hp_level);
+ action.invincibility_hp_level.hp_level = 100;
+ }
+ }
+ break;
case ACTION_T_EVADE: //No Params
case ACTION_T_FLEE_FOR_ASSIST: //No Params
case ACTION_T_DIE: //No Params
diff --git a/src/game/DBCStores.cpp b/src/game/DBCStores.cpp
index f618b8cfb8c..42780870499 100644
--- a/src/game/DBCStores.cpp
+++ b/src/game/DBCStores.cpp
@@ -191,7 +191,7 @@ inline void LoadDBC(uint32& availableDbcLocales,barGoLink& bar, StoreProblemList
if(f)
{
char buf[100];
- snprintf(buf,100," (exist, but have %d fields instead %d) Wrong client version DBC file?",storage.GetFieldCount(),strlen(storage.GetFormat()));
+ snprintf(buf,100," (exist, but have %d fields instead " SIZEFMTD ") Wrong client version DBC file?",storage.GetFieldCount(),strlen(storage.GetFormat()));
errlist.push_back(dbc_filename + buf);
fclose(f);
}
@@ -696,3 +696,4 @@ TRINITY_DLL_SPEC DBCStorage <ItemEntry> const* GetItemDisplayStore()
TRINITY_DLL_SPEC DBCStorage <CreatureDisplayInfoEntry> const* GetCreatureDisplayStore() { return &sCreatureDisplayInfoStore; }
TRINITY_DLL_SPEC DBCStorage <EmotesEntry> const* GetEmotesStore() { return &sEmotesStore; }
TRINITY_DLL_SPEC DBCStorage <EmotesTextEntry> const* GetEmotesTextStore() { return &sEmotesTextStore; }
+TRINITY_DLL_SPEC DBCStorage <AchievementEntry> const* GetAchievementStore() { return &sAchievementStore; }
diff --git a/src/game/DBCStores.h b/src/game/DBCStores.h
index a423cd0bfc8..fc47568e6a5 100644
--- a/src/game/DBCStores.h
+++ b/src/game/DBCStores.h
@@ -158,4 +158,5 @@ TRINITY_DLL_SPEC DBCStorage <ItemEntry> const* GetItemDisplaySt
TRINITY_DLL_SPEC DBCStorage <CreatureDisplayInfoEntry> const* GetCreatureDisplayStore();
TRINITY_DLL_SPEC DBCStorage <EmotesEntry> const* GetEmotesStore();
TRINITY_DLL_SPEC DBCStorage <EmotesTextEntry> const* GetEmotesTextStore();
+TRINITY_DLL_SPEC DBCStorage <AchievementEntry> const* GetAchievementStore();
#endif
diff --git a/src/game/DBCStructure.h b/src/game/DBCStructure.h
index 686c43fc355..a8b5d3ef177 100644
--- a/src/game/DBCStructure.h
+++ b/src/game/DBCStructure.h
@@ -84,11 +84,14 @@ struct AchievementCriteriaEntry
} kill_creature;
// ACHIEVEMENT_CRITERIA_TYPE_WIN_BG = 1
- // TODO: there are further criterias instead just winning
struct
{
uint32 bgMapID; // 3
uint32 winCount; // 4
+ uint32 additionalRequirement1_type; // 5 additional requirement 1 type
+ uint32 additionalRequirement1_value; // 6 additional requirement 1 value
+ uint32 additionalRequirement2_type; // 7 additional requirement 2 type
+ uint32 additionalRequirement2_value; // 8 additional requirement 1 value
} win_bg;
// ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL = 5
@@ -490,7 +493,9 @@ struct AchievementCriteriaEntry
//uint32 name_flags; // 25
uint32 completionFlag; // 26
uint32 groupFlag; // 27
- //uint32 unk1; // 28
+ //uint32 unk1; // 28 Alway appears with timed events
+ // for timed spells it is spell id for
+ // timed kills it is creature id
uint32 timeLimit; // 29 time limit in seconds
//uint32 showOrder; // 30 show order
};
@@ -507,6 +512,14 @@ struct AreaTableEntry
char* area_name[16]; // 11-26
// 27, string flags, unused
uint32 team; // 28
+
+ // helpers
+ bool IsSanctuary() const
+ {
+ if (mapid == 609)
+ return true;
+ return (flags & AREA_FLAG_SANCTUARY);
+ }
};
struct AreaGroupEntry
@@ -1423,7 +1436,7 @@ struct SpellEntry
uint32 SchoolMask; // 228 m_schoolMask
uint32 runeCostID; // 229 m_runeCostID
//uint32 spellMissileID; // 230 m_spellMissileID not used
- //uint32 PowerDisplayId; // 231 PowerDisplay.dbc, new in 3.1
+ //uint32 PowerDisplayId; // 231 PowerDisplay.dbc, new in 3.1
// helpers
int32 CalculateSimpleValue(uint8 eff) const { return EffectBasePoints[eff]+int32(EffectBaseDice[eff]); }
@@ -1453,13 +1466,6 @@ struct SpellFocusObjectEntry
// 16 string flags, unused
};
-// stored in SQL table
-struct SpellThreatEntry
-{
- uint32 spellId;
- int32 threat;
-};
-
struct SpellRadiusEntry
{
uint32 ID;
diff --git a/src/game/Debugcmds.cpp b/src/game/Debugcmds.cpp
index d8b94df4e10..69b3bcb1284 100644
--- a/src/game/Debugcmds.cpp
+++ b/src/game/Debugcmds.cpp
@@ -36,10 +36,12 @@
#include "CellImpl.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
+#include "SpellMgr.h"
+#include "ScriptCalls.h"
bool ChatHandler::HandleDebugSendSpellFailCommand(const char* args)
{
- if(!args)
+ if (!*args)
return false;
char* px = strtok((char*)args, " ");
@@ -47,7 +49,7 @@ bool ChatHandler::HandleDebugSendSpellFailCommand(const char* args)
return false;
uint8 failnum = (uint8)atoi(px);
- if(failnum==0 && *px!='0')
+ if (failnum==0 && *px!='0')
return false;
char* p1 = strtok(NULL, " ");
@@ -72,20 +74,20 @@ bool ChatHandler::HandleDebugSendSpellFailCommand(const char* args)
bool ChatHandler::HandleDebugSendPoiCommand(const char* args)
{
+ if (!*args)
+ return false;
+
Player *pPlayer = m_session->GetPlayer();
Unit* target = getSelectedUnit();
- if(!target)
+ if (!target)
{
SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
return true;
}
- if(!args)
- return false;
-
char* icon_text = strtok((char*)args, " ");
char* flags_text = strtok(NULL, " ");
- if(!icon_text || !flags_text)
+ if (!icon_text || !flags_text)
return false;
uint32 icon = atol(icon_text);
@@ -98,7 +100,7 @@ bool ChatHandler::HandleDebugSendPoiCommand(const char* args)
bool ChatHandler::HandleDebugSendEquipErrorCommand(const char* args)
{
- if(!args)
+ if (!*args)
return false;
uint8 msg = atoi(args);
@@ -108,7 +110,7 @@ bool ChatHandler::HandleDebugSendEquipErrorCommand(const char* args)
bool ChatHandler::HandleDebugSendSellErrorCommand(const char* args)
{
- if(!args)
+ if (!*args)
return false;
uint8 msg = atoi(args);
@@ -118,7 +120,7 @@ bool ChatHandler::HandleDebugSendSellErrorCommand(const char* args)
bool ChatHandler::HandleDebugSendBuyErrorCommand(const char* args)
{
- if(!args)
+ if (!*args)
return false;
uint8 msg = atoi(args);
@@ -137,7 +139,7 @@ bool ChatHandler::HandleDebugSendOpcodeCommand(const char* /*args*/)
if(!unit) unit = player;
std::ifstream ifs("opcode.txt");
- if(ifs.bad())
+ if (ifs.bad())
return false;
uint32 opcode;
@@ -273,7 +275,7 @@ bool ChatHandler::HandleDebugPlayCinematicCommand(const char* args)
{
// USAGE: .debug play cinematic #cinematicid
// #cinematicid - ID decimal number from CinemaicSequences.dbc (1st column)
- if( !*args )
+ if (!*args)
{
SendSysMessage(LANG_BAD_VALUE);
SetSentErrorMessage(true);
@@ -282,7 +284,7 @@ bool ChatHandler::HandleDebugPlayCinematicCommand(const char* args)
uint32 dwId = atoi((char*)args);
- if(!sCinematicSequencesStore.LookupEntry(dwId))
+ if (!sCinematicSequencesStore.LookupEntry(dwId))
{
PSendSysMessage(LANG_CINEMATIC_NOT_EXIST, dwId);
SetSentErrorMessage(true);
@@ -297,7 +299,7 @@ bool ChatHandler::HandleDebugPlayMovieCommand(const char* args)
{
// USAGE: .debug play movie #movieid
// #movieid - ID decimal number from Movie.dbc (1st column)
- if( !*args )
+ if (!*args)
{
SendSysMessage(LANG_BAD_VALUE);
SetSentErrorMessage(true);
@@ -306,7 +308,7 @@ bool ChatHandler::HandleDebugPlayMovieCommand(const char* args)
uint32 dwId = atoi((char*)args);
- if(!sMovieStore.LookupEntry(dwId))
+ if (!sMovieStore.LookupEntry(dwId))
{
PSendSysMessage(LANG_MOVIE_NOT_EXIST, dwId);
SetSentErrorMessage(true);
@@ -322,7 +324,7 @@ bool ChatHandler::HandleDebugPlaySoundCommand(const char* args)
{
// USAGE: .debug playsound #soundid
// #soundid - ID decimal number from SoundEntries.dbc (1st column)
- if( !*args )
+ if (!*args)
{
SendSysMessage(LANG_BAD_VALUE);
SetSentErrorMessage(true);
@@ -331,7 +333,7 @@ bool ChatHandler::HandleDebugPlaySoundCommand(const char* args)
uint32 dwSoundId = atoi((char*)args);
- if(!sSoundEntriesStore.LookupEntry(dwSoundId))
+ if (!sSoundEntriesStore.LookupEntry(dwSoundId))
{
PSendSysMessage(LANG_SOUND_NOT_EXIST, dwSoundId);
SetSentErrorMessage(true);
@@ -339,14 +341,14 @@ bool ChatHandler::HandleDebugPlaySoundCommand(const char* args)
}
Unit* unit = getSelectedUnit();
- if(!unit)
+ if (!unit)
{
SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
SetSentErrorMessage(true);
return false;
}
- if(m_session->GetPlayer()->GetSelection())
+ if (m_session->GetPlayer()->GetSelection())
unit->PlayDistanceSound(dwSoundId,m_session->GetPlayer());
else
unit->PlayDirectSound(dwSoundId,m_session->GetPlayer());
@@ -358,7 +360,7 @@ bool ChatHandler::HandleDebugPlaySoundCommand(const char* args)
//Send notification in channel
bool ChatHandler::HandleDebugSendChannelNotifyCommand(const char* args)
{
- if(!args)
+ if (!*args)
return false;
const char *name = "test";
@@ -376,7 +378,7 @@ bool ChatHandler::HandleDebugSendChannelNotifyCommand(const char* args)
//Send notification in chat
bool ChatHandler::HandleDebugSendChatMsgCommand(const char* args)
{
- if(!args)
+ if (!*args)
return false;
const char *msg = "testtest";
@@ -394,10 +396,10 @@ bool ChatHandler::HandleDebugSendQuestPartyMsgCommand(const char* args)
return true;
}
-bool ChatHandler::HandleDebugGetLootRecipient(const char* /*args*/)
+bool ChatHandler::HandleDebugGetLootRecipientCommand(const char* /*args*/)
{
Creature* target = getSelectedCreature();
- if(!target)
+ if (!target)
return false;
PSendSysMessage("loot recipient: %s", target->hasLootRecipient()?(target->GetLootRecipient()?target->GetLootRecipient()->GetName():"offline"):"no loot recipient");
@@ -411,9 +413,9 @@ bool ChatHandler::HandleDebugSendQuestInvalidMsgCommand(const char* args)
return true;
}
-bool ChatHandler::HandleDebugGetItemState(const char* args)
+bool ChatHandler::HandleDebugGetItemStateCommand(const char* args)
{
- if (!args)
+ if (!*args)
return false;
std::string state_str = args;
@@ -613,13 +615,13 @@ bool ChatHandler::HandleDebugGetItemState(const char* args)
if (item->GetOwnerGUID() != player->GetGUID())
{
- PSendSysMessage("queue(%d): for the an item (guid %d), the owner's guid (%d) and player's guid (%d) don't match!", i, item->GetGUIDLow(), GUID_LOPART(item->GetOwnerGUID()), player->GetGUIDLow());
+ PSendSysMessage("queue(" SIZEFMTD "): for the an item (guid %d), the owner's guid (%d) and player's guid (%d) don't match!", i, item->GetGUIDLow(), GUID_LOPART(item->GetOwnerGUID()), player->GetGUIDLow());
error = true; continue;
}
if (item->GetQueuePos() != i)
{
- PSendSysMessage("queue(%d): for the an item (guid %d), the queuepos doesn't match it's position in the queue!", i, item->GetGUIDLow());
+ PSendSysMessage("queue(" SIZEFMTD "): for the an item (guid %d), the queuepos doesn't match it's position in the queue!", i, item->GetGUIDLow());
error = true; continue;
}
@@ -628,13 +630,13 @@ bool ChatHandler::HandleDebugGetItemState(const char* args)
if (test == NULL)
{
- PSendSysMessage("queue(%d): the bag(%d) and slot(%d) values for the item with guid %d are incorrect, the player doesn't have an item at that position!", i, item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow());
+ PSendSysMessage("queue(" SIZEFMTD "): the bag(%d) and slot(%d) values for the item with guid %d are incorrect, the player doesn't have an item at that position!", i, item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow());
error = true; continue;
}
if (test != item)
{
- PSendSysMessage("queue(%d): the bag(%d) and slot(%d) values for the item with guid %d are incorrect, the item with guid %d is there instead!", i, item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow(), test->GetGUIDLow());
+ PSendSysMessage("queue(" SIZEFMTD "): the bag(%d) and slot(%d) values for the item with guid %d are incorrect, the item with guid %d is there instead!", i, item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow(), test->GetGUIDLow());
error = true; continue;
}
}
@@ -757,7 +759,7 @@ bool ChatHandler::HandleDebugEnterVehicle(const char * args)
bool ChatHandler::HandleDebugSpawnVehicle(const char* args)
{
- if(!args)
+ if (!*args)
return false;
char* e = strtok((char*)args, " ");
@@ -778,12 +780,12 @@ bool ChatHandler::HandleDebugSpawnVehicle(const char* args)
CreatureInfo const *ci = objmgr.GetCreatureTemplate(entry);
- if(!ci)
+ if (!ci)
return false;
VehicleEntry const *ve = sVehicleStore.LookupEntry(id);
- if(!ve)
+ if (!ve)
return false;
Vehicle *v = new Vehicle;
@@ -812,7 +814,7 @@ bool ChatHandler::HandleDebugSendLargePacketCommand(const char* /*args*/)
bool ChatHandler::HandleDebugSendSetPhaseShiftCommand(const char* args)
{
- if(!args)
+ if (!*args)
return false;
uint32 PhaseShift = atoi(args);
@@ -822,7 +824,7 @@ bool ChatHandler::HandleDebugSendSetPhaseShiftCommand(const char* args)
bool ChatHandler::HandleDebugSetItemFlagCommand(const char* args)
{
- if(!args)
+ if (!*args)
return false;
char* e = strtok((char*)args, " ");
@@ -836,7 +838,7 @@ bool ChatHandler::HandleDebugSetItemFlagCommand(const char* args)
Item *i = m_session->GetPlayer()->GetItemByGuid(MAKE_NEW_GUID(guid, 0, HIGHGUID_ITEM));
- if(!i)
+ if (!i)
return false;
i->SetUInt32Value(ITEM_FIELD_FLAGS, flag);
@@ -844,6 +846,28 @@ bool ChatHandler::HandleDebugSetItemFlagCommand(const char* args)
return true;
}
+bool ChatHandler::HandleDebugItemExpireCommand(const char* args)
+{
+ if (!*args)
+ return false;
+
+ char* e = strtok((char*)args, " ");
+ if (!e)
+ return false;
+
+ uint32 guid = (uint32)atoi(e);
+
+ Item *i = m_session->GetPlayer()->GetItemByGuid(MAKE_NEW_GUID(guid, 0, HIGHGUID_ITEM));
+
+ if (!i)
+ return false;
+
+ m_session->GetPlayer()->DestroyItem( i->GetBagSlot(),i->GetSlot(), true);
+ Script->ItemExpire(m_session->GetPlayer(),i->GetProto());
+
+ return true;
+}
+
//show animation
bool ChatHandler::HandleDebugAnimCommand(const char* args)
{
@@ -854,3 +878,216 @@ bool ChatHandler::HandleDebugAnimCommand(const char* args)
m_session->GetPlayer()->HandleEmoteCommand(anim_id);
return true;
}
+
+bool ChatHandler::HandleDebugSetAuraStateCommand(const char* args)
+{
+ if (!*args)
+ {
+ SendSysMessage(LANG_BAD_VALUE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ Unit* unit = getSelectedUnit();
+ if (!unit)
+ {
+ SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ int32 state = atoi((char*)args);
+ if (!state)
+ {
+ // reset all states
+ for(int i = 1; i <= 32; ++i)
+ unit->ModifyAuraState(AuraState(i),false);
+ return true;
+ }
+
+ unit->ModifyAuraState(AuraState(abs(state)),state > 0);
+ return true;
+}
+
+bool ChatHandler::HandleDebugSetValueCommand(const char* args)
+{
+ if(!*args)
+ return false;
+
+ char* px = strtok((char*)args, " ");
+ char* py = strtok(NULL, " ");
+ char* pz = strtok(NULL, " ");
+
+ if (!px || !py)
+ return false;
+
+ WorldObject* target = getSelectedObject();
+ if(!target)
+ {
+ SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ uint64 guid = target->GetGUID();
+
+ uint32 Opcode = (uint32)atoi(px);
+ if(Opcode >= target->GetValuesCount())
+ {
+ PSendSysMessage(LANG_TOO_BIG_INDEX, Opcode, GUID_LOPART(guid), target->GetValuesCount());
+ return false;
+ }
+ uint32 iValue;
+ float fValue;
+ bool isint32 = true;
+ if(pz)
+ isint32 = (bool)atoi(pz);
+ if(isint32)
+ {
+ iValue = (uint32)atoi(py);
+ sLog.outDebug(GetTrinityString(LANG_SET_UINT), GUID_LOPART(guid), Opcode, iValue);
+ target->SetUInt32Value( Opcode , iValue );
+ PSendSysMessage(LANG_SET_UINT_FIELD, GUID_LOPART(guid), Opcode,iValue);
+ }
+ else
+ {
+ fValue = (float)atof(py);
+ sLog.outDebug(GetTrinityString(LANG_SET_FLOAT), GUID_LOPART(guid), Opcode, fValue);
+ target->SetFloatValue( Opcode , fValue );
+ PSendSysMessage(LANG_SET_FLOAT_FIELD, GUID_LOPART(guid), Opcode,fValue);
+ }
+
+ return true;
+}
+
+bool ChatHandler::HandleDebugGetValueCommand(const char* args)
+{
+ if(!*args)
+ return false;
+
+ char* px = strtok((char*)args, " ");
+ char* pz = strtok(NULL, " ");
+
+ if (!px)
+ return false;
+
+ Unit* target = getSelectedUnit();
+ if(!target)
+ {
+ SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ uint64 guid = target->GetGUID();
+
+ uint32 Opcode = (uint32)atoi(px);
+ if(Opcode >= target->GetValuesCount())
+ {
+ PSendSysMessage(LANG_TOO_BIG_INDEX, Opcode, GUID_LOPART(guid), target->GetValuesCount());
+ return false;
+ }
+ uint32 iValue;
+ float fValue;
+ bool isint32 = true;
+ if(pz)
+ isint32 = (bool)atoi(pz);
+
+ if(isint32)
+ {
+ iValue = target->GetUInt32Value( Opcode );
+ sLog.outDebug(GetTrinityString(LANG_GET_UINT), GUID_LOPART(guid), Opcode, iValue);
+ PSendSysMessage(LANG_GET_UINT_FIELD, GUID_LOPART(guid), Opcode, iValue);
+ }
+ else
+ {
+ fValue = target->GetFloatValue( Opcode );
+ sLog.outDebug(GetTrinityString(LANG_GET_FLOAT), GUID_LOPART(guid), Opcode, fValue);
+ PSendSysMessage(LANG_GET_FLOAT_FIELD, GUID_LOPART(guid), Opcode, fValue);
+ }
+
+ return true;
+}
+
+bool ChatHandler::HandleDebugMod32ValueCommand(const char* args)
+{
+ if(!*args)
+ return false;
+
+ char* px = strtok((char*)args, " ");
+ char* py = strtok(NULL, " ");
+
+ if (!px || !py)
+ return false;
+
+ uint32 Opcode = (uint32)atoi(px);
+ int Value = atoi(py);
+
+ if(Opcode >= m_session->GetPlayer()->GetValuesCount())
+ {
+ PSendSysMessage(LANG_TOO_BIG_INDEX, Opcode, m_session->GetPlayer()->GetGUIDLow(), m_session->GetPlayer( )->GetValuesCount());
+ return false;
+ }
+
+ sLog.outDebug(GetTrinityString(LANG_CHANGE_32BIT), Opcode, Value);
+
+ int CurrentValue = (int)m_session->GetPlayer( )->GetUInt32Value( Opcode );
+
+ CurrentValue += Value;
+ m_session->GetPlayer( )->SetUInt32Value( Opcode , (uint32)CurrentValue );
+
+ PSendSysMessage(LANG_CHANGE_32BIT_FIELD, Opcode,CurrentValue);
+
+ return true;
+}
+
+bool ChatHandler::HandleDebugUpdateCommand(const char* args)
+{
+ if(!*args)
+ return false;
+
+ uint32 updateIndex;
+ uint32 value;
+
+ char* pUpdateIndex = strtok((char*)args, " ");
+
+ Unit* chr = getSelectedUnit();
+ if (chr == NULL)
+ {
+ SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ if(!pUpdateIndex)
+ {
+ return true;
+ }
+ updateIndex = atoi(pUpdateIndex);
+ //check updateIndex
+ if(chr->GetTypeId() == TYPEID_PLAYER)
+ {
+ if (updateIndex>=PLAYER_END) return true;
+ }
+ else
+ {
+ if (updateIndex>=UNIT_END) return true;
+ }
+
+ char* pvalue = strtok(NULL, " ");
+ if (!pvalue)
+ {
+ value=chr->GetUInt32Value(updateIndex);
+
+ PSendSysMessage(LANG_UPDATE, chr->GetGUIDLow(),updateIndex,value);
+ return true;
+ }
+
+ value=atoi(pvalue);
+
+ PSendSysMessage(LANG_UPDATE_CHANGE, chr->GetGUIDLow(),updateIndex,value);
+
+ chr->SetUInt32Value(updateIndex,value);
+
+ return true;
+}
diff --git a/src/game/DestinationHolderImp.h b/src/game/DestinationHolderImp.h
index d50d8c3e727..c84ce19a96d 100644
--- a/src/game/DestinationHolderImp.h
+++ b/src/game/DestinationHolderImp.h
@@ -142,7 +142,7 @@ DestinationHolder<TRAVELLER>::UpdateTraveller(TRAVELLER &traveller, uint32 diff,
i_fromZ = z;
}
- if( traveller.GetTraveller().GetPositionX() != x || traveller.GetTraveller().GetPositionY() != y )
+ if( traveller.GetTraveller().GetPositionX() != x || traveller.GetTraveller().GetPositionY() != y || traveller.GetTraveller().GetPositionZ() != z)
{
float ori = traveller.GetTraveller().GetAngle(x, y);
traveller.Relocation(x, y, z, ori);
diff --git a/src/game/DynamicObject.cpp b/src/game/DynamicObject.cpp
index dc2b05e8d6a..80b0d91a1b8 100644
--- a/src/game/DynamicObject.cpp
+++ b/src/game/DynamicObject.cpp
@@ -72,9 +72,8 @@ void DynamicObject::RemoveFromWorld()
bool DynamicObject::Create( uint32 guidlow, Unit *caster, uint32 spellId, uint32 effIndex, float x, float y, float z, int32 duration, float radius )
{
- SetInstanceId(caster->GetInstanceId());
+ SetMap(caster->GetMap());
- WorldObject::_Create(guidlow, HIGHGUID_DYNAMICOBJECT, caster->GetMapId(), caster->GetPhaseMask());
Relocate(x, y, z, 0);
if(!IsPositionValid())
@@ -83,6 +82,8 @@ bool DynamicObject::Create( uint32 guidlow, Unit *caster, uint32 spellId, uint32
return false;
}
+ WorldObject::_Create(guidlow, HIGHGUID_DYNAMICOBJECT, caster->GetPhaseMask());
+
SetEntry(spellId);
SetFloatValue( OBJECT_FIELD_SCALE_X, 1 );
SetUInt64Value( DYNAMICOBJECT_CASTER, caster->GetGUID() );
diff --git a/src/game/FleeingMovementGenerator.cpp b/src/game/FleeingMovementGenerator.cpp
index 2eddd2a128c..eef98b705cc 100644
--- a/src/game/FleeingMovementGenerator.cpp
+++ b/src/game/FleeingMovementGenerator.cpp
@@ -413,6 +413,7 @@ template bool FleeingMovementGenerator<Creature>::Update(Creature &, const uint3
void TimedFleeingMovementGenerator::Finalize(Unit &owner)
{
+ owner.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
owner.clearUnitState(UNIT_STAT_FLEEING | UNIT_STAT_ROAMING);
if (Unit* victim = owner.getVictim())
{
diff --git a/src/game/Formulas.h b/src/game/Formulas.h
index 041c0621c74..2ec175f95be 100644
--- a/src/game/Formulas.h
+++ b/src/game/Formulas.h
@@ -117,7 +117,7 @@ namespace Trinity
(((Creature*)u)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_XP_AT_KILL) ))
return 0;
- uint32 xp_gain= BaseGain(pl->getLevel(), u->getLevel(), GetContentLevelsForMapAndZone(pl->GetMapId(),pl->GetZoneId()));
+ uint32 xp_gain= BaseGain(pl->getLevel(), u->getLevel(), GetContentLevelsForMapAndZone(u->GetMapId(),u->GetZoneId()));
if( xp_gain == 0 )
return 0;
diff --git a/src/game/GameEventMgr.cpp b/src/game/GameEventMgr.cpp
index 0984c896eac..5b7aa737bc0 100644
--- a/src/game/GameEventMgr.cpp
+++ b/src/game/GameEventMgr.cpp
@@ -1215,7 +1215,7 @@ void GameEventMgr::GameEventSpawn(int16 event_id)
if(internal_event_id < 0 || internal_event_id >= mGameEventCreatureGuids.size())
{
- sLog.outError("GameEventMgr::GameEventSpawn attempt access to out of range mGameEventCreatureGuids element %i (size: %u)",internal_event_id,mGameEventCreatureGuids.size());
+ sLog.outError("GameEventMgr::GameEventSpawn attempt access to out of range mGameEventCreatureGuids element %i (size: " SIZEFMTD ")",internal_event_id,mGameEventCreatureGuids.size());
return;
}
@@ -1248,7 +1248,7 @@ void GameEventMgr::GameEventSpawn(int16 event_id)
if(internal_event_id < 0 || internal_event_id >= mGameEventGameobjectGuids.size())
{
- sLog.outError("GameEventMgr::GameEventSpawn attempt access to out of range mGameEventGameobjectGuids element %i (size: %u)",internal_event_id,mGameEventGameobjectGuids.size());
+ sLog.outError("GameEventMgr::GameEventSpawn attempt access to out of range mGameEventGameobjectGuids element %i (size: " SIZEFMTD ")",internal_event_id,mGameEventGameobjectGuids.size());
return;
}
@@ -1282,7 +1282,7 @@ void GameEventMgr::GameEventSpawn(int16 event_id)
if(internal_event_id < 0 || internal_event_id >= mGameEventPoolIds.size())
{
- sLog.outError("GameEventMgr::GameEventSpawn attempt access to out of range mGameEventPoolIds element %i (size: %u)",internal_event_id,mGameEventPoolIds.size());
+ sLog.outError("GameEventMgr::GameEventSpawn attempt access to out of range mGameEventPoolIds element %i (size: " SIZEFMTD ")",internal_event_id,mGameEventPoolIds.size());
return;
}
@@ -1298,7 +1298,7 @@ void GameEventMgr::GameEventUnspawn(int16 event_id)
if(internal_event_id < 0 || internal_event_id >= mGameEventCreatureGuids.size())
{
- sLog.outError("GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventCreatureGuids element %i (size: %u)",internal_event_id,mGameEventCreatureGuids.size());
+ sLog.outError("GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventCreatureGuids element %i (size: " SIZEFMTD ")",internal_event_id,mGameEventCreatureGuids.size());
return;
}
@@ -1313,16 +1313,13 @@ void GameEventMgr::GameEventUnspawn(int16 event_id)
objmgr.RemoveCreatureFromGrid(*itr, data);
if( Creature* pCreature = ObjectAccessor::Instance().GetObjectInWorld(MAKE_NEW_GUID(*itr, data->id, HIGHGUID_UNIT), (Creature*)NULL) )
- {
- pCreature->CleanupsBeforeDelete();
pCreature->AddObjectToRemoveList();
- }
}
}
if(internal_event_id < 0 || internal_event_id >= mGameEventGameobjectGuids.size())
{
- sLog.outError("GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventGameobjectGuids element %i (size: %u)",internal_event_id,mGameEventGameobjectGuids.size());
+ sLog.outError("GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventGameobjectGuids element %i (size: " SIZEFMTD ")",internal_event_id,mGameEventGameobjectGuids.size());
return;
}
@@ -1342,7 +1339,7 @@ void GameEventMgr::GameEventUnspawn(int16 event_id)
}
if(internal_event_id < 0 || internal_event_id >= mGameEventPoolIds.size())
{
- sLog.outError("GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventPoolIds element %i (size: %u)",internal_event_id,mGameEventPoolIds.size());
+ sLog.outError("GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventPoolIds element %i (size: " SIZEFMTD ")",internal_event_id,mGameEventPoolIds.size());
return;
}
diff --git a/src/game/GameObject.cpp b/src/game/GameObject.cpp
index d6aa162b50a..c3bfc1d77b9 100644
--- a/src/game/GameObject.cpp
+++ b/src/game/GameObject.cpp
@@ -54,7 +54,6 @@ GameObject::GameObject() : WorldObject(), m_goValue(new GameObjectValue)
m_spawnedByDefault = true;
m_usetimes = 0;
m_spellId = 0;
- m_charges = 5;
m_cooldownTime = 0;
m_goInfo = NULL;
m_goData = NULL;
@@ -65,28 +64,39 @@ GameObject::GameObject() : WorldObject(), m_goValue(new GameObjectValue)
GameObject::~GameObject()
{
- /*if(m_uint32Values) // field array can be not exist if GameOBject not loaded
+ //if(m_uint32Values) // field array can be not exist if GameOBject not loaded
+ // CleanupsBeforeDelete();
+}
+
+void GameObject::CleanupsBeforeDelete()
+{
+ if(m_uint32Values) // field array can be not exist if GameOBject not loaded
{
// Possible crash at access to deleted GO in Unit::m_gameobj
- uint64 owner_guid = GetOwnerGUID();
- if(owner_guid)
+ if(uint64 owner_guid = GetOwnerGUID())
{
- Unit* owner = ObjectAccessor::GetUnit(*this,owner_guid);
+ Unit* owner = NULL;
+ // Object may be deleted while player is not in world, skip this check for now.
+ /*if(IS_PLAYER_GUID(owner_guid))
+ owner = ObjectAccessor::GetObjectInWorld(owner_guid, (Player*)NULL);
+ else*/
+ owner = ObjectAccessor::GetUnit(*this,owner_guid);
+
if(owner)
owner->RemoveGameObject(this,false);
else
{
- char * ownerType = "creature";
+ const char * ownerType = "creature";
if(IS_PLAYER_GUID(owner_guid))
ownerType = "player";
else if(IS_PET_GUID(owner_guid))
ownerType = "pet";
sLog.outError("Delete GameObject (GUID: %u Entry: %u SpellId %u LinkedGO %u) that lost references to owner (GUID %u Type '%s') GO list. Crash possible later.",
- GetGUIDLow(), GetGOInfo()->id, m_spellId, GetLinkedGameObjectEntry(), GUID_LOPART(owner_guid), ownerType);
+ GetGUIDLow(), GetGOInfo()->id, m_spellId, GetGOInfo()->GetLinkedGameObjectEntry(), GUID_LOPART(owner_guid), ownerType);
}
}
- }*/
+ }
}
void GameObject::AddToWorld()
@@ -113,8 +123,7 @@ void GameObject::RemoveFromWorld()
// Possible crash at access to deleted GO in Unit::m_gameobj
if(uint64 owner_guid = GetOwnerGUID())
{
- Unit* owner = ObjectAccessor::GetUnit(*this,owner_guid);
- if(owner)
+ if(Unit * owner = GetOwner(false))
owner->RemoveGameObject(this,false);
else if(!IS_PLAYER_GUID(owner_guid))
sLog.outError("Delete GameObject (GUID: %u Entry: %u ) that have references in not found creature %u GO list. Crash possible later.",GetGUIDLow(),GetGOInfo()->id,GUID_LOPART(owner_guid));
@@ -126,17 +135,18 @@ void GameObject::RemoveFromWorld()
bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, uint32 phaseMask, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, GOState go_state, uint32 ArtKit)
{
- Relocate(x,y,z,ang);
- SetMapId(map->GetId());
- SetInstanceId(map->GetInstanceId());
- SetPhaseMask(phaseMask,false);
+ ASSERT(map);
+ SetMap(map);
+ Relocate(x,y,z,ang);
if(!IsPositionValid())
{
sLog.outError("Gameobject (GUID: %u Entry: %u ) not created. Suggested coordinates isn't valid (X: %f Y: %f)",guidlow,name_id,x,y);
return false;
}
+ SetPhaseMask(phaseMask,false);
+
GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(name_id);
if (!goinfo)
{
@@ -177,9 +187,6 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, uint32 phaseMa
switch(goinfo->type)
{
- case GAMEOBJECT_TYPE_SPELLCASTER:
- m_charges = goinfo->spellcaster.charges;
- break;
case GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING:
m_goValue->building.health = goinfo->building.intactNumHits + goinfo->building.damagedNumHits;
break;
@@ -298,87 +305,94 @@ void GameObject::Update(uint32 /*p_time*/)
}
}
- // traps can have time and can not have
- GameObjectInfo const* goInfo = GetGOInfo();
- if(goInfo->type == GAMEOBJECT_TYPE_TRAP)
+ if(isSpawned())
{
- // traps
- Unit* owner = GetOwner();
- Unit* ok = NULL; // pointer to appropriate target if found any
+ // traps can have time and can not have
+ GameObjectInfo const* goInfo = GetGOInfo();
+ if(goInfo->type == GAMEOBJECT_TYPE_TRAP)
+ {
+ if(m_cooldownTime >= time(NULL))
+ return;
- if(m_cooldownTime >= time(NULL))
- return;
+ // traps
+ Unit* owner = GetOwner();
+ Unit* ok = NULL; // pointer to appropriate target if found any
- bool IsBattleGroundTrap = false;
- //FIXME: this is activation radius (in different casting radius that must be selected from spell data)
- //TODO: move activated state code (cast itself) to GO_ACTIVATED, in this place only check activating and set state
- float radius = goInfo->trap.radius;
- if(!radius) // i think this is a hack, spell radius is determined by trap radius (spell itself does not have radius)
- if(const SpellEntry *spellEntry = sSpellStore.LookupEntry(m_spellId))
- radius = goInfo->trap.radius;
- if(!radius)
- {
- if(goInfo->trap.cooldown == 3) // cast in other case (at some triggering/linked go/etc explicit call)
+ bool IsBattleGroundTrap = false;
+ //FIXME: this is activation radius (in different casting radius that must be selected from spell data)
+ //TODO: move activated state code (cast itself) to GO_ACTIVATED, in this place only check activating and set state
+ float radius = goInfo->trap.radius;
+ if(!radius)
{
- if(m_respawnTime > 0)
- break;
+ if(goInfo->trap.cooldown != 3) // cast in other case (at some triggering/linked go/etc explicit call)
+ return;
+ else
+ {
+ if(m_respawnTime > 0)
+ break;
+
+ radius = goInfo->trap.cooldown; // battlegrounds gameobjects has data2 == 0 && data5 == 3
+ IsBattleGroundTrap = true;
- radius = goInfo->trap.cooldown; // battlegrounds gameobjects has data2 == 0 && data5 == 3
- IsBattleGroundTrap = true;
+ if(!radius)
+ return;
+ }
}
- if(!radius)
- return;
- }
- // Note: this hack with search required until GO casting not implemented
- // search unfriendly creature
- if(owner) // hunter trap
- {
- Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck checker(this, owner, radius);
- Trinity::UnitSearcher<Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck> searcher(this, ok, checker);
- VisitNearbyGridObject(radius, searcher);
- if(!ok) VisitNearbyWorldObject(radius, searcher);
- }
- else // environmental trap
- {
- // environmental damage spells already have around enemies targeting but this not help in case not existed GO casting support
- // affect only players
- Player* player = NULL;
- MaNGOS::AnyPlayerInObjectRangeCheck checker(this, radius);
- MaNGOS::PlayerSearcher<MaNGOS::AnyPlayerInObjectRangeCheck> searcher(this, player, checker);
- VisitNearbyWorldObject(radius, searcher);
- ok = player;
- }
+ // Note: this hack with search required until GO casting not implemented
+ // search unfriendly creature
+ if(owner) // hunter trap
+ {
+ Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck checker(this, owner, radius);
+ Trinity::UnitSearcher<Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck> searcher(this, ok, checker);
+ VisitNearbyGridObject(radius, searcher);
+ if(!ok) VisitNearbyWorldObject(radius, searcher);
+ }
+ else // environmental trap
+ {
+ // environmental damage spells already have around enemies targeting but this not help in case not existed GO casting support
+ // affect only players
+ Player* player = NULL;
+ MaNGOS::AnyPlayerInObjectRangeCheck checker(this, radius);
+ MaNGOS::PlayerSearcher<MaNGOS::AnyPlayerInObjectRangeCheck> searcher(this, player, checker);
+ VisitNearbyWorldObject(radius, searcher);
+ ok = player;
+ }
+
+ if (ok)
+ {
+ // some traps do not have spell but should be triggered
+ if(goInfo->trap.spellId)
+ CastSpell(ok, goInfo->trap.spellId);
- if (ok)
- {
- // some traps do not have spell but should be triggered
- if(goInfo->trap.spellId)
- CastSpell(ok, goInfo->trap.spellId);
- //Unit *caster = owner ? owner : ok;
- //caster->CastSpell(ok, goInfo->trap.spellId, true, 0, 0, GetGUID());
-
- if(goInfo->trap.cooldown)
- m_cooldownTime = time(NULL) + goInfo->trap.cooldown;
- else
m_cooldownTime = time(NULL) + 4; // 4 seconds
- if(owner)
- SetLootState(GO_JUST_DEACTIVATED); // can be despawned or destroyed
+ // count charges
+ //if(goInfo->trap.charges > 0)
+ // AddUse();
+
+ if(owner)
+ SetLootState(GO_JUST_DEACTIVATED);
- if(IsBattleGroundTrap && ok->GetTypeId() == TYPEID_PLAYER)
+ if(IsBattleGroundTrap && ok->GetTypeId() == TYPEID_PLAYER)
+ {
+ //BattleGround gameobjects case
+ if(((Player*)ok)->InBattleGround())
+ if(BattleGround *bg = ((Player*)ok)->GetBattleGround())
+ bg->HandleTriggerBuff(GetGUID());
+ }
+ }
+ }
+ else if(uint32 max_charges = goInfo->GetCharges())
+ {
+ if (m_usetimes >= max_charges)
{
- //BattleGround gameobjects case
- if(((Player*)ok)->InBattleGround())
- if(BattleGround *bg = ((Player*)ok)->GetBattleGround())
- bg->HandleTriggerBuff(GetGUID());
+ m_usetimes = 0;
+ SetLootState(GO_JUST_DEACTIVATED); // can be despawned or destroyed
}
}
}
- if (m_charges && m_usetimes >= m_charges)
- SetLootState(GO_JUST_DEACTIVATED); // can be despawned or destroyed
-
break;
}
case GO_ACTIVATED:
@@ -387,7 +401,7 @@ void GameObject::Update(uint32 /*p_time*/)
{
case GAMEOBJECT_TYPE_DOOR:
case GAMEOBJECT_TYPE_BUTTON:
- if (GetAutoCloseTime() && (m_cooldownTime < time(NULL)))
+ if (GetGOInfo()->GetAutoCloseTime() && (m_cooldownTime < time(NULL)))
ResetDoorOrButton();
break;
}
@@ -420,16 +434,17 @@ void GameObject::Update(uint32 /*p_time*/)
if(GetOwnerGUID())
{
- if(Unit* owner = GetOwner())
+ if(Unit* owner = GetOwner(false))
+ {
owner->RemoveGameObject(this, false);
-
- SetRespawnTime(0);
- Delete();
+ SetRespawnTime(0);
+ Delete();
+ }
return;
}
//burning flags in some battlegrounds, if you find better condition, just add it
- if (GetGoAnimProgress() > 0)
+ if (GetGOInfo()->IsDespawnAtAction() || GetGoAnimProgress() > 0)
{
SendObjectDeSpawnAnim(GetGUID());
//reset flags
@@ -477,8 +492,18 @@ void GameObject::AddUniqueUse(Player* player)
m_unique_users.insert(player->GetGUIDLow());
}
+void GameObject::DeleteObjectWithOwner()
+{
+ SetLootState(GO_NOT_READY);
+ if (GetOwnerGUID())
+ if (Unit * owner = GetOwner(false))
+ owner->RemoveGameObject(this, false);
+ Delete();
+}
+
void GameObject::Delete()
{
+ assert (!GetOwnerGUID());
SendObjectDeSpawnAnim(GetGUID());
SetGoState(GO_STATE_READY);
@@ -609,7 +634,7 @@ bool GameObject::LoadFromDB(uint32 guid, Map *map)
if (!Create(guid,entry, map, phaseMask, x, y, z, ang, rotation0, rotation1, rotation2, rotation3, animprogress, go_state, ArtKit) )
return false;
- if(!GetDespawnPossibility())
+ if(!GetGOInfo()->GetDespawnPossibility() && !GetGOInfo()->IsDespawnAtAction())
{
SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NODESPAWN);
m_spawnedByDefault = true;
@@ -657,22 +682,6 @@ GameObject* GameObject::GetGameObject(WorldObject& object, uint64 guid)
return object.GetMap()->GetGameObject(guid);
}
-uint32 GameObject::GetLootId(GameObjectInfo const* ginfo)
-{
- if (!ginfo)
- return 0;
-
- switch(ginfo->type)
- {
- case GAMEOBJECT_TYPE_CHEST:
- return ginfo->chest.lootId;
- case GAMEOBJECT_TYPE_FISHINGHOLE:
- return ginfo->fishinghole.lootId;
- default:
- return 0;
- }
-}
-
/*********************************************************/
/*** QUEST SYSTEM ***/
/*********************************************************/
@@ -706,9 +715,11 @@ bool GameObject::IsTransport() const
return gInfo->type == GAMEOBJECT_TYPE_TRANSPORT || gInfo->type == GAMEOBJECT_TYPE_MO_TRANSPORT;
}
-Unit* GameObject::GetOwner() const
+Unit* GameObject::GetOwner(bool inWorld) const
{
- return ObjectAccessor::GetUnit(*this, GetOwnerGUID());
+ if (inWorld)
+ return ObjectAccessor::GetUnit(*this, GetOwnerGUID());
+ return ObjectAccessor::GetUnitInOrOutOfWorld(*this, GetOwnerGUID());
}
void GameObject::SaveRespawnTime()
@@ -788,7 +799,7 @@ bool GameObject::ActivateToQuest( Player *pTarget)const
// scan GO chest with loot including quest items
case GAMEOBJECT_TYPE_CHEST:
{
- if(LootTemplates_Gameobject.HaveQuestLootForPlayer(GetLootId(), pTarget))
+ if(LootTemplates_Gameobject.HaveQuestLootForPlayer(GetGOInfo()->GetLootId(), pTarget))
{
//TODO: fix this hack
//look for battlegroundAV for some objects which are only activated after mine gots captured by own team
@@ -894,7 +905,7 @@ void GameObject::UseDoorOrButton(uint32 time_to_restore, bool alternative /* = f
return;
if(!time_to_restore)
- time_to_restore = GetAutoCloseTime();
+ time_to_restore = GetGOInfo()->GetAutoCloseTime();
SwitchDoorOrButton(true,alternative);
SetLootState(GO_ACTIVATED);
@@ -938,7 +949,7 @@ void GameObject::Use(Unit* user)
UseDoorOrButton();
// activate script
- sWorld.ScriptsStart(sGameObjectScripts, GetDBTableGUIDLow(), spellCaster, this);
+ GetMap()->ScriptsStart(sGameObjectScripts, GetDBTableGUIDLow(), spellCaster, this);
return;
case GAMEOBJECT_TYPE_QUESTGIVER: //2
@@ -1034,7 +1045,7 @@ void GameObject::Use(Unit* user)
player->CastedCreatureOrGO(info->id, GetGUID(), 0);
if (info->goober.eventId)
- sWorld.ScriptsStart(sEventScripts, info->goober.eventId, player, this);
+ GetMap()->ScriptsStart(sEventScripts, info->goober.eventId, player, this);
}
// cast this spell later if provided
@@ -1057,7 +1068,7 @@ void GameObject::Use(Unit* user)
player->SendCinematicStart(info->camera.cinematicId);
if (info->camera.eventID)
- sWorld.ScriptsStart(sEventScripts, info->camera.eventID, player, this);
+ GetMap()->ScriptsStart(sEventScripts, info->camera.eventID, player, this);
return;
}
@@ -1358,6 +1369,7 @@ void GameObject::Use(Unit* user)
}
Spell *spell = new Spell(spellCaster, spellInfo, triggered);
+ //Spell *spell = new Spell(spellCaster, spellInfo, triggered,GetGUID());
// spell target is user of GO
SpellCastTargets targets;
diff --git a/src/game/GameObject.h b/src/game/GameObject.h
index 43f8fb0ea5f..43441e2fb9c 100644
--- a/src/game/GameObject.h
+++ b/src/game/GameObject.h
@@ -399,6 +399,98 @@ struct GameObjectInfo
} raw;
};
uint32 ScriptId;
+
+ // helpers
+ bool IsDespawnAtAction() const
+ {
+ switch(type)
+ {
+ case GAMEOBJECT_TYPE_CHEST: return chest.consumable;
+ case GAMEOBJECT_TYPE_GOOBER: return goober.consumable;
+ default: return false;
+ }
+ }
+
+ uint32 GetLockId() const
+ {
+ switch(type)
+ {
+ case GAMEOBJECT_TYPE_DOOR: return door.lockId;
+ case GAMEOBJECT_TYPE_BUTTON: return button.lockId;
+ case GAMEOBJECT_TYPE_QUESTGIVER: return questgiver.lockId;
+ case GAMEOBJECT_TYPE_CHEST: return chest.lockId;
+ case GAMEOBJECT_TYPE_TRAP: return trap.lockId;
+ case GAMEOBJECT_TYPE_GOOBER: return goober.lockId;
+ case GAMEOBJECT_TYPE_AREADAMAGE: return areadamage.lockId;
+ case GAMEOBJECT_TYPE_CAMERA: return camera.lockId;
+ case GAMEOBJECT_TYPE_FLAGSTAND: return flagstand.lockId;
+ case GAMEOBJECT_TYPE_FISHINGHOLE:return fishinghole.lockId;
+ case GAMEOBJECT_TYPE_FLAGDROP: return flagdrop.lockId;
+ default: return 0;
+ }
+ }
+
+ bool GetDespawnPossibility() const // despawn at targeting of cast?
+ {
+ switch(type)
+ {
+ case GAMEOBJECT_TYPE_DOOR: return door.noDamageImmune;
+ case GAMEOBJECT_TYPE_BUTTON: return button.noDamageImmune;
+ case GAMEOBJECT_TYPE_QUESTGIVER: return questgiver.noDamageImmune;
+ case GAMEOBJECT_TYPE_GOOBER: return goober.noDamageImmune;
+ case GAMEOBJECT_TYPE_FLAGSTAND: return flagstand.noDamageImmune;
+ case GAMEOBJECT_TYPE_FLAGDROP: return flagdrop.noDamageImmune;
+ default: return true;
+ }
+ }
+
+ uint32 GetCharges() const // despawn at uses amount
+ {
+ switch(type)
+ {
+ //case GAMEOBJECT_TYPE_TRAP: return trap.charges;
+ case GAMEOBJECT_TYPE_GUARDPOST: return guardpost.charges;
+ case GAMEOBJECT_TYPE_SPELLCASTER: return spellcaster.charges;
+ default: return 0;
+ }
+ }
+
+ uint32 GetLinkedGameObjectEntry() const
+ {
+ switch(type)
+ {
+ case GAMEOBJECT_TYPE_CHEST: return chest.linkedTrapId;
+ case GAMEOBJECT_TYPE_SPELL_FOCUS: return spellFocus.linkedTrapId;
+ case GAMEOBJECT_TYPE_GOOBER: return goober.linkedTrapId;
+ default: return 0;
+ }
+ }
+
+ uint32 GetAutoCloseTime() const
+ {
+ uint32 autoCloseTime = 0;
+ switch(type)
+ {
+ case GAMEOBJECT_TYPE_DOOR: autoCloseTime = door.autoCloseTime; break;
+ case GAMEOBJECT_TYPE_BUTTON: autoCloseTime = button.autoCloseTime; break;
+ case GAMEOBJECT_TYPE_TRAP: autoCloseTime = trap.autoCloseTime; break;
+ case GAMEOBJECT_TYPE_GOOBER: autoCloseTime = goober.autoCloseTime; break;
+ case GAMEOBJECT_TYPE_TRANSPORT: autoCloseTime = transport.autoCloseTime; break;
+ case GAMEOBJECT_TYPE_AREADAMAGE: autoCloseTime = areadamage.autoCloseTime; break;
+ default: break;
+ }
+ return autoCloseTime / 0x10000;
+ }
+
+ uint32 GetLootId() const
+ {
+ switch(type)
+ {
+ case GAMEOBJECT_TYPE_CHEST: return chest.lootId;
+ case GAMEOBJECT_TYPE_FISHINGHOLE: return fishinghole.lootId;
+ default: return 0;
+ }
+ }
};
class OPvPCapturePoint;
@@ -488,6 +580,7 @@ class TRINITY_DLL_SPEC GameObject : public WorldObject
void AddToWorld();
void RemoveFromWorld();
+ void CleanupsBeforeDelete();
bool Create(uint32 guidlow, uint32 name_id, Map *map, uint32 phaseMask, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, GOState go_state, uint32 ArtKit = 0);
void Update(uint32 p_time);
@@ -498,14 +591,6 @@ class TRINITY_DLL_SPEC GameObject : public WorldObject
bool IsTransport() const;
- void SetOwnerGUID(uint64 owner)
- {
- m_spawnedByDefault = false; // all object with owner is despawned after delay
- SetUInt64Value(OBJECT_FIELD_CREATED_BY, owner);
- }
- uint64 GetOwnerGUID() const { return GetUInt64Value(OBJECT_FIELD_CREATED_BY); }
- Unit* GetOwner() const;
-
uint32 GetDBTableGUIDLow() const { return m_DBTableGuid; }
void UpdateRotationFields(float rotation2 = 0.0f, float rotation3 = 0.0f);
@@ -523,40 +608,26 @@ class TRINITY_DLL_SPEC GameObject : public WorldObject
void SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask);
bool LoadFromDB(uint32 guid, Map *map);
void DeleteFromDB();
- static uint32 GetLootId(GameObjectInfo const* info);
- uint32 GetLootId() const { return GetLootId(GetGOInfo()); }
- uint32 GetLockId() const
+
+ void SetOwnerGUID(uint64 owner)
{
- switch(GetGoType())
+ // Owner already found and different than expected owner - remove object from old owner
+ if (owner && GetOwnerGUID() && GetOwnerGUID() != owner)
{
- case GAMEOBJECT_TYPE_DOOR: return GetGOInfo()->door.lockId;
- case GAMEOBJECT_TYPE_BUTTON: return GetGOInfo()->button.lockId;
- case GAMEOBJECT_TYPE_QUESTGIVER: return GetGOInfo()->questgiver.lockId;
- case GAMEOBJECT_TYPE_CHEST: return GetGOInfo()->chest.lockId;
- case GAMEOBJECT_TYPE_TRAP: return GetGOInfo()->trap.lockId;
- case GAMEOBJECT_TYPE_GOOBER: return GetGOInfo()->goober.lockId;
- case GAMEOBJECT_TYPE_AREADAMAGE: return GetGOInfo()->areadamage.lockId;
- case GAMEOBJECT_TYPE_CAMERA: return GetGOInfo()->camera.lockId;
- case GAMEOBJECT_TYPE_FLAGSTAND: return GetGOInfo()->flagstand.lockId;
- case GAMEOBJECT_TYPE_FISHINGHOLE:return GetGOInfo()->fishinghole.lockId;
- case GAMEOBJECT_TYPE_FLAGDROP: return GetGOInfo()->flagdrop.lockId;
- default: return 0;
+ assert(false);
}
+ m_spawnedByDefault = false; // all object with owner is despawned after delay
+ SetUInt64Value(OBJECT_FIELD_CREATED_BY, owner);
}
+ uint64 GetOwnerGUID() const { return GetUInt64Value(OBJECT_FIELD_CREATED_BY); }
+ Unit* GetOwner(bool inWorld = true) const;
- bool GetDespawnPossibility() const
+ void SetSpellId(uint32 id)
{
- switch(GetGoType())
- {
- case GAMEOBJECT_TYPE_DOOR: return GetGOInfo()->door.noDamageImmune;
- case GAMEOBJECT_TYPE_BUTTON: return GetGOInfo()->button.noDamageImmune;
- case GAMEOBJECT_TYPE_QUESTGIVER: return GetGOInfo()->questgiver.noDamageImmune;
- case GAMEOBJECT_TYPE_GOOBER: return GetGOInfo()->goober.noDamageImmune;
- case GAMEOBJECT_TYPE_FLAGSTAND: return GetGOInfo()->flagstand.noDamageImmune;
- case GAMEOBJECT_TYPE_FLAGDROP: return GetGOInfo()->flagdrop.noDamageImmune;
- default: return true;
- }
+ m_spawnedByDefault = false; // all summoned object is despawned after delay
+ m_spellId = id;
}
+ uint32 GetSpellId() const { return m_spellId;}
time_t GetRespawnTime() const { return m_respawnTime; }
time_t GetRespawnTimeEx() const
@@ -585,8 +656,7 @@ class TRINITY_DLL_SPEC GameObject : public WorldObject
uint32 GetRespawnDelay() const { return m_respawnDelayTime; }
void Refresh();
void Delete();
- void SetSpellId(uint32 id) { m_spellId = id;}
- uint32 GetSpellId() const { return m_spellId;}
+ void DeleteObjectWithOwner();
void getFishLoot(Loot *loot, Player* loot_owner);
GameobjectTypes GetGoType() const { return GameobjectTypes(GetByteValue(GAMEOBJECT_BYTES_1, 1)); }
void SetGoType(GameobjectTypes type) { SetByteValue(GAMEOBJECT_BYTES_1, 1, type); }
@@ -627,34 +697,7 @@ class TRINITY_DLL_SPEC GameObject : public WorldObject
void UseDoorOrButton(uint32 time_to_restore = 0, bool alternative = false);
// 0 = use `gameobject`.`spawntimesecs`
void ResetDoorOrButton();
- // 0 = use `gameobject`.`spawntimesecs`
-
- uint32 GetLinkedGameObjectEntry() const
- {
- switch(GetGoType())
- {
- case GAMEOBJECT_TYPE_CHEST: return GetGOInfo()->chest.linkedTrapId;
- case GAMEOBJECT_TYPE_SPELL_FOCUS: return GetGOInfo()->spellFocus.linkedTrapId;
- case GAMEOBJECT_TYPE_GOOBER: return GetGOInfo()->goober.linkedTrapId;
- default: return 0;
- }
- }
- uint32 GetAutoCloseTime() const
- {
- uint32 autoCloseTime = 0;
- switch(GetGoType())
- {
- case GAMEOBJECT_TYPE_DOOR: autoCloseTime = GetGOInfo()->door.autoCloseTime; break;
- case GAMEOBJECT_TYPE_BUTTON: autoCloseTime = GetGOInfo()->button.autoCloseTime; break;
- case GAMEOBJECT_TYPE_TRAP: autoCloseTime = GetGOInfo()->trap.autoCloseTime; break;
- case GAMEOBJECT_TYPE_GOOBER: autoCloseTime = GetGOInfo()->goober.autoCloseTime; break;
- case GAMEOBJECT_TYPE_TRANSPORT: autoCloseTime = GetGOInfo()->transport.autoCloseTime; break;
- case GAMEOBJECT_TYPE_AREADAMAGE: autoCloseTime = GetGOInfo()->areadamage.autoCloseTime; break;
- default: break;
- }
- return autoCloseTime / 0x10000;
- }
void TriggeringLinkedGameObject( uint32 trapEntry, Unit* target);
@@ -675,7 +718,6 @@ class TRINITY_DLL_SPEC GameObject : public WorldObject
uint64 GetRotation() const { return m_rotation; }
protected:
- uint32 m_charges; // Spell charges for GAMEOBJECT_TYPE_SPELLCASTER (22)
uint32 m_spellId;
time_t m_respawnTime; // (secs) time of next respawn (or despawn if GO have owner()),
uint32 m_respawnDelayTime; // (secs) if 0 then current GO state no dependent from timer
diff --git a/src/game/GridDefines.h b/src/game/GridDefines.h
index a3fe011f402..05080521f58 100644
--- a/src/game/GridDefines.h
+++ b/src/game/GridDefines.h
@@ -35,10 +35,8 @@ class Player;
#ifdef LARGE_CELL
#define MAX_NUMBER_OF_CELLS 4
-#define CENTER_GRID_CELL_ID 128
#else
#define MAX_NUMBER_OF_CELLS 8
-#define CENTER_GRID_CELL_ID 256
#endif
#define MAX_NUMBER_OF_GRIDS 64
@@ -53,6 +51,7 @@ class Player;
#define SIZE_OF_GRID_CELL (SIZE_OF_GRIDS/MAX_NUMBER_OF_CELLS)
+#define CENTER_GRID_CELL_ID (MAX_NUMBER_OF_CELLS*MAX_NUMBER_OF_GRIDS/2)
#define CENTER_GRID_CELL_OFFSET (SIZE_OF_GRID_CELL/2)
#define TOTAL_NUMBER_OF_CELLS_PER_MAP (MAX_NUMBER_OF_GRIDS*MAX_NUMBER_OF_CELLS)
@@ -73,7 +72,7 @@ typedef GridRefManager<GameObject> GameObjectMapType;
typedef GridRefManager<Player> PlayerMapType;
typedef Grid<Player, AllWorldObjectTypes,AllGridObjectTypes> GridType;
-typedef NGrid<8, Player, AllWorldObjectTypes, AllGridObjectTypes> NGridType;
+typedef NGrid<MAX_NUMBER_OF_CELLS, Player, AllWorldObjectTypes, AllGridObjectTypes> NGridType;
typedef TypeMapContainer<AllGridObjectTypes> GridTypeMapContainer;
typedef TypeMapContainer<AllWorldObjectTypes> WorldTypeMapContainer;
diff --git a/src/game/GridNotifiers.h b/src/game/GridNotifiers.h
index 64deb0d3123..997f0806369 100644
--- a/src/game/GridNotifiers.h
+++ b/src/game/GridNotifiers.h
@@ -1135,48 +1135,69 @@ namespace Trinity
Unit const* pUnit;
};
- class AllGameObjectsWithEntryInGrid
+ class AllGameObjectsWithEntryInRange
{
public:
- AllGameObjectsWithEntryInGrid(uint32 ent) : entry(ent) {}
- bool operator() (GameObject* g)
+ AllGameObjectsWithEntryInRange(const WorldObject* pObject, uint32 uiEntry, float fMaxRange) : m_pObject(pObject), m_uiEntry(uiEntry), m_fRange(fMaxRange) {}
+ bool operator() (GameObject* pGo)
{
- if(g->GetEntry() == entry)
+ if (pGo->GetEntry() == m_uiEntry && m_pObject->IsWithinDist(pGo,m_fRange,false))
return true;
return false;
}
private:
- uint32 entry;
+ const WorldObject* m_pObject;
+ uint32 m_uiEntry;
+ float m_fRange;
};
- class GameObjectInRangeCheck
+ class AllCreaturesOfEntryInRange
{
- public:
- GameObjectInRangeCheck(float _x, float _y, float _z, float _range) : x(_x), y(_y), z(_z), range(_range) {}
- bool operator() (GameObject* go)
- {
- return go->IsInRange(x, y, z, range);
- }
- private:
- float x, y, z, range;
+ public:
+ AllCreaturesOfEntryInRange(const WorldObject* pObject, uint32 uiEntry, float fMaxRange) : m_pObject(pObject), m_uiEntry(uiEntry), m_fRange(fMaxRange) {}
+ bool operator() (Unit* pUnit)
+ {
+ if (pUnit->GetEntry() == m_uiEntry && m_pObject->IsWithinDist(pUnit,m_fRange,false))
+ return true;
+
+ return false;
+ }
+
+ private:
+ const WorldObject* m_pObject;
+ uint32 m_uiEntry;
+ float m_fRange;
};
- class AllCreaturesOfEntryInRange
+ class PlayerAtMinimumRangeAway
{
public:
- AllCreaturesOfEntryInRange(Unit const* obj, uint32 ent, float ran) : pUnit(obj), entry(ent), range(ran) {}
- bool operator() (Unit* u)
+ PlayerAtMinimumRangeAway(Unit const* unit, float fMinRange) : pUnit(unit), fRange(fMinRange) {}
+ bool operator() (Player* pPlayer)
{
- if(u->GetEntry() == entry && pUnit->IsWithinDistInMap(u, range))
+ //No threat list check, must be done explicit if expected to be in combat with creature
+ if (!pPlayer->isGameMaster() && pPlayer->isAlive() && !pUnit->IsWithinDist(pPlayer,fRange,false))
return true;
return false;
}
+
private:
Unit const* pUnit;
- uint32 entry;
- float range;
+ float fRange;
+ };
+
+ class GameObjectInRangeCheck
+ {
+ public:
+ GameObjectInRangeCheck(float _x, float _y, float _z, float _range) : x(_x), y(_y), z(_z), range(_range) {}
+ bool operator() (GameObject* go)
+ {
+ return go->IsInRange(x, y, z, range);
+ }
+ private:
+ float x, y, z, range;
};
// Player checks and do
diff --git a/src/game/GridNotifiersImpl.h b/src/game/GridNotifiersImpl.h
index 6502c2ea7c8..211bca9cd3c 100644
--- a/src/game/GridNotifiersImpl.h
+++ b/src/game/GridNotifiersImpl.h
@@ -631,4 +631,28 @@ void MaNGOS::LocalizedPacketListDo<Builder>::operator()( Player* p )
p->SendDirectMessage((*data_list)[i]);
}
+struct ObjectDistanceOrder : public std::binary_function<const WorldObject, const WorldObject, bool>
+{
+ const Unit* m_pSource;
+
+ ObjectDistanceOrder(const Unit* pSource) : m_pSource(pSource) {};
+
+ bool operator()(const WorldObject* pLeft, const WorldObject* pRight) const
+ {
+ return m_pSource->GetDistanceOrder(pLeft, pRight);
+ }
+};
+
+struct ObjectDistanceOrderReversed : public std::binary_function<const WorldObject, const WorldObject, bool>
+{
+ const Unit* m_pSource;
+
+ ObjectDistanceOrderReversed(const Unit* pSource) : m_pSource(pSource) {};
+
+ bool operator()(const WorldObject* pLeft, const WorldObject* pRight) const
+ {
+ return !m_pSource->GetDistanceOrder(pLeft, pRight);
+ }
+};
+
#endif // MANGOS_GRIDNOTIFIERSIMPL_H
diff --git a/src/game/Group.cpp b/src/game/Group.cpp
index c08d1236c32..8a02afa25d2 100644
--- a/src/game/Group.cpp
+++ b/src/game/Group.cpp
@@ -967,7 +967,7 @@ void Group::SendUpdate()
void Group::UpdatePlayerOutOfRange(Player* pPlayer)
{
- if(!pPlayer)
+ if(!pPlayer || !pPlayer->IsInWorld())
return;
Player *player;
@@ -1510,7 +1510,7 @@ void Group::ResetInstances(uint8 method, Player* SendMsgTo)
bool isEmpty = true;
// if the map is loaded, reset it
Map *map = MapManager::Instance().FindMap(p->GetMapId(), p->GetInstanceId());
- if(map && map->IsDungeon())
+ if(map && map->IsDungeon() && !(method == INSTANCE_RESET_GROUP_DISBAND && !p->CanReset()))
{
if(p->CanReset())
isEmpty = ((InstanceMap*)map)->Reset(method);
diff --git a/src/game/Guild.cpp b/src/game/Guild.cpp
index 84271f08d04..7efc92c2fe0 100644
--- a/src/game/Guild.cpp
+++ b/src/game/Guild.cpp
@@ -283,7 +283,7 @@ bool Guild::LoadRanksFromDB(uint32 GuildId)
std::string name = m_ranks[i].name;
uint32 rights = m_ranks[i].rights;
CharacterDatabase.escape_string(name);
- CharacterDatabase.PExecute( "INSERT INTO guild_rank (guildid,rid,rname,rights) VALUES ('%u', '%u', '%s', '%u')", GuildId, i+1, name.c_str(), rights);
+ CharacterDatabase.PExecute( "INSERT INTO guild_rank (guildid,rid,rname,rights) VALUES ('%u', '%u', '%s', '%u')", GuildId, uint32(i+1), name.c_str(), rights);
}
CharacterDatabase.CommitTransaction();
}
@@ -369,20 +369,17 @@ bool Guild::FillPlayerData(uint64 guid, MemberSlot* memslot)
}
else
{
- QueryResult *result = CharacterDatabase.PQuery("SELECT name,data,zone,class FROM characters WHERE guid = '%u'", GUID_LOPART(guid));
- if(!result)
- return false; // player doesn't exist
+ QueryResult *result = CharacterDatabase.PQuery("SELECT name,level,zone,class FROM characters WHERE guid = '%u'", GUID_LOPART(guid));
+ if(!result)
+ return false; // player doesn't exist
Field *fields = result->Fetch();
- plName = fields[0].GetCppString();
-
- Tokens data = StrSplit(fields[1].GetCppString(), " ");
- plLevel = Player::GetUInt32ValueFromArray(data,UNIT_FIELD_LEVEL);
-
- plZone = fields[2].GetUInt32();
- plClass = fields[3].GetUInt32();
- delete result;
+ plName = fields[0].GetCppString();
+ plLevel = fields[1].GetUInt32();
+ plZone = fields[2].GetUInt32();
+ plClass = fields[3].GetUInt32();
+ delete result;
if(plLevel<1||plLevel>STRONG_MAX_LEVEL) // can be at broken `data` field
{
@@ -716,40 +713,40 @@ void Guild::Roster(WorldSession *session)
data << (uint32)m_ranks.size();
for (RankList::const_iterator ritr = m_ranks.begin(); ritr != m_ranks.end(); ++ritr)
{
- data << (uint32)ritr->rights;
- data << (uint32)ritr->BankMoneyPerDay; // count of: withdraw gold(gold/day) Note: in game set gold, in packet set bronze.
- for (uint8 i = 0; i < GUILD_BANK_MAX_TABS; ++i)
+ data << uint32(ritr->rights);
+ data << uint32(ritr->BankMoneyPerDay); // count of: withdraw gold(gold/day) Note: in game set gold, in packet set bronze.
+ for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i)
{
- data << (uint32)ritr->TabRight[i]; // for TAB_i rights: view tabs = 0x01, deposit items =0x02
- data << (uint32)ritr->TabSlotPerDay[i]; // for TAB_i count of: withdraw items(stack/day)
+ data << uint32(ritr->TabRight[i]); // for TAB_i rights: view tabs = 0x01, deposit items =0x02
+ data << uint32(ritr->TabSlotPerDay[i]); // for TAB_i count of: withdraw items(stack/day)
}
}
for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
{
if (Player *pl = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)))
{
- data << (uint64)pl->GetGUID();
- data << (uint8)1;
- data << (std::string)pl->GetName();
- data << (uint32)itr->second.RankId;
- data << (uint8)pl->getLevel();
- data << (uint8)pl->getClass();
- data << (uint8)0; // new 2.4.0
- data << (uint32)pl->GetZoneId();
+ data << uint64(pl->GetGUID());
+ data << uint8(1);
+ data << pl->GetName();
+ data << uint32(itr->second.RankId);
+ data << uint8(pl->getLevel());
+ data << uint8(pl->getClass());
+ data << uint8(0); // new 2.4.0
+ data << uint32(pl->GetZoneId());
data << itr->second.Pnote;
data << itr->second.OFFnote;
}
else
{
data << uint64(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
- data << (uint8)0;
+ data << uint8(0);
data << itr->second.name;
- data << (uint32)itr->second.RankId;
- data << (uint8)itr->second.level;
- data << (uint8)itr->second.Class;
- data << (uint8)0; // new 2.4.0
- data << (uint32)itr->second.zoneId;
- data << (float(time(NULL)-itr->second.logout_time) / DAY);
+ data << uint32(itr->second.RankId);
+ data << uint8(itr->second.level);
+ data << uint8(itr->second.Class);
+ data << uint8(0); // new 2.4.0
+ data << uint32(itr->second.zoneId);
+ data << float(float(time(NULL)-itr->second.logout_time) / DAY);
data << itr->second.Pnote;
data << itr->second.OFFnote;
}
@@ -829,17 +826,17 @@ void Guild::DisplayGuildEventlog(WorldSession *session)
for (GuildEventlog::const_iterator itr = m_GuildEventlog.begin(); itr != m_GuildEventlog.end(); ++itr)
{
// Event type
- data << uint8((*itr)->EventType);
+ data << uint8(itr->EventType);
// Player 1
- data << uint64((*itr)->PlayerGuid1);
+ data << uint64(itr->PlayerGuid1);
// Player 2 not for left/join guild events
- if( (*itr)->EventType != GUILD_EVENT_LOG_JOIN_GUILD && (*itr)->EventType != GUILD_EVENT_LOG_LEAVE_GUILD )
- data << uint64((*itr)->PlayerGuid2);
+ if (itr->EventType != GUILD_EVENT_LOG_JOIN_GUILD && itr->EventType != GUILD_EVENT_LOG_LEAVE_GUILD)
+ data << uint64(itr->PlayerGuid2);
// New Rank - only for promote/demote guild events
- if( (*itr)->EventType == GUILD_EVENT_LOG_PROMOTE_PLAYER || (*itr)->EventType == GUILD_EVENT_LOG_DEMOTE_PLAYER )
- data << uint8((*itr)->NewRank);
+ if (itr->EventType == GUILD_EVENT_LOG_PROMOTE_PLAYER || itr->EventType == GUILD_EVENT_LOG_DEMOTE_PLAYER)
+ data << uint8(itr->NewRank);
// Event timestamp
- data << uint32(time(NULL)-(*itr)->TimeStamp);
+ data << uint32(time(NULL)-itr->TimeStamp);
}
session->SendPacket(&data);
sLog.outDebug("WORLD: Sent (MSG_GUILD_EVENT_LOG_QUERY)");
@@ -858,14 +855,14 @@ void Guild::LoadGuildEventLogFromDB()
do
{
Field *fields = result->Fetch();
- GuildEventlogEntry *NewEvent = new GuildEventlogEntry;
+ GuildEventlogEntry NewEvent;
// Fill entry
- NewEvent->LogGuid = fields[0].GetUInt32();
- NewEvent->EventType = fields[1].GetUInt8();
- NewEvent->PlayerGuid1 = fields[2].GetUInt32();
- NewEvent->PlayerGuid2 = fields[3].GetUInt32();
- NewEvent->NewRank = fields[4].GetUInt8();
- NewEvent->TimeStamp = fields[5].GetUInt64();
+ NewEvent.LogGuid = fields[0].GetUInt32();
+ NewEvent.EventType = fields[1].GetUInt8();
+ NewEvent.PlayerGuid1 = fields[2].GetUInt32();
+ NewEvent.PlayerGuid2 = fields[3].GetUInt32();
+ NewEvent.NewRank = fields[4].GetUInt8();
+ NewEvent.TimeStamp = fields[5].GetUInt64();
// Add entry to map
m_GuildEventlog.push_front(NewEvent);
@@ -875,9 +872,8 @@ void Guild::LoadGuildEventLogFromDB()
// Check lists size in case to many event entries in db
// This cases can happen only if a crash occured somewhere and table has too many log entries
if (!m_GuildEventlog.empty())
- {
- CharacterDatabase.PExecute("DELETE FROM guild_eventlog WHERE guildid=%u AND LogGuid < %u", Id, m_GuildEventlog.front()->LogGuid);
- }
+ CharacterDatabase.PExecute("DELETE FROM guild_eventlog WHERE guildid=%u AND LogGuid < %u", Id, m_GuildEventlog.front().LogGuid);
+
m_eventlogloaded = true;
}
@@ -886,16 +882,8 @@ void Guild::UnloadGuildEventlog()
{
if (!m_eventlogloaded)
return;
- GuildEventlogEntry *EventLogEntry;
- if( !m_GuildEventlog.empty() )
- {
- do
- {
- EventLogEntry = *(m_GuildEventlog.begin());
- m_GuildEventlog.pop_front();
- delete EventLogEntry;
- }while( !m_GuildEventlog.empty() );
- }
+
+ m_GuildEventlog.clear();
m_eventlogloaded = false;
}
@@ -915,27 +903,25 @@ void Guild::RenumGuildEventlog()
// Add entry to guild eventlog
void Guild::LogGuildEvent(uint8 EventType, uint32 PlayerGuid1, uint32 PlayerGuid2, uint8 NewRank)
{
- GuildEventlogEntry *NewEvent = new GuildEventlogEntry;
+ GuildEventlogEntry NewEvent;
// Fill entry
- NewEvent->LogGuid = GuildEventlogMaxGuid++;
- NewEvent->EventType = EventType;
- NewEvent->PlayerGuid1 = PlayerGuid1;
- NewEvent->PlayerGuid2 = PlayerGuid2;
- NewEvent->NewRank = NewRank;
- NewEvent->TimeStamp = uint32(time(NULL));
+ NewEvent.LogGuid = GuildEventlogMaxGuid++;
+ NewEvent.EventType = EventType;
+ NewEvent.PlayerGuid1 = PlayerGuid1;
+ NewEvent.PlayerGuid2 = PlayerGuid2;
+ NewEvent.NewRank = NewRank;
+ NewEvent.TimeStamp = uint32(time(NULL));
// Check max entry limit and delete from db if needed
if (m_GuildEventlog.size() > GUILD_EVENTLOG_MAX_ENTRIES)
{
- GuildEventlogEntry *OldEvent = *(m_GuildEventlog.begin());
+ CharacterDatabase.PExecute("DELETE FROM guild_eventlog WHERE guildid='%u' AND LogGuid='%u'", Id, m_GuildEventlog.front().LogGuid);
m_GuildEventlog.pop_front();
- CharacterDatabase.PExecute("DELETE FROM guild_eventlog WHERE guildid='%u' AND LogGuid='%u'", Id, OldEvent->LogGuid);
- delete OldEvent;
}
// Add entry to map
m_GuildEventlog.push_back(NewEvent);
// Add new eventlog entry into DB
CharacterDatabase.PExecute("INSERT INTO guild_eventlog (guildid, LogGuid, EventType, PlayerGuid1, PlayerGuid2, NewRank, TimeStamp) VALUES ('%u','%u','%u','%u','%u','%u','" UI64FMTD "')",
- Id, NewEvent->LogGuid, uint32(NewEvent->EventType), NewEvent->PlayerGuid1, NewEvent->PlayerGuid2, uint32(NewEvent->NewRank), NewEvent->TimeStamp);
+ Id, NewEvent.LogGuid, uint32(NewEvent.EventType), NewEvent.PlayerGuid1, NewEvent.PlayerGuid2, uint32(NewEvent.NewRank), NewEvent.TimeStamp);
}
// *************************************************
@@ -1507,30 +1493,28 @@ void Guild::LoadGuildBankEventLogFromDB()
do
{
Field *fields = result->Fetch();
- GuildBankEvent *NewEvent = new GuildBankEvent;
+ GuildBankEvent NewEvent;
- NewEvent->LogGuid = fields[0].GetUInt32();
- NewEvent->LogEntry = fields[1].GetUInt8();
+ NewEvent.LogGuid = fields[0].GetUInt32();
+ NewEvent.LogEntry = fields[1].GetUInt8();
uint8 TabId = fields[2].GetUInt8();
- NewEvent->PlayerGuid = fields[3].GetUInt32();
- NewEvent->ItemOrMoney = fields[4].GetUInt32();
- NewEvent->ItemStackCount = fields[5].GetUInt8();
- NewEvent->DestTabId = fields[6].GetUInt8();
- NewEvent->TimeStamp = fields[7].GetUInt64();
+ NewEvent.PlayerGuid = fields[3].GetUInt32();
+ NewEvent.ItemOrMoney = fields[4].GetUInt32();
+ NewEvent.ItemStackCount = fields[5].GetUInt8();
+ NewEvent.DestTabId = fields[6].GetUInt8();
+ NewEvent.TimeStamp = fields[7].GetUInt64();
if (TabId >= GUILD_BANK_MAX_TABS)
{
- sLog.outError( "Guild::LoadGuildBankEventLogFromDB: Invalid tabid '%u' for guild bank log entry (guild: '%s', LogGuid: %u), skipped.", TabId, GetName().c_str(), NewEvent->LogGuid);
- delete NewEvent;
+ sLog.outError( "Guild::LoadGuildBankEventLogFromDB: Invalid tabid '%u' for guild bank log entry (guild: '%s', LogGuid: %u), skipped.", TabId, GetName().c_str(), NewEvent.LogGuid);
continue;
}
- if (NewEvent->isMoneyEvent() && m_GuildBankEventLog_Money.size() >= GUILD_BANK_MAX_LOGS
- || m_GuildBankEventLog_Item[TabId].size() >= GUILD_BANK_MAX_LOGS)
- {
- delete NewEvent;
+
+ if (NewEvent.isMoneyEvent() && m_GuildBankEventLog_Money.size() >= GUILD_BANK_MAX_LOGS ||
+ m_GuildBankEventLog_Item[TabId].size() >= GUILD_BANK_MAX_LOGS)
continue;
- }
- if (NewEvent->isMoneyEvent())
+
+ if (NewEvent.isMoneyEvent())
m_GuildBankEventLog_Money.push_front(NewEvent);
else
m_GuildBankEventLog_Item[TabId].push_front(NewEvent);
@@ -1543,43 +1527,24 @@ void Guild::LoadGuildBankEventLogFromDB()
if (!m_GuildBankEventLog_Money.empty())
{
CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid=%u AND LogGuid < %u",
- Id, m_GuildBankEventLog_Money.front()->LogGuid);
+ Id, m_GuildBankEventLog_Money.front().LogGuid);
}
for (uint8 i = 0; i < GUILD_BANK_MAX_TABS; ++i)
{
if (!m_GuildBankEventLog_Item[i].empty())
{
CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid=%u AND LogGuid < %u",
- Id, m_GuildBankEventLog_Item[i].front()->LogGuid);
+ Id, m_GuildBankEventLog_Item[i].front().LogGuid);
}
}
}
void Guild::UnloadGuildBankEventLog()
{
- GuildBankEvent *EventLogEntry;
- if( !m_GuildBankEventLog_Money.empty() )
- {
- do
- {
- EventLogEntry = *(m_GuildBankEventLog_Money.begin());
- m_GuildBankEventLog_Money.pop_front();
- delete EventLogEntry;
- }while( !m_GuildBankEventLog_Money.empty() );
- }
+ m_GuildBankEventLog_Money.clear();
- for (uint8 i = 0; i < GUILD_BANK_MAX_TABS; ++i)
- {
- if( !m_GuildBankEventLog_Item[i].empty() )
- {
- do
- {
- EventLogEntry = *(m_GuildBankEventLog_Item[i].begin());
- m_GuildBankEventLog_Item[i].pop_front();
- delete EventLogEntry;
- }while( !m_GuildBankEventLog_Item[i].empty() );
- }
- }
+ for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i)
+ m_GuildBankEventLog_Item[i].clear();
}
void Guild::DisplayGuildBankLogs(WorldSession *session, uint8 TabId)
@@ -1595,24 +1560,24 @@ void Guild::DisplayGuildBankLogs(WorldSession *session, uint8 TabId)
data << uint8(m_GuildBankEventLog_Money.size()); // number of log entries
for (GuildBankEventLog::const_iterator itr = m_GuildBankEventLog_Money.begin(); itr != m_GuildBankEventLog_Money.end(); ++itr)
{
- data << uint8((*itr)->LogEntry);
- data << uint64(MAKE_NEW_GUID((*itr)->PlayerGuid,0,HIGHGUID_PLAYER));
- if ((*itr)->LogEntry == GUILD_BANK_LOG_DEPOSIT_MONEY ||
- (*itr)->LogEntry == GUILD_BANK_LOG_WITHDRAW_MONEY ||
- (*itr)->LogEntry == GUILD_BANK_LOG_REPAIR_MONEY ||
- (*itr)->LogEntry == GUILD_BANK_LOG_UNK1 ||
- (*itr)->LogEntry == GUILD_BANK_LOG_UNK2)
+ data << uint8(itr->LogEntry);
+ data << uint64(MAKE_NEW_GUID(itr->PlayerGuid,0,HIGHGUID_PLAYER));
+ if (itr->LogEntry == GUILD_BANK_LOG_DEPOSIT_MONEY ||
+ itr->LogEntry == GUILD_BANK_LOG_WITHDRAW_MONEY ||
+ itr->LogEntry == GUILD_BANK_LOG_REPAIR_MONEY ||
+ itr->LogEntry == GUILD_BANK_LOG_UNK1 ||
+ itr->LogEntry == GUILD_BANK_LOG_UNK2)
{
- data << uint32((*itr)->ItemOrMoney);
+ data << uint32(itr->ItemOrMoney);
}
else
{
- data << uint32((*itr)->ItemOrMoney);
- data << uint32((*itr)->ItemStackCount);
- if ((*itr)->LogEntry == GUILD_BANK_LOG_MOVE_ITEM || (*itr)->LogEntry == GUILD_BANK_LOG_MOVE_ITEM2)
- data << uint8((*itr)->DestTabId); // moved tab
+ data << uint32(itr->ItemOrMoney);
+ data << uint32(itr->ItemStackCount);
+ if (itr->LogEntry == GUILD_BANK_LOG_MOVE_ITEM || itr->LogEntry == GUILD_BANK_LOG_MOVE_ITEM2)
+ data << uint8(itr->DestTabId); // moved tab
}
- data << uint32(time(NULL)-(*itr)->TimeStamp);
+ data << uint32(time(NULL) - itr->TimeStamp);
}
session->SendPacket(&data);
}
@@ -1625,24 +1590,24 @@ void Guild::DisplayGuildBankLogs(WorldSession *session, uint8 TabId)
data << uint8(m_GuildBankEventLog_Item[TabId].size());
for (GuildBankEventLog::const_iterator itr = m_GuildBankEventLog_Item[TabId].begin(); itr != m_GuildBankEventLog_Item[TabId].end(); ++itr)
{
- data << uint8((*itr)->LogEntry);
- data << uint64(MAKE_NEW_GUID((*itr)->PlayerGuid,0,HIGHGUID_PLAYER));
- if ((*itr)->LogEntry == GUILD_BANK_LOG_DEPOSIT_MONEY ||
- (*itr)->LogEntry == GUILD_BANK_LOG_WITHDRAW_MONEY ||
- (*itr)->LogEntry == GUILD_BANK_LOG_REPAIR_MONEY ||
- (*itr)->LogEntry == GUILD_BANK_LOG_UNK1 ||
- (*itr)->LogEntry == GUILD_BANK_LOG_UNK2)
+ data << uint8(itr->LogEntry);
+ data << uint64(MAKE_NEW_GUID(itr->PlayerGuid,0,HIGHGUID_PLAYER));
+ if (itr->LogEntry == GUILD_BANK_LOG_DEPOSIT_MONEY ||
+ itr->LogEntry == GUILD_BANK_LOG_WITHDRAW_MONEY ||
+ itr->LogEntry == GUILD_BANK_LOG_REPAIR_MONEY ||
+ itr->LogEntry == GUILD_BANK_LOG_UNK1 ||
+ itr->LogEntry == GUILD_BANK_LOG_UNK2)
{
- data << uint32((*itr)->ItemOrMoney);
+ data << uint32(itr->ItemOrMoney);
}
else
{
- data << uint32((*itr)->ItemOrMoney);
- data << uint32((*itr)->ItemStackCount);
- if ((*itr)->LogEntry == GUILD_BANK_LOG_MOVE_ITEM || (*itr)->LogEntry == GUILD_BANK_LOG_MOVE_ITEM2)
- data << uint8((*itr)->DestTabId); // moved tab
+ data << uint32(itr->ItemOrMoney);
+ data << uint32(itr->ItemStackCount);
+ if (itr->LogEntry == GUILD_BANK_LOG_MOVE_ITEM || itr->LogEntry == GUILD_BANK_LOG_MOVE_ITEM2)
+ data << uint8(itr->DestTabId); // moved tab
}
- data << uint32(time(NULL)-(*itr)->TimeStamp);
+ data << uint32(time(NULL) - itr->TimeStamp);
}
session->SendPacket(&data);
}
@@ -1651,24 +1616,23 @@ void Guild::DisplayGuildBankLogs(WorldSession *session, uint8 TabId)
void Guild::LogBankEvent(uint8 LogEntry, uint8 TabId, uint32 PlayerGuidLow, uint32 ItemOrMoney, uint8 ItemStackCount, uint8 DestTabId)
{
- GuildBankEvent *NewEvent = new GuildBankEvent;
+ GuildBankEvent NewEvent;
- NewEvent->LogGuid = LogMaxGuid++;
- NewEvent->LogEntry = LogEntry;
- NewEvent->PlayerGuid = PlayerGuidLow;
- NewEvent->ItemOrMoney = ItemOrMoney;
- NewEvent->ItemStackCount = ItemStackCount;
- NewEvent->DestTabId = DestTabId;
- NewEvent->TimeStamp = uint32(time(NULL));
+ NewEvent.LogGuid = LogMaxGuid++;
+ NewEvent.LogEntry = LogEntry;
+ NewEvent.PlayerGuid = PlayerGuidLow;
+ NewEvent.ItemOrMoney = ItemOrMoney;
+ NewEvent.ItemStackCount = ItemStackCount;
+ NewEvent.DestTabId = DestTabId;
+ NewEvent.TimeStamp = uint32(time(NULL));
- if (NewEvent->isMoneyEvent())
+ if (NewEvent.isMoneyEvent())
{
if (m_GuildBankEventLog_Money.size() > GUILD_BANK_MAX_LOGS)
{
- GuildBankEvent *OldEvent = *(m_GuildBankEventLog_Money.begin());
+ CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid='%u' AND LogGuid='%u'",
+ Id, m_GuildBankEventLog_Money.front().LogGuid);
m_GuildBankEventLog_Money.pop_front();
- CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid='%u' AND LogGuid='%u'", Id, OldEvent->LogGuid);
- delete OldEvent;
}
m_GuildBankEventLog_Money.push_back(NewEvent);
}
@@ -1676,15 +1640,14 @@ void Guild::LogBankEvent(uint8 LogEntry, uint8 TabId, uint32 PlayerGuidLow, uint
{
if (m_GuildBankEventLog_Item[TabId].size() > GUILD_BANK_MAX_LOGS)
{
- GuildBankEvent *OldEvent = *(m_GuildBankEventLog_Item[TabId].begin());
+ CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid='%u' AND LogGuid='%u'",
+ Id, m_GuildBankEventLog_Item[TabId].front().LogGuid);
m_GuildBankEventLog_Item[TabId].pop_front();
- CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid='%u' AND LogGuid='%u'", Id, OldEvent->LogGuid);
- delete OldEvent;
}
m_GuildBankEventLog_Item[TabId].push_back(NewEvent);
}
CharacterDatabase.PExecute("INSERT INTO guild_bank_eventlog (guildid,LogGuid,LogEntry,TabId,PlayerGuid,ItemOrMoney,ItemStackCount,DestTabId,TimeStamp) VALUES ('%u','%u','%u','%u','%u','%u','%u','%u','" UI64FMTD "')",
- Id, NewEvent->LogGuid, uint32(NewEvent->LogEntry), uint32(TabId), NewEvent->PlayerGuid, NewEvent->ItemOrMoney, uint32(NewEvent->ItemStackCount), uint32(NewEvent->DestTabId), NewEvent->TimeStamp);
+ Id, NewEvent.LogGuid, uint32(NewEvent.LogEntry), uint32(TabId), NewEvent.PlayerGuid, NewEvent.ItemOrMoney, uint32(NewEvent.ItemStackCount), uint32(NewEvent.DestTabId), NewEvent.TimeStamp);
}
// This will renum guids used at load to prevent always going up until infinit
@@ -2013,4 +1976,3 @@ bool GuildItemPosCount::isContainedIn(GuildItemPosCountVec const &vec) const
return false;
}
-
diff --git a/src/game/Guild.h b/src/game/Guild.h
index 9f832260f14..6e2441416c6 100644
--- a/src/game/Guild.h
+++ b/src/game/Guild.h
@@ -460,8 +460,8 @@ class Guild
TabListMap m_TabListMap;
/** These are actually ordered lists. The first element is the oldest entry.*/
- typedef std::list<GuildEventlogEntry*> GuildEventlog;
- typedef std::list<GuildBankEvent*> GuildBankEventLog;
+ typedef std::list<GuildEventlogEntry> GuildEventlog;
+ typedef std::list<GuildBankEvent> GuildBankEventLog;
GuildEventlog m_GuildEventlog;
GuildBankEventLog m_GuildBankEventLog_Money;
GuildBankEventLog m_GuildBankEventLog_Item[GUILD_BANK_MAX_TABS];
diff --git a/src/game/GuildHandler.cpp b/src/game/GuildHandler.cpp
index f3f9c6c6758..a8eba52dee0 100644
--- a/src/game/GuildHandler.cpp
+++ b/src/game/GuildHandler.cpp
@@ -976,7 +976,7 @@ void WorldSession::HandleGuildBankDepositMoney( WorldPacket & recv_data )
pGuild->SetBankMoney(pGuild->GetGuildBankMoney()+money);
GetPlayer()->ModifyMoney(-int(money));
- GetPlayer()->SaveDataFieldToDB(); //contains money
+ GetPlayer()->SaveGoldToDB();
CharacterDatabase.CommitTransaction();
@@ -1032,7 +1032,7 @@ void WorldSession::HandleGuildBankWithdrawMoney( WorldPacket & recv_data )
}
GetPlayer()->ModifyMoney(money);
- GetPlayer()->SaveDataFieldToDB(); // contains money
+ GetPlayer()->SaveGoldToDB();
CharacterDatabase.CommitTransaction();
diff --git a/src/game/Item.cpp b/src/game/Item.cpp
index bc1c1eeeaab..484fa766da0 100644
--- a/src/game/Item.cpp
+++ b/src/game/Item.cpp
@@ -25,6 +25,7 @@
#include "Database/DatabaseEnv.h"
#include "ItemEnchantmentMgr.h"
#include "SpellMgr.h"
+#include "ScriptCalls.h"
void AddItemsSetItem(Player*player,Item *item)
{
@@ -285,6 +286,7 @@ void Item::UpdateDuration(Player* owner, uint32 diff)
if (GetUInt32Value(ITEM_FIELD_DURATION)<=diff)
{
owner->DestroyItem(GetBagSlot(), GetSlot(), true);
+ Script->ItemExpire(owner, GetProto());
return;
}
@@ -380,6 +382,16 @@ bool Item::LoadFromDB(uint32 guid, uint64 owner_guid, QueryResult *result)
if(!proto)
return false;
+ // update max durability (and durability) if need
+ if(proto->MaxDurability!= GetUInt32Value(ITEM_FIELD_MAXDURABILITY))
+ {
+ SetUInt32Value(ITEM_FIELD_MAXDURABILITY,proto->MaxDurability);
+ if(GetUInt32Value(ITEM_FIELD_DURABILITY) > proto->MaxDurability)
+ SetUInt32Value(ITEM_FIELD_DURABILITY,proto->MaxDurability);
+
+ need_save = true;
+ }
+
// recalculate suffix factor
if(GetItemRandomPropertyId() < 0)
{
diff --git a/src/game/ItemHandler.cpp b/src/game/ItemHandler.cpp
index cf762dd0cb2..114393f4287 100644
--- a/src/game/ItemHandler.cpp
+++ b/src/game/ItemHandler.cpp
@@ -674,7 +674,31 @@ void WorldSession::HandleBuyItemInSlotOpcode( WorldPacket & recv_data )
recv_data >> vendorguid >> item >> slot >> bagguid >> bagslot >> count;
- GetPlayer()->BuyItemFromVendor(vendorguid,item,count,bagguid,bagslot);
+ uint8 bag = NULL_BAG; // init for case invalid bagGUID
+
+ // find bag slot by bag guid
+ if (bagguid == _player->GetGUID())
+ bag = INVENTORY_SLOT_BAG_0;
+ else
+ {
+ for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END;++i)
+ {
+ if (Bag *pBag = (Bag*)_player->GetItemByPos(INVENTORY_SLOT_BAG_0,i))
+ {
+ if (bagguid == pBag->GetGUID())
+ {
+ bag = i;
+ break;
+ }
+ }
+ }
+ }
+
+ // bag not found, cheating?
+ if (bag == NULL_BAG)
+ return;
+
+ GetPlayer()->BuyItemFromVendor(vendorguid,item,count,bag,bagslot);
}
void WorldSession::HandleBuyItemOpcode( WorldPacket & recv_data )
@@ -838,12 +862,14 @@ void WorldSession::HandleBuyBankSlotOpcode(WorldPacket& recvPacket)
recvPacket >> guid;
// cheating protection
+ /* not critical if "cheated", and check skip allow by slots in bank windows open by .bank command.
Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_BANKER);
if(!pCreature)
{
sLog.outDebug( "WORLD: HandleBuyBankSlotOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) );
return;
}
+ */
uint32 slot = _player->GetBankBagSlotCount();
diff --git a/src/game/LFGHandler.cpp b/src/game/LFGHandler.cpp
index 51735c01e02..09653ccb0bc 100644
--- a/src/game/LFGHandler.cpp
+++ b/src/game/LFGHandler.cpp
@@ -42,6 +42,10 @@ static void AttemptJoin(Player* _player)
if(!plr || plr==_player || plr->GetTeam() != _player->GetTeam())
continue;
+ //skip players not in world
+ if(!plr->IsInWorld())
+ continue;
+
// skip not auto add, not group leader cases
if(!plr->GetSession()->LookingForGroup_auto_add || plr->GetGroup() && plr->GetGroup()->GetLeaderGUID()!=plr->GetGUID())
continue;
@@ -98,6 +102,9 @@ static void AttemptAddMore(Player* _player)
if(!plr || plr==_player || plr->GetTeam() != _player->GetTeam())
continue;
+ if(!plr->IsInWorld())
+ continue;
+
// skip not auto join or in group
if(!plr->GetSession()->LookingForGroup_auto_join || plr->GetGroup() )
continue;
@@ -311,6 +318,9 @@ void WorldSession::SendLfgResult(uint32 type, uint32 entry, uint8 lfg_type)
if(!plr || plr->GetTeam() != _player->GetTeam())
continue;
+ if(!plr->IsInWorld())
+ continue;
+
if(!plr->m_lookingForGroup.HaveInSlot(entry, type))
continue;
diff --git a/src/game/Language.h b/src/game/Language.h
index c16393eba1c..bd74333c45a 100644
--- a/src/game/Language.h
+++ b/src/game/Language.h
@@ -85,7 +85,8 @@ enum TrinityStrings
LANG_USING_WORLD_DB = 57,
LANG_USING_SCRIPT_LIB = 58,
LANG_USING_EVENT_AI = 59,
- // Room for more level 0 60-99 not used
+ LANG_CONNECTED_PLAYERS = 60,
+ // Room for more level 0 61-99 not used
// level 1 chat
LANG_GLOBAL_NOTIFY = 100,
@@ -804,14 +805,15 @@ enum TrinityStrings
LANG_BG_AV_NODE_TOWER_FROST_W = 1324,
LANG_BG_AV_NODE_GRAVE_FROST_HUT = 1325,
- LANG_BG_AV_ONEMINTOSTART = 1326,
- LANG_BG_AV_HALFMINTOSTART = 1327,
- LANG_BG_AV_STARTED = 1328,
+ LANG_BG_AV_START_ONE_MINUTE = 1326,
+ LANG_BG_AV_START_HALF_MINUTE = 1327,
+ LANG_BG_AV_HAS_BEGUN = 1328,
LANG_BG_AV_A_NEAR_LOSE = 1329,
LANG_BG_AV_H_NEAR_LOSE = 1330,
LANG_BG_AV_H_CAPTAIN_DEAD = 1331,
LANG_BG_AV_A_CAPTAIN_DEAD = 1332,
- // FREE IDS 1333-1999
+ LANG_BG_AV_START_TWO_MINUTES = 1333,
+ // FREE IDS 1334-1999
// Ticket Strings 2000-2029
LANG_COMMAND_TICKETNEW = 2000,
@@ -868,7 +870,8 @@ enum TrinityStrings
LANG_GM_BROADCAST = 6613,
LANG_GM_NOTIFY = 6614,
LANG_GM_ANNOUNCE_COLOR = 6615,
- LANG_RESETALL_PET_SPELLS = 6616,
+
+ LANG_GM_SILENCE = 6616, // "Silence is ON for %s" - Spell 1852
LANG_WORLD_CLOSED = 7523,
LANG_WORLD_OPENED = 7524,
@@ -940,6 +943,7 @@ enum TrinityStrings
LANG_OPVP_ZM_GOSSIP_HORDE = 10055,
// Use for custom patches 11000-11999
+ LANG_AUTO_BROADCAST = 11000,
// NOT RESERVED IDS 12000-1999999999
// `db_script_string` table index 2000000000-2000009999 (MIN_DB_SCRIPT_STRING_ID-MAX_DB_SCRIPT_STRING_ID)
diff --git a/src/game/Level0.cpp b/src/game/Level0.cpp
index c4f6935bced..efc09494d1d 100644
--- a/src/game/Level0.cpp
+++ b/src/game/Level0.cpp
@@ -86,11 +86,13 @@ bool ChatHandler::HandleStartCommand(const char* /*args*/)
bool ChatHandler::HandleServerInfoCommand(const char* /*args*/)
{
+ uint32 PlayersNum = sWorld.GetPlayerCount();
+ uint32 MaxPlayersNum = sWorld.GetMaxPlayerCount();
uint32 activeClientsNum = sWorld.GetActiveSessionCount();
uint32 queuedClientsNum = sWorld.GetQueuedSessionCount();
uint32 maxActiveClientsNum = sWorld.GetMaxActiveSessionCount();
uint32 maxQueuedClientsNum = sWorld.GetMaxQueuedSessionCount();
- std::string str = secsToTimeString(sWorld.GetUptime());
+ std::string uptime = secsToTimeString(sWorld.GetUptime());
uint32 updateTime = sWorld.GetUpdateTime();
PSendSysMessage(_FULLVERSION);
@@ -103,8 +105,9 @@ bool ChatHandler::HandleServerInfoCommand(const char* /*args*/)
//PSendSysMessage(LANG_USING_SCRIPT_LIB,sWorld.GetScriptsVersion());
//PSendSysMessage(LANG_USING_WORLD_DB,sWorld.GetDBVersion());
//PSendSysMessage(LANG_USING_EVENT_AI,sWorld.GetCreatureEventAIVersion());
+ PSendSysMessage(LANG_CONNECTED_PLAYERS, PlayersNum, MaxPlayersNum);
PSendSysMessage(LANG_CONNECTED_USERS, activeClientsNum, maxActiveClientsNum, queuedClientsNum, maxQueuedClientsNum);
- PSendSysMessage(LANG_UPTIME, str.c_str());
+ PSendSysMessage(LANG_UPTIME, uptime.c_str());
PSendSysMessage("Update time diff: %u.", updateTime);
return true;
@@ -160,9 +163,9 @@ bool ChatHandler::HandleGMListIngameCommand(const char* /*args*/)
HashMapHolder<Player>::MapType::const_iterator itr = m.begin();
for(; itr != m.end(); ++itr)
{
- if (itr->second->GetSession()->GetSecurity() > SEC_PLAYER &&
- (itr->second->isGameMaster() || sWorld.getConfig(CONFIG_GM_IN_GM_LIST)) &&
- (!m_session || itr->second->IsVisibleGloballyFor(m_session->GetPlayer())) )
+ AccountTypes itr_sec = itr->second->GetSession()->GetSecurity();
+ if ((itr->second->isGameMaster() || itr_sec > SEC_PLAYER && itr_sec <= sWorld.getConfig(CONFIG_GM_LEVEL_IN_GM_LIST)) &&
+ (!m_session || itr->second->IsVisibleGloballyFor(m_session->GetPlayer())))
{
if(first)
{
@@ -242,14 +245,14 @@ bool ChatHandler::HandleAccountLockCommand(const char* args)
std::string argstr = (char*)args;
if (argstr == "on")
{
- LoginDatabase.PExecute( "UPDATE account SET locked = '1' WHERE id = '%d'",m_session->GetAccountId());
+ loginDatabase.PExecute( "UPDATE account SET locked = '1' WHERE id = '%d'",m_session->GetAccountId());
PSendSysMessage(LANG_COMMAND_ACCLOCKLOCKED);
return true;
}
if (argstr == "off")
{
- LoginDatabase.PExecute( "UPDATE account SET locked = '0' WHERE id = '%d'",m_session->GetAccountId());
+ loginDatabase.PExecute( "UPDATE account SET locked = '0' WHERE id = '%d'",m_session->GetAccountId());
PSendSysMessage(LANG_COMMAND_ACCLOCKUNLOCKED);
return true;
}
diff --git a/src/game/Level1.cpp b/src/game/Level1.cpp
index cb06b2fe273..275dd5b1e8c 100644
--- a/src/game/Level1.cpp
+++ b/src/game/Level1.cpp
@@ -370,7 +370,7 @@ bool ChatHandler::HandleGMTicketGetByIdCommand(const char* args)
uint64 tguid = atoi(args);
GM_Ticket *ticket = objmgr.GetGMTicket(tguid);
- if(!ticket)
+ if(!ticket || ticket->closed != 0)
{
SendSysMessage(LANG_COMMAND_TICKETNOTEXIST);
return true;
@@ -400,7 +400,10 @@ bool ChatHandler::HandleGMTicketGetByNameCommand(const char* args)
if(!*args)
return false;
- Player *plr = objmgr.GetPlayer(args);
+ std::string name = (char*)args;
+ normalizePlayerName(name);
+
+ Player *plr = objmgr.GetPlayer(name.c_str());
if(!plr)
{
SendSysMessage(LANG_NO_PLAYERS_FOUND);
@@ -496,7 +499,7 @@ bool ChatHandler::HandleGMTicketAssignToCommand(const char* args)
}
uint64 tarGUID = objmgr.GetPlayerGUIDByName(targm.c_str());
uint64 accid = objmgr.GetPlayerAccountIdByGUID(tarGUID);
- QueryResult *result = LoginDatabase.PQuery("SELECT `gmlevel` FROM `account` WHERE `id` = '%u'", accid);
+ QueryResult *result = loginDatabase.PQuery("SELECT `gmlevel` FROM `account` WHERE `id` = '%u'", accid);
if(!tarGUID|| !result || result->Fetch()->GetUInt32() < SEC_MODERATOR)
{
SendSysMessage(LANG_COMMAND_TICKETASSIGNERROR_A);
@@ -846,13 +849,13 @@ bool ChatHandler::HandleNamegoCommand(const char* args)
PSendSysMessage(LANG_SUMMONING, nameLink.c_str(),"");
if (needReportToTarget(target))
- ChatHandler(target).PSendSysMessage(LANG_SUMMONED_BY, nameLink.c_str());
+ ChatHandler(target).PSendSysMessage(LANG_SUMMONED_BY, _player->GetName());
// stop flight if need
if (target->isInFlight())
{
target->GetMotionMaster()->MovementExpired();
- target->m_taxi.ClearTaxiDestinations();
+ target->CleanupAfterTaxiFlight();
}
// save only in non-flight case
else
@@ -937,7 +940,7 @@ bool ChatHandler::HandleGonameCommand(const char* args)
}
else if(cMap->IsDungeon())
{
- Map* pMap = MapManager::Instance().GetMap(_player->GetMapId(),_player);
+ Map* pMap = _player->GetMap();
// we have to go to instance, and can go to player only if:
// 1) we are in his group (either as leader or as member)
@@ -988,7 +991,7 @@ bool ChatHandler::HandleGonameCommand(const char* args)
if (_player->isInFlight())
{
_player->GetMotionMaster()->MovementExpired();
- _player->m_taxi.ClearTaxiDestinations();
+ _player->CleanupAfterTaxiFlight();
}
// save only in non-flight case
else
@@ -1021,7 +1024,7 @@ bool ChatHandler::HandleGonameCommand(const char* args)
if (_player->isInFlight())
{
_player->GetMotionMaster()->MovementExpired();
- _player->m_taxi.ClearTaxiDestinations();
+ _player->CleanupAfterTaxiFlight();
}
// save only in non-flight case
else
@@ -1055,7 +1058,7 @@ bool ChatHandler::HandleRecallCommand(const char* args)
if(target->isInFlight())
{
target->GetMotionMaster()->MovementExpired();
- target->m_taxi.ClearTaxiDestinations();
+ target->CleanupAfterTaxiFlight();
}
target->TeleportTo(target->m_recallMap, target->m_recallX, target->m_recallY, target->m_recallZ, target->m_recallO);
@@ -1468,23 +1471,42 @@ bool ChatHandler::HandleModifyTalentCommand (const char* args)
return false;
int tp = atoi((char*)args);
- if (tp>0)
+ if (tp < 0)
+ return false;
+
+ Unit* target = getSelectedUnit();
+ if(!target)
{
- Player* player = getSelectedPlayer();
- if(!player)
- {
- SendSysMessage(LANG_NO_CHAR_SELECTED);
- SetSentErrorMessage(true);
- return false;
- }
+ SendSysMessage(LANG_NO_CHAR_SELECTED);
+ SetSentErrorMessage(true);
+ return false;
+ }
+ if(target->GetTypeId()==TYPEID_PLAYER)
+ {
// check online security
- if (HasLowerSecurity(player, 0))
+ if (HasLowerSecurity((Player*)target, 0))
return false;
-
- player->SetFreeTalentPoints(tp);
+ ((Player*)target)->SetFreeTalentPoints(tp);
+ ((Player*)target)->SendTalentsInfoData(false);
return true;
}
+ else if(((Creature*)target)->isPet())
+ {
+ Unit *owner = target->GetOwner();
+ if(owner && owner->GetTypeId() == TYPEID_PLAYER && ((Pet *)target)->IsPermanentPetFor((Player*)owner))
+ {
+ // check online security
+ if (HasLowerSecurity((Player*)owner, 0))
+ return false;
+ ((Pet *)target)->SetFreeTalentPoints(tp);
+ ((Player*)owner)->SendTalentsInfoData(true);
+ return true;
+ }
+ }
+
+ SendSysMessage(LANG_NO_CHAR_SELECTED);
+ SetSentErrorMessage(true);
return false;
}
@@ -2222,7 +2244,7 @@ bool ChatHandler::HandleTeleCommand(const char * args)
if(_player->isInFlight())
{
_player->GetMotionMaster()->MovementExpired();
- _player->m_taxi.ClearTaxiDestinations();
+ _player->CleanupAfterTaxiFlight();
}
// save only in non-flight case
else
@@ -2243,7 +2265,7 @@ bool ChatHandler::HandleLookupAreaCommand(const char* args)
if (!Utf8toWStr (namepart,wnamepart))
return false;
- uint32 counter = 0; // Counter for figure out that we found smth.
+ bool found = false;
// converting string that we try to find to lower case
wstrToLower (wnamepart);
@@ -2287,12 +2309,13 @@ bool ChatHandler::HandleLookupAreaCommand(const char* args)
SendSysMessage (ss.str ().c_str());
- ++counter;
+ if(!found)
+ found = true;
}
}
}
- if (counter == 0) // if counter == 0 then we found nth
+ if (!found)
SendSysMessage (LANG_COMMAND_NOAREAFOUND);
return true;
@@ -2485,7 +2508,7 @@ bool ChatHandler::HandleTeleNameCommand(const char * args)
if(target->isInFlight())
{
target->GetMotionMaster()->MovementExpired();
- target->m_taxi.ClearTaxiDestinations();
+ target->CleanupAfterTaxiFlight();
}
// save only in non-flight case
else
@@ -2581,7 +2604,7 @@ bool ChatHandler::HandleTeleGroupCommand(const char * args)
if(pl->isInFlight())
{
pl->GetMotionMaster()->MovementExpired();
- pl->m_taxi.ClearTaxiDestinations();
+ pl->CleanupAfterTaxiFlight();
}
// save only in non-flight case
else
@@ -2670,7 +2693,7 @@ bool ChatHandler::HandleGroupgoCommand(const char* args)
if(pl->isInFlight())
{
pl->GetMotionMaster()->MovementExpired();
- pl->m_taxi.ClearTaxiDestinations();
+ pl->CleanupAfterTaxiFlight();
}
// save only in non-flight case
else
@@ -2720,7 +2743,7 @@ bool ChatHandler::HandleGoTaxinodeCommand(const char* args)
if (_player->isInFlight())
{
_player->GetMotionMaster()->MovementExpired();
- _player->m_taxi.ClearTaxiDestinations();
+ _player->CleanupAfterTaxiFlight();
}
// save only in non-flight case
else
@@ -2763,7 +2786,7 @@ bool ChatHandler::HandleGoXYCommand(const char* args)
if(_player->isInFlight())
{
_player->GetMotionMaster()->MovementExpired();
- _player->m_taxi.ClearTaxiDestinations();
+ _player->CleanupAfterTaxiFlight();
}
// save only in non-flight case
else
@@ -2813,7 +2836,7 @@ bool ChatHandler::HandleGoXYZCommand(const char* args)
if(_player->isInFlight())
{
_player->GetMotionMaster()->MovementExpired();
- _player->m_taxi.ClearTaxiDestinations();
+ _player->CleanupAfterTaxiFlight();
}
// save only in non-flight case
else
@@ -2884,7 +2907,7 @@ bool ChatHandler::HandleGoZoneXYCommand(const char* args)
if(_player->isInFlight())
{
_player->GetMotionMaster()->MovementExpired();
- _player->m_taxi.ClearTaxiDestinations();
+ _player->CleanupAfterTaxiFlight();
}
// save only in non-flight case
else
@@ -2931,7 +2954,7 @@ bool ChatHandler::HandleGoGridCommand(const char* args)
if(_player->isInFlight())
{
_player->GetMotionMaster()->MovementExpired();
- _player->m_taxi.ClearTaxiDestinations();
+ _player->CleanupAfterTaxiFlight();
}
// save only in non-flight case
else
diff --git a/src/game/Level2.cpp b/src/game/Level2.cpp
index 63d8943469d..e3f3bbce6e6 100644
--- a/src/game/Level2.cpp
+++ b/src/game/Level2.cpp
@@ -44,12 +44,6 @@
#include "TargetedMovementGenerator.h" // for HandleNpcUnFollowCommand
#include "CreatureGroups.h"
-static uint32 ReputationRankStrIndex[MAX_REPUTATION_RANK] =
-{
- LANG_REP_HATED, LANG_REP_HOSTILE, LANG_REP_UNFRIENDLY, LANG_REP_NEUTRAL,
- LANG_REP_FRIENDLY, LANG_REP_HONORED, LANG_REP_REVERED, LANG_REP_EXALTED
-};
-
//mute player for some times
bool ChatHandler::HandleMuteCommand(const char* args)
{
@@ -59,6 +53,11 @@ bool ChatHandler::HandleMuteCommand(const char* args)
if(!delayStr)
return false;
+ char *mutereason = strtok(NULL, "\r");
+ std::string mutereasonstr = "No reason";
+ if(mutereason != NULL)
+ mutereasonstr = mutereason;
+
Player* target;
uint64 target_guid;
std::string target_name;
@@ -85,14 +84,15 @@ bool ChatHandler::HandleMuteCommand(const char* args)
if (target)
target->GetSession()->m_muteTime = mutetime;
- LoginDatabase.PExecute("UPDATE account SET mutetime = " UI64FMTD " WHERE id = '%u'",uint64(mutetime), account_id );
+ loginDatabase.PExecute("UPDATE account SET mutetime = " UI64FMTD " WHERE id = '%u'",uint64(mutetime), account_id );
if(target)
- ChatHandler(target).PSendSysMessage(LANG_YOUR_CHAT_DISABLED, notspeaktime);
+ ChatHandler(target).PSendSysMessage(LANG_YOUR_CHAT_DISABLED, notspeaktime, mutereasonstr.c_str());
std::string nameLink = playerLink(target_name);
- PSendSysMessage(LANG_YOU_DISABLE_CHAT, nameLink.c_str(), notspeaktime);
+ PSendSysMessage(LANG_YOU_DISABLE_CHAT, nameLink.c_str(), notspeaktime, mutereasonstr.c_str());
+
return true;
}
@@ -130,7 +130,7 @@ bool ChatHandler::HandleUnmuteCommand(const char* args)
target->GetSession()->m_muteTime = 0;
}
- LoginDatabase.PExecute("UPDATE account SET mutetime = '0' WHERE id = '%u'", account_id );
+ loginDatabase.PExecute("UPDATE account SET mutetime = '0' WHERE id = '%u'", account_id );
if(target)
ChatHandler(target).PSendSysMessage(LANG_YOUR_CHAT_ENABLED);
@@ -891,98 +891,6 @@ bool ChatHandler::HandleGUIDCommand(const char* /*args*/)
return true;
}
-bool ChatHandler::HandleLookupFactionCommand(const char* args)
-{
- if (!*args)
- return false;
-
- // Can be NULL at console call
- Player *target = getSelectedPlayer ();
-
- std::string namepart = args;
- std::wstring wnamepart;
-
- if (!Utf8toWStr (namepart,wnamepart))
- return false;
-
- // converting string that we try to find to lower case
- wstrToLower (wnamepart);
-
- uint32 counter = 0; // Counter for figure out that we found smth.
-
- for (uint32 id = 0; id < sFactionStore.GetNumRows(); ++id)
- {
- FactionEntry const *factionEntry = sFactionStore.LookupEntry (id);
- if (factionEntry)
- {
- FactionState const* repState = target ? target->GetReputationMgr().GetState(factionEntry) : NULL;
-
- int loc = GetSessionDbcLocale();
- std::string name = factionEntry->name[loc];
- if(name.empty())
- continue;
-
- if (!Utf8FitTo(name, wnamepart))
- {
- loc = 0;
- for(; loc < MAX_LOCALE; ++loc)
- {
- if(loc==GetSessionDbcLocale())
- continue;
-
- name = factionEntry->name[loc];
- if(name.empty())
- continue;
-
- if (Utf8FitTo(name, wnamepart))
- break;
- }
- }
-
- if(loc < MAX_LOCALE)
- {
- // send faction in "id - [faction] rank reputation [visible] [at war] [own team] [unknown] [invisible] [inactive]" format
- // or "id - [faction] [no reputation]" format
- std::ostringstream ss;
- if (m_session)
- ss << id << " - |cffffffff|Hfaction:" << id << "|h[" << name << " " << localeNames[loc] << "]|h|r";
- else
- ss << id << " - " << name << " " << localeNames[loc];
-
- if (repState) // and then target!=NULL also
- {
- ReputationRank rank = target->GetReputationMgr().GetRank(factionEntry);
- std::string rankName = GetMangosString(ReputationRankStrIndex[rank]);
-
- ss << " " << rankName << "|h|r (" << target->GetReputationMgr().GetReputation(factionEntry) << ")";
-
- if(repState->Flags & FACTION_FLAG_VISIBLE)
- ss << GetTrinityString(LANG_FACTION_VISIBLE);
- if(repState->Flags & FACTION_FLAG_AT_WAR)
- ss << GetTrinityString(LANG_FACTION_ATWAR);
- if(repState->Flags & FACTION_FLAG_PEACE_FORCED)
- ss << GetTrinityString(LANG_FACTION_PEACE_FORCED);
- if(repState->Flags & FACTION_FLAG_HIDDEN)
- ss << GetTrinityString(LANG_FACTION_HIDDEN);
- if(repState->Flags & FACTION_FLAG_INVISIBLE_FORCED)
- ss << GetTrinityString(LANG_FACTION_INVISIBLE_FORCED);
- if(repState->Flags & FACTION_FLAG_INACTIVE)
- ss << GetTrinityString(LANG_FACTION_INACTIVE);
- }
- else
- ss << GetTrinityString(LANG_FACTION_NOREPUTATION);
-
- SendSysMessage(ss.str().c_str());
- counter++;
- }
- }
- }
-
- if (counter == 0) // if counter == 0 then we found nth
- SendSysMessage(LANG_COMMAND_FACTION_NOTFOUND);
- return true;
-}
-
bool ChatHandler::HandleModifyRepCommand(const char * args)
{
if (!*args) return false;
@@ -1371,7 +1279,6 @@ bool ChatHandler::HandleNpcDeleteCommand(const char* args)
// Delete the creature
unit->CombatStop();
unit->DeleteFromDB();
- unit->CleanupsBeforeDelete();
unit->AddObjectToRemoveList();
SendSysMessage(LANG_COMMAND_DELCREATMESSAGE);
@@ -1754,7 +1661,7 @@ bool ChatHandler::HandleNpcFollowCommand(const char* /*args*/)
}
// Follow player - Using pet's default dist and angle
- creature->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
+ creature->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, creature->GetFollowAngle());
PSendSysMessage(LANG_CREATURE_FOLLOW_YOU_NOW, creature->GetName());
return true;
@@ -2263,40 +2170,40 @@ bool ChatHandler::HandlePInfoCommand(const char* args)
if (HasLowerSecurity(NULL, target_guid))
return false;
- // 0
- QueryResult *result = CharacterDatabase.PQuery("SELECT totaltime FROM characters WHERE guid = '%u'", GUID_LOPART(target_guid));
+ // 0 1 2 3
+ QueryResult *result = CharacterDatabase.PQuery("SELECT totaltime, level, money, account FROM characters WHERE guid = '%u'", GUID_LOPART(target_guid));
if (!result)
return false;
Field *fields = result->Fetch();
total_player_time = fields[0].GetUInt32();
+ level = fields[1].GetUInt32();
+ money = fields[2].GetUInt32();
+ accId = fields[3].GetUInt32();
delete result;
-
- Tokens data;
- if (!Player::LoadValuesArrayFromDB(data,target_guid))
- return false;
-
- money = Player::GetUInt32ValueFromArray(data, PLAYER_FIELD_COINAGE);
- level = Player::GetUInt32ValueFromArray(data, UNIT_FIELD_LEVEL);
- accId = objmgr.GetPlayerAccountIdByGUID(target_guid);
}
std::string username = GetTrinityString(LANG_ERROR);
+ std::string email = GetTrinityString(LANG_ERROR);
std::string last_ip = GetTrinityString(LANG_ERROR);
uint32 security = 0;
std::string last_login = GetTrinityString(LANG_ERROR);
- QueryResult* result = LoginDatabase.PQuery("SELECT username,gmlevel,last_ip,last_login FROM account WHERE id = '%u'",accId);
+ QueryResult* result = loginDatabase.PQuery("SELECT username,gmlevel,email,last_ip,last_login FROM account WHERE id = '%u'",accId);
if(result)
{
Field* fields = result->Fetch();
username = fields[0].GetCppString();
security = fields[1].GetUInt32();
+ email = fields[2].GetCppString();
+
+ if(email.empty())
+ email = "-";
if(!m_session || m_session->GetSecurity() >= security)
{
- last_ip = fields[2].GetCppString();
- last_login = fields[3].GetCppString();
+ last_ip = fields[3].GetCppString();
+ last_login = fields[4].GetCppString();
}
else
{
@@ -2309,7 +2216,7 @@ bool ChatHandler::HandlePInfoCommand(const char* args)
std::string nameLink = playerLink(target_name);
- PSendSysMessage(LANG_PINFO_ACCOUNT, (target?"":GetMangosString(LANG_OFFLINE)), nameLink.c_str(), GUID_LOPART(target_guid), username.c_str(), accId, security, last_ip.c_str(), last_login.c_str(), latency);
+ PSendSysMessage(LANG_PINFO_ACCOUNT, (target?"":GetTrinityString(LANG_OFFLINE)), nameLink.c_str(), GUID_LOPART(target_guid), username.c_str(), accId, email.c_str(), security, last_ip.c_str(), last_login.c_str(), latency);
std::string timeStr = secsToTimeString(total_player_time,true,true);
uint32 gold = money /GOLD;
@@ -3448,7 +3355,6 @@ bool ChatHandler::HandleWpShowCommand(const char* args)
Field *fields = result->Fetch();
uint32 guid = fields[0].GetUInt32();
Creature* pCreature = m_session->GetPlayer()->GetMap()->GetCreature(MAKE_NEW_GUID(guid,VISUAL_WAYPOINT,HIGHGUID_UNIT));
-
if(!pCreature)
{
PSendSysMessage(LANG_WAYPOINT_NOTREMOVED, guid);
@@ -3673,7 +3579,7 @@ bool ChatHandler::HandleLookupEventCommand(const char* args)
wstrToLower(wnamepart);
- uint32 counter = 0;
+ bool found = false;
GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap();
GameEventMgr::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList();
@@ -3695,11 +3601,12 @@ bool ChatHandler::HandleLookupEventCommand(const char* args)
else
PSendSysMessage(LANG_EVENT_ENTRY_LIST_CONSOLE,id,eventData.description.c_str(),active );
- ++counter;
+ if(!found)
+ found = true;
}
}
- if (counter==0)
+ if (!found)
SendSysMessage(LANG_NOEVENTFOUND);
return true;
@@ -4026,9 +3933,9 @@ bool ChatHandler::HandleLookupPlayerIpCommand(const char* args)
char* limit_str = strtok (NULL, " ");
int32 limit = limit_str ? atoi (limit_str) : -1;
- LoginDatabase.escape_string (ip);
+ loginDatabase.escape_string (ip);
- QueryResult* result = LoginDatabase.PQuery ("SELECT id,username FROM account WHERE last_ip = '%s'", ip.c_str ());
+ QueryResult* result = loginDatabase.PQuery ("SELECT id,username FROM account WHERE last_ip = '%s'", ip.c_str ());
return LookupPlayerSearchCommand (result,limit);
}
@@ -4045,9 +3952,9 @@ bool ChatHandler::HandleLookupPlayerAccountCommand(const char* args)
if (!AccountMgr::normalizeString (account))
return false;
- LoginDatabase.escape_string (account);
+ loginDatabase.escape_string (account);
- QueryResult* result = LoginDatabase.PQuery ("SELECT id,username FROM account WHERE username = '%s'", account.c_str ());
+ QueryResult* result = loginDatabase.PQuery ("SELECT id,username FROM account WHERE username = '%s'", account.c_str ());
return LookupPlayerSearchCommand (result,limit);
}
@@ -4062,9 +3969,9 @@ bool ChatHandler::HandleLookupPlayerEmailCommand(const char* args)
char* limit_str = strtok (NULL, " ");
int32 limit = limit_str ? atoi (limit_str) : -1;
- LoginDatabase.escape_string (email);
+ loginDatabase.escape_string (email);
- QueryResult* result = LoginDatabase.PQuery ("SELECT id,username FROM account WHERE email = '%s'", email.c_str ());
+ QueryResult* result = loginDatabase.PQuery ("SELECT id,username FROM account WHERE email = '%s'", email.c_str ());
return LookupPlayerSearchCommand (result,limit);
}
diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp
index adb904dbbbe..c1b8b56f043 100644
--- a/src/game/Level3.cpp
+++ b/src/game/Level3.cpp
@@ -108,7 +108,7 @@ bool ChatHandler::HandleAHBotOptionsCommand(const char* args)
PSendSysMessage("Syntax is: ahbotoptions ahexpire $ahMapID (2, 6 or 7)");
return false;
}
- AuctionHouseBotCommands(0, ahMapID, NULL, NULL);
+ auctionbot.Commands(0, ahMapID, NULL, NULL);
}
else if (strncmp(opt,"minitems",l) == 0)
{
@@ -118,21 +118,17 @@ bool ChatHandler::HandleAHBotOptionsCommand(const char* args)
PSendSysMessage("Syntax is: ahbotoptions minitems $ahMapID (2, 6 or 7) $minItems");
return false;
}
- AuctionHouseBotCommands(1, ahMapID, NULL, param1);
+ auctionbot.Commands(1, ahMapID, NULL, param1);
}
else if (strncmp(opt,"maxitems",l) == 0)
{
- PSendSysMessage("ahbotoptions mintime has been deprecated");
- return false;
- /*
char * param1 = strtok(NULL, " ");
if ((!ahMapIdStr) || (!param1))
{
PSendSysMessage("Syntax is: ahbotoptions maxitems $ahMapID (2, 6 or 7) $maxItems");
return false;
}
- AuctionHouseBotCommands(2, ahMapID, NULL, param1);
- */
+ auctionbot.Commands(2, ahMapID, NULL, param1);
}
else if (strncmp(opt,"mintime",l) == 0)
{
@@ -145,7 +141,7 @@ bool ChatHandler::HandleAHBotOptionsCommand(const char* args)
PSendSysMessage("Syntax is: ahbotoptions mintime $ahMapID (2, 6 or 7) $mintime");
return false;
}
- AuctionHouseBotCommands(3, ahMapID, NULL, param1);
+ auctionbot.Commands(3, ahMapID, NULL, param1);
*/
}
else if (strncmp(opt,"maxtime",l) == 0)
@@ -159,7 +155,7 @@ bool ChatHandler::HandleAHBotOptionsCommand(const char* args)
PSendSysMessage("Syntax is: ahbotoptions maxtime $ahMapID (2, 6 or 7) $maxtime");
return false;
}
- AuctionHouseBotCommands(4, ahMapID, NULL, param1);
+ auctionbot.Commands(4, ahMapID, NULL, param1);
*/
}
else if (strncmp(opt,"percentages",l) == 0)
@@ -240,7 +236,7 @@ bool ChatHandler::HandleAHBotOptionsCommand(const char* args)
strcat(param, param13);
strcat(param, " ");
strcat(param, param14);
- AuctionHouseBotCommands(5, ahMapID, NULL, param);
+ auctionbot.Commands(5, ahMapID, NULL, param);
}
else if (strncmp(opt,"minprice",l) == 0)
{
@@ -253,31 +249,31 @@ bool ChatHandler::HandleAHBotOptionsCommand(const char* args)
}
if (strncmp(param1,"grey",l) == 0)
{
- AuctionHouseBotCommands(6, ahMapID, AHB_GREY, param2);
+ auctionbot.Commands(6, ahMapID, AHB_GREY, param2);
}
else if (strncmp(param1,"white",l) == 0)
{
- AuctionHouseBotCommands(6, ahMapID, AHB_WHITE, param2);
+ auctionbot.Commands(6, ahMapID, AHB_WHITE, param2);
}
else if (strncmp(param1,"green",l) == 0)
{
- AuctionHouseBotCommands(6, ahMapID, AHB_GREEN, param2);
+ auctionbot.Commands(6, ahMapID, AHB_GREEN, param2);
}
else if (strncmp(param1,"blue",l) == 0)
{
- AuctionHouseBotCommands(6, ahMapID, AHB_BLUE, param2);
+ auctionbot.Commands(6, ahMapID, AHB_BLUE, param2);
}
else if (strncmp(param1,"purple",l) == 0)
{
- AuctionHouseBotCommands(6, ahMapID, AHB_PURPLE, param2);
+ auctionbot.Commands(6, ahMapID, AHB_PURPLE, param2);
}
else if (strncmp(param1,"orange",l) == 0)
{
- AuctionHouseBotCommands(6, ahMapID, AHB_ORANGE, param2);
+ auctionbot.Commands(6, ahMapID, AHB_ORANGE, param2);
}
else if (strncmp(param1,"yellow",l) == 0)
{
- AuctionHouseBotCommands(6, ahMapID, AHB_YELLOW, param2);
+ auctionbot.Commands(6, ahMapID, AHB_YELLOW, param2);
}
else
{
@@ -296,31 +292,31 @@ bool ChatHandler::HandleAHBotOptionsCommand(const char* args)
}
if (strncmp(param1,"grey",l) == 0)
{
- AuctionHouseBotCommands(7, ahMapID, AHB_GREY, param2);
+ auctionbot.Commands(7, ahMapID, AHB_GREY, param2);
}
else if (strncmp(param1,"white",l) == 0)
{
- AuctionHouseBotCommands(7, ahMapID, AHB_WHITE, param2);
+ auctionbot.Commands(7, ahMapID, AHB_WHITE, param2);
}
else if (strncmp(param1,"green",l) == 0)
{
- AuctionHouseBotCommands(7, ahMapID, AHB_GREEN, param2);
+ auctionbot.Commands(7, ahMapID, AHB_GREEN, param2);
}
else if (strncmp(param1,"blue",l) == 0)
{
- AuctionHouseBotCommands(7, ahMapID, AHB_BLUE, param2);
+ auctionbot.Commands(7, ahMapID, AHB_BLUE, param2);
}
else if (strncmp(param1,"purple",l) == 0)
{
- AuctionHouseBotCommands(7, ahMapID, AHB_PURPLE, param2);
+ auctionbot.Commands(7, ahMapID, AHB_PURPLE, param2);
}
else if (strncmp(param1,"orange",l) == 0)
{
- AuctionHouseBotCommands(7, ahMapID, AHB_ORANGE, param2);
+ auctionbot.Commands(7, ahMapID, AHB_ORANGE, param2);
}
else if (strncmp(param1,"yellow",l) == 0)
{
- AuctionHouseBotCommands(7, ahMapID, AHB_YELLOW, param2);
+ auctionbot.Commands(7, ahMapID, AHB_YELLOW, param2);
}
else
{
@@ -345,31 +341,31 @@ bool ChatHandler::HandleAHBotOptionsCommand(const char* args)
}
if (strncmp(param1,"grey",l) == 0)
{
- AuctionHouseBotCommands(8, ahMapID, AHB_GREY, param2);
+ auctionbot.Commands(8, ahMapID, AHB_GREY, param2);
}
else if (strncmp(param1,"white",l) == 0)
{
- AuctionHouseBotCommands(8, ahMapID, AHB_WHITE, param2);
+ auctionbot.Commands(8, ahMapID, AHB_WHITE, param2);
}
else if (strncmp(param1,"green",l) == 0)
{
- AuctionHouseBotCommands(8, ahMapID, AHB_GREEN, param2);
+ auctionbot.Commands(8, ahMapID, AHB_GREEN, param2);
}
else if (strncmp(param1,"blue",l) == 0)
{
- AuctionHouseBotCommands(8, ahMapID, AHB_BLUE, param2);
+ auctionbot.Commands(8, ahMapID, AHB_BLUE, param2);
}
else if (strncmp(param1,"purple",l) == 0)
{
- AuctionHouseBotCommands(8, ahMapID, AHB_PURPLE, param2);
+ auctionbot.Commands(8, ahMapID, AHB_PURPLE, param2);
}
else if (strncmp(param1,"orange",l) == 0)
{
- AuctionHouseBotCommands(8, ahMapID, AHB_ORANGE, param2);
+ auctionbot.Commands(8, ahMapID, AHB_ORANGE, param2);
}
else if (strncmp(param1,"yellow",l) == 0)
{
- AuctionHouseBotCommands(8, ahMapID, AHB_YELLOW, param2);
+ auctionbot.Commands(8, ahMapID, AHB_YELLOW, param2);
}
else
{
@@ -394,31 +390,31 @@ bool ChatHandler::HandleAHBotOptionsCommand(const char* args)
}
if (strncmp(param1,"grey",l) == 0)
{
- AuctionHouseBotCommands(9, ahMapID, AHB_GREY, param2);
+ auctionbot.Commands(9, ahMapID, AHB_GREY, param2);
}
else if (strncmp(param1,"white",l) == 0)
{
- AuctionHouseBotCommands(9, ahMapID, AHB_WHITE, param2);
+ auctionbot.Commands(9, ahMapID, AHB_WHITE, param2);
}
else if (strncmp(param1,"green",l) == 0)
{
- AuctionHouseBotCommands(9, ahMapID, AHB_GREEN, param2);
+ auctionbot.Commands(9, ahMapID, AHB_GREEN, param2);
}
else if (strncmp(param1,"blue",l) == 0)
{
- AuctionHouseBotCommands(9, ahMapID, AHB_BLUE, param2);
+ auctionbot.Commands(9, ahMapID, AHB_BLUE, param2);
}
else if (strncmp(param1,"purple",l) == 0)
{
- AuctionHouseBotCommands(9, ahMapID, AHB_PURPLE, param2);
+ auctionbot.Commands(9, ahMapID, AHB_PURPLE, param2);
}
else if (strncmp(param1,"orange",l) == 0)
{
- AuctionHouseBotCommands(9, ahMapID, AHB_ORANGE, param2);
+ auctionbot.Commands(9, ahMapID, AHB_ORANGE, param2);
}
else if (strncmp(param1,"yellow",l) == 0)
{
- AuctionHouseBotCommands(9, ahMapID, AHB_YELLOW, param2);
+ auctionbot.Commands(9, ahMapID, AHB_YELLOW, param2);
}
else
{
@@ -443,31 +439,31 @@ bool ChatHandler::HandleAHBotOptionsCommand(const char* args)
}
if (strncmp(param1,"grey",l) == 0)
{
- AuctionHouseBotCommands(10, ahMapID, AHB_GREY, param2);
+ auctionbot.Commands(10, ahMapID, AHB_GREY, param2);
}
else if (strncmp(param1,"white",l) == 0)
{
- AuctionHouseBotCommands(10, ahMapID, AHB_WHITE, param2);
+ auctionbot.Commands(10, ahMapID, AHB_WHITE, param2);
}
else if (strncmp(param1,"green",l) == 0)
{
- AuctionHouseBotCommands(10, ahMapID, AHB_GREEN, param2);
+ auctionbot.Commands(10, ahMapID, AHB_GREEN, param2);
}
else if (strncmp(param1,"blue",l) == 0)
{
- AuctionHouseBotCommands(10, ahMapID, AHB_BLUE, param2);
+ auctionbot.Commands(10, ahMapID, AHB_BLUE, param2);
}
else if (strncmp(param1,"purple",l) == 0)
{
- AuctionHouseBotCommands(10, ahMapID, AHB_PURPLE, param2);
+ auctionbot.Commands(10, ahMapID, AHB_PURPLE, param2);
}
else if (strncmp(param1,"orange",l) == 0)
{
- AuctionHouseBotCommands(10, ahMapID, AHB_ORANGE, param2);
+ auctionbot.Commands(10, ahMapID, AHB_ORANGE, param2);
}
else if (strncmp(param1,"yellow",l) == 0)
{
- AuctionHouseBotCommands(10, ahMapID, AHB_YELLOW, param2);
+ auctionbot.Commands(10, ahMapID, AHB_YELLOW, param2);
}
else
{
@@ -486,31 +482,31 @@ bool ChatHandler::HandleAHBotOptionsCommand(const char* args)
}
if (strncmp(param1,"grey",l) == 0)
{
- AuctionHouseBotCommands(11, ahMapID, AHB_GREY, param2);
+ auctionbot.Commands(11, ahMapID, AHB_GREY, param2);
}
else if (strncmp(param1,"white",l) == 0)
{
- AuctionHouseBotCommands(11, ahMapID, AHB_WHITE, param2);
+ auctionbot.Commands(11, ahMapID, AHB_WHITE, param2);
}
else if (strncmp(param1,"green",l) == 0)
{
- AuctionHouseBotCommands(11, ahMapID, AHB_GREEN, param2);
+ auctionbot.Commands(11, ahMapID, AHB_GREEN, param2);
}
else if (strncmp(param1,"blue",l) == 0)
{
- AuctionHouseBotCommands(11, ahMapID, AHB_BLUE, param2);
+ auctionbot.Commands(11, ahMapID, AHB_BLUE, param2);
}
else if (strncmp(param1,"purple",l) == 0)
{
- AuctionHouseBotCommands(11, ahMapID, AHB_PURPLE, param2);
+ auctionbot.Commands(11, ahMapID, AHB_PURPLE, param2);
}
else if (strncmp(param1,"orange",l) == 0)
{
- AuctionHouseBotCommands(11, ahMapID, AHB_ORANGE, param2);
+ auctionbot.Commands(11, ahMapID, AHB_ORANGE, param2);
}
else if (strncmp(param1,"yellow",l) == 0)
{
- AuctionHouseBotCommands(11, ahMapID, AHB_YELLOW, param2);
+ auctionbot.Commands(11, ahMapID, AHB_YELLOW, param2);
}
else
{
@@ -526,7 +522,7 @@ bool ChatHandler::HandleAHBotOptionsCommand(const char* args)
PSendSysMessage("Syntax is: ahbotoptions bidinterval $ahMapID (2, 6 or 7) $interval(in minutes)");
return false;
}
- AuctionHouseBotCommands(12, ahMapID, NULL, param1);
+ auctionbot.Commands(12, ahMapID, NULL, param1);
}
else if (strncmp(opt,"bidsperinterval",l) == 0)
{
@@ -536,7 +532,7 @@ bool ChatHandler::HandleAHBotOptionsCommand(const char* args)
PSendSysMessage("Syntax is: ahbotoptions bidsperinterval $ahMapID (2, 6 or 7) $bids");
return false;
}
- AuctionHouseBotCommands(13, ahMapID, NULL, param1);
+ auctionbot.Commands(13, ahMapID, NULL, param1);
}
else
{
@@ -648,7 +644,6 @@ bool ChatHandler::HandleReloadAllSpellCommand(const char*)
{
HandleReloadSkillDiscoveryTemplateCommand("a");
HandleReloadSkillExtraItemTemplateCommand("a");
- HandleReloadSpellAffectCommand("a");
HandleReloadSpellRequiredCommand("a");
HandleReloadSpellAreaCommand("a");
HandleReloadSpellElixirCommand("a");
@@ -996,14 +991,6 @@ bool ChatHandler::HandleReloadSkillFishingBaseLevelCommand(const char* /*args*/)
return true;
}
-bool ChatHandler::HandleReloadSpellAffectCommand(const char*)
-{
- sLog.outString( "Re-Loading SpellAffect definitions..." );
- spellmgr.LoadSpellAffects();
- SendGlobalGMSysMessage("DB table `spell_affect` (spell mods apply requirements) reloaded.");
- return true;
-}
-
bool ChatHandler::HandleReloadSpellAreaCommand(const char*)
{
sLog.outString( "Re-Loading SpellArea Data..." );
@@ -1428,7 +1415,7 @@ bool ChatHandler::HandleAccountSetGmLevelCommand(const char* args)
PSendSysMessage(LANG_YOURS_SECURITY_CHANGED, m_session->GetPlayer()->GetName(), gm);
}
- LoginDatabase.PExecute("UPDATE account SET gmlevel = '%d' WHERE id = '%u'", gm, targetAccountId);
+ loginDatabase.PExecute("UPDATE account SET gmlevel = '%d' WHERE id = '%u'", gm, targetAccountId);
return true;
}else
{
@@ -1469,7 +1456,7 @@ bool ChatHandler::HandleAccountSetGmLevelCommand(const char* args)
}
PSendSysMessage(LANG_YOU_CHANGE_SECURITY, targetAccountName.c_str(), gm);
- LoginDatabase.PExecute("UPDATE account SET gmlevel = '%d' WHERE id = '%u'", gm, targetAccountId);
+ loginDatabase.PExecute("UPDATE account SET gmlevel = '%d' WHERE id = '%u'", gm, targetAccountId);
return true;
}
}
@@ -1644,6 +1631,9 @@ bool ChatHandler::HandleUnLearnCommand(const char* args)
else
SendSysMessage(LANG_FORGET_SPELL);
+ if(GetTalentSpellCost(spell_id))
+ target->SendTalentsInfoData(false);
+
return true;
}
@@ -2134,7 +2124,6 @@ bool ChatHandler::HandleLearnAllCommand(const char* /*args*/)
"1180",
"201",
"12593",
- "12842",
"16770",
"6057",
"12051",
@@ -2161,9 +2150,7 @@ bool ChatHandler::HandleLearnAllCommand(const char* /*args*/)
"11129",
"16766",
"12573",
- "15053",
"12580",
- "12475",
"12472",
"12953",
"12488",
@@ -2586,6 +2573,10 @@ bool ChatHandler::HandleLearnCommand(const char* args)
else
targetPlayer->learnSpell(spell,false);
+ uint32 first_spell = spellmgr.GetFirstSpellInChain(spell);
+ if(GetTalentSpellCost(first_spell))
+ targetPlayer->SendTalentsInfoData(false);
+
return true;
}
@@ -3215,7 +3206,7 @@ bool ChatHandler::HandleLookupItemCommand(const char* args)
wstrToLower(wnamepart);
- uint32 counter = 0;
+ bool found = false;
// Search in `item_template`
for (uint32 id = 0; id < sItemStorage.MaxEntry; id++)
@@ -3240,7 +3231,10 @@ bool ChatHandler::HandleLookupItemCommand(const char* args)
PSendSysMessage(LANG_ITEM_LIST_CHAT, id, id, name.c_str());
else
PSendSysMessage(LANG_ITEM_LIST_CONSOLE, id, name.c_str());
- ++counter;
+
+ if(!found)
+ found = true;
+
continue;
}
}
@@ -3257,11 +3251,13 @@ bool ChatHandler::HandleLookupItemCommand(const char* args)
PSendSysMessage(LANG_ITEM_LIST_CHAT, id, id, name.c_str());
else
PSendSysMessage(LANG_ITEM_LIST_CONSOLE, id, name.c_str());
- ++counter;
+
+ if(!found)
+ found = true;
}
}
- if (counter==0)
+ if (!found)
SendSysMessage(LANG_COMMAND_NOITEMFOUND);
return true;
@@ -3281,7 +3277,7 @@ bool ChatHandler::HandleLookupItemSetCommand(const char* args)
// converting string that we try to find to lower case
wstrToLower( wnamepart );
- uint32 counter = 0; // Counter for figure out that we found smth.
+ bool found = false;
// Search in ItemSet.dbc
for (uint32 id = 0; id < sItemSetStore.GetNumRows(); id++)
@@ -3318,11 +3314,13 @@ bool ChatHandler::HandleLookupItemSetCommand(const char* args)
PSendSysMessage(LANG_ITEMSET_LIST_CHAT,id,id,name.c_str(),localeNames[loc]);
else
PSendSysMessage(LANG_ITEMSET_LIST_CONSOLE,id,name.c_str(),localeNames[loc]);
- ++counter;
+
+ if(!found)
+ found = true;
}
}
}
- if (counter == 0) // if counter == 0 then we found nth
+ if (!found)
SendSysMessage(LANG_COMMAND_NOITEMSETFOUND);
return true;
}
@@ -3344,7 +3342,7 @@ bool ChatHandler::HandleLookupSkillCommand(const char* args)
// converting string that we try to find to lower case
wstrToLower( wnamepart );
- uint32 counter = 0; // Counter for figure out that we found smth.
+ bool found = false;
// Search in SkillLine.dbc
for (uint32 id = 0; id < sSkillLineStore.GetNumRows(); id++)
@@ -3396,11 +3394,12 @@ bool ChatHandler::HandleLookupSkillCommand(const char* args)
else
PSendSysMessage(LANG_SKILL_LIST_CONSOLE,id,name.c_str(),localeNames[loc],knownStr,valStr);
- ++counter;
+ if(!found)
+ found = true;
}
}
}
- if (counter == 0) // if counter == 0 then we found nth
+ if (!found)
SendSysMessage(LANG_COMMAND_NOSKILLFOUND);
return true;
}
@@ -3422,7 +3421,7 @@ bool ChatHandler::HandleLookupSpellCommand(const char* args)
// converting string that we try to find to lower case
wstrToLower( wnamepart );
- uint32 counter = 0; // Counter for figure out that we found smth.
+ bool found = false;
// Search in Spell.dbc
for (uint32 id = 0; id < sSpellStore.GetNumRows(); id++)
@@ -3496,11 +3495,12 @@ bool ChatHandler::HandleLookupSpellCommand(const char* args)
SendSysMessage(ss.str().c_str());
- ++counter;
+ if(!found)
+ found = true;
}
}
}
- if (counter == 0) // if counter == 0 then we found nth
+ if (!found)
SendSysMessage(LANG_COMMAND_NOSPELLFOUND);
return true;
}
@@ -3522,7 +3522,7 @@ bool ChatHandler::HandleLookupQuestCommand(const char* args)
wstrToLower(wnamepart);
- uint32 counter = 0 ;
+ bool found = false;
ObjectMgr::QuestMap const& qTemplates = objmgr.GetQuestTemplates();
for (ObjectMgr::QuestMap::const_iterator iter = qTemplates.begin(); iter != qTemplates.end(); ++iter)
@@ -3562,7 +3562,10 @@ bool ChatHandler::HandleLookupQuestCommand(const char* args)
PSendSysMessage(LANG_QUEST_LIST_CHAT,qinfo->GetQuestId(),qinfo->GetQuestId(),title.c_str(),statusStr);
else
PSendSysMessage(LANG_QUEST_LIST_CONSOLE,qinfo->GetQuestId(),title.c_str(),statusStr);
- ++counter;
+
+ if(!found)
+ found = true;
+
continue;
}
}
@@ -3597,11 +3600,12 @@ bool ChatHandler::HandleLookupQuestCommand(const char* args)
else
PSendSysMessage(LANG_QUEST_LIST_CONSOLE,qinfo->GetQuestId(),title.c_str(),statusStr);
- ++counter;
+ if(!found)
+ found = true;
}
}
- if (counter==0)
+ if (!found)
SendSysMessage(LANG_COMMAND_NOQUESTFOUND);
return true;
@@ -3621,7 +3625,7 @@ bool ChatHandler::HandleLookupCreatureCommand(const char* args)
wstrToLower (wnamepart);
- uint32 counter = 0;
+ bool found = false;
for (uint32 id = 0; id< sCreatureStorage.MaxEntry; ++id)
{
@@ -3645,7 +3649,10 @@ bool ChatHandler::HandleLookupCreatureCommand(const char* args)
PSendSysMessage (LANG_CREATURE_ENTRY_LIST_CHAT, id, id, name.c_str ());
else
PSendSysMessage (LANG_CREATURE_ENTRY_LIST_CONSOLE, id, name.c_str ());
- ++counter;
+
+ if(!found)
+ found = true;
+
continue;
}
}
@@ -3662,11 +3669,13 @@ bool ChatHandler::HandleLookupCreatureCommand(const char* args)
PSendSysMessage (LANG_CREATURE_ENTRY_LIST_CHAT, id, id, name.c_str ());
else
PSendSysMessage (LANG_CREATURE_ENTRY_LIST_CONSOLE, id, name.c_str ());
- ++counter;
+
+ if(!found)
+ found = true;
}
}
- if (counter==0)
+ if (!found)
SendSysMessage (LANG_COMMAND_NOCREATUREFOUND);
return true;
@@ -3686,7 +3695,7 @@ bool ChatHandler::HandleLookupObjectCommand(const char* args)
wstrToLower(wnamepart);
- uint32 counter = 0;
+ bool found = false;
for (uint32 id = 0; id< sGOStorage.MaxEntry; id++ )
{
@@ -3710,7 +3719,10 @@ bool ChatHandler::HandleLookupObjectCommand(const char* args)
PSendSysMessage(LANG_GO_ENTRY_LIST_CHAT, id, id, name.c_str());
else
PSendSysMessage(LANG_GO_ENTRY_LIST_CONSOLE, id, name.c_str());
- ++counter;
+
+ if(!found)
+ found = true;
+
continue;
}
}
@@ -3727,16 +3739,112 @@ bool ChatHandler::HandleLookupObjectCommand(const char* args)
PSendSysMessage(LANG_GO_ENTRY_LIST_CHAT, id, id, name.c_str());
else
PSendSysMessage(LANG_GO_ENTRY_LIST_CONSOLE, id, name.c_str());
- ++counter;
+
+ if(!found)
+ found = true;
}
}
- if(counter==0)
+ if(!found)
SendSysMessage(LANG_COMMAND_NOGAMEOBJECTFOUND);
return true;
}
+bool ChatHandler::HandleLookupFactionCommand(const char* args)
+{
+ if (!*args)
+ return false;
+
+ // Can be NULL at console call
+ Player *target = getSelectedPlayer ();
+
+ std::string namepart = args;
+ std::wstring wnamepart;
+
+ if (!Utf8toWStr (namepart,wnamepart))
+ return false;
+
+ // converting string that we try to find to lower case
+ wstrToLower (wnamepart);
+
+ bool found = false;
+
+ for (uint32 id = 0; id < sFactionStore.GetNumRows(); ++id)
+ {
+ FactionEntry const *factionEntry = sFactionStore.LookupEntry (id);
+ if (factionEntry)
+ {
+ FactionState const* repState = target ? target->GetReputationMgr().GetState(factionEntry) : NULL;
+
+ int loc = GetSessionDbcLocale();
+ std::string name = factionEntry->name[loc];
+ if(name.empty())
+ continue;
+
+ if (!Utf8FitTo(name, wnamepart))
+ {
+ loc = 0;
+ for(; loc < MAX_LOCALE; ++loc)
+ {
+ if(loc==GetSessionDbcLocale())
+ continue;
+
+ name = factionEntry->name[loc];
+ if(name.empty())
+ continue;
+
+ if (Utf8FitTo(name, wnamepart))
+ break;
+ }
+ }
+
+ if(loc < MAX_LOCALE)
+ {
+ // send faction in "id - [faction] rank reputation [visible] [at war] [own team] [unknown] [invisible] [inactive]" format
+ // or "id - [faction] [no reputation]" format
+ std::ostringstream ss;
+ if (m_session)
+ ss << id << " - |cffffffff|Hfaction:" << id << "|h[" << name << " " << localeNames[loc] << "]|h|r";
+ else
+ ss << id << " - " << name << " " << localeNames[loc];
+
+ if (repState) // and then target!=NULL also
+ {
+ ReputationRank rank = target->GetReputationMgr().GetRank(factionEntry);
+ std::string rankName = GetMangosString(ReputationRankStrIndex[rank]);
+
+ ss << " " << rankName << "|h|r (" << target->GetReputationMgr().GetReputation(factionEntry) << ")";
+
+ if(repState->Flags & FACTION_FLAG_VISIBLE)
+ ss << GetTrinityString(LANG_FACTION_VISIBLE);
+ if(repState->Flags & FACTION_FLAG_AT_WAR)
+ ss << GetTrinityString(LANG_FACTION_ATWAR);
+ if(repState->Flags & FACTION_FLAG_PEACE_FORCED)
+ ss << GetTrinityString(LANG_FACTION_PEACE_FORCED);
+ if(repState->Flags & FACTION_FLAG_HIDDEN)
+ ss << GetTrinityString(LANG_FACTION_HIDDEN);
+ if(repState->Flags & FACTION_FLAG_INVISIBLE_FORCED)
+ ss << GetTrinityString(LANG_FACTION_INVISIBLE_FORCED);
+ if(repState->Flags & FACTION_FLAG_INACTIVE)
+ ss << GetTrinityString(LANG_FACTION_INACTIVE);
+ }
+ else
+ ss << GetTrinityString(LANG_FACTION_NOREPUTATION);
+
+ SendSysMessage(ss.str().c_str());
+
+ if(!found)
+ found = true;
+ }
+ }
+ }
+
+ if (!found)
+ SendSysMessage(LANG_COMMAND_FACTION_NOTFOUND);
+ return true;
+}
+
bool ChatHandler::HandleLookupTaxiNodeCommand(const char * args)
{
if(!*args)
@@ -3751,7 +3859,7 @@ bool ChatHandler::HandleLookupTaxiNodeCommand(const char * args)
// converting string that we try to find to lower case
wstrToLower( wnamepart );
- uint32 counter = 0; // Counter for figure out that we found smth.
+ bool found = false;
// Search in TaxiNodes.dbc
for (uint32 id = 0; id < sTaxiNodesStore.GetNumRows(); id++)
@@ -3790,12 +3898,14 @@ bool ChatHandler::HandleLookupTaxiNodeCommand(const char * args)
else
PSendSysMessage (LANG_TAXINODE_ENTRY_LIST_CONSOLE, id, name.c_str(), localeNames[loc],
nodeEntry->map_id,nodeEntry->x,nodeEntry->y,nodeEntry->z);
- ++counter;
+
+ if(!found)
+ found = true;
}
}
}
- if (counter == 0) // if counter == 0 then we found nth
- SendSysMessage(LANG_COMMAND_NOSPELLFOUND);
+ if (!found)
+ SendSysMessage(LANG_COMMAND_NOTAXINODEFOUND);
return true;
}
@@ -3813,7 +3923,7 @@ bool ChatHandler::HandleLookupMapCommand(const char* args)
wstrToLower(wnamepart);
- uint32 counter = 0;
+ bool found = false;
// search in Map.dbc
for(uint32 id = 0; id < sMapStore.GetNumRows(); id++)
@@ -3892,12 +4002,13 @@ bool ChatHandler::HandleLookupMapCommand(const char* args)
else
SendSysMessage(ss.str().c_str());
- counter++;
+ if(!found)
+ found = true;
}
}
}
- if(!counter)
+ if(!found)
SendSysMessage(LANG_COMMAND_NOMAPFOUND);
return true;
@@ -4672,11 +4783,7 @@ void ChatHandler::HandleCharacterLevel(Player* player, uint64 player_guid, uint3
else
{
// update level and XP at level, all other will be updated at loading
- Tokens values;
- Player::LoadValuesArrayFromDB(values,player_guid);
- Player::SetUInt32ValueInArray(values,UNIT_FIELD_LEVEL,newlevel);
- Player::SetUInt32ValueInArray(values,PLAYER_XP,0);
- Player::SaveValuesArrayInDB(values,player_guid);
+ CharacterDatabase.PExecute("UPDATE characters SET level = '%u', xp = 0 WHERE guid = '%u'", newlevel, GUID_LOPART(player_guid));
}
}
@@ -4701,7 +4808,7 @@ bool ChatHandler::HandleCharacterLevelCommand(const char* args)
if(!extractPlayerTarget(nameStr,&target,&target_guid,&target_name))
return false;
- int32 oldlevel = target ? target->getLevel() : Player::GetUInt32ValueFromDB(UNIT_FIELD_LEVEL,target_guid);
+ int32 oldlevel = target ? target->getLevel() : Player::GetLevelFromDB(target_guid);
int32 newlevel = levelStr ? atoi(levelStr) : oldlevel;
if(newlevel < 1)
@@ -4740,7 +4847,7 @@ bool ChatHandler::HandleLevelUpCommand(const char* args)
if(!extractPlayerTarget(nameStr,&target,&target_guid,&target_name))
return false;
- int32 oldlevel = target ? target->getLevel() : Player::GetUInt32ValueFromDB(UNIT_FIELD_LEVEL,target_guid);
+ int32 oldlevel = target ? target->getLevel() : Player::GetLevelFromDB(target_guid);
int32 addlevel = levelStr ? atoi(levelStr) : 1;
int32 newlevel = oldlevel + addlevel;
@@ -4823,57 +4930,6 @@ bool ChatHandler::HandleHideAreaCommand(const char* args)
return true;
}
-bool ChatHandler::HandleDebugUpdate(const char* args)
-{
- if(!*args)
- return false;
-
- uint32 updateIndex;
- uint32 value;
-
- char* pUpdateIndex = strtok((char*)args, " ");
-
- Unit* chr = getSelectedUnit();
- if (chr == NULL)
- {
- SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
- SetSentErrorMessage(true);
- return false;
- }
-
- if(!pUpdateIndex)
- {
- return true;
- }
- updateIndex = atoi(pUpdateIndex);
- //check updateIndex
- if(chr->GetTypeId() == TYPEID_PLAYER)
- {
- if (updateIndex>=PLAYER_END) return true;
- }
- else
- {
- if (updateIndex>=UNIT_END) return true;
- }
-
- char* pvalue = strtok(NULL, " ");
- if (!pvalue)
- {
- value=chr->GetUInt32Value(updateIndex);
-
- PSendSysMessage(LANG_UPDATE, chr->GetGUIDLow(),updateIndex,value);
- return true;
- }
-
- value=atoi(pvalue);
-
- PSendSysMessage(LANG_UPDATE_CHANGE, chr->GetGUIDLow(),updateIndex,value);
-
- chr->SetUInt32Value(updateIndex,value);
-
- return true;
-}
-
bool ChatHandler::HandleBankCommand(const char* /*args*/)
{
m_session->SendShowBank( m_session->GetPlayer()->GetGUID() );
@@ -4923,106 +4979,6 @@ bool ChatHandler::HandleChangeWeather(const char* args)
return true;
}
-bool ChatHandler::HandleDebugSetValue(const char* args)
-{
- if(!*args)
- return false;
-
- char* px = strtok((char*)args, " ");
- char* py = strtok(NULL, " ");
- char* pz = strtok(NULL, " ");
-
- if (!px || !py)
- return false;
-
- WorldObject* target = getSelectedObject();
- if(!target)
- {
- SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
- SetSentErrorMessage(true);
- return false;
- }
-
- uint64 guid = target->GetGUID();
-
- uint32 Opcode = (uint32)atoi(px);
- if(Opcode >= target->GetValuesCount())
- {
- PSendSysMessage(LANG_TOO_BIG_INDEX, Opcode, GUID_LOPART(guid), target->GetValuesCount());
- return false;
- }
- uint32 iValue;
- float fValue;
- bool isint32 = true;
- if(pz)
- isint32 = (bool)atoi(pz);
- if(isint32)
- {
- iValue = (uint32)atoi(py);
- sLog.outDebug(GetTrinityString(LANG_SET_UINT), GUID_LOPART(guid), Opcode, iValue);
- target->SetUInt32Value( Opcode , iValue );
- PSendSysMessage(LANG_SET_UINT_FIELD, GUID_LOPART(guid), Opcode,iValue);
- }
- else
- {
- fValue = (float)atof(py);
- sLog.outDebug(GetTrinityString(LANG_SET_FLOAT), GUID_LOPART(guid), Opcode, fValue);
- target->SetFloatValue( Opcode , fValue );
- PSendSysMessage(LANG_SET_FLOAT_FIELD, GUID_LOPART(guid), Opcode,fValue);
- }
-
- return true;
-}
-
-bool ChatHandler::HandleDebugGetValue(const char* args)
-{
- if(!*args)
- return false;
-
- char* px = strtok((char*)args, " ");
- char* pz = strtok(NULL, " ");
-
- if (!px)
- return false;
-
- Unit* target = getSelectedUnit();
- if(!target)
- {
- SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
- SetSentErrorMessage(true);
- return false;
- }
-
- uint64 guid = target->GetGUID();
-
- uint32 Opcode = (uint32)atoi(px);
- if(Opcode >= target->GetValuesCount())
- {
- PSendSysMessage(LANG_TOO_BIG_INDEX, Opcode, GUID_LOPART(guid), target->GetValuesCount());
- return false;
- }
- uint32 iValue;
- float fValue;
- bool isint32 = true;
- if(pz)
- isint32 = (bool)atoi(pz);
-
- if(isint32)
- {
- iValue = target->GetUInt32Value( Opcode );
- sLog.outDebug(GetTrinityString(LANG_GET_UINT), GUID_LOPART(guid), Opcode, iValue);
- PSendSysMessage(LANG_GET_UINT_FIELD, GUID_LOPART(guid), Opcode, iValue);
- }
- else
- {
- fValue = target->GetFloatValue( Opcode );
- sLog.outDebug(GetTrinityString(LANG_GET_FLOAT), GUID_LOPART(guid), Opcode, fValue);
- PSendSysMessage(LANG_GET_FLOAT_FIELD, GUID_LOPART(guid), Opcode, fValue);
- }
-
- return true;
-}
-
bool ChatHandler::HandleDebugSet32Bit(const char* args)
{
if(!*args)
@@ -5056,38 +5012,6 @@ bool ChatHandler::HandleDebugSet32Bit(const char* args)
return true;
}
-bool ChatHandler::HandleDebugMod32Value(const char* args)
-{
- if(!*args)
- return false;
-
- char* px = strtok((char*)args, " ");
- char* py = strtok(NULL, " ");
-
- if (!px || !py)
- return false;
-
- uint32 Opcode = (uint32)atoi(px);
- int Value = atoi(py);
-
- if(Opcode >= m_session->GetPlayer()->GetValuesCount())
- {
- PSendSysMessage(LANG_TOO_BIG_INDEX, Opcode, m_session->GetPlayer()->GetGUIDLow(), m_session->GetPlayer( )->GetValuesCount());
- return false;
- }
-
- sLog.outDebug(GetTrinityString(LANG_CHANGE_32BIT), Opcode, Value);
-
- int CurrentValue = (int)m_session->GetPlayer( )->GetUInt32Value( Opcode );
-
- CurrentValue += Value;
- m_session->GetPlayer( )->SetUInt32Value( Opcode , (uint32)CurrentValue );
-
- PSendSysMessage(LANG_CHANGE_32BIT_FIELD, Opcode,CurrentValue);
-
- return true;
-}
-
bool ChatHandler::HandleTeleAddCommand(const char * args)
{
if(!*args)
@@ -5243,9 +5167,6 @@ bool ChatHandler::HandleResetHonorCommand (const char * args)
static bool HandleResetStatsOrLevelHelper(Player* player)
{
- PlayerInfo const *info = objmgr.GetPlayerInfo(player->getRace(), player->getClass());
- if(!info) return false;
-
ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(player->getClass());
if(!cEntry)
{
@@ -5268,21 +5189,7 @@ static bool HandleResetStatsOrLevelHelper(Player* player)
// reset only if player not in some form;
if(player->m_form==FORM_NONE)
- {
- switch(player->getGender())
- {
- case GENDER_FEMALE:
- player->SetDisplayId(info->displayId_f);
- player->SetNativeDisplayId(info->displayId_f);
- break;
- case GENDER_MALE:
- player->SetDisplayId(info->displayId_m);
- player->SetNativeDisplayId(info->displayId_m);
- break;
- default:
- break;
- }
- }
+ player->InitDisplayIds();
player->SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP );
player->SetByteValue(UNIT_FIELD_BYTES_2, 3, player->m_form);
@@ -5310,6 +5217,8 @@ bool ChatHandler::HandleResetLevelCommand(const char * args)
? sWorld.getConfig(CONFIG_START_PLAYER_LEVEL)
: sWorld.getConfig(CONFIG_START_HEROIC_PLAYER_LEVEL);
+ target->_ApplyAllLevelScaleItemMods(false);
+
target->SetLevel(start_level);
target->InitRunes();
target->InitStatsForLevel(true);
@@ -5318,6 +5227,8 @@ bool ChatHandler::HandleResetLevelCommand(const char * args)
target->InitTalentForLevel();
target->SetUInt32Value(PLAYER_XP,0);
+ target->_ApplyAllLevelScaleItemMods(true);
+
// reset level for pet
if(Pet* pet = target->GetPet())
pet->SynchronizeLevelWithOwner();
@@ -5374,42 +5285,52 @@ bool ChatHandler::HandleResetTalentsCommand(const char * args)
uint64 target_guid;
std::string target_name;
if (!extractPlayerTarget((char*)args,&target,&target_guid,&target_name))
+ {
+ // Try reset talents as Hunter Pet
+ Creature* creature = getSelectedCreature();
+ if (!*args && creature && creature->isPet())
+ {
+ Unit *owner = creature->GetOwner();
+ if(owner && owner->GetTypeId() == TYPEID_PLAYER && ((Pet *)creature)->IsPermanentPetFor((Player*)owner))
+ {
+ ((Pet *)creature)->resetTalents(true);
+ ((Player*)owner)->SendTalentsInfoData(true);
+
+ ChatHandler((Player*)owner).SendSysMessage(LANG_RESET_PET_TALENTS);
+ if(!m_session || m_session->GetPlayer()!=((Player*)owner))
+ PSendSysMessage(LANG_RESET_PET_TALENTS_ONLINE,GetNameLink((Player*)owner).c_str());
+ }
+ return true;
+ }
+
+ SendSysMessage(LANG_NO_CHAR_SELECTED);
+ SetSentErrorMessage(true);
return false;
+ }
if (target)
{
target->resetTalents(true);
-
+ target->SendTalentsInfoData(false);
ChatHandler(target).SendSysMessage(LANG_RESET_TALENTS);
if (!m_session || m_session->GetPlayer()!=target)
PSendSysMessage(LANG_RESET_TALENTS_ONLINE,GetNameLink(target).c_str());
+ Pet* pet = target->GetPet();
+ Pet::resetTalentsForAllPetsOf(target,pet);
+ if(pet)
+ target->SendTalentsInfoData(true);
return true;
}
else if (target_guid)
{
- CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE guid = '%u'",uint32(AT_LOGIN_RESET_TALENTS), GUID_LOPART(target_guid) );
+ uint32 at_flags = AT_LOGIN_NONE | AT_LOGIN_RESET_PET_TALENTS;
+ CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE guid = '%u'",at_flags, GUID_LOPART(target_guid) );
std::string nameLink = playerLink(target_name);
PSendSysMessage(LANG_RESET_TALENTS_OFFLINE,nameLink.c_str());
return true;
}
- // Try reset talents as Hunter Pet
- Creature* creature = getSelectedCreature();
- if (creature && creature->isPet() && ((Pet *)creature)->getPetType() == HUNTER_PET)
- {
- ((Pet *)creature)->resetTalents(true);
- Unit *owner = creature->GetOwner();
- if (owner && owner->GetTypeId() == TYPEID_PLAYER)
- {
- Player* owner_player = (Player *)owner;
- ChatHandler(owner_player).SendSysMessage(LANG_RESET_PET_TALENTS);
- if(!m_session || m_session->GetPlayer()!=owner_player)
- PSendSysMessage(LANG_RESET_PET_TALENTS_ONLINE,GetNameLink(owner_player).c_str());
- }
- return true;
- }
-
SendSysMessage(LANG_NO_CHAR_SELECTED);
SetSentErrorMessage(true);
return false;
@@ -5434,21 +5355,11 @@ bool ChatHandler::HandleResetAllCommand(const char * args)
}
else if(casename=="talents")
{
- atLogin = AT_LOGIN_RESET_TALENTS;
+ atLogin = AtLoginFlags(AT_LOGIN_RESET_TALENTS | AT_LOGIN_RESET_PET_TALENTS);
sWorld.SendWorldText(LANG_RESETALL_TALENTS);
if(!m_session)
SendSysMessage(LANG_RESETALL_TALENTS);
}
- else if(casename=="pet_spells")
- {
- CharacterDatabase.PExecute("UPDATE character_pet SET load_flags = load_flags | '%u' WHERE (load_flags & '%u') = '0'",uint32(AT_LOAD_RESET_SPELLS),uint32(AT_LOAD_RESET_SPELLS));
- HashMapHolder<Player>::MapType const& plist = ObjectAccessor::Instance().GetPlayers();
- for(HashMapHolder<Player>::MapType::const_iterator itr = plist.begin(); itr != plist.end(); ++itr)
- if (itr->second->GetPet())
- itr->second->SetPetAtLoginFlag(AT_LOAD_RESET_SPELLS);
- sWorld.SendWorldText(LANG_RESETALL_PET_SPELLS);
- return true;
- }
else
{
PSendSysMessage(LANG_RESETALL_UNKNOWN_CASE,args);
@@ -5774,8 +5685,9 @@ bool ChatHandler::HandleQuestComplete(const char* args)
}
else if(creature > 0)
{
- for(uint16 z = 0; z < creaturecount; ++z)
- player->KilledMonster(creature,0);
+ if(CreatureInfo const* cInfo = objmgr.GetCreatureTemplate(creature))
+ for(uint16 z = 0; z < creaturecount; ++z)
+ player->KilledMonster(cInfo,0);
}
else if(creature < 0)
{
@@ -5997,7 +5909,7 @@ bool ChatHandler::HandleBanInfoCharacterCommand(const char* args)
bool ChatHandler::HandleBanInfoHelper(uint32 accountid, char const* accountname)
{
- QueryResult *result = LoginDatabase.PQuery("SELECT FROM_UNIXTIME(bandate), unbandate-bandate, active, unbandate,banreason,bannedby FROM account_banned WHERE id = '%u' ORDER BY bandate ASC",accountid);
+ QueryResult *result = loginDatabase.PQuery("SELECT FROM_UNIXTIME(bandate), unbandate-bandate, active, unbandate,banreason,bannedby FROM account_banned WHERE id = '%u' ORDER BY bandate ASC",accountid);
if(!result)
{
PSendSysMessage(LANG_BANINFO_NOACCOUNTBAN, accountname);
@@ -6037,8 +5949,8 @@ bool ChatHandler::HandleBanInfoIPCommand(const char* args)
std::string IP = cIP;
- LoginDatabase.escape_string(IP);
- QueryResult *result = LoginDatabase.PQuery("SELECT ip, FROM_UNIXTIME(bandate), FROM_UNIXTIME(unbandate), unbandate-UNIX_TIMESTAMP(), banreason,bannedby,unbandate-bandate FROM ip_banned WHERE ip = '%s'",IP.c_str());
+ loginDatabase.escape_string(IP);
+ QueryResult *result = loginDatabase.PQuery("SELECT ip, FROM_UNIXTIME(bandate), FROM_UNIXTIME(unbandate), unbandate-UNIX_TIMESTAMP(), banreason,bannedby,unbandate-bandate FROM ip_banned WHERE ip = '%s'",IP.c_str());
if(!result)
{
PSendSysMessage(LANG_BANINFO_NOIP);
@@ -6056,14 +5968,14 @@ bool ChatHandler::HandleBanInfoIPCommand(const char* args)
bool ChatHandler::HandleBanListCharacterCommand(const char* args)
{
- LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
+ loginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
char* cFilter = strtok ((char*)args, " ");
if(!cFilter)
return false;
std::string filter = cFilter;
- LoginDatabase.escape_string(filter);
+ loginDatabase.escape_string(filter);
QueryResult* result = CharacterDatabase.PQuery("SELECT account FROM characters WHERE name "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'"),filter.c_str());
if (!result)
{
@@ -6076,22 +5988,22 @@ bool ChatHandler::HandleBanListCharacterCommand(const char* args)
bool ChatHandler::HandleBanListAccountCommand(const char* args)
{
- LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
+ loginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
char* cFilter = strtok((char*)args, " ");
std::string filter = cFilter ? cFilter : "";
- LoginDatabase.escape_string(filter);
+ loginDatabase.escape_string(filter);
QueryResult* result;
if(filter.empty())
{
- result = LoginDatabase.Query("SELECT account.id, username FROM account, account_banned"
+ result = loginDatabase.Query("SELECT account.id, username FROM account, account_banned"
" WHERE account.id = account_banned.id AND active = 1 GROUP BY account.id");
}
else
{
- result = LoginDatabase.PQuery("SELECT account.id, username FROM account, account_banned"
+ result = loginDatabase.PQuery("SELECT account.id, username FROM account, account_banned"
" WHERE account.id = account_banned.id AND active = 1 AND username "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'")" GROUP BY account.id",
filter.c_str());
}
@@ -6117,7 +6029,7 @@ bool ChatHandler::HandleBanListHelper(QueryResult* result)
Field* fields = result->Fetch();
uint32 accountid = fields[0].GetUInt32();
- QueryResult* banresult = LoginDatabase.PQuery("SELECT account.username FROM account,account_banned WHERE account_banned.id='%u' AND account_banned.id=account.id",accountid);
+ QueryResult* banresult = loginDatabase.PQuery("SELECT account.username FROM account,account_banned WHERE account_banned.id='%u' AND account_banned.id=account.id",accountid);
if(banresult)
{
Field* fields2 = banresult->Fetch();
@@ -6148,7 +6060,7 @@ bool ChatHandler::HandleBanListHelper(QueryResult* result)
accmgr.GetName (account_id,account_name);
// No SQL injection. id is uint32.
- QueryResult *banInfo = LoginDatabase.PQuery("SELECT bandate,unbandate,bannedby,banreason FROM account_banned WHERE id = %u ORDER BY unbandate", account_id);
+ QueryResult *banInfo = loginDatabase.PQuery("SELECT bandate,unbandate,bannedby,banreason FROM account_banned WHERE id = %u ORDER BY unbandate", account_id);
if (banInfo)
{
Field *fields2 = banInfo->Fetch();
@@ -6185,23 +6097,23 @@ bool ChatHandler::HandleBanListHelper(QueryResult* result)
bool ChatHandler::HandleBanListIPCommand(const char* args)
{
- LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
+ loginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
char* cFilter = strtok((char*)args, " ");
std::string filter = cFilter ? cFilter : "";
- LoginDatabase.escape_string(filter);
+ loginDatabase.escape_string(filter);
QueryResult* result;
if(filter.empty())
{
- result = LoginDatabase.Query ("SELECT ip,bandate,unbandate,bannedby,banreason FROM ip_banned"
+ result = loginDatabase.Query ("SELECT ip,bandate,unbandate,bannedby,banreason FROM ip_banned"
" WHERE (bandate=unbandate OR unbandate>UNIX_TIMESTAMP())"
" ORDER BY unbandate" );
}
else
{
- result = LoginDatabase.PQuery( "SELECT ip,bandate,unbandate,bannedby,banreason FROM ip_banned"
+ result = loginDatabase.PQuery( "SELECT ip,bandate,unbandate,bannedby,banreason FROM ip_banned"
" WHERE (bandate=unbandate OR unbandate>UNIX_TIMESTAMP()) AND ip "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'")
" ORDER BY unbandate",filter.c_str() );
}
@@ -6287,7 +6199,7 @@ bool ChatHandler::HandleRespawnCommand(const char* /*args*/)
TypeContainerVisitor<Trinity::WorldObjectWorker<Trinity::RespawnDo>, GridTypeMapContainer > obj_worker(worker);
CellLock<GridReadGuard> cell_lock(cell, p);
- cell_lock->Visit(cell_lock, obj_worker, *MapManager::Instance().GetMap(pl->GetMapId(), pl));
+ cell_lock->Visit(cell_lock, obj_worker, *pl->GetMap());
return true;
}
@@ -6362,18 +6274,18 @@ bool ChatHandler::HandlePDumpLoadCommand(const char *args)
char* name_str = strtok(NULL, " ");
std::string name;
- if(name_str)
+ if (name_str)
{
name = name_str;
// normalize the name if specified and check if it exists
- if(!normalizePlayerName(name))
+ if (!normalizePlayerName(name))
{
PSendSysMessage(LANG_INVALID_CHARACTER_NAME);
SetSentErrorMessage(true);
return false;
}
- if(!ObjectMgr::IsValidName(name,true))
+ if (ObjectMgr::CheckPlayerName(name,true) != CHAR_NAME_SUCCESS)
{
PSendSysMessage(LANG_INVALID_CHARACTER_NAME);
SetSentErrorMessage(true);
@@ -6385,17 +6297,17 @@ bool ChatHandler::HandlePDumpLoadCommand(const char *args)
uint32 guid = 0;
- if(guid_str)
+ if (guid_str)
{
guid = atoi(guid_str);
- if(!guid)
+ if (!guid)
{
PSendSysMessage(LANG_INVALID_CHARACTER_GUID);
SetSentErrorMessage(true);
return false;
}
- if(objmgr.GetPlayerAccountIdByGUID(guid))
+ if (objmgr.GetPlayerAccountIdByGUID(guid))
{
PSendSysMessage(LANG_CHARACTER_GUID_IN_USE,guid);
SetSentErrorMessage(true);
@@ -6970,7 +6882,7 @@ bool ChatHandler::HandleInstanceSaveDataCommand(const char * /*args*/)
bool ChatHandler::HandleGMListFullCommand(const char* /*args*/)
{
///- Get the accounts with GM Level >0
- QueryResult *result = LoginDatabase.Query( "SELECT username,gmlevel FROM account WHERE gmlevel > 0" );
+ QueryResult *result = loginDatabase.Query( "SELECT username,gmlevel FROM account WHERE gmlevel > 0" );
if(result)
{
SendSysMessage(LANG_GMLIST);
@@ -7079,7 +6991,7 @@ bool ChatHandler::HandleAccountSetAddonCommand(const char* args)
return false;
// No SQL injection
- LoginDatabase.PExecute("UPDATE account SET expansion = '%d' WHERE id = '%u'",lev,account_id);
+ loginDatabase.PExecute("UPDATE account SET expansion = '%d' WHERE id = '%u'",lev,account_id);
PSendSysMessage(LANG_ACCOUNT_SETADDON,account_name.c_str(),account_id,lev);
return true;
}
@@ -7330,8 +7242,7 @@ bool ChatHandler::HandleModifyGenderCommand(const char *args)
player->SetByteValue(PLAYER_BYTES_3, 0, gender);
// Change display ID
- player->SetDisplayId(gender ? info->displayId_f : info->displayId_m);
- player->SetNativeDisplayId(gender ? info->displayId_f : info->displayId_m);
+ player->InitDisplayIds();
char const* gender_full = gender ? "female" : "male";
diff --git a/src/game/LootHandler.cpp b/src/game/LootHandler.cpp
index 172a6ef46c2..6b5f22b6a6b 100644
--- a/src/game/LootHandler.cpp
+++ b/src/game/LootHandler.cpp
@@ -259,6 +259,10 @@ void WorldSession::HandleLootOpcode( WorldPacket & recv_data )
uint64 guid;
recv_data >> guid;
+ // Check possible cheat
+ if(!_player->isAlive())
+ return;
+
GetPlayer()->SendLoot(guid, LOOT_CORPSE);
}
diff --git a/src/game/LootMgr.cpp b/src/game/LootMgr.cpp
index 5654f540da1..b54d7b90774 100644
--- a/src/game/LootMgr.cpp
+++ b/src/game/LootMgr.cpp
@@ -1152,7 +1152,7 @@ void LoadLootTemplates_Gameobject()
{
if(GameObjectInfo const* gInfo = sGOStorage.LookupEntry<GameObjectInfo>(i))
{
- if(uint32 lootid = GameObject::GetLootId(gInfo))
+ if(uint32 lootid = gInfo->GetLootId())
{
if(!ids_set.count(lootid))
LootTemplates_Gameobject.ReportNotExistedId(lootid);
@@ -1323,10 +1323,12 @@ void LoadLootTemplates_Spell()
if(!ids_set.count(spell_id))
{
- // not report about not trainable spells (optionally supported by DB) except with SPELL_ATTR_EX2_UNK14 (clams)
- // 61756 (Northrend Inscription Research (FAST QA VERSION) for example
- if ((spellInfo->Attributes & SPELL_ATTR_UNK5) || (spellInfo->AttributesEx2 & SPELL_ATTR_EX2_UNK14))
+ // not report about not trainable spells (optionally supported by DB)
+ // ignore 61756 (Northrend Inscription Research (FAST QA VERSION) for example
+ if (!(spellInfo->Attributes & SPELL_ATTR_NOT_SHAPESHIFT) || (spellInfo->Attributes & SPELL_ATTR_UNK5))
+ {
LootTemplates_Spell.ReportNotExistedId(spell_id);
+ }
}
else
ids_set.erase(spell_id);
diff --git a/src/game/Mail.cpp b/src/game/Mail.cpp
index 0af4999092f..94f40f0079e 100644
--- a/src/game/Mail.cpp
+++ b/src/game/Mail.cpp
@@ -32,6 +32,15 @@
#include "AuctionHouseBot.h"
#include "DBCStores.h"
+enum MailShowFlags
+{
+ MAIL_SHOW_UNK0 = 0x0001,
+ MAIL_SHOW_DELETE = 0x0002, // forced show delete button instead return button
+ MAIL_SHOW_AUCTION = 0x0004, // from old comment
+ MAIL_SHOW_COD = 0x0008, // show subject prefix
+ MAIL_SHOW_UNK4 = 0x0010,
+};
+
void MailItem::deleteItem( bool inDB )
{
if(item)
@@ -381,7 +390,7 @@ void WorldSession::HandleMailReturnToSender(WorldPacket & recv_data )
}
}
- if (m->sender == AHBplayerGUID)
+ if (m->sender == auctionbot.GetAHBplayerGUID())
{
SendReturnToSender(MAIL_CREATURE, GetAccountId(), m->receiver, m->sender, m->subject, m->itemTextId, &mi, m->money, m->mailTemplateId);
}
@@ -567,7 +576,7 @@ void WorldSession::HandleMailTakeMoney(WorldPacket & recv_data )
// save money and mail to prevent cheating
CharacterDatabase.BeginTransaction();
- pl->SaveDataFieldToDB(); // contains money
+ pl->SaveGoldToDB();
pl->_SaveMail();
CharacterDatabase.CommitTransaction();
}
@@ -611,6 +620,14 @@ void WorldSession::HandleGetMailList(WorldPacket & recv_data )
if(data.wpos()+next_mail_size > maxPacketSize)
break;
+ uint32 show_flags = 0;
+ if ((*itr)->messageType != MAIL_NORMAL)
+ show_flags |= MAIL_SHOW_DELETE;
+ if ((*itr)->messageType == MAIL_AUCTION)
+ show_flags |= MAIL_SHOW_AUCTION;
+ if ((*itr)->COD)
+ show_flags |= MAIL_SHOW_COD;
+
data << (uint16) 0x0040; // unknown 2.3.0, different values
data << (uint32) (*itr)->messageID; // Message ID
data << (uint8) (*itr)->messageType; // Message Type
@@ -634,7 +651,7 @@ void WorldSession::HandleGetMailList(WorldPacket & recv_data )
data << (uint32) 0; // unknown
data << (uint32) (*itr)->stationery; // stationery (Stationery.dbc)
data << (uint32) (*itr)->money; // Gold
- data << (uint32) 0x04; // unknown, 0x4 - auction, 0x10 - normal
+ data << (uint32) show_flags; // unknown, 0x4 - auction, 0x10 - normal
// Time
data << (float) ((*itr)->expire_time-time(NULL))/DAY;
data << (uint32) (*itr)->mailTemplateId; // mail template (MailTemplate.dbc)
@@ -772,38 +789,40 @@ void WorldSession::HandleQueryNextMailTime(WorldPacket & /*recv_data*/ )
{
data << (uint32) 0; // float
data << (uint32) 0; // count
+
uint32 count = 0;
+ time_t now = time(NULL);
for(PlayerMails::iterator itr = _player->GetmailBegin(); itr != _player->GetmailEnd(); ++itr)
{
Mail *m = (*itr);
- // not checked yet, already must be delivered
- if((m->checked & MAIL_CHECK_MASK_READ)==0 && (m->deliver_time <= time(NULL)))
- {
- ++count;
+ // must be not checked yet
+ if(m->checked & MAIL_CHECK_MASK_READ)
+ continue;
- if(count > 2)
- {
- count = 2;
- break;
- }
+ // and already delivered
+ if(now < m->deliver_time)
+ continue;
- data << (uint64) m->sender; // sender guid
+ data << (uint64) m->sender; // sender guid
- switch(m->messageType)
- {
- case MAIL_AUCTION:
- data << (uint32) 2;
- data << (uint32) 2;
- data << (uint32) m->stationery;
- break;
- default:
- data << (uint32) 0;
- data << (uint32) 0;
- data << (uint32) m->stationery;
- break;
- }
- data << (uint32) 0xC6000000; // float unk, time or something
+ switch(m->messageType)
+ {
+ case MAIL_AUCTION:
+ data << (uint32) 2;
+ data << (uint32) 2;
+ data << (uint32) m->stationery;
+ break;
+ default:
+ data << (uint32) 0;
+ data << (uint32) 0;
+ data << (uint32) m->stationery;
+ break;
}
+ data << (uint32) 0xC6000000; // float unk, time or something
+
+ ++count;
+ if(count == 2) // do not display more than 2 mails
+ break;
}
data.put<uint32>(4, count);
}
@@ -817,7 +836,7 @@ void WorldSession::HandleQueryNextMailTime(WorldPacket & /*recv_data*/ )
void WorldSession::SendMailTo(Player* receiver, uint8 messageType, uint8 stationery, uint32 sender_guidlow_or_entry, uint32 receiver_guidlow, std::string subject, uint32 itemTextId, MailItemsInfo* mi, uint32 money, uint32 COD, uint32 checked, uint32 deliver_delay, uint16 mailTemplateId)
{
- if (receiver_guidlow == AHBplayerGUID)
+ if (receiver_guidlow == auctionbot.GetAHBplayerGUID())
{
if(messageType == MAIL_AUCTION && mi) // auction mail with items
{
diff --git a/src/game/Makefile.am b/src/game/Makefile.am
index ed918234265..bc5dace3985 100644
--- a/src/game/Makefile.am
+++ b/src/game/Makefile.am
@@ -624,6 +624,7 @@ libmangosgame_a_SOURCES = \
Channel.cpp \
Channel.h \
ChannelHandler.cpp \
+ ChannelMgr.cpp \
ChannelMgr.h \
CharacterHandler.cpp \
Chat.cpp \
@@ -840,11 +841,8 @@ libmangosgame_a_SOURCES = \
GroupRefManager.h
>>>>>>> 5a6594330caefc0dc00a5fe792dcb0e344b457cb:src/game/Makefile.am
-## Link against shared library
-libmangosgame_a_LIBADD = ../shared/libmangosshared.a ../shared/Auth/libmangosauth.a ../shared/Config/libmangosconfig.a ../shared/Database/libmangosdatabase.a ../shared/vmap/libmangosvmaps.a
-
## Additional files to include when running 'make dist'
# Precompiled Headers for WIN
EXTRA_DIST = \
pchdef.cpp \
- pchdef.h \ No newline at end of file
+ pchdef.h
diff --git a/src/game/Map.cpp b/src/game/Map.cpp
index 6dbb0e37c86..47925102892 100644
--- a/src/game/Map.cpp
+++ b/src/game/Map.cpp
@@ -20,6 +20,7 @@
#include "MapManager.h"
#include "Player.h"
+#include "Vehicle.h"
#include "GridNotifiers.h"
#include "Log.h"
#include "GridStates.h"
@@ -36,6 +37,7 @@
#include "Group.h"
#include "MapRefManager.h"
#include "Vehicle.h"
+#include "WaypointManager.h"
#include "MapInstanced.h"
#include "InstanceSaveMgr.h"
@@ -46,9 +48,20 @@
GridState* si_GridStates[MAX_GRID_STATE];
+struct ScriptAction
+{
+ uint64 sourceGUID;
+ uint64 targetGUID;
+ uint64 ownerGUID; // owner of source if source is item
+ ScriptInfo const* script; // pointer to static script data
+};
+
Map::~Map()
{
UnloadAll();
+
+ if(!m_scriptSchedule.empty())
+ sWorld.DecreaseScheduledScriptCount(m_scriptSchedule.size());
}
bool Map::ExistMap(uint32 mapid,int gx,int gy)
@@ -127,14 +140,12 @@ void Map::LoadMap(int gx,int gy, bool reload)
if(GridMaps[gx][gy])
return;
- Map* baseMap = const_cast<Map*>(MapManager::Instance().CreateBaseMap(i_id));
-
// load grid map for base map
- if (!baseMap->GridMaps[gx][gy])
- baseMap->EnsureGridCreated(GridPair(63-gx,63-gy));
+ if (!m_parentMap->GridMaps[gx][gy])
+ m_parentMap->EnsureGridCreated(GridPair(63-gx,63-gy));
- ((MapInstanced*)(baseMap))->AddGridMapReference(GridPair(gx,gy));
- GridMaps[gx][gy] = baseMap->GridMaps[gx][gy];
+ ((MapInstanced*)(m_parentMap))->AddGridMapReference(GridPair(gx,gy));
+ GridMaps[gx][gy] = m_parentMap->GridMaps[gx][gy];
return;
}
@@ -144,7 +155,7 @@ void Map::LoadMap(int gx,int gy, bool reload)
//map already load, delete it before reloading (Is it necessary? Do we really need the ability the reload maps during runtime?)
if(GridMaps[gx][gy])
{
- sLog.outDetail("Unloading already loaded map %u before reloading.",i_id);
+ sLog.outDetail("Unloading already loaded map %u before reloading.",GetId());
delete (GridMaps[gx][gy]);
GridMaps[gx][gy]=NULL;
}
@@ -153,7 +164,7 @@ void Map::LoadMap(int gx,int gy, bool reload)
char *tmp=NULL;
int len = sWorld.GetDataPath().length()+strlen("maps/%03u%02u%02u.map")+1;
tmp = new char[len];
- snprintf(tmp, len, (char *)(sWorld.GetDataPath()+"maps/%03u%02u%02u.map").c_str(),i_id,gx,gy);
+ snprintf(tmp, len, (char *)(sWorld.GetDataPath()+"maps/%03u%02u%02u.map").c_str(),GetId(),gx,gy);
sLog.outDetail("Loading map %s",tmp);
// loading data
GridMaps[gx][gy] = new GridMap();
@@ -187,11 +198,10 @@ void Map::DeleteStateMachine()
delete si_GridStates[GRID_STATE_REMOVAL];
}
-Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode)
- : i_mapEntry (sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode),
- i_id(id), i_InstanceId(InstanceId), m_unloadTimer(0),
+Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent)
+ : i_mapEntry (sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode), i_InstanceId(InstanceId), m_unloadTimer(0),
m_activeNonPlayersIter(m_activeNonPlayers.end()),
- i_gridExpiry(expiry)
+ i_gridExpiry(expiry), m_parentMap(_parent ? _parent : this)
, i_lock(true)
{
m_notifyTimer.SetInterval(IN_MILISECONDS/2);
@@ -364,6 +374,13 @@ void Map::DeleteFromWorld(T* obj)
delete obj;
}
+template<>
+void Map::DeleteFromWorld(Player* pl)
+{
+ ObjectAccessor::Instance().RemoveObject(pl);
+ delete pl;
+}
+
template<class T>
void Map::AddNotifier(T*)
{
@@ -393,7 +410,7 @@ Map::EnsureGridCreated(const GridPair &p)
Guard guard(*this);
if(!getNGrid(p.x_coord, p.y_coord))
{
- sLog.outDebug("Creating grid[%u,%u] for map %u instance %u", p.x_coord, p.y_coord, i_id, i_InstanceId);
+ sLog.outDebug("Creating grid[%u,%u] for map %u instance %u", p.x_coord, p.y_coord, GetId(), i_InstanceId);
setNGrid(new NGridType(p.x_coord*MAX_NUMBER_OF_GRIDS + p.y_coord, p.x_coord, p.y_coord, i_gridExpiry, sWorld.getConfig(CONFIG_GRID_UNLOAD)),
p.x_coord, p.y_coord);
@@ -425,11 +442,11 @@ Map::EnsureGridLoadedAtEnter(const Cell &cell, Player *player)
if (player)
{
player->SendDelayResponse(MAX_GRID_LOAD_TIME);
- DEBUG_LOG("Player %s enter cell[%u,%u] triggers of loading grid[%u,%u] on map %u", player->GetName(), cell.CellX(), cell.CellY(), cell.GridX(), cell.GridY(), i_id);
+ DEBUG_LOG("Player %s enter cell[%u,%u] triggers of loading grid[%u,%u] on map %u", player->GetName(), cell.CellX(), cell.CellY(), cell.GridX(), cell.GridY(), GetId());
}
else
{
- DEBUG_LOG("Active object nearby triggers of loading grid [%u,%u] on map %u", cell.GridX(), cell.GridY(), i_id);
+ DEBUG_LOG("Active object nearby triggers of loading grid [%u,%u] on map %u", cell.GridX(), cell.GridY(), GetId());
}
ResetGridExpiry(*getNGrid(cell.GridX(), cell.GridY()), 0.1f);
@@ -450,7 +467,7 @@ bool Map::EnsureGridLoaded(const Cell &cell)
assert(grid != NULL);
if( !isGridObjectDataLoaded(cell.GridX(), cell.GridY()) )
{
- sLog.outDebug("Loading grid[%u,%u] for map %u instance %u", cell.GridX(), cell.GridY(), i_id, i_InstanceId);
+ sLog.outDebug("Loading grid[%u,%u] for map %u instance %u", cell.GridX(), cell.GridY(), GetId(), i_InstanceId);
ObjectGridLoader loader(*grid, this, cell);
loader.LoadN();
@@ -474,10 +491,8 @@ void Map::LoadGrid(float x, float y)
bool Map::Add(Player *player)
{
- player->GetMapRef().link(this, player);
-
- player->SetInstanceId(GetInstanceId());
-
+ // Check if we are adding to correct map
+ assert (player->GetMap() == this);
// update player state for other player and visa-versa
CellPair p = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY());
Cell cell(p);
@@ -504,6 +519,8 @@ Map::Add(T *obj)
return;
}
+ obj->SetMap(this);
+
Cell cell(p);
if(obj->isActiveObject())
EnsureGridLoadedAtEnter(cell);
@@ -525,7 +542,6 @@ Map::Add(T *obj)
//also, trigger needs to cast spell, if not update, cannot see visual
//if(obj->GetTypeId() != TYPEID_UNIT)
UpdateObjectVisibility(obj,cell,p);
-
AddNotifier(obj);
}
@@ -633,12 +649,14 @@ void Map::AddUnitToNotify(Unit* u)
}
}
-void Map::RemoveUnitFromNotify(int32 slot)
+void Map::RemoveUnitFromNotify(Unit *unit, int32 slot)
{
if(i_lock)
{
- assert(slot < i_unitsToNotifyBacklog.size());
- i_unitsToNotifyBacklog[slot] = NULL;
+ if(slot < i_unitsToNotifyBacklog.size() && i_unitsToNotifyBacklog[slot] == unit)
+ i_unitsToNotifyBacklog[slot] = NULL;
+ else if(slot < i_unitsToNotify.size() && i_unitsToNotify[slot] == unit)
+ i_unitsToNotify[slot] = NULL;
}
else
{
@@ -774,37 +792,39 @@ void Map::Update(const uint32 &t_diff)
// Don't unload grids if it's battleground, since we may have manually added GOs,creatures, those doesn't load from DB at grid re-load !
// This isn't really bother us, since as soon as we have instanced BG-s, the whole map unloads as the BG gets ended
- if (IsBattleGroundOrArena())
- return;
-
- for (GridRefManager<NGridType>::iterator i = GridRefManager<NGridType>::begin(); i != GridRefManager<NGridType>::end(); )
+ if (!IsBattleGroundOrArena())
{
- NGridType *grid = i->getSource();
- GridInfo *info = i->getSource()->getGridInfoRef();
- ++i; // The update might delete the map and we need the next map before the iterator gets invalid
- assert(grid->GetGridState() >= 0 && grid->GetGridState() < MAX_GRID_STATE);
- si_GridStates[grid->GetGridState()]->Update(*this, *grid, *info, grid->getX(), grid->getY(), t_diff);
+ for (GridRefManager<NGridType>::iterator i = GridRefManager<NGridType>::begin(); i != GridRefManager<NGridType>::end(); )
+ {
+ NGridType *grid = i->getSource();
+ GridInfo *info = i->getSource()->getGridInfoRef();
+ ++i; // The update might delete the map and we need the next map before the iterator gets invalid
+ assert(grid->GetGridState() >= 0 && grid->GetGridState() < MAX_GRID_STATE);
+ si_GridStates[grid->GetGridState()]->Update(*this, *grid, *info, grid->getX(), grid->getY(), t_diff);
+ }
}
+
+ ///- Process necessary scripts
+ if (!m_scriptSchedule.empty())
+ ScriptsProcess();
}
void Map::Remove(Player *player, bool remove)
{
- // this may be called during Map::Update
- // after decrement+unlink, ++m_mapRefIter will continue correctly
- // when the first element of the list is being removed
- // nocheck_prev will return the padding element of the RefManager
- // instead of NULL in the case of prev
- if(m_mapRefIter == player->GetMapRef())
- m_mapRefIter = m_mapRefIter->nocheck_prev();
- player->GetMapRef().unlink();
CellPair p = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY());
if(p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
{
+ if(remove)
+ player->CleanupsBeforeDelete();
+
// invalid coordinates
player->RemoveFromWorld();
if( remove )
+ {
+ player->ResetMap();
DeleteFromWorld(player);
+ }
return;
}
@@ -821,6 +841,9 @@ void Map::Remove(Player *player, bool remove)
NGridType *grid = getNGrid(cell.GridX(), cell.GridY());
assert(grid != NULL);
+ if(remove)
+ player->CleanupsBeforeDelete();
+
player->RemoveFromWorld();
RemoveFromGrid(player,grid,cell);
@@ -870,6 +893,7 @@ Map::Remove(T *obj, bool remove)
UpdateObjectVisibility(obj,cell,p);
+ obj->ResetMap();
if( remove )
{
// if option set then object already saved at this moment
@@ -1010,7 +1034,6 @@ void Map::MoveAllCreaturesInMoveList()
if((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES)==0)
sLog.outDebug("Creature (GUID: %u Entry: %u ) can't be move to unloaded respawn grid.",c->GetGUIDLow(),c->GetEntry());
#endif
- c->CleanupsBeforeDelete();
AddObjectToRemoveList(c);
}
}
@@ -1121,7 +1144,7 @@ bool Map::UnloadGrid(const uint32 &x, const uint32 &y, bool unloadAll)
if(!unloadAll && ActiveObjectsNearGrid(x, y) )
return false;
- sLog.outDebug("Unloading grid[%u,%u] for map %u", x,y, i_id);
+ sLog.outDebug("Unloading grid[%u,%u] for map %u", x,y, GetId());
ObjectGridUnloader unloader(*grid);
@@ -1167,13 +1190,29 @@ bool Map::UnloadGrid(const uint32 &x, const uint32 &y, bool unloadAll)
VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(GetId(), gy, gx);
}
else
- ((MapInstanced*)(MapManager::Instance().CreateBaseMap(i_id)))->RemoveGridMapReference(GridPair(gx, gy));
+ ((MapInstanced*)m_parentMap)->RemoveGridMapReference(GridPair(gx, gy));
+
GridMaps[gx][gy] = NULL;
}
- DEBUG_LOG("Unloading grid[%u,%u] for map %u finished", x,y, i_id);
+ DEBUG_LOG("Unloading grid[%u,%u] for map %u finished", x,y, GetId());
return true;
}
+void Map::RemoveAllPlayers()
+{
+ if(HavePlayers())
+ {
+ sLog.outError("Map::UnloadAll: there are still players in the instance at unload, should not happen!");
+
+ for(MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
+ {
+ Player* plr = itr->getSource();
+ if(!plr->IsBeingTeleportedFar())
+ plr->TeleportTo(plr->m_homebindMapId, plr->m_homebindX, plr->m_homebindY, plr->m_homebindZ, plr->GetOrientation());
+ }
+ }
+}
+
void Map::UnloadAll()
{
// clear all delayed moves, useless anyway do this moves before map unload.
@@ -1297,11 +1336,11 @@ bool GridMap::loadHeihgtData(FILE *in, uint32 offset, uint32 size)
map_heightHeader header;
fseek(in, offset, SEEK_SET);
fread(&header, sizeof(header), 1, in);
- if (header.fourcc != uint32(MAP_HEIGTH_MAGIC))
+ if (header.fourcc != uint32(MAP_HEIGHT_MAGIC))
return false;
m_gridHeight = header.gridHeight;
- if (!(header.flags & MAP_HEIGHT_NO_HIGHT))
+ if (!(header.flags & MAP_HEIGHT_NO_HEIGHT))
{
if ((header.flags & MAP_HEIGHT_AS_INT16))
{
@@ -1350,12 +1389,12 @@ bool GridMap::loadLiquidData(FILE *in, uint32 offset, uint32 size)
m_liquid_height= header.height;
m_liquidLevel = header.liquidLevel;
- if (!(header.flags&MAP_LIQUID_NO_TYPE))
+ if (!(header.flags & MAP_LIQUID_NO_TYPE))
{
m_liquid_type = new uint8 [16*16];
fread(m_liquid_type, sizeof(uint8), 16*16, in);
}
- if (!(header.flags&MAP_LIQUID_NO_HIGHT))
+ if (!(header.flags & MAP_LIQUID_NO_HEIGHT))
{
m_liquid_map = new float [m_liquid_width*m_liquid_height];
fread(m_liquid_map, sizeof(float), m_liquid_width*m_liquid_height, in);
@@ -1792,7 +1831,7 @@ uint16 Map::GetAreaFlag(float x, float y, float z) const
areaflag = gmap->getArea(x, y);
// this used while not all *.map files generated (instances)
else
- areaflag = GetAreaFlagByMapId(i_id);
+ areaflag = GetAreaFlagByMapId(GetId());
//FIXME: some hacks for areas above or underground for ground area
// required for area specific spells/etc, until map/vmap data
@@ -1990,7 +2029,7 @@ void Map::GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 area
zoneid = entry ? (( entry->zone != 0 ) ? entry->zone : entry->ID) : 0;
}
-bool Map::IsInWater(float x, float y, float pZ) const
+bool Map::IsInWater(float x, float y, float pZ, float min_depth) const
{
// Check surface in x, y point for liquid
if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
@@ -1998,7 +2037,7 @@ bool Map::IsInWater(float x, float y, float pZ) const
LiquidData liquid_status;
if (getLiquidStatus(x, y, pZ, MAP_ALL_LIQUIDS, &liquid_status))
{
- if (liquid_status.level - liquid_status.depth_level > 2)
+ if (liquid_status.level - liquid_status.depth_level > min_depth)
return true;
}
}
@@ -2097,7 +2136,7 @@ void Map::SendInitTransports( Player * player )
for (MapManager::TransportSet::const_iterator i = tset.begin(); i != tset.end(); ++i)
{
// send data for current transport in other place
- if((*i) != player->GetTransport() && (*i)->GetMapId()==i_id)
+ if((*i) != player->GetTransport() && (*i)->GetMapId()==GetId())
{
(*i)->BuildCreateUpdateBlockForPlayer(&transData, player);
}
@@ -2123,7 +2162,7 @@ void Map::SendRemoveTransports( Player * player )
// except used transport
for (MapManager::TransportSet::const_iterator i = tset.begin(); i != tset.end(); ++i)
- if((*i) != player->GetTransport() && (*i)->GetMapId()!=i_id)
+ if((*i) != player->GetTransport() && (*i)->GetMapId()!=GetId())
(*i)->BuildOutOfRangeUpdateBlock(&transData);
WorldPacket packet;
@@ -2151,6 +2190,8 @@ void Map::AddObjectToRemoveList(WorldObject *obj)
{
assert(obj->GetMapId()==GetId() && obj->GetInstanceId()==GetInstanceId());
+ obj->CleanupsBeforeDelete(); // remove or simplify at least cross referenced links
+
i_objectsToRemove.insert(obj);
//sLog.outDebug("Object (GUID: %u TypeId: %u ) added to removing list.",obj->GetGUIDLow(),obj->GetTypeId());
}
@@ -2326,8 +2367,8 @@ template void Map::Remove(DynamicObject *, bool);
/* ******* Dungeon Instance Maps ******* */
-InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode)
- : Map(id, expiry, InstanceId, SpawnMode),
+InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent)
+ : Map(id, expiry, InstanceId, SpawnMode, _parent),
m_resetAfterUnload(false), m_unloadWhenEmpty(false),
i_data(NULL), i_script_id(0)
{
@@ -2388,8 +2429,9 @@ bool InstanceMap::Add(Player *player)
{
Guard guard(*this);
- if(!CanEnter(player))
- return false;
+ // Check moved to void WorldSession::HandleMoveWorldportAckOpcode()
+ //if(!CanEnter(player))
+ //return false;
// Dungeon only code
if(IsDungeon())
@@ -2617,15 +2659,7 @@ void InstanceMap::PermBindAllPlayers(Player *player)
void InstanceMap::UnloadAll()
{
- if(HavePlayers())
- {
- sLog.outError("InstanceMap::UnloadAll: there are still players in the instance at unload, should not happen!");
- for(MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
- {
- Player* plr = itr->getSource();
- plr->TeleportTo(plr->m_homebindMapId, plr->m_homebindX, plr->m_homebindY, plr->m_homebindZ, plr->GetOrientation());
- }
- }
+ assert(!HavePlayers());
if(m_resetAfterUnload == true)
objmgr.DeleteRespawnTimeForInstance(GetInstanceId());
@@ -2662,8 +2696,8 @@ uint32 InstanceMap::GetMaxPlayers() const
/* ******* Battleground Instance Maps ******* */
-BattleGroundMap::BattleGroundMap(uint32 id, time_t expiry, uint32 InstanceId)
- : Map(id, expiry, InstanceId, DIFFICULTY_NORMAL)
+BattleGroundMap::BattleGroundMap(uint32 id, time_t expiry, uint32 InstanceId, Map* _parent)
+ : Map(id, expiry, InstanceId, DIFFICULTY_NORMAL, _parent)
{
}
@@ -2692,8 +2726,9 @@ bool BattleGroundMap::Add(Player * player)
{
{
Guard guard(*this);
- if(!CanEnter(player))
- return false;
+ //Check moved to void WorldSession::HandleMoveWorldportAckOpcode()
+ //if(!CanEnter(player))
+ //return false;
// reset instance validity, battleground maps do not homebind
player->m_InstanceValid = true;
}
@@ -2711,21 +2746,847 @@ void BattleGroundMap::SetUnload()
m_unloadTimer = MIN_UNLOAD_DELAY;
}
-void BattleGroundMap::UnloadAll()
+void BattleGroundMap::RemoveAllPlayers()
{
- while(HavePlayers())
+ if(HavePlayers())
{
- if(Player * plr = m_mapRefManager.getFirst()->getSource())
+ for(MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
{
- plr->TeleportTo(plr->GetBattleGroundEntryPoint());
- // TeleportTo removes the player from this map (if the map exists) -> calls BattleGroundMap::Remove -> invalidates the iterator.
- // just in case, remove the player from the list explicitly here as well to prevent a possible infinite loop
- // note that this remove is not needed if the code works well in other places
- plr->GetMapRef().unlink();
+ Player* plr = itr->getSource();
+ if(!plr->IsBeingTeleportedFar())
+ plr->TeleportTo(plr->GetBattleGroundEntryPoint());
}
}
+}
- Map::UnloadAll();
+/// Put scripts in the execution queue
+void Map::ScriptsStart(ScriptMapMap const& scripts, uint32 id, Object* source, Object* target)
+{
+ ///- Find the script map
+ ScriptMapMap::const_iterator s = scripts.find(id);
+ if (s == scripts.end())
+ return;
+
+ // prepare static data
+ uint64 sourceGUID = source ? source->GetGUID() : (uint64)0; //some script commands doesn't have source
+ uint64 targetGUID = target ? target->GetGUID() : (uint64)0;
+ uint64 ownerGUID = (source->GetTypeId()==TYPEID_ITEM) ? ((Item*)source)->GetOwnerGUID() : (uint64)0;
+
+ ///- Schedule script execution for all scripts in the script map
+ ScriptMap const *s2 = &(s->second);
+ bool immedScript = false;
+ for (ScriptMap::const_iterator iter = s2->begin(); iter != s2->end(); ++iter)
+ {
+ ScriptAction sa;
+ sa.sourceGUID = sourceGUID;
+ sa.targetGUID = targetGUID;
+ sa.ownerGUID = ownerGUID;
+
+ sa.script = &iter->second;
+ m_scriptSchedule.insert(std::pair<time_t, ScriptAction>(time_t(sWorld.GetGameTime() + iter->first), sa));
+ if (iter->first == 0)
+ immedScript = true;
+
+ sWorld.IncreaseScheduledScriptsCount();
+ }
+ ///- If one of the effects should be immediate, launch the script execution
+ if (/*start &&*/ immedScript)
+ ScriptsProcess();
+}
+
+void Map::ScriptCommandStart(ScriptInfo const& script, uint32 delay, Object* source, Object* target)
+{
+ // NOTE: script record _must_ exist until command executed
+
+ // prepare static data
+ uint64 sourceGUID = source ? source->GetGUID() : (uint64)0;
+ uint64 targetGUID = target ? target->GetGUID() : (uint64)0;
+ uint64 ownerGUID = (source->GetTypeId()==TYPEID_ITEM) ? ((Item*)source)->GetOwnerGUID() : (uint64)0;
+
+ ScriptAction sa;
+ sa.sourceGUID = sourceGUID;
+ sa.targetGUID = targetGUID;
+ sa.ownerGUID = ownerGUID;
+
+ sa.script = &script;
+ m_scriptSchedule.insert(std::pair<time_t, ScriptAction>(time_t(sWorld.GetGameTime() + delay), sa));
+
+ sWorld.IncreaseScheduledScriptsCount();
+
+ ///- If effects should be immediate, launch the script execution
+ if(delay == 0)
+ ScriptsProcess();
+}
+
+/// Process queued scripts
+void Map::ScriptsProcess()
+{
+ if (m_scriptSchedule.empty())
+ return;
+
+ ///- Process overdue queued scripts
+ std::multimap<time_t, ScriptAction>::iterator iter = m_scriptSchedule.begin();
+ // ok as multimap is a *sorted* associative container
+ while (!m_scriptSchedule.empty() && (iter->first <= sWorld.GetGameTime()))
+ {
+ ScriptAction const& step = iter->second;
+
+ Object* source = NULL;
+
+ if(step.sourceGUID)
+ {
+ switch(GUID_HIPART(step.sourceGUID))
+ {
+ case HIGHGUID_ITEM:
+ // case HIGHGUID_CONTAINER: ==HIGHGUID_ITEM
+ {
+ Player* player = HashMapHolder<Player>::Find(step.ownerGUID);
+ if(player)
+ source = player->GetItemByGuid(step.sourceGUID);
+ break;
+ }
+ case HIGHGUID_UNIT:
+ source = HashMapHolder<Creature>::Find(step.sourceGUID);
+ break;
+ case HIGHGUID_PET:
+ source = HashMapHolder<Pet>::Find(step.sourceGUID);
+ break;
+ case HIGHGUID_VEHICLE:
+ source = HashMapHolder<Vehicle>::Find(step.sourceGUID);
+ break;
+ case HIGHGUID_PLAYER:
+ source = HashMapHolder<Player>::Find(step.sourceGUID);
+ break;
+ case HIGHGUID_GAMEOBJECT:
+ source = HashMapHolder<GameObject>::Find(step.sourceGUID);
+ break;
+ case HIGHGUID_CORPSE:
+ source = HashMapHolder<Corpse>::Find(step.sourceGUID);
+ break;
+ case HIGHGUID_MO_TRANSPORT:
+ for (MapManager::TransportSet::iterator iter = MapManager::Instance().m_Transports.begin(); iter != MapManager::Instance().m_Transports.end(); ++iter)
+ {
+ if((*iter)->GetGUID() == step.sourceGUID)
+ {
+ source = reinterpret_cast<Object*>(*iter);
+ break;
+ }
+ }
+ break;
+ default:
+ sLog.outError("*_script source with unsupported high guid value %u",GUID_HIPART(step.sourceGUID));
+ break;
+ }
+ }
+
+ //if(source && !source->IsInWorld()) source = NULL;
+
+ Object* target = NULL;
+
+ if(step.targetGUID)
+ {
+ switch(GUID_HIPART(step.targetGUID))
+ {
+ case HIGHGUID_UNIT:
+ target = HashMapHolder<Creature>::Find(step.targetGUID);
+ break;
+ case HIGHGUID_PET:
+ target = HashMapHolder<Pet>::Find(step.targetGUID);
+ break;
+ case HIGHGUID_VEHICLE:
+ target = HashMapHolder<Vehicle>::Find(step.targetGUID);
+ break;
+ case HIGHGUID_PLAYER: // empty GUID case also
+ target = HashMapHolder<Player>::Find(step.targetGUID);
+ break;
+ case HIGHGUID_GAMEOBJECT:
+ target = HashMapHolder<GameObject>::Find(step.targetGUID);
+ break;
+ case HIGHGUID_CORPSE:
+ target = HashMapHolder<Corpse>::Find(step.targetGUID);
+ break;
+ default:
+ sLog.outError("*_script source with unsupported high guid value %u",GUID_HIPART(step.targetGUID));
+ break;
+ }
+ }
+
+ //if(target && !target->IsInWorld()) target = NULL;
+
+ switch (step.script->command)
+ {
+ case SCRIPT_COMMAND_TALK:
+ {
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_TALK call for NULL creature.");
+ break;
+ }
+
+ if(source->GetTypeId()!=TYPEID_UNIT)
+ {
+ sLog.outError("SCRIPT_COMMAND_TALK call for non-creature (TypeId: %u), skipping.",source->GetTypeId());
+ break;
+ }
+ if(step.script->datalong > 3)
+ {
+ sLog.outError("SCRIPT_COMMAND_TALK invalid chat type (%u), skipping.",step.script->datalong);
+ break;
+ }
+
+ uint64 unit_target = target ? target->GetGUID() : 0;
+
+ //datalong 0=normal say, 1=whisper, 2=yell, 3=emote text
+ switch(step.script->datalong)
+ {
+ case 0: // Say
+ ((Creature *)source)->Say(step.script->dataint, LANG_UNIVERSAL, unit_target);
+ break;
+ case 1: // Whisper
+ if(!unit_target)
+ {
+ sLog.outError("SCRIPT_COMMAND_TALK attempt to whisper (%u) NULL, skipping.",step.script->datalong);
+ break;
+ }
+ ((Creature *)source)->Whisper(step.script->dataint,unit_target);
+ break;
+ case 2: // Yell
+ ((Creature *)source)->Yell(step.script->dataint, LANG_UNIVERSAL, unit_target);
+ break;
+ case 3: // Emote text
+ ((Creature *)source)->TextEmote(step.script->dataint, unit_target);
+ break;
+ default:
+ break; // must be already checked at load
+ }
+ break;
+ }
+
+ case SCRIPT_COMMAND_EMOTE:
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_EMOTE call for NULL creature.");
+ break;
+ }
+
+ if(source->GetTypeId()!=TYPEID_UNIT)
+ {
+ sLog.outError("SCRIPT_COMMAND_EMOTE call for non-creature (TypeId: %u), skipping.",source->GetTypeId());
+ break;
+ }
+
+ ((Creature *)source)->HandleEmoteCommand(step.script->datalong);
+ break;
+ case SCRIPT_COMMAND_FIELD_SET:
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_FIELD_SET call for NULL object.");
+ break;
+ }
+ if(step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= source->GetValuesCount())
+ {
+ sLog.outError("SCRIPT_COMMAND_FIELD_SET call for wrong field %u (max count: %u) in object (TypeId: %u).",
+ step.script->datalong,source->GetValuesCount(),source->GetTypeId());
+ break;
+ }
+
+ source->SetUInt32Value(step.script->datalong, step.script->datalong2);
+ break;
+ case SCRIPT_COMMAND_MOVE_TO:
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_MOVE_TO call for NULL creature.");
+ break;
+ }
+
+ if(source->GetTypeId()!=TYPEID_UNIT)
+ {
+ sLog.outError("SCRIPT_COMMAND_MOVE_TO call for non-creature (TypeId: %u), skipping.",source->GetTypeId());
+ break;
+ }
+ ((Creature*)source)->SendMonsterMoveWithSpeed(step.script->x, step.script->y, step.script->z, step.script->datalong2 );
+ ((Creature*)source)->GetMap()->CreatureRelocation(((Creature*)source), step.script->x, step.script->y, step.script->z, 0);
+ break;
+ case SCRIPT_COMMAND_FLAG_SET:
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_FLAG_SET call for NULL object.");
+ break;
+ }
+ if(step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= source->GetValuesCount())
+ {
+ sLog.outError("SCRIPT_COMMAND_FLAG_SET call for wrong field %u (max count: %u) in object (TypeId: %u).",
+ step.script->datalong,source->GetValuesCount(),source->GetTypeId());
+ break;
+ }
+
+ source->SetFlag(step.script->datalong, step.script->datalong2);
+ break;
+ case SCRIPT_COMMAND_FLAG_REMOVE:
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE call for NULL object.");
+ break;
+ }
+ if(step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= source->GetValuesCount())
+ {
+ sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE call for wrong field %u (max count: %u) in object (TypeId: %u).",
+ step.script->datalong,source->GetValuesCount(),source->GetTypeId());
+ break;
+ }
+
+ source->RemoveFlag(step.script->datalong, step.script->datalong2);
+ break;
+
+ case SCRIPT_COMMAND_TELEPORT_TO:
+ {
+ // accept player in any one from target/source arg
+ if (!target && !source)
+ {
+ sLog.outError("SCRIPT_COMMAND_TELEPORT_TO call for NULL object.");
+ break;
+ }
+
+ // must be only Player
+ if((!target || target->GetTypeId() != TYPEID_PLAYER) && (!source || source->GetTypeId() != TYPEID_PLAYER))
+ {
+ sLog.outError("SCRIPT_COMMAND_TELEPORT_TO call for non-player (TypeIdSource: %u)(TypeIdTarget: %u), skipping.", source ? source->GetTypeId() : 0, target ? target->GetTypeId() : 0);
+ break;
+ }
+
+ Player* pSource = target && target->GetTypeId() == TYPEID_PLAYER ? (Player*)target : (Player*)source;
+
+ pSource->TeleportTo(step.script->datalong, step.script->x, step.script->y, step.script->z, step.script->o);
+ break;
+ }
+
+ case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE:
+ {
+ if(!step.script->datalong) // creature not specified
+ {
+ sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE call for NULL creature.");
+ break;
+ }
+
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE call for NULL world object.");
+ break;
+ }
+
+ WorldObject* summoner = dynamic_cast<WorldObject*>(source);
+
+ if(!summoner)
+ {
+ sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE call for non-WorldObject (TypeId: %u), skipping.",source->GetTypeId());
+ break;
+ }
+
+ float x = step.script->x;
+ float y = step.script->y;
+ float z = step.script->z;
+ float o = step.script->o;
+
+ Creature* pCreature = summoner->SummonCreature(step.script->datalong, x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,step.script->datalong2);
+ if (!pCreature)
+ {
+ sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON failed for creature (entry: %u).",step.script->datalong);
+ break;
+ }
+
+ break;
+ }
+
+ case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT:
+ {
+ if(!step.script->datalong) // gameobject not specified
+ {
+ sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT call for NULL gameobject.");
+ break;
+ }
+
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT call for NULL world object.");
+ break;
+ }
+
+ WorldObject* summoner = dynamic_cast<WorldObject*>(source);
+
+ if(!summoner)
+ {
+ sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT call for non-WorldObject (TypeId: %u), skipping.",source->GetTypeId());
+ break;
+ }
+
+ GameObject *go = NULL;
+ int32 time_to_despawn = step.script->datalong2<5 ? 5 : (int32)step.script->datalong2;
+
+ CellPair p(MaNGOS::ComputeCellPair(summoner->GetPositionX(), summoner->GetPositionY()));
+ Cell cell(p);
+ cell.data.Part.reserved = ALL_DISTRICT;
+
+ MaNGOS::GameObjectWithDbGUIDCheck go_check(*summoner,step.script->datalong);
+ MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck> checker(summoner, go,go_check);
+
+ TypeContainerVisitor<MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > object_checker(checker);
+ CellLock<GridReadGuard> cell_lock(cell, p);
+ cell_lock->Visit(cell_lock, object_checker, *summoner->GetMap());
+
+ if ( !go )
+ {
+ sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT failed for gameobject(guid: %u).", step.script->datalong);
+ break;
+ }
+
+ if( go->GetGoType()==GAMEOBJECT_TYPE_FISHINGNODE ||
+ go->GetGoType()==GAMEOBJECT_TYPE_DOOR ||
+ go->GetGoType()==GAMEOBJECT_TYPE_BUTTON ||
+ go->GetGoType()==GAMEOBJECT_TYPE_TRAP )
+ {
+ sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT can not be used with gameobject of type %u (guid: %u).", uint32(go->GetGoType()), step.script->datalong);
+ break;
+ }
+
+ if( go->isSpawned() )
+ break; //gameobject already spawned
+
+ go->SetLootState(GO_READY);
+ go->SetRespawnTime(time_to_despawn); //despawn object in ? seconds
+
+ go->GetMap()->Add(go);
+ break;
+ }
+ case SCRIPT_COMMAND_OPEN_DOOR:
+ {
+ if(!step.script->datalong) // door not specified
+ {
+ sLog.outError("SCRIPT_COMMAND_OPEN_DOOR call for NULL door.");
+ break;
+ }
+
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_OPEN_DOOR call for NULL unit.");
+ break;
+ }
+
+ if(!source->isType(TYPEMASK_UNIT)) // must be any Unit (creature or player)
+ {
+ sLog.outError("SCRIPT_COMMAND_OPEN_DOOR call for non-unit (TypeId: %u), skipping.",source->GetTypeId());
+ break;
+ }
+
+ Unit* caster = (Unit*)source;
+
+ GameObject *door = NULL;
+ int32 time_to_close = step.script->datalong2 < 15 ? 15 : (int32)step.script->datalong2;
+
+ CellPair p(MaNGOS::ComputeCellPair(caster->GetPositionX(), caster->GetPositionY()));
+ Cell cell(p);
+ cell.data.Part.reserved = ALL_DISTRICT;
+
+ MaNGOS::GameObjectWithDbGUIDCheck go_check(*caster,step.script->datalong);
+ MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck> checker(caster,door,go_check);
+
+ TypeContainerVisitor<MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > object_checker(checker);
+ CellLock<GridReadGuard> cell_lock(cell, p);
+ cell_lock->Visit(cell_lock, object_checker, *caster->GetMap());
+
+ if (!door)
+ {
+ sLog.outError("SCRIPT_COMMAND_OPEN_DOOR failed for gameobject(guid: %u).", step.script->datalong);
+ break;
+ }
+ if (door->GetGoType() != GAMEOBJECT_TYPE_DOOR)
+ {
+ sLog.outError("SCRIPT_COMMAND_OPEN_DOOR failed for non-door(GoType: %u).", door->GetGoType());
+ break;
+ }
+
+ if (door->GetGoState() != GO_STATE_READY)
+ break; //door already open
+
+ door->UseDoorOrButton(time_to_close);
+
+ if(target && target->isType(TYPEMASK_GAMEOBJECT) && ((GameObject*)target)->GetGoType()==GAMEOBJECT_TYPE_BUTTON)
+ ((GameObject*)target)->UseDoorOrButton(time_to_close);
+ break;
+ }
+ case SCRIPT_COMMAND_CLOSE_DOOR:
+ {
+ if(!step.script->datalong) // guid for door not specified
+ {
+ sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR call for NULL door.");
+ break;
+ }
+
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR call for NULL unit.");
+ break;
+ }
+
+ if(!source->isType(TYPEMASK_UNIT)) // must be any Unit (creature or player)
+ {
+ sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR call for non-unit (TypeId: %u), skipping.",source->GetTypeId());
+ break;
+ }
+
+ Unit* caster = (Unit*)source;
+
+ GameObject *door = NULL;
+ int32 time_to_open = step.script->datalong2 < 15 ? 15 : (int32)step.script->datalong2;
+
+ CellPair p(MaNGOS::ComputeCellPair(caster->GetPositionX(), caster->GetPositionY()));
+ Cell cell(p);
+ cell.data.Part.reserved = ALL_DISTRICT;
+
+ MaNGOS::GameObjectWithDbGUIDCheck go_check(*caster,step.script->datalong);
+ MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck> checker(caster,door,go_check);
+
+ TypeContainerVisitor<MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > object_checker(checker);
+ CellLock<GridReadGuard> cell_lock(cell, p);
+ cell_lock->Visit(cell_lock, object_checker, *caster->GetMap());
+
+ if ( !door )
+ {
+ sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR failed for gameobject(guid: %u).", step.script->datalong);
+ break;
+ }
+ if ( door->GetGoType() != GAMEOBJECT_TYPE_DOOR )
+ {
+ sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR failed for non-door(GoType: %u).", door->GetGoType());
+ break;
+ }
+
+ if( door->GetGoState() == GO_STATE_READY )
+ break; //door already closed
+
+ door->UseDoorOrButton(time_to_open);
+
+ if(target && target->isType(TYPEMASK_GAMEOBJECT) && ((GameObject*)target)->GetGoType()==GAMEOBJECT_TYPE_BUTTON)
+ ((GameObject*)target)->UseDoorOrButton(time_to_open);
+
+ break;
+ }
+ case SCRIPT_COMMAND_QUEST_EXPLORED:
+ {
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for NULL source.");
+ break;
+ }
+
+ if(!target)
+ {
+ sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for NULL target.");
+ break;
+ }
+
+ // when script called for item spell casting then target == (unit or GO) and source is player
+ WorldObject* worldObject;
+ Player* player;
+
+ if(target->GetTypeId()==TYPEID_PLAYER)
+ {
+ if(source->GetTypeId()!=TYPEID_UNIT && source->GetTypeId()!=TYPEID_GAMEOBJECT)
+ {
+ sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for non-creature and non-gameobject (TypeId: %u), skipping.",source->GetTypeId());
+ break;
+ }
+
+ worldObject = (WorldObject*)source;
+ player = (Player*)target;
+ }
+ else
+ {
+ if(target->GetTypeId()!=TYPEID_UNIT && target->GetTypeId()!=TYPEID_GAMEOBJECT)
+ {
+ sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for non-creature and non-gameobject (TypeId: %u), skipping.",target->GetTypeId());
+ break;
+ }
+
+ if(source->GetTypeId()!=TYPEID_PLAYER)
+ {
+ sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for non-player(TypeId: %u), skipping.",source->GetTypeId());
+ break;
+ }
+
+ worldObject = (WorldObject*)target;
+ player = (Player*)source;
+ }
+
+ // quest id and flags checked at script loading
+ if( (worldObject->GetTypeId()!=TYPEID_UNIT || ((Unit*)worldObject)->isAlive()) &&
+ (step.script->datalong2==0 || worldObject->IsWithinDistInMap(player,float(step.script->datalong2))) )
+ player->AreaExploredOrEventHappens(step.script->datalong);
+ else
+ player->FailQuest(step.script->datalong);
+
+ break;
+ }
+
+ case SCRIPT_COMMAND_ACTIVATE_OBJECT:
+ {
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT must have source caster.");
+ break;
+ }
+
+ if(!source->isType(TYPEMASK_UNIT))
+ {
+ sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT source caster isn't unit (TypeId: %u), skipping.",source->GetTypeId());
+ break;
+ }
+
+ if(!target)
+ {
+ sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT call for NULL gameobject.");
+ break;
+ }
+
+ if(target->GetTypeId()!=TYPEID_GAMEOBJECT)
+ {
+ sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT call for non-gameobject (TypeId: %u), skipping.",target->GetTypeId());
+ break;
+ }
+
+ Unit* caster = (Unit*)source;
+
+ GameObject *go = (GameObject*)target;
+
+ go->Use(caster);
+ break;
+ }
+
+ case SCRIPT_COMMAND_REMOVE_AURA:
+ {
+ Object* cmdTarget = step.script->datalong2 ? source : target;
+
+ if(!cmdTarget)
+ {
+ sLog.outError("SCRIPT_COMMAND_REMOVE_AURA call for NULL %s.",step.script->datalong2 ? "source" : "target");
+ break;
+ }
+
+ if(!cmdTarget->isType(TYPEMASK_UNIT))
+ {
+ sLog.outError("SCRIPT_COMMAND_REMOVE_AURA %s isn't unit (TypeId: %u), skipping.",step.script->datalong2 ? "source" : "target",cmdTarget->GetTypeId());
+ break;
+ }
+
+ ((Unit*)cmdTarget)->RemoveAurasDueToSpell(step.script->datalong);
+ break;
+ }
+
+ case SCRIPT_COMMAND_CAST_SPELL:
+ {
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_CAST_SPELL must have source caster.");
+ break;
+ }
+
+ Object* cmdTarget = step.script->datalong2 & 0x01 ? source : target;
+
+ if(!cmdTarget)
+ {
+ sLog.outError("SCRIPT_COMMAND_CAST_SPELL call for NULL %s.",step.script->datalong2 & 0x01 ? "source" : "target");
+ break;
+ }
+
+ if(!cmdTarget->isType(TYPEMASK_UNIT))
+ {
+ sLog.outError("SCRIPT_COMMAND_CAST_SPELL %s isn't unit (TypeId: %u), skipping.",step.script->datalong2 & 0x01 ? "source" : "target",cmdTarget->GetTypeId());
+ break;
+ }
+
+ Unit* spellTarget = (Unit*)cmdTarget;
+
+ Object* cmdSource = step.script->datalong2 & 0x02 ? target : source;
+
+ if(!cmdSource)
+ {
+ sLog.outError("SCRIPT_COMMAND_CAST_SPELL call for NULL %s.",step.script->datalong2 & 0x02 ? "target" : "source");
+ break;
+ }
+
+ if(!cmdSource->isType(TYPEMASK_UNIT))
+ {
+ sLog.outError("SCRIPT_COMMAND_CAST_SPELL %s isn't unit (TypeId: %u), skipping.",step.script->datalong2 & 0x02 ? "target" : "source", cmdSource->GetTypeId());
+ break;
+ }
+
+ Unit* spellSource = (Unit*)cmdSource;
+
+ //TODO: when GO cast implemented, code below must be updated accordingly to also allow GO spell cast
+ spellSource->CastSpell(spellTarget,step.script->datalong,false);
+
+ break;
+ }
+
+ case SCRIPT_COMMAND_LOAD_PATH:
+ {
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_START_MOVE is tried to apply to NON-existing unit.");
+ break;
+ }
+
+ if(!source->isType(TYPEMASK_UNIT))
+ {
+ sLog.outError("SCRIPT_COMMAND_START_MOVE source mover isn't unit (TypeId: %u), skipping.",source->GetTypeId());
+ break;
+ }
+
+ if(!WaypointMgr.GetPath(step.script->datalong))
+ {
+ sLog.outError("SCRIPT_COMMAND_START_MOVE source mover has an invallid path, skipping.", step.script->datalong2);
+ break;
+ }
+
+ dynamic_cast<Unit*>(source)->GetMotionMaster()->MovePath(step.script->datalong, step.script->datalong2);
+ break;
+ }
+
+ case SCRIPT_COMMAND_CALLSCRIPT_TO_UNIT:
+ {
+ if(!step.script->datalong || !step.script->datalong2)
+ {
+ sLog.outError("SCRIPT_COMMAND_CALLSCRIPT calls invallid db_script_id or lowguid not present: skipping.");
+ break;
+ }
+ //our target
+ Creature* target = NULL;
+
+ if(source) //using grid searcher
+ {
+ CellPair p(Trinity::ComputeCellPair(((Unit*)source)->GetPositionX(), ((Unit*)source)->GetPositionY()));
+ Cell cell(p);
+ cell.data.Part.reserved = ALL_DISTRICT;
+
+ //sLog.outDebug("Attempting to find Creature: Db GUID: %i", step.script->datalong);
+ Trinity::CreatureWithDbGUIDCheck target_check(((Unit*)source), step.script->datalong);
+ Trinity::CreatureSearcher<Trinity::CreatureWithDbGUIDCheck> checker(((Unit*)source), target, target_check);
+
+ TypeContainerVisitor<Trinity::CreatureSearcher <Trinity::CreatureWithDbGUIDCheck>, GridTypeMapContainer > unit_checker(checker);
+ CellLock<GridReadGuard> cell_lock(cell, p);
+ cell_lock->Visit(cell_lock, unit_checker, *(((Unit*)source)->GetMap()));
+ }
+ else //check hashmap holders
+ {
+ if(CreatureData const* data = objmgr.GetCreatureData(step.script->datalong))
+ target = ObjectAccessor::GetObjectInWorld<Creature>(data->mapid, data->posX, data->posY, MAKE_NEW_GUID(step.script->datalong, data->id, HIGHGUID_UNIT), target);
+ }
+ //sLog.outDebug("attempting to pass target...");
+ if(!target)
+ break;
+ //sLog.outDebug("target passed");
+ //Lets choose our ScriptMap map
+ ScriptMapMap *datamap = NULL;
+ switch(step.script->dataint)
+ {
+ case 1://QUEST END SCRIPTMAP
+ datamap = &sQuestEndScripts;
+ break;
+ case 2://QUEST START SCRIPTMAP
+ datamap = &sQuestStartScripts;
+ break;
+ case 3://SPELLS SCRIPTMAP
+ datamap = &sSpellScripts;
+ break;
+ case 4://GAMEOBJECTS SCRIPTMAP
+ datamap = &sGameObjectScripts;
+ break;
+ case 5://EVENTS SCRIPTMAP
+ datamap = &sEventScripts;
+ break;
+ case 6://WAYPOINTS SCRIPTMAP
+ datamap = &sWaypointScripts;
+ break;
+ default:
+ sLog.outError("SCRIPT_COMMAND_CALLSCRIPT ERROR: no scriptmap present... ignoring");
+ break;
+ }
+ //if no scriptmap present...
+ if(!datamap)
+ break;
+
+ uint32 script_id = step.script->datalong2;
+ //insert script into schedule but do not start it
+ ScriptsStart(*datamap, script_id, target, NULL/*, false*/);
+ break;
+ }
+
+ case SCRIPT_COMMAND_KILL:
+ {
+ if(!source || ((Creature*)source)->isDead())
+ break;
+
+ ((Creature*)source)->DealDamage(((Creature*)source), ((Creature*)source)->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
+
+ switch(step.script->dataint)
+ {
+ case 0: break; //return false not remove corpse
+ case 1: ((Creature*)source)->RemoveCorpse(); break;
+ }
+ break;
+ }
+
+ case SCRIPT_COMMAND_PLAY_SOUND:
+ {
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_PLAY_SOUND call for NULL creature.");
+ break;
+ }
+
+ WorldObject* pSource = dynamic_cast<WorldObject*>(source);
+ if(!pSource)
+ {
+ sLog.outError("SCRIPT_COMMAND_PLAY_SOUND call for non-world object (TypeId: %u), skipping.",source->GetTypeId());
+ break;
+ }
+
+ // bitmask: 0/1=anyone/target, 0/2=with distance dependent
+ Player* pTarget = NULL;
+ if(step.script->datalong2 & 1)
+ {
+ if(!target)
+ {
+ sLog.outError("SCRIPT_COMMAND_PLAY_SOUND in targeted mode call for NULL target.");
+ break;
+ }
+
+ if(target->GetTypeId()!=TYPEID_PLAYER)
+ {
+ sLog.outError("SCRIPT_COMMAND_PLAY_SOUND in targeted mode call for non-player (TypeId: %u), skipping.",target->GetTypeId());
+ break;
+ }
+
+ pTarget = (Player*)target;
+ }
+
+ // bitmask: 0/1=anyone/target, 0/2=with distance dependent
+ if(step.script->datalong2 & 2)
+ pSource->PlayDistanceSound(step.script->datalong,pTarget);
+ else
+ pSource->PlayDirectSound(step.script->datalong,pTarget);
+ break;
+ }
+ default:
+ sLog.outError("Unknown script command %u called.",step.script->command);
+ break;
+ }
+
+ m_scriptSchedule.erase(iter);
+ sWorld.DecreaseScheduledScriptCount();
+
+ iter = m_scriptSchedule.begin();
+ }
+ return;
}
Creature*
@@ -2774,3 +3635,10 @@ Map::GetDynamicObject(uint64 guid)
return NULL;
return ret;
}
+
+void Map::UpdateIteratorBack(Player *player)
+{
+ if(m_mapRefIter == player->GetMapRef())
+ m_mapRefIter = m_mapRefIter->nocheck_prev();
+}
+
diff --git a/src/game/Map.h b/src/game/Map.h
index 4caa1942c3c..68d5b90f48d 100644
--- a/src/game/Map.h
+++ b/src/game/Map.h
@@ -43,9 +43,13 @@ class WorldPacket;
class InstanceData;
class Group;
class InstanceSave;
+class Object;
class WorldObject;
class TempSummon;
+class Player;
class CreatureGroup;
+struct ScriptInfo;
+struct ScriptAction;
typedef ACE_RW_Thread_Mutex GridRWLock;
@@ -74,10 +78,11 @@ typedef MaNGOS::SingleThreaded<GridRWLock>::Lock NullGuard;
#define MAP_MAGIC 'SPAM'
#define MAP_VERSION_MAGIC '0.1w'
#define MAP_AREA_MAGIC 'AERA'
-#define MAP_HEIGTH_MAGIC 'TGHM'
+#define MAP_HEIGHT_MAGIC 'TGHM'
#define MAP_LIQUID_MAGIC 'QILM'
-struct map_fileheader{
+struct map_fileheader
+{
uint32 mapMagic;
uint32 versionMagic;
uint32 areaMapOffset;
@@ -89,17 +94,20 @@ struct map_fileheader{
};
#define MAP_AREA_NO_AREA 0x0001
-struct map_areaHeader{
+
+struct map_areaHeader
+{
uint32 fourcc;
uint16 flags;
uint16 gridArea;
};
-#define MAP_HEIGHT_NO_HIGHT 0x0001
+#define MAP_HEIGHT_NO_HEIGHT 0x0001
#define MAP_HEIGHT_AS_INT16 0x0002
#define MAP_HEIGHT_AS_INT8 0x0004
-struct map_heightHeader{
+struct map_heightHeader
+{
uint32 fourcc;
uint32 flags;
float gridHeight;
@@ -107,8 +115,10 @@ struct map_heightHeader{
};
#define MAP_LIQUID_NO_TYPE 0x0001
-#define MAP_LIQUID_NO_HIGHT 0x0002
-struct map_liquidHeader{
+#define MAP_LIQUID_NO_HEIGHT 0x0002
+
+struct map_liquidHeader
+{
uint32 fourcc;
uint16 flags;
uint16 liquidType;
@@ -119,7 +129,8 @@ struct map_liquidHeader{
float liquidLevel;
};
-enum ZLiquidStatus{
+enum ZLiquidStatus
+{
LIQUID_MAP_NO_WATER = 0x00000000,
LIQUID_MAP_ABOVE_WATER = 0x00000001,
LIQUID_MAP_WATER_WALK = 0x00000002,
@@ -138,7 +149,8 @@ enum ZLiquidStatus{
#define MAP_LIQUID_TYPE_DARK_WATER 0x10
#define MAP_LIQUID_TYPE_WMO_WATER 0x20
-struct LiquidData{
+struct LiquidData
+{
uint32 type;
float level;
float depth_level;
@@ -251,7 +263,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
{
friend class MapReference;
public:
- Map(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode);
+ Map(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode, Map* _parent = NULL);
virtual ~Map();
// currently unused for normal maps
@@ -298,7 +310,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
}
time_t GetGridExpiry(void) const { return i_gridExpiry; }
- uint32 GetId(void) const { return i_id; }
+ uint32 GetId(void) const { return i_mapEntry->MapID; }
static bool ExistMap(uint32 mapid, int gx, int gy);
static bool ExistVMap(uint32 mapid, int gx, int gy);
@@ -306,11 +318,13 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
static void InitStateMachine();
static void DeleteStateMachine();
+ Map const * GetParent() const { return m_parentMap; }
+
// some calls like isInWater should not use vmaps due to processor power
// can return INVALID_HEIGHT if under z+2 z coord not found height
float GetHeight(float x, float y, float z, bool pCheckVMap=true) const;
float GetVmapHeight(float x, float y, float z, bool useMaps) const;
- bool IsInWater(float x, float y, float z) const; // does not use z pos. This is for future use
+ bool IsInWater(float x, float y, float z, float min_depth = 2.0f) const;
ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData *data = 0) const;
@@ -325,22 +339,23 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
uint32 GetAreaId(float x, float y, float z) const
{
- return GetAreaIdByAreaFlag(GetAreaFlag(x,y,z),i_id);
+ return GetAreaIdByAreaFlag(GetAreaFlag(x,y,z),GetId());
}
uint32 GetZoneId(float x, float y, float z) const
{
- return GetZoneIdByAreaFlag(GetAreaFlag(x,y,z),i_id);
+ return GetZoneIdByAreaFlag(GetAreaFlag(x,y,z),GetId());
}
void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const
{
- GetZoneAndAreaIdByAreaFlag(zoneid,areaid,GetAreaFlag(x,y,z),i_id);
+ GetZoneAndAreaIdByAreaFlag(zoneid,areaid,GetAreaFlag(x,y,z),GetId());
}
virtual void MoveAllCreaturesInMoveList();
virtual void RemoveAllObjectsInRemoveList();
virtual void RelocationNotify();
+ virtual void RemoveAllPlayers();
bool CreatureRespawnRelocation(Creature *c); // used only in MoveAllCreaturesInMoveList and ObjectGridUnloader
@@ -389,13 +404,17 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
bool ActiveObjectsNearGrid(uint32 x, uint32 y) const;
void AddUnitToNotify(Unit* unit);
- void RemoveUnitFromNotify(int32 slot);
+ void RemoveUnitFromNotify(Unit *unit, int32 slot);
void SendToPlayers(WorldPacket const* data) const;
typedef MapRefManager PlayerList;
PlayerList const& GetPlayers() const { return m_mapRefManager; }
+ //per-map script storage
+ void ScriptsStart(std::map<uint32, std::multimap<uint32, ScriptInfo> > const& scripts, uint32 id, Object* source, Object* target);
+ void ScriptCommandStart(ScriptInfo const& script, uint32 delay, Object* source, Object* target);
+
// must called with AddToWorld
template<class T>
void AddToActive(T* obj) { AddToActiveHelper(obj); }
@@ -414,6 +433,8 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
template<class NOTIFIER> void VisitGrid(const float &x, const float &y, float radius, NOTIFIER &notifier);
CreatureGroupHolderType CreatureGroupHolder;
+ void UpdateIteratorBack(Player *player);
+
#ifdef MAP_BASED_RAND_GEN
MTRand mtRand;
int32 irand(int32 min, int32 max) { return int32 (mtRand.randInt(max - min)) + min; }
@@ -465,6 +486,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
void setGridObjectDataLoaded(bool pLoaded, uint32 x, uint32 y) { getNGrid(x,y)->setGridObjectDataLoaded(pLoaded); }
void setNGrid(NGridType* grid, uint32 x, uint32 y);
+ void ScriptsProcess();
void UpdateActiveCells(const float &x, const float &y, const uint32 &t_diff);
protected:
@@ -474,7 +496,6 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
MapEntry const* i_mapEntry;
uint8 i_spawnMode;
- uint32 i_id;
uint32 i_InstanceId;
uint32 m_unloadTimer;
@@ -487,6 +508,10 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
private:
+ //used for fast base_map (e.g. MapInstanced class object) search for
+ //InstanceMaps and BattleGroundMaps...
+ Map* m_parentMap;
+
typedef GridReadGuard ReadGuard;
typedef GridWriteGuard WriteGuard;
@@ -502,6 +527,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
std::vector<Unit*> i_unitsToNotify;
std::set<WorldObject *> i_objectsToRemove;
std::map<WorldObject*, bool> i_objectsToSwitch;
+ std::multimap<time_t, ScriptAction> m_scriptSchedule;
// Type specific code for add/remove to/from grid
template<class T>
@@ -553,7 +579,7 @@ enum InstanceResetMethod
class TRINITY_DLL_SPEC InstanceMap : public Map
{
public:
- InstanceMap(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode);
+ InstanceMap(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode, Map* _parent);
~InstanceMap();
bool Add(Player *);
void Remove(Player *, bool);
@@ -578,14 +604,14 @@ class TRINITY_DLL_SPEC InstanceMap : public Map
class TRINITY_DLL_SPEC BattleGroundMap : public Map
{
public:
- BattleGroundMap(uint32 id, time_t, uint32 InstanceId);
+ BattleGroundMap(uint32 id, time_t, uint32 InstanceId, Map* _parent);
~BattleGroundMap();
bool Add(Player *);
void Remove(Player *, bool);
bool CanEnter(Player* player);
void SetUnload();
- void UnloadAll();
+ void RemoveAllPlayers();
};
/*inline
diff --git a/src/game/MapInstanced.cpp b/src/game/MapInstanced.cpp
index ca106d6506c..e423abbad31 100644
--- a/src/game/MapInstanced.cpp
+++ b/src/game/MapInstanced.cpp
@@ -46,7 +46,10 @@ void MapInstanced::Update(const uint32& t)
{
if(i->second->CanUnload(t))
{
- DestroyInstance(i); // iterator incremented
+ if(!DestroyInstance(i)) // iterator incremented
+ {
+ //m_unloadTimer
+ }
}
else
{
@@ -116,17 +119,8 @@ void MapInstanced::UnloadAll()
- create the instance if it's not created already
- the player is not actually added to the instance (only in InstanceMap::Add)
*/
-Map* MapInstanced::GetInstance(const WorldObject* obj)
+Map* MapInstanced::CreateInstance(const uint32 mapId, Player * player, uint32 instanceId)
{
- if(obj->GetTypeId() == TYPEID_UNIT)
- {
- assert(obj->GetMapId() == GetId() && obj->GetInstanceId());
- return _FindMap(obj->GetInstanceId());
- }
-
- Player* player = (Player*)obj;
- uint32 instanceId = player->GetInstanceId();
-
if(instanceId)
if(Map *map = _FindMap(instanceId))
return map;
@@ -134,28 +128,12 @@ Map* MapInstanced::GetInstance(const WorldObject* obj)
if(IsBattleGroundOrArena())
{
instanceId = player->GetBattleGroundId();
-
if(instanceId)
- {
if(Map *map = _FindMap(instanceId))
return map;
- else
- return CreateBattleGround(instanceId);
- }
- else
- return NULL;
- }
-
- InstancePlayerBind *pBind = player->GetBoundInstance(GetId(), player->GetDifficulty());
- InstanceSave *pSave = pBind ? pBind->save : NULL;
- if(!pBind || !pBind->perm)
- {
- if(Group *group = player->GetGroup())
- if(InstanceGroupBind *groupBind = group->GetBoundInstance(GetId(), player->GetDifficulty()))
- pSave = groupBind->save;
+ return CreateBattleGround(instanceId);
}
-
- if(pSave)
+ else if(InstanceSave *pSave = player->GetInstanceSave(GetId()))
{
if(!instanceId)
{
@@ -202,10 +180,10 @@ InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave *save,
// some instances only have one difficulty
if (entry && !entry->SupportsHeroicMode()) difficulty = DIFFICULTY_NORMAL;
- sLog.outDebug("MapInstanced::CreateInstance: %smap instance %d for %d created with difficulty %s", save?"":"new ", InstanceId, GetId(), difficulty?"heroic":"normal");
+ sLog.outDebug("MapInstanced::CreateInstance: %s map instance %d for %d created with difficulty %s", save?"":"new ", InstanceId, GetId(), difficulty?"heroic":"normal");
- InstanceMap *map = new InstanceMap(GetId(), GetGridExpiry(), InstanceId, difficulty);
- assert(map->IsDungeon());
+ InstanceMap *map = new InstanceMap(GetId(), GetGridExpiry(), InstanceId, difficulty, this);
+ ASSERT(map->IsDungeon());
bool load_data = save != NULL;
map->CreateInstanceData(load_data);
@@ -221,23 +199,23 @@ BattleGroundMap* MapInstanced::CreateBattleGround(uint32 InstanceId)
sLog.outDebug("MapInstanced::CreateBattleGround: map bg %d for %d created.", InstanceId, GetId());
- BattleGroundMap *map = new BattleGroundMap(GetId(), GetGridExpiry(), InstanceId);
- assert(map->IsBattleGroundOrArena());
+ BattleGroundMap *map = new BattleGroundMap(GetId(), GetGridExpiry(), InstanceId, this);
+ ASSERT(map->IsBattleGroundOrArena());
m_InstancedMaps[InstanceId] = map;
return map;
}
-void MapInstanced::DestroyInstance(uint32 InstanceId)
-{
- InstancedMaps::iterator itr = m_InstancedMaps.find(InstanceId);
- if(itr != m_InstancedMaps.end())
- DestroyInstance(itr);
-}
-
// increments the iterator after erase
-void MapInstanced::DestroyInstance(InstancedMaps::iterator &itr)
+bool MapInstanced::DestroyInstance(InstancedMaps::iterator &itr)
{
+ itr->second->RemoveAllPlayers();
+ if(itr->second->HavePlayers())
+ {
+ ++itr;
+ return false;
+ }
+
itr->second->UnloadAll();
// should only unload VMaps if this is the last instance and grid unloading is enabled
if(m_InstancedMaps.size() <= 1 && sWorld.getConfig(CONFIG_GRID_UNLOAD))
@@ -250,13 +228,12 @@ void MapInstanced::DestroyInstance(InstancedMaps::iterator &itr)
// erase map
delete itr->second;
m_InstancedMaps.erase(itr++);
+ return true;
}
bool MapInstanced::CanEnter(Player *player)
{
- if(Map* map = GetInstance(player))
- return map->CanEnter(player);
-
- return false;
+ //assert(false);
+ return true;
}
diff --git a/src/game/MapInstanced.h b/src/game/MapInstanced.h
index 6338726fd47..851fe8942a0 100644
--- a/src/game/MapInstanced.h
+++ b/src/game/MapInstanced.h
@@ -42,10 +42,9 @@ class TRINITY_DLL_DECL MapInstanced : public Map
void UnloadAll();
bool CanEnter(Player* player);
- Map* GetInstance(const WorldObject* obj);
+ Map* CreateInstance(const uint32 mapId, Player * player, uint32 instanceId);
Map* FindMap(uint32 InstanceId) const { return _FindMap(InstanceId); }
- void DestroyInstance(uint32 InstanceId);
- void DestroyInstance(InstancedMaps::iterator &itr);
+ bool DestroyInstance(InstancedMaps::iterator &itr);
void AddGridMapReference(const GridPair &p)
{
diff --git a/src/game/MapManager.cpp b/src/game/MapManager.cpp
index 5fde20c55eb..297bc1a3874 100644
--- a/src/game/MapManager.cpp
+++ b/src/game/MapManager.cpp
@@ -117,10 +117,14 @@ MapManager::_createBaseMap(uint32 id)
{
m = new MapInstanced(id, i_gridCleanUpDelay);
}
- else
+ else if (entry)
{
m = new Map(id, i_gridCleanUpDelay, 0, 0);
}
+ else
+ {
+ assert(false);
+ }
i_maps[id] = m;
}
@@ -128,13 +132,13 @@ MapManager::_createBaseMap(uint32 id)
return m;
}
-Map* MapManager::GetMap(uint32 id, const WorldObject* obj)
+Map* MapManager::CreateMap(uint32 id, const WorldObject* obj, uint32 instanceId)
{
ASSERT(obj);
//if(!obj->IsInWorld()) sLog.outError("GetMap: called for map %d with object (typeid %d, guid %d, mapid %d, instanceid %d) who is not in world!", id, obj->GetTypeId(), obj->GetGUIDLow(), obj->GetMapId(), obj->GetInstanceId());
Map *m = _createBaseMap(id);
- if (m && obj && m->Instanceable()) m = ((MapInstanced*)m)->GetInstance(obj);
+ if (m && (obj->GetTypeId() == TYPEID_PLAYER) && m->Instanceable()) m = ((MapInstanced*)m)->CreateInstance(id, (Player*)obj, instanceId);
return m;
}
@@ -230,13 +234,6 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player)
return true;
}
-void MapManager::DeleteInstance(uint32 mapid, uint32 instanceId)
-{
- Map *m = _createBaseMap(mapid);
- if (m && m->Instanceable())
- ((MapInstanced*)m)->DestroyInstance(instanceId);
-}
-
void MapManager::RemoveBonesFromMap(uint32 mapid, uint64 guid, float x, float y)
{
bool remove_result = _createBaseMap(mapid)->RemoveBones(guid, x, y);
@@ -259,20 +256,19 @@ MapManager::Update(uint32 diff)
MapMapType::iterator iter;
std::vector<Map*> update_queue(i_maps.size());
int omp_set_num_threads(sWorld.getConfig(CONFIG_NUMTHREADS));
- for(iter = i_maps.begin(), i=0;iter != i_maps.end(); ++iter, i++)
- update_queue[i]=iter->second;
+ for(iter = i_maps.begin(), i=0;iter != i_maps.end(); ++iter, i++)
+ update_queue[i]=iter->second;
/*
- gomp in gcc <4.4 version cannot parallelise loops using random access iterators
- so until gcc 4.4 isnt standard, we need the update_queue workaround
+ gomp in gcc <4.4 version cannot parallelise loops using random access iterators
+ so until gcc 4.4 isnt standard, we need the update_queue workaround
*/
#pragma omp parallel for schedule(dynamic) private(i) shared(update_queue)
for(int32 i = 0; i < i_maps.size(); ++i)
{
checkAndCorrectGridStatesArray(); // debugging code, should be deleted some day
- update_queue[i]->Update(i_timer.GetCurrent());
- sWorld.RecordTimeDiff("UpdateMap %u", update_queue[i]->GetId());
- // sLog.outError("This is thread %d out of %d threads,updating map %u",omp_get_thread_num(),omp_get_num_threads(),iter->second->GetId());
-
+ update_queue[i]->Update(i_timer.GetCurrent());
+ sWorld.RecordTimeDiff("UpdateMap %u", update_queue[i]->GetId());
+ // sLog.outError("This is thread %d out of %d threads,updating map %u",omp_get_thread_num(),omp_get_num_threads(),iter->second->GetId());
}
#else
for(MapMapType::iterator iter=i_maps.begin(); iter != i_maps.end(); ++iter)
diff --git a/src/game/MapManager.h b/src/game/MapManager.h
index b07a26ed0f0..118a057c9af 100644
--- a/src/game/MapManager.h
+++ b/src/game/MapManager.h
@@ -39,13 +39,10 @@ class MANGOS_DLL_DECL MapManager : public MaNGOS::Singleton<MapManager, MaNGOS::
public:
- Map* GetMap(uint32, const WorldObject* obj);
+ Map* CreateMap(uint32, const WorldObject* obj, uint32 instanceId);
Map const* CreateBaseMap(uint32 id) const { return const_cast<MapManager*>(this)->_createBaseMap(id); }
Map* FindMap(uint32 mapid, uint32 instanceId = 0) const;
- // only const version for outer users
- void DeleteInstance(uint32 mapid, uint32 instanceId);
-
uint16 GetAreaFlag(uint32 mapid, float x, float y, float z) const
{
Map const* m = CreateBaseMap(mapid);
diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp
index f5a1013f085..48fdda872e9 100644
--- a/src/game/MiscHandler.cpp
+++ b/src/game/MiscHandler.cpp
@@ -231,7 +231,7 @@ void WorldSession::HandleWhoOpcode( WorldPacket & recv_data )
uint32 team = _player->GetTeam();
uint32 security = GetSecurity();
bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST);
- bool gmInWhoList = sWorld.getConfig(CONFIG_GM_IN_WHO_LIST);
+ uint32 gmLevelInWhoList = sWorld.getConfig(CONFIG_GM_LEVEL_IN_WHO_LIST);
WorldPacket data( SMSG_WHO, 50 ); // guess size
data << clientcount; // clientcount place holder
@@ -248,10 +248,14 @@ void WorldSession::HandleWhoOpcode( WorldPacket & recv_data )
continue;
// player can see MODERATOR, GAME MASTER, ADMINISTRATOR only if CONFIG_GM_IN_WHO_LIST
- if ((itr->second->GetSession()->GetSecurity() > SEC_PLAYER && !gmInWhoList))
+ if ((itr->second->GetSession()->GetSecurity() > gmLevelInWhoList))
continue;
}
+ //do not process players which are not in world
+ if(!(itr->second->IsInWorld()))
+ continue;
+
// check if target is globally visible for player
if (!(itr->second->IsVisibleGloballyFor(_player)))
continue;
@@ -1014,10 +1018,11 @@ void WorldSession::HandleRequestAccountData(WorldPacket& recv_data)
uint32 size = adata->Data.size();
+ uLongf destSize = compressBound(size);
+
ByteBuffer dest;
- dest.resize(size);
+ dest.resize(destSize);
- uLongf destSize = size;
if(size && compress(const_cast<uint8*>(dest.contents()), &destSize, (uint8*)adata->Data.c_str(), size) != Z_OK)
{
sLog.outDebug("RAD: Failed to compress account data");
@@ -1040,40 +1045,41 @@ void WorldSession::HandleSetActionButtonOpcode(WorldPacket& recv_data)
CHECK_PACKET_SIZE(recv_data,1+2+1+1);
sLog.outDebug( "WORLD: Received CMSG_SET_ACTION_BUTTON" );
- uint8 button, misc, type;
- uint16 action;
- recv_data >> button >> action >> misc >> type;
- sLog.outDetail( "BUTTON: %u ACTION: %u TYPE: %u MISC: %u", button, action, type, misc );
- if(action==0)
+ uint8 button;
+ uint32 packetData;
+ recv_data >> button >> packetData;
+
+ uint32 action = ACTION_BUTTON_ACTION(packetData);
+ uint8 type = ACTION_BUTTON_TYPE(packetData);
+
+ sLog.outDetail( "BUTTON: %u ACTION: %u TYPE: %u", button, action, type );
+ if (!packetData)
{
sLog.outDetail( "MISC: Remove action from button %u", button );
-
GetPlayer()->removeActionButton(button);
}
else
{
- if(type==ACTION_BUTTON_MACRO || type==ACTION_BUTTON_CMACRO)
- {
- sLog.outDetail( "MISC: Added Macro %u into button %u", action, button );
- GetPlayer()->addActionButton(button,action,type,misc);
- }
- else if(type==ACTION_BUTTON_EQSET)
- {
- sLog.outDetail( "MISC: Added EquipmentSet %u into button %u", action, button );
- GetPlayer()->addActionButton(button,action,type,misc);
- }
- else if(type==ACTION_BUTTON_SPELL)
+ switch(type)
{
- sLog.outDetail( "MISC: Added Spell %u into button %u", action, button );
- GetPlayer()->addActionButton(button,action,type,misc);
- }
- else if(type==ACTION_BUTTON_ITEM)
- {
- sLog.outDetail( "MISC: Added Item %u into button %u", action, button );
- GetPlayer()->addActionButton(button,action,type,misc);
+ case ACTION_BUTTON_MACRO:
+ case ACTION_BUTTON_CMACRO:
+ sLog.outDetail( "MISC: Added Macro %u into button %u", action, button );
+ break;
+ case ACTION_BUTTON_EQSET:
+ sLog.outDetail( "MISC: Added EquipmentSet %u into button %u", action, button );
+ break;
+ case ACTION_BUTTON_SPELL:
+ sLog.outDetail( "MISC: Added Spell %u into button %u", action, button );
+ break;
+ case ACTION_BUTTON_ITEM:
+ sLog.outDetail( "MISC: Added Item %u into button %u", action, button );
+ break;
+ default:
+ sLog.outError( "MISC: Unknown action button type %u for action %u into button %u", type, action, button );
+ return;
}
- else
- sLog.outError( "MISC: Unknown action button type %u for action %u into button %u", type, action, button );
+ GetPlayer()->addActionButton(button,action,type);
}
}
@@ -1210,15 +1216,17 @@ void WorldSession::HandleWardenDataOpcode(WorldPacket& /*recv_data*/)
*/
}
-void WorldSession::HandlePlayedTime(WorldPacket& /*recv_data*/)
+void WorldSession::HandlePlayedTime(WorldPacket& recv_data)
{
- uint32 TotalTimePlayed = GetPlayer()->GetTotalPlayedTime();
- uint32 LevelPlayedTime = GetPlayer()->GetLevelPlayedTime();
+ CHECK_PACKET_SIZE(recv_data, 1);
- WorldPacket data(SMSG_PLAYED_TIME, 9);
- data << TotalTimePlayed;
- data << LevelPlayedTime;
- data << uint8(0);
+ uint8 unk1;
+ recv_data >> unk1; // 0 or 1 expected
+
+ WorldPacket data(SMSG_PLAYED_TIME, 4 + 4 + 1);
+ data << uint32(_player->GetTotalPlayedTime());
+ data << uint32(_player->GetLevelPlayedTime());
+ data << uint8(unk1); // 0 - will not show in chat frame
SendPacket(&data);
}
@@ -1350,7 +1358,7 @@ void WorldSession::HandleWhoisOpcode(WorldPacket& recv_data)
uint32 accid = plr->GetSession()->GetAccountId();
- QueryResult *result = LoginDatabase.PQuery("SELECT username,email,last_ip FROM account WHERE id=%u", accid);
+ QueryResult *result = loginDatabase.PQuery("SELECT username,email,last_ip FROM account WHERE id=%u", accid);
if(!result)
{
SendNotification(LANG_ACCOUNT_FOR_PLAYER_NOT_FOUND, charname.c_str());
@@ -1488,7 +1496,7 @@ void WorldSession::HandleSetTitleOpcode( WorldPacket & recv_data )
recv_data >> title;
// -1 at none
- if(title > 0 && title < 192)
+ if(title > 0 && title < MAX_TITLE_INDEX)
{
if(!GetPlayer()->HasTitle(title))
return;
diff --git a/src/game/MovementHandler.cpp b/src/game/MovementHandler.cpp
index 7d7733763cd..f0ff9ec05d7 100644
--- a/src/game/MovementHandler.cpp
+++ b/src/game/MovementHandler.cpp
@@ -66,27 +66,30 @@ void WorldSession::HandleMoveWorldportAckOpcode()
GetPlayer()->SetSemaphoreTeleportFar(false);
+ Map * oldMap = GetPlayer()->GetMap();
// relocate the player to the teleport destination
- GetPlayer()->SetMapId(loc.mapid);
- GetPlayer()->Relocate(loc.coord_x, loc.coord_y, loc.coord_z, loc.orientation);
+ Map * newMap = MapManager::Instance().CreateMap(loc.mapid, GetPlayer(), 0);
+ // the CanEnter checks are done in TeleporTo but conditions may change
+ // while the player is in transit, for example the map may get full
+ if (!newMap || !newMap->CanEnter(GetPlayer()))
+ {
+ sLog.outError("Map %d could not be created for player %d, porting player to homebind", loc.mapid, GetPlayer()->GetGUIDLow());
+ GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation());
+ return;
+ }
+ else
+ GetPlayer()->Relocate(loc.coord_x, loc.coord_y, loc.coord_z, loc.orientation);
- // since the MapId is set before the GetInstance call, the InstanceId must be set to 0
- // to let GetInstance() determine the proper InstanceId based on the player's binds
- GetPlayer()->SetInstanceId(0);
+ GetPlayer()->ResetMap();
+ GetPlayer()->SetMap(newMap);
GetPlayer()->SendInitialPacketsBeforeAddToMap();
- // the CanEnter checks are done in TeleporTo but conditions may change
- // while the player is in transit, for example the map may get full
if(!GetPlayer()->GetMap()->Add(GetPlayer()))
{
- sLog.outDebug("WORLD: teleport of player %s (%d) to location %d, %f, %f, %f, %f failed", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow(), loc.mapid, loc.coord_x, loc.coord_y, loc.coord_z, loc.orientation);
- // teleport the player home
- if(!GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation()))
- {
- // the player must always be able to teleport home
- sLog.outError("WORLD: failed to teleport player %s (%d) to homebind location %d, %f, %f, %f, %f!", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow(), GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation());
- assert(false);
- }
+ sLog.outError("WORLD: failed to teleport player %s (%d) to map %d because of unknown reason!", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow(), loc.mapid);
+ GetPlayer()->ResetMap();
+ GetPlayer()->SetMap(oldMap);
+ GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation());
return;
}
@@ -156,11 +159,14 @@ void WorldSession::HandleMoveWorldportAckOpcode()
// resummon pet
GetPlayer()->ResummonPetTemporaryUnSummonedIfAny();
+
+ //lets process all delayed operations on successful teleport
+ GetPlayer()->ProcessDelayedOperations();
}
void WorldSession::HandleMoveTeleportAck(WorldPacket& recv_data)
{
- CHECK_PACKET_SIZE(recv_data, 8+4);
+ CHECK_PACKET_SIZE(recv_data, 8+4+4);
sLog.outDebug("MSG_MOVE_TELEPORT_ACK");
uint64 guid;
@@ -202,6 +208,9 @@ void WorldSession::HandleMoveTeleportAck(WorldPacket& recv_data)
// resummon pet
GetPlayer()->ResummonPetTemporaryUnSummonedIfAny();
+
+ //lets process all delayed operations on successful teleport
+ GetPlayer()->ProcessDelayedOperations();
}
void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data )
@@ -223,7 +232,7 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data )
if(recv_data.size() != recv_data.rpos())
{
- sLog.outError("MovementHandler: player %s (guid %d, account %u) sent a packet (opcode %u) that is %u bytes larger than it should be. Kicked as cheater.", _player->GetName(), _player->GetGUIDLow(), _player->GetSession()->GetAccountId(), recv_data.GetOpcode(), recv_data.size() - recv_data.rpos());
+ sLog.outError("MovementHandler: player %s (guid %d, account %u) sent a packet (opcode %u) that is " SIZEFMTD " bytes larger than it should be. Kicked as cheater.", _player->GetName(), _player->GetGUIDLow(), _player->GetSession()->GetAccountId(), recv_data.GetOpcode(), recv_data.size() - recv_data.rpos());
KickPlayer();
return;
}
@@ -294,6 +303,12 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data )
mover->m_movementInfo = movementInfo;
+ if(mover->m_Vehicle)
+ {
+ mover->SetOrientation(movementInfo.o);
+ return;
+ }
+
if(plMover) // nothing is charmed, or player charmed
{
plMover->SetPosition(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o);
@@ -332,9 +347,6 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data )
}
else // creature charmed
{
- uint32 entry = mover->GetEntry();
- if(mover->m_Vehicle)
- return;
mover->GetMap()->CreatureRelocation((Creature*)mover, movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o);
/*if(mover->canFly())
diff --git a/src/game/NPCHandler.cpp b/src/game/NPCHandler.cpp
index c60d368659a..bb9823ee71f 100644
--- a/src/game/NPCHandler.cpp
+++ b/src/game/NPCHandler.cpp
@@ -422,7 +422,7 @@ void WorldSession::HandleBinderActivateOpcode( WorldPacket & recv_data )
uint64 npcGUID;
recv_data >> npcGUID;
- if(!GetPlayer()->isAlive())
+ if(!GetPlayer()->IsInWorld() || !GetPlayer()->isAlive())
return;
Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID,UNIT_NPC_FLAG_INNKEEPER);
@@ -442,7 +442,7 @@ void WorldSession::HandleBinderActivateOpcode( WorldPacket & recv_data )
void WorldSession::SendBindPoint(Creature *npc)
{
// prevent set homebind to instances in any case
- if(sMapStore.LookupEntry(GetPlayer()->GetMapId())->Instanceable())
+ if(GetPlayer()->GetMap()->Instanceable())
return;
uint32 bindspell = 3286;
diff --git a/src/game/Object.cpp b/src/game/Object.cpp
index 3561621f0bd..69a286289b3 100644
--- a/src/game/Object.cpp
+++ b/src/game/Object.cpp
@@ -259,13 +259,13 @@ void Object::BuildOutOfRangeUpdateBlock(UpdateData * data) const
data->AddOutOfRangeGUID(GetGUID());
}
-void Object::DestroyForPlayer(Player *target) const
+void Object::DestroyForPlayer( Player *target, bool anim ) const
{
ASSERT(target);
WorldPacket data(SMSG_DESTROY_OBJECT, 8);
data << uint64(GetGUID());
- data << uint8(0); // WotLK (bool)
+ data << uint8(anim ? 1 : 0); // WotLK (bool), may be despawn animation
target->GetSession()->SendPacket( &data );
}
@@ -477,6 +477,13 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask
if (((GameObject*)this)->GetGoArtKit())
updateMask->SetBit(GAMEOBJECT_BYTES_1);
}
+ else if (isType(TYPEMASK_UNIT))
+ {
+ if( ((Unit*)this)->HasFlag(UNIT_FIELD_AURASTATE, PER_CASTER_AURA_STATE_MASK))
+ {
+ updateMask->SetBit(UNIT_FIELD_AURASTATE);
+ }
+ }
}
else // case UPDATETYPE_VALUES
{
@@ -489,6 +496,13 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask
updateMask->SetBit(GAMEOBJECT_DYNAMIC);
updateMask->SetBit(GAMEOBJECT_BYTES_1);
}
+ else if (isType(TYPEMASK_UNIT))
+ {
+ if( ((Unit*)this)->HasFlag(UNIT_FIELD_AURASTATE, PER_CASTER_AURA_STATE_MASK))
+ {
+ updateMask->SetBit(UNIT_FIELD_AURASTATE);
+ }
+ }
}
WPAssert(updateMask && updateMask->GetCount() == m_valuesCount);
@@ -513,6 +527,11 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask
*data << uint32(appendValue);
}
+ else if (index == UNIT_FIELD_AURASTATE)
+ {
+ // Check per caster aura states to not enable using a pell in client if specified aura is not by target
+ *data << ((Unit*)this)->BuildAuraStateUpdateForTarget(target);
+ }
// FIXME: Some values at server stored in float format but must be sent to client in uint32 format
else if(index >= UNIT_FIELD_BASEATTACKTIME && index <= UNIT_FIELD_RANGEDATTACKTIME)
{
@@ -730,7 +749,7 @@ void Object::_SetCreateBits(UpdateMask *updateMask, Player* /*target*/) const
void Object::SetInt32Value( uint16 index, int32 value )
{
- ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
+ ASSERT( index < m_valuesCount || PrintIndexError( index, true ) );
if(m_int32Values[ index ] != value)
{
@@ -749,7 +768,7 @@ void Object::SetInt32Value( uint16 index, int32 value )
void Object::SetUInt32Value( uint16 index, uint32 value )
{
- ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
+ ASSERT( index < m_valuesCount || PrintIndexError( index, true ) );
if(m_uint32Values[ index ] != value)
{
@@ -768,7 +787,7 @@ void Object::SetUInt32Value( uint16 index, uint32 value )
void Object::SetUInt64Value( uint16 index, const uint64 &value )
{
- ASSERT( index + 1 < m_valuesCount || PrintIndexError( index , true ) );
+ ASSERT( index + 1 < m_valuesCount || PrintIndexError( index, true ) );
if(*((uint64*)&(m_uint32Values[ index ])) != value)
{
m_uint32Values[ index ] = *((uint32*)&value);
@@ -829,7 +848,7 @@ bool Object::RemoveUInt64Value(uint16 index, const uint64 &value)
void Object::SetFloatValue( uint16 index, float value )
{
- ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
+ ASSERT( index < m_valuesCount || PrintIndexError( index, true ) );
if(m_floatValues[ index ] != value)
{
@@ -848,7 +867,7 @@ void Object::SetFloatValue( uint16 index, float value )
void Object::SetByteValue( uint16 index, uint8 offset, uint8 value )
{
- ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
+ ASSERT( index < m_valuesCount || PrintIndexError( index, true ) );
if(offset > 4)
{
@@ -874,7 +893,7 @@ void Object::SetByteValue( uint16 index, uint8 offset, uint8 value )
void Object::SetUInt16Value( uint16 index, uint8 offset, uint16 value )
{
- ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
+ ASSERT( index < m_valuesCount || PrintIndexError( index, true ) );
if(offset > 2)
{
@@ -948,7 +967,7 @@ void Object::ApplyModPositiveFloatValue(uint16 index, float val, bool apply)
void Object::SetFlag( uint16 index, uint32 newFlag )
{
- ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
+ ASSERT( index < m_valuesCount || PrintIndexError( index, true ) );
uint32 oldval = m_uint32Values[ index ];
uint32 newval = oldval | newFlag;
@@ -969,7 +988,7 @@ void Object::SetFlag( uint16 index, uint32 newFlag )
void Object::RemoveFlag( uint16 index, uint32 oldFlag )
{
- ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
+ ASSERT( index < m_valuesCount || PrintIndexError( index, true ) );
uint32 oldval = m_uint32Values[ index ];
uint32 newval = oldval & ~oldFlag;
@@ -990,7 +1009,7 @@ void Object::RemoveFlag( uint16 index, uint32 oldFlag )
void Object::SetByteFlag( uint16 index, uint8 offset, uint8 newFlag )
{
- ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
+ ASSERT( index < m_valuesCount || PrintIndexError( index, true ) );
if(offset > 4)
{
@@ -1015,7 +1034,7 @@ void Object::SetByteFlag( uint16 index, uint8 offset, uint8 newFlag )
void Object::RemoveByteFlag( uint16 index, uint8 offset, uint8 oldFlag )
{
- ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
+ ASSERT( index < m_valuesCount || PrintIndexError( index, true ) );
if(offset > 4)
{
@@ -1047,9 +1066,9 @@ bool Object::PrintIndexError(uint32 index, bool set) const
}
WorldObject::WorldObject()
- : m_mapId(0), m_InstanceId(0), m_phaseMask(PHASEMASK_NORMAL),
- m_positionX(0.0f), m_positionY(0.0f), m_positionZ(0.0f), m_orientation(0.0f)
- , m_map(NULL), m_zoneScript(NULL)
+ : m_phaseMask(PHASEMASK_NORMAL),
+ m_positionX(0.0f), m_positionY(0.0f), m_positionZ(0.0f), m_orientation(0.0f), m_currMap(NULL)
+ , m_zoneScript(NULL)
, m_isActive(false), IsTempWorldObject(false)
, m_name("")
{
@@ -1096,11 +1115,13 @@ void WorldObject::setActive( bool on )
}
}
-void WorldObject::_Create( uint32 guidlow, HighGuid guidhigh, uint32 mapid, uint32 phaseMask )
+void WorldObject::CleanupsBeforeDelete()
{
- Object::_Create(guidlow, 0, guidhigh);
+}
- m_mapId = mapid;
+void WorldObject::_Create( uint32 guidlow, HighGuid guidhigh, uint32 phaseMask )
+{
+ Object::_Create(guidlow, 0, guidhigh);
m_phaseMask = phaseMask;
}
@@ -1430,7 +1451,7 @@ bool WorldObject::IsInBetween(const WorldObject *obj1, const WorldObject *obj2,
void WorldObject::GetRandomPoint( float x, float y, float z, float distance, float &rand_x, float &rand_y, float &rand_z) const
{
- if(distance==0)
+ if(distance == 0)
{
rand_x = x;
rand_y = y;
@@ -1621,8 +1642,6 @@ void WorldObject::MonsterWhisper(int32 textId, uint64 receiver, bool IsBossWhisp
void WorldObject::BuildMonsterChat(WorldPacket *data, uint8 msgtype, char const* text, uint32 language, char const* name, uint64 targetGuid) const
{
- bool pre = (msgtype==CHAT_MSG_MONSTER_EMOTE || msgtype==CHAT_MSG_RAID_BOSS_EMOTE);
-
*data << (uint8)msgtype;
*data << (uint32)language;
*data << (uint64)GetGUID();
@@ -1635,9 +1654,7 @@ void WorldObject::BuildMonsterChat(WorldPacket *data, uint8 msgtype, char const*
*data << (uint32)1; // target name length
*data << (uint8)0; // target name
}
- *data << (uint32)(strlen(text)+1+(pre?3:0));
- if(pre)
- data->append("%s ",3);
+ *data << (uint32)(strlen(text)+1);
*data << text;
*data << (uint8)0; // ChatTag
}
@@ -1668,23 +1685,20 @@ void WorldObject::SendMessageToSetInRange(WorldPacket *data, float dist, bool /*
void WorldObject::SendObjectDeSpawnAnim(uint64 guid)
{
WorldPacket data(SMSG_GAMEOBJECT_DESPAWN_ANIM, 8);
- data << guid;
+ data << uint64(guid);
SendMessageToSet(&data, true);
}
-Map* WorldObject::_getMap()
-{
- return m_map = MapManager::Instance().GetMap(GetMapId(), this);
-}
-
-Map* WorldObject::_findMap()
+void WorldObject::SetMap(Map * map)
{
- return m_map = MapManager::Instance().FindMap(GetMapId(), GetInstanceId());
+ ASSERT(map);
+ m_currMap = map;
}
Map const* WorldObject::GetBaseMap() const
{
- return MapManager::Instance().CreateBaseMap(GetMapId());
+ ASSERT(m_currMap);
+ return m_currMap->GetParent();
}
void WorldObject::AddObjectToRemoveList()
@@ -1720,6 +1734,8 @@ TempSummon *Map::SummonCreature(uint32 entry, float x, float y, float z, float a
mask = SUMMON_MASK_PUPPET;
else if(properties->Type == SUMMON_TYPE_MINIPET)
mask = SUMMON_MASK_MINION;
+ else if (properties->Flags & 512) // Mirror Image, Summon Gargoyle
+ mask = SUMMON_MASK_GUARDIAN;
}
uint32 phase = PHASEMASK_NORMAL, team = 0;
@@ -1992,6 +2008,36 @@ GameObject* WorldObject::FindNearestGameObject(uint32 entry, float range)
return go;
}
+void WorldObject::GetGameObjectListWithEntryInGrid(std::list<GameObject*>& lList, uint32 uiEntry, float fMaxSearchRange)
+{
+ CellPair pair(Trinity::ComputeCellPair(this->GetPositionX(), this->GetPositionY()));
+ Cell cell(pair);
+ cell.data.Part.reserved = ALL_DISTRICT;
+ cell.SetNoCreate();
+
+ Trinity::AllGameObjectsWithEntryInRange check(this, uiEntry, fMaxSearchRange);
+ Trinity::GameObjectListSearcher<Trinity::AllGameObjectsWithEntryInRange> searcher(this, lList, check);
+ TypeContainerVisitor<Trinity::GameObjectListSearcher<Trinity::AllGameObjectsWithEntryInRange>, GridTypeMapContainer> visitor(searcher);
+
+ CellLock<GridReadGuard> cell_lock(cell, pair);
+ cell_lock->Visit(cell_lock, visitor, *(this->GetMap()));
+}
+
+void WorldObject::GetCreatureListWithEntryInGrid(std::list<Creature*>& lList, uint32 uiEntry, float fMaxSearchRange)
+{
+ CellPair pair(Trinity::ComputeCellPair(this->GetPositionX(), this->GetPositionY()));
+ Cell cell(pair);
+ cell.data.Part.reserved = ALL_DISTRICT;
+ cell.SetNoCreate();
+
+ Trinity::AllCreaturesOfEntryInRange check(this, uiEntry, fMaxSearchRange);
+ Trinity::CreatureListSearcher<Trinity::AllCreaturesOfEntryInRange> searcher(this, lList, check);
+ TypeContainerVisitor<Trinity::CreatureListSearcher<Trinity::AllCreaturesOfEntryInRange>, GridTypeMapContainer> visitor(searcher);
+
+ CellLock<GridReadGuard> cell_lock(cell, pair);
+ cell_lock->Visit(cell_lock, visitor, *(this->GetMap()));
+}
+
/*
namespace MaNGOS
{
diff --git a/src/game/Object.h b/src/game/Object.h
index 8e86ff1c87b..c44dd4fd65c 100644
--- a/src/game/Object.h
+++ b/src/game/Object.h
@@ -160,7 +160,7 @@ class TRINITY_DLL_SPEC Object
uint32 GetEntry() const { return GetUInt32Value(OBJECT_FIELD_ENTRY); }
void SetEntry(uint32 entry) { SetUInt32Value(OBJECT_FIELD_ENTRY, entry); }
- uint8 GetTypeId() const { return m_objectTypeId; }
+ TypeID GetTypeId() const { return m_objectTypeId; }
bool isType(uint16 mask) const { return (mask & m_objectType); }
virtual void BuildCreateUpdateBlockForPlayer( UpdateData *data, Player *target ) const;
@@ -171,7 +171,7 @@ class TRINITY_DLL_SPEC Object
void BuildMovementUpdateBlock( UpdateData * data, uint32 flags = 0 ) const;
void BuildUpdate(UpdateDataMapType &);
- virtual void DestroyForPlayer( Player *target ) const;
+ virtual void DestroyForPlayer( Player *target, bool anim = false ) const;
const int32& GetInt32Value( uint16 index ) const
{
@@ -337,7 +337,7 @@ class TRINITY_DLL_SPEC Object
uint16 m_objectType;
- uint8 m_objectTypeId;
+ TypeID m_objectTypeId;
uint16 m_updateFlag;
union
@@ -371,7 +371,7 @@ class TRINITY_DLL_SPEC WorldObject : public Object
virtual void Update ( uint32 /*time_diff*/ ) { }
- void _Create( uint32 guidlow, HighGuid guidhigh, uint32 mapid, uint32 phaseMask);
+ void _Create( uint32 guidlow, HighGuid guidhigh, uint32 phaseMask);
void Relocate(WorldObject *obj)
{
@@ -407,7 +407,7 @@ class TRINITY_DLL_SPEC WorldObject : public Object
void GetPosition( float &x, float &y, float &z ) const
{ x = m_positionX; y = m_positionY; z = m_positionZ; }
void GetPosition( WorldLocation &loc ) const
- { loc.mapid = m_mapId; GetPosition(loc.coord_x, loc.coord_y, loc.coord_z); loc.orientation = GetOrientation(); }
+ { loc.mapid = GetMapId(); GetPosition(loc.coord_x, loc.coord_y, loc.coord_z); loc.orientation = GetOrientation(); }
void GetPosition(Position pos) const
{ pos[0] = m_positionX; pos[1] = m_positionY; pos[2] = m_positionZ; pos[3] = m_orientation; }
float GetOrientation( ) const { return m_orientation; }
@@ -439,10 +439,8 @@ class TRINITY_DLL_SPEC WorldObject : public Object
void GetRandomPoint( float x, float y, float z, float distance, float &rand_x, float &rand_y, float &rand_z ) const;
- void SetMapId(uint32 newMap) { m_mapId = newMap; m_map = NULL; }
- uint32 GetMapId() const { return m_mapId; }
- void SetInstanceId(uint32 val) { m_InstanceId = val; m_map = NULL; }
- uint32 GetInstanceId() const { return m_InstanceId; }
+ virtual uint32 GetMapId() const { return m_currMap ? m_currMap->GetId() : 0; }
+ virtual uint32 GetInstanceId() const { return m_currMap ? m_currMap->GetInstanceId() : 0; }
virtual void SetPhaseMask(uint32 newPhaseMask, bool update);
uint32 GetPhaseMask() const { return m_phaseMask; }
@@ -470,8 +468,7 @@ class TRINITY_DLL_SPEC WorldObject : public Object
float GetDistanceZ(const WorldObject* obj) const;
bool IsInMap(const WorldObject* obj) const
{
- return IsInWorld() && obj->IsInWorld() && GetMapId()==obj->GetMapId() &&
- GetInstanceId()==obj->GetInstanceId() && InSamePhase(obj);
+ return IsInWorld() && obj->IsInWorld() && (GetMap() == obj->GetMap()) && InSamePhase(obj);
}
bool IsWithinDist3d(float x, float y, float z, float dist2compare) const;
bool IsWithinDist2d(float x, float y, float dist2compare) const;
@@ -498,6 +495,8 @@ class TRINITY_DLL_SPEC WorldObject : public Object
bool HasInArc( const float arcangle, const WorldObject* obj ) const;
bool IsInBetween(const WorldObject *obj1, const WorldObject *obj2, float size = 0) const;
+ virtual void CleanupsBeforeDelete(); // used in destructor or explicitly before mass creature delete to remove cross-references to already deleted units
+
virtual void SendMessageToSet(WorldPacket *data, bool self);
virtual void SendMessageToSetInRange(WorldPacket *data, float dist, bool self);
@@ -518,7 +517,6 @@ class TRINITY_DLL_SPEC WorldObject : public Object
void SendObjectDeSpawnAnim(uint64 guid);
virtual void SaveRespawnTime() {}
-
void AddObjectToRemoveList();
// main visibility check function in normal case (ignore grey zone distance check)
@@ -530,8 +528,13 @@ class TRINITY_DLL_SPEC WorldObject : public Object
// Low Level Packets
void SendPlaySound(uint32 Sound, bool OnlySelf);
- Map * GetMap() const { return m_map ? m_map : const_cast<WorldObject*>(this)->_getMap(); }
- Map * FindMap() const { return m_map ? m_map : const_cast<WorldObject*>(this)->_findMap(); }
+ virtual void SetMap(Map * map);
+ Map * GetMap() const { ASSERT(m_currMap); return m_currMap; }
+ Map * FindMap() const { return m_currMap; }
+ //used to check all object's GetMap() calls when object is not in world!
+ virtual void ResetMap() { assert(m_currMap); m_currMap = NULL; }
+
+ //this function should be removed in nearest time...
Map const* GetBaseMap() const;
void SetZoneScript();
@@ -545,6 +548,9 @@ class TRINITY_DLL_SPEC WorldObject : public Object
Creature* FindNearestCreature(uint32 entry, float range, bool alive = true);
GameObject* FindNearestGameObject(uint32 entry, float range);
+ void GetGameObjectListWithEntryInGrid(std::list<GameObject*>& lList, uint32 uiEntry, float fMaxSearchRange);
+ void GetCreatureListWithEntryInGrid(std::list<Creature*>& lList, uint32 uiEntry, float fMaxSearchRange);
+
bool isActiveObject() const { return m_isActive; }
void setActive(bool isActiveObject);
void SetWorldObject(bool apply);
@@ -555,10 +561,10 @@ class TRINITY_DLL_SPEC WorldObject : public Object
#ifdef MAP_BASED_RAND_GEN
int32 irand(int32 min, int32 max) const { return int32 (GetMap()->mtRand.randInt(max - min)) + min; }
- uint32 urand(uint32 min, uint32 max) const { return GetMap()->mtRand.randInt(max - min) + min; }
- int32 rand32() const { return GetMap()->mtRand.randInt(); }
- double rand_norm() const { return GetMap()->mtRand.randExc(); }
- double rand_chance() const { return GetMap()->mtRand.randExc(100.0); }
+ uint32 urand(uint32 min, uint32 max) const { return GetMap()->mtRand.randInt(max - min) + min;}
+ int32 rand32() const { return GetMap()->mtRand.randInt();}
+ double rand_norm() const { return GetMap()->mtRand.randExc();}
+ double rand_chance() const { return GetMap()->mtRand.randExc(100.0);}
#endif
protected:
@@ -568,13 +574,8 @@ class TRINITY_DLL_SPEC WorldObject : public Object
ZoneScript *m_zoneScript;
private:
- uint32 m_mapId; // object at map with map_id
- uint32 m_InstanceId; // in map copy with instance id
+ Map * m_currMap; //current object's Map location
uint32 m_phaseMask; // in area phase state
- Map *m_map;
-
- Map* _getMap();
- Map* _findMap();
float m_positionX;
float m_positionY;
diff --git a/src/game/ObjectAccessor.cpp b/src/game/ObjectAccessor.cpp
index b420e4af4b2..43d3d0a1534 100644
--- a/src/game/ObjectAccessor.cpp
+++ b/src/game/ObjectAccessor.cpp
@@ -46,7 +46,11 @@ INSTANTIATE_SINGLETON_2(ObjectAccessor, CLASS_LOCK);
INSTANTIATE_CLASS_MUTEX(ObjectAccessor, ACE_Thread_Mutex);
ObjectAccessor::ObjectAccessor() {}
-ObjectAccessor::~ObjectAccessor() {}
+ObjectAccessor::~ObjectAccessor()
+{
+ for(Player2CorpsesMapType::const_iterator itr = i_player2corpse.begin(); itr != i_player2corpse.end(); ++itr)
+ delete itr->second;
+}
Creature*
ObjectAccessor::GetCreatureOrPetOrVehicle(WorldObject const &u, uint64 guid)
@@ -60,7 +64,7 @@ ObjectAccessor::GetCreatureOrPetOrVehicle(WorldObject const &u, uint64 guid)
if(IS_VEHICLE_GUID(guid))
return GetVehicle(guid);
- return u.GetMap()->GetCreature(guid);
+ return u.IsInWorld() ? u.GetMap()->GetCreature(guid) : NULL;
}
/*
@@ -135,7 +139,11 @@ Object* ObjectAccessor::GetObjectByTypeMask(WorldObject const &p, uint64 guid, u
Player*
ObjectAccessor::FindPlayer(uint64 guid)
{
- return GetObjectInWorld(guid, (Player*)NULL);
+ Player * plr = GetObjectInWorld(guid, (Player*)NULL);
+ if(!plr || !plr->IsInWorld())
+ return NULL;
+
+ return plr;
}
Player*
@@ -145,7 +153,7 @@ ObjectAccessor::FindPlayerByName(const char *name)
HashMapHolder<Player>::MapType& m = HashMapHolder<Player>::GetContainer();
HashMapHolder<Player>::MapType::iterator iter = m.begin();
for(; iter != m.end(); ++iter)
- if( ::strcmp(name, iter->second->GetName()) == 0 )
+ if(iter->second->IsInWorld() && ( ::strcmp(name, iter->second->GetName()) == 0 ))
return iter->second;
return NULL;
}
@@ -346,8 +354,6 @@ ObjectAccessor::ConvertCorpseForPlayer(uint64 player_guid, bool insignia)
// bones->m_inWorld = m_inWorld; // don't overwrite world state
// bones->m_type = m_type; // don't overwrite type
bones->Relocate(corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetOrientation());
- bones->SetMapId(corpse->GetMapId());
- bones->SetInstanceId(corpse->GetInstanceId());
bones->SetPhaseMask(corpse->GetPhaseMask(), false);
bones->SetUInt32Value(CORPSE_FIELD_FLAGS, CORPSE_FLAG_UNK2 | CORPSE_FLAG_BONES);
diff --git a/src/game/ObjectAccessor.h b/src/game/ObjectAccessor.h
index 80aac0bcf92..1941ccea30c 100644
--- a/src/game/ObjectAccessor.h
+++ b/src/game/ObjectAccessor.h
@@ -103,8 +103,14 @@ class MANGOS_DLL_DECL ObjectAccessor : public MaNGOS::Singleton<ObjectAccessor,
if(!guid)
return NULL;
- if(IS_PLAYER_GUID(guid))
- return (Unit*)HashMapHolder<Player>::Find(guid);
+ if (IS_PLAYER_GUID(guid))
+ {
+ Unit * u = (Unit*)HashMapHolder<Player>::Find(guid);
+ if(!u || !u->IsInWorld())
+ return NULL;
+
+ return u;
+ }
if(IS_CREATURE_GUID(guid))
return (Unit*)HashMapHolder<Creature>::Find(guid);
@@ -115,6 +121,24 @@ class MANGOS_DLL_DECL ObjectAccessor : public MaNGOS::Singleton<ObjectAccessor,
return (Unit*)HashMapHolder<Vehicle>::Find(guid);
}
+ static Unit* GetUnitInOrOutOfWorld(uint64 guid, Unit* /*fake*/)
+ {
+ if(!guid)
+ return NULL;
+
+ if (IS_PLAYER_GUID(guid))
+ {
+ Unit * u = (Unit*)HashMapHolder<Player>::Find(guid);
+ if(!u)
+ return NULL;
+
+ return u;
+ }
+ // Other object types than player are unloaded while out of world
+ return GetObjectInWorld(guid, ((Unit*)NULL));
+ }
+
+
template<class T> static T* GetObjectInWorld(uint32 mapid, float x, float y, uint64 guid, T* /*fake*/)
{
T* obj = HashMapHolder<T>::Find(guid);
@@ -144,6 +168,7 @@ class MANGOS_DLL_DECL ObjectAccessor : public MaNGOS::Singleton<ObjectAccessor,
static Object* GetObjectByTypeMask(WorldObject const &, uint64, uint32 typemask);
static Creature* GetCreatureOrPetOrVehicle(WorldObject const &, uint64);
static Unit* GetUnit(WorldObject const &, uint64 guid) { return GetObjectInWorld(guid, (Unit*)NULL); }
+ static Unit* GetUnitInOrOutOfWorld(WorldObject const &, uint64 guid) { return GetUnitInOrOutOfWorld(guid, (Unit*)NULL); }
static Pet* GetPet(Unit const &, uint64 guid) { return GetPet(guid); }
static Player* GetPlayer(Unit const &, uint64 guid) { return FindPlayer(guid); }
static Corpse* GetCorpse(WorldObject const &u, uint64 guid);
@@ -204,7 +229,7 @@ class MANGOS_DLL_DECL ObjectAccessor : public MaNGOS::Singleton<ObjectAccessor,
Corpse* GetCorpseForPlayerGUID(uint64 guid);
void RemoveCorpse(Corpse *corpse);
- void AddCorpse(Corpse* corpse);
+ void AddCorpse(Corpse *corpse);
void AddCorpsesToGrid(GridPair const& gridpair,GridType& grid,Map* map);
Corpse* ConvertCorpseForPlayer(uint64 player_guid, bool insignia = false);
diff --git a/src/game/ObjectGridLoader.cpp b/src/game/ObjectGridLoader.cpp
index 368edce0a53..d08e3010a78 100644
--- a/src/game/ObjectGridLoader.cpp
+++ b/src/game/ObjectGridLoader.cpp
@@ -126,6 +126,7 @@ void LoadHelper(CellGuidSet const& guid_set, CellPair &cell, GridRefManager<T> &
obj->GetGridRef().link(&m, obj);
addUnitState(obj,cell);
+ obj->SetMap(map);
obj->AddToWorld();
if(obj->isActiveObject())
map->AddToActive(obj);
@@ -184,6 +185,7 @@ void LoadHelper(CellCorpseSet const& cell_corpses, CellPair &cell, CorpseMapType
obj->GetGridRef().link(&m, obj);
addUnitState(obj,cell);
+ obj->SetMap(map);
obj->AddToWorld();
if(obj->isActiveObject())
map->AddToActive(obj);
diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp
index cbf445ebc6b..ec300715f86 100644
--- a/src/game/ObjectMgr.cpp
+++ b/src/game/ObjectMgr.cpp
@@ -178,6 +178,9 @@ ObjectMgr::~ObjectMgr()
for (CachePlayerInfoMap::iterator itr = m_mPlayerInfoMap.begin(); itr != m_mPlayerInfoMap.end(); ++itr)
delete itr->second;
+ for (ArenaTeamMap::iterator itr = mArenaTeamMap.begin(); itr != mArenaTeamMap.end(); ++itr)
+ delete itr->second;
+
for (CacheVendorItemMap::iterator itr = m_mCacheVendorItemMap.begin(); itr != m_mCacheVendorItemMap.end(); ++itr)
itr->second.Clear();
@@ -635,7 +638,7 @@ void ObjectMgr::LoadCreatureTemplates()
// used later for scale
CreatureDisplayInfoEntry const* displayScaleEntry = NULL;
-
+
if (cInfo->DisplayID_A[0])
{
CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->DisplayID_A[0]);
@@ -703,6 +706,18 @@ void ObjectMgr::LoadCreatureTemplates()
if (!displayScaleEntry)
sLog.outErrorDb("Creature (Entry: %u) not has any existed display id in DisplayID_A/DisplayID_A2/DisplayID_H/DisplayID_H2", cInfo->Entry);
+ for(int k = 0; k < MAX_KILL_CREDIT; ++k)
+ {
+ if(cInfo->KillCredit[k])
+ {
+ if(!GetCreatureTemplate(cInfo->KillCredit[k]))
+ {
+ sLog.outErrorDb("Creature (Entry: %u) has not existed creature entry in `KillCredit%d` (%u)",cInfo->Entry,k+1,cInfo->KillCredit[k]);
+ const_cast<CreatureInfo*>(cInfo)->KillCredit[k] = 0;
+ }
+ }
+ }
+
if (cInfo->unit_class && ((1 << (cInfo->unit_class-1)) & CLASSMASK_ALL_CREATURES) == 0)
sLog.outErrorDb("Creature (Entry: %u) has invalid unit_class(%u) for creature_template", cInfo->Entry, cInfo->unit_class);
@@ -786,7 +801,7 @@ void ObjectMgr::LoadCreatureTemplates()
const_cast<CreatureInfo*>(cInfo)->scale = 1.0f;
}
- //const_cast<CreatureInfo*>(cInfo)->dmg_multiplier *= Creature::_GetDamageMod(cInfo->rank);
+ const_cast<CreatureInfo*>(cInfo)->dmg_multiplier *= Creature::_GetDamageMod(cInfo->rank);
}
}
@@ -865,17 +880,17 @@ void ObjectMgr::ConvertCreatureAddonAuras(CreatureDataAddon* addon, char const*
endAura.effect_idx = 0;
}
-void ObjectMgr::LoadCreatureAddons()
+void ObjectMgr::LoadCreatureAddons(SQLStorage& creatureaddons, char const* entryName, char const* comment)
{
- sCreatureInfoAddonStorage.Load();
+ creatureaddons.Load();
- sLog.outString( ">> Loaded %u creature template addons", sCreatureInfoAddonStorage.RecordCount );
+ sLog.outString(">> Loaded %u %s", creatureaddons.RecordCount, comment);
sLog.outString();
// check data correctness and convert 'auras'
- for(uint32 i = 1; i < sCreatureInfoAddonStorage.MaxEntry; ++i)
+ for(uint32 i = 1; i < creatureaddons.MaxEntry; ++i)
{
- CreatureDataAddon const* addon = sCreatureInfoAddonStorage.LookupEntry<CreatureDataAddon>(i);
+ CreatureDataAddon const* addon = creatureaddons.LookupEntry<CreatureDataAddon>(i);
if(!addon)
continue;
@@ -883,49 +898,41 @@ void ObjectMgr::LoadCreatureAddons()
{
if (!sCreatureDisplayInfoStore.LookupEntry(addon->mount))
{
- sLog.outErrorDb("Creature (Entry %u) have invalid displayInfoId for mount (%u) defined in `creature_template_addon`.",addon->guidOrEntry, addon->mount);
+ sLog.outErrorDb("Creature (%s %u) have invalid displayInfoId for mount (%u) defined in `%s`.", entryName, addon->guidOrEntry, addon->mount, creatureaddons.GetTableName());
const_cast<CreatureDataAddon*>(addon)->mount = 0;
}
}
if (!sEmotesStore.LookupEntry(addon->emote))
- sLog.outErrorDb("Creature (Entry %u) have invalid emote (%u) defined in `creature_template_addon`.",addon->guidOrEntry, addon->emote);
+ sLog.outErrorDb("Creature (%s %u) have invalid emote (%u) defined in `%s`.", entryName, addon->guidOrEntry, addon->emote, creatureaddons.GetTableName());
- ConvertCreatureAddonAuras(const_cast<CreatureDataAddon*>(addon), "creature_template_addon", "Entry");
+ /*if (addon->move_flags & (MONSTER_MOVE_UNK1|MONSTER_MOVE_UNK4))
+ {
+ sLog.outErrorDb("Creature (%s %u) movement flags mask defined in `%s` include forbidden flags (" I32FMT ") that can crash client, cleanup at load.", entryName, addon->guidOrEntry, creatureaddons.GetTableName(), (MONSTER_MOVE_UNK1|MONSTER_MOVE_UNK4));
+ const_cast<CreatureDataAddon*>(addon)->move_flags &= ~(MONSTER_MOVE_UNK1|MONSTER_MOVE_UNK4);
+ }*/
- if(!sCreatureStorage.LookupEntry<CreatureInfo>(addon->guidOrEntry))
- sLog.outErrorDb("Creature (Entry: %u) does not exist but has a record in `creature_template_addon`",addon->guidOrEntry);
+ ConvertCreatureAddonAuras(const_cast<CreatureDataAddon*>(addon), creatureaddons.GetTableName(), entryName);
}
+}
- sCreatureDataAddonStorage.Load();
-
- sLog.outString( ">> Loaded %u creature addons", sCreatureDataAddonStorage.RecordCount );
- sLog.outString();
-
- // check data correctness and convert 'auras'
- for(uint32 i = 1; i < sCreatureDataAddonStorage.MaxEntry; ++i)
- {
- CreatureDataAddon const* addon = sCreatureDataAddonStorage.LookupEntry<CreatureDataAddon>(i);
- if(!addon)
- continue;
-
- if (addon->mount)
- {
- if (!sCreatureDisplayInfoStore.LookupEntry(addon->mount))
- {
- sLog.outErrorDb("Creature (GUID %u) have invalid displayInfoId for mount (%u) defined in `creature_addon`.",addon->guidOrEntry, addon->mount);
- const_cast<CreatureDataAddon*>(addon)->mount = 0;
- }
- }
+void ObjectMgr::LoadCreatureAddons()
+{
+ LoadCreatureAddons(sCreatureInfoAddonStorage,"Entry","creature template addons");
- if (!sEmotesStore.LookupEntry(addon->emote))
- sLog.outErrorDb("Creature (GUID %u) have invalid emote (%u) defined in `creature_addon`.",addon->guidOrEntry, addon->emote);
+ // check entry ids
+ for(uint32 i = 1; i < sCreatureInfoAddonStorage.MaxEntry; ++i)
+ if(CreatureDataAddon const* addon = sCreatureInfoAddonStorage.LookupEntry<CreatureDataAddon>(i))
+ if(!sCreatureStorage.LookupEntry<CreatureInfo>(addon->guidOrEntry))
+ sLog.outErrorDb("Creature (Entry: %u) does not exist but has a record in `%s`",addon->guidOrEntry, sCreatureInfoAddonStorage.GetTableName());
- ConvertCreatureAddonAuras(const_cast<CreatureDataAddon*>(addon), "creature_addon", "GUIDLow");
+ LoadCreatureAddons(sCreatureDataAddonStorage,"GUID","creature addons");
- if(mCreatureDataMap.find(addon->guidOrEntry)==mCreatureDataMap.end())
- sLog.outErrorDb("Creature (GUID: %u) does not exist but has a record in `creature_addon`",addon->guidOrEntry);
- }
+ // check entry ids
+ for(uint32 i = 1; i < sCreatureDataAddonStorage.MaxEntry; ++i)
+ if(CreatureDataAddon const* addon = sCreatureDataAddonStorage.LookupEntry<CreatureDataAddon>(i))
+ if(mCreatureDataMap.find(addon->guidOrEntry)==mCreatureDataMap.end())
+ sLog.outErrorDb("Creature (GUID: %u) does not exist but has a record in `creature_addon`",addon->guidOrEntry);
}
EquipmentInfo const* ObjectMgr::GetEquipmentInfo(uint32 entry)
@@ -1533,6 +1540,12 @@ void ObjectMgr::LoadGameobjects()
data.rotation2 = fields[ 9].GetFloat();
data.rotation3 = fields[10].GetFloat();
data.spawntimesecs = fields[11].GetInt32();
+
+ if (data.spawntimesecs==0 && gInfo->IsDespawnAtAction())
+ {
+ sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with `spawntimesecs` (0) value, but gameobejct marked as despawnable at action.",guid,data.id);
+ }
+
data.animprogress = fields[12].GetUInt32();
data.ArtKit = 0;
@@ -2035,6 +2048,12 @@ void ObjectMgr::LoadItemPrototypes()
const_cast<ItemPrototype*>(proto)->Stackable = 1000;
}
+ if(proto->ContainerSlots > MAX_BAG_SIZE)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has too large value in ContainerSlots (%u), replace by hardcoded limit (%u).",i,proto->ContainerSlots,MAX_BAG_SIZE);
+ const_cast<ItemPrototype*>(proto)->ContainerSlots = MAX_BAG_SIZE;
+ }
+
if(proto->StatsCount > MAX_ITEM_PROTO_STATS)
{
sLog.outErrorDb("Item (Entry: %u) has too large value in statscount (%u), replace by hardcoded limit (%u).",i,proto->StatsCount,MAX_ITEM_PROTO_STATS);
@@ -2706,8 +2725,8 @@ void ObjectMgr::LoadPlayerInfo()
// Load playercreate actions
{
- // 0 1 2 3 4 5
- QueryResult *result = WorldDatabase.Query("SELECT race, class, button, action, type, misc FROM playercreateinfo_action");
+ // 0 1 2 3 4
+ QueryResult *result = WorldDatabase.Query("SELECT race, class, button, action, type FROM playercreateinfo_action");
uint32 count = 0;
@@ -2742,10 +2761,7 @@ void ObjectMgr::LoadPlayerInfo()
}
PlayerInfo* pInfo = &playerInfo[current_race][current_class];
- pInfo->action[0].push_back(fields[2].GetUInt16());
- pInfo->action[1].push_back(fields[3].GetUInt16());
- pInfo->action[2].push_back(fields[4].GetUInt16());
- pInfo->action[3].push_back(fields[5].GetUInt16());
+ pInfo->action.push_back(PlayerCreateInfoAction(fields[2].GetUInt8(),fields[3].GetUInt32(),fields[4].GetUInt8()));
bar.step();
++count;
@@ -3901,13 +3917,20 @@ void ObjectMgr::LoadQuests()
qinfo->RewSpell = 0; // no spell reward will display for this quest
}
- else if(!SpellMgr::IsSpellValid(spellInfo))
+ if(!SpellMgr::IsSpellValid(spellInfo))
{
- sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u is broken, quest can't be done.",
+ sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u is broken, quest will not have a spell reward.",
qinfo->GetQuestId(),qinfo->RewSpell,qinfo->RewSpell);
qinfo->RewSpell = 0; // no spell reward will display for this quest
}
+ if(GetTalentSpellCost(qinfo->RewSpell))
+ {
+ sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u is talent, quest will not have a spell reward.",
+ qinfo->GetQuestId(),qinfo->RewSpell,qinfo->RewSpell);
+ qinfo->RewSpell = 0; // no spell reward will display for this quest
+ continue;
+ }
}
if(qinfo->RewSpellCast)
@@ -3921,13 +3944,20 @@ void ObjectMgr::LoadQuests()
qinfo->RewSpellCast = 0; // no spell will be casted on player
}
- else if(!SpellMgr::IsSpellValid(spellInfo))
+ if(!SpellMgr::IsSpellValid(spellInfo))
{
- sLog.outErrorDb("Quest %u has `RewSpellCast` = %u but spell %u is broken, quest can't be done.",
+ sLog.outErrorDb("Quest %u has `RewSpellCast` = %u but spell %u is broken, quest will not have a spell reward.",
qinfo->GetQuestId(),qinfo->RewSpellCast,qinfo->RewSpellCast);
qinfo->RewSpellCast = 0; // no spell will be casted on player
}
+ if(GetTalentSpellCost(qinfo->RewSpellCast))
+ {
+ sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u is talent, quest will not have a spell reward.",
+ qinfo->GetQuestId(),qinfo->RewSpellCast,qinfo->RewSpellCast);
+ qinfo->RewSpellCast = 0; // no spell will be casted on player
+ continue;
+ }
}
if(qinfo->RewMailTemplateId)
@@ -6131,6 +6161,16 @@ inline void CheckGONoDamageImmuneId(GameObjectInfo const* goInfo,uint32 dataN,ui
goInfo->id,goInfo->type,N,dataN);
}
+inline void CheckGOConsumable(GameObjectInfo const* goInfo,uint32 dataN,uint32 N)
+{
+ // 0/1 correct values
+ if (dataN <= 1)
+ return;
+
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but expected boolean (0/1) consumable field value.",
+ goInfo->id,goInfo->type,N,dataN);
+}
+
void ObjectMgr::LoadGameobjectInfo()
{
SQLGameObjectLoader loader;
@@ -6173,6 +6213,8 @@ void ObjectMgr::LoadGameobjectInfo()
if (goInfo->chest.lockId)
CheckGOLockId(goInfo,goInfo->chest.lockId,0);
+ CheckGOConsumable(goInfo,goInfo->chest.consumable,3);
+
if (goInfo->chest.linkedTrapId) // linked trap
CheckGOLinkedTrapId(goInfo,goInfo->chest.linkedTrapId,7);
break;
@@ -6208,6 +6250,8 @@ void ObjectMgr::LoadGameobjectInfo()
if (goInfo->goober.lockId)
CheckGOLockId(goInfo,goInfo->goober.lockId,0);
+ CheckGOConsumable(goInfo,goInfo->goober.consumable,3);
+
if (goInfo->goober.pageId) // pageId
{
if (!sPageTextStore.LookupEntry<PageText>(goInfo->goober.pageId))
@@ -7054,18 +7098,24 @@ bool isValidString(std::wstring wstr, uint32 strictMask, bool numericOrSpace, bo
return false;
}
-bool ObjectMgr::IsValidName( const std::string& name, bool create )
+uint8 ObjectMgr::CheckPlayerName( const std::string& name, bool create )
{
std::wstring wname;
if(!Utf8toWStr(name,wname))
- return false;
+ return CHAR_NAME_INVALID_CHARACTER;
- if(wname.size() < 1 || wname.size() > MAX_PLAYER_NAME)
- return false;
+ if(wname.size() > MAX_PLAYER_NAME)
+ return CHAR_NAME_TOO_LONG;
+
+ uint32 minName = sWorld.getConfig(CONFIG_MIN_PLAYER_NAME);
+ if(wname.size() < minName)
+ return CHAR_NAME_TOO_SHORT;
uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_PLAYER_NAMES);
+ if(!isValidString(wname,strictMask,false,create))
+ return CHAR_NAME_MIXED_LANGUAGES;
- return isValidString(wname,strictMask,false,create);
+ return CHAR_NAME_SUCCESS;
}
bool ObjectMgr::IsValidCharterName( const std::string& name )
@@ -7074,7 +7124,11 @@ bool ObjectMgr::IsValidCharterName( const std::string& name )
if(!Utf8toWStr(name,wname))
return false;
- if(wname.size() < 1)
+ if(wname.size() > MAX_CHARTER_NAME)
+ return false;
+
+ uint32 minName = sWorld.getConfig(CONFIG_MIN_CHARTER_NAME);
+ if(wname.size() < minName)
return false;
uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_CHARTER_NAMES);
@@ -7082,18 +7136,24 @@ bool ObjectMgr::IsValidCharterName( const std::string& name )
return isValidString(wname,strictMask,true);
}
-bool ObjectMgr::IsValidPetName( const std::string& name )
+PetNameInvalidReason ObjectMgr::CheckPetName( const std::string& name )
{
std::wstring wname;
if(!Utf8toWStr(name,wname))
- return false;
+ return PET_NAME_INVALID;
- if(wname.size() < 1)
- return false;
+ if(wname.size() > MAX_PET_NAME)
+ return PET_NAME_TOO_LONG;
+
+ uint32 minName = sWorld.getConfig(CONFIG_MIN_PET_NAME);
+ if(wname.size() < minName)
+ return PET_NAME_TOO_SHORT;
uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_PET_NAMES);
+ if(!isValidString(wname,strictMask,false))
+ return PET_NAME_MIXED_LANGUAGES;
- return isValidString(wname,strictMask,false);
+ return PET_NAME_SUCCESS;
}
int ObjectMgr::GetIndexForLocale( LocaleConstant loc )
@@ -7158,7 +7218,7 @@ void ObjectMgr::LoadGameObjectForQuests()
// scan GO chest with loot including quest items
case GAMEOBJECT_TYPE_CHEST:
{
- uint32 loot_id = GameObject::GetLootId(goInfo);
+ uint32 loot_id = goInfo->GetLootId();
// find quest loot for GO
if(LootTemplates_Gameobject.HaveQuestLootFor(loot_id))
diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h
index f5189116463..b770c3044a4 100644
--- a/src/game/ObjectMgr.h
+++ b/src/game/ObjectMgr.h
@@ -234,7 +234,7 @@ enum ConditionType
CONDITION_SKILL = 7, // skill_id skill_value
CONDITION_QUESTREWARDED = 8, // quest_id 0
CONDITION_QUESTTAKEN = 9, // quest_id 0, for condition true while quest active.
- CONDITION_AD_COMMISSION_AURA = 10, // 0 0, for condition true while one from AD ńommission aura active
+ CONDITION_AD_COMMISSION_AURA = 10, // 0 0, for condition true while one from AD commission aura active
CONDITION_NO_AURA = 11, // spell_id effindex
CONDITION_ACTIVE_EVENT = 12, // event_id
CONDITION_INSTANCE_DATA = 13, // entry data
@@ -312,8 +312,10 @@ struct GM_Ticket
typedef std::list<GM_Ticket*> GmTicketList;
SkillRangeType GetSkillRangeType(SkillLineEntry const *pSkill, bool racial);
-#define MAX_PLAYER_NAME 12 // max allowed by client name length
+#define MAX_PLAYER_NAME 12 // max allowed by client name length
#define MAX_INTERNAL_PLAYER_NAME 15 // max server internal player name length ( > MAX_PLAYER_NAME for support declined names )
+#define MAX_PET_NAME 12 // max allowed by client name length
+#define MAX_CHARTER_NAME 24 // max allowed by client name length
bool normalizePlayerName(std::string& name);
@@ -628,6 +630,7 @@ class ObjectMgr
CachePlayerInfoMap m_mPlayerInfoMap;
uint32 CreateItemText(std::string text);
+ void AddItemText(uint32 itemTextId, std::string text) { mItemTexts[itemTextId] = text; }
std::string GetItemText( uint32 id )
{
ItemTextMap::const_iterator itr = mItemTexts.find( id );
@@ -759,9 +762,9 @@ class ObjectMgr
bool IsReservedName(const std::string& name) const;
// name with valid structure and symbols
- static bool IsValidName( const std::string& name, bool create = false );
+ static uint8 CheckPlayerName( const std::string& name, bool create = false );
+ static PetNameInvalidReason CheckPetName( const std::string& name );
static bool IsValidCharterName( const std::string& name );
- static bool IsValidPetName( const std::string& name );
static bool CheckDeclinedNames(std::wstring mainpart, DeclinedName const& names);
@@ -845,7 +848,7 @@ class ObjectMgr
GM_Ticket *GetGMTicket(uint64 ticketGuid)
{
for(GmTicketList::const_iterator i = m_GMTicketList.begin(); i != m_GMTicketList.end(); ++i)
- if((*i) && (*i)->guid == ticketGuid && (*i)->closed == 0)
+ if((*i) && (*i)->guid == ticketGuid)
return (*i);
return NULL;
@@ -943,6 +946,7 @@ class ObjectMgr
private:
void LoadScripts(ScriptMapMap& scripts, char const* tablename);
void CheckScripts(ScriptMapMap const& scripts,std::set<int32>& ids);
+ void LoadCreatureAddons(SQLStorage& creatureaddons, char const* entryName, char const* comment);
void ConvertCreatureAddonAuras(CreatureDataAddon* addon, char const* table, char const* guidEntryStr);
void LoadQuestRelationsHelper(QuestRelations& map,char const* table);
diff --git a/src/game/Opcodes.cpp b/src/game/Opcodes.cpp
index b66786f9d91..8fd57ad52be 100644
--- a/src/game/Opcodes.cpp
+++ b/src/game/Opcodes.cpp
@@ -1025,7 +1025,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] =
/*0x3E2*/ { "SMSG_COMSAT_CONNECT_FAIL", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x3E3*/ { "SMSG_VOICE_CHAT_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x3E4*/ { "CMSG_REPORT_PVP_AFK", STATUS_LOGGEDIN, &WorldSession::HandleReportPvPAFK },
- /*0x3E5*/ { "CMSG_REPORT_PVP_AFK_RESULT", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x3E5*/ { "SMSG_REPORT_PVP_AFK_RESULT", STATUS_NEVER, &WorldSession::Handle_NULL },
/*0x3E6*/ { "CMSG_GUILD_BANKER_ACTIVATE", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankerActivate },
/*0x3E7*/ { "CMSG_GUILD_BANK_QUERY_TAB", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankQueryTab },
/*0x3E8*/ { "SMSG_GUILD_BANK_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide },
@@ -1053,7 +1053,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] =
/*0x3FE*/ { "MSG_GUILD_BANK_MONEY_WITHDRAWN", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankMoneyWithdrawn },
/*0x3FF*/ { "MSG_GUILD_EVENT_LOG_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleGuildEventLogQueryOpcode },
/*0x400*/ { "CMSG_MAELSTROM_RENAME_GUILD", STATUS_NEVER, &WorldSession::Handle_NULL },
- /*0x401*/ { "CMSG_GET_MIRRORIMAGE_DATA", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x401*/ { "CMSG_GET_MIRRORIMAGE_DATA", STATUS_LOGGEDIN, &WorldSession::HandleMirrrorImageDataRequest },
/*0x402*/ { "SMSG_MIRRORIMAGE_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x403*/ { "SMSG_FORCE_DISPLAY_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x404*/ { "SMSG_SPELL_CHANCE_RESIST_PUSHBACK", STATUS_NEVER, &WorldSession::Handle_ServerSide },
diff --git a/src/game/Opcodes.h b/src/game/Opcodes.h
index b3d9c4f8f11..b468cc64978 100644
--- a/src/game/Opcodes.h
+++ b/src/game/Opcodes.h
@@ -694,8 +694,8 @@ enum Opcodes
CMSG_GROUP_ASSISTANT_LEADER = 0x28F,
CMSG_BUYBACK_ITEM = 0x290,
SMSG_SERVER_MESSAGE = 0x291,
- CMSG_MEETINGSTONE_JOIN = 0x292,
- CMSG_MEETINGSTONE_LEAVE = 0x293, // SMSG?
+ CMSG_MEETINGSTONE_JOIN = 0x292, // lua: SetSavedInstanceExtend
+ SMSG_MEETINGSTONE_LEAVE = 0x293,
CMSG_MEETINGSTONE_CHEAT = 0x294,
SMSG_MEETINGSTONE_SETQUEUE = 0x295,
CMSG_MEETINGSTONE_INFO = 0x296,
@@ -1033,7 +1033,7 @@ enum Opcodes
SMSG_COMSAT_CONNECT_FAIL = 0x3E2,
SMSG_VOICE_CHAT_STATUS = 0x3E3,
CMSG_REPORT_PVP_AFK = 0x3E4,
- CMSG_REPORT_PVP_AFK_RESULT = 0x3E5,
+ SMSG_REPORT_PVP_AFK_RESULT = 0x3E5, // SMSG?
CMSG_GUILD_BANKER_ACTIVATE = 0x3E6,
CMSG_GUILD_BANK_QUERY_TAB = 0x3E7,
SMSG_GUILD_BANK_LIST = 0x3E8,
diff --git a/src/game/OutdoorPvP.cpp b/src/game/OutdoorPvP.cpp
index fd1cf87e6d6..d3c96f53fcb 100644
--- a/src/game/OutdoorPvP.cpp
+++ b/src/game/OutdoorPvP.cpp
@@ -116,7 +116,6 @@ bool OPvPCapturePoint::DelCreature(uint32 type)
// Don't save respawn time
cr->SetRespawnTime(0);
cr->RemoveCorpse();
- cr->CleanupsBeforeDelete();
// explicit removal from map
// beats me why this is needed, but with the recent removal "cleanup" some creatures stay in the map if "properly" deleted
// so this is a big fat workaround, if AddObjectToRemoveList and DoDelayedMovesAndRemoves worked correctly, this wouldn't be needed
@@ -360,7 +359,7 @@ void OPvPCapturePoint::SendObjectiveComplete(uint32 id,uint64 guid)
// send to all players present in the area
for(PlayerSet::iterator itr = m_activePlayers[team].begin(); itr != m_activePlayers[team].end(); ++itr)
- (*itr)->KilledMonster(id, guid);
+ (*itr)->KilledMonsterCredit(id, guid);
}
void OutdoorPvP::HandleKill(Player *killer, Unit * killed)
diff --git a/src/game/OutdoorPvPNA.cpp b/src/game/OutdoorPvPNA.cpp
index 53bf1a3c770..7a421b848ba 100644
--- a/src/game/OutdoorPvPNA.cpp
+++ b/src/game/OutdoorPvPNA.cpp
@@ -33,7 +33,7 @@ void OutdoorPvPNA::HandleKillImpl(Player *plr, Unit * killed)
{
if(killed->GetTypeId() == TYPEID_PLAYER && plr->GetTeam() != ((Player*)killed)->GetTeam())
{
- plr->KilledMonster(NA_CREDIT_MARKER,0); // 0 guid, btw it isn't even used in killedmonster function :S
+ plr->KilledMonsterCredit(NA_CREDIT_MARKER,0); // 0 guid, btw it isn't even used in killedmonster function :S
if(plr->GetTeam() == ALLIANCE)
plr->CastSpell(plr,NA_KILL_TOKEN_ALLIANCE,true);
else
diff --git a/src/game/OutdoorPvPSI.cpp b/src/game/OutdoorPvPSI.cpp
index c1f47db49c7..e60888c7e08 100644
--- a/src/game/OutdoorPvPSI.cpp
+++ b/src/game/OutdoorPvPSI.cpp
@@ -107,7 +107,7 @@ bool OutdoorPvPSI::HandleAreaTrigger(Player *plr, uint32 trigger)
// add 20 cenarion circle repu
plr->GetReputationMgr().ModifyReputation(sFactionStore.LookupEntry(609),20);
// complete quest
- plr->KilledMonster(SI_TURNIN_QUEST_CM_A,0);
+ plr->KilledMonsterCredit(SI_TURNIN_QUEST_CM_A,0);
}
return true;
case SI_AREATRIGGER_H:
@@ -132,7 +132,7 @@ bool OutdoorPvPSI::HandleAreaTrigger(Player *plr, uint32 trigger)
// add 20 cenarion circle repu
plr->GetReputationMgr().ModifyReputation(sFactionStore.LookupEntry(609),20);
// complete quest
- plr->KilledMonster(SI_TURNIN_QUEST_CM_H,0);
+ plr->KilledMonsterCredit(SI_TURNIN_QUEST_CM_H,0);
}
return true;
}
@@ -156,7 +156,7 @@ bool OutdoorPvPSI::HandleDropFlag(Player *plr, uint32 spellId)
{
// he dropped it further, summon mound
GameObject * go = new GameObject;
- Map * map = MapManager::Instance().GetMap(plr->GetMapId(), plr);
+ Map * map = plr->GetMap();
if(!map)
{
delete go;
@@ -186,7 +186,7 @@ bool OutdoorPvPSI::HandleDropFlag(Player *plr, uint32 spellId)
{
// he dropped it further, summon mound
GameObject * go = new GameObject;
- Map * map = MapManager::Instance().GetMap(plr->GetMapId(), plr);
+ Map * map = plr->GetMap();
if(!map)
{
delete go;
diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp
index 7448d6440ce..05764beec11 100644
--- a/src/game/Pet.cpp
+++ b/src/game/Pet.cpp
@@ -49,10 +49,15 @@ m_declinedname(NULL), m_owner(owner)
m_summonMask |= SUMMON_MASK_PET;
if(type == HUNTER_PET)
m_summonMask |= SUMMON_MASK_HUNTER_PET;
+
+ if (!(m_summonMask & SUMMON_MASK_CONTROLABLE_GUARDIAN))
+ {
+ m_summonMask |= SUMMON_MASK_CONTROLABLE_GUARDIAN;
+ InitCharmInfo();
+ }
+
m_name = "Pet";
m_regenTimer = 4000;
-
- owner->SetPetAtLoginFlag(0);
}
Pet::~Pet()
@@ -93,24 +98,24 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool
if (petnumber)
// known petnumber entry 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
- result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType, load_flags "
+ result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType "
"FROM character_pet WHERE owner = '%u' AND id = '%u'",
ownerid, petnumber);
else if (current)
// current pet (slot 0) 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
- result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType, load_flags "
+ result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType "
"FROM character_pet WHERE owner = '%u' AND slot = '%u'",
ownerid, PET_SAVE_AS_CURRENT );
else if (petentry)
// known petentry entry (unique for summoned pet, but non unique for hunter pet (only from current or not stabled pets)
// 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
- result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType, load_flags "
+ result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType "
"FROM character_pet WHERE owner = '%u' AND entry = '%u' AND (slot = '%u' OR slot > '%u') ",
ownerid, petentry,PET_SAVE_AS_CURRENT,PET_SAVE_LAST_STABLE_SLOT);
else
// any current or other non-stabled pet (for hunter "call pet")
// 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
- result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType, load_flags "
+ result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType "
"FROM character_pet WHERE owner = '%u' AND (slot = '%u' OR slot > '%u') ",
ownerid,PET_SAVE_AS_CURRENT,PET_SAVE_LAST_STABLE_SLOT);
@@ -151,7 +156,7 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool
}
uint32 pet_number = fields[0].GetUInt32();
-
+
if (current && owner->IsPetNeedBeTemporaryUnsummoned())
{
owner->SetTemporaryUnsummonedPetNumber(pet_number);
@@ -168,7 +173,7 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool
}
float px, py, pz;
- owner->GetClosePoint(px, py, pz, GetObjectSize(), PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
+ owner->GetClosePoint(px, py, pz, GetObjectSize(), PET_FOLLOW_DIST, GetFollowAngle());
Relocate(px, py, pz, owner->GetOrientation());
if (!IsPositionValid())
@@ -284,29 +289,16 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool
uint32 timediff = (time(NULL) - fields[14].GetUInt32());
_LoadAuras(timediff);
- uint8 loadFlags = fields[19].GetUInt8();
- owner->SetPetAtLoginFlag(loadFlags);
- if (loadFlags & AT_LOAD_RESET_SPELLS)
- {
- CharacterDatabase.PExecute("UPDATE character_pet SET load_flags = load_flags & ~ %u WHERE id = '%u'",uint32(AT_LOAD_RESET_SPELLS),pet_number);
- loadFlags &= ~uint8(AT_LOAD_RESET_SPELLS);
- CharacterDatabase.PExecute("DELETE FROM pet_spell WHERE guid = '%u'",pet_number);
- InitPetCreateSpells();
- resetTalents(true);
- }
- else
+ // load action bar, if data broken will fill later by default spells.
+ if (!is_temporary_summoned)
{
- // load action bar, if data broken will fill later by default spells.
- if (!is_temporary_summoned)
- {
- m_charmInfo->LoadPetActionBar(fields[13].GetCppString());
+ m_charmInfo->LoadPetActionBar(fields[13].GetCppString());
- _LoadSpells();
- _LoadSpellCooldowns();
- LearnPetPassives();
- InitLevelupSpellsForLevel();
- CastPetAuras(current);
- }
+ _LoadSpells();
+ _LoadSpellCooldowns();
+ LearnPetPassives();
+ InitLevelupSpellsForLevel();
+ CastPetAuras(current);
}
CleanupActionBar(); // remove unknown spells from action bar after load
@@ -408,7 +400,7 @@ void Pet::SavePetToDB(PetSaveMode mode)
owner,PET_SAVE_AS_CURRENT,PET_SAVE_LAST_STABLE_SLOT);
// save pet
std::ostringstream ss;
- ss << "INSERT INTO character_pet ( id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType, load_flags) "
+ ss << "INSERT INTO character_pet ( id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType) "
<< "VALUES ("
<< m_charmInfo->GetPetNumber() << ", "
<< GetEntry() << ", "
@@ -427,8 +419,8 @@ void Pet::SavePetToDB(PetSaveMode mode)
// save only spell slots from action bar
for(uint32 i = ACTION_BAR_INDEX_PET_SPELL_START; i < ACTION_BAR_INDEX_PET_SPELL_END; ++i)
{
- ss << uint32(m_charmInfo->GetActionBarEntry(i)->Type) << " "
- << uint32(m_charmInfo->GetActionBarEntry(i)->SpellOrAction) << " ";
+ ss << uint32(m_charmInfo->GetActionBarEntry(i)->GetType()) << " "
+ << uint32(m_charmInfo->GetActionBarEntry(i)->GetAction()) << " ";
};
ss << "', "
@@ -436,8 +428,7 @@ void Pet::SavePetToDB(PetSaveMode mode)
<< uint32(m_resetTalentsCost) << ", "
<< uint64(m_resetTalentsTime) << ", "
<< GetUInt32Value(UNIT_CREATED_BY_SPELL) << ", "
- << uint32(getPetType()) << ", "
- << (pOwner->GetAtLoginFlag()>>AT_LOAD_PET_FLAGS) << ")";
+ << uint32(getPetType()) << ")";
CharacterDatabase.Execute( ss.str().c_str() );
CharacterDatabase.CommitTransaction();
@@ -448,7 +439,6 @@ void Pet::SavePetToDB(PetSaveMode mode)
RemoveAllAuras();
DeleteFromDB(m_charmInfo->GetPetNumber());
}
- pOwner->SetPetAtLoginFlag(0);
}
void Pet::DeleteFromDB(uint32 guidlow)
@@ -732,9 +722,6 @@ bool Pet::CreateBaseAtCreature(Creature* creature)
}
uint32 guid=objmgr.GenerateLowGuid(HIGHGUID_PET);
- sLog.outDebug("SetInstanceID()");
- SetInstanceId(creature->GetInstanceId());
-
sLog.outDebug("Create pet");
uint32 pet_number = objmgr.GeneratePetNumber();
if(!Create(guid, creature->GetMap(), creature->GetPhaseMask(), creature->GetEntry(), pet_number))
@@ -941,6 +928,16 @@ bool Guardian::InitStatsForLevel(uint32 petlevel)
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel * 4 + petlevel));
break;
}
+ case 31216: // Mirror Image
+ {
+ SetBonusDamage( int32(m_owner->SpellBaseDamageBonus(SPELL_SCHOOL_MASK_FROST) * 0.33f));
+ if(!pInfo)
+ {
+ SetCreateMana(28 + 30*petlevel);
+ SetCreateHealth(28 + 10*petlevel);
+ }
+ break;
+ }
default:
{
if(!pInfo)
@@ -1081,7 +1078,7 @@ void Pet::_LoadSpells()
{
Field *fields = result->Fetch();
- addSpell(fields[0].GetUInt32(), ActiveStates(fields[1].GetUInt16()), PETSPELL_UNCHANGED);
+ addSpell(fields[0].GetUInt32(), ActiveStates(fields[1].GetUInt8()), PETSPELL_UNCHANGED);
}
while( result->NextRow() );
@@ -1346,8 +1343,8 @@ bool Pet::learnSpell(uint32 spell_id)
if(!m_loading)
{
- WorldPacket data(SMSG_PET_LEARNED_SPELL, 2);
- data << uint16(spell_id);
+ WorldPacket data(SMSG_PET_LEARNED_SPELL, 4);
+ data << uint32(spell_id);
m_owner->GetSession()->SendPacket(&data);
m_owner->PetSpellInitialize();
}
@@ -1399,8 +1396,8 @@ bool Pet::unlearnSpell(uint32 spell_id, bool learn_prev, bool clear_ab)
{
if(!m_loading)
{
- WorldPacket data(SMSG_PET_REMOVED_SPELL, 2);
- data << uint16(spell_id);
+ WorldPacket data(SMSG_PET_REMOVED_SPELL, 4);
+ data << uint32(spell_id);
m_owner->GetSession()->SendPacket(&data);
}
return true;
@@ -1464,12 +1461,12 @@ void Pet::CleanupActionBar()
{
for(uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
if(UnitActionBarEntry const* ab = m_charmInfo->GetActionBarEntry(i))
- if(ab->SpellOrAction && ab->IsActionBarForSpell())
+ if(ab->GetAction() && ab->IsActionBarForSpell())
{
- if(!HasSpell(ab->SpellOrAction))
+ if(!HasSpell(ab->GetAction()))
m_charmInfo->SetActionBar(i, 0, ACT_PASSIVE);
- else if(ab->Type == ACT_ENABLED)
- ToggleAutocast(ab->SpellOrAction, true);
+ else if(ab->GetType() == ACT_ENABLED)
+ ToggleAutocast(ab->GetAction(), true);
}
}
@@ -1490,6 +1487,10 @@ bool Pet::resetTalents(bool no_cost)
if (!owner || owner->GetTypeId()!=TYPEID_PLAYER)
return false;
+ // not need after this call
+ if(((Player*)owner)->HasAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS))
+ ((Player*)owner)->RemoveAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS,true);
+
CreatureInfo const * ci = GetCreatureInfo();
if(!ci)
return false;
@@ -1576,6 +1577,90 @@ bool Pet::resetTalents(bool no_cost)
return true;
}
+void Pet::resetTalentsForAllPetsOf(Player* owner, Pet* online_pet /*= NULL*/)
+{
+ // not need after this call
+ if(((Player*)owner)->HasAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS))
+ ((Player*)owner)->RemoveAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS,true);
+
+ // reset for online
+ if(online_pet)
+ online_pet->resetTalents(true);
+
+ // now need only reset for offline pets (all pets except online case)
+ uint32 except_petnumber = online_pet ? online_pet->GetCharmInfo()->GetPetNumber() : 0;
+
+ QueryResult *resultPets = CharacterDatabase.PQuery(
+ "SELECT id FROM character_pet WHERE owner = '%u' AND id <> '%u'",
+ owner->GetGUIDLow(),except_petnumber);
+
+ // no offline pets
+ if(!resultPets)
+ return;
+
+ QueryResult *result = CharacterDatabase.PQuery(
+ "SELECT DISTINCT pet_spell.spell FROM pet_spell, character_pet "
+ "WHERE character_pet.owner = '%u' AND character_pet.id = pet_spell.guid AND character_pet.id <> %u",
+ owner->GetGUIDLow(),except_petnumber);
+
+ if(!result)
+ {
+ delete resultPets;
+ return;
+ }
+
+ bool need_comma = false;
+ std::ostringstream ss;
+ ss << "DELETE FROM pet_spell WHERE guid IN (";
+
+ do
+ {
+ Field *fields = resultPets->Fetch();
+
+ uint32 id = fields[0].GetUInt32();
+
+ if(need_comma)
+ ss << ",";
+
+ ss << id;
+
+ need_comma = true;
+ }
+ while( resultPets->NextRow() );
+
+ delete resultPets;
+
+ ss << ") AND spell IN (";
+
+ bool need_execute = false;
+ do
+ {
+ Field *fields = result->Fetch();
+
+ uint32 spell = fields[0].GetUInt32();
+
+ if(!GetTalentSpellCost(spell))
+ continue;
+
+ if(need_execute)
+ ss << ",";
+
+ ss << spell;
+
+ need_execute = true;
+ }
+ while( result->NextRow() );
+
+ delete result;
+
+ if(!need_execute)
+ return;
+
+ ss << ")";
+
+ CharacterDatabase.Execute(ss.str().c_str());
+}
+
void Pet::InitTalentForLevel()
{
uint32 level = getLevel();
@@ -1693,10 +1778,10 @@ bool Pet::IsPermanentPetFor(Player* owner)
bool Pet::Create(uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint32 pet_number)
{
- SetMapId(map->GetId());
- SetInstanceId(map->GetInstanceId());
- SetPhaseMask(phaseMask,false);
+ assert(map);
+ SetMap(map);
+ SetPhaseMask(phaseMask,false);
Object::_Create(guidlow, pet_number, HIGHGUID_PET);
m_DBTableGuid = guidlow;
@@ -1761,7 +1846,7 @@ void Pet::CastPetAuras(bool current)
void Pet::CastPetAura(PetAura const* aura)
{
- uint16 auraId = aura->GetAura(GetEntry());
+ uint32 auraId = aura->GetAura(GetEntry());
if(!auraId)
return;
diff --git a/src/game/Pet.h b/src/game/Pet.h
index 49daad429ed..88287ce5dee 100644
--- a/src/game/Pet.h
+++ b/src/game/Pet.h
@@ -89,14 +89,11 @@ enum PetTalk
PET_TALK_ATTACK = 1
};
-enum AtLoadFlags
-{
- AT_LOAD_NONE = 0,
- AT_LOAD_RESET_SPELLS = 1,
-};
-
enum PetNameInvalidReason
{
+ // custom, not send
+ PET_NAME_SUCCESS = 0,
+
PET_NAME_INVALID = 1,
PET_NAME_NO_NAME = 2,
PET_NAME_TOO_SHORT = 3,
@@ -212,6 +209,7 @@ class Pet : public Guardian
void InitPetCreateSpells();
bool resetTalents(bool no_cost = false);
+ static void resetTalentsForAllPetsOf(Player* owner, Pet* online_pet = NULL);
uint32 resetTalentsCost() const;
void InitTalentForLevel();
diff --git a/src/game/PetAI.cpp b/src/game/PetAI.cpp
index 7851ee6773f..0fcc707b104 100644
--- a/src/game/PetAI.cpp
+++ b/src/game/PetAI.cpp
@@ -74,7 +74,7 @@ void PetAI::_stopAttack()
if(owner && m_creature->GetCharmInfo() && m_creature->GetCharmInfo()->HasCommandState(COMMAND_FOLLOW))
{
- m_creature->GetMotionMaster()->MoveFollow(owner,PET_FOLLOW_DIST,PET_FOLLOW_ANGLE);
+ m_creature->GetMotionMaster()->MoveFollow(owner,PET_FOLLOW_DIST, m_creature->GetFollowAngle());
}
else
{
@@ -112,17 +112,22 @@ void PetAI::UpdateAI(const uint32 diff)
if(owner->isInCombat() && !(m_creature->HasReactState(REACT_PASSIVE) || m_creature->GetCharmInfo()->HasCommandState(COMMAND_STAY)))
AttackStart(owner->getAttackerForHelper());
else if(m_creature->GetCharmInfo()->HasCommandState(COMMAND_FOLLOW) && !m_creature->hasUnitState(UNIT_STAT_FOLLOW))
- m_creature->GetMotionMaster()->MoveFollow(owner,PET_FOLLOW_DIST,PET_FOLLOW_ANGLE);
+ m_creature->GetMotionMaster()->MoveFollow(owner,PET_FOLLOW_DIST, m_creature->GetFollowAngle());
}
+ else if (owner && !m_creature->hasUnitState(UNIT_STAT_FOLLOW)) // no charm info and no victim
+ m_creature->GetMotionMaster()->MoveFollow(owner,PET_FOLLOW_DIST, m_creature->GetFollowAngle());
if(!me->GetCharmInfo())
return;
+ bool inCombat = me->getVictim();
+
+ // Autocast (casted only in combat or persistent spells in any state)
if (m_creature->GetGlobalCooldown() == 0 && !m_creature->hasUnitState(UNIT_STAT_CASTING))
{
- bool inCombat = me->getVictim();
+ typedef std::vector<std::pair<Unit*, Spell*> > TargetSpellList;
+ TargetSpellList targetSpellStore;
- //Autocast
for (uint8 i = 0; i < m_creature->GetPetAutoSpellSize(); ++i)
{
uint32 spellID = m_creature->GetPetAutoSpellOnPos(i);
@@ -136,20 +141,38 @@ void PetAI::UpdateAI(const uint32 diff)
// ignore some combinations of combat state and combat/noncombat spells
if (!inCombat)
{
+ // ignore attacking spells, and allow only self/around spells
if (!IsPositiveSpell(spellInfo->Id))
continue;
+
+ // non combat spells allowed
+ // only pet spells have IsNonCombatSpell and not fit this reqs:
+ // Consume Shadows, Lesser Invisibility, so ignore checks for its
+ if (!IsNonCombatSpell(spellInfo))
+ {
+ // allow only spell without spell cost or with spell cost but not duration limit
+ int32 duration = GetSpellDuration(spellInfo);
+ if ((spellInfo->manaCost || spellInfo->ManaCostPercentage || spellInfo->manaPerSecond) && duration > 0)
+ continue;
+
+ // allow only spell without cooldown > duration
+ int32 cooldown = GetSpellRecoveryTime(spellInfo);
+ if (cooldown >= 0 && duration >= 0 && cooldown > duration)
+ continue;
+ }
}
else
{
+ // just ignore non-combat spells
if (IsNonCombatSpell(spellInfo))
continue;
}
Spell *spell = new Spell(m_creature, spellInfo, false, 0);
- if(inCombat && !m_creature->hasUnitState(UNIT_STAT_FOLLOW) && spell->CanAutoCast(m_creature->getVictim()))
+ if (inCombat && !m_creature->hasUnitState(UNIT_STAT_FOLLOW) && spell->CanAutoCast(m_creature->getVictim()))
{
- m_targetSpellStore.push_back(std::make_pair<Unit*, Spell*>(m_creature->getVictim(), spell));
+ targetSpellStore.push_back(std::make_pair<Unit*, Spell*>(m_creature->getVictim(), spell));
continue;
}
else
@@ -165,7 +188,7 @@ void PetAI::UpdateAI(const uint32 diff)
if(spell->CanAutoCast(Target))
{
- m_targetSpellStore.push_back(std::make_pair<Unit*, Spell*>(Target, spell));
+ targetSpellStore.push_back(std::make_pair<Unit*, Spell*>(Target, spell));
spellUsed = true;
break;
}
@@ -176,14 +199,14 @@ void PetAI::UpdateAI(const uint32 diff)
}
//found units to cast on to
- if(!m_targetSpellStore.empty())
+ if (!targetSpellStore.empty())
{
- uint32 index = urand(0, m_targetSpellStore.size() - 1);
+ uint32 index = urand(0, targetSpellStore.size() - 1);
- Spell* spell = m_targetSpellStore[index].second;
- Unit* target = m_targetSpellStore[index].first;
+ Spell* spell = targetSpellStore[index].second;
+ Unit* target = targetSpellStore[index].first;
- m_targetSpellStore.erase(m_targetSpellStore.begin() + index);
+ targetSpellStore.erase(targetSpellStore.begin() + index);
SpellCastTargets targets;
targets.setUnitTarget( target );
@@ -202,11 +225,10 @@ void PetAI::UpdateAI(const uint32 diff)
spell->prepare(&targets);
}
- while (!m_targetSpellStore.empty())
- {
- delete m_targetSpellStore.begin()->second;
- m_targetSpellStore.erase(m_targetSpellStore.begin());
- }
+
+ // deleted cached Spell objects
+ for(TargetSpellList::const_iterator itr = targetSpellStore.begin(); itr != targetSpellStore.end(); ++itr)
+ delete itr->second;
}
}
diff --git a/src/game/PetAI.h b/src/game/PetAI.h
index 67ce6edefe3..918259cd098 100644
--- a/src/game/PetAI.h
+++ b/src/game/PetAI.h
@@ -50,9 +50,6 @@ class TRINITY_DLL_DECL PetAI : public CreatureAI
bool inCombat;
std::set<uint64> m_AllySet;
uint32 m_updateAlliesTimer;
-
- typedef std::pair<Unit*, Spell*> TargetSpellPair;
- std::vector<TargetSpellPair> m_targetSpellStore;
};
#endif
diff --git a/src/game/PetHandler.cpp b/src/game/PetHandler.cpp
index 3960b59d6d4..3de8ee028d3 100644
--- a/src/game/PetHandler.cpp
+++ b/src/game/PetHandler.cpp
@@ -37,17 +37,18 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )
CHECK_PACKET_SIZE(recv_data, 8+2+2+8);
uint64 guid1;
- uint16 spellid;
- uint16 flag;
+ uint32 data;
uint64 guid2;
recv_data >> guid1; //pet guid
- recv_data >> spellid;
- recv_data >> flag; //delete = 0x0700 CastSpell = C100
+ recv_data >> data;
recv_data >> guid2; //tag guid
+ uint32 spellid = UNIT_ACTION_BUTTON_ACTION(data);
+ uint8 flag = UNIT_ACTION_BUTTON_TYPE(data); //delete = 0x07 CastSpell = C1
+
// used also for charmed creature
Unit* pet= ObjectAccessor::GetUnit(*_player, guid1);
- sLog.outDetail("HandlePetAction.Pet %u flag is %u, spellid is %u, target %u.", uint32(GUID_LOPART(guid1)), flag, spellid, uint32(GUID_LOPART(guid2)) );
+ sLog.outDetail("HandlePetAction.Pet %u flag is %u, spellid is %u, target %u.", uint32(GUID_LOPART(guid1)), uint32(flag), spellid, uint32(GUID_LOPART(guid2)) );
if(!pet)
{
sLog.outError( "Pet %u not exist.", uint32(GUID_LOPART(guid1)) );
@@ -89,7 +90,7 @@ void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid
switch(flag)
{
- case ACT_COMMAND: //0x0700
+ case ACT_COMMAND: //0x07
switch(spellid)
{
case COMMAND_STAY: //flat=1792 //STAY
@@ -101,7 +102,7 @@ void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid
case COMMAND_FOLLOW: //spellid=1792 //FOLLOW
pet->AttackStop();
pet->InterruptNonMeleeSpells(false);
- pet->GetMotionMaster()->MoveFollow(_player,PET_FOLLOW_DIST,PET_FOLLOW_ANGLE);
+ pet->GetMotionMaster()->MoveFollow(_player,PET_FOLLOW_DIST,pet->GetFollowAngle());
charmInfo->SetCommandState( COMMAND_FOLLOW );
break;
case COMMAND_ATTACK: //spellid=1792 //ATTACK
@@ -151,7 +152,7 @@ void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid
pet->SendPetAIReaction(guid1);
}
}
- else // charmed player
+ else // charmed player
{
if(pet->getVictim() && pet->getVictim() != TargetUnit)
pet->AttackStop();
@@ -183,10 +184,10 @@ void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid
}
break;
default:
- sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", flag, spellid);
+ sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid);
}
break;
- case ACT_REACTION: // 0x600
+ case ACT_REACTION: // 0x6
switch(spellid)
{
case REACT_PASSIVE: //passive
@@ -197,9 +198,9 @@ void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid
break;
}
break;
- case ACT_DISABLED: // 0x8100 spell (disabled), ignore
- case ACT_PASSIVE: // 0x0100
- case ACT_ENABLED: // 0xC100 spell
+ case ACT_DISABLED: // 0x81 spell (disabled), ignore
+ case ACT_PASSIVE: // 0x01
+ case ACT_ENABLED: // 0xC1 spell
{
Unit* unit_target = NULL;
if (((Creature*)pet)->GetGlobalCooldown() > 0)
@@ -291,7 +292,7 @@ void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid
pet->SendPetCastFail(spellid, result);
if(!((Creature*)pet)->HasSpellCooldown(spellid))
- pet->SendPetClearCooldown(spellid);
+ GetPlayer()->SendClearCooldown(spellid, pet);
spell->finish(false);
delete spell;
@@ -299,7 +300,7 @@ void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid
break;
}
default:
- sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", flag, spellid);
+ sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid);
}
}
@@ -350,9 +351,6 @@ void WorldSession::HandlePetSetAction( WorldPacket & recv_data )
sLog.outDetail( "HandlePetSetAction. CMSG_PET_SET_ACTION" );
uint64 petguid;
- uint32 position;
- uint16 spell_id;
- uint16 act_state;
uint8 count;
recv_data >> petguid;
@@ -375,11 +373,16 @@ void WorldSession::HandlePetSetAction( WorldPacket & recv_data )
count = (recv_data.size() == 24) ? 2 : 1;
for(uint8 i = 0; i < count; ++i)
{
+ uint32 position;
+ uint32 data;
+
recv_data >> position;
- recv_data >> spell_id;
- recv_data >> act_state;
+ recv_data >> data;
- sLog.outDetail( "Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X", _player->GetName(), position, spell_id, act_state);
+ uint32 spell_id = UNIT_ACTION_BUTTON_ACTION(data);
+ uint8 act_state = UNIT_ACTION_BUTTON_TYPE(data);
+
+ sLog.outDetail( "Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X", _player->GetName(), position, spell_id, uint32(act_state));
//ignore invalid position
if(position >= MAX_UNIT_ACTION_BAR_INDEX)
@@ -435,9 +438,10 @@ void WorldSession::HandlePetRename( WorldPacket & recv_data )
pet->GetOwnerGUID() != _player->GetGUID() || !pet->GetCharmInfo() )
return;
- if(!ObjectMgr::IsValidPetName(name))
+ PetNameInvalidReason res = ObjectMgr::CheckPetName(name);
+ if(res != PET_NAME_SUCCESS)
{
- SendPetNameInvalid(PET_NAME_INVALID, name, NULL);
+ SendPetNameInvalid(res, name, NULL);
return;
}
@@ -497,6 +501,9 @@ void WorldSession::HandlePetAbandon( WorldPacket & recv_data )
recv_data >> guid; //pet guid
sLog.outDetail( "HandlePetAbandon. CMSG_PET_ABANDON pet guid is %u", GUID_LOPART(guid) );
+ if(!_player->IsInWorld())
+ return;
+
// pet/charmed
Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid);
if(pet)
@@ -551,10 +558,9 @@ void WorldSession::HandlePetSpellAutocastOpcode( WorldPacket& recvPacket )
sLog.outDetail("CMSG_PET_SPELL_AUTOCAST");
uint64 guid;
- uint16 spellid;
- uint16 spellid2; //maybe second spell, automatically toggled off when first toggled on?
+ uint32 spellid;
uint8 state; //1 for on, 0 for off
- recvPacket >> guid >> spellid >> spellid2 >> state;
+ recvPacket >> guid >> spellid >> state;
if(!_player->GetGuardianPet() && !_player->GetCharm())
return;
@@ -615,12 +621,6 @@ void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket )
return;
}
- if (caster->GetTypeId() == TYPEID_UNIT && ((Creature*)caster)->GetGlobalCooldown() > 0)
- {
- caster->SendPetCastFail(spellid, SPELL_FAILED_NOT_READY);
- return;
- }
-
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid);
if(!spellInfo)
{
@@ -628,6 +628,13 @@ void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket )
return;
}
+ if (spellInfo->StartRecoveryCategory > 0) //Check if spell is affected by GCD
+ if (caster->GetTypeId() == TYPEID_UNIT && ((Creature*)caster)->GetGlobalCooldown() > 0)
+ {
+ caster->SendPetCastFail(spellid, SPELL_FAILED_NOT_READY);
+ return;
+ }
+
// do not cast not learned spells
if(!caster->HasSpell(spellid) || IsPassiveSpell(spellid))
return;
@@ -669,12 +676,12 @@ void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket )
if(caster->GetTypeId() == TYPEID_PLAYER)
{
if(!((Player*)caster)->HasSpellCooldown(spellid))
- caster->SendPetClearCooldown(spellid);
+ GetPlayer()->SendClearCooldown(spellid, caster);
}
else
{
if(!((Creature*)caster)->HasSpellCooldown(spellid))
- caster->SendPetClearCooldown(spellid);
+ GetPlayer()->SendClearCooldown(spellid, caster);
}
spell->finish(false);
diff --git a/src/game/Player.cpp b/src/game/Player.cpp
index 17203faadde..8a3a4bffd93 100644
--- a/src/game/Player.cpp
+++ b/src/game/Player.cpp
@@ -316,10 +316,6 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa
m_nextSave = sWorld.getConfig(CONFIG_INTERVAL_SAVE);
- // randomize first save time in range [CONFIG_INTERVAL_SAVE] around [CONFIG_INTERVAL_SAVE]
- // this must help in case next save after mass player load after server startup
- m_nextSave = urand(m_nextSave/2,m_nextSave*3/2);
-
clearResurrectRequestData();
memset(m_items, 0, sizeof(Item*)*PLAYER_SLOTS_COUNT);
@@ -341,6 +337,11 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa
mSemaphoreTeleport_Near = false;
mSemaphoreTeleport_Far = false;
+ m_DelayedOperations = 0;
+ m_bCanDelayTeleport = false;
+ m_bHasDelayedTeleport = false;
+ m_teleport_options = 0;
+
pTrader = 0;
ClearTrade();
@@ -471,6 +472,8 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa
m_lastFallZ = 0;
m_ControlledByPlayer = true;
+
+ sWorld.IncreasePlayerCount();
}
Player::~Player ()
@@ -478,6 +481,10 @@ Player::~Player ()
// it must be unloaded already in PlayerLogout and accessed only for loggined player
//m_social = NULL;
+ // Player may still set map - remove it to correctly unload instances
+ if (FindMap())
+ ResetMap();
+
// Note: buy back item already deleted from DB when player was saved
for(uint8 i = 0; i < PLAYER_SLOTS_COUNT; ++i)
{
@@ -503,6 +510,8 @@ Player::~Player ()
delete m_declinedname;
delete m_runes;
+
+ sWorld.DecreasePlayerCount();
}
void Player::CleanupsBeforeDelete()
@@ -539,10 +548,6 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8
for (uint8 i = 0; i < PLAYER_SLOTS_COUNT; i++)
m_items[i] = NULL;
- m_race = race;
- m_class = class_;
-
- SetMapId(info->mapId);
Relocate(info->positionX,info->positionY,info->positionZ);
ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(class_);
@@ -552,32 +557,19 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8
return false;
}
+ SetMap(MapManager::Instance().CreateMap(info->mapId, this, 0));
+
uint8 powertype = cEntry->powerType;
SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, DEFAULT_WORLD_OBJECT_SIZE);
SetFloatValue(UNIT_FIELD_COMBATREACH, 1.5f);
- switch(gender)
- {
- case GENDER_FEMALE:
- SetDisplayId(info->displayId_f );
- SetNativeDisplayId(info->displayId_f );
- break;
- case GENDER_MALE:
- SetDisplayId(info->displayId_m );
- SetNativeDisplayId(info->displayId_m );
- break;
- default:
- sLog.outError("Invalid gender %u for player",gender);
- return false;
- break;
- }
-
- setFactionForRace(m_race);
+ setFactionForRace(race);
uint32 RaceClassGender = ( race ) | ( class_ << 8 ) | ( gender << 16 );
SetUInt32Value(UNIT_FIELD_BYTES_0, ( RaceClassGender | ( powertype << 24 ) ) );
+ InitDisplayIds();
SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP );
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE );
SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_REGENERATE_POWER);
@@ -676,8 +668,8 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8
// Played time
m_Last_tick = time(NULL);
- m_Played_time[0] = 0;
- m_Played_time[1] = 0;
+ m_Played_time[PLAYED_TIME_TOTAL] = 0;
+ m_Played_time[PLAYED_TIME_LEVEL] = 0;
// base stats and related field values
InitStatsForLevel();
@@ -707,21 +699,8 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8
learnDefaultSpells();
// original action bar
- std::list<uint16>::const_iterator action_itr[4];
- for(uint8 i=0; i<4; i++)
- action_itr[i] = info->action[i].begin();
-
- for (; action_itr[0]!=info->action[0].end() && action_itr[1]!=info->action[1].end();)
- {
- uint16 taction[4];
- for(uint8 i=0; i<4 ;i++)
- taction[i] = (*action_itr[i]);
-
- addActionButton((uint8)taction[0], taction[1], (uint8)taction[2], (uint8)taction[3]);
-
- for(uint8 i=0; i<4 ;i++)
- ++action_itr[i];
- }
+ for (PlayerCreateInfoActions::const_iterator action_itr = info->action.begin(); action_itr != info->action.end(); ++action_itr)
+ addActionButton(action_itr->button,action_itr->action,action_itr->type);
// original items
CharStartOutfitEntry const* oEntry = NULL;
@@ -746,7 +725,6 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8
uint32 item_id = oEntry->ItemId[j];
-
// Hack for not existed item id in dbc 3.0.3
if(item_id==40582)
continue;
@@ -758,22 +736,23 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8
continue;
}
- // max stack by default (mostly 1), 1 for infinity stackable
- uint32 count = iProto->Stackable > 0 ? uint32(iProto->Stackable) : 1;
+ // BuyCount by default
+ uint32 count = iProto->BuyCount;
+ // special amount for foor/drink
if(iProto->Class==ITEM_CLASS_CONSUMABLE && iProto->SubClass==ITEM_SUBCLASS_FOOD)
{
switch(iProto->Spells[0].SpellCategory)
{
case 11: // food
- if(iProto->Stackable > 4)
- count = 4;
+ count = getClass()==CLASS_DEATH_KNIGHT ? 10 : 4;
break;
case 59: // drink
- if(iProto->Stackable > 2)
- count = 2;
+ count = 2;
break;
}
+ if(iProto->Stackable < count)
+ count = iProto->Stackable;
}
StoreNewItemInBestSlots(item_id, count);
@@ -1138,7 +1117,10 @@ void Player::Update( uint32 p_time )
// Having this would prevent more aura charges to be dropped, so let's crash
assert (!m_spellModTakingSpell);
+ //used to implement delayed far teleports
+ SetCanDelayTeleport(true);
Unit::Update( p_time );
+ SetCanDelayTeleport(false);
time_t now = time (NULL);
@@ -1346,8 +1328,8 @@ void Player::Update( uint32 p_time )
{
if (p_time >= m_DetectInvTimer)
{
- m_DetectInvTimer = 3000;
HandleStealthedUnitsDetection();
+ m_DetectInvTimer = 3000;
}
else
m_DetectInvTimer -= p_time;
@@ -1357,8 +1339,8 @@ void Player::Update( uint32 p_time )
if (now > m_Last_tick)
{
uint32 elapsed = uint32(now - m_Last_tick);
- m_Played_time[0] += elapsed; // Total played time
- m_Played_time[1] += elapsed; // Level played time
+ m_Played_time[PLAYED_TIME_TOTAL] += elapsed; // Total played time
+ m_Played_time[PLAYED_TIME_LEVEL] += elapsed; // Level played time
m_Last_tick = now;
}
@@ -1394,8 +1376,12 @@ void Player::Update( uint32 p_time )
//if(pet && !IsWithinDistInMap(pet, OWNER_MAX_DISTANCE) && (GetCharmGUID() && (pet->GetGUID() != GetCharmGUID())))
{
RemovePet(pet, PET_SAVE_NOT_IN_SLOT, true);
- return;
}
+
+ //we should execute delayed teleports only for alive(!) players
+ //because we don't want player's ghost teleported from graveyard
+ if(IsHasDelayedTeleport() && isAlive())
+ TeleportTo(m_teleport_dest, m_teleport_options);
}
void Player::setDeathState(DeathState s)
@@ -1452,53 +1438,67 @@ void Player::setDeathState(DeathState s)
}
}
-void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
+bool Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
{
+ // 0 1 2 3 4 5 6 7
+ // "SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.playerBytes, characters.playerBytes2, characters.level, "
+ // 8 9 10 11 12 13 14
+ // "characters.zone, characters.map, characters.position_x, characters.position_y, characters.position_z, guild_member.guildid, characters.playerFlags, "
+ // 15 16 17 18 19 20
+ // "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.data, character_declinedname.genitive "
+
Field *fields = result->Fetch();
- *p_data << uint64(GetGUID());
- *p_data << m_name;
+ uint32 guid = fields[0].GetUInt32();
+ uint8 pRace = fields[2].GetUInt8();
+ uint8 pClass = fields[3].GetUInt8();
- *p_data << uint8(getRace());
- uint8 pClass = getClass();
- *p_data << uint8(pClass);
- *p_data << uint8(getGender());
+ PlayerInfo const *info = objmgr.GetPlayerInfo(pRace, pClass);
+ if(!info)
+ {
+ sLog.outError("Player %u has incorrect race/class pair. Don't build enum.", guid);
+ return false;
+ }
+
+ *p_data << uint64(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER));
+ *p_data << fields[1].GetString(); // name
+ *p_data << uint8(pRace); // race
+ *p_data << uint8(pClass); // class
+ *p_data << uint8(fields[4].GetUInt8()); // gender
- uint32 bytes = GetUInt32Value(PLAYER_BYTES);
- *p_data << uint8(bytes);
- *p_data << uint8(bytes >> 8);
- *p_data << uint8(bytes >> 16);
- *p_data << uint8(bytes >> 24);
+ uint32 playerBytes = fields[5].GetUInt32();
+ *p_data << uint8(playerBytes); // skin
+ *p_data << uint8(playerBytes >> 8); // face
+ *p_data << uint8(playerBytes >> 16); // hair style
+ *p_data << uint8(playerBytes >> 24); // hair color
- bytes = GetUInt32Value(PLAYER_BYTES_2);
- *p_data << uint8(bytes);
+ uint32 playerBytes2 = fields[6].GetUInt32();
+ *p_data << uint8(playerBytes2 & 0xFF); // facial hair
- *p_data << uint8(getLevel()); // player level
- // do not use GetMap! it will spawn a new instance since the bound instances are not loaded
- uint32 zoneId = fields[10].GetUInt32();
- sLog.outDebug("Player::BuildEnumData: map:%u, x:%f, y:%f, z:%f zone:%u", GetMapId(), GetPositionX(), GetPositionY(), GetPositionZ(), zoneId);
- *p_data << uint32(zoneId);
- *p_data << uint32(GetMapId());
+ *p_data << uint8(fields[7].GetUInt8()); // level
+ *p_data << uint32(fields[8].GetUInt32()); // zone
+ *p_data << uint32(fields[9].GetUInt32()); // map
- *p_data << GetPositionX();
- *p_data << GetPositionY();
- *p_data << GetPositionZ();
+ *p_data << fields[10].GetFloat(); // x
+ *p_data << fields[11].GetFloat(); // y
+ *p_data << fields[12].GetFloat(); // z
- // guild id
- *p_data << uint32(fields[14].GetUInt32());
+ *p_data << uint32(fields[13].GetUInt32()); // guild id
uint32 char_flags = 0;
- if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM))
+ uint32 playerFlags = fields[14].GetUInt32();
+ uint32 atLoginFlags = fields[15].GetUInt32();
+ if(playerFlags & PLAYER_FLAGS_HIDE_HELM)
char_flags |= CHARACTER_FLAG_HIDE_HELM;
- if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK))
+ if(playerFlags & PLAYER_FLAGS_HIDE_CLOAK)
char_flags |= CHARACTER_FLAG_HIDE_CLOAK;
- if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))
+ if(playerFlags & PLAYER_FLAGS_GHOST)
char_flags |= CHARACTER_FLAG_GHOST;
- if(HasAtLoginFlag(AT_LOGIN_RENAME))
+ if(atLoginFlags & AT_LOGIN_RENAME)
char_flags |= CHARACTER_FLAG_RENAME;
if(sWorld.getConfig(CONFIG_DECLINED_NAMES_USED))
{
- if(!fields[15].GetCppString().empty())
+ if(!fields[20].GetCppString().empty())
char_flags |= CHARACTER_FLAG_DECLINED;
}
else
@@ -1506,7 +1506,7 @@ void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
*p_data << uint32(char_flags); // character flags
// character customize (flags?)
- *p_data << uint32(HasAtLoginFlag(AT_LOGIN_CUSTOMIZE) ? 1 : 0);
+ *p_data << uint32(atLoginFlags & AT_LOGIN_CUSTOMIZE ? 1 : 0);
*p_data << uint8(1); // unknown
// Pets info
@@ -1515,15 +1515,15 @@ void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
uint32 petLevel = 0;
uint32 petFamily = 0;
- // show pet at selection character in character list only for non-ghost character
- if (result && isAlive() && (pClass == CLASS_WARLOCK || pClass == CLASS_HUNTER || pClass == CLASS_DEATH_KNIGHT))
+ // show pet at selection character in character list only for non-ghost character
+ if (result && !(playerFlags & PLAYER_FLAGS_GHOST) && (pClass == CLASS_WARLOCK || pClass == CLASS_HUNTER || pClass == CLASS_DEATH_KNIGHT))
{
- uint32 entry = fields[11].GetUInt32();
+ uint32 entry = fields[16].GetUInt32();
CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(entry);
if(cInfo)
{
- petDisplayId = fields[12].GetUInt32();
- petLevel = fields[13].GetUInt32();
+ petDisplayId = fields[17].GetUInt32();
+ petLevel = fields[18].GetUInt32();
petFamily = cInfo->family;
}
}
@@ -1533,36 +1533,45 @@ void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
*p_data << uint32(petFamily);
}
+ // TODO: do not access data field here
+ Tokens data = StrSplit(fields[19].GetCppString(), " ");
+
for (uint8 slot = 0; slot < EQUIPMENT_SLOT_END; slot++)
{
uint32 visualbase = PLAYER_VISIBLE_ITEM_1_ENTRYID + (slot * 2);
- uint32 item_id = GetUInt32Value(visualbase);
+ uint32 item_id = GetUInt32ValueFromArray(data, visualbase);
const ItemPrototype * proto = objmgr.GetItemPrototype(item_id);
+ if(!proto)
+ {
+ *p_data << uint32(0);
+ *p_data << uint8(0);
+ *p_data << uint32(0);
+ continue;
+ }
+
SpellItemEnchantmentEntry const *enchant = NULL;
+ uint32 enchants = GetUInt32ValueFromArray(data, visualbase + 1);
for(uint8 enchantSlot = PERM_ENCHANTMENT_SLOT; enchantSlot <= TEMP_ENCHANTMENT_SLOT; ++enchantSlot)
{
- uint32 enchantId = GetUInt16Value(visualbase + 1, enchantSlot);
+ // values stored in 2 uint16
+ uint32 enchantId = 0x0000FFFF & (enchants >> enchantSlot*16);
+ if(!enchantId)
+ continue;
+
if(enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId))
break;
}
- if (proto != NULL)
- {
- *p_data << uint32(proto->DisplayInfoID);
- *p_data << uint8(proto->InventoryType);
- *p_data << uint32(enchant ? enchant->aura_id : 0);
- }
- else
- {
- *p_data << uint32(0);
- *p_data << uint8(0);
- *p_data << uint32(0); // enchant?
- }
+ *p_data << uint32(proto->DisplayInfoID);
+ *p_data << uint8(proto->InventoryType);
+ *p_data << uint32(enchant ? enchant->aura_id : 0);
}
*p_data << uint32(0); // first bag display id
*p_data << uint8(0); // first bag inventory type
*p_data << uint32(0); // enchant?
+
+ return true;
}
bool Player::ToggleAFK()
@@ -1611,6 +1620,27 @@ void Player::SendTeleportAckMsg()
GetSession()->SendPacket(&data);
}
+void Player::TeleportOutOfMap(Map *oldMap)
+{
+ while(IsBeingTeleportedFar())
+ GetSession()->HandleMoveWorldportAckOpcode();
+
+ if(FindMap() != oldMap)
+ return;
+
+ TeleportTo(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, GetOrientation());
+
+ while(IsBeingTeleportedFar())
+ GetSession()->HandleMoveWorldportAckOpcode();
+
+ if(FindMap() == oldMap)
+ {
+ sLog.outCrash("Cannot teleport player out of map!");
+ ResetMap();
+ assert(false);
+ }
+}
+
bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options)
{
if(!MapManager::IsValidMapCoord(mapid, x, y, z, orientation))
@@ -1683,6 +1713,21 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
if ((GetMapId() == mapid) && (!m_transport))
{
+ //lets reset far teleport flag if it wasn't reset during chained teleports
+ SetSemaphoreTeleportFar(false);
+ //setup delayed teleport flag
+ SetDelayedTeleportFlag(IsCanDelayTeleport());
+ //if teleport spell is casted in Unit::Update() func
+ //then we need to delay it until update process will be finished
+ if(IsHasDelayedTeleport())
+ {
+ SetSemaphoreTeleportNear(true);
+ //lets save teleport destination for player
+ m_teleport_dest = WorldLocation(mapid, x, y, z, orientation);
+ m_teleport_options = options;
+ return true;
+ }
+
if (!(options & TELE_TO_NOT_UNSUMMON_PET))
{
//same map, only remove pet if out of range for new position
@@ -1697,7 +1742,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
m_teleport_dest = WorldLocation(mapid, x, y, z, orientation);
SetFallInformation(0, z);
- // code for finish transfer called in WorldSession::HandleMovementOpcodes()
+ // code for finish transfer called in WorldSession::HandleMovementOpcodes()
// at client packet MSG_MOVE_TELEPORT_ACK
SetSemaphoreTeleportNear(true);
// near teleport, triggering send MSG_MOVE_TELEPORT_ACK from client at landing
@@ -1712,6 +1757,10 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
}
else
{
+ if(getClass() == CLASS_DEATH_KNIGHT && GetMapId() == 609 && !isGameMaster()
+ && !IsActiveQuest(13165))
+ return false;
+
// far teleport to another map
Map* oldmap = IsInWorld() ? GetMap() : NULL;
// check if we can enter before stopping combat / removing pet / totems / interrupting spells
@@ -1726,6 +1775,21 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
Map *map = MapManager::Instance().FindMap(mapid);
if (!map || map->CanEnter(this))
{
+ //lets reset near teleport flag if it wasn't reset during chained teleports
+ SetSemaphoreTeleportNear(false);
+ //setup delayed teleport flag
+ SetDelayedTeleportFlag(IsCanDelayTeleport());
+ //if teleport spell is casted in Unit::Update() func
+ //then we need to delay it until update process will be finished
+ if(IsHasDelayedTeleport())
+ {
+ SetSemaphoreTeleportFar(true);
+ //lets save teleport destination for player
+ m_teleport_dest = WorldLocation(mapid, x, y, z, orientation);
+ m_teleport_options = options;
+ return true;
+ }
+
SetSelection(0);
CombatStop();
@@ -1755,6 +1819,9 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
if(IsNonMeleeSpellCasted(true))
InterruptNonMeleeSpells(true);
+ //remove auras before removing from map...
+ RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CHANGE_MAP | AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_TURNING);
+
if(!GetSession()->PlayerLogout())
{
// send transfer packets
@@ -1801,8 +1868,6 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
// if the player is saved before worldportack (at logout for example)
// this will be used instead of the current location in SaveToDB
- RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CHANGE_MAP | AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_TURNING);
-
// move packet sent by client always after far teleport
// code for finish transfer to new map called in WorldSession::HandleMoveWorldportAckOpcode at client packet
SetSemaphoreTeleportFar(true);
@@ -1813,6 +1878,53 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
return true;
}
+void Player::ProcessDelayedOperations()
+{
+ if(m_DelayedOperations == 0)
+ return;
+
+ if(m_DelayedOperations & DELAYED_RESURRECT_PLAYER)
+ {
+ ResurrectPlayer(0.0f, false);
+
+ if(GetMaxHealth() > m_resurrectHealth)
+ SetHealth( m_resurrectHealth );
+ else
+ SetHealth( GetMaxHealth() );
+
+ if(GetMaxPower(POWER_MANA) > m_resurrectMana)
+ SetPower(POWER_MANA, m_resurrectMana );
+ else
+ SetPower(POWER_MANA, GetMaxPower(POWER_MANA) );
+
+ SetPower(POWER_RAGE, 0 );
+ SetPower(POWER_ENERGY, GetMaxPower(POWER_ENERGY) );
+
+ SpawnCorpseBones();
+ }
+
+ if(m_DelayedOperations & DELAYED_SAVE_PLAYER)
+ {
+ SaveToDB();
+ }
+
+ if(m_DelayedOperations & DELAYED_SPELL_CAST_DESERTER)
+ {
+ CastSpell(this, 26013, true); // Deserter
+ }
+
+ //we have executed ALL delayed ops, so clear the flag
+ m_DelayedOperations = 0;
+}
+
+void Player::ScheduleDelayedOperation(uint32 operation)
+{
+ if(operation >= DELAYED_END)
+ return;
+
+ m_DelayedOperations |= operation;
+}
+
void Player::AddToWorld()
{
///- Do not add/remove the player from the object storage
@@ -1863,33 +1975,6 @@ void Player::RemoveFromWorld()
}
}
-void Player::RewardRage( uint32 damage, uint32 weaponSpeedHitFactor, bool attacker )
-{
- float addRage;
-
- float rageconversion = ((0.0091107836 * getLevel()*getLevel())+3.225598133*getLevel())+4.2652911;
-
- if(attacker)
- {
- addRage = ((damage/rageconversion*7.5 + weaponSpeedHitFactor)/2);
-
- // talent who gave more rage on attack
- addRage *= 1.0f + GetTotalAuraModifier(SPELL_AURA_MOD_RAGE_FROM_DAMAGE_DEALT) / 100.0f;
- }
- else
- {
- addRage = damage/rageconversion*2.5;
-
- // Berserker Rage effect
- if(HasAura(18499))
- addRage *= 1.3;
- }
-
- addRage *= sWorld.getRate(RATE_POWER_RAGE_INCOME);
-
- ModifyPower(POWER_RAGE, uint32(addRage*10));
-}
-
void Player::RegenerateAll()
{
if (m_regenTimer != 0)
@@ -2372,9 +2457,12 @@ void Player::GiveLevel(uint32 level)
SetUInt32Value(PLAYER_NEXT_LEVEL_XP, objmgr.GetXPForLevel(level));
//update level, max level of skills
- if(getLevel()!= level)
- m_Played_time[1] = 0; // Level Played Time reset
+ m_Played_time[PLAYED_TIME_LEVEL] = 0; // Level Played Time reset
+
+ _ApplyAllLevelScaleItemMods(false);
+
SetLevel(level);
+
UpdateSkillsForLevel ();
// save base values (bonuses already included in stored stats
@@ -2402,6 +2490,8 @@ void Player::GiveLevel(uint32 level)
SetPower(POWER_FOCUS, 0);
SetPower(POWER_HAPPINESS, 0);
+ _ApplyAllLevelScaleItemMods(true);
+
// update level to hunter/summon pet
if (Pet* pet = GetPet())
pet->SynchronizeLevelWithOwner();
@@ -2603,7 +2693,7 @@ void Player::InitStatsForLevel(bool reapplyMods)
void Player::SendInitialSpells()
{
time_t curTime = time(NULL);
- time_t infTime = curTime + MONTH/2;
+ time_t infTime = curTime + infinityCooldownDelayCheck;
uint16 spellCount = 0;
@@ -2637,18 +2727,21 @@ void Player::SendInitialSpells()
if(!sEntry)
continue;
- // not send infinity cooldown
- if(itr->second.end > infTime)
- continue;
-
data << uint32(itr->first);
- time_t cooldown = 0;
- if(itr->second.end > curTime)
- cooldown = (itr->second.end-curTime)*IN_MILISECONDS;
-
data << uint16(itr->second.itemid); // cast item id
data << uint16(sEntry->Category); // spell category
+
+ // send infinity cooldown in special format
+ if(itr->second.end >= infTime)
+ {
+ data << uint32(1); // cooldown
+ data << uint32(0x80000000); // category cooldown
+ continue;
+ }
+
+ time_t cooldown = itr->second.end > curTime ? (itr->second.end-curTime)*IN_MILISECONDS : 0;
+
if(sEntry->Category) // may be wrong, but anyway better than nothing...
{
data << uint32(0); // cooldown
@@ -2897,7 +2990,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen
if(!rankSpellId || rankSpellId==spell_id)
continue;
- removeSpell(rankSpellId);
+ removeSpell(rankSpellId,false,false);
}
}
}
@@ -3125,7 +3218,6 @@ bool Player::IsNeedCastPassiveSpellAtLearn(SpellEntry const* spellInfo) const
switch(spellInfo->Id)
{
// some spells not have stance data expected cast at form change or present
- case 5420: need_cast = (m_form == FORM_TREE); break;
case 5419: need_cast = (m_form == FORM_TRAVEL); break;
case 7376: need_cast = (m_form == FORM_DEFENSIVESTANCE); break;
case 7381: need_cast = (m_form == FORM_BERSERKERSTANCE); break;
@@ -3173,7 +3265,7 @@ void Player::learnSpell(uint32 spell_id, bool dependent)
GetSession()->SendPacket(&data);
}
-void Player::removeSpell(uint32 spell_id, bool disabled, bool update_action_bar_for_low_rank)
+void Player::removeSpell(uint32 spell_id, bool disabled, bool learn_low_rank)
{
PlayerSpellMap::iterator itr = m_spells.find(spell_id);
if (itr == m_spells.end())
@@ -3193,7 +3285,7 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool update_action_bar_
SpellsRequiringSpellMap const& reqMap = spellmgr.GetSpellsRequiringSpell();
SpellsRequiringSpellMap::const_iterator itr2 = reqMap.find(spell_id);
for (uint32 i=reqMap.count(spell_id);i>0;i--,itr2++)
- removeSpell(itr2->second,disabled);
+ removeSpell(itr2->second,disabled,false);
// re-search, it can be corrupted in prev loop
itr = m_spells.find(spell_id);
@@ -3223,8 +3315,9 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool update_action_bar_
RemoveAurasDueToSpell(spell_id);
// remove pet auras
- if(PetAura const* petSpell = spellmgr.GetPetAura(spell_id))
- RemovePetAura(petSpell);
+ for(int i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ if(PetAura const* petSpell = spellmgr.GetPetAura(spell_id, i))
+ RemovePetAura(petSpell);
// free talent points
uint32 talentCosts = GetTalentSpellCost(spell_id);
@@ -3321,15 +3414,17 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool update_action_bar_
{
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id);
- // if talent then lesser rank also talent and need learn
+ // if talent then lesser rank also talent and need learn
if(talentCosts)
{
- //learnSpell (prev_id,false);
+ // I cannot see why mangos has these lines.
+ //if(learn_low_rank)
+ // learnSpell (prev_id,false);
}
- // if ranked non-stackable spell: need activate lesser rank and update dendence state
+ // if ranked non-stackable spell: need activate lesser rank and update dendence state
else if(cur_active && !SpellMgr::canStackSpellRanks(spellInfo) && spellmgr.GetSpellRank(spellInfo->Id) != 0)
{
- // need manually update dependence state (learn spell ignore like attempts)
+ // need manually update dependence state (learn spell ignore like attempts)
PlayerSpellMap::iterator prev_itr = m_spells.find(prev_id);
if (prev_itr != m_spells.end())
{
@@ -3341,19 +3436,16 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool update_action_bar_
}
// now re-learn if need re-activate
- if(cur_active && !prev_itr->second->active)
+ if(cur_active && !prev_itr->second->active && learn_low_rank)
{
if(addSpell(prev_id,true,false,prev_itr->second->dependent,prev_itr->second->disabled))
{
- if(update_action_bar_for_low_rank)
- {
- // downgrade spell ranks in spellbook and action bar
- WorldPacket data(SMSG_SUPERCEDED_SPELL, 4 + 4);
- data << uint32(spell_id);
- data << uint32(prev_id);
- GetSession()->SendPacket( &data );
- prev_activate = true;
- }
+ // downgrade spell ranks in spellbook and action bar
+ WorldPacket data(SMSG_SUPERCEDED_SPELL, 4 + 4);
+ data << uint32(spell_id);
+ data << uint32(prev_id);
+ GetSession()->SendPacket( &data );
+ prev_activate = true;
}
}
}
@@ -3374,14 +3466,10 @@ void Player::RemoveSpellCooldown( uint32 spell_id, bool update /* = false */ )
m_spellCooldowns.erase(spell_id);
if(update)
- {
- WorldPacket data(SMSG_CLEAR_COOLDOWN, 4+8);
- data << uint32(spell_id);
- data << uint64(GetGUID());
- SendDirectMessage(&data);
- }
+ SendClearCooldown(spell_id, this);
}
+// I am not sure which one is more efficient
void Player::RemoveCategoryCooldown( uint32 cat )
{
SpellCategoryStore::const_iterator i_scstore = sSpellCategoryStore.find(cat);
@@ -3390,6 +3478,22 @@ void Player::RemoveCategoryCooldown( uint32 cat )
RemoveSpellCooldown(*i_scset, true);
}
+void Player::RemoveSpellCategoryCooldown(uint32 cat, bool update /* = false */)
+{
+ SpellCategoryStore::const_iterator ct = sSpellCategoryStore.find(cat);
+ if (ct == sSpellCategoryStore.end())
+ return;
+
+ const SpellCategorySet& ct_set = ct->second;
+ for (SpellCooldowns::const_iterator i = m_spellCooldowns.begin(); i != m_spellCooldowns.end();)
+ {
+ if (ct_set.find(i->first) != ct_set.end())
+ RemoveSpellCooldown((i++)->first, update);
+ else
+ ++i;
+ }
+}
+
void Player::RemoveArenaSpellCooldowns()
{
// remove cooldowns on spells that has < 15 min CD
@@ -3405,13 +3509,8 @@ void Player::RemoveArenaSpellCooldowns()
entry->RecoveryTime <= 15 * MINUTE * IN_MILISECONDS &&
entry->CategoryRecoveryTime <= 15 * MINUTE * IN_MILISECONDS )
{
- // notify player
- WorldPacket data(SMSG_CLEAR_COOLDOWN, 4+8);
- data << uint32(itr->first);
- data << uint64(GetGUID());
- GetSession()->SendPacket(&data);
- // remove cooldown
- m_spellCooldowns.erase(itr);
+ // remove & notify
+ RemoveSpellCooldown(itr->first, true);
}
}
}
@@ -3421,12 +3520,8 @@ void Player::RemoveAllSpellCooldown()
if(!m_spellCooldowns.empty())
{
for(SpellCooldowns::const_iterator itr = m_spellCooldowns.begin();itr != m_spellCooldowns.end(); ++itr)
- {
- WorldPacket data(SMSG_CLEAR_COOLDOWN, 4+8);
- data << uint32(itr->first);
- data << uint64(GetGUID());
- GetSession()->SendPacket(&data);
- }
+ SendClearCooldown(itr->first, this);
+
m_spellCooldowns.clear();
}
}
@@ -3451,7 +3546,7 @@ void Player::_LoadSpellCooldowns(QueryResult *result)
if(!sSpellStore.LookupEntry(spell_id))
{
- sLog.outError("Player %u have unknown spell %u in `character_spell_cooldown`, skipping.",GetGUIDLow(),spell_id);
+ sLog.outError("Player %u has unknown spell %u in `character_spell_cooldown`, skipping.",GetGUIDLow(),spell_id);
continue;
}
@@ -3474,7 +3569,7 @@ void Player::_SaveSpellCooldowns()
CharacterDatabase.PExecute("DELETE FROM character_spell_cooldown WHERE guid = '%u'", GetGUIDLow());
time_t curTime = time(NULL);
- time_t infTime = curTime + MONTH/2;
+ time_t infTime = curTime + infinityCooldownDelayCheck;
// remove outdated and save active
for(SpellCooldowns::iterator itr = m_spellCooldowns.begin();itr != m_spellCooldowns.end();)
@@ -3528,10 +3623,7 @@ bool Player::resetTalents(bool no_cost)
{
// not need after this call
if(HasAtLoginFlag(AT_LOGIN_RESET_TALENTS))
- {
- m_atLoginFlags = m_atLoginFlags & ~AT_LOGIN_RESET_TALENTS;
- CharacterDatabase.PExecute("UPDATE characters set at_login = at_login & ~ %u WHERE guid ='%u'", uint32(AT_LOGIN_RESET_TALENTS), GetGUIDLow());
- }
+ RemoveAtLoginFlag(AT_LOGIN_RESET_TALENTS,true);
uint32 talentPointsForLevel = CalculateTalentsPoints();
@@ -3585,7 +3677,13 @@ bool Player::resetTalents(bool no_cost)
uint32 itrFirstId = spellmgr.GetFirstSpellInChain(itr->first);
// unlearn if first rank is talent or learned by talent
- if (itrFirstId == talentInfo->RankID[j] || spellmgr.IsSpellLearnToSpell(talentInfo->RankID[j],itrFirstId))
+ if (itrFirstId == talentInfo->RankID[j])
+ {
+ removeSpell(itr->first,!IsPassiveSpell(itr->first),false);
+ itr = GetSpellMap().begin();
+ continue;
+ }
+ else if (spellmgr.IsSpellLearnToSpell(talentInfo->RankID[j],itrFirstId))
{
removeSpell(itr->first,!IsPassiveSpell(itr->first));
itr = GetSpellMap().begin();
@@ -3791,9 +3889,9 @@ void Player::BuildCreateUpdateBlockForPlayer( UpdateData *data, Player *target )
Unit::BuildCreateUpdateBlockForPlayer( data, target );
}
-void Player::DestroyForPlayer( Player *target ) const
+void Player::DestroyForPlayer( Player *target, bool anim ) const
{
- Unit::DestroyForPlayer( target );
+ Unit::DestroyForPlayer( target, anim );
for(uint8 i = 0; i < INVENTORY_SLOT_BAG_END; i++)
{
@@ -4036,7 +4134,7 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC
CharacterDatabase.PExecute("DELETE FROM character_equipmentsets WHERE guid = '%u'",guid);
CharacterDatabase.CommitTransaction();
- //LoginDatabase.PExecute("UPDATE realmcharacters SET numchars = numchars - 1 WHERE acctid = %d AND realmid = %d", accountId, realmID);
+ //loginDatabase.PExecute("UPDATE realmcharacters SET numchars = numchars - 1 WHERE acctid = %d AND realmid = %d", accountId, realmID);
if(updateRealmChars) sWorld.UpdateRealmCharCount(accountId);
}
@@ -4458,7 +4556,7 @@ uint32 Player::DurabilityRepair(uint16 pos, bool cost, float discountMod, bool g
uint32 dmultiplier = dcost->multiplier[ItemSubClassToDurabilityMultiplierId(ditemProto->Class,ditemProto->SubClass)];
uint32 costs = uint32(LostDurability*dmultiplier*double(dQualitymodEntry->quality_mod));
- costs = uint32(costs * discountMod);
+ costs = uint32(costs * discountMod) * sWorld.getRate(RATE_REPAIRCOST);
if (costs==0) //fix for ITEM_QUALITY_ARTIFACT
costs = 1;
@@ -5214,6 +5312,9 @@ void Player::UpdateWeaponSkill (WeaponAttackType attType)
if(m_form == FORM_TREE)
return; // use weapon but not skill up
+ if(pVictim && pVictim->GetTypeId() == TYPEID_UNIT && (((Creature*)pVictim)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_SKILLGAIN))
+ return;
+
uint32 weapon_skill_gain = sWorld.getConfig(CONFIG_SKILL_GAIN_WEAPON);
switch(attType)
@@ -5557,65 +5658,69 @@ void Player::SendInitialActionButtons() const
sLog.outDetail( "Initializing Action Buttons for '%u'", GetGUIDLow() );
WorldPacket data(SMSG_ACTION_BUTTONS, 1+(MAX_ACTION_BUTTONS*4));
- data << uint8(0); // can be 0, 1, 2
+ data << uint8(0); // can be 0, 1, 2 (talent spec)
for(int button = 0; button < MAX_ACTION_BUTTONS; ++button)
{
ActionButtonList::const_iterator itr = m_actionButtons.find(button);
if(itr != m_actionButtons.end() && itr->second.uState != ACTIONBUTTON_DELETED)
- {
- data << uint16(itr->second.action);
- data << uint8(itr->second.misc);
- data << uint8(itr->second.type);
- }
+ data << uint32(itr->second.packedData);
else
- {
data << uint32(0);
- }
}
GetSession()->SendPacket( &data );
sLog.outDetail( "Action Buttons for '%u' Initialized", GetGUIDLow() );
}
-bool Player::addActionButton(const uint8 button, const uint16 action, const uint8 type, const uint8 misc)
+ActionButton* Player::addActionButton(uint8 button, uint32 action, uint8 type)
{
if(button >= MAX_ACTION_BUTTONS)
{
sLog.outError( "Action %u not added into button %u for player %s: button must be < 132", action, button, GetName() );
- return false;
+ return NULL;
}
- // check cheating with adding non-known spells to action bar
- if(type==ACTION_BUTTON_SPELL)
+ if(action >= MAX_ACTION_BUTTON_ACTION_VALUE)
{
- if(!sSpellStore.LookupEntry(action))
- {
- sLog.outError( "Action %u not added into button %u for player %s: spell not exist", action, button, GetName() );
- return false;
- }
-
- if(!HasSpell(action))
- {
- sLog.outError( "Action %u not added into button %u for player %s: player don't known this spell", action, button, GetName() );
- return false;
- }
+ sLog.outError( "Action %u not added into button %u for player %s: action must be < %u", action, button, GetName(), MAX_ACTION_BUTTON_ACTION_VALUE );
+ return NULL;
}
- ActionButtonList::iterator buttonItr = m_actionButtons.find(button);
+ switch(type)
+ {
+ case ACTION_BUTTON_SPELL:
+ if(!sSpellStore.LookupEntry(action))
+ {
+ sLog.outError( "Action %u not added into button %u for player %s: spell not exist", action, button, GetName() );
+ return NULL;
+ }
- if (buttonItr==m_actionButtons.end())
- { // just add new button
- m_actionButtons[button] = ActionButton(action,type,misc);
+ if(!HasSpell(action))
+ {
+ sLog.outError( "Action %u not added into button %u for player %s: player don't known this spell", action, button, GetName() );
+ return NULL;
+ }
+ break;
+ case ACTION_BUTTON_ITEM:
+ if(!objmgr.GetItemPrototype(action))
+ {
+ sLog.outError( "Action %u not added into button %u for player %s: item not exist", action, button, GetName() );
+ return NULL;
+ }
+ break;
+ default:
+ break; // pther cases not checked at this moment
}
- else
- { // change state of current button
- ActionButtonUpdateState uState = buttonItr->second.uState;
- buttonItr->second = ActionButton(action,type,misc);
- if (uState != ACTIONBUTTON_NEW) buttonItr->second.uState = ACTIONBUTTON_CHANGED;
- };
- sLog.outDetail( "Player '%u' Added Action '%u' to Button '%u'", GetGUIDLow(), action, button );
- return true;
+
+ // it create new button (NEW state) if need or return existed
+ ActionButton& ab = m_actionButtons[button];
+
+ // set data and update to CHANGED if not NEW
+ ab.SetActionAndType(action,ActionButtonType(type));
+
+ sLog.outDetail( "Player '%u' Added Action '%u' (type %u) to Button '%u'", GetGUIDLow(), action, uint32(type), button );
+ return &ab;
}
void Player::removeActionButton(uint8 button)
@@ -5883,7 +5988,7 @@ int32 Player::CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, in
if (percent <= 0.0f)
return 0;
- return int32(rep*percent*0.01f);
+ return int32(rep*percent)/100;
}
//Calculates how many reputation points player gains in victim's enemy factions
@@ -6010,7 +6115,7 @@ bool Player::RewardHonor(Unit *uVictim, uint32 groupsize, float honor, bool pvpt
}
// 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
- if(GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
+ if(HasAura(SPELL_AURA_PLAYER_INACTIVE))
return false;
uint64 victim_guid = 0;
@@ -6259,6 +6364,19 @@ uint32 Player::GetZoneIdFromDB(uint64 guid)
return zone;
}
+uint32 Player::GetLevelFromDB(uint64 guid)
+{
+ QueryResult *result = CharacterDatabase.PQuery( "SELECT level FROM characters WHERE guid='%u'", GUID_LOPART(guid) );
+ if (!result)
+ return 0;
+
+ Field* fields = result->Fetch();
+ uint32 level = fields[0].GetUInt32();
+ delete result;
+
+ return level;
+}
+
void Player::UpdateArea(uint32 newArea)
{
// FFA_PVP flags are area and not zone id dependent
@@ -6328,10 +6446,11 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea)
}
pvpInfo.inNoPvPArea = false;
- if((zone->flags & AREA_FLAG_SANCTUARY) || zone->mapid == 609) // in sanctuary
+ if(zone->IsSanctuary()) // in sanctuary
{
SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY);
pvpInfo.inNoPvPArea = true;
+ CombatStopWithPets();
}
else
{
@@ -6456,22 +6575,6 @@ void Player::DuelComplete(DuelCompleteType type)
duel->opponent->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL, 1);
}
- // cool-down duel spell
- /*data.Initialize(SMSG_SPELL_COOLDOWN, 17);
-
- data<<GetGUID();
- data<<uint8(0x0);
-
- data<<(uint32)7266;
- data<<uint32(0x0);
- GetSession()->SendPacket(&data);
- data.Initialize(SMSG_SPELL_COOLDOWN, 17);
- data<<duel->opponent->GetGUID();
- data<<uint8(0x0);
- data<<(uint32)7266;
- data<<uint32(0x0);
- duel->opponent->GetSession()->SendPacket(&data);*/
-
//Remove Duel Flag object
GameObject* obj = GetMap()->GetGameObject(GetUInt64Value(PLAYER_DUEL_ARBITER));
if(obj)
@@ -6568,13 +6671,16 @@ void Player::_ApplyItemMods(Item *item, uint8 slot,bool apply)
sLog.outDebug("_ApplyItemMods complete.");
}
-void Player::_ApplyItemBonuses(ItemPrototype const *proto, uint8 slot, bool apply)
+void Player::_ApplyItemBonuses(ItemPrototype const *proto, uint8 slot, bool apply, bool only_level_scale /*= false*/)
{
if(slot >= INVENTORY_SLOT_BAG_END || !proto)
return;
- ScalingStatDistributionEntry const *ssd = proto->ScalingStatDistribution ? sScalingStatDistributionStore.LookupEntry(proto->ScalingStatDistribution) : 0;
- ScalingStatValuesEntry const *ssv = proto->ScalingStatValue ? sScalingStatValuesStore.LookupEntry(getLevel()) : 0;
+ ScalingStatDistributionEntry const *ssd = proto->ScalingStatDistribution ? sScalingStatDistributionStore.LookupEntry(proto->ScalingStatDistribution) : NULL;
+ ScalingStatValuesEntry const *ssv = proto->ScalingStatValue ? sScalingStatValuesStore.LookupEntry(getLevel()) : NULL;
+
+ if(only_level_scale && !(ssd && ssv))
+ return;
for (uint8 i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
{
@@ -6755,7 +6861,8 @@ void Player::_ApplyItemBonuses(ItemPrototype const *proto, uint8 slot, bool appl
}
// Add armor bonus from ArmorDamageModifier if > 0
if (proto->ArmorDamageModifier > 0)
- armor+=proto->ArmorDamageModifier;
+ armor += uint32(proto->ArmorDamageModifier);
+
if (armor)
HandleStatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(armor), apply);
@@ -7015,17 +7122,48 @@ void Player::UpdateEquipSpellsAtFormChange()
}
}
}
-
-void Player::CastItemCombatSpell(Item *item, CalcDamageInfo *damageInfo, ItemPrototype const * proto)
+void Player::CastItemCombatSpell(Unit *target, WeaponAttackType attType, uint32 procVictim, uint32 procEx)
{
- Unit * Target = damageInfo->target;
- WeaponAttackType attType = damageInfo->attackType;
-
- if (!Target || Target == this )
+ if(!target || !target->isAlive() || target == this)
return;
+ for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
+ {
+ // If usable, try to cast item spell
+ if (Item * item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0,i))
+ if(!item->IsBroken())
+ if (ItemPrototype const *proto = item->GetProto())
+ {
+ // Additional check for weapons
+ if (proto->Class==ITEM_CLASS_WEAPON)
+ {
+ // offhand item cannot proc from main hand hit etc
+ EquipmentSlots slot;
+ switch (attType)
+ {
+ case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break;
+ case OFF_ATTACK: slot = EQUIPMENT_SLOT_OFFHAND; break;
+ case RANGED_ATTACK: slot = EQUIPMENT_SLOT_RANGED; break;
+ default: slot = EQUIPMENT_SLOT_END; break;
+ }
+ if (slot != i)
+ continue;
+ // Check if item is useable (forms or disarm)
+ if (attType == BASE_ATTACK)
+ {
+ if (!((Player*)this)->IsUseEquipedWeapon(true))
+ continue;
+ }
+ }
+ ((Player*)this)->CastItemCombatSpell(target, attType, procVictim, procEx, item, proto);
+ }
+ }
+}
+
+void Player::CastItemCombatSpell(Unit *target, WeaponAttackType attType, uint32 procVictim, uint32 procEx, Item *item, ItemPrototype const * proto)
+{
// Can do effect if any damage done to target
- if (damageInfo->damage)
+ if (procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE)
//if (damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE)
{
for (int i = 0; i < 5; i++)
@@ -7048,7 +7186,7 @@ void Player::CastItemCombatSpell(Item *item, CalcDamageInfo *damageInfo, ItemPro
}
// not allow proc extra attack spell at extra attack
- if( m_extraAttacks && IsSpellHaveEffect(spellInfo,SPELL_EFFECT_ADD_EXTRA_ATTACKS) )
+ if( m_extraAttacks && IsSpellHaveEffect(spellInfo, SPELL_EFFECT_ADD_EXTRA_ATTACKS) )
return;
float chance = spellInfo->procChance;
@@ -7064,7 +7202,7 @@ void Player::CastItemCombatSpell(Item *item, CalcDamageInfo *damageInfo, ItemPro
}
if (roll_chance_f(chance))
- CastSpell(Target, spellInfo->Id, true, item);
+ CastSpell(target, spellInfo->Id, true, item);
}
}
@@ -7084,13 +7222,13 @@ void Player::CastItemCombatSpell(Item *item, CalcDamageInfo *damageInfo, ItemPro
if (entry && entry->procEx)
{
// Check hit/crit/dodge/parry requirement
- if((entry->procEx & damageInfo->procEx) == 0)
+ if((entry->procEx & procEx) == 0)
continue;
}
else
{
// Can do effect if any damage done to target
- if (!(damageInfo->damage))
+ if (!(procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE))
//if (!(damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE))
continue;
}
@@ -7105,10 +7243,7 @@ void Player::CastItemCombatSpell(Item *item, CalcDamageInfo *damageInfo, ItemPro
float chance = pEnchant->amount[s] != 0 ? float(pEnchant->amount[s]) : GetWeaponProcChance();
if (entry && entry->PPMChance)
- {
- uint32 WeaponSpeed = GetAttackTime(attType);
- chance = GetPPMProcChance(WeaponSpeed, entry->PPMChance, spellInfo);
- }
+ chance = GetPPMProcChance(proto->Delay, entry->PPMChance, spellInfo);
else if (entry && entry->customChance)
chance = entry->customChance;
@@ -7120,7 +7255,7 @@ void Player::CastItemCombatSpell(Item *item, CalcDamageInfo *damageInfo, ItemPro
if(IsPositiveSpell(pEnchant->spellid[s]))
CastSpell(this, pEnchant->spellid[s], true, item);
else
- CastSpell(Target, pEnchant->spellid[s], true, item);
+ CastSpell(target, pEnchant->spellid[s], true, item);
}
}
}
@@ -7309,6 +7444,24 @@ void Player::_ApplyAllItemMods()
sLog.outDebug("_ApplyAllItemMods complete.");
}
+void Player::_ApplyAllLevelScaleItemMods(bool apply)
+{
+ for (int i = 0; i < INVENTORY_SLOT_BAG_END; ++i)
+ {
+ if(m_items[i])
+ {
+ if(m_items[i]->IsBroken())
+ continue;
+
+ ItemPrototype const *proto = m_items[i]->GetProto();
+ if(!proto)
+ continue;
+
+ _ApplyItemBonuses(proto,i, apply, true);
+ }
+ }
+}
+
void Player::_ApplyAmmoBonuses()
{
// check ammo
@@ -7434,7 +7587,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
if (go->getLootState() == GO_READY)
{
- uint32 lootid = go->GetLootId();
+ uint32 lootid = go->GetGOInfo()->GetLootId();
//TODO: fix this big hack
if((go->GetEntry() == BG_AV_OBJECTID_MINE_N || go->GetEntry() == BG_AV_OBJECTID_MINE_S))
@@ -9040,39 +9193,42 @@ uint8 Player::_CanStoreItem_InSpecificSlot( uint8 bag, uint8 slot, ItemPosCountV
Item* pItem2 = GetItemByPos( bag, slot );
// ignore move item (this slot will be empty at move)
- if(pItem2==pSrcItem)
+ if (pItem2==pSrcItem)
pItem2 = NULL;
uint32 need_space;
// empty specific slot - check item fit to slot
- if( !pItem2 || swap )
+ if (!pItem2 || swap)
{
- if( bag == INVENTORY_SLOT_BAG_0 )
+ if (bag == INVENTORY_SLOT_BAG_0)
{
// keyring case
- if(slot >= KEYRING_SLOT_START && slot < KEYRING_SLOT_START+GetMaxKeyringSize() && !(pProto->BagFamily & BAG_FAMILY_MASK_KEYS))
+ if (slot >= KEYRING_SLOT_START && slot < KEYRING_SLOT_START+GetMaxKeyringSize() && !(pProto->BagFamily & BAG_FAMILY_MASK_KEYS))
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
// currencytoken case
- if(slot >= CURRENCYTOKEN_SLOT_START && slot < CURRENCYTOKEN_SLOT_END && !(pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS))
+ if (slot >= CURRENCYTOKEN_SLOT_START && slot < CURRENCYTOKEN_SLOT_END && !(pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS))
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
// prevent cheating
- if(slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END || slot >= PLAYER_SLOT_END)
+ if (slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END || slot >= PLAYER_SLOT_END)
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
}
else
{
Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag );
- if( !pBag )
+ if (!pBag)
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
ItemPrototype const* pBagProto = pBag->GetProto();
- if( !pBagProto )
+ if (!pBagProto)
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
- if( !ItemCanGoIntoBag(pProto,pBagProto) )
+ if (slot >= pBagProto->ContainerSlots)
+ return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
+
+ if (!ItemCanGoIntoBag(pProto,pBagProto))
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
}
@@ -9083,22 +9239,22 @@ uint8 Player::_CanStoreItem_InSpecificSlot( uint8 bag, uint8 slot, ItemPosCountV
else
{
// check item type
- if(pItem2->GetEntry() != pProto->ItemId)
+ if (pItem2->GetEntry() != pProto->ItemId)
return EQUIP_ERR_ITEM_CANT_STACK;
// check free space
- if(pItem2->GetCount() >= pProto->GetMaxStackSize())
+ if (pItem2->GetCount() >= pProto->GetMaxStackSize())
return EQUIP_ERR_ITEM_CANT_STACK;
// free stack space or infinity
need_space = pProto->GetMaxStackSize() - pItem2->GetCount();
}
- if(need_space > count)
+ if (need_space > count)
need_space = count;
ItemPosCount newPosition = ItemPosCount((bag << 8) | slot, need_space);
- if(!newPosition.isContainedIn(dest))
+ if (!newPosition.isContainedIn(dest))
{
dest.push_back(newPosition);
count -= need_space;
@@ -9109,55 +9265,55 @@ uint8 Player::_CanStoreItem_InSpecificSlot( uint8 bag, uint8 slot, ItemPosCountV
uint8 Player::_CanStoreItem_InBag( uint8 bag, ItemPosCountVec &dest, ItemPrototype const *pProto, uint32& count, bool merge, bool non_specialized, Item* pSrcItem, uint8 skip_bag, uint8 skip_slot ) const
{
// skip specific bag already processed in first called _CanStoreItem_InBag
- if(bag==skip_bag)
+ if (bag==skip_bag)
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag );
- if( !pBag )
+ if (!pBag)
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
ItemPrototype const* pBagProto = pBag->GetProto();
- if( !pBagProto )
+ if (!pBagProto)
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
// specialized bag mode or non-specilized
- if( non_specialized != (pBagProto->Class == ITEM_CLASS_CONTAINER && pBagProto->SubClass == ITEM_SUBCLASS_CONTAINER) )
+ if (non_specialized != (pBagProto->Class == ITEM_CLASS_CONTAINER && pBagProto->SubClass == ITEM_SUBCLASS_CONTAINER))
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
- if( !ItemCanGoIntoBag(pProto,pBagProto) )
+ if (!ItemCanGoIntoBag(pProto,pBagProto))
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
for(uint32 j = 0; j < pBag->GetBagSize(); j++)
{
// skip specific slot already processed in first called _CanStoreItem_InSpecificSlot
- if(j==skip_slot)
+ if (j==skip_slot)
continue;
Item* pItem2 = GetItemByPos( bag, j );
// ignore move item (this slot will be empty at move)
- if(pItem2==pSrcItem)
+ if (pItem2==pSrcItem)
pItem2 = NULL;
// if merge skip empty, if !merge skip non-empty
- if((pItem2!=NULL)!=merge)
+ if ((pItem2!=NULL)!=merge)
continue;
- if( pItem2 )
+ if (pItem2)
{
- if(pItem2->GetEntry() == pProto->ItemId && pItem2->GetCount() < pProto->GetMaxStackSize())
+ if (pItem2->GetEntry() == pProto->ItemId && pItem2->GetCount() < pProto->GetMaxStackSize())
{
uint32 need_space = pProto->GetMaxStackSize() - pItem2->GetCount();
if(need_space > count)
need_space = count;
ItemPosCount newPosition = ItemPosCount((bag << 8) | j, need_space);
- if(!newPosition.isContainedIn(dest))
+ if (!newPosition.isContainedIn(dest))
{
dest.push_back(newPosition);
count -= need_space;
- if(count==0)
+ if (count==0)
return EQUIP_ERR_OK;
}
}
@@ -9165,16 +9321,16 @@ uint8 Player::_CanStoreItem_InBag( uint8 bag, ItemPosCountVec &dest, ItemPrototy
else
{
uint32 need_space = pProto->GetMaxStackSize();
- if(need_space > count)
+ if (need_space > count)
need_space = count;
ItemPosCount newPosition = ItemPosCount((bag << 8) | j, need_space);
- if(!newPosition.isContainedIn(dest))
+ if (!newPosition.isContainedIn(dest))
{
dest.push_back(newPosition);
count -= need_space;
- if(count==0)
+ if (count==0)
return EQUIP_ERR_OK;
}
}
@@ -9187,33 +9343,33 @@ uint8 Player::_CanStoreItem_InInventorySlots( uint8 slot_begin, uint8 slot_end,
for(uint32 j = slot_begin; j < slot_end; j++)
{
// skip specific slot already processed in first called _CanStoreItem_InSpecificSlot
- if(INVENTORY_SLOT_BAG_0==skip_bag && j==skip_slot)
+ if (INVENTORY_SLOT_BAG_0==skip_bag && j==skip_slot)
continue;
Item* pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, j );
// ignore move item (this slot will be empty at move)
- if(pItem2==pSrcItem)
+ if (pItem2==pSrcItem)
pItem2 = NULL;
// if merge skip empty, if !merge skip non-empty
- if((pItem2!=NULL)!=merge)
+ if ((pItem2!=NULL)!=merge)
continue;
- if( pItem2 )
+ if (pItem2)
{
- if(pItem2->GetEntry() == pProto->ItemId && pItem2->GetCount() < pProto->GetMaxStackSize())
+ if (pItem2->GetEntry() == pProto->ItemId && pItem2->GetCount() < pProto->GetMaxStackSize())
{
uint32 need_space = pProto->GetMaxStackSize() - pItem2->GetCount();
- if(need_space > count)
+ if (need_space > count)
need_space = count;
ItemPosCount newPosition = ItemPosCount((INVENTORY_SLOT_BAG_0 << 8) | j, need_space);
- if(!newPosition.isContainedIn(dest))
+ if (!newPosition.isContainedIn(dest))
{
dest.push_back(newPosition);
count -= need_space;
- if(count==0)
+ if (count==0)
return EQUIP_ERR_OK;
}
}
@@ -9221,16 +9377,16 @@ uint8 Player::_CanStoreItem_InInventorySlots( uint8 slot_begin, uint8 slot_end,
else
{
uint32 need_space = pProto->GetMaxStackSize();
- if(need_space > count)
+ if (need_space > count)
need_space = count;
ItemPosCount newPosition = ItemPosCount((INVENTORY_SLOT_BAG_0 << 8) | j, need_space);
- if(!newPosition.isContainedIn(dest))
+ if (!newPosition.isContainedIn(dest))
{
dest.push_back(newPosition);
count -= need_space;
- if(count==0)
+ if (count==0)
return EQUIP_ERR_OK;
}
}
@@ -9243,16 +9399,16 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
sLog.outDebug( "STORAGE: CanStoreItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, entry, count);
ItemPrototype const *pProto = objmgr.GetItemPrototype(entry);
- if( !pProto )
+ if (!pProto)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count;
return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED :EQUIP_ERR_ITEM_NOT_FOUND;
}
- if(pItem && pItem->IsBindedNotWith(this))
+ if (pItem && pItem->IsBindedNotWith(this))
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count;
return EQUIP_ERR_DONT_OWN_THAT_ITEM;
}
@@ -9260,11 +9416,11 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
// check count of items (skip for auto move for same player from bank)
uint32 no_similar_count = 0; // can't store this amount similar items
uint8 res = _CanTakeMoreSimilarItems(entry,count,pItem,&no_similar_count);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(count==no_similar_count)
+ if (count==no_similar_count)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = no_similar_count;
return res;
}
@@ -9272,22 +9428,22 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
}
// in specific slot
- if( bag != NULL_BAG && slot != NULL_SLOT )
+ if (bag != NULL_BAG && slot != NULL_SLOT)
{
res = _CanStoreItem_InSpecificSlot(bag,slot,dest,pProto,count,swap,pItem);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
@@ -9296,45 +9452,45 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
// not specific slot or have space for partly store only in specific slot
// in specific bag
- if( bag != NULL_BAG )
+ if (bag != NULL_BAG)
{
// search stack in bag for merge to
- if( pProto->Stackable != 1 )
+ if (pProto->Stackable != 1)
{
- if( bag == INVENTORY_SLOT_BAG_0 ) // inventory
+ if (bag == INVENTORY_SLOT_BAG_0) // inventory
{
res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,CURRENCYTOKEN_SLOT_END,dest,pProto,count,true,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
res = _CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START,INVENTORY_SLOT_ITEM_END,dest,pProto,count,true,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
@@ -9343,22 +9499,22 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
{
// we need check 2 time (specialized/non_specialized), use NULL_BAG to prevent skipping bag
res = _CanStoreItem_InBag(bag,dest,pProto,count,true,false,pItem,NULL_BAG,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
res = _CanStoreItem_InBag(bag,dest,pProto,count,true,true,pItem,NULL_BAG,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
@@ -9366,83 +9522,83 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
}
// search free slot in bag for place to
- if( bag == INVENTORY_SLOT_BAG_0 ) // inventory
+ if(bag == INVENTORY_SLOT_BAG_0) // inventory
{
// search free slot - keyring case
- if(pProto->BagFamily & BAG_FAMILY_MASK_KEYS)
+ if (pProto->BagFamily & BAG_FAMILY_MASK_KEYS)
{
uint32 keyringSize = GetMaxKeyringSize();
res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,KEYRING_SLOT_START+keyringSize,dest,pProto,count,false,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
res = _CanStoreItem_InInventorySlots(CURRENCYTOKEN_SLOT_START,CURRENCYTOKEN_SLOT_END,dest,pProto,count,false,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
}
- else if(pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS)
+ else if (pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS)
{
res = _CanStoreItem_InInventorySlots(CURRENCYTOKEN_SLOT_START,CURRENCYTOKEN_SLOT_END,dest,pProto,count,false,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
}
res = _CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START,INVENTORY_SLOT_ITEM_END,dest,pProto,count,false,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
@@ -9450,22 +9606,22 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
else // equipped bag
{
res = _CanStoreItem_InBag(bag,dest,pProto,count,false,false,pItem,NULL_BAG,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
res = _CanStoreItem_InBag(bag,dest,pProto,count,false,true,pItem,NULL_BAG,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
@@ -9475,58 +9631,58 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
// not specific bag or have space for partly store only in specific bag
// search stack for merge to
- if( pProto->Stackable != 1 )
+ if (pProto->Stackable != 1)
{
res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,CURRENCYTOKEN_SLOT_END,dest,pProto,count,true,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
res = _CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START,INVENTORY_SLOT_ITEM_END,dest,pProto,count,true,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
- if( pProto->BagFamily )
+ if (pProto->BagFamily)
{
for(uint32 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
{
res = _CanStoreItem_InBag(i,dest,pProto,count,true,false,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
continue;
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
@@ -9536,15 +9692,15 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
for(uint32 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
{
res = _CanStoreItem_InBag(i,dest,pProto,count,true,true,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
continue;
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
@@ -9552,45 +9708,45 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
}
// search free slot - special bag case
- if( pProto->BagFamily )
+ if (pProto->BagFamily)
{
- if(pProto->BagFamily & BAG_FAMILY_MASK_KEYS)
+ if (pProto->BagFamily & BAG_FAMILY_MASK_KEYS)
{
uint32 keyringSize = GetMaxKeyringSize();
res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,KEYRING_SLOT_START+keyringSize,dest,pProto,count,false,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
}
- else if(pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS)
+ else if (pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS)
{
res = _CanStoreItem_InInventorySlots(CURRENCYTOKEN_SLOT_START,CURRENCYTOKEN_SLOT_END,dest,pProto,count,false,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
@@ -9599,15 +9755,15 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
for(uint32 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
{
res = _CanStoreItem_InBag(i,dest,pProto,count,false,false,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
continue;
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
@@ -9616,19 +9772,19 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
// search free slot
res = _CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START,INVENTORY_SLOT_ITEM_END,dest,pProto,count,false,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
{
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
@@ -9636,21 +9792,21 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
for(uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
{
res = _CanStoreItem_InBag(i,dest,pProto,count,false,true,pItem,bag,slot);
- if(res!=EQUIP_ERR_OK)
+ if (res!=EQUIP_ERR_OK)
continue;
- if(count==0)
+ if (count==0)
{
- if(no_similar_count==0)
+ if (no_similar_count==0)
return EQUIP_ERR_OK;
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
}
}
- if(no_space_count)
+ if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_INVENTORY_FULL;
@@ -10378,7 +10534,7 @@ uint8 Player::CanUseAmmo( uint32 item ) const
return EQUIP_ERR_CANT_EQUIP_LEVEL_I;
// Requires No Ammo
- if(GetDummyAura(46699))
+ if(HasAura(46699))
return EQUIP_ERR_BAG_FULL6;
return EQUIP_ERR_OK;
@@ -10474,7 +10630,7 @@ Item* Player::_StoreItem( uint16 pos, Item *pItem, uint32 count, bool clone, boo
uint8 bag = pos >> 8;
uint8 slot = pos & 255;
- sLog.outDebug( "STORAGE: StoreItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, pItem->GetEntry(), count);
+ sLog.outDebug( "STORAGE: StoreItem bag = %u, slot = %u, item = %u, count = %u, guid = %u", bag, slot, pItem->GetEntry(), count, pItem->GetGUIDLow());
Item *pItem2 = GetItemByPos( bag, slot );
@@ -10581,7 +10737,6 @@ Item* Player::EquipNewItem( uint16 pos, uint32 item, bool update )
Item* Player::EquipItem( uint16 pos, Item *pItem, bool update )
{
-
AddEnchantmentDurations(pItem);
AddItemDurations(pItem);
@@ -12311,7 +12466,11 @@ void Player::PrepareQuestMenu( uint64 guid )
}
else
{
- GameObject *pGameObject = GetMap()->GetGameObject(guid);
+ //we should obtain map pointer from GetMap() in 99% of cases. Special case
+ //only for quests which cast teleport spells on player
+ Map * _map = IsInWorld() ? GetMap() : MapManager::Instance().FindMap(GetMapId(), GetInstanceId());
+ ASSERT(_map);
+ GameObject *pGameObject = _map->GetGameObject(guid);
if( pGameObject )
{
pObject = (Object*)pGameObject;
@@ -12333,8 +12492,8 @@ void Player::PrepareQuestMenu( uint64 guid )
qm.AddMenuItem(quest_id, DIALOG_STATUS_UNK2);
else if ( status == QUEST_STATUS_INCOMPLETE )
qm.AddMenuItem(quest_id, DIALOG_STATUS_UNK2);
- else if (status == QUEST_STATUS_AVAILABLE )
- qm.AddMenuItem(quest_id, DIALOG_STATUS_CHAT);
+ //else if (status == QUEST_STATUS_AVAILABLE )
+ // qm.AddMenuItem(quest_id, DIALOG_STATUS_CHAT);
}
for(QuestRelations::const_iterator i = pObjectQR->lower_bound(pObject->GetEntry()); i != pObjectQR->upper_bound(pObject->GetEntry()); ++i)
@@ -12464,7 +12623,11 @@ Quest const * Player::GetNextQuest( uint64 guid, Quest const *pQuest )
}
else
{
- GameObject *pGameObject = GetMap()->GetGameObject(guid);
+ //we should obtain map pointer from GetMap() in 99% of cases. Special case
+ //only for quests which cast teleport spells on player
+ Map * _map = IsInWorld() ? GetMap() : MapManager::Instance().FindMap(GetMapId(), GetInstanceId());
+ ASSERT(_map);
+ GameObject *pGameObject = _map->GetGameObject(guid);
if( pGameObject )
{
pObject = (Object*)pGameObject;
@@ -12746,7 +12909,7 @@ void Player::AddQuest( Quest const *pQuest, Object *questGiver )
//starting initial quest script
if(questGiver && pQuest->GetQuestStartScript()!=0)
- sWorld.ScriptsStart(sQuestStartScripts, pQuest->GetQuestStartScript(), questGiver, this);
+ GetMap()->ScriptsStart(sQuestStartScripts, pQuest->GetQuestStartScript(), questGiver, this);
// Some spells applied at quest activation
SpellAreaForQuestMapBounds saBounds = spellmgr.GetSpellAreaForQuestMapBounds(quest_id,true);
@@ -12798,11 +12961,15 @@ void Player::IncompleteQuest( uint32 quest_id )
void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver, bool announce )
{
+ //this THING should be here to protect code from quest, which cast on player far teleport as a reward
+ //should work fine, cause far teleport will be executed in Player::Update()
+ SetCanDelayTeleport(true);
+
uint32 quest_id = pQuest->GetQuestId();
for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; i++ )
{
- if ( pQuest->ReqItemId[i] )
+ if (pQuest->ReqItemId[i])
DestroyItemCount( pQuest->ReqItemId[i], pQuest->ReqItemCount[i], true);
}
@@ -12810,29 +12977,29 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
// SetTimedQuest( 0 );
m_timedquests.erase(pQuest->GetQuestId());
- if ( pQuest->GetRewChoiceItemsCount() > 0 )
+ if (pQuest->GetRewChoiceItemsCount() > 0)
{
- if( pQuest->RewChoiceItemId[reward] )
+ if (uint32 itemId = pQuest->RewChoiceItemId[reward])
{
ItemPosCountVec dest;
- if( CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, pQuest->RewChoiceItemId[reward], pQuest->RewChoiceItemCount[reward] ) == EQUIP_ERR_OK )
+ if (CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, itemId, pQuest->RewChoiceItemCount[reward] ) == EQUIP_ERR_OK)
{
- Item* item = StoreNewItem( dest, pQuest->RewChoiceItemId[reward], true);
+ Item* item = StoreNewItem( dest, itemId, true, Item::GenerateItemRandomPropertyId(itemId));
SendNewItem(item, pQuest->RewChoiceItemCount[reward], true, false);
}
}
}
- if ( pQuest->GetRewItemsCount() > 0 )
+ if (pQuest->GetRewItemsCount() > 0)
{
for (uint32 i=0; i < pQuest->GetRewItemsCount(); ++i)
{
- if( pQuest->RewItemId[i] )
+ if (uint32 itemId = pQuest->RewItemId[i])
{
ItemPosCountVec dest;
- if( CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, pQuest->RewItemId[i], pQuest->RewItemCount[i] ) == EQUIP_ERR_OK )
+ if (CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, itemId, pQuest->RewItemCount[i] ) == EQUIP_ERR_OK)
{
- Item* item = StoreNewItem( dest, pQuest->RewItemId[i], true);
+ Item* item = StoreNewItem( dest, itemId, true, Item::GenerateItemRandomPropertyId(itemId));
SendNewItem(item, pQuest->RewItemCount[i], true, false);
}
}
@@ -12841,13 +13008,8 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
RewardReputation( pQuest );
- if( pQuest->GetRewSpellCast() > 0 )
- CastSpell( this, pQuest->GetRewSpellCast(), true);
- else if( pQuest->GetRewSpell() > 0)
- CastSpell( this, pQuest->GetRewSpell(), true);
-
uint16 log_slot = FindQuestSlot( quest_id );
- if( log_slot < MAX_QUEST_LOG_SIZE)
+ if (log_slot < MAX_QUEST_LOG_SIZE)
SetQuestSlot(log_slot,0);
QuestStatusData& q_status = mQuestStatus[quest_id];
@@ -12855,7 +13017,7 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
// Not give XP in case already completed once repeatable quest
uint32 XP = q_status.m_rewarded ? 0 : uint32(pQuest->XPValue( this )*sWorld.getRate(RATE_XP_QUEST));
- if ( getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) )
+ if (getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
GiveXP( XP , NULL );
else
{
@@ -12865,33 +13027,33 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
}
// Give player extra money if GetRewOrReqMoney > 0 and get ReqMoney if negative
- if(pQuest->GetRewOrReqMoney())
+ if (pQuest->GetRewOrReqMoney())
{
ModifyMoney( pQuest->GetRewOrReqMoney() );
- if(pQuest->GetRewOrReqMoney() > 0)
+ if (pQuest->GetRewOrReqMoney() > 0)
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD, pQuest->GetRewOrReqMoney());
}
// honor reward
- if(pQuest->GetRewHonorableKills())
- RewardHonor(NULL, 0, Trinity::Honor::hk_honor_at_level(getLevel(), pQuest->GetRewHonorableKills()));
+ if (pQuest->GetRewHonorableKills())
+ RewardHonor(NULL, 0, MaNGOS::Honor::hk_honor_at_level(getLevel(), pQuest->GetRewHonorableKills()));
// title reward
- if(pQuest->GetCharTitleId())
+ if (pQuest->GetCharTitleId())
{
- if(CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(pQuest->GetCharTitleId()))
+ if (CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(pQuest->GetCharTitleId()))
SetTitle(titleEntry);
}
- if(pQuest->GetBonusTalents())
+ if (pQuest->GetBonusTalents())
{
m_questRewardTalentCount+=pQuest->GetBonusTalents();
InitTalentForLevel();
}
// Send reward mail
- if(pQuest->GetRewMailTemplateId())
+ if (pQuest->GetRewMailTemplateId())
{
MailMessageType mailType;
uint32 senderGuidOrEntry;
@@ -12929,9 +13091,9 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
uint32 max_slot = questMailLoot.GetMaxSlotInLootFor(this);
for(uint32 i = 0; mi.size() < MAX_MAIL_ITEMS && i < max_slot; ++i)
{
- if(LootItem* lootitem = questMailLoot.LootItemInSlot(i,this))
+ if (LootItem* lootitem = questMailLoot.LootItemInSlot(i,this))
{
- if(Item* item = Item::CreateItem(lootitem->itemid,lootitem->count,this))
+ if (Item* item = Item::CreateItem(lootitem->itemid,lootitem->count,this))
{
item->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted
mi.AddItem(item->GetGUIDLow(), item->GetEntry(), item);
@@ -12942,23 +13104,30 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
WorldSession::SendMailTo(this, mailType, MAIL_STATIONERY_NORMAL, senderGuidOrEntry, GetGUIDLow(), "", 0, &mi, 0, 0, MAIL_CHECK_MASK_NONE,pQuest->GetRewMailDelaySecs(),pQuest->GetRewMailTemplateId());
}
- if(pQuest->IsDaily())
+ if (pQuest->IsDaily())
{
SetDailyQuestStatus(quest_id);
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST, 1);
}
- if ( !pQuest->IsRepeatable() )
+ if (!pQuest->IsRepeatable())
SetQuestStatus(quest_id, QUEST_STATUS_COMPLETE);
else
SetQuestStatus(quest_id, QUEST_STATUS_NONE);
q_status.m_rewarded = true;
+ if (q_status.uState != QUEST_NEW)
+ q_status.uState = QUEST_CHANGED;
- if(announce)
+ if (announce)
SendQuestReward( pQuest, XP, questGiver );
- if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED;
+ // cast spells after mark quest complete (some spells have quest completed state reqyurements in spell_area data)
+ if (pQuest->GetRewSpellCast() > 0)
+ CastSpell( this, pQuest->GetRewSpellCast(), true);
+ else if ( pQuest->GetRewSpell() > 0)
+ CastSpell( this, pQuest->GetRewSpell(), true);
+
if (pQuest->GetZoneOrSort() > 0)
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE, pQuest->GetZoneOrSort());
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT);
@@ -12990,6 +13159,9 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
if( !HasAura(itr->second->spellId) )
CastSpell(this,itr->second->spellId,true);
}
+
+ //lets remove flag for delayed teleports
+ SetCanDelayTeleport(false);
}
void Player::FailQuest( uint32 quest_id )
@@ -13657,7 +13829,17 @@ void Player::ItemRemovedQuestCheck( uint32 entry, uint32 count )
UpdateForQuestWorldObjects();
}
-void Player::KilledMonster( uint32 entry, uint64 guid )
+void Player::KilledMonster( CreatureInfo const* cInfo, uint64 guid )
+{
+ if(cInfo->Entry)
+ KilledMonsterCredit(cInfo->Entry,guid);
+
+ for(int i = 0; i < MAX_KILL_CREDIT; ++i)
+ if(cInfo->KillCredit[i])
+ KilledMonsterCredit(cInfo->KillCredit[i],guid);
+}
+
+void Player::KilledMonsterCredit( uint32 entry, uint64 guid )
{
uint32 addkillcount = 1;
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, entry, addkillcount);
@@ -13987,7 +14169,7 @@ void Player::SendQuestReward( Quest const *pQuest, uint32 XP, Object * questGive
GetSession()->SendPacket( &data );
if (pQuest->GetQuestCompleteScript() != 0)
- sWorld.ScriptsStart(sQuestEndScripts, pQuest->GetQuestCompleteScript(), questGiver, this);
+ GetMap()->ScriptsStart(sQuestEndScripts, pQuest->GetQuestCompleteScript(), questGiver, this);
}
void Player::SendQuestFailed( uint32 quest_id )
@@ -14074,8 +14256,8 @@ bool Player::MinimalLoadFromDB( QueryResult *result, uint32 guid )
bool delete_result = true;
if (!result)
{
- // 0 1 2 3 4 5 6 7 8 9 10
- result = CharacterDatabase.PQuery("SELECT guid, data, name, position_x, position_y, position_z, map, totaltime, leveltime, at_login, zone FROM characters WHERE guid = '%u'",guid);
+ // 0 1 2 3 4 5 6 7 8 9 10 11
+ result = CharacterDatabase.PQuery("SELECT guid, data, name, position_x, position_y, position_z, map, totaltime, leveltime, at_login, zone, level FROM characters WHERE guid = '%u'",guid);
if (!result)
return false;
}
@@ -14098,11 +14280,17 @@ bool Player::MinimalLoadFromDB( QueryResult *result, uint32 guid )
m_name = fields[2].GetCppString();
Relocate(fields[3].GetFloat(),fields[4].GetFloat(),fields[5].GetFloat());
- SetMapId(fields[6].GetUInt32());
+ Map *map = MapManager::Instance().CreateMap(fields[6].GetUInt32(), this, 0);
+ SetMap(map);
+
+ // randomize first save time in range [CONFIG_INTERVAL_SAVE] around [CONFIG_INTERVAL_SAVE]
+ // this must help in case next save after mass player load after server startup
+ m_nextSave = urand(m_nextSave/2,m_nextSave*3/2);
+
// the instance id is not needed at character enum
- m_Played_time[0] = fields[7].GetUInt32();
- m_Played_time[1] = fields[8].GetUInt32();
+ m_Played_time[PLAYED_TIME_TOTAL] = fields[7].GetUInt32();
+ m_Played_time[PLAYED_TIME_LEVEL] = fields[8].GetUInt32();
m_atLoginFlags = fields[9].GetUInt32();
@@ -14308,8 +14496,8 @@ float Player::GetFloatValueFromDB(uint16 index, uint64 guid)
bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
{
- //// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 [28] [29] 30 31 32 33 34 35 36 37 38 39 40
- //QueryResult *result = CharacterDatabase.PQuery("SELECT guid, account, data, name, race, class, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty, arena_pending_points,bgid,bgteam,bgmap,bgx,bgy,bgz,bgo FROM characters WHERE guid = '%u'", guid);
+ //// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
+ //QueryResult *result = CharacterDatabase.PQuery("SELECT guid, account, data, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty, arena_pending_points,bgid,bgteam,bgmap,bgx,bgy,bgz,bgo FROM characters WHERE guid = '%u'", guid);
QueryResult *result = holder->GetResult(PLAYER_LOGIN_QUERY_LOADFROM);
if(!result)
@@ -14336,7 +14524,8 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
m_name = fields[3].GetCppString();
// check name limitations
- if(!ObjectMgr::IsValidName(m_name) || (GetSession()->GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(m_name)))
+ if (ObjectMgr::CheckPlayerName(m_name) != CHAR_NAME_SUCCESS ||
+ GetSession()->GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(m_name))
{
delete result;
CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE guid ='%u'", uint32(AT_LOGIN_RENAME),guid);
@@ -14353,6 +14542,23 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
// overwrite possible wrong/corrupted guid
SetUInt64Value(OBJECT_FIELD_GUID, MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER));
+ // overwrite some data fields
+ uint32 bytes0 = GetUInt32Value(UNIT_FIELD_BYTES_0) & 0xFF000000;
+ bytes0 |= fields[4].GetUInt8(); // race
+ bytes0 |= fields[5].GetUInt8() << 8; // class
+ bytes0 |= fields[6].GetUInt8() << 16; // gender
+ SetUInt32Value(UNIT_FIELD_BYTES_0, bytes0);
+
+ SetUInt32Value(UNIT_FIELD_LEVEL, fields[7].GetUInt8());
+ SetUInt32Value(PLAYER_XP, fields[8].GetUInt32());
+ SetUInt32Value(PLAYER_FIELD_COINAGE, fields[9].GetUInt32());
+ SetUInt32Value(PLAYER_BYTES, fields[10].GetUInt32());
+ SetUInt32Value(PLAYER_BYTES_2, fields[11].GetUInt32());
+ SetUInt32Value(PLAYER_BYTES_3, (GetUInt32Value(PLAYER_BYTES_3) & ~1) | fields[6].GetUInt8());
+ SetUInt32Value(PLAYER_FLAGS, fields[12].GetUInt32());
+
+ InitDisplayIds();
+
// cleanup inventory related item value fields (its will be filled correctly in _LoadInventory)
for(uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
{
@@ -14373,12 +14579,9 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
sLog.outDebug("Load Basic value of player %s is: ", m_name.c_str());
outDebugValues();
- m_race = fields[4].GetUInt8();
- //Need to call it to initialize m_team (m_team can be calculated from m_race)
+ //Need to call it to initialize m_team (m_team can be calculated from race)
//Other way is to saves m_team into characters table.
- setFactionForRace(m_race);
-
- m_class = fields[5].GetUInt8();
+ setFactionForRace(getRace());
// load home bind and check in same time class/race pair, it used later for restore broken positions
if(!_LoadHomeBind(holder->GetResult(PLAYER_LOGIN_QUERY_LOADHOMEBIND)))
@@ -14389,18 +14592,13 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
InitPrimaryProfessions(); // to max set before any spell loaded
- // init saved position, and fix it later if problematic
- uint32 transGUID = fields[24].GetUInt32();
- Relocate(fields[6].GetFloat(),fields[7].GetFloat(),fields[8].GetFloat(),fields[10].GetFloat());
- SetMapId(fields[9].GetUInt32());
- SetInstanceId(fields[41].GetFloat());
- SetDifficulty(fields[32].GetUInt32()); // may be changed in _LoadGroup
+ SetDifficulty(fields[39].GetUInt32()); // may be changed in _LoadGroup
_LoadGroup(holder->GetResult(PLAYER_LOGIN_QUERY_LOADGROUP));
_LoadArenaTeamInfo(holder->GetResult(PLAYER_LOGIN_QUERY_LOADARENAINFO));
- uint32 arena_currency = GetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY) + fields[33].GetUInt32();
+ uint32 arena_currency = GetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY) + fields[40].GetUInt32();
if (arena_currency > sWorld.getConfig(CONFIG_MAX_ARENA_POINTS))
arena_currency = sWorld.getConfig(CONFIG_MAX_ARENA_POINTS);
@@ -14424,35 +14622,42 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
_LoadBoundInstances(holder->GetResult(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES));
+ // load player map related values
+ uint32 transGUID = fields[31].GetUInt32();
+ Relocate(fields[13].GetFloat(),fields[14].GetFloat(),fields[15].GetFloat(),fields[17].GetFloat());
+ uint32 mapId = fields[16].GetUInt32();
+ uint32 instanceId = fields[41].GetFloat();
+ std::string taxi_nodes = fields[38].GetCppString();
+
+ MapEntry const * mapEntry = sMapStore.LookupEntry(mapId);
if(!IsPositionValid())
{
sLog.outError("Player (guidlow %d) have invalid coordinates (X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.",guid,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
- RelocateToHomebind();
+ RelocateToHomebind(mapId);
transGUID = 0;
+ instanceId = 0;
m_movementInfo.t_x = 0.0f;
m_movementInfo.t_y = 0.0f;
m_movementInfo.t_z = 0.0f;
m_movementInfo.t_o = 0.0f;
}
-
- uint32 bgid = fields[34].GetUInt32();
- uint32 bgteam = fields[35].GetUInt32();
-
- if(bgid) //saved in BattleGround
+ // Player was saved in Arena or Bg
+ else if (mapEntry && mapEntry->IsBattleGroundOrArena())
{
- SetBattleGroundEntryPoint(fields[36].GetUInt32(),fields[37].GetFloat(),fields[38].GetFloat(),fields[39].GetFloat(),fields[40].GetFloat());
+ // Get Entry Point(bg master) or Homebind
+ SetBattleGroundEntryPoint(fields[43].GetUInt32(),fields[44].GetFloat(),fields[45].GetFloat(),fields[46].GetFloat(),fields[47].GetFloat());
- // check entry point and fix to homebind if need
- MapEntry const* mapEntry = sMapStore.LookupEntry(m_bgEntryPoint.mapid);
- if(!mapEntry || mapEntry->Instanceable() || !MapManager::IsValidMapCoord(m_bgEntryPoint))
+ MapEntry const* bgEntry = sMapStore.LookupEntry(m_bgEntryPoint.mapid);
+ if(!bgEntry || bgEntry->Instanceable() || !MapManager::IsValidMapCoord(m_bgEntryPoint))
SetBattleGroundEntryPoint(m_homebindMapId,m_homebindX,m_homebindY,m_homebindZ,0.0f);
- BattleGround *currentBg = sBattleGroundMgr.GetBattleGround(bgid, BATTLEGROUND_TYPE_NONE);
-
+ // Bg still exists - join it!
+ BattleGround *currentBg = sBattleGroundMgr.GetBattleGround(instanceId, BATTLEGROUND_TYPE_NONE);
if(currentBg && currentBg->IsPlayerInBattleGround(GetGUID()))
{
+ uint32 bgteam = fields[42].GetUInt32();
BattleGroundQueueTypeId bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(currentBg->GetTypeID(), currentBg->GetArenaType());
AddBattleGroundQueueId(bgQueueTypeId);
@@ -14465,38 +14670,25 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
SetInviteForBattleGroundQueueType(bgQueueTypeId,currentBg->GetInstanceID());
}
+ // Bg was not found - go to Entry Point
else
{
+ // Do not look for instance if bg not found
+ instanceId = 0;
const WorldLocation& _loc = GetBattleGroundEntryPoint();
- SetMapId(_loc.mapid);
+ mapId = _loc.mapid;
Relocate(_loc.coord_x, _loc.coord_y, _loc.coord_z, _loc.orientation);
- //RemoveArenaAuras(true);
}
}
- else
+ else if (transGUID != 0)
{
- MapEntry const* mapEntry = sMapStore.LookupEntry(GetMapId());
- // if server restart after player save in BG or area
- // player can have current coordinates in to BG/Arean map, fix this
- if(!mapEntry || mapEntry->IsBattleGroundOrArena())
- {
- // return to BG master
- SetMapId(fields[36].GetUInt32());
- Relocate(fields[37].GetFloat(),fields[38].GetFloat(),fields[39].GetFloat(),fields[40].GetFloat());
-
- // check entry point and fix to homebind if need
- mapEntry = sMapStore.LookupEntry(GetMapId());
- if(!mapEntry || mapEntry->IsBattleGroundOrArena() || !IsPositionValid())
- RelocateToHomebind();
- }
- }
+ // There are no transports on instances
+ instanceId = 0;
- if (transGUID != 0)
- {
- m_movementInfo.t_x = fields[20].GetFloat();
- m_movementInfo.t_y = fields[21].GetFloat();
- m_movementInfo.t_z = fields[22].GetFloat();
- m_movementInfo.t_o = fields[23].GetFloat();
+ m_movementInfo.t_x = fields[27].GetFloat();
+ m_movementInfo.t_y = fields[28].GetFloat();
+ m_movementInfo.t_z = fields[29].GetFloat();
+ m_movementInfo.t_o = fields[30].GetFloat();
if( !Trinity::IsValidMapCoord(
GetPositionX()+m_movementInfo.t_x,GetPositionY()+m_movementInfo.t_y,
@@ -14508,7 +14700,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
guid,GetPositionX()+m_movementInfo.t_x,GetPositionY()+m_movementInfo.t_y,
GetPositionZ()+m_movementInfo.t_z,GetOrientation()+m_movementInfo.t_o);
- RelocateToHomebind();
+ RelocateToHomebind(mapId);
m_movementInfo.t_x = 0.0f;
m_movementInfo.t_y = 0.0f;
@@ -14517,112 +14709,146 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
transGUID = 0;
}
- }
-
- if (transGUID != 0)
- {
- for (MapManager::TransportSet::iterator iter = MapManager::Instance().m_Transports.begin(); iter != MapManager::Instance().m_Transports.end(); ++iter)
+ else
{
- if( (*iter)->GetGUIDLow() == transGUID)
+ for (MapManager::TransportSet::iterator iter = MapManager::Instance().m_Transports.begin(); iter != MapManager::Instance().m_Transports.end(); ++iter)
{
- MapEntry const* transMapEntry = sMapStore.LookupEntry((*iter)->GetMapId());
- // client without expansion support
- if(GetSession()->Expansion() < transMapEntry->Expansion())
+ if( (*iter)->GetGUIDLow() == transGUID)
{
- sLog.outDebug("Player %s using client without required expansion tried login at transport at non accessible map %u", GetName(), (*iter)->GetMapId());
+ m_transport = *iter;
+ m_transport->AddPassenger(this);
+ mapId = (m_transport->GetMapId());
break;
}
-
- m_transport = *iter;
- m_transport->AddPassenger(this);
- SetMapId(m_transport->GetMapId());
- break;
}
- }
-
- if(!m_transport)
- {
- sLog.outError("Player (guidlow %d) have problems with transport guid (%u). Teleport to default race/class locations.",
- guid,transGUID);
+ if(!m_transport)
+ {
+ sLog.outError("Player (guidlow %d) have problems with transport guid (%u). Teleport to default race/class locations.",
+ guid,transGUID);
- RelocateToHomebind();
+ RelocateToHomebind(mapId);
- m_movementInfo.t_x = 0.0f;
- m_movementInfo.t_y = 0.0f;
- m_movementInfo.t_z = 0.0f;
- m_movementInfo.t_o = 0.0f;
+ m_movementInfo.t_x = 0.0f;
+ m_movementInfo.t_y = 0.0f;
+ m_movementInfo.t_z = 0.0f;
+ m_movementInfo.t_o = 0.0f;
- transGUID = 0;
+ transGUID = 0;
+ }
}
}
- else // not transport case
+ else if (!taxi_nodes.empty()) // Taxi Flight path loaded from db
{
- MapEntry const* mapEntry = sMapStore.LookupEntry(GetMapId());
- // client without expansion support
- if(GetSession()->Expansion() < mapEntry->Expansion())
+ // There are no flightpaths in instances
+ instanceId = 0;
+
+ if(!m_taxi.LoadTaxiDestinationsFromString(taxi_nodes,GetTeam()))
+ {
+ // problems with taxi path loading
+ TaxiNodesEntry const* nodeEntry = NULL;
+ if(uint32 node_id = m_taxi.GetTaxiSource())
+ nodeEntry = sTaxiNodesStore.LookupEntry(node_id);
+
+ if(!nodeEntry) // don't know taxi start node, to homebind
+ {
+ sLog.outError("Character %u have wrong data in taxi destination list, teleport to homebind.",GetGUIDLow());
+ RelocateToHomebind(mapId);
+ }
+ else // have start node, to it
+ {
+ sLog.outError("Character %u have too short taxi destination list, teleport to original node.",GetGUIDLow());
+ mapId = nodeEntry->map_id;
+ Relocate(nodeEntry->x, nodeEntry->y, nodeEntry->z,0.0f);
+ }
+ }
+ // Taxi path loading succesfull
+ else if(uint32 node_id = m_taxi.GetTaxiSource())
{
- sLog.outDebug("Player %s using client without required expansion tried login at non accessible map %u", GetName(), GetMapId());
- RelocateToHomebind();
+ // save source node as recall coord to prevent recall and fall from sky
+ TaxiNodesEntry const* nodeEntry = sTaxiNodesStore.LookupEntry(node_id);
+ assert(nodeEntry); // checked in m_taxi.LoadTaxiDestinationsFromString
+ Relocate(nodeEntry->x,nodeEntry->y,nodeEntry->z,0);
+ mapId = nodeEntry->map_id;
+ // flight will started later
}
}
+ // Map could be changed before
+ mapEntry = sMapStore.LookupEntry(mapId);
+ // client without expansion support
+ if(GetSession()->Expansion() < mapEntry->Expansion())
+ {
+ sLog.outDebug("Player %s using client without required expansion tried login at non accessible map %u", GetName(), mapId);
+ RelocateToHomebind(mapId);
+ instanceId = 0;
+ }
+
+ // fix crash (because of if(Map *map = _FindMap(instanceId)) in MapInstanced::CreateInstance)
+ if(instanceId)
+ if(InstanceSave * save = GetInstanceSave(mapId))
+ if(save->GetInstanceId() != instanceId)
+ instanceId = 0;
// NOW player must have valid map
// load the player's map here if it's not already loaded
- Map *map = GetMap();
+ Map *map = MapManager::Instance().CreateMap(mapId, this, instanceId);
if (!map)
{
- AreaTrigger const* at = objmgr.GetGoBackTrigger(GetMapId());
+ instanceId = 0;
+ AreaTrigger const* at = objmgr.GetGoBackTrigger(mapId);
if(at)
{
- SetMapId(at->target_mapId);
+ sLog.outError("Player (guidlow %d) is teleported to gobacktrigger (Map: %u X: %f Y: %f Z: %f O: %f).",guid,mapId,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
Relocate(at->target_X, at->target_Y, at->target_Z, GetOrientation());
- sLog.outError("Player (guidlow %d) is teleported to gobacktrigger (Map: %u X: %f Y: %f Z: %f O: %f).",guid,GetMapId(),GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
+ mapId = at->target_mapId;
}
else
{
- RelocateToHomebind();
- sLog.outError("Player (guidlow %d) is teleported to home (Map: %u X: %f Y: %f Z: %f O: %f).",guid,GetMapId(),GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
+ sLog.outError("Player (guidlow %d) is teleported to home (Map: %u X: %f Y: %f Z: %f O: %f).",guid,mapId,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
+ RelocateToHomebind(mapId);
}
- map = GetMap();
+ map = MapManager::Instance().CreateMap(mapId, this, 0);
if(!map)
{
- sLog.outError("ERROR: Player (guidlow %d) have invalid coordinates (X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.",guid,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
- delete result;
- return false;
-
- /*SetMapId(info->mapId);
+ PlayerInfo const *info = objmgr.GetPlayerInfo(getRace(), getClass());
+ mapId = info->mapId;
Relocate(info->positionX,info->positionY,info->positionZ,0.0f);
-
- map = GetMap();
- if(!map)
+ sLog.outError("ERROR: Player (guidlow %d) have invalid coordinates (X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.",guid,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
+ map = MapManager::Instance().CreateMap(mapId, this, 0);
+ if (!map)
{
- sLog.outError("ERROR: Player (guidlow %d) have invalid coordinates (X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.",guid,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
- sLog.outError("CRASH.");
- assert(false);
- }*/
+ sLog.outError("ERROR: Player (guidlow %d) has invalid default map coordinates (X: %f Y: %f Z: %f O: %f). or instance couldn't be created",guid,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
+ delete result;
+ return false;
+ }
}
}
- // since the player may not be bound to the map yet, make sure subsequent
- // getmap calls won't create new maps
- SetInstanceId(map->GetInstanceId());
-
// if the player is in an instance and it has been reset in the meantime teleport him to the entrance
- if(GetInstanceId() && !sInstanceSaveManager.GetInstanceSave(GetInstanceId()))
+ if(instanceId && !sInstanceSaveManager.GetInstanceSave(instanceId))
{
- AreaTrigger const* at = objmgr.GetMapEntranceTrigger(GetMapId());
+ AreaTrigger const* at = objmgr.GetMapEntranceTrigger(mapId);
if(at)
Relocate(at->target_X, at->target_Y, at->target_Z, at->target_Orientation);
else
- sLog.outError("Player %s(GUID: %u) logged in to a reset instance (map: %u) and there is no area-trigger leading to this map. Thus he can't be ported back to the entrance. This _might_ be an exploit attempt.", GetName(), GetGUIDLow(), GetMapId());
+ {
+ sLog.outError("Player %s(GUID: %u) logged in to a reset instance (map: %u) and there is no area-trigger leading to this map. Thus he can't be ported back to the entrance. This _might_ be an exploit attempt.", GetName(), GetGUIDLow(), mapId);
+ RelocateToHomebind(mapId);
+ instanceId = 0;
+ }
}
+ SetMap(map);
+
+ // randomize first save time in range [CONFIG_INTERVAL_SAVE] around [CONFIG_INTERVAL_SAVE]
+ // this must help in case next save after mass player load after server startup
+ m_nextSave = urand(m_nextSave/2,m_nextSave*3/2);
+
SaveRecallPosition();
time_t now = time(NULL);
- time_t logoutTime = time_t(fields[16].GetUInt64());
+ time_t logoutTime = time_t(fields[23].GetUInt64());
// since last logout (in seconds)
uint64 time_diff = uint64(now - logoutTime);
@@ -14637,27 +14863,27 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
uint16 newDrunkenValue = uint16(soberFactor*(GetUInt32Value(PLAYER_BYTES_3) & 0xFFFE));
SetDrunkValue(newDrunkenValue);
- m_rest_bonus = fields[15].GetFloat();
+ m_rest_bonus = fields[22].GetFloat();
//speed collect rest bonus in offline, in logout, far from tavern, city (section/in hour)
float bubble0 = 0.031;
//speed collect rest bonus in offline, in logout, in tavern, city (section/in hour)
float bubble1 = 0.125;
- if((int32)fields[16].GetUInt32() > 0)
+ if(time_diff > 0)
{
- float bubble = fields[17].GetUInt32() > 0
+ float bubble = fields[24].GetUInt32() > 0
? bubble1*sWorld.getRate(RATE_REST_OFFLINE_IN_TAVERN_OR_CITY)
: bubble0*sWorld.getRate(RATE_REST_OFFLINE_IN_WILDERNESS);
SetRestBonus(GetRestBonus()+ time_diff*((float)GetUInt32Value(PLAYER_NEXT_LEVEL_XP)/72000)*bubble);
}
- m_cinematic = fields[12].GetUInt32();
- m_Played_time[0]= fields[13].GetUInt32();
- m_Played_time[1]= fields[14].GetUInt32();
+ m_cinematic = fields[19].GetUInt32();
+ m_Played_time[PLAYED_TIME_TOTAL]= fields[20].GetUInt32();
+ m_Played_time[PLAYED_TIME_LEVEL]= fields[21].GetUInt32();
- m_resetTalentsCost = fields[18].GetUInt32();
- m_resetTalentsTime = time_t(fields[19].GetUInt64());
+ m_resetTalentsCost = fields[25].GetUInt32();
+ m_resetTalentsTime = time_t(fields[26].GetUInt64());
// reserve some flags
uint32 old_safe_flags = GetUInt32Value(PLAYER_FLAGS) & ( PLAYER_FLAGS_HIDE_CLOAK | PLAYER_FLAGS_HIDE_HELM );
@@ -14665,30 +14891,28 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
if( HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM) )
SetUInt32Value(PLAYER_FLAGS, 0 | old_safe_flags);
- m_taxi.LoadTaxiMask( fields[11].GetString() ); // must be before InitTaxiNodesForLevel
+ m_taxi.LoadTaxiMask( fields[18].GetString() ); // must be before InitTaxiNodesForLevel
- uint32 extraflags = fields[25].GetUInt32();
+ uint32 extraflags = fields[32].GetUInt32();
- m_stableSlots = fields[26].GetUInt32();
+ m_stableSlots = fields[33].GetUInt32();
if(m_stableSlots > MAX_PET_STABLES)
{
sLog.outError("Player can have not more %u stable slots, but have in DB %u",MAX_PET_STABLES,uint32(m_stableSlots));
m_stableSlots = MAX_PET_STABLES;
}
- m_atLoginFlags = fields[27].GetUInt32();
+ m_atLoginFlags = fields[34].GetUInt32();
// Honor system
// Update Honor kills data
m_lastHonorUpdateTime = logoutTime;
UpdateHonorFields();
- m_deathExpireTime = (time_t)fields[30].GetUInt64();
+ m_deathExpireTime = (time_t)fields[37].GetUInt64();
if(m_deathExpireTime > now+MAX_DEATH_COUNT*DEATH_EXPIRE_STEP)
m_deathExpireTime = now+MAX_DEATH_COUNT*DEATH_EXPIRE_STEP-1;
- std::string taxi_nodes = fields[31].GetCppString();
-
delete result;
// clear channel spell data (if saved at channel spell casting)
@@ -14774,42 +14998,6 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
SetUInt32Value(PLAYER_CHOSEN_TITLE, 0);
}
- // Not finish taxi flight path
- if(!m_taxi.LoadTaxiDestinationsFromString(taxi_nodes,GetTeam()))
- {
- // problems with taxi path loading
- TaxiNodesEntry const* nodeEntry = NULL;
- if(uint32 node_id = m_taxi.GetTaxiSource())
- nodeEntry = sTaxiNodesStore.LookupEntry(node_id);
-
- if(!nodeEntry) // don't know taxi start node, to homebind
- {
- sLog.outError("Character %u have wrong data in taxi destination list, teleport to homebind.",GetGUIDLow());
- RelocateToHomebind();
- SaveRecallPosition(); // save as recall also to prevent recall and fall from sky
- }
- else // have start node, to it
- {
- sLog.outError("Character %u have too short taxi destination list, teleport to original node.",GetGUIDLow());
- SetMapId(nodeEntry->map_id);
- Relocate(nodeEntry->x, nodeEntry->y, nodeEntry->z,0.0f);
- SaveRecallPosition(); // save as recall also to prevent recall and fall from sky
- }
- m_taxi.ClearTaxiDestinations();
- }
- else if(uint32 node_id = m_taxi.GetTaxiSource())
- {
- // save source node as recall coord to prevent recall and fall from sky
- TaxiNodesEntry const* nodeEntry = sTaxiNodesStore.LookupEntry(node_id);
- assert(nodeEntry); // checked in m_taxi.LoadTaxiDestinationsFromString
- m_recallMap = nodeEntry->map_id;
- m_recallX = nodeEntry->x;
- m_recallY = nodeEntry->y;
- m_recallZ = nodeEntry->z;
-
- // flight will started later
- }
-
// has to be called after last Relocate() in Player::LoadFromDB
SetFallInformation(0, GetPositionZ());
@@ -14928,7 +15116,7 @@ void Player::_LoadActions(QueryResult *result)
{
m_actionButtons.clear();
- //QueryResult *result = CharacterDatabase.PQuery("SELECT button,action,type,misc FROM character_action WHERE guid = '%u' ORDER BY button",GetGUIDLow());
+ //QueryResult *result = CharacterDatabase.PQuery("SELECT button,action,type FROM character_action WHERE guid = '%u' ORDER BY button",GetGUIDLow());
if(result)
{
@@ -14937,9 +15125,11 @@ void Player::_LoadActions(QueryResult *result)
Field *fields = result->Fetch();
uint8 button = fields[0].GetUInt8();
+ uint32 action = fields[1].GetUInt32();
+ uint8 type = fields[2].GetUInt8();
- if(addActionButton(button, fields[1].GetUInt16(), fields[2].GetUInt8(), fields[3].GetUInt8()))
- m_actionButtons[button].uState = ACTIONBUTTON_UNCHANGED;
+ if(ActionButton* ab = addActionButton(button, action, type))
+ ab->uState = ACTIONBUTTON_UNCHANGED;
else
{
sLog.outError( " ...at loading, and will deleted in DB also");
@@ -15012,7 +15202,7 @@ void Player::_LoadAuras(QueryResult *result, uint32 timediff)
delete result;
}
- if(m_class == CLASS_WARRIOR)
+ if(getClass() == CLASS_WARRIOR && !HasAuraType(SPELL_AURA_MOD_SHAPESHIFT))
CastSpell(this,SPELL_ID_PASSIVE_BATTLE_STANCE,true);
}
@@ -15248,7 +15438,7 @@ void Player::_LoadMailedItems(Mail *mail)
if(!proto)
{
- sLog.outError( "Player %u have unknown item_template (ProtoType) in mailed items(GUID: %u template: %u) in mail (%u), deleted.", GetGUIDLow(), item_guid_low, item_template,mail->messageID);
+ sLog.outError( "Player %u has unknown item_template (ProtoType) in mailed items(GUID: %u template: %u) in mail (%u), deleted.", GetGUIDLow(), item_guid_low, item_template,mail->messageID);
CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid = '%u'", item_guid_low);
CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", item_guid_low);
continue;
@@ -15508,7 +15698,7 @@ void Player::_LoadSpells(QueryResult *result)
{
Field *fields = result->Fetch();
- addSpell(fields[0].GetUInt16(), fields[1].GetBool(), false, false, fields[2].GetBool());
+ addSpell(fields[0].GetUInt32(), fields[1].GetBool(), false, false, fields[2].GetBool());
}
while( result->NextRow() );
@@ -15595,6 +15785,19 @@ InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, uint8 difficulty)
return NULL;
}
+InstanceSave * Player::GetInstanceSave(uint32 mapid)
+{
+ InstancePlayerBind *pBind = GetBoundInstance(mapid, GetDifficulty());
+ InstanceSave *pSave = pBind ? pBind->save : NULL;
+ if(!pBind || !pBind->perm)
+ {
+ if(Group *group = GetGroup())
+ if(InstanceGroupBind *groupBind = group->GetBoundInstance(mapid, GetDifficulty()))
+ pSave = groupBind->save;
+ }
+ return pSave;
+}
+
void Player::UnbindInstance(uint32 mapid, uint8 difficulty, bool unload)
{
BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid);
@@ -15764,8 +15967,7 @@ bool Player::Satisfy(AccessRequirement const *ar, uint32 target_map, bool report
{
if(ar->levelMin && getLevel() < ar->levelMin)
LevelMin = ar->levelMin;
- else if(ar->heroicLevelMin && GetDifficulty() == DIFFICULTY_HEROIC
- && getLevel() < ar->heroicLevelMin)
+ if(ar->heroicLevelMin && GetDifficulty() == DIFFICULTY_HEROIC && getLevel() < ar->heroicLevelMin)
LevelMin = ar->heroicLevelMin;
if(ar->levelMax && getLevel() > ar->levelMax)
LevelMax = ar->levelMax;
@@ -15807,7 +16009,7 @@ bool Player::Satisfy(AccessRequirement const *ar, uint32 target_map, bool report
if(report)
{
if(missingItem)
- GetSession()->SendAreaTriggerMessage(GetSession()->GetTrinityString(LANG_LEVEL_MINREQUIRED_AND_ITEM), ar->levelMin, objmgr.GetItemPrototype(missingItem)->Name1);
+ GetSession()->SendAreaTriggerMessage(GetSession()->GetTrinityString(LANG_LEVEL_MINREQUIRED_AND_ITEM), LevelMin, objmgr.GetItemPrototype(missingItem)->Name1);
else if(missingKey)
SendTransferAborted(target_map, TRANSFER_ABORT_DIFFICULTY);
else if(missingHeroicQuest)
@@ -15882,30 +16084,19 @@ void Player::SaveToDB()
// delay auto save at any saves (manual, in code, or autosave)
m_nextSave = sWorld.getConfig(CONFIG_INTERVAL_SAVE);
+ //lets allow only players in world to be saved
+ if(IsBeingTeleportedFar())
+ {
+ ScheduleDelayedOperation(DELAYED_SAVE_PLAYER);
+ return;
+ }
+
// first save/honor gain after midnight will also update the player's honor fields
UpdateHonorFields();
- uint32 is_save_resting = HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) ? 1 : 0;
- //save, far from tavern/city
- //save, but in tavern/city
sLog.outDebug("The value of player %s at save: ", m_name.c_str());
outDebugValues();
- // save state (after auras removing), if aura remove some flags then it must set it back by self)
- uint32 tmp_bytes = GetUInt32Value(UNIT_FIELD_BYTES_1);
- uint32 tmp_bytes2 = GetUInt32Value(UNIT_FIELD_BYTES_2);
- uint32 tmp_flags = GetUInt32Value(UNIT_FIELD_FLAGS);
- uint32 tmp_pflags = GetUInt32Value(PLAYER_FLAGS);
- uint32 tmp_displayid = GetDisplayId();
-
- // Set player sit state to standing on save, also stealth and shifted form
- SetByteValue(UNIT_FIELD_BYTES_1, 0, UNIT_STAND_STATE_STAND);
- SetByteValue(UNIT_FIELD_BYTES_2, 3, 0); // shapeshift
- RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
- SetDisplayId(GetNativeDisplayId());
-
- bool inworld = IsInWorld();
-
CharacterDatabase.BeginTransaction();
CharacterDatabase.PExecute("DELETE FROM characters WHERE guid = '%u'",GetGUIDLow());
@@ -15914,7 +16105,7 @@ void Player::SaveToDB()
CharacterDatabase.escape_string(sql_name);
std::ostringstream ss;
- ss << "INSERT INTO characters (guid,account,name,race,class,"
+ ss << "INSERT INTO characters (guid,account,name,race,class,gender,level,xp,money,playerBytes,playerBytes2,playerFlags,"
"map, instance_id, dungeon_difficulty, position_x, position_y, position_z, orientation, data, "
"taximask, online, cinematic, "
"totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, "
@@ -15923,8 +16114,15 @@ void Player::SaveToDB()
<< GetGUIDLow() << ", "
<< GetSession()->GetAccountId() << ", '"
<< sql_name << "', "
- << m_race << ", "
- << m_class << ", ";
+ << (uint32)getRace() << ", "
+ << (uint32)getClass() << ", "
+ << (uint32)getGender() << ", "
+ << getLevel() << ", "
+ << GetUInt32Value(PLAYER_XP) << ", "
+ << GetMoney() << ", "
+ << GetUInt32Value(PLAYER_BYTES) << ", "
+ << GetUInt32Value(PLAYER_BYTES_2) << ", "
+ << GetUInt32Value(PLAYER_FLAGS) << ", ";
if(!IsBeingTeleported())
{
@@ -15955,69 +16153,48 @@ void Player::SaveToDB()
ss << "', ";
- ss << m_taxi; // string with TaxiMaskSize numbers
+ ss << m_taxi << ", "; // string with TaxiMaskSize numbers
- ss << ", ";
- ss << (inworld ? 1 : 0);
+ ss << (IsInWorld() ? 1 : 0) << ", ";
- ss << ", ";
- ss << m_cinematic;
+ ss << m_cinematic << ", ";
- ss << ", ";
- ss << m_Played_time[0];
- ss << ", ";
- ss << m_Played_time[1];
+ ss << m_Played_time[PLAYED_TIME_TOTAL] << ", ";
+ ss << m_Played_time[PLAYED_TIME_LEVEL] << ", ";
- ss << ", ";
- ss << finiteAlways(m_rest_bonus);
- ss << ", ";
- ss << (uint64)time(NULL);
- ss << ", ";
- ss << is_save_resting;
- ss << ", ";
- ss << m_resetTalentsCost;
- ss << ", ";
- ss << (uint64)m_resetTalentsTime;
+ ss << finiteAlways(m_rest_bonus) << ", ";
+ ss << (uint64)time(NULL) << ", ";
+ ss << (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) ? 1 : 0) << ", ";
+ //save, far from tavern/city
+ //save, but in tavern/city
+ ss << m_resetTalentsCost << ", ";
+ ss << (uint64)m_resetTalentsTime << ", ";
- ss << ", ";
- ss << finiteAlways(m_movementInfo.t_x);
- ss << ", ";
- ss << finiteAlways(m_movementInfo.t_y);
- ss << ", ";
- ss << finiteAlways(m_movementInfo.t_z);
- ss << ", ";
- ss << finiteAlways(m_movementInfo.t_o);
- ss << ", ";
+ ss << finiteAlways(m_movementInfo.t_x) << ", ";
+ ss << finiteAlways(m_movementInfo.t_y) << ", ";
+ ss << finiteAlways(m_movementInfo.t_z) << ", ";
+ ss << finiteAlways(m_movementInfo.t_o) << ", ";
if (m_transport)
ss << m_transport->GetGUIDLow();
else
ss << "0";
-
ss << ", ";
- ss << m_ExtraFlags;
- ss << ", ";
- ss << uint32(m_stableSlots); // to prevent save uint8 as char
+ ss << m_ExtraFlags << ", ";
- ss << ", ";
- ss << uint32(m_atLoginFlags & ((1<<AT_LOAD_PET_FLAGS) -1));
+ ss << uint32(m_stableSlots) << ", "; // to prevent save uint8 as char
- ss << ", ";
- ss << GetZoneId();
+ ss << uint32(m_atLoginFlags) << ", ";
- ss << ", ";
- ss << (uint64)m_deathExpireTime;
+ ss << GetZoneId() << ", ";
- ss << ", '";
- ss << m_taxi.SaveTaxiDestinationsToString();
+ ss << (uint64)m_deathExpireTime << ", '";
- ss << "', '0', ";
- ss << GetSession()->GetLatency();
- ss << ", ";
- ss << GetBattleGroundId();
- ss << ", ";
- ss << GetBGTeam();
- ss << ", ";
+ ss << m_taxi.SaveTaxiDestinationsToString() << "', ";
+ ss << "'0', "; // arena_pending_points
+ ss << GetSession()->GetLatency() << ", ";
+ ss << GetBattleGroundId() << ", ";
+ ss << GetBGTeam() << ", ";
ss << m_bgEntryPoint.mapid << ", "
<< finiteAlways(m_bgEntryPoint.coord_x) << ", "
<< finiteAlways(m_bgEntryPoint.coord_y) << ", "
@@ -16044,13 +16221,6 @@ void Player::SaveToDB()
CharacterDatabase.CommitTransaction();
- // restore state (before aura apply, if aura remove flag then aura must set it ack by self)
- SetDisplayId(tmp_displayid);
- SetUInt32Value(UNIT_FIELD_BYTES_1, tmp_bytes);
- SetUInt32Value(UNIT_FIELD_BYTES_2, tmp_bytes2);
- SetUInt32Value(UNIT_FIELD_FLAGS, tmp_flags);
- SetUInt32Value(PLAYER_FLAGS, tmp_pflags);
-
// save pet (hunter pet level and experience and all type pets health/mana).
if(Pet* pet = GetPet())
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
@@ -16060,8 +16230,12 @@ void Player::SaveToDB()
void Player::SaveInventoryAndGoldToDB()
{
_SaveInventory();
- //money is in data field
- SaveDataFieldToDB();
+ SaveGoldToDB();
+}
+
+void Player::SaveGoldToDB()
+{
+ CharacterDatabase.PExecute("UPDATE characters SET money = '%u' WHERE guid = '%u'", GetMoney(), GetGUIDLow());
}
void Player::_SaveActions()
@@ -16071,14 +16245,14 @@ void Player::_SaveActions()
switch (itr->second.uState)
{
case ACTIONBUTTON_NEW:
- CharacterDatabase.PExecute("INSERT INTO character_action (guid,button,action,type,misc) VALUES ('%u', '%u', '%u', '%u', '%u')",
- GetGUIDLow(), (uint32)itr->first, (uint32)itr->second.action, (uint32)itr->second.type, (uint32)itr->second.misc );
+ CharacterDatabase.PExecute("INSERT INTO character_action (guid,button,action,type) VALUES ('%u', '%u', '%u', '%u')",
+ GetGUIDLow(), (uint32)itr->first, (uint32)itr->second.GetAction(), (uint32)itr->second.GetType() );
itr->second.uState = ACTIONBUTTON_UNCHANGED;
++itr;
break;
case ACTIONBUTTON_CHANGED:
- CharacterDatabase.PExecute("UPDATE character_action SET action = '%u', type = '%u', misc= '%u' WHERE guid= '%u' AND button= '%u' ",
- (uint32)itr->second.action, (uint32)itr->second.type, (uint32)itr->second.misc, GetGUIDLow(), (uint32)itr->first );
+ CharacterDatabase.PExecute("UPDATE character_action SET action = '%u', type = '%u' WHERE guid= '%u' AND button= '%u' ",
+ (uint32)itr->second.GetAction(), (uint32)itr->second.GetType(), GetGUIDLow(), (uint32)itr->first );
itr->second.uState = ACTIONBUTTON_UNCHANGED;
++itr;
break;
@@ -16089,7 +16263,7 @@ void Player::_SaveActions()
default:
++itr;
break;
- };
+ }
}
}
@@ -16103,13 +16277,11 @@ void Player::_SaveAuras()
// skip:
// area auras or single cast auras casted by other unit
// passive auras and stances
- if (itr->second->IsPassive()
- || itr->second->IsAuraType(SPELL_AURA_MOD_SHAPESHIFT)
- || itr->second->IsRemovedOnShapeLost())
+ if (itr->second->IsPassive())
continue;
- bool isCaster = itr->second->GetCasterGUID() == GetGUID();
- if (!isCaster)
- if (itr->second->IsSingleTarget()
+
+ if (itr->second->GetCasterGUID() != GetGUID())
+ if (IsSingleTargetSpell(itr->second->GetSpellProto())
|| itr->second->IsAreaAura())
continue;
@@ -16330,7 +16502,7 @@ void Player::outDebugValues() const
sLog.outDebug("HP is: \t\t\t%u\t\tMP is: \t\t\t%u",GetMaxHealth(), GetMaxPower(POWER_MANA));
sLog.outDebug("AGILITY is: \t\t%f\t\tSTRENGTH is: \t\t%f",GetStat(STAT_AGILITY), GetStat(STAT_STRENGTH));
sLog.outDebug("INTELLECT is: \t\t%f\t\tSPIRIT is: \t\t%f",GetStat(STAT_INTELLECT), GetStat(STAT_SPIRIT));
- sLog.outDebug("STAMINA is: \t\t%f\t\tSPIRIT is: \t\t%f",GetStat(STAT_STAMINA), GetStat(STAT_SPIRIT));
+ sLog.outDebug("STAMINA is: \t\t%f",GetStat(STAT_STAMINA));
sLog.outDebug("Armor is: \t\t%u\t\tBlock is: \t\t%f",GetArmor(), GetFloatValue(PLAYER_BLOCK_PERCENTAGE));
sLog.outDebug("HolyRes is: \t\t%u\t\tFireRes is: \t\t%u",GetResistance(SPELL_SCHOOL_HOLY), GetResistance(SPELL_SCHOOL_FIRE));
sLog.outDebug("NatureRes is: \t\t%u\t\tFrostRes is: \t\t%u",GetResistance(SPELL_SCHOOL_NATURE), GetResistance(SPELL_SCHOOL_FROST));
@@ -16465,38 +16637,20 @@ void Player::SetFloatValueInDB(uint16 index, float value, uint64 guid)
void Player::Customize(uint64 guid, uint8 gender, uint8 skin, uint8 face, uint8 hairStyle, uint8 hairColor, uint8 facialHair)
{
- Tokens tokens;
- if(!LoadValuesArrayFromDB(tokens, guid))
- return;
-
- uint32 unit_bytes0 = GetUInt32ValueFromArray(tokens, UNIT_FIELD_BYTES_0);
- uint8 race = unit_bytes0 & 0xFF;
- uint8 class_ = (unit_bytes0 >> 8) & 0xFF;
-
- PlayerInfo const* info = objmgr.GetPlayerInfo(race, class_);
- if(!info)
+ // 0
+ QueryResult* result = CharacterDatabase.PQuery("SELECT playerBytes2 FROM characters WHERE guid = '%u'", GUID_LOPART(guid));
+ if(!result)
return;
- unit_bytes0 &= ~(0xFF << 16);
- unit_bytes0 |= (gender << 16);
- SetUInt32ValueInArray(tokens, UNIT_FIELD_BYTES_0, unit_bytes0);
-
- SetUInt32ValueInArray(tokens, UNIT_FIELD_DISPLAYID, gender ? info->displayId_f : info->displayId_m);
- SetUInt32ValueInArray(tokens, UNIT_FIELD_NATIVEDISPLAYID, gender ? info->displayId_f : info->displayId_m);
-
- SetUInt32ValueInArray(tokens, PLAYER_BYTES, (skin | (face << 8) | (hairStyle << 16) | (hairColor << 24)));
+ Field* fields = result->Fetch();
- uint32 player_bytes2 = GetUInt32ValueFromArray(tokens, PLAYER_BYTES_2);
+ uint32 player_bytes2 = fields[0].GetUInt32();
player_bytes2 &= ~0xFF;
player_bytes2 |= facialHair;
- SetUInt32ValueInArray(tokens, PLAYER_BYTES_2, player_bytes2);
- uint32 player_bytes3 = GetUInt32ValueFromArray(tokens, PLAYER_BYTES_3);
- player_bytes3 &= ~0xFF;
- player_bytes3 |= gender;
- SetUInt32ValueInArray(tokens, PLAYER_BYTES_3, player_bytes3);
+ CharacterDatabase.PExecute("UPDATE characters SET gender = '%u', playerBytes = '%u', playerBytes2 = '%u' WHERE guid = '%u'", gender, skin | (face << 8) | (hairStyle << 16) | (hairColor << 24), player_bytes2, GUID_LOPART(guid));
- SaveValuesArrayInDB(tokens, guid);
+ delete result;
}
void Player::SendAttackSwingDeadTarget()
@@ -16523,10 +16677,10 @@ void Player::SendAttackSwingBadFacingAttack()
GetSession()->SendPacket( &data );
}
-void Player::SendAutoRepeatCancel()
+void Player::SendAutoRepeatCancel(Unit *target)
{
- WorldPacket data(SMSG_CANCEL_AUTO_REPEAT, GetPackGUID().size());
- data.append(GetPackGUID()); // may be it's target guid
+ WorldPacket data(SMSG_CANCEL_AUTO_REPEAT, target->GetPackGUID().size());
+ data.append(target->GetPackGUID()); // may be it's target guid
GetSession()->SendPacket( &data );
}
@@ -16751,7 +16905,6 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent)
SetMinion(pet, false);
- pet->CleanupsBeforeDelete();
pet->AddObjectToRemoveList();
pet->m_removed = true;
@@ -16784,8 +16937,14 @@ void Player::StopCastingCharm()
if(GetCharmGUID())
{
- sLog.outCrash("Player %s is not able to uncharm unit (Entry: %u, Type: %u)", GetName(), charm->GetEntry(), charm->GetTypeId());
- assert(false);
+ sLog.outCrash("Player %s (GUID: " UI64FMTD " is not able to uncharm unit (GUID: " UI64FMTD " Entry: %u, Type: %u)", GetName(), GetGUID(), GetCharmGUID(), charm->GetEntry(), charm->GetTypeId());
+ if(charm->GetCharmerGUID())
+ {
+ sLog.outCrash("Charmed unit has charmer guid " UI64FMTD, charm->GetCharmerGUID());
+ assert(false);
+ }
+ else
+ SetCharm(charm, false);
}
}
@@ -16911,8 +17070,7 @@ void Player::PetSpellInitialize()
if(itr->second.state == PETSPELL_REMOVED)
continue;
- data << uint16(itr->first);
- data << uint16(itr->second.active); // pet spell active state isn't boolean
+ data << uint32(MAKE_UNIT_ACTION_BUTTON(itr->first,itr->second.active));
++addlist;
}
}
@@ -17037,7 +17195,7 @@ void Player::CharmSpellInitialize()
{
for(uint32 i = 0; i < MAX_SPELL_CHARM; ++i)
{
- if(charmInfo->GetCharmSpell(i)->spellId)
+ if(charmInfo->GetCharmSpell(i)->GetAction())
++addlist;
}
}
@@ -17062,11 +17220,8 @@ void Player::CharmSpellInitialize()
for(uint32 i = 0; i < MAX_SPELL_CHARM; ++i)
{
CharmSpellEntry *cspell = charmInfo->GetCharmSpell(i);
- if(cspell->spellId)
- {
- data << uint16(cspell->spellId);
- data << uint16(cspell->active);
- }
+ if(cspell->GetAction())
+ data << uint32(cspell->packedData);
}
}
@@ -17162,6 +17317,10 @@ void Player::RestoreSpellMods(Spell * spell)
else
mod->charges++;
+ // Do not set more spellmods than avalible
+ if (mod->ownerAura->GetAuraCharges() < mod->charges)
+ mod->charges = mod->ownerAura->GetAuraCharges();
+
// Skip this check for now - aura charges may change due to various reason
// TODO: trac these changes correctly
//assert (mod->ownerAura->GetAuraCharges() <= mod->charges);
@@ -17189,11 +17348,7 @@ void Player::RemoveSpellMods(Spell * spell)
checkedSpells.find(aur->GetParentAura()) != checkedSpells.end())
continue;
- flag96 const * mask = spellmgr.GetSpellAffect(aur->GetId(), aur->GetEffIndex());
- if (!mask)
- mask = &spellInfo->EffectSpellClassMask[aur->GetEffIndex()];
-
- if (spell->m_spellInfo->SpellFamilyFlags & *mask)
+ if (spell->m_spellInfo->SpellFamilyFlags & spellInfo->EffectSpellClassMask[aur->GetEffIndex()])
{
checkedSpells.insert(aur->GetParentAura());
spell->m_appliedMods.erase(aur->GetParentAura());
@@ -17248,6 +17403,9 @@ void Player::SetSpellModTakingSpell(Spell * spell, bool apply)
if (!spell || (m_spellModTakingSpell && m_spellModTakingSpell != spell))
return;
+ if (apply && spell->getState() == SPELL_STATE_FINISHED)
+ return;
+
if (apply)
m_spellModTakingSpell = spell;
else
@@ -17360,19 +17518,38 @@ void Player::HandleStealthedUnitsDetection()
Trinity::UnitListSearcher<Trinity::AnyStealthedCheck > searcher(this, stealthedUnits, u_check);
VisitNearbyObject(World::GetMaxVisibleDistance(), searcher);
- for (std::list<Unit*>::iterator i = stealthedUnits.begin(); i != stealthedUnits.end(); ++i)
+ for (std::list<Unit*>::const_iterator i = stealthedUnits.begin(); i != stealthedUnits.end(); ++i)
{
- if (!HaveAtClient(*i) && canSeeOrDetect(*i, true))
+ if((*i)==this)
+ continue;
+
+ bool hasAtClient = HaveAtClient((*i));
+ bool hasDetected = canSeeOrDetect(*i, true);
+
+ if (hasDetected)
{
- (*i)->SendUpdateToPlayer(this);
- m_clientGUIDs.insert((*i)->GetGUID());
+ if(!hasAtClient)
+ {
+ (*i)->SendUpdateToPlayer(this);
+ m_clientGUIDs.insert((*i)->GetGUID());
- #ifdef TRINITY_DEBUG
- if((sLog.getLogFilter() & LOG_FILTER_VISIBILITY_CHANGES)==0)
- sLog.outDebug("Object %u (Type: %u) is detected in stealth by player %u. Distance = %f",(*i)->GetGUIDLow(),(*i)->GetTypeId(),GetGUIDLow(),GetDistance(*i));
- #endif
+ #ifdef MANGOS_DEBUG
+ if((sLog.getLogFilter() & LOG_FILTER_VISIBILITY_CHANGES)==0)
+ sLog.outDebug("Object %u (Type: %u) is detected in stealth by player %u. Distance = %f",(*i)->GetGUIDLow(),(*i)->GetTypeId(),GetGUIDLow(),GetDistance(*i));
+ #endif
- SendInitialVisiblePackets(*i);
+ // target aura duration for caster show only if target exist at caster client
+ // send data at target visibility change (adding to client)
+ SendInitialVisiblePackets(*i);
+ }
+ }
+ else
+ {
+ if(hasAtClient)
+ {
+ (*i)->DestroyForPlayer(this);
+ m_clientGUIDs.erase((*i)->GetGUID());
+ }
}
}
}
@@ -17382,8 +17559,8 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc
if(nodes.size() < 2)
return false;
- // not let cheating with start flight in time of logout process || if casting not finished || while in combat || if not use Spell's with EffectSendTaxi
- if(GetSession()->isLogingOut() || isInCombat())
+ // not let cheating with start flight in time of logout process || while in combat || has type state: stunned || has type state: root
+ if(GetSession()->isLogingOut() || isInCombat() || hasUnitState(UNIT_STAT_STUNNED) || hasUnitState(UNIT_STAT_ROOT))
{
WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4);
data << uint32(ERR_TAXIPLAYERBUSY);
@@ -17585,6 +17762,14 @@ bool Player::ActivateTaxiPathTo( uint32 taxi_path_id, uint32 spellid /*= 0*/ )
return ActivateTaxiPathTo(nodes,NULL,spellid);
}
+void Player::CleanupAfterTaxiFlight()
+{
+ m_taxi.ClearTaxiDestinations(); // not destinations, clear source node
+ Unmount();
+ RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
+ getHostilRefManager().setOnlineOfflineState(true);
+}
+
void Player::ProhibitSpellScholl(SpellSchoolMask idSchoolMask, uint32 unTimeMs )
{
// last check 2.0.10
@@ -17666,17 +17851,47 @@ void Player::InitDataForForm(bool reapplyMods)
UpdateAttackPowerAndDamage(true);
}
+void Player::InitDisplayIds()
+{
+ PlayerInfo const *info = objmgr.GetPlayerInfo(getRace(), getClass());
+ if(!info)
+ {
+ sLog.outError("Player %u has incorrect race/class pair. Can't init display ids.", GetGUIDLow());
+ return;
+ }
+
+ uint8 gender = getGender();
+ switch(gender)
+ {
+ case GENDER_FEMALE:
+ SetDisplayId(info->displayId_f );
+ SetNativeDisplayId(info->displayId_f );
+ break;
+ case GENDER_MALE:
+ SetDisplayId(info->displayId_m );
+ SetNativeDisplayId(info->displayId_m );
+ break;
+ default:
+ sLog.outError("Invalid gender %u for player",gender);
+ return;
+ }
+}
+
// Return true is the bought item has a max count to force refresh of window by caller
-bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint64 bagguid, uint8 slot)
+bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint8 bag, uint8 slot)
{
// cheating attempt
- if(count < 1) count = 1;
+ if (count < 1) count = 1;
- if(!isAlive())
+ // cheating attempt
+ if(slot > MAX_BAG_SIZE && slot !=NULL_SLOT)
+ return false;
+
+ if (!isAlive())
return false;
ItemPrototype const *pProto = objmgr.GetItemPrototype( item );
- if( !pProto )
+ if (!pProto)
{
SendBuyError( BUY_ERR_CANT_FIND_ITEM, NULL, item, 0);
return false;
@@ -17698,7 +17913,7 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
}
size_t vendor_slot = vItems->FindItemSlot(item);
- if(vendor_slot >= vItems->GetItemCount())
+ if (vendor_slot >= vItems->GetItemCount())
{
SendBuyError( BUY_ERR_CANT_FIND_ITEM, pCreature, item, 0);
return false;
@@ -17707,39 +17922,39 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
VendorItem const* crItem = vItems->m_items[vendor_slot];
// check current item amount if it limited
- if( crItem->maxcount != 0 )
+ if (crItem->maxcount != 0)
{
- if(pCreature->GetVendorItemCurrentCount(crItem) < pProto->BuyCount * count )
+ if (pCreature->GetVendorItemCurrentCount(crItem) < pProto->BuyCount * count )
{
SendBuyError( BUY_ERR_ITEM_ALREADY_SOLD, pCreature, item, 0);
return false;
}
}
- if( uint32(GetReputationRank(pProto->RequiredReputationFaction)) < pProto->RequiredReputationRank)
+ if (uint32(GetReputationRank(pProto->RequiredReputationFaction)) < pProto->RequiredReputationRank)
{
SendBuyError( BUY_ERR_REPUTATION_REQUIRE, pCreature, item, 0);
return false;
}
- if(crItem->ExtendedCost)
+ if (crItem->ExtendedCost)
{
ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost);
- if(!iece)
+ if (!iece)
{
sLog.outError("Item %u have wrong ExtendedCost field value %u", pProto->ItemId, crItem->ExtendedCost);
return false;
}
// honor points price
- if(GetHonorPoints() < (iece->reqhonorpoints * count))
+ if (GetHonorPoints() < (iece->reqhonorpoints * count))
{
SendEquipError(EQUIP_ERR_NOT_ENOUGH_HONOR_POINTS, NULL, NULL);
return false;
}
// arena points price
- if(GetArenaPoints() < (iece->reqarenapoints * count))
+ if (GetArenaPoints() < (iece->reqarenapoints * count))
{
SendEquipError(EQUIP_ERR_NOT_ENOUGH_ARENA_POINTS, NULL, NULL);
return false;
@@ -17769,63 +17984,38 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
// reputation discount
price = uint32(floor(price * GetReputationPriceDiscount(pCreature)));
- if( GetMoney() < price )
+ if (GetMoney() < price)
{
SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, item, 0);
return false;
}
- uint8 bag = 0; // init for case invalid bagGUID
-
- if (bagguid != NULL_BAG && slot != NULL_SLOT)
- {
- if( bagguid == GetGUID() )
- {
- bag = INVENTORY_SLOT_BAG_0;
- }
- else
- {
- for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END;i++)
- {
- if( Bag *pBag = (Bag*)GetItemByPos(INVENTORY_SLOT_BAG_0,i) )
- {
- if( bagguid == pBag->GetGUID() )
- {
- if(slot < pBag->GetBagSlot() && !pBag->GetItemByPos(slot))
- bag = i;
- break;
- }
- }
- }
- }
- }
-
- if( IsInventoryPos( bag, slot ) || (bagguid == NULL_BAG && slot == NULL_SLOT) )
+ if ((bag == NULL_BAG && slot == NULL_SLOT) || IsInventoryPos(bag, slot))
{
ItemPosCountVec dest;
uint8 msg = CanStoreNewItem( bag, slot, dest, item, pProto->BuyCount * count );
- if( msg != EQUIP_ERR_OK )
+ if (msg != EQUIP_ERR_OK)
{
SendEquipError( msg, NULL, NULL );
return false;
}
ModifyMoney( -(int32)price );
- if(crItem->ExtendedCost) // case for new honor system
+ if (crItem->ExtendedCost) // case for new honor system
{
ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost);
- if(iece->reqhonorpoints)
+ if (iece->reqhonorpoints)
ModifyHonorPoints( - int32(iece->reqhonorpoints * count));
- if(iece->reqarenapoints)
+ if (iece->reqarenapoints)
ModifyArenaPoints( - int32(iece->reqarenapoints * count));
for (uint8 i = 0; i < 5; ++i)
{
- if(iece->reqitem[i])
+ if (iece->reqitem[i])
DestroyItemCount(iece->reqitem[i], (iece->reqitemcount[i] * count), true);
}
}
- if(Item *it = StoreNewItem( dest, item, true ))
+ if (Item *it = StoreNewItem( dest, item, true ))
{
uint32 new_count = pCreature->UpdateVendorItemCurrentCount(crItem,pProto->BuyCount * count);
@@ -17839,9 +18029,9 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
SendNewItem(it, pProto->BuyCount*count, true, false, false);
}
}
- else if( IsEquipmentPos( bag, slot ) )
+ else if (IsEquipmentPos(bag, slot))
{
- if(pProto->BuyCount * count != 1)
+ if (pProto->BuyCount * count != 1)
{
SendEquipError( EQUIP_ERR_ITEM_CANT_BE_EQUIPPED, NULL, NULL );
return false;
@@ -17849,19 +18039,19 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
uint16 dest;
uint8 msg = CanEquipNewItem( slot, dest, item, false );
- if( msg != EQUIP_ERR_OK )
+ if (msg != EQUIP_ERR_OK)
{
SendEquipError( msg, NULL, NULL );
return false;
}
ModifyMoney( -(int32)price );
- if(crItem->ExtendedCost) // case for new honor system
+ if (crItem->ExtendedCost) // case for new honor system
{
ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost);
- if(iece->reqhonorpoints)
+ if (iece->reqhonorpoints)
ModifyHonorPoints( - int32(iece->reqhonorpoints));
- if(iece->reqarenapoints)
+ if (iece->reqarenapoints)
ModifyArenaPoints( - int32(iece->reqarenapoints));
for (uint8 i = 0; i < 5; ++i)
{
@@ -17870,7 +18060,7 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
}
}
- if(Item *it = EquipNewItem( dest, item, true ))
+ if (Item *it = EquipNewItem( dest, item, true ))
{
uint32 new_count = pCreature->UpdateVendorItemCurrentCount(crItem,pProto->BuyCount * count);
@@ -17892,7 +18082,7 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
return false;
}
- return crItem->maxcount!=0;
+ return crItem->maxcount != 0;
}
uint32 Player::GetMaxPersonalArenaRatingRequirement()
@@ -18051,8 +18241,8 @@ void Player::AddSpellAndCategoryCooldowns(SpellEntry const* spellInfo, uint32 it
{
// use +MONTH as infinity mark for spell cooldown (will checked as MONTH/2 at save ans skipped)
// but not allow ignore until reset or re-login
- catrecTime = catrec > 0 ? curTime+MONTH : 0;
- recTime = rec > 0 ? curTime+MONTH : catrecTime;
+ catrecTime = catrec > 0 ? curTime+infinityCooldownDelay : 0;
+ recTime = rec > 0 ? curTime+infinityCooldownDelay : catrecTime;
}
else
{
@@ -18314,7 +18504,16 @@ void Player::LeaveBattleground(bool teleportToEntryPoint)
if( bg->isBattleGround() && !isGameMaster() && sWorld.getConfig(CONFIG_BATTLEGROUND_CAST_DESERTER) )
{
if( bg->GetStatus() == STATUS_IN_PROGRESS || bg->GetStatus() == STATUS_WAIT_JOIN )
+ {
+ //lets check if player was teleported from BG and schedule delayed Deserter spell cast
+ if(IsBeingTeleportedFar())
+ {
+ ScheduleDelayedOperation(DELAYED_SPELL_CAST_DESERTER);
+ return;
+ }
+
CastSpell(this, 26013, true); // Deserter
+ }
}
}
}
@@ -18322,7 +18521,7 @@ void Player::LeaveBattleground(bool teleportToEntryPoint)
bool Player::CanJoinToBattleground() const
{
// check Deserter debuff
- if(GetDummyAura(26013))
+ if(HasAura(26013))
return false;
return true;
@@ -18558,7 +18757,7 @@ void Player::UpdateVisibilityOf(WorldObject* target)
{
if(HaveAtClient(target))
{
- if(!target->isVisibleForInState(this,true))
+ if(!target->isVisibleForInState(this, true))
{
target->DestroyForPlayer(this);
m_clientGUIDs.erase(target->GetGUID());
@@ -18656,17 +18855,19 @@ void Player::SendComboPoints()
}
}
-void Player::AddComboPoints(Unit* target, int8 count)
+void Player::AddComboPoints(Unit* target, int8 count, Spell * spell)
{
if(!count)
return;
+ int8 * comboPoints = spell ? &spell->m_comboPointGain : &m_comboPoints;
+
// without combo points lost (duration checked in aura)
RemoveAurasByType(SPELL_AURA_RETAIN_COMBO_POINTS);
if(target->GetGUID() == m_comboTarget)
{
- m_comboPoints += count;
+ *comboPoints += count;
}
else
{
@@ -18675,13 +18876,26 @@ void Player::AddComboPoints(Unit* target, int8 count)
target2->RemoveComboPointHolder(GetGUIDLow());
m_comboTarget = target->GetGUID();
- m_comboPoints = count;
+ *comboPoints = count;
target->AddComboPointHolder(GetGUIDLow());
}
+ if (*comboPoints > 5) *comboPoints = 5;
+ else if (*comboPoints < 0) *comboPoints = 0;
+
+ if (!spell)
+ SendComboPoints();
+}
+
+void Player::GainSpellComboPoints(int8 count)
+{
+ if(!count)
+ return;
+
+ m_comboPoints += count;
if (m_comboPoints > 5) m_comboPoints = 5;
- if (m_comboPoints < 0) m_comboPoints = 0;
+ else if (m_comboPoints < 0) m_comboPoints = 0;
SendComboPoints();
}
@@ -18746,11 +18960,6 @@ void Player::SendInitialPacketsBeforeAddToMap()
m_reputationMgr.SendInitialReputations();
m_achievementMgr.SendAllAchievementData();
- // update zone
- uint32 newzone, newarea;
- GetZoneAndAreaId(newzone,newarea);
- UpdateZone(newzone,newarea); // also call SendInitWorldStates();
-
SendEquipmentSetList();
data.Initialize(SMSG_LOGIN_SETTIMESPEED, 4 + 4 + 4);
@@ -18762,6 +18971,11 @@ void Player::SendInitialPacketsBeforeAddToMap()
void Player::SendInitialPacketsAfterAddToMap()
{
+ // update zone
+ uint32 newzone, newarea;
+ GetZoneAndAreaId(newzone,newarea);
+ UpdateZone(newzone,newarea); // also call SendInitWorldStates();
+
WorldPacket data(SMSG_TIME_SYNC_REQ, 4); // new 2.0.x, enable movement
data << uint32(0x00000000); // on blizz it increments periodically
GetSession()->SendPacket(&data);
@@ -18883,17 +19097,14 @@ void Player::resetSpells()
{
// not need after this call
if(HasAtLoginFlag(AT_LOGIN_RESET_SPELLS))
- {
- m_atLoginFlags = m_atLoginFlags & ~AT_LOGIN_RESET_SPELLS;
- CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login & ~ %u WHERE guid ='%u'", uint32(AT_LOGIN_RESET_SPELLS), GetGUIDLow());
- }
+ RemoveAtLoginFlag(AT_LOGIN_RESET_SPELLS,true);
// make full copy of map (spells removed and marked as deleted at another spell remove
// and we can't use original map for safe iterative with visit each spell at loop end
PlayerSpellMap smap = GetSpellMap();
for(PlayerSpellMap::const_iterator iter = smap.begin();iter != smap.end(); ++iter)
- removeSpell(iter->first); // only iter->first can be accessed, object by iter->second can be deleted already
+ removeSpell(iter->first,false,false); // only iter->first can be accessed, object by iter->second can be deleted already
learnDefaultSpells();
learnQuestRewardedSpells();
@@ -18954,8 +19165,10 @@ void Player::learnQuestRewardedSpells(Quest const* quest)
if(!learnedInfo)
return;
+ uint32 profSpell = spellmgr.GetSpellRequired(learned_0);
+
// specialization
- if(learnedInfo->Effect[0]==SPELL_EFFECT_TRADE_SKILL && learnedInfo->Effect[1]==0)
+ if(learnedInfo->Effect[0]==SPELL_EFFECT_TRADE_SKILL && learnedInfo->Effect[1]==0 && profSpell)
{
// search other specialization for same prof
for(PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
@@ -18972,11 +19185,7 @@ void Player::learnQuestRewardedSpells(Quest const* quest)
continue;
// compare same chain spells
- if(spellmgr.GetFirstSpellInChain(itr->first) != first_spell)
- continue;
-
- // now we have 2 specialization, learn possible only if found is lesser specialization rank
- if(!spellmgr.IsHighRankOfSpell(learned_0,itr->first))
+ if (spellmgr.GetSpellRequired(itr->first) == profSpell)
return;
}
}
@@ -19273,7 +19482,7 @@ void Player::SummonIfPossible(bool agree)
if(isInFlight())
{
GetMotionMaster()->MovementExpired();
- m_taxi.ClearTaxiDestinations();
+ CleanupAfterTaxiFlight();
}
// drop flag at summon
@@ -19572,7 +19781,7 @@ bool Player::RewardPlayerAndGroupAtKill(Unit* pVictim)
{
// normal creature (not pet/etc) can be only in !PvP case
if(pVictim->GetTypeId()==TYPEID_UNIT)
- pGroupGuy->KilledMonster(pVictim->GetEntry(), pVictim->GetGUID());
+ pGroupGuy->KilledMonster(((Creature*)pVictim)->GetCreatureInfo(), pVictim->GetGUID());
}
}
}
@@ -19597,7 +19806,7 @@ bool Player::RewardPlayerAndGroupAtKill(Unit* pVictim)
// normal creature (not pet/etc) can be only in !PvP case
if(pVictim->GetTypeId()==TYPEID_UNIT)
- KilledMonster(pVictim->GetEntry(),pVictim->GetGUID());
+ KilledMonster(((Creature*)pVictim)->GetCreatureInfo(), pVictim->GetGUID());
}
}
return xp || honored_kill;
@@ -19621,26 +19830,23 @@ void Player::RewardPlayerAndGroupAtEvent(uint32 creature_id, WorldObject* pRewar
// quest objectives updated only for alive group member or dead but with not released body
if(pGroupGuy->isAlive()|| !pGroupGuy->GetCorpse())
- pGroupGuy->KilledMonster(creature_id, creature_guid);
+ pGroupGuy->KilledMonsterCredit(creature_id, creature_guid);
}
}
else // if (!pGroup)
- KilledMonster(creature_id, creature_guid);
+ KilledMonsterCredit(creature_id, creature_guid);
}
bool Player::IsAtGroupRewardDistance(WorldObject const* pRewardSource) const
{
- if (pRewardSource->IsWithinDistInMap(this,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)))
- return true;
+ const WorldObject* player = GetCorpse();
+ if(!player || isAlive())
+ player = this;
- if (isAlive())
+ if(player->GetMapId() != pRewardSource->GetMapId() || player->GetInstanceId() != pRewardSource->GetInstanceId())
return false;
- Corpse* corpse = GetCorpse();
- if (!corpse)
- return false;
-
- return pRewardSource->IsWithinDistInMap(corpse,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE));
+ return pRewardSource->GetDistance(player) <= sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE);
}
uint32 Player::GetBaseWeaponSkillValue (WeaponAttackType attType) const
@@ -19662,6 +19868,14 @@ void Player::ResurectUsingRequestData()
if(IS_PLAYER_GUID(m_resurrectGUID))
TeleportTo(m_resurrectMap, m_resurrectX, m_resurrectY, m_resurrectZ, GetOrientation());
+ //we cannot resurrect player when we triggered far teleport
+ //player will be resurrected upon teleportation
+ if(IsBeingTeleportedFar())
+ {
+ ScheduleDelayedOperation(DELAYED_RESURRECT_PLAYER);
+ return;
+ }
+
ResurrectPlayer(0.0f,false);
if(GetMaxHealth() > m_resurrectHealth)
@@ -19693,13 +19907,6 @@ void Player::SetClientControl(Unit* target, uint8 allowMove)
void Player::UpdateZoneDependentAuras( uint32 newZone )
{
- // remove new continent flight forms
- if( !IsAllowUseFlyMountsHere() )
- {
- RemoveAurasByType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED);
- RemoveAurasByType(SPELL_AURA_FLY);
- }
-
// Some spells applied at enter into zone (with subzones), aura removed in UpdateAreaDependentAuras that called always at zone->area update
SpellAreaForAreaMapBounds saBounds = spellmgr.GetSpellAreaForAreaMapBounds(newZone);
for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
@@ -20122,7 +20329,7 @@ bool Player::isTotalImmune()
bool Player::HasTitle(uint32 bitIndex)
{
- if (bitIndex > 192)
+ if (bitIndex > MAX_TITLE_INDEX)
return false;
uint32 fieldIndexOffset = bitIndex / 32;
@@ -20130,11 +20337,30 @@ bool Player::HasTitle(uint32 bitIndex)
return HasFlag(PLAYER__FIELD_KNOWN_TITLES + fieldIndexOffset, flag);
}
-void Player::SetTitle(CharTitlesEntry const* title)
+void Player::SetTitle(CharTitlesEntry const* title, bool lost)
{
uint32 fieldIndexOffset = title->bit_index / 32;
uint32 flag = 1 << (title->bit_index % 32);
- SetFlag(PLAYER__FIELD_KNOWN_TITLES + fieldIndexOffset, flag);
+
+ if(lost)
+ {
+ if(!HasFlag(PLAYER__FIELD_KNOWN_TITLES + fieldIndexOffset, flag))
+ return;
+
+ RemoveFlag(PLAYER__FIELD_KNOWN_TITLES + fieldIndexOffset, flag);
+ }
+ else
+ {
+ if(HasFlag(PLAYER__FIELD_KNOWN_TITLES + fieldIndexOffset, flag))
+ return;
+
+ SetFlag(PLAYER__FIELD_KNOWN_TITLES + fieldIndexOffset, flag);
+ }
+
+ WorldPacket data(SMSG_TITLE_EARNED, 4 + 4);
+ data << uint32(title->bit_index);
+ data << uint32(lost ? 0 : 1); // 1 - earned, 0 - lost
+ GetSession()->SendPacket(&data);
}
/*-----------------------TRINITY--------------------------*/
@@ -20230,6 +20456,7 @@ void Player::InitRunes()
m_runes = new Runes;
m_runes->runeState = 0;
+ m_runes->lastUsedRune = RUNE_BLOOD;
for(uint32 i = 0; i < MAX_RUNES; ++i)
{
@@ -20272,29 +20499,25 @@ void Player::AutoStoreLoot(uint8 bag, uint8 slot, uint32 loot_id, LootStore cons
uint32 Player::CalculateTalentsPoints() const
{
- uint32 base_talent = getLevel() < 10 ? 0 : uint32((getLevel()-9)*sWorld.getRate(RATE_TALENT));
+ uint32 base_talent = getLevel() < 10 ? 0 : getLevel()-9;
- if(getClass() != CLASS_DEATH_KNIGHT)
- return base_talent;
+ if(getClass() != CLASS_DEATH_KNIGHT || GetMapId() != 609)
+ return uint32(base_talent * sWorld.getRate(RATE_TALENT));
- uint32 talentPointsForLevel =
- (getLevel() < 56 ? 0 : uint32((getLevel()-55)*sWorld.getRate(RATE_TALENT)))
- + m_questRewardTalentCount;
+ uint32 talentPointsForLevel = getLevel() < 56 ? 0 : getLevel() - 55;
+ talentPointsForLevel += m_questRewardTalentCount;
if(talentPointsForLevel > base_talent)
talentPointsForLevel = base_talent;
- return talentPointsForLevel;
+ return uint32(talentPointsForLevel * sWorld.getRate(RATE_TALENT));
}
-bool Player::IsAllowUseFlyMountsHere() const
+bool Player::IsKnowHowFlyIn(uint32 mapid, uint32 zone) const
{
- if (isGameMaster())
- return true;
-
- uint32 zoneId = GetZoneId();
- uint32 v_map = GetVirtualMapForMapAndZone(GetMapId(), zoneId);
- return v_map == 530 || v_map == 571 && HasSpell(54197) && zoneId != 4197;
+ // continent checked in SpellMgr::GetSpellAllowedInLocationError at cast and area update
+ uint32 v_map = GetVirtualMapForMapAndZone(mapid, zone);
+ return v_map != 571 || HasSpell(54197) && zone != 4197; // Cold Weather Flying
}
void Player::learnSpellHighRank(uint32 spellid)
@@ -20484,7 +20707,7 @@ void Player::HandleFall(MovementInfo const& movementInfo)
damage = GetMaxHealth();
// Gust of Wind
- if (GetDummyAura(43621))
+ if (HasAura(43621))
damage = GetMaxHealth()/2;
EnvironmentalDamage(DAMAGE_FALL, damage);
@@ -20502,7 +20725,12 @@ void Player::HandleFall(MovementInfo const& movementInfo)
void Player::UpdateAchievementCriteria( AchievementCriteriaTypes type, uint32 miscvalue1/*=0*/, uint32 miscvalue2/*=0*/, Unit *unit/*=NULL*/, uint32 time/*=0*/ )
{
- GetAchievementMgr().UpdateAchievementCriteria(type, miscvalue1,miscvalue2,unit,time);
+ GetAchievementMgr().UpdateAchievementCriteria(type, miscvalue1, miscvalue2, unit, time);
+}
+
+void Player::CompletedAchievement(AchievementEntry const* entry)
+{
+ GetAchievementMgr().CompletedAchievement(entry);
}
void Player::LearnTalent(uint32 talentId, uint32 talentRank)
@@ -21130,3 +21358,37 @@ void Player::ActivateSpec(uint32 specNum)
resetTalents(true);
}
+
+void Player::RemoveAtLoginFlag( AtLoginFlags f, bool in_db_also /*= false*/ )
+{
+ m_atLoginFlags &= ~f;
+
+ if(in_db_also)
+ CharacterDatabase.PExecute("UPDATE characters set at_login = at_login & ~ %u WHERE guid ='%u'", uint32(f), GetGUIDLow());
+}
+
+void Player::SendClearCooldown( uint32 spell_id, Unit* target )
+{
+ WorldPacket data(SMSG_CLEAR_COOLDOWN, 4+8);
+ data << uint32(spell_id);
+ data << uint64(target->GetGUID());
+ SendDirectMessage(&data);
+}
+
+void Player::ResetMap()
+{
+ // this may be called during Map::Update
+ // after decrement+unlink, ++m_mapRefIter will continue correctly
+ // when the first element of the list is being removed
+ // nocheck_prev will return the padding element of the RefManager
+ // instead of NULL in the case of prev
+ GetMap()->UpdateIteratorBack(this);
+ Unit::ResetMap();
+ GetMapRef().unlink();
+}
+
+void Player::SetMap(Map * map)
+{
+ Unit::SetMap(map);
+ m_mapRef.link(map, this);
+}
diff --git a/src/game/Player.h b/src/game/Player.h
index 111e5def205..a63cb719d6f 100644
--- a/src/game/Player.h
+++ b/src/game/Player.h
@@ -57,7 +57,6 @@ typedef std::deque<Mail*> PlayerMails;
#define PLAYER_MAX_SKILLS 127
#define PLAYER_MAX_DAILY_QUESTS 25
-#define AT_LOAD_PET_FLAGS 16
// Note: SPELLMOD_* values is aura types in fact
enum SpellModType
@@ -135,24 +134,40 @@ enum ActionButtonUpdateState
ACTIONBUTTON_DELETED = 3
};
+enum ActionButtonType
+{
+ ACTION_BUTTON_SPELL = 0x00,
+ ACTION_BUTTON_C = 0x01, // click?
+ ACTION_BUTTON_EQSET = 0x20,
+ ACTION_BUTTON_MACRO = 0x40,
+ ACTION_BUTTON_CMACRO = ACTION_BUTTON_C | ACTION_BUTTON_MACRO,
+ ACTION_BUTTON_ITEM = 0x80
+};
+
+#define ACTION_BUTTON_ACTION(X) (uint32(X) & 0x00FFFFFF)
+#define ACTION_BUTTON_TYPE(X) ((uint32(X) & 0xFF000000) >> 24)
+#define MAX_ACTION_BUTTON_ACTION_VALUE (0x00FFFFFF+1)
+
struct ActionButton
{
- ActionButton() : action(0), type(0), misc(0), uState( ACTIONBUTTON_NEW ) {}
- ActionButton(uint16 _action, uint8 _type, uint8 _misc) : action(_action), type(_type), misc(_misc), uState( ACTIONBUTTON_NEW ) {}
+ ActionButton() : packedData(0), uState( ACTIONBUTTON_NEW ) {}
- uint16 action;
- uint8 type;
- uint8 misc;
+ uint32 packedData;
ActionButtonUpdateState uState;
-};
-enum ActionButtonType
-{
- ACTION_BUTTON_SPELL = 0,
- ACTION_BUTTON_EQSET = 32,
- ACTION_BUTTON_MACRO = 64,
- ACTION_BUTTON_CMACRO= 65,
- ACTION_BUTTON_ITEM = 128
+ // helpers
+ ActionButtonType GetType() const { return ActionButtonType(ACTION_BUTTON_TYPE(packedData)); }
+ uint32 GetAction() const { return ACTION_BUTTON_ACTION(packedData); }
+ void SetActionAndType(uint32 action, ActionButtonType type)
+ {
+ uint32 newData = action | (uint32(type) << 24);
+ if (newData != packedData)
+ {
+ packedData = newData;
+ if (uState != ACTIONBUTTON_NEW)
+ uState = ACTIONBUTTON_CHANGED;
+ }
+ }
};
#define MAX_ACTION_BUTTONS 132 //checked in 2.3.0
@@ -192,6 +207,18 @@ struct PlayerLevelInfo
typedef std::list<uint32> PlayerCreateInfoSpells;
+struct PlayerCreateInfoAction
+{
+ PlayerCreateInfoAction() : button(0), type(0), action(0) {}
+ PlayerCreateInfoAction(uint8 _button, uint32 _action, uint8 _type) : button(_button), type(_type), action(_action) {}
+
+ uint8 button;
+ uint8 type;
+ uint32 action;
+};
+
+typedef std::list<PlayerCreateInfoAction> PlayerCreateInfoActions;
+
struct PlayerInfo
{
// existence checked by displayId != 0 // existence checked by displayId != 0
@@ -208,7 +235,7 @@ struct PlayerInfo
uint16 displayId_f;
PlayerCreateInfoItems item;
PlayerCreateInfoSpells spell;
- std::list<uint16> action[4];
+ PlayerCreateInfoActions action;
PlayerLevelInfo* levelInfo; //[level-1] 0..MaxPlayerLevel-1
};
@@ -267,6 +294,7 @@ struct Runes
{
RuneInfo runes[MAX_RUNES];
uint8 runeState; // mask of available runes
+ RuneType lastUsedRune;
void SetRuneState(uint8 index, bool set = true)
{
@@ -450,6 +478,8 @@ enum PlayerFlags
#define PLAYER_TITLE_HAND_OF_ADAL UI64LIT(0x0000008000000000) // 39
#define PLAYER_TITLE_VENGEFUL_GLADIATOR UI64LIT(0x0000010000000000) // 40
+#define MAX_TITLE_INDEX (3*64) // 3 uint64 fields
+
// used in PLAYER_FIELD_BYTES values
enum PlayerFieldByteFlags
{
@@ -510,11 +540,12 @@ enum PlayerExtraFlags
// 2^n values
enum AtLoginFlags
{
- AT_LOGIN_NONE = 0,
- AT_LOGIN_RENAME = 1,
- AT_LOGIN_RESET_SPELLS = 2,
- AT_LOGIN_RESET_TALENTS = 4,
- AT_LOGIN_CUSTOMIZE = 8,
+ 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,
};
typedef std::map<uint32, QuestStatusData> QuestStatusMap;
@@ -726,6 +757,14 @@ enum EnviromentalDamage
DAMAGE_FALL_TO_VOID = 6 // custom case for fall without durability loss
};
+enum PlayedTimeIndex
+{
+ PLAYED_TIME_TOTAL = 0,
+ PLAYED_TIME_LEVEL = 1
+};
+
+#define MAX_PLAYED_TIME_INDEX 2
+
// used at player loading query list preparing, and later result selection
enum PlayerLoginQueryIndex
{
@@ -753,6 +792,14 @@ enum PlayerLoginQueryIndex
MAX_PLAYER_LOGIN_QUERY = 21
};
+enum PlayerDelayedOperations
+{
+ DELAYED_SAVE_PLAYER = 1,
+ DELAYED_RESURRECT_PLAYER = 2,
+ DELAYED_SPELL_CAST_DESERTER = 4,
+ DELAYED_END
+};
+
// Player summoning auto-decline time (in secs)
#define MAX_PLAYER_SUMMON_DELAY (2*MINUTE)
#define MAX_MONEY_AMOUNT (0x7FFFFFFF-1)
@@ -853,10 +900,11 @@ class TRINITY_DLL_SPEC Player : public Unit
void RemoveFromWorld();
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options = 0);
+ void TeleportOutOfMap(Map *oldMap);
bool TeleportTo(WorldLocation const &loc, uint32 options = 0)
{
- return TeleportTo(loc.mapid, loc.coord_x, loc.coord_y, loc.coord_z, options);
+ return TeleportTo(loc.mapid, loc.coord_x, loc.coord_y, loc.coord_z, loc.orientation, options);
}
void SetSummonPoint(uint32 mapid, float x, float y, float z)
@@ -873,7 +921,7 @@ class TRINITY_DLL_SPEC Player : public Unit
void Update( uint32 time );
- void BuildEnumData( QueryResult * result, WorldPacket * p_data );
+ static bool BuildEnumData( QueryResult * result, WorldPacket * p_data );
void SetInWater(bool apply);
@@ -905,6 +953,7 @@ class TRINITY_DLL_SPEC Player : public Unit
void InitTaxiNodesForLevel() { m_taxi.InitTaxiNodesForLevel(getRace(), getClass(), getLevel()); }
bool ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc = NULL, uint32 spellid = 0);
bool ActivateTaxiPathTo(uint32 taxi_path_id, uint32 spellid = 0);
+ void CleanupAfterTaxiFlight();
// mount_id can be used in scripting calls
bool isAcceptWhispers() const { return m_ExtraFlags & PLAYER_EXTRA_ACCEPT_WHISPERS; }
void SetAcceptWhispers(bool on) { if(on) m_ExtraFlags |= PLAYER_EXTRA_ACCEPT_WHISPERS; else m_ExtraFlags &= ~PLAYER_EXTRA_ACCEPT_WHISPERS; }
@@ -926,9 +975,9 @@ class TRINITY_DLL_SPEC Player : public Unit
// Played Time Stuff
time_t m_logintime;
time_t m_Last_tick;
- uint32 m_Played_time[2];
- uint32 GetTotalPlayedTime() { return m_Played_time[0]; };
- uint32 GetLevelPlayedTime() { return m_Played_time[1]; };
+ uint32 m_Played_time[MAX_PLAYED_TIME_INDEX];
+ uint32 GetTotalPlayedTime() { return m_Played_time[PLAYED_TIME_TOTAL]; };
+ uint32 GetLevelPlayedTime() { return m_Played_time[PLAYED_TIME_LEVEL]; };
void setDeathState(DeathState s); // overwrite Unit::setDeathState
@@ -1090,7 +1139,7 @@ class TRINITY_DLL_SPEC Player : public Unit
return mainItem && mainItem->GetProto()->InventoryType == INVTYPE_2HWEAPON && !CanTitanGrip();
}
void SendNewItem( Item *item, uint32 count, bool received, bool created, bool broadcast = false );
- bool BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint64 bagguid, uint8 slot);
+ bool BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint8 bag, uint8 slot);
float GetReputationPriceDiscount( Creature const* pCreature ) const;
Player* GetTrader() const { return pTrader; }
@@ -1193,7 +1242,8 @@ class TRINITY_DLL_SPEC Player : public Unit
void GroupEventHappens( uint32 questId, WorldObject const* pEventObject );
void ItemAddedQuestCheck( uint32 entry, uint32 count );
void ItemRemovedQuestCheck( uint32 entry, uint32 count );
- void KilledMonster( uint32 entry, uint64 guid );
+ void KilledMonster( CreatureInfo const* cInfo, uint64 guid );
+ void KilledMonsterCredit( uint32 entry, uint64 guid );
void CastedCreatureOrGO( uint32 entry, uint64 guid, uint32 spell_id );
void TalkedToCreature( uint32 entry, uint64 guid );
void MoneyChanged( uint32 value );
@@ -1234,6 +1284,7 @@ class TRINITY_DLL_SPEC Player : public Unit
static uint32 GetUInt32ValueFromDB(uint16 index, uint64 guid);
static float GetFloatValueFromDB(uint16 index, uint64 guid);
static uint32 GetZoneIdFromDB(uint64 guid);
+ static uint32 GetLevelFromDB(uint64 guid);
static bool LoadPositionFromDB(uint32& mapid, float& x,float& y,float& z,float& o, bool& in_flight, uint64 guid);
/*********************************************************/
@@ -1242,6 +1293,7 @@ class TRINITY_DLL_SPEC Player : public Unit
void SaveToDB();
void SaveInventoryAndGoldToDB(); // fast save function for item/money cheating preventing
+ void SaveGoldToDB();
void SaveDataFieldToDB();
static bool SaveValuesArrayInDB(Tokens const& data,uint64 guid);
static void SetUInt32ValueInArray(Tokens& data,uint16 index, uint32 value);
@@ -1256,7 +1308,6 @@ class TRINITY_DLL_SPEC Player : public Unit
void SetBindPoint(uint64 guid);
void SendTalentWipeConfirm(uint64 guid);
- void RewardRage( uint32 damage, uint32 weaponSpeedHitFactor, bool attacker );
void SendPetSkillWipeConfirm();
void CalcRage( uint32 damage,bool attacker );
void RegenerateAll();
@@ -1292,7 +1343,8 @@ class TRINITY_DLL_SPEC Player : public Unit
uint8 GetComboPoints() { return m_comboPoints; }
const uint64& GetComboTarget() const { return m_comboTarget; }
- void AddComboPoints(Unit* target, int8 count);
+ void AddComboPoints(Unit* target, int8 count, Spell * spell = NULL);
+ void GainSpellComboPoints(int8 count);
void ClearComboPoints();
void SendComboPoints();
@@ -1356,7 +1408,7 @@ class TRINITY_DLL_SPEC Player : public Unit
void SendInitialSpells();
bool addSpell(uint32 spell_id, bool active, bool learning, bool dependent, bool disabled);
void learnSpell(uint32 spell_id, bool dependent);
- void removeSpell(uint32 spell_id, bool disabled = false, bool update_action_bar_for_low_rank = false);
+ void removeSpell(uint32 spell_id, bool disabled = false, bool learn_low_rank = true);
void resetSpells();
void learnDefaultSpells();
void learnQuestRewardedSpells();
@@ -1398,6 +1450,8 @@ class TRINITY_DLL_SPEC Player : public Unit
PlayerSpellMap const& GetSpellMap() const { return m_spells; }
PlayerSpellMap & GetSpellMap() { return m_spells; }
+ SpellCooldowns const& GetSpellCooldownMap() const { return m_spellCooldowns; }
+
void AddSpellMod(SpellModifier* mod, bool apply);
bool IsAffectedBySpellmod(SpellEntry const *spellInfo, SpellModifier *mod, Spell * spell = NULL);
template <class T> T ApplySpellMod(uint32 spellId, SpellModOp op, T &basevalue, Spell * spell = NULL);
@@ -1406,6 +1460,8 @@ class TRINITY_DLL_SPEC Player : public Unit
void DropModCharge(SpellModifier * mod, Spell * spell);
void SetSpellModTakingSpell(Spell* spell, bool apply);
+ static uint32 const infinityCooldownDelay = MONTH; // used for set "infinity cooldowns" for spells and check
+ static uint32 const infinityCooldownDelayCheck = MONTH/2;
bool HasSpellCooldown(uint32 spell_id) const
{
SpellCooldowns::const_iterator itr = m_spellCooldowns.find(spell_id);
@@ -1422,6 +1478,9 @@ class TRINITY_DLL_SPEC Player : public Unit
void SendCooldownEvent(SpellEntry const *spellInfo, uint32 itemId = 0, Spell* spell = NULL);
void ProhibitSpellScholl(SpellSchoolMask idSchoolMask, uint32 unTimeMs );
void RemoveSpellCooldown(uint32 spell_id, bool update = false);
+ void RemoveSpellCategoryCooldown(uint32 cat, bool update = false);
+ void SendClearCooldown( uint32 spell_id, Unit* target );
+
void RemoveCategoryCooldown(uint32 cat);
void RemoveArenaSpellCooldowns();
void RemoveAllSpellCooldown();
@@ -1454,7 +1513,7 @@ class TRINITY_DLL_SPEC Player : public Unit
m_cinematic = cine;
}
- bool addActionButton(uint8 button, uint16 action, uint8 type, uint8 misc);
+ ActionButton* addActionButton(uint8 button, uint32 action, uint8 type);
void removeActionButton(uint8 button);
void SendInitialActionButtons() const;
@@ -1597,7 +1656,7 @@ class TRINITY_DLL_SPEC Player : public Unit
void SetSession(WorldSession *s) { m_session = s; }
void BuildCreateUpdateBlockForPlayer( UpdateData *data, Player *target ) const;
- void DestroyForPlayer( Player *target ) const;
+ void DestroyForPlayer( Player *target, bool anim = false ) const;
void SendDelayResponse(const uint32);
void SendLogXPGain(uint32 GivenXP,Unit* victim,uint32 RestXP);
@@ -1607,7 +1666,7 @@ class TRINITY_DLL_SPEC Player : public Unit
void SendAttackSwingDeadTarget();
void SendAttackSwingNotInRange();
void SendAttackSwingBadFacingAttack();
- void SendAutoRepeatCancel();
+ void SendAutoRepeatCancel(Unit *target);
void SendExplorationExperience(uint32 Area, uint32 Experience);
void SendDungeonDifficulty(bool IsInGroup);
@@ -1681,6 +1740,7 @@ class TRINITY_DLL_SPEC Player : public Unit
bool IsBeingTeleportedFar() const { return mSemaphoreTeleport_Far; }
void SetSemaphoreTeleportNear(bool semphsetting) { mSemaphoreTeleport_Near = semphsetting; }
void SetSemaphoreTeleportFar(bool semphsetting) { mSemaphoreTeleport_Far = semphsetting; }
+ void ProcessDelayedOperations();
void CheckExploreSystem(void);
@@ -1690,6 +1750,8 @@ class TRINITY_DLL_SPEC Player : public Unit
static uint32 getFactionForRace(uint8 race);
void setFactionForRace(uint8 race);
+ void InitDisplayIds();
+
bool IsAtGroupRewardDistance(WorldObject const* pRewardSource) const;
bool RewardPlayerAndGroupAtKill(Unit* pVictim);
void RewardPlayerAndGroupAtEvent(uint32 creature_id,WorldObject* pRewardSource);
@@ -1755,7 +1817,8 @@ class TRINITY_DLL_SPEC Player : public Unit
void _ApplyItemMods(Item *item,uint8 slot,bool apply);
void _RemoveAllItemMods();
void _ApplyAllItemMods();
- void _ApplyItemBonuses(ItemPrototype const *proto,uint8 slot,bool apply);
+ void _ApplyAllLevelScaleItemMods(bool apply);
+ void _ApplyItemBonuses(ItemPrototype const *proto,uint8 slot,bool apply, bool only_level_scale = false);
void _ApplyAmmoBonuses();
bool EnchantmentFitsRequirements(uint32 enchantmentcondition, int8 slot);
void ToggleMetaGemsActive(uint8 exceptslot, bool apply);
@@ -1765,8 +1828,9 @@ class TRINITY_DLL_SPEC Player : public Unit
void ApplyItemEquipSpell(Item *item, bool apply, bool form_change = false);
void ApplyEquipSpell(SpellEntry const* spellInfo, Item* item, bool apply, bool form_change = false);
void UpdateEquipSpellsAtFormChange();
- void CastItemCombatSpell(Item *item, CalcDamageInfo *damageInfo, ItemPrototype const * proto);
+ void CastItemCombatSpell(Unit *target, WeaponAttackType attType, uint32 procVictim, uint32 procEx);
void CastItemUseSpell(Item *item,SpellCastTargets const& targets,uint8 cast_count, uint32 glyphIndex);
+ void CastItemCombatSpell(Unit *target, WeaponAttackType attType, uint32 procVictim, uint32 procEx, Item *item, ItemPrototype const * proto);
void SendEquipmentSetList();
void SetEquipmentSet(uint32 index, EquipmentSet eqset);
@@ -1942,7 +2006,7 @@ class TRINITY_DLL_SPEC Player : public Unit
}
void HandleFall(MovementInfo const& movementInfo);
- bool IsAllowUseFlyMountsHere() const;
+ bool IsKnowHowFlyIn(uint32 mapid, uint32 zone) const;
void SetClientControl(Unit* target, uint8 allowMove);
@@ -1970,7 +2034,7 @@ class TRINITY_DLL_SPEC Player : public Unit
float m_homebindX;
float m_homebindY;
float m_homebindZ;
- void RelocateToHomebind() { SetMapId(m_homebindMapId); Relocate(m_homebindX,m_homebindY,m_homebindZ); }
+ void RelocateToHomebind(uint32 & newMap) { newMap = m_homebindMapId; Relocate(m_homebindX,m_homebindY,m_homebindZ); }
// currently visible objects at player client
typedef std::set<uint64> ClientGUIDs;
@@ -1989,15 +2053,13 @@ class TRINITY_DLL_SPEC Player : public Unit
void UpdateVisibilityOf(T* target, UpdateData& data, std::set<WorldObject*>& visibleNow);
// Stealth detection system
- uint32 m_DetectInvTimer;
void HandleStealthedUnitsDetection();
uint8 m_forced_speed_changes[MAX_MOVE_TYPE];
bool HasAtLoginFlag(AtLoginFlags f) const { return m_atLoginFlags & f; }
void SetAtLoginFlag(AtLoginFlags f) { m_atLoginFlags |= f; }
- uint32 GetAtLoginFlag() { return m_atLoginFlags; }
- void SetPetAtLoginFlag(uint8 f) { m_atLoginFlags |= uint32(f<<AT_LOAD_PET_FLAGS); }
+ void RemoveAtLoginFlag(AtLoginFlags f, bool in_db_also = false);
LookingForGroup m_lookingForGroup;
@@ -2025,6 +2087,7 @@ class TRINITY_DLL_SPEC Player : public Unit
BoundInstancesMap m_boundInstances[TOTAL_DIFFICULTIES];
InstancePlayerBind* GetBoundInstance(uint32 mapid, uint8 difficulty);
BoundInstancesMap& GetBoundInstances(uint8 difficulty) { return m_boundInstances[difficulty]; }
+ InstanceSave * GetInstanceSave(uint32 mapid);
void UnbindInstance(uint32 mapid, uint8 difficulty, bool unload = false);
void UnbindInstance(BoundInstancesMap::iterator &itr, uint8 difficulty, bool unload = false);
InstancePlayerBind* BindToInstance(InstanceSave *save, bool permanent, bool load = false);
@@ -2061,6 +2124,10 @@ class TRINITY_DLL_SPEC Player : public Unit
GridReference<Player> &GetGridRef() { return m_gridRef; }
MapReference &GetMapRef() { return m_mapRef; }
+ // Set map to player and add reference
+ void SetMap(Map * map);
+ void ResetMap();
+
bool isAllowedToLoot(Creature* creature);
DeclinedName const* GetDeclinedNames() const { return m_declinedname; }
@@ -2068,6 +2135,8 @@ class TRINITY_DLL_SPEC Player : public Unit
uint8 GetBaseRune(uint8 index) const { return m_runes->runes[index].BaseRune; }
uint8 GetCurrentRune(uint8 index) const { return m_runes->runes[index].CurrentRune; }
uint8 GetRuneCooldown(uint8 index) const { return m_runes->runes[index].Cooldown; }
+ RuneType GetLastUsedRune() { return m_runes->lastUsedRune; }
+ void SetLastUsedRune(RuneType type) { m_runes->lastUsedRune = type; }
void SetBaseRune(uint8 index, uint8 baseRune) { m_runes->runes[index].BaseRune = baseRune; }
void SetCurrentRune(uint8 index, uint8 currentRune) { m_runes->runes[index].CurrentRune = currentRune; }
void SetRuneCooldown(uint8 index, uint8 cooldown) { m_runes->runes[index].Cooldown = cooldown; m_runes->SetRuneState(index, (cooldown == 0) ? true : false); }
@@ -2075,11 +2144,14 @@ class TRINITY_DLL_SPEC Player : public Unit
void ResyncRunes(uint8 count);
void AddRunePower(uint8 index);
void InitRunes();
+
AchievementMgr& GetAchievementMgr() { return m_achievementMgr; }
- void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1=0, uint32 miscvalue2=0, Unit *unit=NULL, uint32 time=0);
+ void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1 = 0, uint32 miscvalue2 = 0, Unit *unit = NULL, uint32 time = 0);
+ void CompletedAchievement(AchievementEntry const* entry);
+
bool HasTitle(uint32 bitIndex);
bool HasTitle(CharTitlesEntry const* title) { return HasTitle(title->bit_index); }
- void SetTitle(CharTitlesEntry const* title);
+ void SetTitle(CharTitlesEntry const* title, bool lost = false);
//bool isActiveObject() const { return true; }
bool canSeeSpellClickOn(Creature const* creature) const;
@@ -2175,8 +2247,6 @@ class TRINITY_DLL_SPEC Player : public Unit
void outDebugValues() const;
uint64 m_lootGuid;
- uint32 m_race;
- uint32 m_class;
uint32 m_team;
uint32 m_nextSave;
time_t m_speakTime;
@@ -2313,6 +2383,13 @@ class TRINITY_DLL_SPEC Player : public Unit
int32 CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, int32 faction, bool for_quest);
void AdjustQuestReqItemCount( Quest const* pQuest, QuestStatusData& questStatusData );
+ bool IsCanDelayTeleport() const { return m_bCanDelayTeleport; }
+ void SetCanDelayTeleport(bool setting) { m_bCanDelayTeleport = setting; }
+ bool IsHasDelayedTeleport() const { return m_bHasDelayedTeleport; }
+ void SetDelayedTeleportFlag(bool setting) { m_bHasDelayedTeleport = setting; }
+
+ void ScheduleDelayedOperation(uint32 operation);
+
GridReference<Player> m_gridRef;
MapReference m_mapRef;
@@ -2329,9 +2406,16 @@ class TRINITY_DLL_SPEC Player : public Unit
// Current teleport data
WorldLocation m_teleport_dest;
+ uint32 m_teleport_options;
bool mSemaphoreTeleport_Near;
bool mSemaphoreTeleport_Far;
+ uint32 m_DelayedOperations;
+ bool m_bCanDelayTeleport;
+ bool m_bHasDelayedTeleport;
+
+ uint32 m_DetectInvTimer;
+
// Temporary removed pet cache
uint32 m_temporaryUnsummonedPetNumber;
uint32 m_oldpetspell;
diff --git a/src/game/PlayerDump.cpp b/src/game/PlayerDump.cpp
index 73939115211..06550269856 100644
--- a/src/game/PlayerDump.cpp
+++ b/src/game/PlayerDump.cpp
@@ -304,19 +304,19 @@ void PlayerDumpWriter::DumpTable(std::string& dump, uint32 guid, char const*tabl
// collect guids
switch ( type )
{
- case DTT_INVENTORY:
- StoreGUID(result,3,items); break; // item guid collection
- case DTT_ITEM:
- StoreGUID(result,0,ITEM_FIELD_ITEM_TEXT_ID,texts); break;
- // item text id collection
- case DTT_PET:
- StoreGUID(result,0,pets); break; // pet guid collection
- case DTT_MAIL:
- StoreGUID(result,0,mails); // mail id collection
- StoreGUID(result,6,texts); break; // item text id collection
- case DTT_MAIL_ITEM:
- StoreGUID(result,1,items); break; // item guid collection
- default: break;
+ case DTT_INVENTORY:
+ StoreGUID(result,3,items); break; // item guid collection
+ case DTT_ITEM:
+ StoreGUID(result,0,ITEM_FIELD_ITEM_TEXT_ID,texts); break;
+ // item text id collection
+ case DTT_PET:
+ StoreGUID(result,0,pets); break; // pet guid collection
+ case DTT_MAIL:
+ StoreGUID(result,0,mails); // mail id collection
+ StoreGUID(result,7,texts); break; // item text id collection
+ case DTT_MAIL_ITEM:
+ StoreGUID(result,1,items); break; // item guid collection
+ default: break;
}
dump += CreateDumpString(tableTo, result);
@@ -332,7 +332,7 @@ void PlayerDumpWriter::DumpTable(std::string& dump, uint32 guid, char const*tabl
std::string PlayerDumpWriter::GetDump(uint32 guid)
{
std::string dump;
-
+
dump += "IMPORTANT NOTE: This sql queries not created for apply directly, use '.pdump load' command in console or client chat instead.\n";
dump += "IMPORTANT NOTE: NOT APPLY ITS DIRECTLY to character DB or you will DAMAGE and CORRUPT character DB\n\n";
@@ -395,7 +395,7 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s
{
QueryResult *result = CharacterDatabase.PQuery("SELECT COUNT(guid) FROM characters WHERE account = '%d'", account);
uint8 charcount = 0;
- if ( result )
+ if (result)
{
Field *fields=result->Fetch();
charcount = fields[0].GetUInt8();
@@ -407,7 +407,7 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s
}
FILE *fin = fopen(file.c_str(), "r");
- if(!fin)
+ if (!fin)
return DUMP_FILE_OPEN_ERROR;
QueryResult * result = NULL;
@@ -415,7 +415,7 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s
// make sure the same guid doesn't already exist and is safe to use
bool incHighest = true;
- if(guid != 0 && guid < objmgr.m_hiCharGuid)
+ if (guid != 0 && guid < objmgr.m_hiCharGuid)
{
result = CharacterDatabase.PQuery("SELECT * FROM characters WHERE guid = '%d'", guid);
if (result)
@@ -429,10 +429,10 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s
guid = objmgr.m_hiCharGuid;
// normalize the name if specified and check if it exists
- if(!normalizePlayerName(name))
+ if (!normalizePlayerName(name))
name = "";
- if(ObjectMgr::IsValidName(name,true))
+ if (ObjectMgr::CheckPlayerName(name,true) == CHAR_NAME_SUCCESS)
{
CharacterDatabase.escape_string(name); // for safe, we use name only for sql quearies anyway
result = CharacterDatabase.PQuery("SELECT * FROM characters WHERE name = '%s'", name.c_str());
@@ -442,7 +442,8 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s
delete result;
}
}
- else name = "";
+ else
+ name = "";
// name encoded or empty
@@ -453,6 +454,7 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s
std::map<uint32,uint32> items;
std::map<uint32,uint32> mails;
+ std::map<uint32,uint32> itemTexts;
char buf[32000] = "";
typedef std::map<uint32, uint32> PetIds; // old->new petid relation
@@ -547,8 +549,8 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s
if (result)
{
delete result;
- // rename on login: `at_login` field 30 in raw field list
- if(!changenth(line, 30, "1"))
+
+ if(!changenth(line, 37, "1")) // rename on login: `at_login` field 37 in raw field list
ROLLBACK(DUMP_FILE_BROKEN);
}
}
@@ -581,6 +583,8 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s
ROLLBACK(DUMP_FILE_BROKEN);
if(!changetoknth(vals, ITEM_FIELD_OWNER+1, newguid))
ROLLBACK(DUMP_FILE_BROKEN);
+ if(!changetokGuid(vals, ITEM_FIELD_ITEM_TEXT_ID+1, itemTexts, objmgr.m_ItemTextId,true))
+ ROLLBACK(DUMP_FILE_BROKEN);
if(!changenth(line, 3, vals.c_str()))
ROLLBACK(DUMP_FILE_BROKEN);
break;
@@ -638,10 +642,12 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s
}
case DTT_MAIL: // mail
{
- // id,messageType,stationery,sender,receiver
+ // id,messageType,stationery,mailtemplate,sender,receiver,subject,itemText
if(!changeGuid(line, 1, mails, objmgr.m_mailid))
ROLLBACK(DUMP_FILE_BROKEN);
- if(!changenth(line, 5, newguid))
+ if(!changenth(line, 6, newguid))
+ ROLLBACK(DUMP_FILE_BROKEN);
+ if(!changeGuid(line, 8, itemTexts, objmgr.m_ItemTextId))
ROLLBACK(DUMP_FILE_BROKEN);
break;
}
@@ -656,6 +662,18 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s
ROLLBACK(DUMP_FILE_BROKEN);
break;
}
+ case DTT_ITEM_TEXT: // item_text
+ {
+ // id
+ if(!changeGuid(line, 1, itemTexts, objmgr.m_ItemTextId))
+ ROLLBACK(DUMP_FILE_BROKEN);
+
+ // add it to cache
+ uint32 id= atoi(getnth(line,1).c_str());
+ std::string text = getnth(line,2);
+ objmgr.AddItemText(id,text);
+ break;
+ }
default:
sLog.outError("Unknown dump table type: %u",type);
break;
@@ -669,6 +687,7 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s
objmgr.m_hiItemGuid += items.size();
objmgr.m_mailid += mails.size();
+ objmgr.m_ItemTextId += itemTexts.size();
if(incHighest)
++objmgr.m_hiCharGuid;
diff --git a/src/game/PointMovementGenerator.cpp b/src/game/PointMovementGenerator.cpp
index ed057854aaa..ffd036e9c21 100644
--- a/src/game/PointMovementGenerator.cpp
+++ b/src/game/PointMovementGenerator.cpp
@@ -30,9 +30,9 @@ template<class T>
void PointMovementGenerator<T>::Initialize(T &unit)
{
unit.StopMoving();
- unit.clearUnitState(UNIT_STAT_MOVING);
Traveller<T> traveller(unit);
- i_destinationHolder.SetDestination(traveller,i_x,i_y,i_z, !unit.hasUnitState(UNIT_STAT_JUMPING));
+ // knockback effect has UNIT_STAT_JUMPING set,so if here we disable sentmonstermove there will be creature position sync problem between client and server
+ i_destinationHolder.SetDestination(traveller,i_x,i_y,i_z, true /* !unit.hasUnitState(UNIT_STAT_JUMPING)*/);
if (unit.GetTypeId() == TYPEID_UNIT && ((Creature*)&unit)->canFly())
unit.AddUnitMovementFlag(MOVEMENTFLAG_FLYING);
diff --git a/src/game/PoolHandler.cpp b/src/game/PoolHandler.cpp
index 09a1d4293b7..dd0834b80f4 100644
--- a/src/game/PoolHandler.cpp
+++ b/src/game/PoolHandler.cpp
@@ -127,10 +127,7 @@ void PoolGroup<Creature>::Despawn1Object(uint32 guid)
objmgr.RemoveCreatureFromGrid(guid, data);
if (Creature* pCreature = ObjectAccessor::Instance().GetObjectInWorld(MAKE_NEW_GUID(guid, data->id, HIGHGUID_UNIT), (Creature*)NULL))
- {
- pCreature->CleanupsBeforeDelete();
pCreature->AddObjectToRemoveList();
- }
}
}
diff --git a/src/game/QueryHandler.cpp b/src/game/QueryHandler.cpp
index 9da24d404f9..b70a85c58e2 100644
--- a/src/game/QueryHandler.cpp
+++ b/src/game/QueryHandler.cpp
@@ -65,17 +65,17 @@ void WorldSession::SendNameQueryOpcodeFromDB(uint64 guid)
CharacterDatabase.AsyncPQuery(&WorldSession::SendNameQueryOpcodeFromDBCallBack, GetAccountId(),
!sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) ?
// ------- Query Without Declined Names --------
- // 0 1 2
- "SELECT guid, name, SUBSTRING(data, LENGTH(SUBSTRING_INDEX(data, ' ', '%u'))+2, LENGTH(SUBSTRING_INDEX(data, ' ', '%u')) - LENGTH(SUBSTRING_INDEX(data, ' ', '%u'))-1) "
+ // 0 1 2 3 4
+ "SELECT guid, name, race, gender, class "
"FROM characters WHERE guid = '%u'"
:
// --------- Query With Declined Names ---------
- // 0 1 2
- "SELECT characters.guid, name, SUBSTRING(data, LENGTH(SUBSTRING_INDEX(data, ' ', '%u'))+2, LENGTH(SUBSTRING_INDEX(data, ' ', '%u')) - LENGTH(SUBSTRING_INDEX(data, ' ', '%u'))-1), "
- // 3 4 5 6 7
+ // 0 1 2 3 4
+ "SELECT characters.guid, name, race, gender, class, "
+ // 5 6 7 8 9
"genitive, dative, accusative, instrumental, prepositional "
"FROM characters LEFT JOIN character_declinedname ON characters.guid = character_declinedname.guid WHERE characters.guid = '%u'",
- UNIT_FIELD_BYTES_0, UNIT_FIELD_BYTES_0+1, UNIT_FIELD_BYTES_0, GUID_LOPART(guid));
+ GUID_LOPART(guid));
}
void WorldSession::SendNameQueryOpcodeFromDBCallBack(QueryResult *result, uint32 accountId)
@@ -93,31 +93,35 @@ void WorldSession::SendNameQueryOpcodeFromDBCallBack(QueryResult *result, uint32
Field *fields = result->Fetch();
uint32 guid = fields[0].GetUInt32();
std::string name = fields[1].GetCppString();
- uint32 field = 0;
+ uint8 pRace = 0, pGender = 0, pClass = 0;
if(name == "")
name = session->GetTrinityString(LANG_NON_EXIST_CHARACTER);
else
- field = fields[2].GetUInt32();
+ {
+ pRace = fields[2].GetUInt8();
+ pGender = fields[3].GetUInt8();
+ pClass = fields[4].GetUInt8();
+ }
// guess size
WorldPacket data( SMSG_NAME_QUERY_RESPONSE, (8+1+1+1+1+1+1+10) );
data.appendPackGUID(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER));
data << uint8(0); // added in 3.1
data << name;
- data << uint8(0);
- data << uint8(field & 0xFF);
- data << uint8((field >> 16) & 0xFF);
- data << uint8((field >> 8) & 0xFF);
+ data << uint8(0); // realm name for cross realm BG usage
+ data << uint8(pRace); // race
+ data << uint8(pGender); // gender
+ data << uint8(pClass); // class
- // if the first declined name field (3) is empty, the rest must be too
- if(sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) && fields[3].GetCppString() != "")
+ // if the first declined name field (5) is empty, the rest must be too
+ if(sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) && fields[5].GetCppString() != "")
{
data << uint8(1); // is declined
- for(int i = 3; i < MAX_DECLINED_NAME_CASES+3; ++i)
+ for(int i = 5; i < MAX_DECLINED_NAME_CASES+5; ++i)
data << fields[i].GetCppString();
}
else
- data << uint8(0); // is declined
+ data << uint8(0); // is not declined
session->SendPacket( &data );
delete result;
@@ -187,8 +191,8 @@ void WorldSession::HandleCreatureQueryOpcode( WorldPacket & recv_data )
data << uint32(ci->type); // CreatureType.dbc
data << uint32(ci->family); // CreatureFamily.dbc
data << uint32(ci->rank); // Creature Rank (elite, boss, etc)
- data << uint32(ci->unk1); // new in 3.1, creature entry?
- data << uint32(ci->unk2); // new in 3.1, creature entry?
+ data << uint32(ci->KillCredit[0]); // new in 3.1, kill credit
+ data << uint32(ci->KillCredit[1]); // new in 3.1, kill credit
data << uint32(ci->DisplayID_A[0]); // modelid_male1
data << uint32(ci->DisplayID_H[0]); // modelid_female1 ?
data << uint32(ci->DisplayID_A[1]); // modelid_male2 ?
diff --git a/src/game/QuestDef.h b/src/game/QuestDef.h
index c3285ec816c..412c66cf9fd 100644
--- a/src/game/QuestDef.h
+++ b/src/game/QuestDef.h
@@ -96,9 +96,9 @@ enum QuestStatus
{
QUEST_STATUS_NONE = 0,
QUEST_STATUS_COMPLETE = 1,
- QUEST_STATUS_UNAVAILABLE = 2,
+ //QUEST_STATUS_UNAVAILABLE = 2,
QUEST_STATUS_INCOMPLETE = 3,
- QUEST_STATUS_AVAILABLE = 4,
+ //QUEST_STATUS_AVAILABLE = 4,
MAX_QUEST_STATUS
};
diff --git a/src/game/QuestHandler.cpp b/src/game/QuestHandler.cpp
index b2478860c61..52d2ee6d77a 100644
--- a/src/game/QuestHandler.cpp
+++ b/src/game/QuestHandler.cpp
@@ -439,60 +439,56 @@ void WorldSession::HandlePushQuestToParty(WorldPacket& recvPacket)
{
CHECK_PACKET_SIZE(recvPacket,4);
- uint32 quest;
- recvPacket >> quest;
+ uint32 questId;
+ recvPacket >> questId;
- sLog.outDebug( "WORLD: Received CMSG_PUSHQUESTTOPARTY quest = %u", quest );
+ sLog.outDebug("WORLD: Received CMSG_PUSHQUESTTOPARTY quest = %u", questId);
- Quest const *pQuest = objmgr.GetQuestTemplate(quest);
- if( pQuest )
+ if (Quest const *pQuest = objmgr.GetQuestTemplate(questId))
{
- if( _player->GetGroup() )
+ if (Group* pGroup = _player->GetGroup())
{
- Group *pGroup = _player->GetGroup();
- if( pGroup )
+ for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
{
- for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
- {
- Player *pPlayer = itr->getSource();
- if (!pPlayer || pPlayer == _player) // skip self
- continue;
+ Player *pPlayer = itr->getSource();
- _player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_SHARING_QUEST);
+ if (!pPlayer || pPlayer == _player) // skip self
+ continue;
- if( !pPlayer->SatisfyQuestStatus( pQuest, false ) )
- {
- _player->SendPushToPartyResponse( pPlayer, QUEST_PARTY_MSG_HAVE_QUEST );
- continue;
- }
+ _player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_SHARING_QUEST);
- if( pPlayer->GetQuestStatus( quest ) == QUEST_STATUS_COMPLETE )
- {
- _player->SendPushToPartyResponse( pPlayer, QUEST_PARTY_MSG_FINISH_QUEST );
- continue;
- }
+ if (!pPlayer->SatisfyQuestStatus(pQuest, false))
+ {
+ _player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_HAVE_QUEST);
+ continue;
+ }
- if( !pPlayer->CanTakeQuest( pQuest, false ) )
- {
- _player->SendPushToPartyResponse( pPlayer, QUEST_PARTY_MSG_CANT_TAKE_QUEST );
- continue;
- }
+ if (pPlayer->GetQuestStatus(questId) == QUEST_STATUS_COMPLETE)
+ {
+ _player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_FINISH_QUEST);
+ continue;
+ }
- if( !pPlayer->SatisfyQuestLog( false ) )
- {
- _player->SendPushToPartyResponse( pPlayer, QUEST_PARTY_MSG_LOG_FULL );
- continue;
- }
+ if (!pPlayer->CanTakeQuest(pQuest, false))
+ {
+ _player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_CANT_TAKE_QUEST);
+ continue;
+ }
- if( pPlayer->GetDivider() != 0 )
- {
- _player->SendPushToPartyResponse( pPlayer, QUEST_PARTY_MSG_BUSY );
- continue;
- }
+ if (!pPlayer->SatisfyQuestLog(false))
+ {
+ _player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_LOG_FULL);
+ continue;
+ }
- pPlayer->PlayerTalkClass->SendQuestGiverQuestDetails( pQuest, _player->GetGUID(), true );
- pPlayer->SetDivider( _player->GetGUID() );
+ if (pPlayer->GetDivider() != 0)
+ {
+ _player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_BUSY);
+ continue;
}
+
+ pPlayer->PlayerTalkClass->SendQuestGiverQuestDetails(pQuest, _player->GetGUID(), true);
+ pPlayer->SetDivider(_player->GetGUID());
}
}
}
diff --git a/src/game/ReputationMgr.cpp b/src/game/ReputationMgr.cpp
index ee7ca8d44a4..e4ed5b0db2e 100644
--- a/src/game/ReputationMgr.cpp
+++ b/src/game/ReputationMgr.cpp
@@ -255,7 +255,7 @@ bool ReputationMgr::SetOneFactionReputation(FactionEntry const* factionEntry, in
if(incremental)
{
// int32 *= float cause one point loss?
- standing = (int32)((float)standing * sWorld.getRate(RATE_REPUTATION_GAIN));
+ standing = floor( (float)standing * sWorld.getRate(RATE_REPUTATION_GAIN) + 0.5 );
standing += itr->second.Standing + BaseRep;
}
@@ -475,4 +475,4 @@ void ReputationMgr::UpdateRankCounters( ReputationRank old_rank, ReputationRank
++m_reveredFactionCount;
if(new_rank >= REP_HONORED)
++m_honoredFactionCount;
-} \ No newline at end of file
+}
diff --git a/src/game/ReputationMgr.h b/src/game/ReputationMgr.h
index b81634119df..d63c518eb82 100644
--- a/src/game/ReputationMgr.h
+++ b/src/game/ReputationMgr.h
@@ -21,9 +21,16 @@
#include "Common.h"
#include "SharedDefines.h"
+#include "Language.h"
#include "DBCStructure.h"
#include <map>
+static uint32 ReputationRankStrIndex[MAX_REPUTATION_RANK] =
+{
+ LANG_REP_HATED, LANG_REP_HOSTILE, LANG_REP_UNFRIENDLY, LANG_REP_NEUTRAL,
+ LANG_REP_FRIENDLY, LANG_REP_HONORED, LANG_REP_REVERED, LANG_REP_EXALTED
+};
+
enum FactionFlags
{
FACTION_FLAG_VISIBLE = 0x01, // makes visible in client (set or can be set at interaction with target of this faction)
diff --git a/src/game/ScriptCalls.cpp b/src/game/ScriptCalls.cpp
index fec1afb08ae..b8870c2a1dd 100644
--- a/src/game/ScriptCalls.cpp
+++ b/src/game/ScriptCalls.cpp
@@ -79,6 +79,7 @@ bool LoadScriptingModule(char const* libName)
||!(testScript->ItemQuestAccept =(scriptCallItemQuestAccept )TRINITY_GET_PROC_ADDR(testScript->hScriptsLib,"ItemQuestAccept" ))
||!(testScript->GOQuestAccept =(scriptCallGOQuestAccept )TRINITY_GET_PROC_ADDR(testScript->hScriptsLib,"GOQuestAccept" ))
||!(testScript->ItemUse =(scriptCallItemUse )TRINITY_GET_PROC_ADDR(testScript->hScriptsLib,"ItemUse" ))
+ ||!(testScript->ItemExpire =(scriptCallItemExpire )TRINITY_GET_PROC_ADDR(testScript->hScriptsLib,"ItemExpire" ))
||!(testScript->EffectDummyGameObj =(scriptCallEffectDummyGameObj )TRINITY_GET_PROC_ADDR(testScript->hScriptsLib,"EffectDummyGameObj" ))
||!(testScript->EffectDummyCreature =(scriptCallEffectDummyCreature )TRINITY_GET_PROC_ADDR(testScript->hScriptsLib,"EffectDummyCreature" ))
||!(testScript->EffectDummyItem =(scriptCallEffectDummyItem )TRINITY_GET_PROC_ADDR(testScript->hScriptsLib,"EffectDummyItem" ))
diff --git a/src/game/ScriptCalls.h b/src/game/ScriptCalls.h
index 4e23f9f576d..0eae69cb505 100644
--- a/src/game/ScriptCalls.h
+++ b/src/game/ScriptCalls.h
@@ -59,6 +59,7 @@ typedef bool(TRINITY_IMPORT * scriptCallItemQuestAccept)(Player *player, Item *,
typedef bool(TRINITY_IMPORT * scriptCallGOQuestAccept)(Player *player, GameObject *, Quest const*);
typedef bool(TRINITY_IMPORT * scriptCallGOChooseReward)(Player *player, GameObject *, Quest const*, uint32 opt );
typedef bool(TRINITY_IMPORT * scriptCallItemUse) (Player *player, Item *_Item, SpellCastTargets const& targets);
+typedef bool(TRINITY_IMPORT * scriptCallItemExpire) (Player *player, ItemPrototype const *_ItemProto);
typedef bool(TRINITY_IMPORT * scriptCallEffectDummyGameObj) (Unit *caster, uint32 spellId, uint32 effIndex, GameObject *gameObjTarget);
typedef bool(TRINITY_IMPORT * scriptCallEffectDummyCreature) (Unit *caster, uint32 spellId, uint32 effIndex, Creature *crTarget);
typedef bool(TRINITY_IMPORT * scriptCallEffectDummyItem) (Unit *caster, uint32 spellId, uint32 effIndex, Item *itemTarget);
@@ -89,6 +90,7 @@ typedef struct
scriptCallItemQuestAccept ItemQuestAccept;
scriptCallGOQuestAccept GOQuestAccept;
scriptCallItemUse ItemUse;
+ scriptCallItemExpire ItemExpire;
scriptCallEffectDummyGameObj EffectDummyGameObj;
scriptCallEffectDummyCreature EffectDummyCreature;
scriptCallEffectDummyItem EffectDummyItem;
diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h
index e958f911440..987eea769f5 100644
--- a/src/game/SharedDefines.h
+++ b/src/game/SharedDefines.h
@@ -249,8 +249,9 @@ enum SpellCategory
#define SPELL_ATTR_CASTABLE_WHILE_SITTING 0x08000000 // 27 castable while sitting
#define SPELL_ATTR_CANT_USED_IN_COMBAT 0x10000000 // 28 Cannot be used in combat
#define SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY 0x20000000 // 29 unaffected by invulnerability (hmm possible not...)
-#define SPELL_ATTR_BREAKABLE_BY_DAMAGE 0x40000000 // 30 breakable by damage?
+#define SPELL_ATTR_BREAKABLE_BY_DAMAGE 0x40000000 // 30
#define SPELL_ATTR_CANT_CANCEL 0x80000000 // 31 positive aura can't be canceled
+
#define SPELL_ATTR_EX_DISMISS_PET 0x00000001 // 0 dismiss pet and not allow to summon new one?
#define SPELL_ATTR_EX_DRAIN_ALL_POWER 0x00000002 // 1 use all power (Only paladin Lay of Hands and Bunyanize)
#define SPELL_ATTR_EX_CHANNELED_1 0x00000004 // 2 channeled target
@@ -270,7 +271,7 @@ enum SpellCategory
#define SPELL_ATTR_EX_UNK16 0x00010000 // 16 on immuniy
#define SPELL_ATTR_EX_UNAUTOCASTABLE_BY_PET 0x00020000 // 17
#define SPELL_ATTR_EX_UNK18 0x00040000 // 18
-#define SPELL_ATTR_EX_UNK19 0x00080000 // 19
+#define SPELL_ATTR_EX_CANT_TARGET_SELF 0x00080000 // 19 Applies only to unit target - for example Divine Intervention (19752)
#define SPELL_ATTR_EX_REQ_COMBO_POINTS1 0x00100000 // 20 Req combo points on target
#define SPELL_ATTR_EX_UNK21 0x00200000 // 21
#define SPELL_ATTR_EX_REQ_COMBO_POINTS2 0x00400000 // 22 Req combo points on target
@@ -320,11 +321,11 @@ enum SpellCategory
#define SPELL_ATTR_EX3_UNK0 0x00000001 // 0
#define SPELL_ATTR_EX3_UNK1 0x00000002 // 1
#define SPELL_ATTR_EX3_UNK2 0x00000004 // 2
-#define SPELL_ATTR_EX3_UNK3 0x00000008 // 3
+#define SPELL_ATTR_EX3_BLOCKABLE_SPELL 0x00000008 // 3 Only dmg class melee in 3.1.3
#define SPELL_ATTR_EX3_UNK4 0x00000010 // 4 Druid Rebirth only this spell have this flag
#define SPELL_ATTR_EX3_UNK5 0x00000020 // 5
#define SPELL_ATTR_EX3_UNK6 0x00000040 // 6
-#define SPELL_ATTR_EX3_UNK7 0x00000080 // 7 separate stack for every caster
+#define SPELL_ATTR_EX3_STACKS_FOR_DIFFERENT_CASTERS 0x00000080 // 7 separate stack for every caster
#define SPELL_ATTR_EX3_PLAYERS_ONLY 0x00000100 // 8 Player only?
#define SPELL_ATTR_EX3_TRIGGERED_CAN_TRIGGER_2 0x00000200 // 9 triggered from effect?
#define SPELL_ATTR_EX3_MAIN_HAND 0x00000400 // 10 Main hand weapon required
@@ -336,7 +337,7 @@ enum SpellCategory
#define SPELL_ATTR_EX3_UNK16 0x00010000 // 16 no triggers effects that trigger on casting a spell??
#define SPELL_ATTR_EX3_NO_INITIAL_AGGRO 0x00020000 // 17 Soothe Animal, 39758, Mind Soothe
#define SPELL_ATTR_EX3_UNK18 0x00040000 // 18
-#define SPELL_ATTR_EX3_UNK19 0x00080000 // 19 spells triggered by spell with this flag can't proc caster auras and can proc from triggered (swings too - 20178)
+#define SPELL_ATTR_EX3_DISABLE_PROC 0x00080000 // 19 during aura proc no spells can trigger (20178, 20375)
#define SPELL_ATTR_EX3_DEATH_PERSISTENT 0x00100000 // 20 Death persistent spells
#define SPELL_ATTR_EX3_UNK21 0x00200000 // 21
#define SPELL_ATTR_EX3_REQ_WAND 0x00400000 // 22 Req wand
@@ -358,7 +359,7 @@ enum SpellCategory
#define SPELL_ATTR_EX4_UNK5 0x00000020 // 5
#define SPELL_ATTR_EX4_NOT_STEALABLE 0x00000040 // 6 although such auras might be dispellable, they cannot be stolen
#define SPELL_ATTR_EX4_UNK7 0x00000080 // 7
-#define SPELL_ATTR_EX4_UNK8 0x00000100 // 8
+#define SPELL_ATTR_EX4_FIXED_DAMAGE 0x00000100 // 8 decimate, share damage?
#define SPELL_ATTR_EX4_UNK9 0x00000200 // 9
#define SPELL_ATTR_EX4_SPELL_VS_EXTEND_COST 0x00000400 // 10 Rogue Shiv have this flag
#define SPELL_ATTR_EX4_UNK11 0x00000800 // 11
@@ -593,7 +594,7 @@ enum SpellEffects
SPELL_EFFECT_SUMMON_PET = 56,
SPELL_EFFECT_LEARN_PET_SPELL = 57,
SPELL_EFFECT_WEAPON_DAMAGE = 58,
- SPELL_EFFECT_OPEN_LOCK_ITEM = 59,
+ SPELL_EFFECT_CREATE_RANDOM_ITEM = 59,
SPELL_EFFECT_PROFICIENCY = 60,
SPELL_EFFECT_SEND_EVENT = 61,
SPELL_EFFECT_POWER_BURN = 62,
@@ -666,10 +667,10 @@ enum SpellEffects
SPELL_EFFECT_APPLY_AREA_AURA_ENEMY = 129,
SPELL_EFFECT_REDIRECT_THREAT = 130,
SPELL_EFFECT_131 = 131,
- SPELL_EFFECT_132 = 132,
+ SPELL_EFFECT_PLAY_MUSIC = 132,
SPELL_EFFECT_UNLEARN_SPECIALIZATION = 133,
SPELL_EFFECT_KILL_CREDIT2 = 134,
- SPELL_EFFECT_135 = 135,
+ SPELL_EFFECT_CALL_PET = 135,
SPELL_EFFECT_HEAL_PCT = 136,
SPELL_EFFECT_ENERGIZE_PCT = 137,
SPELL_EFFECT_138 = 138,
@@ -702,196 +703,201 @@ enum SpellEffects
enum SpellCastResult
{
- SPELL_FAILED_AFFECTING_COMBAT = 0,
- SPELL_FAILED_ALREADY_AT_FULL_HEALTH = 1,
- SPELL_FAILED_ALREADY_AT_FULL_MANA = 2,
- SPELL_FAILED_ALREADY_AT_FULL_POWER = 3,
- SPELL_FAILED_ALREADY_BEING_TAMED = 4,
- SPELL_FAILED_ALREADY_HAVE_CHARM = 5,
- SPELL_FAILED_ALREADY_HAVE_SUMMON = 6,
- SPELL_FAILED_ALREADY_OPEN = 7,
- SPELL_FAILED_AURA_BOUNCED = 8,
- SPELL_FAILED_AUTOTRACK_INTERRUPTED = 9,
- SPELL_FAILED_BAD_IMPLICIT_TARGETS = 10,
- SPELL_FAILED_BAD_TARGETS = 11,
- SPELL_FAILED_CANT_BE_CHARMED = 12,
- SPELL_FAILED_CANT_BE_DISENCHANTED = 13,
- SPELL_FAILED_CANT_BE_DISENCHANTED_SKILL = 14,
- SPELL_FAILED_CANT_BE_MILLED = 15,
- SPELL_FAILED_CANT_BE_PROSPECTED = 16,
- SPELL_FAILED_CANT_CAST_ON_TAPPED = 17,
- SPELL_FAILED_CANT_DUEL_WHILE_INVISIBLE = 18,
- SPELL_FAILED_CANT_DUEL_WHILE_STEALTHED = 19,
- SPELL_FAILED_CANT_STEALTH = 20,
- SPELL_FAILED_CASTER_AURASTATE = 21,
- SPELL_FAILED_CASTER_DEAD = 22,
- SPELL_FAILED_CHARMED = 23,
- SPELL_FAILED_CHEST_IN_USE = 24,
- SPELL_FAILED_CONFUSED = 25,
- SPELL_FAILED_DONT_REPORT = 26,
- SPELL_FAILED_EQUIPPED_ITEM = 27,
- SPELL_FAILED_EQUIPPED_ITEM_CLASS = 28,
- SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND = 29,
- SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND = 30,
- SPELL_FAILED_ERROR = 31,
- SPELL_FAILED_FIZZLE = 32,
- SPELL_FAILED_FLEEING = 33,
- SPELL_FAILED_FOOD_LOWLEVEL = 34,
- SPELL_FAILED_HIGHLEVEL = 35,
- SPELL_FAILED_HUNGER_SATIATED = 36,
- SPELL_FAILED_IMMUNE = 37,
- SPELL_FAILED_INCORRECT_AREA = 38,
- SPELL_FAILED_INTERRUPTED = 39,
- SPELL_FAILED_INTERRUPTED_COMBAT = 40,
- SPELL_FAILED_ITEM_ALREADY_ENCHANTED = 41,
- SPELL_FAILED_ITEM_GONE = 42,
- SPELL_FAILED_ITEM_NOT_FOUND = 43,
- SPELL_FAILED_ITEM_NOT_READY = 44,
- SPELL_FAILED_LEVEL_REQUIREMENT = 45,
- SPELL_FAILED_LINE_OF_SIGHT = 46,
- SPELL_FAILED_LOWLEVEL = 47,
- SPELL_FAILED_LOW_CASTLEVEL = 48,
- SPELL_FAILED_MAINHAND_EMPTY = 49,
- SPELL_FAILED_MOVING = 50,
- SPELL_FAILED_NEED_AMMO = 51,
- SPELL_FAILED_NEED_AMMO_POUCH = 52,
- SPELL_FAILED_NEED_EXOTIC_AMMO = 53,
- SPELL_FAILED_NEED_MORE_ITEMS = 54,
- SPELL_FAILED_NOPATH = 55,
- SPELL_FAILED_NOT_BEHIND = 56,
- SPELL_FAILED_NOT_FISHABLE = 57,
- SPELL_FAILED_NOT_FLYING = 58,
- SPELL_FAILED_NOT_HERE = 59,
- SPELL_FAILED_NOT_INFRONT = 60,
- SPELL_FAILED_NOT_IN_CONTROL = 61,
- SPELL_FAILED_NOT_KNOWN = 62,
- SPELL_FAILED_NOT_MOUNTED = 63,
- SPELL_FAILED_NOT_ON_TAXI = 64,
- SPELL_FAILED_NOT_ON_TRANSPORT = 65,
- SPELL_FAILED_NOT_READY = 66,
- SPELL_FAILED_NOT_SHAPESHIFT = 67,
- SPELL_FAILED_NOT_STANDING = 68,
- SPELL_FAILED_NOT_TRADEABLE = 69,
- SPELL_FAILED_NOT_TRADING = 70,
- SPELL_FAILED_NOT_UNSHEATHED = 71,
- SPELL_FAILED_NOT_WHILE_GHOST = 72,
- SPELL_FAILED_NOT_WHILE_LOOTING = 73,
- SPELL_FAILED_NO_AMMO = 74,
- SPELL_FAILED_NO_CHARGES_REMAIN = 75,
- SPELL_FAILED_NO_CHAMPION = 76,
- SPELL_FAILED_NO_COMBO_POINTS = 77,
- SPELL_FAILED_NO_DUELING = 78,
- SPELL_FAILED_NO_ENDURANCE = 79,
- SPELL_FAILED_NO_FISH = 80,
- SPELL_FAILED_NO_ITEMS_WHILE_SHAPESHIFTED = 81,
- SPELL_FAILED_NO_MOUNTS_ALLOWED = 82,
- SPELL_FAILED_NO_PET = 83,
- SPELL_FAILED_NO_POWER = 84,
- SPELL_FAILED_NOTHING_TO_DISPEL = 85,
- SPELL_FAILED_NOTHING_TO_STEAL = 86,
- SPELL_FAILED_ONLY_ABOVEWATER = 87,
- SPELL_FAILED_ONLY_DAYTIME = 88,
- SPELL_FAILED_ONLY_INDOORS = 89,
- SPELL_FAILED_ONLY_MOUNTED = 90,
- SPELL_FAILED_ONLY_NIGHTTIME = 91,
- SPELL_FAILED_ONLY_OUTDOORS = 92,
- SPELL_FAILED_ONLY_SHAPESHIFT = 93,
- SPELL_FAILED_ONLY_STEALTHED = 94,
- SPELL_FAILED_ONLY_UNDERWATER = 95,
- SPELL_FAILED_OUT_OF_RANGE = 96,
- SPELL_FAILED_PACIFIED = 97,
- SPELL_FAILED_POSSESSED = 98,
- SPELL_FAILED_REAGENTS = 99,
- SPELL_FAILED_REQUIRES_AREA = 100,
- SPELL_FAILED_REQUIRES_SPELL_FOCUS = 101,
- SPELL_FAILED_ROOTED = 102,
- SPELL_FAILED_SILENCED = 103,
- SPELL_FAILED_SPELL_IN_PROGRESS = 104,
- SPELL_FAILED_SPELL_LEARNED = 105,
- SPELL_FAILED_SPELL_UNAVAILABLE = 106,
- SPELL_FAILED_STUNNED = 107,
- SPELL_FAILED_TARGETS_DEAD = 108,
- SPELL_FAILED_TARGET_AFFECTING_COMBAT = 109,
- SPELL_FAILED_TARGET_AURASTATE = 110,
- SPELL_FAILED_TARGET_DUELING = 111,
- SPELL_FAILED_TARGET_ENEMY = 112,
- SPELL_FAILED_TARGET_ENRAGED = 113,
- SPELL_FAILED_TARGET_FRIENDLY = 114,
- SPELL_FAILED_TARGET_IN_COMBAT = 115,
- SPELL_FAILED_TARGET_IS_PLAYER = 116,
- SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED = 117,
- SPELL_FAILED_TARGET_NOT_DEAD = 118,
- SPELL_FAILED_TARGET_NOT_IN_PARTY = 119,
- SPELL_FAILED_TARGET_NOT_LOOTED = 120,
- SPELL_FAILED_TARGET_NOT_PLAYER = 121,
- SPELL_FAILED_TARGET_NO_POCKETS = 122,
- SPELL_FAILED_TARGET_NO_WEAPONS = 123,
- SPELL_FAILED_TARGET_NO_RANGED_WEAPONS = 124,
- SPELL_FAILED_TARGET_UNSKINNABLE = 125,
- SPELL_FAILED_THIRST_SATIATED = 126,
- SPELL_FAILED_TOO_CLOSE = 127,
- SPELL_FAILED_TOO_MANY_OF_ITEM = 128,
- SPELL_FAILED_TOTEM_CATEGORY = 129,
- SPELL_FAILED_TOTEMS = 130,
- SPELL_FAILED_TRY_AGAIN = 131,
- SPELL_FAILED_UNIT_NOT_BEHIND = 132,
- SPELL_FAILED_UNIT_NOT_INFRONT = 133,
- SPELL_FAILED_WRONG_PET_FOOD = 134,
- SPELL_FAILED_NOT_WHILE_FATIGUED = 135,
- SPELL_FAILED_TARGET_NOT_IN_INSTANCE = 136,
- SPELL_FAILED_NOT_WHILE_TRADING = 137,
- SPELL_FAILED_TARGET_NOT_IN_RAID = 138,
- SPELL_FAILED_TARGET_FREEFORALL = 139,
- SPELL_FAILED_NO_EDIBLE_CORPSES = 140,
- SPELL_FAILED_ONLY_BATTLEGROUNDS = 141,
- SPELL_FAILED_TARGET_NOT_GHOST = 142,
- SPELL_FAILED_TRANSFORM_UNUSABLE = 143,
- SPELL_FAILED_WRONG_WEATHER = 144,
- SPELL_FAILED_DAMAGE_IMMUNE = 145,
- SPELL_FAILED_PREVENTED_BY_MECHANIC = 146,
- SPELL_FAILED_PLAY_TIME = 147,
- SPELL_FAILED_REPUTATION = 148,
- SPELL_FAILED_MIN_SKILL = 149,
- SPELL_FAILED_NOT_IN_ARENA = 150,
- SPELL_FAILED_NOT_ON_SHAPESHIFT = 151,
- SPELL_FAILED_NOT_ON_STEALTHED = 152,
- SPELL_FAILED_NOT_ON_DAMAGE_IMMUNE = 153,
- SPELL_FAILED_NOT_ON_MOUNTED = 154,
- SPELL_FAILED_TOO_SHALLOW = 155,
- SPELL_FAILED_TARGET_NOT_IN_SANCTUARY = 156,
- SPELL_FAILED_TARGET_IS_TRIVIAL = 157,
- SPELL_FAILED_BM_OR_INVISGOD = 158,
- SPELL_FAILED_EXPERT_RIDING_REQUIREMENT = 159,
- SPELL_FAILED_ARTISAN_RIDING_REQUIREMENT = 160,
- SPELL_FAILED_NOT_IDLE = 161,
- SPELL_FAILED_NOT_INACTIVE = 162,
- SPELL_FAILED_PARTIAL_PLAYTIME = 163,
- SPELL_FAILED_NO_PLAYTIME = 164,
- SPELL_FAILED_NOT_IN_BATTLEGROUND = 165,
- SPELL_FAILED_NOT_IN_RAID_INSTANCE = 166,
- SPELL_FAILED_ONLY_IN_ARENA = 167,
- SPELL_FAILED_TARGET_LOCKED_TO_RAID_INSTANCE = 168,
- SPELL_FAILED_ON_USE_ENCHANT = 169,
- SPELL_FAILED_NOT_ON_GROUND = 170,
- SPELL_FAILED_CUSTOM_ERROR = 171,
- SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW = 172,
- SPELL_FAILED_TOO_MANY_SOCKETS = 173,
- SPELL_FAILED_INVALID_GLYPH = 174,
- SPELL_FAILED_UNIQUE_GLYPH = 175,
- SPELL_FAILED_GLYPH_SOCKET_LOCKED = 176,
- SPELL_FAILED_NO_VALID_TARGETS = 177,
- SPELL_FAILED_ITEM_AT_MAX_CHARGES = 178,
- SPELL_FAILED_NOT_IN_BARBERSHOP = 179,
- SPELL_FAILED_FISHING_TOO_LOW = 180,
- SPELL_FAILED_UNKNOWN = 181,
-
- SPELL_CAST_OK = 255 //custom value, don't must be send to client
+ SPELL_FAILED_AFFECTING_COMBAT = 0x00,
+ SPELL_FAILED_ALREADY_AT_FULL_HEALTH = 0x01,
+ SPELL_FAILED_ALREADY_AT_FULL_MANA = 0x02,
+ SPELL_FAILED_ALREADY_AT_FULL_POWER = 0x03,
+ SPELL_FAILED_ALREADY_BEING_TAMED = 0x04,
+ SPELL_FAILED_ALREADY_HAVE_CHARM = 0x05,
+ SPELL_FAILED_ALREADY_HAVE_SUMMON = 0x06,
+ SPELL_FAILED_ALREADY_OPEN = 0x07,
+ SPELL_FAILED_AURA_BOUNCED = 0x08,
+ SPELL_FAILED_AUTOTRACK_INTERRUPTED = 0x09,
+ SPELL_FAILED_BAD_IMPLICIT_TARGETS = 0x0A,
+ SPELL_FAILED_BAD_TARGETS = 0x0B,
+ SPELL_FAILED_CANT_BE_CHARMED = 0x0C,
+ SPELL_FAILED_CANT_BE_DISENCHANTED = 0x0D,
+ SPELL_FAILED_CANT_BE_DISENCHANTED_SKILL = 0x0E,
+ SPELL_FAILED_CANT_BE_MILLED = 0x0F,
+ SPELL_FAILED_CANT_BE_PROSPECTED = 0x10,
+ SPELL_FAILED_CANT_CAST_ON_TAPPED = 0x11,
+ SPELL_FAILED_CANT_DUEL_WHILE_INVISIBLE = 0x12,
+ SPELL_FAILED_CANT_DUEL_WHILE_STEALTHED = 0x13,
+ SPELL_FAILED_CANT_STEALTH = 0x14,
+ SPELL_FAILED_CASTER_AURASTATE = 0x15,
+ SPELL_FAILED_CASTER_DEAD = 0x16,
+ SPELL_FAILED_CHARMED = 0x17,
+ SPELL_FAILED_CHEST_IN_USE = 0x18,
+ SPELL_FAILED_CONFUSED = 0x19,
+ SPELL_FAILED_DONT_REPORT = 0x1A,
+ SPELL_FAILED_EQUIPPED_ITEM = 0x1B,
+ SPELL_FAILED_EQUIPPED_ITEM_CLASS = 0x1C,
+ SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND = 0x1D,
+ SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND = 0x1E,
+ SPELL_FAILED_ERROR = 0x1F,
+ SPELL_FAILED_FIZZLE = 0x20,
+ SPELL_FAILED_FLEEING = 0x21,
+ SPELL_FAILED_FOOD_LOWLEVEL = 0x22,
+ SPELL_FAILED_HIGHLEVEL = 0x23,
+ SPELL_FAILED_HUNGER_SATIATED = 0x24,
+ SPELL_FAILED_IMMUNE = 0x25,
+ SPELL_FAILED_INCORRECT_AREA = 0x26,
+ SPELL_FAILED_INTERRUPTED = 0x27,
+ SPELL_FAILED_INTERRUPTED_COMBAT = 0x28,
+ SPELL_FAILED_ITEM_ALREADY_ENCHANTED = 0x29,
+ SPELL_FAILED_ITEM_GONE = 0x2A,
+ SPELL_FAILED_ITEM_NOT_FOUND = 0x2B,
+ SPELL_FAILED_ITEM_NOT_READY = 0x2C,
+ SPELL_FAILED_LEVEL_REQUIREMENT = 0x2D,
+ SPELL_FAILED_LINE_OF_SIGHT = 0x2E,
+ SPELL_FAILED_LOWLEVEL = 0x2F,
+ SPELL_FAILED_LOW_CASTLEVEL = 0x30,
+ SPELL_FAILED_MAINHAND_EMPTY = 0x31,
+ SPELL_FAILED_MOVING = 0x32,
+ SPELL_FAILED_NEED_AMMO = 0x33,
+ SPELL_FAILED_NEED_AMMO_POUCH = 0x34,
+ SPELL_FAILED_NEED_EXOTIC_AMMO = 0x35,
+ SPELL_FAILED_NEED_MORE_ITEMS = 0x36,
+ SPELL_FAILED_NOPATH = 0x37,
+ SPELL_FAILED_NOT_BEHIND = 0x38,
+ SPELL_FAILED_NOT_FISHABLE = 0x39,
+ SPELL_FAILED_NOT_FLYING = 0x3A,
+ SPELL_FAILED_NOT_HERE = 0x3B,
+ SPELL_FAILED_NOT_INFRONT = 0x3C,
+ SPELL_FAILED_NOT_IN_CONTROL = 0x3D,
+ SPELL_FAILED_NOT_KNOWN = 0x3E,
+ SPELL_FAILED_NOT_MOUNTED = 0x3F,
+ SPELL_FAILED_NOT_ON_TAXI = 0x40,
+ SPELL_FAILED_NOT_ON_TRANSPORT = 0x41,
+ SPELL_FAILED_NOT_READY = 0x42,
+ SPELL_FAILED_NOT_SHAPESHIFT = 0x43,
+ SPELL_FAILED_NOT_STANDING = 0x44,
+ SPELL_FAILED_NOT_TRADEABLE = 0x45,
+ SPELL_FAILED_NOT_TRADING = 0x46,
+ SPELL_FAILED_NOT_UNSHEATHED = 0x47,
+ SPELL_FAILED_NOT_WHILE_GHOST = 0x48,
+ SPELL_FAILED_NOT_WHILE_LOOTING = 0x49,
+ SPELL_FAILED_NO_AMMO = 0x4A,
+ SPELL_FAILED_NO_CHARGES_REMAIN = 0x4B,
+ SPELL_FAILED_NO_CHAMPION = 0x4C,
+ SPELL_FAILED_NO_COMBO_POINTS = 0x4D,
+ SPELL_FAILED_NO_DUELING = 0x4E,
+ SPELL_FAILED_NO_ENDURANCE = 0x4F,
+ SPELL_FAILED_NO_FISH = 0x50,
+ SPELL_FAILED_NO_ITEMS_WHILE_SHAPESHIFTED = 0x51,
+ SPELL_FAILED_NO_MOUNTS_ALLOWED = 0x52,
+ SPELL_FAILED_NO_PET = 0x53,
+ SPELL_FAILED_NO_POWER = 0x54,
+ SPELL_FAILED_NOTHING_TO_DISPEL = 0x55,
+ SPELL_FAILED_NOTHING_TO_STEAL = 0x56,
+ SPELL_FAILED_ONLY_ABOVEWATER = 0x57,
+ SPELL_FAILED_ONLY_DAYTIME = 0x58,
+ SPELL_FAILED_ONLY_INDOORS = 0x59,
+ SPELL_FAILED_ONLY_MOUNTED = 0x5A,
+ SPELL_FAILED_ONLY_NIGHTTIME = 0x5B,
+ SPELL_FAILED_ONLY_OUTDOORS = 0x5C,
+ SPELL_FAILED_ONLY_SHAPESHIFT = 0x5D,
+ SPELL_FAILED_ONLY_STEALTHED = 0x5E,
+ SPELL_FAILED_ONLY_UNDERWATER = 0x5F,
+ SPELL_FAILED_OUT_OF_RANGE = 0x60,
+ SPELL_FAILED_PACIFIED = 0x61,
+ SPELL_FAILED_POSSESSED = 0x62,
+ SPELL_FAILED_REAGENTS = 0x63,
+ SPELL_FAILED_REQUIRES_AREA = 0x64,
+ SPELL_FAILED_REQUIRES_SPELL_FOCUS = 0x65,
+ SPELL_FAILED_ROOTED = 0x66,
+ SPELL_FAILED_SILENCED = 0x67,
+ SPELL_FAILED_SPELL_IN_PROGRESS = 0x68,
+ SPELL_FAILED_SPELL_LEARNED = 0x69,
+ SPELL_FAILED_SPELL_UNAVAILABLE = 0x6A,
+ SPELL_FAILED_STUNNED = 0x6B,
+ SPELL_FAILED_TARGETS_DEAD = 0x6C,
+ SPELL_FAILED_TARGET_AFFECTING_COMBAT = 0x6D,
+ SPELL_FAILED_TARGET_AURASTATE = 0x6E,
+ SPELL_FAILED_TARGET_DUELING = 0x6F,
+ SPELL_FAILED_TARGET_ENEMY = 0x70,
+ SPELL_FAILED_TARGET_ENRAGED = 0x71,
+ SPELL_FAILED_TARGET_FRIENDLY = 0x72,
+ SPELL_FAILED_TARGET_IN_COMBAT = 0x73,
+ SPELL_FAILED_TARGET_IS_PLAYER = 0x74,
+ SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED = 0x75,
+ SPELL_FAILED_TARGET_NOT_DEAD = 0x76,
+ SPELL_FAILED_TARGET_NOT_IN_PARTY = 0x77,
+ SPELL_FAILED_TARGET_NOT_LOOTED = 0x78,
+ SPELL_FAILED_TARGET_NOT_PLAYER = 0x79,
+ SPELL_FAILED_TARGET_NO_POCKETS = 0x7A,
+ SPELL_FAILED_TARGET_NO_WEAPONS = 0x7B,
+ SPELL_FAILED_TARGET_NO_RANGED_WEAPONS = 0x7C,
+ SPELL_FAILED_TARGET_UNSKINNABLE = 0x7D,
+ SPELL_FAILED_THIRST_SATIATED = 0x7E,
+ SPELL_FAILED_TOO_CLOSE = 0x7F,
+ SPELL_FAILED_TOO_MANY_OF_ITEM = 0x80,
+ SPELL_FAILED_TOTEM_CATEGORY = 0x81,
+ SPELL_FAILED_TOTEMS = 0x82,
+ SPELL_FAILED_TRY_AGAIN = 0x83,
+ SPELL_FAILED_UNIT_NOT_BEHIND = 0x84,
+ SPELL_FAILED_UNIT_NOT_INFRONT = 0x85,
+ SPELL_FAILED_WRONG_PET_FOOD = 0x86,
+ SPELL_FAILED_NOT_WHILE_FATIGUED = 0x87,
+ SPELL_FAILED_TARGET_NOT_IN_INSTANCE = 0x88,
+ SPELL_FAILED_NOT_WHILE_TRADING = 0x89,
+ SPELL_FAILED_TARGET_NOT_IN_RAID = 0x8A,
+ SPELL_FAILED_TARGET_FREEFORALL = 0x8B,
+ SPELL_FAILED_NO_EDIBLE_CORPSES = 0x8C,
+ SPELL_FAILED_ONLY_BATTLEGROUNDS = 0x8D,
+ SPELL_FAILED_TARGET_NOT_GHOST = 0x8E,
+ SPELL_FAILED_TRANSFORM_UNUSABLE = 0x8F,
+ SPELL_FAILED_WRONG_WEATHER = 0x90,
+ SPELL_FAILED_DAMAGE_IMMUNE = 0x91,
+ SPELL_FAILED_PREVENTED_BY_MECHANIC = 0x92,
+ SPELL_FAILED_PLAY_TIME = 0x93,
+ SPELL_FAILED_REPUTATION = 0x94,
+ SPELL_FAILED_MIN_SKILL = 0x95,
+ SPELL_FAILED_NOT_IN_ARENA = 0x96,
+ SPELL_FAILED_NOT_ON_SHAPESHIFT = 0x97,
+ SPELL_FAILED_NOT_ON_STEALTHED = 0x98,
+ SPELL_FAILED_NOT_ON_DAMAGE_IMMUNE = 0x99,
+ SPELL_FAILED_NOT_ON_MOUNTED = 0x9A,
+ SPELL_FAILED_TOO_SHALLOW = 0x9B,
+ SPELL_FAILED_TARGET_NOT_IN_SANCTUARY = 0x9C,
+ SPELL_FAILED_TARGET_IS_TRIVIAL = 0x9D,
+ SPELL_FAILED_BM_OR_INVISGOD = 0x9E,
+ SPELL_FAILED_EXPERT_RIDING_REQUIREMENT = 0x9F,
+ SPELL_FAILED_ARTISAN_RIDING_REQUIREMENT = 0xA0,
+ SPELL_FAILED_NOT_IDLE = 0xA1,
+ SPELL_FAILED_NOT_INACTIVE = 0xA2,
+ SPELL_FAILED_PARTIAL_PLAYTIME = 0xA3,
+ SPELL_FAILED_NO_PLAYTIME = 0xA4,
+ SPELL_FAILED_NOT_IN_BATTLEGROUND = 0xA5,
+ SPELL_FAILED_NOT_IN_RAID_INSTANCE = 0xA6,
+ SPELL_FAILED_ONLY_IN_ARENA = 0xA7,
+ SPELL_FAILED_TARGET_LOCKED_TO_RAID_INSTANCE = 0xA8,
+ SPELL_FAILED_ON_USE_ENCHANT = 0xA9,
+ SPELL_FAILED_NOT_ON_GROUND = 0xAA,
+ SPELL_FAILED_CUSTOM_ERROR = 0xAB,
+ SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW = 0xAC,
+ SPELL_FAILED_TOO_MANY_SOCKETS = 0xAD,
+ SPELL_FAILED_INVALID_GLYPH = 0xAE,
+ SPELL_FAILED_UNIQUE_GLYPH = 0xAF,
+ SPELL_FAILED_GLYPH_SOCKET_LOCKED = 0xB0,
+ SPELL_FAILED_NO_VALID_TARGETS = 0xB1,
+ SPELL_FAILED_ITEM_AT_MAX_CHARGES = 0xB2,
+ SPELL_FAILED_NOT_IN_BARBERSHOP = 0xB3,
+ SPELL_FAILED_FISHING_TOO_LOW = 0xB4,
+ SPELL_FAILED_ITEM_ENCHANT_TRADE_WINDOW = 0xB5,
+ SPELL_FAILED_SUMMON_PENDING = 0xB6,
+ SPELL_FAILED_MAX_SOCKETS = 0xB7,
+ SPELL_FAILED_PET_CAN_RENAME = 0xB8,
+ SPELL_FAILED_UNKNOWN = 0xB9,
+
+ SPELL_CAST_OK = 0xFF // custom value, don't must be send to client
};
// Spell aura states
enum AuraState
{ // (C) used in caster aura state (T) used in target aura state
// (c) used in caster aura state-not (t) used in target aura state-not
+ AURA_STATE_NONE = 0, // C |
AURA_STATE_DEFENSE = 1, // C |
AURA_STATE_HEALTHLESS_20_PERCENT = 2, // CcT |
AURA_STATE_BERSERKING = 3, // C T |
@@ -907,7 +913,7 @@ enum AuraState
//AURA_STATE_UNKNOWN11 = 11, // t|
AURA_STATE_FAERIE_FIRE = 12, // c t|
AURA_STATE_HEALTHLESS_35_PERCENT = 13, // C T |
- AURA_STATE_IMMOLATE = 14, // T |
+ AURA_STATE_CONFLAGRATE = 14, // T |
AURA_STATE_SWIFTMEND = 15, // T |
AURA_STATE_DEADLY_POISON = 16, // T |
AURA_STATE_ENRAGE = 17, // C |
@@ -919,6 +925,9 @@ enum AuraState
AURA_STATE_HEALTH_ABOVE_75_PERCENT = 23, // C |
};
+#define PER_CASTER_AURA_STATE_MASK ( \
+ (1<<(AURA_STATE_CONFLAGRATE-1))|(1<<(AURA_STATE_DEADLY_POISON-1)))
+
// Spell mechanics
enum Mechanics
{
@@ -965,7 +974,13 @@ enum Mechanics
(1<<MECHANIC_SHACKLE )|(1<<MECHANIC_TURN )|(1<<MECHANIC_HORROR)| \
(1<<MECHANIC_DAZE )|(1<<MECHANIC_SAPPED ) )
-// Spell dispel type
+// Daze and all croud control spells except polymorph are not removed
+#define MECHANIC_NOT_REMOVED_BY_SHAPESHIFT ( \
+ (1<<MECHANIC_CHARM )|(1<<MECHANIC_DISORIENTED)|(1<<MECHANIC_FEAR )|(1<<MECHANIC_PACIFY )| \
+ (1<<MECHANIC_STUN )|(1<<MECHANIC_FREEZE )|(1<<MECHANIC_BANISH)|(1<<MECHANIC_SHACKLE)| \
+ (1<<MECHANIC_HORROR)|(1<<MECHANIC_TURN )|(1<<MECHANIC_DAZE )|(1<<MECHANIC_SAPPED ) )
+
+// Spell dispell type
enum DispelType
{
DISPEL_NONE = 0,
@@ -1835,6 +1850,7 @@ enum CreatureType
CREATURE_TYPE_GAS_CLOUD = 13
};
+uint32 const CREATURE_TYPEMASK_DEMON_OR_UNDEAD = (1 << (CREATURE_TYPE_DEMON-1)) | (1 << (CREATURE_TYPE_UNDEAD-1));
uint32 const CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD = (1 << (CREATURE_TYPE_HUMANOID-1)) | (1 << (CREATURE_TYPE_UNDEAD-1));
uint32 const CREATURE_TYPEMASK_MECHANICAL_OR_ELEMENTAL = (1 << (CREATURE_TYPE_MECHANICAL-1)) | (1 << (CREATURE_TYPE_ELEMENTAL-1));
@@ -2269,7 +2285,9 @@ enum CorpseDynFlags
#define SPELL_ID_WEAPON_SWITCH_COOLDOWN_1_0s 6123
#define SPELL_ID_AUTOSHOT 75 // used for checks in other spells interruption
#define SPELL_ID_SHADOWMELD 58984 // used for check ignore stealth stance state
-
+#define SPELL_ID_BLOOD_PRESENCE 48266 // Blood Presence
+#define SPELL_ID_FROST_PRESENCE 48263 // Frost Presence
+#define SPELL_ID_UNHOLY_PRESENCE 48265 // Unholy Presence
enum WeatherType
{
WEATHER_TYPE_FINE = 0,
@@ -2384,20 +2402,23 @@ enum DiminishingGroup
{
// Common Groups
DIMINISHING_NONE,
- DIMINISHING_CONTROL_STUN, // Player Controlled stuns
- DIMINISHING_TRIGGER_STUN, // By aura proced stuns, usualy chance on hit talents
- DIMINISHING_CONTROL_ROOT, // Immobilizing effects from casted spells
- DIMINISHING_TRIGGER_ROOT, // Immobilizing effects from triggered spells like Frostbite
+ DIMINISHING_CONTROL_STUN, // Player Controlled stuns
+ DIMINISHING_TRIGGER_STUN, // By aura proced stuns, usualy chance on hit talents
+ DIMINISHING_CONTROL_ROOT, // Immobilizing effects from casted spells
+ DIMINISHING_TRIGGER_ROOT, // Immobilizing effects from triggered spells like Frostbite
DIMINISHING_CHARM,
- DIMINISHING_SLEEP_FREEZE,
DIMINISHING_POLYMORPH, // Also: Gouge, Sap, Repentance, Hungering Cold
- DIMINISHING_CHEAPSHOT_POUNCE,
- DIMINISHING_DEATHCOIL, // Death Coil Diminish only with another Death Coil
- DIMINISHING_SILENCE,
DIMINISHING_KNOCKOUT, // Sap, Knockout mechanics
- DIMINISHING_DISARM,
DIMINISHING_FEAR_BLIND, // Intimidating Shout, Howl of Terror, Blind
- DIMINISHING_FEAR,
+ // Warlock Specific
+ DIMINISHING_DEATHCOIL, // Death Coil Diminish only with another Death Coil
+ // Druid Specific
+ DIMINISHING_CYCLONE, // From 2.3.0
+ // Shared Class Specific
+ DIMINISHING_CHEAPSHOT_POUNCE,
+ DIMINISHING_DISARM, // From 2.3.0
+ DIMINISHING_SILENCE, // From 2.3.0
+ DIMINISHING_FREEZE_SLEEP, // Hunter's Freezing Trap
DIMINISHING_BANISH,
DIMINISHING_TAUNT,
DIMINISHING_LIMITONLY // Don't Diminish, but limit duration to 10s
diff --git a/src/game/SkillDiscovery.cpp b/src/game/SkillDiscovery.cpp
index 2116e554a9f..686fcf889b9 100644
--- a/src/game/SkillDiscovery.cpp
+++ b/src/game/SkillDiscovery.cpp
@@ -26,6 +26,7 @@
#include "Util.h"
#include "SkillDiscovery.h"
#include "SpellMgr.h"
+#include "Player.h"
#include <map>
struct SkillDiscoveryEntry
@@ -37,7 +38,7 @@ struct SkillDiscoveryEntry
SkillDiscoveryEntry()
: spellId(0), reqSkillValue(0), chance(0) {}
- SkillDiscoveryEntry(uint16 _spellId, uint32 req_skill_val, float _chance)
+ SkillDiscoveryEntry(uint32 _spellId, uint32 req_skill_val, float _chance)
: spellId(_spellId), reqSkillValue(req_skill_val), chance(_chance) {}
};
@@ -105,7 +106,9 @@ void LoadSkillDiscoveryTable()
{
if (reportedReqSpells.count(reqSkillOrSpell)==0)
{
- sLog.outErrorDb("Spell (ID: %u) not have have MECHANIC_DISCOVERY (28) value in Mechanic field in spell.dbc and not 100%% chance random discovery ability but listed for spellId %u (and maybe more) in `skill_discovery_template` table",reqSkillOrSpell,spellId);
+ sLog.outErrorDb("Spell (ID: %u) not have MECHANIC_DISCOVERY (28) value in Mechanic field in spell.dbc"
+ " and not 100%% chance random discovery ability but listed for spellId %u (and maybe more) in `skill_discovery_template` table",
+ reqSkillOrSpell,spellId);
reportedReqSpells.insert(reqSkillOrSpell);
}
continue;
@@ -144,6 +147,21 @@ void LoadSkillDiscoveryTable()
sLog.outString( ">> Loaded %u skill discovery definitions", count );
if(!ssNonDiscoverableEntries.str().empty())
sLog.outErrorDb("Some items can't be successfully discovered: have in chance field value < 0.000001 in `skill_discovery_template` DB table . List:\n%s",ssNonDiscoverableEntries.str().c_str());
+
+ // report about empty data for explicit discovery spells
+ for(uint32 spell_id = 1; spell_id < sSpellStore.GetNumRows(); ++spell_id)
+ {
+ SpellEntry const* spellEntry = sSpellStore.LookupEntry(spell_id);
+ if(!spellEntry)
+ continue;
+
+ // skip not explicit discovery spells
+ if (!IsExplicitDiscoverySpell(spellEntry))
+ continue;
+
+ if(SkillDiscoveryStore.find(spell_id)==SkillDiscoveryStore.end())
+ sLog.outErrorDb("Spell (ID: %u) is 100%% chance random discovery ability but not have data in `skill_discovery_template` table",spell_id);
+ }
}
uint32 GetExplicitDiscoverySpell(uint32 spellId, Player* player)
diff --git a/src/game/SocialMgr.cpp b/src/game/SocialMgr.cpp
index fb0e1574d08..d94cd422f11 100644
--- a/src/game/SocialMgr.cpp
+++ b/src/game/SocialMgr.cpp
@@ -198,7 +198,7 @@ void SocialMgr::GetFriendInfo(Player *player, uint32 friendGUID, FriendInfo &fri
uint32 team = player->GetTeam();
AccountTypes security = player->GetSession()->GetSecurity();
bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST);
- bool gmInWhoList = sWorld.getConfig(CONFIG_GM_IN_WHO_LIST) || security > SEC_PLAYER;
+ AccountTypes gmLevelInWhoList = AccountTypes (sWorld.getConfig(CONFIG_GM_LEVEL_IN_WHO_LIST));
PlayerSocialMap::iterator itr = player->GetSocial()->m_playerSocialMap.find(friendGUID);
if(itr != player->GetSocial()->m_playerSocialMap.end())
@@ -206,10 +206,10 @@ void SocialMgr::GetFriendInfo(Player *player, uint32 friendGUID, FriendInfo &fri
// PLAYER see his team only and PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters
// MODERATOR, GAME MASTER, ADMINISTRATOR can see all
- if( pFriend && pFriend->GetName() &&
- ( security > SEC_PLAYER ||
- ( pFriend->GetTeam() == team || allowTwoSideWhoList ) &&
- ( pFriend->GetSession()->GetSecurity() == SEC_PLAYER || gmInWhoList && pFriend->IsVisibleGloballyFor(player) )))
+ if (pFriend && pFriend->GetName() &&
+ (security > SEC_PLAYER ||
+ (pFriend->GetTeam() == team || allowTwoSideWhoList) && (pFriend->GetSession()->GetSecurity() <= gmLevelInWhoList)) &&
+ pFriend->IsVisibleGloballyFor(player))
{
friendInfo.Status = FRIEND_STATUS_ONLINE;
if(pFriend->isAFK())
@@ -273,7 +273,7 @@ void SocialMgr::BroadcastToFriendListers(Player *player, WorldPacket *packet)
uint32 team = player->GetTeam();
AccountTypes security = player->GetSession()->GetSecurity();
uint32 guid = player->GetGUIDLow();
- bool gmInWhoList = sWorld.getConfig(CONFIG_GM_IN_WHO_LIST);
+ AccountTypes gmLevelInWhoList = AccountTypes(sWorld.getConfig(CONFIG_GM_LEVEL_IN_WHO_LIST));
bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST);
for(SocialMap::const_iterator itr = m_socialMap.begin(); itr != m_socialMap.end(); ++itr)
@@ -285,10 +285,10 @@ void SocialMgr::BroadcastToFriendListers(Player *player, WorldPacket *packet)
// PLAYER see his team only and PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters
// MODERATOR, GAME MASTER, ADMINISTRATOR can see all
- if( pFriend && pFriend->IsInWorld() &&
- ( pFriend->GetSession()->GetSecurity() > SEC_PLAYER ||
- ( pFriend->GetTeam() == team || allowTwoSideWhoList ) &&
- (security == SEC_PLAYER || gmInWhoList && player->IsVisibleGloballyFor(pFriend) )))
+ if (pFriend && pFriend->IsInWorld() &&
+ (pFriend->GetSession()->GetSecurity() > SEC_PLAYER ||
+ (pFriend->GetTeam() == team || allowTwoSideWhoList) && security <= gmLevelInWhoList) &&
+ player->IsVisibleGloballyFor(pFriend))
{
pFriend->GetSession()->SendPacket(packet);
}
diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp
index ed818d95570..991b525afa7 100644
--- a/src/game/Spell.cpp
+++ b/src/game/Spell.cpp
@@ -82,7 +82,7 @@ struct PrioritizeMana
{
int operator()( PrioritizeManaUnitWraper const& x, PrioritizeManaUnitWraper const& y ) const
{
- return x.getPercent() < y.getPercent();
+ return x.getPercent() > y.getPercent();
}
};
@@ -106,7 +106,7 @@ struct PrioritizeHealth
{
int operator()( PrioritizeHealthUnitWraper const& x, PrioritizeHealthUnitWraper const& y ) const
{
- return x.getPercent() < y.getPercent();
+ return x.getPercent() > y.getPercent();
}
};
@@ -363,6 +363,7 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi
m_referencedFromCurrentSpell = false;
m_executedCurrently = false;
m_needComboPoints = NeedsComboPoints(m_spellInfo);
+ m_comboPointGain = 0;
m_delayStart = 0;
m_delayAtDamageCount = 0;
@@ -370,6 +371,7 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi
m_applyMultiplierMask = 0;
m_effectMask = 0;
+ m_auraScaleMask = 0;
// Get data for type of attack
switch (m_spellInfo->DmgClass)
@@ -700,7 +702,6 @@ void Spell::FillTargetMap()
break;
}
}
-
if(IsChanneledSpell(m_spellInfo))
{
uint8 mask = (1<<i);
@@ -713,6 +714,29 @@ void Spell::FillTargetMap()
}
}
}
+ else if (m_auraScaleMask)
+ {
+ bool checkLvl = !m_UniqueTargetInfo.empty();
+ for(std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end();)
+ {
+ // remove targets which did not pass min level check
+ if(m_auraScaleMask && ihit->effectMask == m_auraScaleMask)
+ {
+ // Do not check for selfcast
+ if (!ihit->scaleAura && ihit->targetGUID != m_caster->GetGUID())
+ {
+ m_UniqueTargetInfo.erase(ihit++);
+ continue;
+ }
+ }
+ ++ihit;
+ }
+ if (checkLvl && m_UniqueTargetInfo.empty())
+ {
+ SendCastResult(SPELL_FAILED_LOWLEVEL);
+ finish(false);
+ }
+ }
}
if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
@@ -734,6 +758,7 @@ void Spell::prepareDataForTriggerSystem(AuraEffect * triggeredByAura)
// Create base triggers flags for Attacker and Victim ( m_procAttacker, m_procVictim and m_procEx)
//==========================================================================================
+ m_procVictim = m_procAttacker = 0;
// Get data for type of attack and fill base info for trigger
switch (m_spellInfo->DmgClass)
{
@@ -755,37 +780,15 @@ void Spell::prepareDataForTriggerSystem(AuraEffect * triggeredByAura)
}
break;
default:
- if (IsPositiveSpell(m_spellInfo->Id)) // Check for positive spell
- {
- if(m_customAttr & SPELL_ATTR_CU_DIRECT_DAMAGE)
- {
- m_procAttacker = PROC_FLAG_SUCCESSFUL_HEALING_SPELL;
- m_procVictim = PROC_FLAG_TAKEN_HEALING_SPELL;
- }
- else
- {
- m_procAttacker = PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL;
- m_procVictim = PROC_FLAG_TAKEN_POSITIVE_SPELL;
- }
- }
- else if (m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_AUTOREPEAT_FLAG) // Wands auto attack
+ if (m_spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON &&
+ m_spellInfo->EquippedItemSubClassMask & (1<<ITEM_SUBCLASS_WEAPON_WAND)
+ && m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_AUTOREPEAT_FLAG) // Wands auto attack
{
m_procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_HIT;
m_procVictim = PROC_FLAG_TAKEN_RANGED_HIT;
}
- else // Negative spell
- {
- if(m_customAttr & SPELL_ATTR_CU_DIRECT_DAMAGE)
- {
- m_procAttacker = PROC_FLAG_SUCCESSFUL_DAMAGING_SPELL_HIT;
- m_procVictim = PROC_FLAG_TAKEN_DAMAGING_SPELL_HIT;
- }
- else
- {
- m_procAttacker = PROC_FLAG_SUCCESSFUL_NEGATIVE_SPELL_HIT;
- m_procVictim = PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT;
- }
- }
+ // For other spells trigger procflags are set in Spell::DoAllEffectOnTarget
+ // Because spell positivity is dependant on target
}
m_procEx= PROC_EX_NONE;
@@ -794,40 +797,34 @@ void Spell::prepareDataForTriggerSystem(AuraEffect * triggeredByAura)
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && (m_spellInfo->SpellFamilyFlags[1] & 0x00002000 || m_spellInfo->SpellFamilyFlags[0] & 0x1C))
{
m_procAttacker |= PROC_FLAG_ON_TRAP_ACTIVATION;
+ // Trigger only from spells originally casted by hunter(trap activation) to prevent multiple trigger from trap triggered spells
+ if (m_originalCasterGUID != m_caster->GetGUID() && m_originalCasterGUID)
+ return;
}
- else
+ /*
+ Effects which are result of aura proc from triggered spell cannot proc
+ to prevent chain proc of these spells
+ */
+ if ((triggeredByAura && !triggeredByAura->GetParentAura()->GetTarget()->CanProc()))
{
- /*
- Effects which are result of aura proc from triggered spell cannot proc
- to prevent chain proc of these spells
- */
- if ((triggeredByAura && !triggeredByAura->GetParentAura()->GetTarget()->CanProc()) || !m_caster->CanProc())
- {
- m_canTrigger=false;
- }
+ m_canTrigger=false;
+ }
+ // Ranged autorepeat attack is set as triggered spell - ignore it
+ if (!(m_procAttacker & PROC_FLAG_SUCCESSFUL_RANGED_HIT))
+ {
if (m_IsTriggeredSpell &&
(m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_TRIGGERED_CAN_TRIGGER ||
m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_TRIGGERED_CAN_TRIGGER_2))
+ m_procEx |= PROC_EX_INTERNAL_CANT_PROC;
+ else if (m_IsTriggeredSpell)
m_procEx |= PROC_EX_INTERNAL_TRIGGERED;
-
- // Totem casts require spellfamilymask defined in spell_proc_event to proc
- if (m_originalCaster && m_caster != m_originalCaster && m_caster->GetTypeId()==TYPEID_UNIT && ((Creature*)m_caster)->isTotem() && m_caster->IsControlledByPlayer())
- {
- m_procEx |= PROC_EX_INTERNAL_REQ_FAMILY;
- }
- // Check done for judgements to make them not trigger seal effects
- else if (m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_UNK1)
- {
- // Rogue poisons
- if (m_spellInfo->SpellFamilyName && m_spellInfo->SpellFamilyFlags)
- m_procEx |= PROC_EX_INTERNAL_REQ_FAMILY;
- else
- m_canTrigger=false;
- }
}
- if (m_IsTriggeredSpell || triggeredByAura)
- m_procEx |= PROC_EX_INTERNAL_CANT_PROC;
+ // Totem casts require spellfamilymask defined in spell_proc_event to proc
+ if (m_originalCaster && m_caster != m_originalCaster && m_caster->GetTypeId()==TYPEID_UNIT && ((Creature*)m_caster)->isTotem() && m_caster->IsControlledByPlayer())
+ {
+ m_procEx |= PROC_EX_INTERNAL_REQ_FAMILY;
+ }
}
void Spell::CleanupTargetList()
@@ -858,6 +855,13 @@ void Spell::AddUnitTarget(Unit* pVictim, uint32 effIndex)
{
if (!immuned)
ihit->effectMask |= 1 << effIndex; // Add only effect mask if not immuned
+ ihit->scaleAura = false;
+ if (m_auraScaleMask && ihit->effectMask == m_auraScaleMask && m_caster != pVictim)
+ {
+ SpellEntry const * auraSpell = sSpellStore.LookupEntry(spellmgr.GetFirstSpellInChain(m_spellInfo->Id));
+ if ((pVictim->getLevel() + 10) >= auraSpell->spellLevel)
+ ihit->scaleAura = true;
+ }
return;
}
}
@@ -872,6 +876,13 @@ void Spell::AddUnitTarget(Unit* pVictim, uint32 effIndex)
target.alive = pVictim->isAlive();
target.damage = 0;
target.crit = false;
+ target.scaleAura = false;
+ if (m_auraScaleMask && target.effectMask == m_auraScaleMask && m_caster != pVictim)
+ {
+ SpellEntry const * auraSpell = sSpellStore.LookupEntry(spellmgr.GetFirstSpellInChain(m_spellInfo->Id));
+ if ((pVictim->getLevel() + 10) >= auraSpell->spellLevel)
+ target.scaleAura = true;
+ }
// Calculate hit result
if(m_originalCaster)
@@ -1052,7 +1063,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)
if(spellHitTarget)
{
- SpellMissInfo missInfo = DoSpellHitOnUnit(spellHitTarget, mask);
+ SpellMissInfo missInfo = DoSpellHitOnUnit(spellHitTarget, mask, target->scaleAura);
if(missInfo != SPELL_MISS_NONE)
{
if(missInfo != SPELL_MISS_MISS)
@@ -1067,6 +1078,50 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)
if( missInfo != SPELL_MISS_NONE && missInfo != SPELL_MISS_MISS)
m_needComboPoints = false;
+ // Trigger info was not filled in spell::preparedatafortriggersystem - we do it now
+ if (canEffectTrigger && !procAttacker && !procVictim)
+ {
+ bool positive = true;
+ if (m_damage > 0)
+ positive = false;
+ else if (!m_healing)
+ {
+ for (uint8 i = 0; i< MAX_SPELL_EFFECTS; ++i)
+ // If at least one effect negative spell is negative hit
+ if (mask & (1<<i) && !IsPositiveEffect(m_spellInfo->Id, i))
+ {
+ positive = false;
+ break;
+ }
+ }
+ switch(m_spellInfo->DmgClass)
+ {
+ case SPELL_DAMAGE_CLASS_MAGIC:
+ if (positive)
+ {
+ procAttacker |= PROC_FLAG_SUCCESSFUL_POSITIVE_MAGIC_SPELL;
+ procVictim |= PROC_FLAG_TAKEN_POSITIVE_MAGIC_SPELL;
+ }
+ else
+ {
+ procAttacker |= PROC_FLAG_SUCCESSFUL_NEGATIVE_MAGIC_SPELL;
+ procVictim |= PROC_FLAG_TAKEN_NEGATIVE_MAGIC_SPELL;
+ }
+ break;
+ case SPELL_DAMAGE_CLASS_NONE:
+ if (positive)
+ {
+ procAttacker |= PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL_HIT;
+ procVictim |= PROC_FLAG_TAKEN_POSITIVE_SPELL;
+ }
+ else
+ {
+ procAttacker |= PROC_FLAG_SUCCESSFUL_NEGATIVE_SPELL_HIT;
+ procVictim |= PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT;
+ }
+ break;
+ }
+ }
// All calculated do it!
// Do healing and triggers
if (m_healing > 0)
@@ -1109,11 +1164,15 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)
// Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
if (canEffectTrigger && missInfo != SPELL_MISS_REFLECT)
+ {
caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, damageInfo.damage, m_attackType, m_spellInfo, m_triggeredByAuraSpell);
+ if(caster->GetTypeId() == TYPEID_PLAYER && (m_spellInfo->Attributes & SPELL_ATTR_STOP_ATTACK_TARGET) == 0 &&
+ (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED))
+ ((Player *)caster)->CastItemCombatSpell(unitTarget, m_attackType, procVictim, procEx);
+ }
if (m_spellAura)
m_spellAura->SetProcDamage(damageInfo.damage);
-
caster->DealSpellDamage(&damageInfo, true);
// Judgement of Blood
@@ -1136,11 +1195,9 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)
if( !m_caster->IsFriendlyTo(unit) && !IsPositiveSpell(m_spellInfo->Id))
{
- if( !(m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_NO_INITIAL_AGGRO) )
- {
- m_caster->CombatStart(unit);
- }
- else if(m_customAttr & SPELL_ATTR_CU_AURA_CC)
+ m_caster->CombatStart(unit, !(m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_NO_INITIAL_AGGRO));
+
+ if(m_customAttr & SPELL_ATTR_CU_AURA_CC)
{
if(!unit->IsStandState())
unit->SetStandState(UNIT_STAND_STATE_STAND);
@@ -1174,7 +1231,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)
}
}
-SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
+SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask, bool scaleAura)
{
if(!unit || !effectMask)
return SPELL_MISS_EVADE;
@@ -1242,7 +1299,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
}
if( unit->isInCombat() && !(m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_NO_INITIAL_AGGRO) )
{
- m_caster->SetInCombatState(unit->GetCombatTimer() > 0);
+ m_caster->SetInCombatState(unit->GetCombatTimer() > 0, unit);
unit->getHostilRefManager().threatAssist(m_caster, 0.0f);
}
}
@@ -1265,21 +1322,43 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
if (aura_effmask)
{
+ // Select rank for aura with level requirements only in specific cases
+ // Unit has to be target only of aura effect, both caster and target have to be players, target has to be other than unit target
+ SpellEntry const * aurSpellInfo = m_spellInfo;
+ int32 basePoints[3];
+ if (scaleAura)
+ {
+ aurSpellInfo = spellmgr.SelectAuraRankForPlayerLevel(m_spellInfo,unitTarget->getLevel());
+ assert (aurSpellInfo);
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ basePoints[i] = aurSpellInfo->EffectBasePoints[i];
+ }
+ }
+ else
+ {
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ basePoints[i] = m_currentBasePoints[i];
+ }
+ }
+
Unit * caster = m_originalCaster ? m_originalCaster : m_caster;
- Aura * Aur = new Aura(m_spellInfo, aura_effmask, m_currentBasePoints, unit, m_caster, caster, m_CastItem);
+ Aura * Aur = new Aura(aurSpellInfo, aura_effmask, basePoints, unit, m_caster, caster, m_CastItem);
if (!Aur->IsAreaAura())
{
// Now Reduce spell duration using data received at spell hit
int32 duration = Aur->GetAuraMaxDuration();
- unit->ApplyDiminishingToDuration(m_diminishGroup,duration,caster,m_diminishLevel);
+ int32 limitduration = GetDiminishingReturnsLimitDuration(m_diminishGroup,aurSpellInfo);
+ unitTarget->ApplyDiminishingToDuration(m_diminishGroup, duration, caster, m_diminishLevel,limitduration);
Aur->setDiminishGroup(m_diminishGroup);
- duration = caster->ModSpellDuration(m_spellInfo, unit, duration, Aur->IsPositive());
+ duration = caster->ModSpellDuration(aurSpellInfo, unit, duration, Aur->IsPositive());
//mod duration of channeled aura by spell haste
if (IsChanneledSpell(m_spellInfo))
- caster->ModSpellCastTime(m_spellInfo, duration, this);
+ caster->ModSpellCastTime(aurSpellInfo, duration, this);
if(duration != Aur->GetAuraMaxDuration())
{
@@ -1288,9 +1367,9 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
}
// Prayer of Mending (jump animation), we need formal caster instead original for correct animation
- if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST)
+ if( aurSpellInfo->SpellFamilyName == SPELLFAMILY_PRIEST)
{
- if(m_spellInfo->SpellFamilyFlags[1] & 0x000020)
+ if(aurSpellInfo->SpellFamilyFlags[1] & 0x000020)
m_caster->CastSpell(unit, 41637, true, NULL, NULL, m_originalCasterGUID);
}
}
@@ -1337,7 +1416,7 @@ void Spell::DoTriggersOnSpellHit(Unit *unit)
if(roll_chance_i(i->second))
{
m_caster->CastSpell(unit, i->first, true);
- sLog.outDebug("Spell %d triggered spell %d by SPELL_AURA_ADD_TARGET_TRIGGER aura", m_spellInfo->Id, i->first);
+ sLog.outDebug("Spell %d triggered spell %d by SPELL_AURA_ADD_TARGET_TRIGGER aura", m_spellInfo->Id, i->first->Id);
}
if (GetSpellDuration(i->first)==-1)
{
@@ -1651,6 +1730,15 @@ WorldObject* Spell::SearchNearbyTarget(float range, SpellTargets TargetType)
{
switch(i_spellST->second.type)
{
+ case SPELL_TARGET_TYPE_CONTROLLED:
+ for(Unit::ControlList::iterator itr = m_caster->m_Controlled.begin(); itr != m_caster->m_Controlled.end(); ++itr)
+ if ((*itr)->GetEntry() == i_spellST->second.targetEntry && (*itr)->IsWithinDistInMap(m_caster, range))
+ {
+ goScriptTarget = NULL;
+ range = m_caster->GetDistance(creatureScriptTarget);
+ creatureScriptTarget = ((Creature *)*itr);
+ }
+ break;
case SPELL_TARGET_TYPE_GAMEOBJECT:
if(i_spellST->second.targetEntry)
{
@@ -2143,6 +2231,7 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)
case TARGET_UNIT_AREA_ENEMY_DST:
case TARGET_UNIT_CONE_ENEMY:
case TARGET_UNIT_CONE_ENEMY_UNKNOWN:
+ case TARGET_UNIT_AREA_PATH:
radius = GetSpellRadius(m_spellInfo, i, false);
targetType = SPELL_TARGETS_ENEMY;
break;
@@ -2181,8 +2270,6 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)
{
case 46584: // Raise Dead
{
- // TODO: change visual of corpses which gave ghoul?
- // Allow corpses to be ghouled only once?
m_targets.m_targetMask &= ~TARGET_FLAG_DEST_LOCATION;
WorldObject* result = FindCorpseUsing<MaNGOS::RaiseDeadObjectCheck> ();
if(result)
@@ -2195,6 +2282,45 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)
}
break;
}
+ // Corpse Explosion
+ case 49158:
+ case 51325:
+ case 51326:
+ case 51327:
+ case 51328:
+ // Search for ghoul if our ghoul or dead body not valid unit target
+ if (!(m_targets.getUnitTarget() && (m_targets.getUnitTarget()->GetEntry() == 26125 && m_targets.getUnitTarget()->GetOwnerGUID() == m_caster->GetGUID()
+ || (m_targets.getUnitTarget()->getDeathState() == CORPSE
+ && m_targets.getUnitTarget()->GetDisplayId() == m_targets.getUnitTarget()->GetNativeDisplayId()
+ && m_targets.getUnitTarget()->GetTypeId()== TYPEID_UNIT
+ && !((Creature*)m_targets.getUnitTarget())->isDeadByDefault()
+ && !(m_targets.getUnitTarget()->GetCreatureTypeMask() & CREATURE_TYPEMASK_MECHANICAL_OR_ELEMENTAL))
+ && m_targets.getUnitTarget()->GetDisplayId() == m_targets.getUnitTarget()->GetNativeDisplayId())))
+ {
+ CleanupTargetList();
+
+ WorldObject* result = FindCorpseUsing <Trinity::ExplodeCorpseObjectCheck> ();
+
+ if(result)
+ {
+ switch(result->GetTypeId())
+ {
+ case TYPEID_UNIT:
+ case TYPEID_PLAYER:
+ m_targets.setUnitTarget((Unit*)result);
+ break;
+ }
+ }
+ else
+ {
+ if (m_caster->GetTypeId()==TYPEID_PLAYER)
+ ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id,true);
+ SendCastResult(SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW);
+ finish(false);
+ }
+ }
+ break;
+
default:
sLog.outDebug("Spell (ID: %u) (caster Entry: %u) does not have record in `spell_script_target`", m_spellInfo->Id, m_caster->GetEntry());
@@ -2213,6 +2339,13 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)
{
if(i_spellST->second.type == SPELL_TARGET_TYPE_CREATURE)
SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ENTRY, i_spellST->second.targetEntry);
+ else if (i_spellST->second.type == SPELL_TARGET_TYPE_CONTROLLED)
+ {
+ for(Unit::ControlList::iterator itr = m_caster->m_Controlled.begin(); itr != m_caster->m_Controlled.end(); ++itr)
+ if ((*itr)->GetEntry() == i_spellST->second.targetEntry &&
+ /*(*itr)->IsWithinDistInMap(m_caster, radius)*/ (*itr)->IsInMap(m_caster)) // For 60243 and 52173 need skip radius check or use range (no radius entry for effect)
+ unitList.push_back(*itr);
+ }
}
}
}
@@ -2319,7 +2452,7 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)
case 59725: // Improved Spell Reflection - aoe aura
unitList.remove(m_caster);
break;
- case 57699: //Replenishment (special target selection) 10 targets with lowest mana
+ case 57669: //Replenishment (special target selection) 10 targets with lowest mana
{
typedef std::priority_queue<PrioritizeManaUnitWraper, std::vector<PrioritizeManaUnitWraper>, PrioritizeMana> TopMana;
TopMana manaUsers;
@@ -2380,6 +2513,34 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)
healedMembers.pop();
}
}
+ // Death Pact
+ if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && m_spellInfo->SpellFamilyFlags[0] & 0x00080000)
+ {
+ Unit * unit_to_add = NULL;
+ for (std::list<Unit*>::iterator itr = unitList.begin() ; itr != unitList.end();++itr)
+ {
+ if ((*itr)->GetTypeId() == TYPEID_UNIT
+ && (*itr)->GetOwnerGUID() == m_caster->GetGUID()
+ && ((Creature*)(*itr))->GetCreatureInfo()->type == CREATURE_TYPE_UNDEAD)
+ {
+ unit_to_add = (*itr);
+ break;
+ }
+ }
+ if (unit_to_add)
+ {
+ unitList.clear();
+ unitList.push_back(unit_to_add);
+ }
+ // Pet not found - remove cooldown
+ else
+ {
+ if (modOwner->GetTypeId()==TYPEID_PLAYER)
+ modOwner->RemoveSpellCooldown(m_spellInfo->Id,true);
+ SendCastResult(SPELL_FAILED_NO_PET);
+ finish(false);
+ }
+ }
}
for(std::list<Unit*>::iterator itr = unitList.begin(); itr != unitList.end(); ++itr)
AddUnitTarget(*itr, i);
@@ -2414,6 +2575,27 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect* triggeredByAura
}
}
+ // Fill aura scaling information
+ if (m_caster->IsControlledByPlayer() && !IsPassiveSpell(m_spellInfo->Id) && m_spellInfo->spellLevel && !IsChanneledSpell(m_spellInfo) && !m_IsTriggeredSpell)
+ {
+ for (uint8 i = 0; i< MAX_SPELL_EFFECTS; ++i)
+ {
+ if (m_spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA)
+ {
+ // Change aura with ranks only if basepoints are taken from spellInfo and aura is positive
+ if (IsPositiveEffect(m_spellInfo->Id, i))
+ {
+ m_auraScaleMask |= (1<<i);
+ if (m_currentBasePoints[i] != m_spellInfo->EffectBasePoints[i])
+ {
+ m_auraScaleMask = 0;
+ break;
+ }
+ }
+ }
+ }
+ }
+
m_spellState = SPELL_STATE_PREPARING;
if(triggeredByAura)
@@ -2458,8 +2640,12 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect* triggeredByAura
}
}
- // Fill cost data
- m_powerCost = CalculatePowerCost();
+ if (m_caster->GetTypeId()==TYPEID_PLAYER)
+ ((Player*)m_caster)->SetSpellModTakingSpell(this, true);
+ // Fill cost data (not use power for item casts
+ m_powerCost = m_CastItem ? 0 : CalculatePowerCost(m_spellInfo, m_caster, m_spellSchoolMask);
+ if (m_caster->GetTypeId()==TYPEID_PLAYER)
+ ((Player*)m_caster)->SetSpellModTakingSpell(this, false);
SpellCastResult result = CheckCast(true);
if(result != SPELL_CAST_OK && !IsAutoRepeat()) //always cast autorepeat dummy for triggering
@@ -2500,7 +2686,7 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect* triggeredByAura
{
// stealth must be removed at cast starting (at show channel bar)
// skip triggered spell (item equip spell casting and other not explicit character casts/item uses)
- if(isSpellBreakStealth(m_spellInfo) )
+ if(!m_IsTriggeredSpell && isSpellBreakStealth(m_spellInfo) )
{
m_caster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CAST);
for(uint32 i = 0; i < 3; ++i)
@@ -2593,6 +2779,7 @@ void Spell::cast(bool skipCheck)
&& !target->IsFriendlyTo(m_caster) && !m_caster->canSeeOrDetect(target, true))
{
SendCastResult(SPELL_FAILED_BAD_TARGETS);
+ SendInterrupted(0);
finish(false);
return;
}
@@ -2626,6 +2813,7 @@ void Spell::cast(bool skipCheck)
if(castResult != SPELL_CAST_OK)
{
SendCastResult(castResult);
+ SendInterrupted(0);
finish(false);
SetExecutedCurrently(false);
return;
@@ -2634,6 +2822,14 @@ void Spell::cast(bool skipCheck)
FillTargetMap();
+ // Spell may be finished after target map check
+ if(m_spellState == SPELL_STATE_FINISHED)
+ {
+ SendInterrupted(0);
+ SetExecutedCurrently(false);
+ return;
+ }
+
if(m_spellInfo->SpellFamilyName)
{
if (m_spellInfo->excludeCasterAuraSpell && !IsPositiveSpell(m_spellInfo->excludeCasterAuraSpell))
@@ -2647,8 +2843,18 @@ void Spell::cast(bool skipCheck)
{
if (m_spellInfo->Mechanic == MECHANIC_BANDAGE) // Bandages
m_preCastSpell = 11196; // Recently Bandaged
- else if(m_spellInfo->SpellIconID == 1662 && m_spellInfo->AttributesEx & 0x20)
- m_preCastSpell = 23230; // Blood Fury - Healing Reduction
+ break;
+ }
+ case SPELLFAMILY_DRUID:
+ {
+ // Faerie Fire (Feral)
+ if (m_spellInfo->SpellFamilyFlags[0] & 0x00000400)
+ {
+ // Trigger only if has correct shapeshift for triggered spell
+ SpellEntry const * spellInfo = sSpellStore.LookupEntry(60089);
+ if (GetErrorAtShapeshiftedCast(spellInfo, m_caster->m_form) == SPELL_CAST_OK)
+ m_preCastSpell = 60089;
+ }
break;
}
}
@@ -2664,7 +2870,13 @@ void Spell::cast(bool skipCheck)
((Player*)m_caster)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL, m_spellInfo->Id);
}
- // this is related to combo points so must be done before takepower
+ if(!m_IsTriggeredSpell)
+ {
+ // Powers have to be taken before SendSpellGo
+ TakePower();
+ TakeReagents(); // we must remove reagents before HandleEffects to allow place crafted item in same slot
+ }
+
// are there any spells need to be triggered after hit?
// handle SPELL_AURA_ADD_TARGET_TRIGGER auras
Unit::AuraEffectList const& targetTriggers = m_caster->GetAurasByType(SPELL_AURA_ADD_TARGET_TRIGGER);
@@ -2682,17 +2894,9 @@ void Spell::cast(bool skipCheck)
}
}
- // this is related to combo points so must be done before takepower
if(m_customAttr & SPELL_ATTR_CU_DIRECT_DAMAGE)
CalculateDamageDoneForAllTargets();
- if(!m_IsTriggeredSpell)
- {
- // Powers have to be taken before SendSpellGo
- TakePower();
- TakeReagents(); // we must remove reagents before HandleEffects to allow place crafted item in same slot
- }
-
// CAST SPELL
SendSpellCooldown();
//SendCastResult(castResult);
@@ -2726,6 +2930,9 @@ void Spell::cast(bool skipCheck)
m_immediateHandled = false;
m_spellState = SPELL_STATE_DELAYED;
SetDelayStart(0);
+
+ if(m_caster->hasUnitState(UNIT_STAT_CASTING) && !m_caster->IsNonMeleeSpellCasted(false, false, true))
+ m_caster->clearUnitState(UNIT_STAT_CASTING);
}
else
{
@@ -2882,6 +3089,7 @@ void Spell::_handle_immediate_phase()
if(!m_originalCaster)
return;
+ uint8 oldEffMask = m_effectMask;
// process ground
for(uint32 j = 0; j < 3; ++j)
{
@@ -2898,6 +3106,38 @@ void Spell::_handle_immediate_phase()
m_effectMask |= (1<<j);
}
}
+ if (oldEffMask != m_effectMask && m_UniqueTargetInfo.empty())
+ {
+ uint32 procAttacker = m_procAttacker;
+ if (!procAttacker)
+ {
+ bool positive = true;
+ for (uint8 i = 0; i< MAX_SPELL_EFFECTS; ++i)
+ // If at least one effect negative spell is negative hit
+ if (m_effectMask & (1<<i) && !IsPositiveEffect(m_spellInfo->Id, i))
+ {
+ positive = false;
+ break;
+ }
+ switch(m_spellInfo->DmgClass)
+ {
+ case SPELL_DAMAGE_CLASS_MAGIC:
+ if (positive)
+ procAttacker |= PROC_FLAG_SUCCESSFUL_POSITIVE_MAGIC_SPELL;
+ else
+ procAttacker |= PROC_FLAG_SUCCESSFUL_NEGATIVE_MAGIC_SPELL;
+ break;
+ case SPELL_DAMAGE_CLASS_NONE:
+ if (positive)
+ procAttacker |= PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL_HIT;
+ else
+ procAttacker |= PROC_FLAG_SUCCESSFUL_NEGATIVE_SPELL_HIT;
+ break;
+ }
+ }
+ // Proc damage for spells which have only dest targets (2484 should proc 51486 for example)
+ m_originalCaster->ProcDamageAndSpell(0, procAttacker, 0, m_procEx | PROC_EX_NORMAL_HIT, 0, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell);
+ }
}
void Spell::_handle_finish_phase()
@@ -2906,6 +3146,10 @@ void Spell::_handle_finish_phase()
if (m_needComboPoints)
((Player*)m_caster)->ClearComboPoints();
+ // Real add combo points from effects
+ if (m_caster->GetTypeId()==TYPEID_PLAYER)
+ ((Player*)m_caster)->GainSpellComboPoints(m_comboPointGain);
+
// spell log
if(m_needSpellLog)
SendLogExecute();
@@ -3046,7 +3290,7 @@ void Spell::finish(bool ok)
if(IsChanneledSpell(m_spellInfo))
m_caster->UpdateInterruptMask();
- if(!m_caster->IsNonMeleeSpellCasted(false, false, true))
+ if(m_caster->hasUnitState(UNIT_STAT_CASTING) && !m_caster->IsNonMeleeSpellCasted(false, false, true))
m_caster->clearUnitState(UNIT_STAT_CASTING);
// Unsummon summon as possessed creatures on spell cancel
@@ -3103,9 +3347,10 @@ void Spell::finish(bool ok)
}
// potions disabled by client, send event "not in combat" if need
- if (!m_triggeredByAuraSpell && m_caster->GetTypeId() == TYPEID_PLAYER)
+ if (m_caster->GetTypeId() == TYPEID_PLAYER)
{
- ((Player*)m_caster)->UpdatePotionCooldown(this);
+ if (!m_triggeredByAuraSpell)
+ ((Player*)m_caster)->UpdatePotionCooldown(this);
// triggered spell pointer can be not set in some cases
// this is needed for proper apply of triggered spell mods
@@ -3251,11 +3496,11 @@ void Spell::SendSpellGo()
//sLog.outDebug("Sending SMSG_SPELL_GO id=%u", m_spellInfo->Id);
uint32 castFlags = CAST_FLAG_UNKNOWN3;
-
+
// triggered spells with spell visual != 0
- if(m_IsTriggeredSpell || m_triggeredByAuraSpell)
+ if((m_IsTriggeredSpell && !IsAutoRepeatRangedSpell(m_spellInfo)) || m_triggeredByAuraSpell)
castFlags |= CAST_FLAG_UNKNOWN0;
-
+
if(m_spellInfo->Attributes & SPELL_ATTR_REQ_AMMO)
castFlags |= CAST_FLAG_AMMO; // arrows/bullets visual
if ((m_caster->GetTypeId() == TYPEID_PLAYER ||
@@ -3352,7 +3597,7 @@ void Spell::WriteAmmoToPacket( WorldPacket * data )
ammoInventoryType = pProto->InventoryType;
}
}
- else if(m_caster->GetDummyAura(46699)) // Requires No Ammo
+ else if(m_caster->HasAura(46699)) // Requires No Ammo
{
ammoDisplayID = 5996; // normal arrow
ammoInventoryType = INVTYPE_AMMO;
@@ -3887,6 +4132,7 @@ void Spell::TakeRunePower()
if((plr->GetRuneCooldown(i) == 0) && (runeCost[rune] > 0))
{
plr->SetRuneCooldown(i, RUNE_COOLDOWN); // 5*2=10 sec
+ plr->SetLastUsedRune(RuneType(rune));
runeCost[rune]--;
}
}
@@ -3901,8 +4147,52 @@ void Spell::TakeRunePower()
if((plr->GetRuneCooldown(i) == 0) && (rune == RUNE_DEATH))
{
plr->SetRuneCooldown(i, RUNE_COOLDOWN); // 5*2=10 sec
+ plr->SetLastUsedRune(RuneType(rune));
runeCost[rune]--;
+ bool auraFound = false;
plr->ConvertRune(i, plr->GetBaseRune(i));
+ // * * * * * * * * * * *
+ // update convert rune auras
+ // * * * * * * * * * * *
+ // Remove rune from SPELL_AURA_CONVERT_RUNE when rune is used
+ // To prevent overriding other rune convert effects
+ Unit::AuraEffectList const& runeconvert = m_caster->GetAurasByType(SPELL_AURA_CONVERT_RUNE);
+ for(Unit::AuraEffectList::const_iterator itr = runeconvert.begin(); itr != runeconvert.end(); ++itr)
+ {
+ // Remove rune of aura if avalible
+ if ((*itr)->GetAmount() & (1<<i))
+ {
+ (*itr)->SetAmount((*itr)->GetAmount() & ~(1<<i));
+ auraFound = true;
+ }
+ // All runes from aura used - remove aura
+ if (!(*itr)->GetAmount())
+ plr->RemoveAura((*itr)->GetParentAura(), AURA_REMOVE_BY_EXPIRE);
+ break;
+ }
+ if (!auraFound)
+ {
+ // Decrease used rune count for dk talent auras
+ // To prevent overriding other rune convert effects
+ Unit::AuraEffectList const& runeconvert = m_caster->GetAurasByType(SPELL_AURA_CONVERT_RUNE);
+ for(Unit::AuraEffectList::const_iterator itr = runeconvert.begin(); itr != runeconvert.end(); ++itr)
+ {
+ if (plr->GetBaseRune(i) != RUNE_DEATH)
+ {
+ if ((*itr)->GetSpellProto()->SpellIconID != 2622)
+ continue;
+ }
+ else if ((*itr)->GetSpellProto()->SpellIconID != 3041 &&
+ (*itr)->GetSpellProto()->SpellIconID != 22)
+ continue;
+
+ // Remove rune of aura if avalible
+ if ((*itr)->GetAmount() & (1<<i))
+ (*itr)->SetAmount((*itr)->GetAmount() & ~(1<<i));
+ break;
+ }
+ }
+
if(runeCost[RUNE_DEATH] == 0)
break;
}
@@ -3976,13 +4266,14 @@ void Spell::HandleThreatSpells(uint32 spellId)
if(!m_targets.getUnitTarget()->CanHaveThreatList())
return;
- SpellThreatEntry const *threatSpell = sSpellThreatStore.LookupEntry<SpellThreatEntry>(spellId);
- if(!threatSpell)
+ uint16 threat = spellmgr.GetSpellThreat(spellId);
+
+ if(!threat)
return;
- m_targets.getUnitTarget()->AddThreat(m_caster, float(threatSpell->threat));
+ m_targets.getUnitTarget()->AddThreat(m_caster, float(threat));
- DEBUG_LOG("Spell %u, rank %u, added an additional %i threat", spellId, spellmgr.GetSpellRank(spellId), threatSpell->threat);
+ DEBUG_LOG("Spell %u, rank %u, added an additional %i threat", spellId, spellmgr.GetSpellRank(spellId), threat);
}
void Spell::HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTarget,uint32 i)
@@ -4021,15 +4312,19 @@ void Spell::TriggerSpell()
SpellCastResult Spell::CheckCast(bool strict)
{
// check cooldowns to prevent cheating
- if(m_caster->GetTypeId()==TYPEID_PLAYER && ((Player*)m_caster)->HasSpellCooldown(m_spellInfo->Id))
+ if(m_caster->GetTypeId()==TYPEID_PLAYER)
{
//can cast triggered (by aura only?) spells while have this flag
if (!m_IsTriggeredSpell && ((Player*)m_caster)->HasFlag(PLAYER_FLAGS, PLAYER_ALLOW_ONLY_ABILITY))
return SPELL_FAILED_SPELL_IN_PROGRESS;
- if(m_triggeredByAuraSpell)
- return SPELL_FAILED_DONT_REPORT;
- else
- return SPELL_FAILED_NOT_READY;
+
+ if (((Player*)m_caster)->HasSpellCooldown(m_spellInfo->Id))
+ {
+ if(m_triggeredByAuraSpell)
+ return SPELL_FAILED_DONT_REPORT;
+ else
+ return SPELL_FAILED_NOT_READY;
+ }
}
// only allow triggered spells if at an ended battleground
@@ -4118,7 +4413,12 @@ SpellCastResult Spell::CheckCast(bool strict)
if(m_spellInfo->excludeTargetAuraSpell && target->HasAura(m_spellInfo->excludeTargetAuraSpell))
return SPELL_FAILED_TARGET_AURASTATE;
- if(target != m_caster)
+ if(!m_IsTriggeredSpell && target == m_caster && m_spellInfo->AttributesEx & SPELL_ATTR_EX_CANT_TARGET_SELF)
+ return SPELL_FAILED_BAD_TARGETS;
+
+ bool non_caster_target = target != m_caster && !spellmgr.IsSpellWithCasterSourceTargetsOnly(m_spellInfo);
+
+ if(non_caster_target)
{
// target state requirements (apply to non-self only), to allow cast affects to self like Dirty Deeds
if(!m_IsTriggeredSpell && m_spellInfo->TargetAuraState && !target->HasAuraState(AuraState(m_spellInfo->TargetAuraState), m_spellInfo, m_caster))
@@ -4131,13 +4431,6 @@ SpellCastResult Spell::CheckCast(bool strict)
if(!m_IsTriggeredSpell && VMAP::VMapFactory::checkSpellForLoS(m_spellInfo->Id) && !m_caster->IsWithinLOSInMap(target))
return SPELL_FAILED_LINE_OF_SIGHT;
- // auto selection spell rank implemented in WorldSession::HandleCastSpellOpcode
- // this case can be triggered if rank not found (too low-level target for first rank)
- if(m_caster->GetTypeId() == TYPEID_PLAYER && !IsPassiveSpell(m_spellInfo->Id) && !m_CastItem)
- for(int i=0;i<3;i++)
- if(IsPositiveEffect(m_spellInfo->Id, i) && m_spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA)
- if(target->getLevel() + 10 < m_spellInfo->spellLevel)
- return SPELL_FAILED_LOWLEVEL;
}
else if (m_caster->GetTypeId() == TYPEID_PLAYER) // Target - is player caster
{
@@ -4173,7 +4466,7 @@ SpellCastResult Spell::CheckCast(bool strict)
//check creature type
//ignore self casts (including area casts when caster selected as target)
- if(target != m_caster)
+ if(non_caster_target)
{
if(!CheckTargetCreatureType(target))
{
@@ -4186,7 +4479,7 @@ SpellCastResult Spell::CheckCast(bool strict)
// TODO: this check can be applied and for player to prevent cheating when IsPositiveSpell will return always correct result.
// check target for pet/charmed casts (not self targeted), self targeted cast used for area effects and etc
- if(m_caster != target && m_caster->GetTypeId() == TYPEID_UNIT && m_caster->GetCharmerOrOwnerGUID())
+ if(non_caster_target && m_caster->GetTypeId() == TYPEID_UNIT && m_caster->GetCharmerOrOwnerGUID())
{
// check correctness positive/negative cast target (pet cast real check and cheating check)
if(IsPositiveSpell(m_spellInfo->Id))
@@ -4225,7 +4518,7 @@ SpellCastResult Spell::CheckCast(bool strict)
}
// check if target is in combat
- if (target != m_caster && (m_spellInfo->AttributesEx & SPELL_ATTR_EX_NOT_IN_COMBAT_TARGET) && target->isInCombat())
+ if (non_caster_target && (m_spellInfo->AttributesEx & SPELL_ATTR_EX_NOT_IN_COMBAT_TARGET) && target->isInCombat())
return SPELL_FAILED_TARGET_AFFECTING_COMBAT;
}
@@ -4442,12 +4735,23 @@ SpellCastResult Spell::CheckCast(bool strict)
if(m_targets.getUnitTarget() && !m_caster->IsFriendlyTo(m_targets.getUnitTarget()) && !m_caster->HasInArc( M_PI, m_targets.getUnitTarget() ))
return SPELL_FAILED_UNIT_NOT_INFRONT;
}
+ else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && m_spellInfo->SpellFamilyFlags[0] == 0x2000) // Death Coil (DeathKnight)
+ {
+ Unit* target = m_targets.getUnitTarget();
+ if (!target || (target->IsFriendlyTo(m_caster) && target->GetCreatureType() != CREATURE_TYPE_UNDEAD))
+ return SPELL_FAILED_BAD_TARGETS;
+ }
else if (m_spellInfo->Id == 19938) // Awaken Peon
{
Unit *unit = m_targets.getUnitTarget();
if(!unit || !unit->HasAura(17743, 0))
return SPELL_FAILED_BAD_TARGETS;
}
+ else if (m_spellInfo->Id == 52264) // Deliver Stolen Horse
+ {
+ if(!m_caster->FindNearestCreature(28653,5))
+ return SPELL_FAILED_OUT_OF_RANGE;
+ }
break;
}
case SPELL_EFFECT_LEARN_SPELL:
@@ -4492,6 +4796,14 @@ SpellCastResult Spell::CheckCast(bool strict)
break;
}
+ case SPELL_EFFECT_APPLY_GLYPH:
+ {
+ uint32 glyphId = m_spellInfo->EffectMiscValue[i];
+ if(GlyphPropertiesEntry const *gp = sGlyphPropertiesStore.LookupEntry(glyphId))
+ if(m_caster->HasAura(gp->SpellId))
+ return SPELL_FAILED_UNIQUE_GLYPH;
+ break;
+ }
case SPELL_EFFECT_FEED_PET:
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
@@ -4529,9 +4841,14 @@ SpellCastResult Spell::CheckCast(bool strict)
}
case SPELL_EFFECT_CHARGE:
{
+ if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR)
+ {
+ // Warbringer - can't be handled in proc system - should be done before checkcast root check and charge effect process
+ if (strict && m_caster->IsScriptOverriden(m_spellInfo, 6953))
+ m_caster->RemoveMovementImpairingAuras();
+ }
if (m_caster->hasUnitState(UNIT_STAT_ROOT))
return SPELL_FAILED_ROOTED;
-
break;
}
case SPELL_EFFECT_SKINNING:
@@ -4564,7 +4881,6 @@ SpellCastResult Spell::CheckCast(bool strict)
break;
}
- case SPELL_EFFECT_OPEN_LOCK_ITEM:
case SPELL_EFFECT_OPEN_LOCK:
{
if( m_spellInfo->EffectImplicitTargetA[i] != TARGET_GAMEOBJECT &&
@@ -4588,7 +4904,7 @@ SpellCastResult Spell::CheckCast(bool strict)
uint32 lockId = 0;
if (GameObject* go = m_targets.getGOTarget())
{
- lockId = go->GetLockId();
+ lockId = go->GetGOInfo()->GetLockId();
if (!lockId)
return SPELL_FAILED_BAD_TARGETS;
}
@@ -4762,27 +5078,34 @@ SpellCastResult Spell::CheckCast(bool strict)
}
case SPELL_AURA_MOD_POSSESS:
case SPELL_AURA_MOD_CHARM:
- //case SPELL_AURA_MOD_POSSESS_PET:
+ case SPELL_AURA_MOD_POSSESS_PET:
+ case SPELL_AURA_AOE_CHARM:
{
- if(m_caster->GetPetGUID())
- return SPELL_FAILED_ALREADY_HAVE_SUMMON;
-
- if(m_caster->GetCharmGUID())
- return SPELL_FAILED_ALREADY_HAVE_CHARM;
-
if(m_caster->GetCharmerGUID())
return SPELL_FAILED_CHARMED;
- Unit *target = m_targets.getUnitTarget();
- if(!target || target->GetTypeId() == TYPEID_UNIT
- && ((Creature*)target)->isVehicle())
- return SPELL_FAILED_BAD_IMPLICIT_TARGETS;
+ if(m_spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_CHARM
+ || m_spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_POSSESS)
+ {
+ if(m_caster->GetPetGUID())
+ return SPELL_FAILED_ALREADY_HAVE_SUMMON;
- if(target->GetCharmerGUID())
- return SPELL_FAILED_CHARMED;
+ if(m_caster->GetCharmGUID())
+ return SPELL_FAILED_ALREADY_HAVE_CHARM;
+ }
+
+ if(Unit *target = m_targets.getUnitTarget())
+ {
+ if(target->GetTypeId() == TYPEID_UNIT && ((Creature*)target)->isVehicle())
+ return SPELL_FAILED_BAD_IMPLICIT_TARGETS;
+
+ if(target->GetCharmerGUID())
+ return SPELL_FAILED_CHARMED;
- if(int32(target->getLevel()) > CalculateDamage(i, target))
- return SPELL_FAILED_HIGHLEVEL;
+ int32 damage = CalculateDamage(i, target);
+ if(damage && int32(target->getLevel()) > damage)
+ return SPELL_FAILED_HIGHLEVEL;
+ }
break;
}
@@ -4818,14 +5141,15 @@ SpellCastResult Spell::CheckCast(bool strict)
break;
}
- case SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED:
case SPELL_AURA_FLY:
+ case SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED:
{
- // not allow cast fly spells at old maps by players (all spells is self target)
- if(m_originalCaster && m_originalCaster->GetTypeId()==TYPEID_PLAYER)
+ // not allow cast fly spells if not have req. skills (all spells is self target)
+ // allow always ghost flight spells
+ if (m_originalCaster && m_originalCaster->GetTypeId() == TYPEID_PLAYER && m_originalCaster->isAlive())
{
- if( !((Player*)m_originalCaster)->IsAllowUseFlyMountsHere() )
- return SPELL_FAILED_NOT_HERE;
+ if (!((Player*)m_originalCaster)->IsKnowHowFlyIn(m_originalCaster->GetMapId(),m_originalCaster->GetZoneId()))
+ return m_IsTriggeredSpell ? SPELL_FAILED_DONT_REPORT : SPELL_FAILED_NOT_HERE;
}
break;
}
@@ -5092,81 +5416,13 @@ SpellCastResult Spell::CheckRange(bool strict)
{
if(!m_caster->IsWithinDist3d(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, max_range))
return SPELL_FAILED_OUT_OF_RANGE;
- if(m_caster->IsWithinDist3d(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, min_range))
+ if(min_range && m_caster->IsWithinDist3d(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, min_range))
return SPELL_FAILED_TOO_CLOSE;
}
return SPELL_CAST_OK;
}
-int32 Spell::CalculatePowerCost()
-{
- // item cast not used power
- if(m_CastItem)
- return 0;
-
- // Spell drain all exist power on cast (Only paladin lay of Hands)
- if (m_spellInfo->AttributesEx & SPELL_ATTR_EX_DRAIN_ALL_POWER)
- {
- // If power type - health drain all
- if (m_spellInfo->powerType == POWER_HEALTH)
- return m_caster->GetHealth();
- // Else drain all power
- if (m_spellInfo->powerType < MAX_POWERS)
- return m_caster->GetPower(Powers(m_spellInfo->powerType));
- sLog.outError("Spell::CalculateManaCost: Unknown power type '%d' in spell %d", m_spellInfo->powerType, m_spellInfo->Id);
- return 0;
- }
-
- // Base powerCost
- int32 powerCost = m_spellInfo->manaCost;
- // PCT cost from total amount
- if (m_spellInfo->ManaCostPercentage)
- {
- switch (m_spellInfo->powerType)
- {
- // health as power used
- case POWER_HEALTH:
- powerCost += m_spellInfo->ManaCostPercentage * m_caster->GetCreateHealth() / 100;
- break;
- case POWER_MANA:
- powerCost += m_spellInfo->ManaCostPercentage * m_caster->GetCreateMana() / 100;
- break;
- case POWER_RAGE:
- case POWER_FOCUS:
- case POWER_ENERGY:
- case POWER_HAPPINESS:
- powerCost += m_spellInfo->ManaCostPercentage * m_caster->GetMaxPower(Powers(m_spellInfo->powerType)) / 100;
- break;
- case POWER_RUNE:
- case POWER_RUNIC_POWER:
- sLog.outDebug("Spell::CalculateManaCost: Not implemented yet!");
- break;
- default:
- sLog.outError("Spell::CalculateManaCost: Unknown power type '%d' in spell %d", m_spellInfo->powerType, m_spellInfo->Id);
- return 0;
- }
- }
- SpellSchools school = GetFirstSchoolInMask(m_spellSchoolMask);
- // Flat mod from caster auras by spell school
- powerCost += m_caster->GetInt32Value(UNIT_FIELD_POWER_COST_MODIFIER + school);
- // Shiv - costs 20 + weaponSpeed*10 energy (apply only to non-triggered spell with energy cost)
- if ( m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_SPELL_VS_EXTEND_COST )
- powerCost += m_caster->GetAttackTime(OFF_ATTACK)/100;
- // Apply cost mod by spell
- if(Player* modOwner = m_caster->GetSpellModOwner())
- modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, powerCost, this);
-
- if(m_spellInfo->Attributes & SPELL_ATTR_LEVEL_DAMAGE_CALCULATION)
- powerCost = int32(powerCost/ (1.117f* m_spellInfo->spellLevel / m_caster->getLevel() -0.1327f));
-
- // PCT mod from user auras by school
- powerCost = int32(powerCost * (1.0f+m_caster->GetFloatValue(UNIT_FIELD_POWER_COST_MULTIPLIER+school)));
- if (powerCost < 0)
- powerCost = 0;
- return powerCost;
-}
-
SpellCastResult Spell::CheckPower()
{
// item cast not used power
@@ -5310,7 +5566,7 @@ SpellCastResult Spell::CheckItems()
TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectFocusCheck>, GridTypeMapContainer > object_checker(checker);
CellLock<GridReadGuard> cell_lock(cell, p);
- cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
+ cell_lock->Visit(cell_lock, object_checker, *m_caster->GetMap());
if(!ok)
return SPELL_FAILED_REQUIRES_SPELL_FOCUS;
@@ -5567,7 +5823,7 @@ SpellCastResult Spell::CheckItems()
if(!ammo)
{
// Requires No Ammo
- if(m_caster->GetDummyAura(46699))
+ if(m_caster->HasAura(46699))
break; // skip other checks
return SPELL_FAILED_NO_AMMO;
@@ -5758,8 +6014,10 @@ bool Spell::CheckTargetCreatureType(Unit* target) const
{
uint32 spellCreatureTargetMask = m_spellInfo->TargetCreatureType;
- // Curse of Doom : not find another way to fix spell target check :/
- if(m_spellInfo->SpellFamilyName==SPELLFAMILY_WARLOCK && m_spellInfo->SpellFamilyFlags.IsEqual(0,0x02,0))
+ // Curse of Doom & Exorcism: not find another way to fix spell target check :/
+ if (m_spellInfo->SpellFamilyName==SPELLFAMILY_WARLOCK && m_spellInfo->Category == 1179 ||
+ // TODO: will be removed in 3.2.x
+ m_spellInfo->SpellFamilyName==SPELLFAMILY_PALADIN && m_spellInfo->Category == 19)
{
// not allow cast at player
if(target->GetTypeId()==TYPEID_PLAYER)
@@ -5834,7 +6092,26 @@ bool Spell::CheckTarget(Unit* target, uint32 eff)
return false;
}
- //Do not check LOS for triggered spells
+ switch(m_spellInfo->EffectApplyAuraName[eff])
+ {
+ case SPELL_AURA_NONE:
+ default:
+ break;
+ case SPELL_AURA_MOD_POSSESS:
+ case SPELL_AURA_MOD_CHARM:
+ case SPELL_AURA_MOD_POSSESS_PET:
+ case SPELL_AURA_AOE_CHARM:
+ if(target->GetTypeId() == TYPEID_UNIT && ((Creature*)target)->isVehicle())
+ return false;
+ if(target->GetCharmerGUID())
+ return false;
+ if(int32 damage = CalculateDamage(eff, target))
+ if((int32)target->getLevel() > damage)
+ return false;
+ break;
+ }
+
+ //Do not do further checks for triggered spells
if(m_IsTriggeredSpell)
return true;
@@ -6115,7 +6392,7 @@ void Spell::CalculateDamageDoneForAllTargets()
if (target.missCondition==SPELL_MISS_NONE) // In case spell hit target, do all effect on that target
{
- target.damage += CalculateDamageDone(unit, mask, multiplier);
+ target.damage += CalculateDamageDone(unit, mask, multiplier);
target.crit = m_caster->isSpellCrit(unit, m_spellInfo, m_spellSchoolMask, m_attackType);
}
else if (target.missCondition == SPELL_MISS_REFLECT) // In case spell reflect from target, do all effect on caster (if hit)
diff --git a/src/game/Spell.h b/src/game/Spell.h
index 6aa539808df..b593bf79881 100644
--- a/src/game/Spell.h
+++ b/src/game/Spell.h
@@ -263,11 +263,11 @@ class Spell
void EffectQuestComplete(uint32 i);
void EffectCreateItem(uint32 i);
void EffectCreateItem2(uint32 i);
+ void EffectCreateRandomItem(uint32 i);
void EffectPersistentAA(uint32 i);
void EffectEnergize(uint32 i);
void EffectOpenLock(uint32 i);
void EffectSummonChangeItem(uint32 i);
- void EffectOpenSecretSafe(uint32 i);
void EffectProficiency(uint32 i);
void EffectApplyAreaAura(uint32 i);
void EffectSummonType(uint32 i);
@@ -319,6 +319,7 @@ class Spell
void EffectSelfResurrect(uint32 i);
void EffectSkinning(uint32 i);
void EffectCharge(uint32 i);
+ void EffectCharge2(uint32 i);
void EffectProspecting(uint32 i);
void EffectMilling(uint32 i);
void EffectRenamePet(uint32 i);
@@ -353,6 +354,7 @@ class Spell
void EffectActivateRune(uint32 i);
void EffectTitanGrip(uint32 i);
void EffectEnchantItemPrismatic(uint32 i);
+ void EffectPlayMusic(uint32 i);
typedef std::set<Aura *> UsedSpellMods;
@@ -389,7 +391,6 @@ class Spell
SpellCastResult CheckCasterAuras() const;
int32 CalculateDamage(uint8 i, Unit* target) { return m_caster->CalculateSpellDamage(m_spellInfo,i,m_currentBasePoints[i],target); }
- int32 CalculatePowerCost();
bool HaveTargetsForEffect(uint8 effect) const;
void Delayed();
@@ -438,6 +439,7 @@ class Spell
uint32 m_glyphIndex;
uint32 m_preCastSpell;
SpellCastTargets m_targets;
+ int8 m_comboPointGain;
UsedSpellMods m_appliedMods;
@@ -567,9 +569,10 @@ class Spell
SpellMissInfo reflectResult:8;
uint8 effectMask:8;
bool processed:1;
- bool alive:1;
+ bool alive:1;
+ bool crit:1;
+ bool scaleAura:1;
int32 damage;
- bool crit;
};
std::list<TargetInfo> m_UniqueTargetInfo;
uint8 m_needAliveTargetMask; // Mask req. alive targets
@@ -596,7 +599,7 @@ class Spell
void AddGOTarget(uint64 goGUID, uint32 effIndex);
void AddItemTarget(Item* target, uint32 effIndex);
void DoAllEffectOnTarget(TargetInfo *target);
- SpellMissInfo DoSpellHitOnUnit(Unit *unit, uint32 effectMask);
+ SpellMissInfo DoSpellHitOnUnit(Unit *unit, uint32 effectMask, bool scaleAura);
void DoTriggersOnSpellHit(Unit *unit);
void DoAllEffectOnTarget(GOTargetInfo *target);
void DoAllEffectOnTarget(ItemTargetInfo *target);
@@ -637,6 +640,7 @@ class Spell
uint32 m_customAttr;
bool m_skipCheck;
uint32 m_effectMask;
+ uint8 m_auraScaleMask;
#ifdef MAP_BASED_RAND_GEN
int32 irand(int32 min, int32 max) { return int32 (m_caster->GetMap()->mtRand.randInt(max - min)) + min; }
diff --git a/src/game/SpellAuraDefines.h b/src/game/SpellAuraDefines.h
index f38bd455896..1a116173135 100644
--- a/src/game/SpellAuraDefines.h
+++ b/src/game/SpellAuraDefines.h
@@ -250,7 +250,7 @@ enum AuraType
SPELL_AURA_IGNORE_COMBAT_RESULT = 202,
SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE = 203,
SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE = 204,
- SPELL_AURA_205 = 205, // school vunderability?
+ SPELL_AURA_MOD_SCHOOL_CRIT_DMG_TAKEN = 205,
SPELL_AURA_MOD_INCREASE_VEHICLE_FLIGHT_SPEED = 206,
SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED = 207,
SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED = 208,
@@ -266,7 +266,7 @@ enum AuraType
SPELL_AURA_HASTE_RANGED = 218,
SPELL_AURA_MOD_MANA_REGEN_FROM_STAT = 219,
SPELL_AURA_MOD_RATING_FROM_STAT = 220,
- SPELL_AURA_221 = 221,
+ SPELL_AURA_MOD_DETAUNT = 221,
SPELL_AURA_222 = 222,
SPELL_AURA_RAID_PROC_FROM_CHARGE = 223,
SPELL_AURA_224 = 224,
@@ -292,7 +292,7 @@ enum AuraType
SPELL_AURA_COMPREHEND_LANGUAGE = 244,
SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL = 245,
SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL_NOT_STACK = 246,
- SPELL_AURA_247 = 247,
+ SPELL_AURA_CLONE_CASTER = 247,
SPELL_AURA_MOD_COMBAT_RESULT_CHANCE = 248,
SPELL_AURA_CONVERT_RUNE = 249,
SPELL_AURA_MOD_INCREASE_HEALTH_2 = 250,
@@ -324,14 +324,14 @@ enum AuraType
SPELL_AURA_276 = 276, // Only "Test Mod Damage % Mechanic" spell, possible mod damage done
SPELL_AURA_MOD_MAX_AFFECTED_TARGETS = 277,
SPELL_AURA_MOD_DISARM_RANGED = 278,
- SPELL_AURA_279 = 279,
+ SPELL_AURA_INITIALIZE_IMAGES = 279,
SPELL_AURA_MOD_ARMOR_PENETRATION_PCT = 280,
SPELL_AURA_MOD_HONOR_GAIN_PCT = 281,
SPELL_AURA_MOD_BASE_HEALTH_PCT = 282,
SPELL_AURA_MOD_HEALING_RECEIVED = 283, // Possibly only for some spell family class spells
SPELL_AURA_LINKED = 284,
SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR = 285,
- SPELL_AURA_286,
+ SPELL_AURA_ABILITY_PERIODIC_CRIT = 286,
SPELL_AURA_DEFLECT_SPELLS,
SPELL_AURA_288,
SPELL_AURA_289,
diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp
index 9c54bf7e27b..c303e5cdb11 100644
--- a/src/game/SpellAuras.cpp
+++ b/src/game/SpellAuras.cpp
@@ -74,7 +74,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=
&Aura::HandleInvisibility, // 18 SPELL_AURA_MOD_INVISIBILITY
&Aura::HandleInvisibilityDetect, // 19 SPELL_AURA_MOD_INVISIBILITY_DETECTION
&Aura::HandleAuraModTotalHealthPercentRegen, // 20 SPELL_AURA_OBS_MOD_HEALTH
- &Aura::HandleAuraModTotalEnergyPercentRegen, // 21 SPELL_AURA_OBS_MOD_ENERGY
+ &Aura::HandleAuraModTotalEnergyPercentRegen, // 21 SPELL_AURA_OBS_MOD_ENERGY
&Aura::HandleAuraModResistance, // 22 SPELL_AURA_MOD_RESISTANCE
&Aura::HandlePeriodicTriggerSpell, // 23 SPELL_AURA_PERIODIC_TRIGGER_SPELL
&Aura::HandlePeriodicEnergize, // 24 SPELL_AURA_PERIODIC_ENERGIZE
@@ -223,7 +223,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=
&Aura::HandleAuraModRangedAttackPowerPercent, //167 SPELL_AURA_MOD_RANGED_ATTACK_POWER_PCT
&Aura::HandleNoImmediateEffect, //168 SPELL_AURA_MOD_DAMAGE_DONE_VERSUS implemented in Unit::SpellDamageBonus, Unit::MeleeDamageBonus
&Aura::HandleNoImmediateEffect, //169 SPELL_AURA_MOD_CRIT_PERCENT_VERSUS implemented in Unit::DealDamageBySchool, Unit::DoAttackDamage, Unit::SpellCriticalBonus
- &Aura::HandleNULL, //170 SPELL_AURA_DETECT_AMORE different spells that ignore transformation effects
+ &Aura::HandleNULL, //170 SPELL_AURA_DETECT_AMORE various spells that change visual of units for aura target (clientside?)
&Aura::HandleAuraModIncreaseSpeed, //171 SPELL_AURA_MOD_SPEED_NOT_STACK
&Aura::HandleAuraModIncreaseMountedSpeed, //172 SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK
&Aura::HandleUnused, //173 unused (3.0.8a) no spells, old SPELL_AURA_ALLOW_CHAMPION_SPELLS only for Proclaim Champion spell
@@ -236,7 +236,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=
&Aura::HandleNoImmediateEffect, //180 SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS implemented in Unit::SpellDamageBonus
&Aura::HandleUnused, //181 unused (3.0.8a) old SPELL_AURA_MOD_FLAT_SPELL_CRIT_DAMAGE_VERSUS
&Aura::HandleAuraModResistenceOfStatPercent, //182 SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT
- &Aura::HandleNULL, //183 SPELL_AURA_MOD_CRITICAL_THREAT only used in 28746
+ &Aura::HandleNULL, //183 SPELL_AURA_MOD_CRITICAL_THREAT only used in 28746 - miscvalue - spell school
&Aura::HandleNoImmediateEffect, //184 SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst
&Aura::HandleNoImmediateEffect, //185 SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst
&Aura::HandleNoImmediateEffect, //186 SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE implemented in Unit::MagicSpellHitResult
@@ -247,9 +247,9 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=
&Aura::HandleAuraModUseNormalSpeed, //191 SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED
&Aura::HandleModMeleeRangedSpeedPct, //192 SPELL_AURA_HASTE_MELEE
&Aura::HandleModCombatSpeedPct, //193 SPELL_AURA_MELEE_SLOW (in fact combat (any type attack) speed pct)
- &Aura::HandleNULL, //194 SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL implemented in Unit::CalcAbsorbResist
+ &Aura::HandleNoImmediateEffect, //194 SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL implemented in Unit::CalcAbsorbResist
&Aura::HandleNoImmediateEffect, //195 SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL implemented in Unit::CalcAbsorbResist
- &Aura::HandleNULL, //196 SPELL_AURA_MOD_COOLDOWN
+ &Aura::HandleNULL, //196 SPELL_AURA_MOD_COOLDOWN - flat mod of spell cooldowns
&Aura::HandleNoImmediateEffect, //197 SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE implemented in Unit::SpellCriticalBonus Unit::GetUnitCriticalChance
&Aura::HandleUnused, //198 unused (3.0.8a) old SPELL_AURA_MOD_ALL_WEAPON_SKILLS
&Aura::HandleNoImmediateEffect, //199 SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT implemented in Unit::MagicSpellHitResult
@@ -258,7 +258,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=
&Aura::HandleNoImmediateEffect, //202 SPELL_AURA_CANNOT_BE_DODGED implemented in Unit::RollPhysicalOutcomeAgainst
&Aura::HandleNoImmediateEffect, //203 SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE implemented in Unit::CalculateMeleeDamage and Unit::CalculateSpellDamage
&Aura::HandleNoImmediateEffect, //204 SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE implemented in Unit::CalculateMeleeDamage and Unit::CalculateSpellDamage
- &Aura::HandleNULL, //205 vulnerable to school dmg?
+ &Aura::HandleNULL, //205 SPELL_AURA_MOD_SCHOOL_CRIT_DMG_TAKEN
&Aura::HandleAuraModIncreaseFlightSpeed, //206 SPELL_AURA_MOD_INCREASE_VEHICLE_FLIGHT_SPEED
&Aura::HandleAuraModIncreaseFlightSpeed, //207 SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED
&Aura::HandleAuraModIncreaseFlightSpeed, //208 SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED
@@ -274,19 +274,19 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=
&Aura::HandleAuraModRangedHaste, //218 SPELL_AURA_HASTE_RANGED
&Aura::HandleModManaRegen, //219 SPELL_AURA_MOD_MANA_REGEN_FROM_STAT
&Aura::HandleModRatingFromStat, //220 SPELL_AURA_MOD_RATING_FROM_STAT
- &Aura::HandleNULL, //221 ignored
+ &Aura::HandleNULL, //221 SPELL_AURA_MOD_DETAUNT
&Aura::HandleUnused, //222 unused (3.0.8a) only for spell 44586 that not used in real spell cast
&Aura::HandleNoImmediateEffect, //223 SPELL_AURA_RAID_PROC_FROM_CHARGE
&Aura::HandleUnused, //224 unused (3.0.8a)
&Aura::HandleNoImmediateEffect, //225 SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE
&Aura::HandleAuraPeriodicDummy, //226 SPELL_AURA_PERIODIC_DUMMY
&Aura::HandlePeriodicTriggerSpellWithValue, //227 SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE
- &Aura::HandleNoImmediateEffect, //228 stealth detection
- &Aura::HandleNULL, //229 SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE
+ &Aura::HandleNoImmediateEffect, //228 SPELL_AURA_DETECT_STEALTH stealth detection
+ &Aura::HandleNoImmediateEffect, //229 SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE
&Aura::HandleAuraModIncreaseHealth, //230 SPELL_AURA_MOD_INCREASE_HEALTH_2
&Aura::HandleNoImmediateEffect, //231 SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE
&Aura::HandleNoImmediateEffect, //232 SPELL_AURA_MECHANIC_DURATION_MOD implement in Unit::CalculateSpellDuration
- &Aura::HandleNULL, //233 set model id to the one of the creature with id GetMiscValue()
+ &Aura::HandleUnused, //233 set model id to the one of the creature with id GetMiscValue() - clientside
&Aura::HandleNoImmediateEffect, //234 SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK implement in Unit::CalculateSpellDuration
&Aura::HandleNoImmediateEffect, //235 SPELL_AURA_MOD_DISPEL_RESIST implement in Unit::MagicSpellHitResult
&Aura::HandleAuraControlVehicle, //236 SPELL_AURA_CONTROL_VEHICLE
@@ -294,18 +294,18 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=
&Aura::HandleModSpellHealingPercentFromAttackPower, //238 SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER implemented in Unit::SpellBaseHealingBonus
&Aura::HandleAuraModScale, //239 SPELL_AURA_MOD_SCALE_2 only in Noggenfogger Elixir (16595) before 2.3.0 aura 61
&Aura::HandleAuraModExpertise, //240 SPELL_AURA_MOD_EXPERTISE
- &Aura::HandleForceMoveForward, //241 Forces the player to move forward
- &Aura::HandleUnused, //242 SPELL_AURA_MOD_SPELL_DAMAGE_FROM_HEALING
+ &Aura::HandleForceMoveForward, //241 SPELL_AURA_FORCE_MOVE_FORWARD Forces the player to move forward
+ &Aura::HandleUnused, //242 SPELL_AURA_MOD_SPELL_DAMAGE_FROM_HEALING - 2 test spells: 44183 and 44182
&Aura::HandleNULL, //243 faction reaction override spells
- &Aura::HandleComprehendLanguage, //244 Comprehend language
+ &Aura::HandleComprehendLanguage, //244 SPELL_AURA_COMPREHEND_LANGUAGE
&Aura::HandleNoImmediateEffect, //245 SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL
&Aura::HandleNoImmediateEffect, //246 SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL_NOT_STACK implemented in Spell::EffectApplyAura
- &Aura::HandleNULL, //247 target to become a clone of the caster
+ &Aura::HandleAuraCloneCaster, //247 SPELL_AURA_CLONE_CASTER
&Aura::HandleNoImmediateEffect, //248 SPELL_AURA_MOD_COMBAT_RESULT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst
&Aura::HandleAuraConvertRune, //249 SPELL_AURA_CONVERT_RUNE
&Aura::HandleAuraModIncreaseHealth, //250 SPELL_AURA_MOD_INCREASE_HEALTH_2
&Aura::HandleNoImmediateEffect, //251 SPELL_AURA_MOD_ENEMY_DODGE
- &Aura::HandleNULL, //252 haste all?
+ &Aura::HandleModCombatSpeedPct, //252 SPELL_AURA_252 Is there any difference between this and SPELL_AURA_MELEE_SLOW ? maybe not stacking mod?
&Aura::HandleNoImmediateEffect, //253 SPELL_AURA_MOD_BLOCK_CRIT_CHANCE implemented in Unit::isBlockCritical
&Aura::HandleAuraModDisarm, //254 SPELL_AURA_MOD_DISARM_OFFHAND
&Aura::HandleNoImmediateEffect, //255 SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT implemented in Unit::SpellDamageBonus
@@ -325,26 +325,26 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=
&Aura::HandleNoImmediateEffect, //269 SPELL_AURA_MOD_IGNORE_TARGET_RESIST implemented in Unit::CalcAbsorbResist and CalcArmorReducedDamage
&Aura::HandleNoImmediateEffect, //270 SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST implemented in Unit::CalcAbsorbResist and CalcArmorReducedDamage
&Aura::HandleNoImmediateEffect, //271 SPELL_AURA_MOD_DAMAGE_FROM_CASTER implemented in Unit::SpellDamageBonus
- &Aura::HandleNULL, //272 reduce spell cast time?
+ &Aura::HandleNULL, //272 unknown
&Aura::HandleUnused, //273 clientside
&Aura::HandleNoImmediateEffect, //274 SPELL_AURA_CONSUME_NO_AMMO implemented in spell::CalculateDamageDoneForAllTargets
&Aura::HandleNoImmediateEffect, //275 SPELL_AURA_MOD_IGNORE_SHAPESHIFT Use SpellClassMask for spell select
&Aura::HandleNULL, //276 mod damage % mechanic?
&Aura::HandleNoImmediateEffect, //277 SPELL_AURA_MOD_ABILITY_AFFECTED_TARGETS implemented in spell::settargetmap
&Aura::HandleAuraModDisarm, //278 SPELL_AURA_MOD_DISARM_RANGED disarm ranged weapon
- &Aura::HandleNULL, //279 visual effects? 58836 and 57507
+ &Aura::HandleAuraInitializeImages, //279 SPELL_AURA_INITIALIZE_IMAGES
&Aura::HandleModArmorPenetrationPct, //280 SPELL_AURA_MOD_ARMOR_PENETRATION_PCT
&Aura::HandleNoImmediateEffect, //281 SPELL_AURA_MOD_HONOR_GAIN_PCT implemented in Player::RewardHonor
&Aura::HandleAuraIncreaseBaseHealthPercent, //282 SPELL_AURA_INCREASE_BASE_HEALTH_PERCENT
&Aura::HandleNoImmediateEffect, //283 SPELL_AURA_MOD_HEALING_RECEIVED implemented in Unit::SpellHealingBonus
- &Aura::HandleUnused, //284 not used by any spells (3.08a)
+ &Aura::HandleNULL, //284 SPELL_AURA_LINKED - probably not sent to client
&Aura::HandleAuraModAttackPowerOfArmor, //285 SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR implemented in Player::UpdateAttackPowerAndDamage
- &Aura::HandleUnused, //286 not used by any spells (3.08a)
+ &Aura::HandleNoImmediateEffect, //286 SPELL_AURA_ABILITY_PERIODIC_CRIT implemented in AuraEffect::PeriodicTick
&Aura::HandleNoImmediateEffect, //287 SPELL_AURA_DEFLECT_SPELLS implemented in Unit::MagicSpellHitResult and Unit::MeleeSpellHitResult
- &Aura::HandleUnused, //288 not used by any spells (3.09) except 1 test spell.
+ &Aura::HandleUnused, //288 unused
&Aura::HandleUnused, //289 unused
- &Aura::HandleUnused, //290 unused
- &Aura::HandleUnused, //291 unused
+ &Aura::HandleNULL, //290 mod all critical hit chances?
+ &Aura::HandleNULL, //291 SPELL_AURA_MOD_XP_QUEST_PCT
&Aura::HandleNULL, //292 call stabled pet
&Aura::HandleNULL, //293 2 test spells
&Aura::HandleNULL //294 2 spells, possible prevent mana regen
@@ -354,7 +354,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=
Aura::Aura(SpellEntry const* spellproto, uint32 effMask, int32 *currentBasePoints, Unit *target, WorldObject *source, Unit *caster, Item* castItem) :
m_caster_guid(0), m_castItemGuid(castItem?castItem->GetGUID():0), m_target(target),
m_timeCla(0), m_removeMode(AURA_REMOVE_BY_DEFAULT), m_AuraDRGroup(DIMINISHING_NONE),
-m_auraSlot(MAX_AURAS), m_auraLevel(1), m_procCharges(0), m_stackAmount(1),m_auraStateMask(0), m_updated(false), m_isRemoved(false)
+m_auraSlot(MAX_AURAS), m_auraLevel(1), m_procCharges(0), m_stackAmount(1), m_updated(false), m_isRemoved(false)
{
assert(target);
@@ -369,8 +369,6 @@ m_auraSlot(MAX_AURAS), m_auraLevel(1), m_procCharges(0), m_stackAmount(1),m_aura
m_isPassive = IsPassiveSpell(GetId());
- m_auraStateMask = 0;
-
m_isSingleTargetAura = IsSingleTargetSpell(m_spellProto);
m_applyTime = time(NULL);
@@ -400,7 +398,7 @@ m_auraSlot(MAX_AURAS), m_auraLevel(1), m_procCharges(0), m_stackAmount(1),m_aura
{
// Glyph of Thorns
if (m_target == caster && m_spellProto->SpellFamilyName==SPELLFAMILY_DRUID && m_spellProto->SpellFamilyFlags[0] & 0x100)
- if (AuraEffect * aurEff = m_target->GetDummyAura(57862))
+ if (AuraEffect * aurEff = m_target->GetAuraEffect(57862, 0))
m_maxduration += aurEff->GetAmount() * MINUTE * IN_MILISECONDS;
modOwner->ApplySpellMod(GetId(), SPELLMOD_DURATION, m_maxduration);
@@ -486,6 +484,9 @@ m_target(parentAura->GetTarget()), m_tickNumber(0)
else
m_amount = m_currentBasePoints + 1;
+ if (int32 amount = CalculateCrowdControlAuraAmount(caster))
+ m_amount = amount;
+
if (!m_amount && castItem && castItem->GetItemSuffixFactor())
{
ItemRandomSuffixEntry const *item_rand_suffix = sItemRandomSuffixStore.LookupEntry(abs(castItem->GetItemRandomPropertyId()));
@@ -766,7 +767,8 @@ void AreaAuraEffect::Update(uint32 diff)
case AREA_AURA_PET:
{
if(Unit *owner = caster->GetCharmerOrOwner())
- targets.push_back(owner);
+ if (owner->IsWithinDistInMap(source, m_radius))
+ targets.push_back(owner);
break;
}
}
@@ -836,7 +838,7 @@ void AreaAuraEffect::Update(uint32 diff)
}
else if (!source->IsWithinDistInMap(m_target, m_radius))
{
- if (needFriendly)
+ if (needFriendly && source->isMoving())
{
m_removeTime -= diff;
if (m_removeTime < 0)
@@ -940,6 +942,191 @@ void Aura::ApplyAllModifiers(bool apply, bool Real)
m_partAuras[i]->ApplyModifier(apply, Real);
}
+void Aura::HandleAuraSpecificMods(bool apply)
+{
+ if (apply)
+ {
+ if(m_spellProto->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT)
+ {
+ // Icebound Fortitude
+ if (m_spellProto->SpellFamilyFlags[0] & 0x00100000)
+ {
+ Unit * caster = GetCaster();
+ if (caster && caster->GetTypeId() == TYPEID_PLAYER)
+ {
+ if(AuraEffect *auraeff = GetPartAura(2))
+ {
+ int32 value = int32((auraeff->GetAmount()*-1)-10);
+ uint32 defva = uint32(((Player*)caster)->GetSkillValue(SKILL_DEFENSE) + ((Player*)caster)->GetRatingBonusValue(CR_DEFENSE_SKILL));
+
+ if(defva > 400)
+ value += int32((defva-400)*0.15);
+
+ // Glyph of Icebound Fortitude
+ if (AuraEffect *auradummy = caster->GetAuraEffect(58625,0))
+ {
+ uint32 valmax = auradummy->GetAmount();
+ if(value < valmax)
+ value = valmax;
+ }
+ auraeff->SetAmount(-value);
+ }
+ }
+ }
+ }
+
+ if (m_spellProto->SpellFamilyName == SPELLFAMILY_MAGE)
+ {
+ if (m_spellProto->SpellFamilyFlags[0] & 0x00000001 && m_spellProto->SpellFamilyFlags[2] & 0x00000008)
+ {
+ // Glyph of Fireball
+ if (Unit * caster = GetCaster())
+ if (caster->HasAura(56368))
+ SetAuraDuration(0);
+ }
+ else if (m_spellProto->SpellFamilyFlags[0] & 0x00000020 && m_spellProto->SpellVisual[0] == 13)
+ {
+ // Glyph of Frostbolt
+ if (Unit * caster = GetCaster())
+ if (caster->HasAura(56370))
+ SetAuraDuration(0);
+ }
+ // Todo: This should be moved to similar function in spell::hit
+ else if (m_spellProto->SpellFamilyFlags[0] & 0x01000000)
+ {
+ Unit * caster = GetCaster();
+ if (!caster)
+ return;
+
+ // Polymorph Sound - Sheep && Penguin
+ if (m_spellProto->SpellIconID == 82 && m_spellProto->SpellVisual[0] == 12978)
+ {
+ // Glyph of the Penguin
+ if (caster->HasAura(52648))
+ caster->CastSpell(m_target,61635,true);
+ else
+ caster->CastSpell(m_target,61634,true);
+ }
+ }
+ }
+ }
+
+ // Aura Mastery Triggered Spell Handler
+ // If apply Concentration Aura -> trigger -> apply Aura Mastery Immunity
+ // If remove Concentration Aura -> trigger -> remove Aura Mastery Immunity
+ // If remove Aura Mastery -> trigger -> remove Aura Mastery Immunity
+ if (m_spellProto->Id == 19746 || m_spellProto->Id == 31821)
+ {
+ if (GetCasterGUID() != m_target->GetGUID())
+ return;
+ if (apply)
+ {
+ if ((m_spellProto->Id == 31821 && m_target->HasAura(19746, GetCasterGUID())) || (m_spellProto->Id == 19746 && m_target->HasAura(31821)))
+ {
+ m_target->CastSpell(m_target,64364,true);
+ return;
+ }
+ }
+ else
+ {
+ m_target->RemoveAurasDueToSpell(64364, GetCasterGUID());
+ return;
+ }
+ }
+
+ if (GetSpellSpecific(m_spellProto->Id) == SPELL_PRESENCE)
+ {
+ AuraEffect *bloodPresenceAura=0; // healing by damage done
+ AuraEffect *frostPresenceAura=0; // increased health
+ AuraEffect *unholyPresenceAura=0; // increased movement speed, faster rune recovery
+
+ // Improved Presences
+ Unit::AuraEffectList const& vDummyAuras = m_target->GetAurasByType(SPELL_AURA_DUMMY);
+ for(Unit::AuraEffectList::const_iterator itr = vDummyAuras.begin(); itr != vDummyAuras.end(); ++itr)
+ {
+ switch((*itr)->GetId())
+ {
+ // Improved Blood Presence
+ case 50365:
+ case 50371:
+ {
+ bloodPresenceAura = (*itr);
+ break;
+ }
+ // Improved Frost Presence
+ case 50384:
+ case 50385:
+ {
+ frostPresenceAura = (*itr);
+ break;
+ }
+ // Improved Unholy Presence
+ case 50391:
+ case 50392:
+ {
+ unholyPresenceAura = (*itr);
+ break;
+ }
+ }
+ }
+
+ uint32 presence=GetId();
+ if (apply)
+ {
+ // Blood Presence bonus
+ if (presence == SPELL_ID_BLOOD_PRESENCE)
+ m_target->CastSpell(m_target,63611,true);
+ else if (bloodPresenceAura)
+ {
+ int32 basePoints1=bloodPresenceAura->GetAmount();
+ m_target->CastCustomSpell(m_target,63611,NULL,&basePoints1,NULL,true,0,bloodPresenceAura);
+ }
+ // Frost Presence bonus
+ if (presence == SPELL_ID_FROST_PRESENCE)
+ m_target->CastSpell(m_target,61261,true);
+ else if (frostPresenceAura)
+ {
+ int32 basePoints0=frostPresenceAura->GetAmount();
+ m_target->CastCustomSpell(m_target,61261,&basePoints0,NULL,NULL,true,0,frostPresenceAura);
+ }
+ // Unholy Presence bonus
+ if (presence == SPELL_ID_UNHOLY_PRESENCE)
+ {
+ if(unholyPresenceAura)
+ {
+ // Not listed as any effect, only base points set
+ int32 basePoints0 = unholyPresenceAura->GetSpellProto()->EffectBasePoints[1];
+ //m_target->CastCustomSpell(m_target,63622,&basePoints0 ,NULL,NULL,true,0,unholyPresenceAura);
+ m_target->CastCustomSpell(m_target,65095,&basePoints0 ,NULL,NULL,true,0,unholyPresenceAura);
+ }
+ m_target->CastSpell(m_target,49772, true);
+ }
+ else if (unholyPresenceAura)
+ {
+ int32 basePoints0=unholyPresenceAura->GetAmount();
+ m_target->CastCustomSpell(m_target,49772,&basePoints0,NULL,NULL,true,0,unholyPresenceAura);
+ }
+ }
+ else
+ {
+ // Remove passive auras
+ if (presence == SPELL_ID_BLOOD_PRESENCE || bloodPresenceAura)
+ m_target->RemoveAurasDueToSpell(63611);
+ if (presence == SPELL_ID_FROST_PRESENCE || frostPresenceAura)
+ m_target->RemoveAurasDueToSpell(61261);
+ if (presence == SPELL_ID_UNHOLY_PRESENCE || unholyPresenceAura)
+ {
+ if(presence == SPELL_ID_UNHOLY_PRESENCE && unholyPresenceAura)
+ {
+ //m_target->RemoveAurasDueToSpell(63622);
+ m_target->RemoveAurasDueToSpell(65095);
+ }
+ m_target->RemoveAurasDueToSpell(49772);
+ }
+ }
+ }
+}
+
void Aura::SendAuraUpdate()
{
if (m_auraSlot>=MAX_AURAS)
@@ -960,7 +1147,7 @@ void Aura::SendAuraUpdate()
data << uint32(GetId());
data << uint8(m_auraFlags);
data << uint8(m_auraLevel);
- data << uint8(m_stackAmount > 1 ? m_stackAmount : m_procCharges);
+ data << uint8(m_stackAmount > 1 ? m_stackAmount : (m_procCharges) ? m_procCharges : 1);
if(!(m_auraFlags & AFLAG_CASTER))
{
@@ -1096,57 +1283,7 @@ void Aura::_AddAura()
}
}
- //*****************************************************
- // Update target aura state flag
- //*****************************************************
-
- // Update Seals information
- if (IsSealSpell(m_spellProto))
- SetAuraState(AURA_STATE_JUDGEMENT);
-
- // Conflagrate aura state on Immolate or Shadowflame
- if (m_spellProto->SpellFamilyName == SPELLFAMILY_WARLOCK && (m_spellProto->SpellFamilyFlags[0] & 4
- || m_spellProto->SpellFamilyFlags[2] & 2))
- SetAuraState(AURA_STATE_IMMOLATE);
-
- // Faerie Fire (druid versions)
- if (m_spellProto->SpellFamilyName == SPELLFAMILY_DRUID && m_spellProto->SpellFamilyFlags[0] & 0x400)
- SetAuraState(AURA_STATE_FAERIE_FIRE);
-
- // Victorious
- if (m_spellProto->SpellFamilyName == SPELLFAMILY_WARRIOR && m_spellProto->SpellFamilyFlags[1] & 0x00040000)
- SetAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH);
-
- // Swiftmend state on Regrowth & Rejuvenation
- if (m_spellProto->SpellFamilyName == SPELLFAMILY_DRUID && m_spellProto->SpellFamilyFlags[0] & 0x50 )
- SetAuraState(AURA_STATE_SWIFTMEND);
-
- // Deadly poison aura state
- if(m_spellProto->SpellFamilyName == SPELLFAMILY_ROGUE && m_spellProto->SpellFamilyFlags[0] & 0x10000)
- SetAuraState(AURA_STATE_DEADLY_POISON);
-
- // Enrage aura state
- if(m_spellProto->Dispel == DISPEL_ENRAGE)
- SetAuraState(AURA_STATE_ENRAGE);
-
- // Bleeding aura state
- if (GetAllSpellMechanicMask(m_spellProto) & 1<<MECHANIC_BLEED)
- SetAuraState(AURA_STATE_BLEEDING);
-
- if(GetSpellSchoolMask(m_spellProto) & SPELL_SCHOOL_MASK_FROST)
- {
- for (uint8 i = 0;i<MAX_SPELL_EFFECTS;++i)
- {
- if (m_spellProto->EffectApplyAuraName[i]==SPELL_AURA_MOD_STUN
- || m_spellProto->EffectApplyAuraName[i]==SPELL_AURA_MOD_ROOT)
- {
- SetAuraState(AURA_STATE_FROZEN);
- break;
- }
- }
- }
-
- m_target->ApplyModFlag(UNIT_FIELD_AURASTATE, GetAuraStateMask(), true);
+ HandleAuraSpecificMods(true);
}
bool Aura::SetPartAura(AuraEffect* aurEff, uint8 effIndex)
@@ -1192,22 +1329,6 @@ void Aura::_RemoveAura()
if (getDiminishGroup() != DIMINISHING_NONE )
m_target->ApplyDiminishingAura(getDiminishGroup(),false);
- // Check needed only if aura applies aurastate
- if(GetAuraStateMask())
- {
- uint32 foundMask = 0;
- Unit::AuraMap& Auras = m_target->GetAuras();
- // Get mask of all aurastates from remaining auras
- for(Unit::AuraMap::iterator i = Auras.begin(); i != Auras.end(); ++i)
- {
- foundMask|=(*i).second->GetAuraStateMask();
- }
- // Remove only aurastates which were not found
- foundMask = GetAuraStateMask() &~foundMask;
- if (foundMask)
- m_target->ApplyModFlag(UNIT_FIELD_AURASTATE, foundMask, false);
- }
-
// since now aura cannot apply/remove it's modifiers
m_isRemoved = true;
// disable client server communication for removed aura
@@ -1262,23 +1383,25 @@ void Aura::_RemoveAura()
if (procEx)
{
uint32 ProcCaster, ProcVictim;
- if (IsPositiveSpell(GetId()))
+ if (IsPositive())
{
- ProcCaster = PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL;
- ProcVictim = PROC_FLAG_TAKEN_POSITIVE_SPELL;
+ ProcCaster = PROC_FLAG_SUCCESSFUL_POSITIVE_MAGIC_SPELL | PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL_HIT;
+ ProcVictim = PROC_FLAG_TAKEN_POSITIVE_MAGIC_SPELL | PROC_FLAG_TAKEN_POSITIVE_SPELL;
}
else
{
- ProcCaster = PROC_FLAG_SUCCESSFUL_NEGATIVE_SPELL_HIT;
- ProcVictim = PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT;
+ ProcCaster = PROC_FLAG_SUCCESSFUL_NEGATIVE_MAGIC_SPELL | PROC_FLAG_SUCCESSFUL_NEGATIVE_SPELL_HIT;
+ ProcVictim = PROC_FLAG_TAKEN_NEGATIVE_MAGIC_SPELL | PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT;
}
caster->ProcDamageAndSpell(m_target,ProcCaster, ProcVictim, procEx, m_procDamage, BASE_ATTACK, m_spellProto);
}
}
+ HandleAuraSpecificMods(false);
}
void Aura::SetStackAmount(uint8 stackAmount, bool applied)
{
+ bool refresh = stackAmount >= m_stackAmount;
if (stackAmount != m_stackAmount)
{
m_stackAmount = stackAmount;
@@ -1290,7 +1413,11 @@ void Aura::SetStackAmount(uint8 stackAmount, bool applied)
}
}
}
- RefreshAura();
+
+ if (refresh)
+ RefreshAura();
+ else
+ SendAuraUpdate();
}
bool Aura::modStackAmount(int32 num)
@@ -1398,6 +1525,7 @@ void AuraEffect::HandleShapeshiftBoosts(bool apply)
{
uint32 spellId = 0;
uint32 spellId2 = 0;
+ uint32 spellId3 = 0;
uint32 HotWSpellId = 0;
switch(GetMiscValue())
@@ -1407,8 +1535,7 @@ void AuraEffect::HandleShapeshiftBoosts(bool apply)
HotWSpellId = 24900;
break;
case FORM_TREE:
- spellId = 5420;
- spellId2 = 34123;
+ spellId = 34123;
break;
case FORM_TRAVEL:
spellId = 5419;
@@ -1456,14 +1583,15 @@ void AuraEffect::HandleShapeshiftBoosts(bool apply)
spellId = 27792;
spellId2 = 27795; // must be second, this important at aura remove to prevent to early iterator invalidation.
break;
+ case FORM_SHADOW:
+ spellId = 49868;
+ break;
case FORM_GHOUL:
case FORM_GHOSTWOLF:
case FORM_AMBIENT:
- case FORM_SHADOW:
case FORM_STEALTH:
case FORM_CREATURECAT:
case FORM_CREATUREBEAR:
- spellId = 0;
break;
}
@@ -1471,8 +1599,20 @@ void AuraEffect::HandleShapeshiftBoosts(bool apply)
if(apply)
{
- if (spellId) m_target->CastSpell(m_target, spellId, true, NULL, this );
- if (spellId2) m_target->CastSpell(m_target, spellId2, true, NULL, this);
+ // Remove cooldown of spells triggered on stance change - they may share cooldown with stance spell
+ if (spellId)
+ {
+ if(m_target->GetTypeId() == TYPEID_PLAYER)
+ ((Player *)m_target)->RemoveSpellCooldown(spellId);
+ m_target->CastSpell(m_target, spellId, true, NULL, this );
+ }
+
+ if (spellId2)
+ {
+ if(m_target->GetTypeId() == TYPEID_PLAYER)
+ ((Player *)m_target)->RemoveSpellCooldown(spellId2);
+ m_target->CastSpell(m_target, spellId2, true, NULL, this);
+ }
if(m_target->GetTypeId() == TYPEID_PLAYER)
{
@@ -1510,12 +1650,71 @@ void AuraEffect::HandleShapeshiftBoosts(bool apply)
}
}
}
+ switch(GetMiscValue())
+ {
+ case FORM_CAT:
+ // Nurturing Instinct
+ if (AuraEffect const * aurEff = m_target->GetAuraEffect(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT, SPELLFAMILY_DRUID, 2254,0))
+ {
+ uint32 spellId = 0;
+ switch (aurEff->GetId())
+ {
+ case 33872:
+ spellId = 47179;
+ break;
+ case 33873:
+ spellId = 47180;
+ break;
+ }
+ m_target->CastSpell(m_target, spellId, true, NULL, this);
+ }
+ // Master Shapeshifter - Cat
+ if (AuraEffect const * aurEff = m_target->GetDummyAura(SPELLFAMILY_GENERIC, 2851, 0))
+ {
+ int32 bp = aurEff->GetAmount();
+ m_target->CastCustomSpell(m_target, 48420, &bp, NULL, NULL, true);
+ }
+ break;
+ case FORM_DIREBEAR:
+ case FORM_BEAR:
+ // Master Shapeshifter - Bear
+ if (AuraEffect const * aurEff = m_target->GetDummyAura(SPELLFAMILY_GENERIC, 2851, 0))
+ {
+ int32 bp = aurEff->GetAmount();
+ m_target->CastCustomSpell(m_target, 48418, &bp, NULL, NULL, true);
+ }
+ // Survival of the Fittest
+ if (AuraEffect const * aurEff = m_target->GetAuraEffect(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE,SPELLFAMILY_DRUID, 961, 0))
+ {
+ int32 bp = m_target->CalculateSpellDamage(aurEff->GetSpellProto(),2,aurEff->GetSpellProto()->EffectBasePoints[2],m_target);
+ m_target->CastCustomSpell(m_target, 62069,&bp, NULL, NULL, true, 0, this);
+ }
+ break;
+ case FORM_MOONKIN:
+ // Master Shapeshifter - Moonkin
+ if (AuraEffect const * aurEff = m_target->GetDummyAura(SPELLFAMILY_GENERIC, 2851, 0))
+ {
+ int32 bp = aurEff->GetAmount();
+ m_target->CastCustomSpell(m_target, 48421, &bp, NULL, NULL, true);
+ }
+ break;
+ // Master Shapeshifter - Tree of Life
+ case FORM_TREE:
+ if (AuraEffect const * aurEff = m_target->GetDummyAura(SPELLFAMILY_GENERIC, 2851, 0))
+ {
+ int32 bp = aurEff->GetAmount();
+ m_target->CastCustomSpell(m_target, 48422, &bp, NULL, NULL, true);
+ }
+ break;
+ }
}
}
else
{
- m_target->RemoveAurasDueToSpell(spellId);
- m_target->RemoveAurasDueToSpell(spellId2);
+ if (spellId)
+ m_target->RemoveAurasDueToSpell(spellId);
+ if (spellId2)
+ m_target->RemoveAurasDueToSpell(spellId2);
Unit::AuraMap& tAuras = m_target->GetAuras();
for (Unit::AuraMap::iterator itr = tAuras.begin(); itr != tAuras.end();)
@@ -1540,12 +1739,8 @@ bool AuraEffect::isAffectedOnSpell(SpellEntry const *spell) const
if (spell->SpellFamilyName != m_spellProto->SpellFamilyName)
return false;
- // Check EffectClassMask and Spell_Affect table
- flag96 const *spellAffect = spellmgr.GetSpellAffect(GetId(), m_effIndex);
- if (!spellAffect)
- spellAffect = &m_spellProto->EffectSpellClassMask[m_effIndex];
-
- if (*spellAffect & spell->SpellFamilyFlags)
+ // Check EffectClassMask
+ if (m_spellProto->EffectSpellClassMask[m_effIndex] & spell->SpellFamilyFlags)
return true;
return false;
}
@@ -1590,10 +1785,7 @@ void AuraEffect::HandleAddModifier(bool apply, bool Real, bool changeAmount)
mod->type = SpellModType(m_auraName); // SpellModType value == spell aura types
mod->spellId = GetId();
- flag96 const *spellAffect = spellmgr.GetSpellAffect(GetId(), m_effIndex);
- if (!spellAffect)
- spellAffect = &m_spellProto->EffectSpellClassMask[m_effIndex];
- mod->mask = *spellAffect;
+ mod->mask = m_spellProto->EffectSpellClassMask[m_effIndex];
mod->charges = GetParentAura()->GetAuraCharges();
m_spellmod = mod;
@@ -1707,43 +1899,13 @@ void AuraEffect::TriggerSpell()
((Player*)caster)->ApplyEnchantment(item,TEMP_ENCHANTMENT_SLOT,true);
return;
}
-// // Periodic Mana Burn
-// case 812: break;
-// // Polymorphic Ray
-// case 6965: break;
-// // Fire Nova (1-7 ranks)
-// case 8350:
-// case 8508:
-// case 8509:
-// case 11312:
-// case 11313:
-// case 25540:
-// case 25544:
-// break;
// Thaumaturgy Channel
case 9712: trigger_spell_id = 21029; break;
-// // Egan's Blaster
-// case 17368: break;
-// // Haunted
-// case 18347: break;
-// // Ranshalla Waiting
-// case 18953: break;
-// // Inferno
-// case 19695: break;
-// // Frostwolf Muzzle DND
-// case 21794: break;
-// // Alterac Ram Collar DND
-// case 21866: break;
-// // Celebras Waiting
-// case 21916: break;
- // Brood Affliction: Bronze
case 23170:
{
m_target->CastSpell(m_target, 23171, true, 0, this);
return;
}
-// // Mark of Frost
-// case 23184: break;
// Restoration
case 23493:
{
@@ -1758,46 +1920,6 @@ void AuraEffect::TriggerSpell()
}
return;
}
-// // Stoneclaw Totem Passive TEST
-// case 23792: break;
-// // Axe Flurry
-// case 24018: break;
-// // Mark of Arlokk
-// case 24210: break;
-// // Restoration
-// case 24379: break;
-// // Happy Pet
-// case 24716: break;
-// // Dream Fog
-// case 24780: break;
-// // Cannon Prep
-// case 24832: break;
-// // Shadow Bolt Whirl
-// case 24834: break;
-// // Stink Trap
-// case 24918: break;
-// // Mark of Nature
-// case 25041: break;
-// // Agro Drones
-// case 25152: break;
-// // Consume
-// case 25371: break;
-// // Pain Spike
-// case 25572: break;
-// // Rotate 360
-// case 26009: break;
-// // Rotate -360
-// case 26136: break;
-// // Consume
-// case 26196: break;
-// // Berserk
-// case 26615: break;
-// // Defile
-// case 27177: break;
-// // Teleport: IF/UC
-// case 27601: break;
-// // Five Fat Finger Exploding Heart Technique
-// case 27673: break;
// Nitrous Boost
case 27746:
{
@@ -1811,8 +1933,6 @@ void AuraEffect::TriggerSpell()
return;
}
} break;
-// // Steam Tank Passive
-// case 27747: break;
// Frost Blast
case 27808:
caster->CastCustomSpell(29879, SPELLVALUE_BASE_POINT0, (float)m_target->GetMaxHealth()*0.26f, m_target, true, NULL, this);
@@ -1825,49 +1945,13 @@ void AuraEffect::TriggerSpell()
m_target->CastCustomSpell(27820, SPELLVALUE_BASE_POINT0, -mana*4, NULL, true, NULL, this, caster->GetGUID());
}
return;
-// // Controller Timer
-// case 28095: break;
-// // Stalagg Chain
-// case 28096: break;
-// // Stalagg Tesla Passive
-// case 28097: break;
-// // Feugen Tesla Passive
-// case 28109: break;
-// // Feugen Chain
-// case 28111: break;
-// // Mark of Didier
-// case 28114: break;
-// // Communique Timer, camp
-// case 28346: break;
-// // Icebolt
-// case 28522: break;
-// // Silithyst
-// case 29519: break;
// Inoculate Nestlewood Owlkin
case 29528:
if(target->GetTypeId()!=TYPEID_UNIT)// prevent error reports in case ignored player target
return;
break;
-// // Overload
-// case 29768: break;
-// // Return Fire
-// case 29788: break;
-// // Return Fire
-// case 29793: break;
-// // Return Fire
-// case 29794: break;
-// // Guardian of Icecrown Passive
-// case 29897: break;
// Feed Captured Animal
case 29917: trigger_spell_id = 29916; break;
-// // Flame Wreath
-// case 29946: break;
-// // Flame Wreath
-// case 29947: break;
-// // Mind Exhaustion Passive
-// case 30025: break;
-// // Nether Beam - Serenity
-// case 30401: break;
// Extract Gas
case 30427:
{
@@ -1890,19 +1974,6 @@ void AuraEffect::TriggerSpell()
}
// Quake
case 30576: trigger_spell_id = 30571; break;
-// // Burning Maul
-// case 30598: break;
-// // Regeneration
-// case 30799:
-// case 30800:
-// case 30801:
-// break;
-// // Despawn Self - Smoke cloud
-// case 31269: break;
-// // Time Rift Periodic
-// case 31320: break;
-// // Corrupt Medivh
-// case 31326: break;
// Doom
case 31347:
{
@@ -1917,20 +1988,6 @@ void AuraEffect::TriggerSpell()
caster->SummonCreature(17870, 0, 0, 0, caster->GetOrientation(), TEMPSUMMON_DEAD_DESPAWN, 0);
return;
}
-// // Bloodmyst Tesla
-// case 31611: break;
-// // Doomfire
-// case 31944: break;
-// // Teleport Test
-// case 32236: break;
-// // Earthquake
-// case 32686: break;
-// // Possess
-// case 33401: break;
-// // Draw Shadows
-// case 33563: break;
-// // Murmur's Touch
-// case 33711: break;
// Flame Quills
case 34229:
{
@@ -1941,82 +1998,8 @@ void AuraEffect::TriggerSpell()
caster->CastSpell(m_target,spell_id,true, NULL, this);
return;
}
-// // Gravity Lapse
-// case 34480: break;
-// // Tornado
-// case 34683: break;
-// // Frostbite Rotate
-// case 34748: break;
-// // Arcane Flurry
-// case 34821: break;
-// // Interrupt Shutdown
-// case 35016: break;
-// // Interrupt Shutdown
-// case 35176: break;
-// // Inferno
-// case 35268: break;
-// // Salaadin's Tesla
-// case 35515: break;
-// // Ethereal Channel (Red)
-// case 35518: break;
-// // Nether Vapor
-// case 35879: break;
-// // Dark Portal Storm
-// case 36018: break;
-// // Burning Maul
-// case 36056: break;
-// // Living Grove Defender Lifespan
-// case 36061: break;
-// // Professor Dabiri Talks
-// case 36064: break;
-// // Kael Gaining Power
-// case 36091: break;
-// // They Must Burn Bomb Aura
-// case 36344: break;
-// // They Must Burn Bomb Aura (self)
-// case 36350: break;
-// // Stolen Ravenous Ravager Egg
-// case 36401: break;
-// // Activated Cannon
-// case 36410: break;
-// // Stolen Ravenous Ravager Egg
-// case 36418: break;
-// // Enchanted Weapons
-// case 36510: break;
-// // Cursed Scarab Periodic
-// case 36556: break;
-// // Cursed Scarab Despawn Periodic
-// case 36561: break;
-// // Vision Guide
-// case 36573: break;
-// // Cannon Charging (platform)
-// case 36785: break;
-// // Cannon Charging (self)
-// case 36860: break;
// Remote Toy
case 37027: trigger_spell_id = 37029; break;
-// // Mark of Death
-// case 37125: break;
-// // Arcane Flurry
-// case 37268: break;
-// // Spout
-// case 37429: break;
-// // Spout
-// case 37430: break;
-// // Karazhan - Chess NPC AI, Snapshot timer
-// case 37440: break;
-// // Karazhan - Chess NPC AI, action timer
-// case 37504: break;
-// // Karazhan - Chess: Is Square OCCUPIED aura (DND)
-// case 39400: break;
-// // Banish
-// case 37546: break;
-// // Shriveling Gaze
-// case 37589: break;
-// // Fake Aggro Radius (2 yd)
-// case 37815: break;
-// // Corrupt Medivh
-// case 37853: break;
// Eye of Grillok
case 38495:
{
@@ -2036,93 +2019,18 @@ void AuraEffect::TriggerSpell()
creatureTarget->ForcedDespawn();
return;
}
-// // Magic Sucker Device timer
-// case 38672: break;
-// // Tomb Guarding Charging
-// case 38751: break;
-// // Murmur's Touch
-// case 38794: break;
-// // Activate Nether-wraith Beacon (31742 Nether-wraith Beacon item)
-// case 39105: break;
-// // Drain World Tree Visual
-// case 39140: break;
-// // Quest - Dustin's Undead Dragon Visual aura
-// case 39259: break;
-// // Hellfire - The Exorcism, Jules releases darkness, aura
-// case 39306: break;
-// // Inferno
-// case 39346: break;
-// // Enchanted Weapons
-// case 39489: break;
-// // Shadow Bolt Whirl
-// case 39630: break;
-// // Shadow Bolt Whirl
-// case 39634: break;
-// // Shadow Inferno
-// case 39645: break;
// Tear of Azzinoth Summon Channel - it's not really supposed to do anything,and this only prevents the console spam
case 39857: trigger_spell_id = 39856; break;
-// // Soulgrinder Ritual Visual (Smashed)
-// case 39974: break;
-// // Simon Game Pre-game timer
-// case 40041: break;
-// // Knockdown Fel Cannon: The Aggro Check Aura
-// case 40113: break;
-// // Spirit Lance
-// case 40157: break;
-// // Demon Transform 2
-// case 40398: break;
-// // Demon Transform 1
-// case 40511: break;
-// // Ancient Flames
-// case 40657: break;
-// // Ethereal Ring Cannon: Cannon Aura
-// case 40734: break;
-// // Cage Trap
-// case 40760: break;
-// // Random Periodic
-// case 40867: break;
-// // Prismatic Shield
-// case 40879: break;
// Aura of Desire
case 41350:
{
- Unit::AuraEffectList const& mMod = m_target->GetAurasByType(SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT);
- for(Unit::AuraEffectList::const_iterator i = mMod.begin(); i != mMod.end(); ++i)
- {
- if ((*i)->GetId() == 41350)
- {
- (*i)->ApplyModifier(false);
- (*i)->SetAmount((*i)->GetAmount()-5);
- (*i)->ApplyModifier(true);
- break;
- }
- }
- }break;
-// // Dementia
-// case 41404: break;
-// // Chaos Form
-// case 41629: break;
-// // Alert Drums
-// case 42177: break;
-// // Spout
-// case 42581: break;
-// // Spout
-// case 42582: break;
-// // Return to the Spirit Realm
-// case 44035: break;
-// // Curse of Boundless Agony
-// case 45050: break;
-// // Earthquake
-// case 46240: break;
- // Personalized Weather
+ AuraEffect * aurEff = GetParentAura()->GetPartAura(1);
+ aurEff->ApplyModifier(false, false, true);
+ aurEff->SetAmount(aurEff->GetAmount()-5);
+ aurEff->ApplyModifier(true, false, true);
+ break;
+ }
case 46736: trigger_spell_id = 46737; break;
-// // Stay Submerged
-// case 46981: break;
-// // Dragonblight Ram
-// case 47015: break;
-// // Party G.R.E.N.A.D.E.
-// case 51510: break;
default:
break;
}
@@ -2141,32 +2049,6 @@ void AuraEffect::TriggerSpell()
}
break;
}
-// case SPELLFAMILY_WARRIOR:
-// {
-// switch(auraId)
-// {
-// // Wild Magic
-// case 23410: break;
-// // Corrupted Totems
-// case 23425: break;
-// default:
-// break;
-// }
-// break;
-// }
-// case SPELLFAMILY_PRIEST:
-// {
-// switch(auraId)
-// {
-// // Blue Beam
-// case 32930: break;
-// // Fury of the Dreghood Elders
-// case 35460: break;
-// default:
-// break;
-// }
- // break;
- // }
case SPELLFAMILY_DRUID:
{
switch(auraId)
@@ -2177,8 +2059,6 @@ void AuraEffect::TriggerSpell()
return;
// Frenzied Regeneration
case 22842:
- case 22895:
- case 22896:
case 26999:
{
int32 LifePerRage = GetAmount();
@@ -2196,42 +2076,42 @@ void AuraEffect::TriggerSpell()
}
break;
}
+ case SPELLFAMILY_HUNTER:
+ {
+ switch (auraId)
+ {
+ // Sniper training
+ case 53302:
+ case 53303:
+ case 53304:
+ if (m_target->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ if (((Player*)m_target)->isMoving())
+ {
+ m_amount = m_target->CalculateSpellDamage(m_spellProto,m_effIndex,m_currentBasePoints,m_target);
+ return;
+ }
+
+ // We are standing at the moment
+ if (m_amount > 0)
+ {
+ --m_amount;
+ return;
+ }
-// case SPELLFAMILY_HUNTER:
-// {
-// switch(auraId)
-// {
-// //Frost Trap Aura
-// case 13810:
-// return;
-// //Rizzle's Frost Trap
-// case 39900:
-// return;
-// // Tame spells
-// case 19597: // Tame Ice Claw Bear
-// case 19676: // Tame Snow Leopard
-// case 19677: // Tame Large Crag Boar
-// case 19678: // Tame Adult Plainstrider
-// case 19679: // Tame Prairie Stalker
-// case 19680: // Tame Swoop
-// case 19681: // Tame Dire Mottled Boar
-// case 19682: // Tame Surf Crawler
-// case 19683: // Tame Armored Scorpid
-// case 19684: // Tame Webwood Lurker
-// case 19685: // Tame Nightsaber Stalker
-// case 19686: // Tame Strigid Screecher
-// case 30100: // Tame Crazed Dragonhawk
-// case 30103: // Tame Elder Springpaw
-// case 30104: // Tame Mistbat
-// case 30647: // Tame Barbed Crawler
-// case 30648: // Tame Greater Timberstrider
-// case 30652: // Tame Nightstalker
-// return;
-// default:
-// break;
-// }
-// break;
-// }
+ trigger_spell_id = 64418 + auraId - 53302;
+
+ // If aura is active - no need to continue
+ if (target->HasAura(trigger_spell_id))
+ return;
+
+ break;
+ default:
+ break;
+ }
+ break;
+ }
case SPELLFAMILY_SHAMAN:
{
switch(auraId)
@@ -2240,15 +2120,8 @@ void AuraEffect::TriggerSpell()
case 28820:
{
// Need remove self if Lightning Shield not active
- Unit::AuraMap const& auras = target->GetAuras();
- for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
- {
- SpellEntry const* spell = itr->second->GetSpellProto();
- if( spell->SpellFamilyName == SPELLFAMILY_SHAMAN &&
- spell->SpellFamilyFlags[0] & 0x400)
- return;
- }
- target->RemoveAurasDueToSpell(28820);
+ if (!target->GetAura(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN,0x400))
+ target->RemoveAurasDueToSpell(28820);
return;
}
// Totemic Mastery (Skyshatter Regalia (Shaman Tier 6) - bonus)
@@ -2287,43 +2160,6 @@ void AuraEffect::TriggerSpell()
// Spell exist but require custom code
switch(auraId)
{
- // Curse of Idiocy
- case 1010:
- {
- // TODO: spell casted by result in correct way mostly
- // BUT:
- // 1) target show casting at each triggered cast: target don't must show casting animation for any triggered spell
- // but must show affect apply like item casting
- // 2) maybe aura must be replace by new with accumulative stat mods instead stacking
-
- // prevent cast by triggered auras
- if(GetCasterGUID() == m_target->GetGUID())
- return;
-
- // stop triggering after each affected stats lost > 90
- int32 intellectLoss = 0;
- int32 spiritLoss = 0;
-
- Unit::AuraEffectList const& mModStat = m_target->GetAurasByType(SPELL_AURA_MOD_STAT);
- for(Unit::AuraEffectList::const_iterator i = mModStat.begin(); i != mModStat.end(); ++i)
- {
- if ((*i)->GetId() == 1010)
- {
- switch((*i)->GetMiscValue())
- {
- case STAT_INTELLECT: intellectLoss += (*i)->GetAmount(); break;
- case STAT_SPIRIT: spiritLoss += (*i)->GetAmount(); break;
- default: break;
- }
- }
- }
-
- if(intellectLoss <= -90 && spiritLoss <= -90)
- return;
-
- caster = target;
- break;
- }
// Mana Tide
case 16191:
{
@@ -2347,6 +2183,10 @@ void AuraEffect::TriggerSpell()
case 54835:
caster->CastSpell(m_target, trigger_spell_id, true, NULL, this);
return;
+ // Ground Slam
+ case 33525:
+ target->CastSpell(target, trigger_spell_id, true);
+ return;
}
}
@@ -2395,6 +2235,29 @@ void AuraEffect::HandleAuraDummy(bool apply, bool Real, bool changeAmount)
// AT APPLY
if(apply)
{
+ // Overpower
+ if (caster && m_spellProto->SpellFamilyName == SPELLFAMILY_WARRIOR &&
+ m_spellProto->SpellFamilyFlags[0] & 0x4)
+ {
+ // Must be casting target
+ if (!m_target->IsNonMeleeSpellCasted(false, false, true))
+ return;
+ if (AuraEffect * aurEff = caster->GetAuraEffect(SPELL_AURA_ADD_FLAT_MODIFIER, SPELLFAMILY_WARRIOR, 2775, 0))
+ {
+ switch (aurEff->GetId())
+ {
+ // Unrelenting Assault, rank 1
+ case 46859:
+ m_target->CastSpell(m_target,64849,true,NULL,aurEff);
+ break;
+ // Unrelenting Assault, rank 2
+ case 46860:
+ m_target->CastSpell(m_target,64850,true,NULL,aurEff);
+ break;
+ }
+ }
+ return;
+ }
switch(GetId())
{
// Haunting Spirits - perdiodic trigger demon
@@ -2435,6 +2298,24 @@ void AuraEffect::HandleAuraDummy(bool apply, bool Real, bool changeAmount)
}
return;
}
+ case 37096: // Blood Elf Illusion
+ {
+ if(caster)
+ {
+ switch(caster->getGender())
+ {
+ case GENDER_FEMALE:
+ caster->CastSpell(m_target,37095,true,NULL,this); // Blood Elf Disguise
+ break;
+ case GENDER_MALE:
+ caster->CastSpell(m_target,37093,true,NULL,this);
+ break;
+ default:
+ break;
+ }
+ }
+ return;
+ }
case 55198: // Tidal Force
{
m_target->CastSpell(m_target,55166,true,NULL,this);
@@ -2479,8 +2360,9 @@ void AuraEffect::HandleAuraDummy(bool apply, bool Real, bool changeAmount)
((Player*)m_target)->RemoveAmmo(); // not use ammo and not allow use
return;
case 52916: // Honor Among Thieves
- if (Unit * target = ObjectAccessor::GetUnit(*m_target, m_target->GetUInt64Value(UNIT_FIELD_TARGET)))
- m_target->CastSpell(target, 51699, true);
+ if(m_target->GetTypeId()==TYPEID_PLAYER)
+ if (Unit * target = ObjectAccessor::GetUnit(*m_target,((Player*)m_target)->GetComboTarget()))
+ m_target->CastSpell(target, 51699, true);
return;
}
@@ -2551,7 +2433,11 @@ void AuraEffect::HandleAuraDummy(bool apply, bool Real, bool changeAmount)
return;
case 46308: // Burning Winds casted only at creatures at spawn
m_target->CastSpell(m_target,47287,true,NULL,this);
- return;
+ return;
+ case 52173: // Coyote Spirit Despawn Aura
+ case 60244: // Blood Parrot Despawn Aura
+ m_target->CastSpell((Unit*)NULL, GetAmount(), true, NULL, this);
+ return;
}
break;
case SPELLFAMILY_WARLOCK:
@@ -2581,6 +2467,14 @@ void AuraEffect::HandleAuraDummy(bool apply, bool Real, bool changeAmount)
return;
}
break;
+ case SPELLFAMILY_DEATHKNIGHT:
+ // Summon Gargoyle ( will start feeding gargoyle )
+ if(GetId()==61777)
+ {
+ m_target->CastSpell(m_target,m_spellProto->EffectTriggerSpell[m_effIndex],true);
+ return;
+ }
+ break;
default:
break;
}
@@ -2597,6 +2491,10 @@ void AuraEffect::HandleAuraDummy(bool apply, bool Real, bool changeAmount)
break;
switch(GetId())
{
+ // Recently Bandaged
+ case 11196:
+ m_target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, GetMiscValue(), apply);
+ return;
// Unstable Power
case 24658:
{
@@ -2763,6 +2661,14 @@ void AuraEffect::HandleAuraDummy(bool apply, bool Real, bool changeAmount)
return;
}
}
+ // Predatory Strikes
+ if(m_target->GetTypeId()==TYPEID_PLAYER && GetSpellProto()->SpellIconID == 1563)
+ {
+ ((Player*)m_target)->UpdateAttackPowerAndDamage();
+ return;
+ }
+ if (!Real)
+ break;
// Lifebloom
if ( GetSpellProto()->SpellFamilyFlags[1] & 0x10 )
{
@@ -2783,85 +2689,19 @@ void AuraEffect::HandleAuraDummy(bool apply, bool Real, bool changeAmount)
if(m_target->IsInWorld())
m_target->CastCustomSpell(m_target,33778,&m_amount,NULL,NULL,true,NULL,this,GetCasterGUID());
- /*// have a look if there is still some other Lifebloom dummy aura
- Unit::AuraList auras = m_target->GetAurasByType(SPELL_AURA_DUMMY);
- for(Unit::AuraList::iterator itr = auras.begin(); itr!=auras.end(); ++itr)
- if((*itr)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID &&
- (*itr)->GetSpellProto()->SpellFamilyFlags & 0x1000000000LL)
- return;
-
- // final heal
- if(m_target->IsInWorld() && m_stackAmount > 0)
+ // restore mana
+ if (caster)
{
- int32 amount = m_amount / m_stackAmount;
- m_target->CastCustomSpell(m_target,33778,&amount,NULL,NULL,true,NULL,this,GetCasterGUID());
- }*/
- }
- return;
- }
-
- // Predatory Strikes
- if(m_target->GetTypeId()==TYPEID_PLAYER && GetSpellProto()->SpellIconID == 1563)
- {
- ((Player*)m_target)->UpdateAttackPowerAndDamage();
- return;
- }
- break;
- }
- case SPELLFAMILY_HUNTER:
- {
- if (!Real)
- break;
- // Glyph of Aspect of the Monkey
- if(m_spellProto->Id==56833)
- {
- if(apply)
- {
- SpellModifier *mod = new SpellModifier;
- mod->op = SPELLMOD_CHANCE_OF_SUCCESS;
- mod->value = 100;
- mod->type = SPELLMOD_FLAT;
- mod->spellId = GetId();
- mod->mask[2] = 8192;
- mod->mask[1] = 0x00000000;
- mod->mask[0] = 524288;
- m_spellmod = mod;
+ int32 returnmana = (GetSpellProto()->ManaCostPercentage * caster->GetCreateMana() / 100) * GetParentAura()->GetStackAmount() / 2;
+ caster->CastCustomSpell(caster, 64372, &returnmana, NULL, NULL, true, NULL, this, GetCasterGUID());
+ }
}
- ((Player*)m_target)->AddSpellMod(m_spellmod, apply);
return;
}
break;
}
case SPELLFAMILY_SHAMAN:
{
- if (!Real && !changeAmount)
- break;
- // Improved Weapon Totems
- if( GetSpellProto()->SpellIconID == 57 && m_target->GetTypeId()==TYPEID_PLAYER )
- {
- if(apply)
- {
- SpellModifier *mod = new SpellModifier;
- mod->op = SPELLMOD_EFFECT1;
- mod->value = m_amount;
- mod->type = SPELLMOD_PCT;
- mod->spellId = GetId();
- switch (m_effIndex)
- {
- case 0:
- mod->mask[1] = 0x002; // Windfury Totem
- break;
- case 1:
- mod->mask[1] = 0x004; // Flametongue Totem
- break;
- }
-
- m_spellmod = mod;
- }
-
- ((Player*)m_target)->AddSpellMod(m_spellmod, apply);
- return;
- }
if (!Real)
break;
// Sentry Totem
@@ -2888,7 +2728,7 @@ void AuraEffect::HandleAuraDummy(bool apply, bool Real, bool changeAmount)
if (Real)
{
// pet auras
- if(PetAura const* petSpell = spellmgr.GetPetAura(GetId()))
+ if(PetAura const* petSpell = spellmgr.GetPetAura(GetId(), m_effIndex))
{
if(apply)
m_target->AddPetAura(petSpell);
@@ -3088,6 +2928,8 @@ void AuraEffect::HandleAuraModShapeshift(bool apply, bool Real, bool changeAmoun
case FORM_AMBIENT:
case FORM_SHADOW:
case FORM_STEALTH:
+ case FORM_UNDEAD:
+ case FORM_SHADOW_DANCE:
break;
case FORM_TREE:
modelid = 864;
@@ -3116,13 +2958,37 @@ void AuraEffect::HandleAuraModShapeshift(bool apply, bool Real, bool changeAmoun
case FORM_FLIGHT_EPIC:
case FORM_FLIGHT:
case FORM_MOONKIN:
+ {
// remove movement affects
m_target->RemoveMovementImpairingAuras();
+/*
+ m_target->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
+ Unit::AuraList const& slowingAuras = m_target->GetAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
+ for (Unit::AuraList::const_iterator iter = slowingAuras.begin(); iter != slowingAuras.end();)
+ {
+ SpellEntry const* aurSpellInfo = (*iter)->GetSpellProto();
+
+ // If spell that caused this aura has Croud Control or Daze effect
+ if((GetAllSpellMechanicMask(aurSpellInfo) & MECHANIC_NOT_REMOVED_BY_SHAPESHIFT) ||
+ // some Daze spells have these parameters instead of MECHANIC_DAZE
+ (aurSpellInfo->SpellIconID == 15 && aurSpellInfo->Dispel == 0))
+ {
+ ++iter;
+ continue;
+ }
+
+ // All OK, remove aura now
+ m_target->RemoveAurasDueToSpellByCancel(aurSpellInfo->Id);
+ iter = slowingAuras.begin();
+ }
+*/
// and polymorphic affects
if(m_target->IsPolymorphed())
m_target->RemoveAurasDueToSpell(m_target->getTransForm());
+
break;
+ }
default:
break;
}
@@ -3176,28 +3042,6 @@ void AuraEffect::HandleAuraModShapeshift(bool apply, bool Real, bool changeAmoun
}
break;
}
- case FORM_BATTLESTANCE:
- case FORM_DEFENSIVESTANCE:
- case FORM_BERSERKERSTANCE:
- {
- uint32 Rage_val = 0;
- // Stance mastery + Tactical mastery (both passive, and last have aura only in defense stance, but need apply at any stance switch)
- if(m_target->GetTypeId() == TYPEID_PLAYER)
- {
- PlayerSpellMap const& sp_list = ((Player *)m_target)->GetSpellMap();
- for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
- {
- if(itr->second->state == PLAYERSPELL_REMOVED) continue;
- SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
- if (spellInfo && spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR && spellInfo->SpellIconID == 139)
- Rage_val += m_target->CalculateSpellDamage(spellInfo,0,spellInfo->EffectBasePoints[0],m_target) * 10;
- }
- }
-
- if (m_target->GetPower(POWER_RAGE) > Rage_val)
- m_target->SetPower(POWER_RAGE,Rage_val);
- break;
- }
default:
break;
}
@@ -3222,14 +3066,41 @@ void AuraEffect::HandleAuraModShapeshift(bool apply, bool Real, bool changeAmoun
case FORM_BEAR:
case FORM_DIREBEAR:
case FORM_CAT:
- if(AuraEffect* dummy = m_target->GetDummyAura(37315) )
+ if(AuraEffect* dummy = m_target->GetAuraEffect(37315, 0) )
m_target->CastSpell(m_target,37316,true,NULL,dummy);
break;
// Nordrassil Regalia - bonus
case FORM_MOONKIN:
- if(AuraEffect* dummy = m_target->GetDummyAura(37324) )
+ if(AuraEffect* dummy = m_target->GetAuraEffect(37324, 0) )
m_target->CastSpell(m_target,37325,true,NULL,dummy);
break;
+ case FORM_BATTLESTANCE:
+ case FORM_DEFENSIVESTANCE:
+ case FORM_BERSERKERSTANCE:
+ {
+ uint32 Rage_val = 0;
+ // Defensive Tactics
+ if (form == FORM_DEFENSIVESTANCE)
+ {
+ if (AuraEffect const * aurEff = m_target->IsScriptOverriden(m_spellProto,831))
+ Rage_val += aurEff->GetAmount() * 10;
+ }
+ // Stance mastery + Tactical mastery (both passive, and last have aura only in defense stance, but need apply at any stance switch)
+ if(m_target->GetTypeId() == TYPEID_PLAYER)
+ {
+ PlayerSpellMap const& sp_list = ((Player *)m_target)->GetSpellMap();
+ for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
+ {
+ if(itr->second->state == PLAYERSPELL_REMOVED) continue;
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
+ if (spellInfo && spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR && spellInfo->SpellIconID == 139)
+ Rage_val += m_target->CalculateSpellDamage(spellInfo,0,spellInfo->EffectBasePoints[0],m_target) * 10;
+ }
+ }
+ if (m_target->GetPower(POWER_RAGE) > Rage_val)
+ m_target->SetPower(POWER_RAGE,Rage_val);
+ break;
+ }
default:
break;
}
@@ -3244,8 +3115,9 @@ void AuraEffect::HandleAuraModShapeshift(bool apply, bool Real, bool changeAmoun
if(m_target->getClass() == CLASS_DRUID)
{
- if(form == FORM_CAT && apply) // add dash if in cat-from
+ if(form == FORM_CAT && apply)
{
+ // add dash if in cat-from
Unit::AuraMap & auras = m_target->GetAuras();
for (Unit::AuraMap::iterator iter = auras.begin(); iter != auras.end();++iter)
{
@@ -3364,6 +3236,13 @@ void AuraEffect::HandleAuraTransform(bool apply, bool Real, bool /*changeAmount*
// Dragonmaw Illusion (set mount model also)
if(GetId()==42016 && m_target->GetMountID() && !m_target->GetAurasByType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED).empty())
m_target->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID,16314);
+
+ // Polymorph (sheep)
+ if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_MAGE && GetSpellProto()->SpellIconID == 82 && GetSpellProto()->SpellVisual[0] == 12978)
+ if (Unit * caster = GetCaster())
+ // Glyph of the Penguin
+ if (caster->HasAura(52648))
+ m_target->SetDisplayId(26452);
}
}
@@ -4055,12 +3934,12 @@ void AuraEffect::HandleModThreat(bool apply, bool Real, bool changeAmount)
if(!Real && !changeAmount)
return;
- if(!m_target->isAlive())
+ if (!m_target->isAlive())
return;
Unit* caster = GetCaster();
- if(!caster || !caster->isAlive())
+ if (!caster || !caster->isAlive())
return;
int level_diff = 0;
@@ -4078,17 +3957,14 @@ void AuraEffect::HandleModThreat(bool apply, bool Real, bool changeAmount)
multiplier = 1;
break;
}
+
if (level_diff > 0)
m_amount += multiplier * level_diff;
- for(int8 x=0;x < MAX_SPELL_SCHOOL;x++)
- {
- if(GetMiscValue() & int32(1<<x))
- {
- if(m_target->GetTypeId() == TYPEID_PLAYER)
+ if (m_target->GetTypeId() == TYPEID_PLAYER)
+ for(int8 x=0;x < MAX_SPELL_SCHOOL;x++)
+ if (GetMiscValue() & int32(1<<x))
ApplyPercentModFloatVar(m_target->m_threatModifier[x], m_amount, apply);
- }
- }
}
void AuraEffect::HandleAuraModTotalThreat(bool apply, bool Real, bool changeAmount)
@@ -4097,19 +3973,15 @@ void AuraEffect::HandleAuraModTotalThreat(bool apply, bool Real, bool changeAmou
if(!Real && !changeAmount)
return;
- if(!m_target->isAlive() || m_target->GetTypeId()!= TYPEID_PLAYER)
+ if (!m_target->isAlive() || m_target->GetTypeId() != TYPEID_PLAYER)
return;
Unit* caster = GetCaster();
- if(!caster || !caster->isAlive())
+ if (!caster || !caster->isAlive())
return;
- float threatMod = 0.0f;
- if(apply)
- threatMod = float(m_amount);
- else
- threatMod = float(-m_amount);
+ float threatMod = apply ? float(m_amount) : float(-m_amount);
m_target->getHostilRefManager().threatAssist(caster, threatMod);
}
@@ -4117,18 +3989,18 @@ void AuraEffect::HandleAuraModTotalThreat(bool apply, bool Real, bool changeAmou
void AuraEffect::HandleModTaunt(bool apply, bool Real, bool /*changeAmount*/)
{
// only at real add/remove aura
- if(!Real)
+ if (!Real)
return;
- if(!m_target->isAlive() || !m_target->CanHaveThreatList())
+ if (!m_target->isAlive() || !m_target->CanHaveThreatList())
return;
Unit* caster = GetCaster();
- if(!caster || !caster->isAlive() || caster->GetTypeId() != TYPEID_PLAYER)
+ if (!caster || !caster->isAlive())
return;
- if(apply)
+ if (apply)
m_target->TauntApply(caster);
else
{
@@ -4204,15 +4076,28 @@ void AuraEffect::HandleAuraModIncreaseSwimSpeed(bool /*apply*/, bool Real, bool
m_target->UpdateSpeed(MOVE_SWIM, true);
}
-void AuraEffect::HandleAuraModDecreaseSpeed(bool /*apply*/, bool Real, bool changeAmount)
+void AuraEffect::HandleAuraModDecreaseSpeed(bool apply, bool Real, bool changeAmount)
{
// all applied/removed only at real aura add/remove
if(!Real && !changeAmount)
return;
+ if (apply)
+ {
+ // Gronn Lord's Grasp, becomes stoned
+ if (GetId() == 33572)
+ {
+ if (GetParentAura()->GetStackAmount() >= 5 && !m_target->HasAura(33652))
+ m_target->CastSpell(m_target, 33652, true);
+ }
+ }
+
m_target->UpdateSpeed(MOVE_RUN, true);
m_target->UpdateSpeed(MOVE_SWIM, true);
m_target->UpdateSpeed(MOVE_FLIGHT, true);
+ m_target->UpdateSpeed(MOVE_RUN_BACK, true);
+ m_target->UpdateSpeed(MOVE_SWIM_BACK, true);
+ m_target->UpdateSpeed(MOVE_FLIGHT_BACK, true);
}
void AuraEffect::HandleAuraModUseNormalSpeed(bool /*apply*/, bool Real, bool changeAmount)
@@ -4240,7 +4125,7 @@ void AuraEffect::HandleModStateImmunityMask(bool apply, bool Real, bool /*change
if (GetMiscValue() & (1<<7))
immunity_list.push_back(SPELL_AURA_MOD_DISARM);
if (GetMiscValue() & (1<<1))
- immunity_list.push_back(SPELL_AURA_MOD_TAUNT);
+ immunity_list.push_back(SPELL_AURA_TRANSFORM);
// These flag can be recognized wrong:
if (GetMiscValue() & (1<<6))
@@ -4283,6 +4168,11 @@ void AuraEffect::HandleModMechanicImmunity(bool apply, bool Real, bool /*changeA
//immune movement impairment and loss of control
if(GetId()==42292 || GetId()==59752)
mechanic=IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
+ // Forbearance
+ // in DBC wrong mechanic immune since 3.0.x
+ else if (GetId() == 25771)
+ mechanic = 1 << MECHANIC_IMMUNE_SHIELD;
+
if (!mechanic)
return;
@@ -4310,23 +4200,18 @@ void AuraEffect::HandleModMechanicImmunity(bool apply, bool Real, bool /*changeA
m_target->ApplySpellImmune(GetId(),IMMUNITY_MECHANIC,GetMiscValue(),apply);
// Bestial Wrath
- if ( GetSpellProto()->SpellFamilyName == SPELLFAMILY_HUNTER && GetSpellProto()->Id == 19574)
+ if (GetSpellProto()->Id == 19574)
{
// The Beast Within cast on owner if talent present
if ( Unit* owner = m_target->GetOwner() )
{
// Search talent
- Unit::AuraEffectList const& m_dummyAuras = owner->GetAurasByType(SPELL_AURA_DUMMY);
- for(Unit::AuraEffectList::const_iterator i = m_dummyAuras.begin(); i != m_dummyAuras.end(); ++i)
+ if (owner->GetAuraEffect(34692, 0))
{
- if ( (*i)->GetSpellProto()->SpellIconID == 2229 )
- {
- if (apply)
- owner->CastSpell(owner, 34471, true, 0, this);
- else
- owner->RemoveAurasDueToSpell(34471);
- break;
- }
+ if (apply)
+ owner->CastSpell(owner, 34471, true, 0, this);
+ else
+ owner->RemoveAurasDueToSpell(34471);
}
}
}
@@ -4365,7 +4250,7 @@ void AuraEffect::HandleModMechanicImmunity(bool apply, bool Real, bool /*changeA
m_target->ApplySpellImmune(GetId(),IMMUNITY_STATE,SPELL_AURA_MOD_DECREASE_SPEED,apply);
}
// Demonic Circle
- else if (m_spellProto->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellProto->SpellIconID == 3221)
+ else if (GetId() == 48020)
{
if (m_target->GetTypeId() != TYPEID_PLAYER)
return;
@@ -4378,7 +4263,6 @@ void AuraEffect::HandleModMechanicImmunity(bool apply, bool Real, bool /*changeA
}
}
-//this method is called whenever we add / remove aura which gives m_target some imunity to some spell effect
void AuraEffect::HandleAuraModEffectImmunity(bool apply, bool Real, bool /*changeAmount*/)
{
// when removing flag aura, handle flag drop
@@ -4518,15 +4402,20 @@ void AuraEffect::HandlePeriodicTriggerSpellWithValue(bool apply, bool Real, bool
void AuraEffect::HandlePeriodicEnergize(bool apply, bool Real, bool changeAmount)
{
- if(!Real && !changeAmount)
+ if(!Real)
return;
m_isPeriodic = apply;
- // Replenishment (0.25% from max)
- // Infinite Replenishment
- if (m_spellProto->SpellIconID == 3184 && m_spellProto->SpellVisual[0] == 12495)
- m_amount = m_target->GetMaxPower(POWER_MANA) * 25 / 10000;
+ if (apply)
+ {
+ // Replenishment (0.25% from max)
+ // Infinite Replenishment
+ if (m_spellProto->SpellIconID == 3184 && m_spellProto->SpellVisual[0] == 12495)
+ m_amount = m_target->GetMaxPower(POWER_MANA) * 25 / 10000;
+ else if (m_spellProto->Id == 29166) // Innervate
+ m_amount = m_target->GetCreatePowers(POWER_MANA) * m_amount / (GetTotalTicks() * 100.0f);
+ }
}
void AuraEffect::HandleAuraPowerBurn(bool apply, bool Real, bool /*changeAmount*/)
@@ -4572,10 +4461,19 @@ void AuraEffect::HandleAuraPeriodicDummy(bool apply, bool Real, bool changeAmoun
case SPELLFAMILY_HUNTER:
{
// Explosive Shot
- if (apply && !loading && caster)
+ if (apply && !loading && caster && spell->SpellFamilyFlags[1] & 0x80000000)
m_amount += int32(caster->GetTotalAttackPowerValue(RANGED_ATTACK) * 14 / 100);
break;
}
+ case SPELLFAMILY_DEATHKNIGHT:
+ {
+ // Reaping
+ // Blood of the North
+ // Death Rune Mastery
+ if (spell->SpellIconID == 3041 || spell->SpellIconID == 22 || spell->SpellIconID == 2622)
+ m_amount = 0;
+ break;
+ }
}
m_isPeriodic = apply;
@@ -4599,7 +4497,7 @@ void AuraEffect::HandlePeriodicDamage(bool apply, bool Real, bool changeAmount)
// Curse of Doom
// This is a hack - this aura should be handled by passive aura and proc doomguard spawn on kill, however there is no such aura in dbcs
- if(m_spellProto->SpellFamilyName==SPELLFAMILY_WARLOCK && m_spellProto->SpellFamilyFlags.IsEqual(0,0x02,0))
+ if(m_spellProto->SpellFamilyName==SPELLFAMILY_WARLOCK && m_spellProto->SpellFamilyFlags[1] & 0x02)
{
if (Real && !apply && GetParentAura()->GetRemoveMode()==AURA_REMOVE_BY_DEATH)
{
@@ -4621,17 +4519,6 @@ void AuraEffect::HandlePeriodicDamage(bool apply, bool Real, bool changeAmount)
switch (m_spellProto->SpellFamilyName)
{
- case SPELLFAMILY_GENERIC:
- {
- // Pounce Bleed
- if ( m_spellProto->SpellIconID == 147 && m_spellProto->SpellVisual[0] == 0 )
- {
- // $AP*0.18/6 bonus per tick
- m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 3 / 100);
- return;
- }
- break;
- }
case SPELLFAMILY_WARRIOR:
{
// Rend
@@ -4643,28 +4530,32 @@ void AuraEffect::HandlePeriodicDamage(bool apply, bool Real, bool changeAmount)
float mwb_min = caster->GetWeaponDamageRange(BASE_ATTACK,MINDAMAGE);
float mwb_max = caster->GetWeaponDamageRange(BASE_ATTACK,MAXDAMAGE);
m_amount+=int32(((mwb_min+mwb_max)/2+ap*mws/14000)*0.2f);
+ // "If used while your target is above 75% health, Rend does 35% more damage."
+ // as for 3.1.3 only ranks above 9 (wrong tooltip?)
+ if (spellmgr.GetSpellRank(m_spellProto->Id) >= 9)
+ {
+ if (m_target->HasAuraState(AURA_STATE_HEALTH_ABOVE_75_PERCENT, m_spellProto, caster))
+ m_amount += int32(m_amount*0.35);
+ }
return;
}
break;
}
- case SPELLFAMILY_DRUID:
+ // Drain Soul - If the target is at or below 25% health, Drain Soul causes four times the normal damage
+ case SPELLFAMILY_WARLOCK:
{
- // Rake
- if (m_spellProto->SpellFamilyFlags[0] & 0x1000)
- {
- // $AP*0.06 bonus per tick
- m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 6 / 100);
- return;
- }
- // Lacerate
- if (m_spellProto->SpellFamilyFlags[1] & 0x0000000100)
+ if (m_spellProto->SpellFamilyFlags[0] & 0x00004000)
{
- // $AP*0.05/5 bonus per tick
- m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
- return;
+ // if victim is below 25% of hp
+ if (m_target->GetMaxHealth() / 4 > m_target->GetHealth())
+ m_amount *= 4;
}
+ break;
+ }
+ case SPELLFAMILY_DRUID:
+ {
// Rip
- if (m_spellProto->SpellVisual[0] == 3941)
+ if (m_spellProto->SpellFamilyFlags[0] & 0x00800000)
{
// 0.01*$AP*cp
if (caster->GetTypeId() != TYPEID_PLAYER)
@@ -4673,25 +4564,12 @@ void AuraEffect::HandlePeriodicDamage(bool apply, bool Real, bool changeAmount)
uint8 cp = ((Player*)caster)->GetComboPoints();
// Idol of Feral Shadows. Cant be handled as SpellMod in SpellAura:Dummy due its dependency from CPs
- Unit::AuraEffectList const& dummyAuras = caster->GetAurasByType(SPELL_AURA_DUMMY);
- for(Unit::AuraEffectList::const_iterator itr = dummyAuras.begin(); itr != dummyAuras.end(); ++itr)
- {
- if((*itr)->GetId()==34241)
- {
- m_amount += cp * (*itr)->GetAmount();
- break;
- }
- }
+ if (AuraEffect const * aurEff = caster->GetAuraEffect(34241,0))
+ m_amount += cp * aurEff->GetAmount();
+
m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * cp / 100);
return;
}
- // Lock Jaw
- if (m_spellProto->SpellFamilyFlags[1] & 0x10000000)
- {
- // 0.15*$AP
- m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 15 / 100);
- return;
- }
break;
}
case SPELLFAMILY_ROGUE:
@@ -4712,38 +4590,6 @@ void AuraEffect::HandlePeriodicDamage(bool apply, bool Real, bool changeAmount)
m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * AP_per_combo[cp]);
return;
}
- // Garrote
- if (m_spellProto->SpellFamilyFlags[0] & 0x100)
- {
- // $AP*0.07 bonus per tick
- m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 7 / 100);
- return;
- }
- // Deadly Poison
- if (m_spellProto->SpellFamilyFlags[0] & 0x10000)
- {
- // 0.08*$AP / 4 * amount of stack
- m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 2 * GetParentAura()->GetStackAmount() / 100);
- return;
- }
- break;
- }
- case SPELLFAMILY_HUNTER:
- {
- // Serpent Sting
- if (m_spellProto->SpellFamilyFlags[0] & 0x4000)
- {
- // $RAP*0.1/5 bonus per tick
- m_amount += int32(caster->GetTotalAttackPowerValue(RANGED_ATTACK) * 10 / 500);
- return;
- }
- // Immolation Trap
- if (m_spellProto->SpellFamilyFlags[0] & 0x4 && m_spellProto->SpellIconID == 678)
- {
- // $RAP*0.1/5 bonus per tick
- m_amount += int32(caster->GetTotalAttackPowerValue(RANGED_ATTACK) * 10 / 500);
- return;
- }
break;
}
default:
@@ -4913,7 +4759,7 @@ void AuraEffect::HandleModSpellDamagePercentFromStat(bool /*apply*/, bool Real,
((Player*)m_target)->UpdateSpellDamageAndHealingBonus();
}
-void AuraEffect::HandleModSpellHealingPercentFromStat(bool /*apply*/, bool Real, bool /*changeAmount*/)
+void AuraEffect::HandleModSpellHealingPercentFromStat(bool apply, bool Real, bool /*changeAmount*/)
{
if(m_target->GetTypeId() != TYPEID_PLAYER)
return;
@@ -5663,6 +5509,7 @@ void AuraEffect::HandleAuraModPacify(bool apply, bool Real, bool /*changeAmount*
void AuraEffect::HandleAuraModPacifyAndSilence(bool apply, bool Real, bool changeAmount)
{
+ // Vengeance of the Blue Flight
if(m_spellProto->Id == 45839)
{
if(apply)
@@ -5855,7 +5702,7 @@ void AuraEffect::HandleSchoolAbsorb(bool apply, bool Real, bool changeAmount)
{
case SPELLFAMILY_PRIEST:
// Power Word: Shield
- if(m_spellProto->SpellFamilyFlags.IsEqual(0x1, 0, 0x400))
+ if(m_spellProto->SpellFamilyFlags[0] & 0x1 && m_spellProto->SpellFamilyFlags[2] & 0x400)
{
// +80.68% from sp bonus
DoneActualBenefit = caster->SpellBaseHealingBonus(GetSpellSchoolMask(m_spellProto)) * 0.8068f;
@@ -5863,7 +5710,7 @@ void AuraEffect::HandleSchoolAbsorb(bool apply, bool Real, bool changeAmount)
break;
case SPELLFAMILY_MAGE:
// ice barrier
- if(m_spellProto->SpellFamilyFlags.IsEqual(0, 0x1, 0x8))
+ if(m_spellProto->SpellFamilyFlags[1] & 0x1 && m_spellProto->SpellFamilyFlags[2] & 0x8)
{
// +80.67% from sp bonus
DoneActualBenefit = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) * 0.8067f;
@@ -5880,7 +5727,7 @@ void AuraEffect::HandleSchoolAbsorb(bool apply, bool Real, bool changeAmount)
break;
case SPELLFAMILY_WARLOCK:
// shadow ward
- if(m_spellProto->SpellFamilyFlags.IsEqual(0, 0, 0x40))
+ if(m_spellProto->SpellFamilyFlags[2]& 0x40)
{
// +30% from sp bonus
DoneActualBenefit = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) * 0.3f;
@@ -5891,7 +5738,7 @@ void AuraEffect::HandleSchoolAbsorb(bool apply, bool Real, bool changeAmount)
if (m_spellProto->SpellFamilyFlags[1] & 0x80000)
{
// 0.75 from sp bonus
- DoneActualBenefit = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) * 0.75f;
+ DoneActualBenefit = caster->SpellBaseHealingBonus(GetSpellSchoolMask(m_spellProto)) * 0.75f;
}
break;
default:
@@ -5903,6 +5750,38 @@ void AuraEffect::HandleSchoolAbsorb(bool apply, bool Real, bool changeAmount)
m_amount += (int32)DoneActualBenefit;
}
}
+
+ // Guardian Spirit
+ if(m_spellProto->Id == 47788 && Real && !apply)
+ {
+ Unit *caster = GetCaster();
+ if(!caster)
+ return;
+
+ if(caster->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ Player *player = ((Player*)caster);
+ // Glyph of Guardian Spirit
+ if(AuraEffect * aurEff = player->GetAuraEffect(63231, 0))
+ {
+ if (GetParentAura()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE)
+ {
+ if (!player->HasSpellCooldown(47788))
+ return;
+
+ player->RemoveSpellCooldown(m_spellProto->Id, true);
+ player->AddSpellCooldown(m_spellProto->Id, 0, uint32(time(NULL) + aurEff->GetAmount()));
+
+ WorldPacket data(SMSG_SPELL_COOLDOWN, 8+1+4+4);
+ data << uint64(player->GetGUID());
+ data << uint8(0x0); // flags (0x1, 0x2)
+ data << uint32(m_spellProto->Id);
+ data << uint32(aurEff->GetAmount()*IN_MILISECONDS);
+ player->SendDirectMessage(&data);
+ }
+ }
+ }
}
void AuraEffect::PeriodicTick()
@@ -5933,15 +5812,15 @@ void AuraEffect::PeriodicTick()
{
switch(GetId())
{
- case 43093: case 31956: case 38801:
- case 35321: case 38363: case 39215:
+ case 43093: case 31956: case 38801: // Grievous Wound
+ case 35321: case 38363: case 39215: // Gushing Wound
if(m_target->GetHealth() == m_target->GetMaxHealth() )
{
m_target->RemoveAurasDueToSpell(GetId());
return;
}
break;
- case 38772:
+ case 38772: // Grievous Wound
{
uint32 percent =
GetEffIndex() < 2 && GetSpellProto()->Effect[GetEffIndex()]==SPELL_EFFECT_DUMMY ?
@@ -5954,18 +5833,13 @@ void AuraEffect::PeriodicTick()
}
break;
}
- case 41337:// aura of anger
+ case 41337:// Aura of Anger
{
- Unit::AuraEffectList const& mMod = m_target->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
- for(Unit::AuraEffectList::const_iterator i = mMod.begin(); i != mMod.end(); ++i)
+ if (AuraEffect * aurEff = GetParentAura()->GetPartAura(1))
{
- if ((*i)->GetId() == 41337)
- {
- (*i)->ApplyModifier(false);
- (*i)->SetAmount((*i)->GetAmount()+5);
- (*i)->ApplyModifier(true);
- break;
- }
+ aurEff->ApplyModifier(false, false, true);
+ aurEff->SetAmount(aurEff->GetAmount()+5);
+ aurEff->ApplyModifier(true, false, true);
}
m_amount = 100 * m_tickNumber;
break;
@@ -5977,7 +5851,7 @@ void AuraEffect::PeriodicTick()
uint32 absorb=0;
uint32 resist=0;
- CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
+ CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL );
// ignore non positive values (can be result apply spellmods to aura damage
//uint32 amount = GetModifierValuePerStack() > 0 ? GetModifierValuePerStack() : 0;
@@ -5993,7 +5867,7 @@ void AuraEffect::PeriodicTick()
GetEffectMechanic(GetSpellProto(), m_effIndex) != MECHANIC_BLEED)
{
uint32 pdamageReductedArmor = pCaster->CalcArmorReducedDamage(m_target, pdamage, GetSpellProto());
- cleanDamage.damage += pdamage - pdamageReductedArmor;
+ cleanDamage.mitigated_damage += pdamage - pdamageReductedArmor;
pdamage = pdamageReductedArmor;
}
@@ -6013,6 +5887,21 @@ void AuraEffect::PeriodicTick()
else
pdamage = uint32(m_target->GetMaxHealth()*pdamage/100);
+ bool crit = false;
+ Unit::AuraEffectList const& mPeriodicCritAuras= pCaster->GetAurasByType(SPELL_AURA_ABILITY_PERIODIC_CRIT);
+ for(Unit::AuraEffectList::const_iterator itr = mPeriodicCritAuras.begin(); itr != mPeriodicCritAuras.end(); ++itr)
+ {
+ if (!(*itr)->isAffectedOnSpell(m_spellProto))
+ continue;
+
+ if (pCaster->isSpellCrit(m_target, m_spellProto, GetSpellSchoolMask(m_spellProto)))
+ {
+ crit = true;
+ pdamage = pCaster->SpellCriticalDamageBonus(m_spellProto, pdamage, m_target);
+ }
+ break;
+ }
+
//As of 2.2 resilience reduces damage from DoT ticks as much as the chance to not be critically hit
// Reduce dot damage from resilience for players
if (m_target->GetTypeId()==TYPEID_PLAYER)
@@ -6025,7 +5914,7 @@ void AuraEffect::PeriodicTick()
pCaster->DealDamageMods(m_target,pdamage,&absorb);
- SpellPeriodicAuraLogInfo pInfo(this, pdamage, 0, absorb, resist, 0.0f);
+ SpellPeriodicAuraLogInfo pInfo(this, pdamage, 0, absorb, resist, 0.0f, crit);
m_target->SendPeriodicAuraLog(&pInfo);
Unit* target = m_target; // aura can be deleted in DealDamage
@@ -6062,7 +5951,7 @@ void AuraEffect::PeriodicTick()
uint32 absorb=0;
uint32 resist=0;
- CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
+ CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL );
//uint32 pdamage = GetModifierValuePerStack() > 0 ? GetModifierValuePerStack() : 0;
uint32 pdamage = GetAmount() > 0 ? GetAmount() : 0;
@@ -6072,7 +5961,7 @@ void AuraEffect::PeriodicTick()
if (GetSpellSchoolMask(GetSpellProto()) & SPELL_SCHOOL_MASK_NORMAL)
{
uint32 pdamageReductedArmor = pCaster->CalcArmorReducedDamage(m_target, pdamage, GetSpellProto());
- cleanDamage.damage += pdamage - pdamageReductedArmor;
+ cleanDamage.mitigated_damage += pdamage - pdamageReductedArmor;
pdamage = pdamageReductedArmor;
}
@@ -6156,7 +6045,7 @@ void AuraEffect::PeriodicTick()
return;
// heal for caster damage (must be alive)
- if(m_target != pCaster && GetSpellProto()->SpellVisual[0]==163 && !pCaster->isAlive())
+ if(m_target != pCaster && GetSpellProto()->AttributesEx2 & SPELL_ATTR_EX2_HEALTH_FUNNEL && !pCaster->isAlive())
return;
if(GetParentAura()->GetAuraDuration() ==-1 && m_target->GetHealth()==m_target->GetMaxHealth())
@@ -6169,14 +6058,39 @@ void AuraEffect::PeriodicTick()
if(m_auraName==SPELL_AURA_OBS_MOD_HEALTH)
pdamage = uint32(m_target->GetMaxHealth() * pdamage * GetParentAura()->GetStackAmount() / 100);
else
+ {
+ // Wild Growth (1/7 - 6 + 2*ramainTicks) %
+ if (m_spellProto->SpellFamilyName == SPELLFAMILY_DRUID && m_spellProto->SpellIconID == 2864)
+ {
+ int32 ticks = GetParentAura()->GetAuraMaxDuration()/m_amplitude;
+ int32 remainingTicks = int32(float(GetParentAura()->GetAuraDuration()) / m_amplitude + 0.5);
+ pdamage = int32(pdamage) + int32(pdamage)*ticks*(-6+2*remainingTicks)/100;
+ }
+
pdamage = pCaster->SpellHealingBonus(m_target, GetSpellProto(), pdamage, DOT, GetParentAura()->GetStackAmount());
+ }
+
+ bool crit = false;
+ Unit::AuraEffectList const& mPeriodicCritAuras= pCaster->GetAurasByType(SPELL_AURA_ABILITY_PERIODIC_CRIT);
+ for(Unit::AuraEffectList::const_iterator itr = mPeriodicCritAuras.begin(); itr != mPeriodicCritAuras.end(); ++itr)
+ {
+ if (!(*itr)->isAffectedOnSpell(m_spellProto))
+ continue;
+
+ if (pCaster->isSpellCrit(m_target, m_spellProto, GetSpellSchoolMask(m_spellProto)))
+ {
+ crit = true;
+ pdamage = pCaster->SpellCriticalHealingBonus(m_spellProto, pdamage, m_target);
+ }
+ break;
+ }
sLog.outDetail("PeriodicTick: %u (TypeId: %u) heal of %u (TypeId: %u) for %u health inflicted by %u",
GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), m_target->GetGUIDLow(), m_target->GetTypeId(), pdamage, GetId());
int32 gain = m_target->ModifyHealth(pdamage);
- SpellPeriodicAuraLogInfo pInfo(this, pdamage, pdamage - gain, 0, 0, 0.0f);
+ SpellPeriodicAuraLogInfo pInfo(this, pdamage, pdamage - gain, 0, 0, 0.0f, crit);
m_target->SendPeriodicAuraLog(&pInfo);
// add HoTs to amount healed in bgs
@@ -6192,7 +6106,7 @@ void AuraEffect::PeriodicTick()
// Health Funnel
// heal for caster damage
- if(m_target!=pCaster && spellProto->SpellVisual[0]==163)
+ if(m_target!=pCaster && GetSpellProto()->AttributesEx2 & SPELL_ATTR_EX2_HEALTH_FUNNEL)
{
uint32 dmg = spellProto->manaPerSecond;
if(pCaster->GetHealth() <= dmg && pCaster->GetTypeId()==TYPEID_PLAYER)
@@ -6217,7 +6131,7 @@ void AuraEffect::PeriodicTick()
pCaster->DealDamageMods(pCaster,damage,&absorb);
pCaster->SendSpellNonMeleeDamageLog(pCaster, GetId(), damage, GetSpellSchoolMask(GetSpellProto()), absorb, 0, false, 0, false);
- CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
+ CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL );
pCaster->DealDamage(pCaster, damage, &cleanDamage, NODAMAGE, GetSpellSchoolMask(GetSpellProto()), GetSpellProto(), true);
}
}
@@ -6291,7 +6205,7 @@ void AuraEffect::PeriodicTick()
modOwner->ApplySpellMod(GetId(), SPELLMOD_MULTIPLE_VALUE, gain_multiplier);
}
- SpellPeriodicAuraLogInfo pInfo(this, drain_amount, 0, 0, 0, gain_multiplier);
+ SpellPeriodicAuraLogInfo pInfo(this, drain_amount, 0, 0, 0, gain_multiplier, false);
m_target->SendPeriodicAuraLog(&pInfo);
int32 gain_amount = int32(drain_amount*gain_multiplier);
@@ -6323,6 +6237,20 @@ void AuraEffect::PeriodicTick()
GetParentAura()->SetAuraDuration(0);
}
}
+ // Mana Feed - Drain Mana
+ if (m_spellProto->SpellFamilyName == SPELLFAMILY_WARLOCK
+ && m_spellProto->SpellFamilyFlags[0] & 0x00000010)
+ {
+ int32 manaFeedVal = 0;
+ if (AuraEffect const * aurEff = GetParentAura()->GetPartAura(1))
+ manaFeedVal = aurEff->GetAmount();
+
+ if(manaFeedVal > 0)
+ {
+ manaFeedVal = manaFeedVal * gain_amount / 100;
+ pCaster->CastCustomSpell(pCaster, 32554, &manaFeedVal, NULL, NULL, true, NULL, this);
+ }
+ }
break;
}
case SPELL_AURA_OBS_MOD_ENERGY:
@@ -6346,7 +6274,7 @@ void AuraEffect::PeriodicTick()
sLog.outDetail("PeriodicTick: %u (TypeId: %u) energize %u (TypeId: %u) for %u dmg inflicted by %u",
GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), m_target->GetGUIDLow(), m_target->GetTypeId(), amount, GetId());
- SpellPeriodicAuraLogInfo pInfo(this, amount, 0, 0, 0, 0.0f);
+ SpellPeriodicAuraLogInfo pInfo(this, amount, 0, 0, 0, 0.0f, false);
m_target->SendPeriodicAuraLog(&pInfo);
int32 gain = m_target->ModifyPower(power,amount);
@@ -6371,7 +6299,7 @@ void AuraEffect::PeriodicTick()
uint32 amount = m_amount;
- SpellPeriodicAuraLogInfo pInfo(this, amount, 0, 0, 0, 0.0f);
+ SpellPeriodicAuraLogInfo pInfo(this, amount, 0, 0, 0, 0.0f, false);
m_target->SendPeriodicAuraLog(&pInfo);
sLog.outDetail("PeriodicTick: %u (TypeId: %u) energize %u (TypeId: %u) for %u dmg inflicted by %u",
@@ -6523,6 +6451,7 @@ void AuraEffect::PeriodicDummyTick()
case 34291:
case 43182:
case 43183:
+ case 43706:
case 46755:
case 49472: // Drink Coffee
case 57073:
@@ -6602,165 +6531,10 @@ void AuraEffect::PeriodicDummyTick()
// 7053 Forsaken Skill: Shadow
return;
}
-// // Panda
-// case 19230: break;
-// // Gossip NPC Periodic - Talk
-// case 33208: break;
-// // Gossip NPC Periodic - Despawn
-// case 33209: break;
-// // Steal Weapon
-// case 36207: break;
-// // Simon Game START timer, (DND)
-// case 39993: break;
-// // Knockdown Fel Cannon: break; The Aggro Burst
-// case 40119: break;
-// // Old Mount Spell
-// case 40154: break;
-// // Magnetic Pull
-// case 40581: break;
-// // Ethereal Ring: break; The Bolt Burst
-// case 40801: break;
-// // Crystal Prison
-// case 40846: break;
-// // Copy Weapon
-// case 41054: break;
-// // Dementia
-// case 41404: break;
-// // Ethereal Ring Visual, Lightning Aura
-// case 41477: break;
-// // Ethereal Ring Visual, Lightning Aura (Fork)
-// case 41525: break;
-// // Ethereal Ring Visual, Lightning Jumper Aura
-// case 41567: break;
-// // No Man's Land
-// case 41955: break;
-// // Headless Horseman - Fire
-// case 42074: break;
-// // Headless Horseman - Visual - Large Fire
-// case 42075: break;
-// // Headless Horseman - Start Fire, Periodic Aura
-// case 42140: break;
-// // Ram Speed Boost
-// case 42152: break;
-// // Headless Horseman - Fires Out Victory Aura
-// case 42235: break;
-// // Pumpkin Life Cycle
-// case 42280: break;
-// // Brewfest Request Chick Chuck Mug Aura
-// case 42537: break;
-// // Squashling
-// case 42596: break;
-// // Headless Horseman Climax, Head: Periodic
-// case 42603: break;
-// // Fire Bomb
-// case 42621: break;
-// // Headless Horseman - Conflagrate, Periodic Aura
-// case 42637: break;
-// // Headless Horseman - Create Pumpkin Treats Aura
-// case 42774: break;
-// // Headless Horseman Climax - Summoning Rhyme Aura
-// case 42879: break;
-// // Tricky Treat
-// case 42919: break;
-// // Giddyup!
-// case 42924: break;
-// // Ram - Trot
-// case 42992: break;
-// // Ram - Canter
-// case 42993: break;
-// // Ram - Gallop
-// case 42994: break;
-// // Ram Level - Neutral
-// case 43310: break;
-// // Headless Horseman - Maniacal Laugh, Maniacal, Delayed 17
-// case 43884: break;
-// // Wretched!
-// case 43963: break;
-// // Headless Horseman - Maniacal Laugh, Maniacal, other, Delayed 17
-// case 44000: break;
-// // Energy Feedback
-// case 44328: break;
-// // Romantic Picnic
-// case 45102: break;
-// // Romantic Picnic
-// case 45123: break;
-// // Looking for Love
-// case 45124: break;
-// // Kite - Lightning Strike Kite Aura
-// case 45197: break;
-// // Rocket Chicken
-// case 45202: break;
-// // Copy Offhand Weapon
-// case 45205: break;
-// // Upper Deck - Kite - Lightning Periodic Aura
-// case 45207: break;
-// // Kite -Sky Lightning Strike Kite Aura
-// case 45251: break;
-// // Ribbon Pole Dancer Check Aura
-// case 45390: break;
-// // Holiday - Midsummer, Ribbon Pole Periodic Visual
-// case 45406: break;
-// // Parachute
-// case 45472: break;
-// // Alliance Flag, Extra Damage Debuff
-// case 45898: break;
-// // Horde Flag, Extra Damage Debuff
-// case 45899: break;
-// // Ahune - Summoning Rhyme Aura
-// case 45926: break;
-// // Ahune - Slippery Floor
-// case 45945: break;
-// // Ahune's Shield
-// case 45954: break;
-// // Nether Vapor Lightning
-// case 45960: break;
-// // Darkness
-// case 45996: break;
-// // Summon Blood Elves Periodic
-// case 46041: break;
-// // Transform Visual Missile Periodic
-// case 46205: break;
-// // Find Opening Beam End
-// case 46333: break;
-// // Ice Spear Control Aura
-// case 46371: break;
-// // Hailstone Chill
-// case 46458: break;
-// // Hailstone Chill, Internal
-// case 46465: break;
-// // Chill, Internal Shifter
-// case 46549: break;
-// // Summon Ice Spear Knockback Delayer
-// case 46878: break;
-// // Burninate Effect
-// case 47214: break;
-// // Fizzcrank Practice Parachute
-// case 47228: break;
-// // Send Mug Control Aura
-// case 47369: break;
-// // Direbrew's Disarm (precast)
-// case 47407: break;
-// // Mole Machine Port Schedule
-// case 47489: break;
-// case 47941: break; // Crystal Spike
-// case 48200: break; // Healer Aura
-// case 48630: break; // Summon Gauntlet Mobs Periodic
-// case 49313: break; // Proximity Mine Area Aura
-// // Mole Machine Portal Schedule
-// case 49466: break;
-// case 49555: break; // Corpse Explode
-// case 49592: break; // Temporal Rift
-// case 49957: break; // Cutting Laser
-// case 50085: break; // Slow Fall
-// // Listening to Music
-// case 50493: break;
-// // Love Rocket Barrage
-// case 50530: break;
case 58549: // Tenacity
case 59911: // Tenacity (vehicle)
GetParentAura()->RefreshAura();
break;
-// Exist more after, need add later
default:
break;
}
@@ -6768,8 +6542,12 @@ void AuraEffect::PeriodicDummyTick()
case SPELLFAMILY_MAGE:
{
// Mirror Image
-// if (spell->Id == 55342)
-// return;
+ if (spell->Id == 55342)
+ {
+ // Set name of summons to name of caster
+ m_target->CastSpell((Unit *)NULL, m_spellProto->EffectTriggerSpell[m_effIndex], true);
+ m_isPeriodic = false;
+ }
break;
}
case SPELLFAMILY_WARLOCK:
@@ -6881,9 +6659,6 @@ void AuraEffect::PeriodicDummyTick()
}
switch (spell->Id)
{
- // Harpooner's Mark
- // case 40084:
- // return;
// Feeding Frenzy Rank 1
case 53511:
if ( m_target->GetHealth() * 100 < m_target->GetMaxHealth() * 35 )
@@ -6935,26 +6710,46 @@ void AuraEffect::PeriodicDummyTick()
return;
}
// Summon Gargoyle
-// if (spell->SpellFamilyFlags & 0x0000008000000000LL)
-// return;
+ // Being pursuaded by Gargoyle - AI related?
+ // if (spell->SpellFamilyFlags[1] & 0x00000080)
+ // break;
+ // Blood of the North
+ // Reaping
// Death Rune Mastery
-// if (spell->SpellFamilyFlags & 0x0000000000004000LL)
-// return;
- // Bladed Armor
- if (spell->SpellIconID == 2653)
+ if (spell->SpellIconID == 3041 || spell->SpellIconID == 22 || spell->SpellIconID == 2622)
{
- // Increases your attack power by $s1 for every $s2 armor value you have.
- // Calculate AP bonus (from 1 efect of this spell)
- int32 apBonus = m_amount * m_target->GetArmor() / m_target->CalculateSpellDamage(spell, 1, spell->EffectBasePoints[1], m_target);
- m_target->CastCustomSpell(m_target, 61217, &apBonus, &apBonus, 0, true, 0, this);
+ if (m_target->GetTypeId() != TYPEID_PLAYER)
+ return;
+ // Aura not used - prevent removing death runes from other effects
+ if (!GetAmount())
+ return;
+ if(((Player*)m_target)->getClass() != CLASS_DEATH_KNIGHT)
+ return;
+
+ // Remove death rune added on proc
+ for (uint8 i=0;i<MAX_RUNES && m_amount;++i)
+ {
+ if (m_spellProto->SpellIconID == 2622)
+ {
+ if (((Player*)m_target)->GetCurrentRune(i) != RUNE_DEATH ||
+ ((Player*)m_target)->GetBaseRune(i) == RUNE_BLOOD )
+ continue;
+ }
+ else
+ {
+ if (((Player*)m_target)->GetCurrentRune(i) != RUNE_DEATH ||
+ ((Player*)m_target)->GetBaseRune(i) != RUNE_BLOOD )
+ continue;
+ }
+
+ if (!(m_amount & (1<<i)))
+ continue;
+
+ ((Player*)m_target)->ConvertRune(i,((Player*)m_target)->GetBaseRune(i));
+ }
+ m_amount = 0;
return;
}
- // Reaping
-// if (spell->SpellIconID == 22)
-// return;
- // Blood of the North
-// if (spell->SpellIconID == 30412)
-// return;
break;
}
default:
@@ -6992,7 +6787,7 @@ void AuraEffect::HandleManaShield(bool apply, bool Real, bool changeAmount)
switch(m_spellProto->SpellFamilyName)
{
case SPELLFAMILY_MAGE:
- if(m_spellProto->SpellFamilyFlags[0] & 0x8000)
+ if(m_spellProto->SpellFamilyFlags[0] & 0x8000 && m_spellProto->SpellFamilyFlags[2] & 0x8)
{
// Mana Shield
// +50% from +spd bonus
@@ -7075,26 +6870,32 @@ void AuraEffect::HandleAuraConvertRune(bool apply, bool Real, bool /*changeAmoun
if(plr->getClass() != CLASS_DEATH_KNIGHT)
return;
- // how to determine what rune need to be converted?
- for(uint32 i = 0; i < MAX_RUNES; ++i)
+ uint32 runes = 0;
+ // convert number of runes specified in aura amount of rune type in miscvalue to runetype in miscvalueb
+ for(uint32 i = 0; i < MAX_RUNES && m_amount; ++i)
{
if(apply)
{
+ if (GetMiscValue() != plr->GetCurrentRune(i))
+ continue;
if(!plr->GetRuneCooldown(i))
{
plr->ConvertRune(i, GetSpellProto()->EffectMiscValueB[m_effIndex]);
- break;
+ runes |= 1<<i;
+ --m_amount;
}
}
else
{
if(plr->GetCurrentRune(i) == GetSpellProto()->EffectMiscValueB[m_effIndex])
{
- plr->ConvertRune(i, plr->GetBaseRune(i));
- break;
+ if (m_amount & (1<<i))
+ plr->ConvertRune(i, plr->GetBaseRune(i));
}
}
}
+ if (apply)
+ m_amount = runes;
}
// Control Auras
@@ -7130,12 +6931,7 @@ void AuraEffect::HandleModPossess(bool apply, bool Real, bool /*changeAmount*/)
}
if(apply)
- {
- if(m_target->getLevel() > m_amount)
- return;
-
m_target->SetCharmedBy(caster, CHARM_TYPE_POSSESS);
- }
else
m_target->RemoveCharmedBy(caster);
}
@@ -7153,7 +6949,6 @@ void AuraEffect::HandleModPossessPet(bool apply, bool Real, bool /*changeAmount*
{
if(caster->GetGuardianPet() != m_target)
return;
-
m_target->SetCharmedBy(caster, CHARM_TYPE_POSSESS);
}
else
@@ -7164,7 +6959,7 @@ void AuraEffect::HandleModPossessPet(bool apply, bool Real, bool /*changeAmount*
((Player*)caster)->PetSpellInitialize();
if(!m_target->getVictim())
{
- m_target->GetMotionMaster()->MoveFollow(caster, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
+ m_target->GetMotionMaster()->MoveFollow(caster, PET_FOLLOW_DIST, m_target->GetFollowAngle());
m_target->GetCharmInfo()->SetCommandState(COMMAND_FOLLOW);
}
}
@@ -7178,12 +6973,7 @@ void AuraEffect::HandleModCharm(bool apply, bool Real, bool /*changeAmount*/)
Unit* caster = GetCaster();
if(apply)
- {
- if(m_amount && int32(m_target->getLevel()) > m_amount)
- return;
-
m_target->SetCharmedBy(caster, CHARM_TYPE_CHARM);
- }
else
m_target->RemoveCharmedBy(caster);
}
@@ -7196,12 +6986,7 @@ void AuraEffect::HandleCharmConvert(bool apply, bool Real, bool /*changeAmount*/
Unit* caster = GetCaster();
if(apply)
- {
- if(m_amount && int32(m_target->getLevel()) > m_amount)
- return;
-
m_target->SetCharmedBy(caster, CHARM_TYPE_CONVERT);
- }
else
m_target->RemoveCharmedBy(caster);
}
@@ -7268,7 +7053,7 @@ void AuraEffect::HandleAuraSafeFall( bool Apply, bool Real , bool /*changeAmount
{
// implemented in WorldSession::HandleMovementOpcodes
- // only special case
+ // Buffeting Winds of Susurrus - only special case
if(Apply && Real && GetId()==32474 && m_target->GetTypeId()==TYPEID_PLAYER)
((Player*)m_target)->ActivateTaxiPathTo(506,GetId());
}
@@ -7286,12 +7071,13 @@ void AuraEffect::HandleReflectSpells( bool Apply, bool Real , bool /*changeAmoun
// implemented in Unit::SpellHitResult
// only special case
- if(!Apply && Real && m_spellProto->SpellFamilyName == SPELLFAMILY_WARRIOR && m_spellProto->SpellFamilyFlags[1] & 0x2)
+ if(!Apply && Real && GetParentAura()->GetRemoveMode() != AURA_REMOVE_BY_DEFAULT
+ && m_spellProto->SpellFamilyName == SPELLFAMILY_WARRIOR && m_spellProto->SpellFamilyFlags[1] & 0x2)
{
if (Unit * caster = GetCaster())
{
// Improved Spell Reflection
- if (caster->GetDummyAura(SPELLFAMILY_WARRIOR,1935))
+ if (caster->GetDummyAura(SPELLFAMILY_WARRIOR,1935, 1))
{
// aura remove - remove auras from all party members
std::list<Unit*> PartyMembers;
@@ -7305,4 +7091,98 @@ void AuraEffect::HandleReflectSpells( bool Apply, bool Real , bool /*changeAmoun
}
}
}
+void AuraEffect::HandleAuraInitializeImages( bool Apply, bool Real , bool /*changeAmount*/)
+{
+ if (!Real)
+ return;
+ if (Apply)
+ {
+ Unit * caster = GetCaster();
+ if (!caster)
+ return;
+ // Set item visual
+ if (caster->GetTypeId()== TYPEID_PLAYER)
+ {
+ if (Item const * item = ((Player *)caster)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND))
+ m_target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, item->GetProto()->ItemId);
+ if (Item const * item = ((Player *)caster)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND))
+ m_target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, item->GetProto()->ItemId);
+ }
+ else // TYPEID_UNIT
+ {
+ m_target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, caster->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID));
+ m_target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, caster->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1));
+ m_target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, caster->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2));
+ }
+ }
+ else
+ {
+ // Remove equipment visual
+ if (m_target->GetTypeId() == TYPEID_PLAYER)
+ {
+ for (uint8 i = 0; i < 3; ++i)
+ m_target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i, 0);
+ }
+ else // TYPEID_UNIT
+ {
+ ((Creature*)m_target)->LoadEquipment(((Creature*)m_target)->GetEquipmentId());
+ }
+ }
+}
+
+void AuraEffect::HandleAuraCloneCaster( bool Apply, bool Real , bool /*changeAmount*/)
+{
+ if (!Real)
+ return;
+
+ if (Apply)
+ {
+ Unit * caster = GetCaster();
+ if (!caster)
+ return;
+ // Set display id (probably for portrait?)
+ m_target->SetDisplayId(caster->GetDisplayId());
+ m_target->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_MIRROR_IMAGE);
+ }
+ else
+ {
+ m_target->SetDisplayId(m_target->GetNativeDisplayId());
+ m_target->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_MIRROR_IMAGE);
+ }
+}
+
+int32 AuraEffect::CalculateCrowdControlAuraAmount(Unit * caster)
+{
+ // Damage cap for CC effects
+ if (!m_spellProto->procFlags)
+ return 0;
+
+ if (m_auraName !=SPELL_AURA_MOD_CONFUSE &&
+ m_auraName !=SPELL_AURA_MOD_FEAR &&
+ m_auraName !=SPELL_AURA_MOD_STUN &&
+ m_auraName !=SPELL_AURA_MOD_ROOT &&
+ m_auraName !=SPELL_AURA_TRANSFORM)
+ return 0;
+
+ int32 damageCap = (int32)(m_target->GetMaxHealth()*0.10f);
+
+ if (!caster)
+ return damageCap;
+
+ // Glyphs increasing damage cap
+ Unit::AuraEffectList const& overrideClassScripts = caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
+ for(Unit::AuraEffectList::const_iterator itr = overrideClassScripts.begin();itr != overrideClassScripts.end(); ++itr)
+ {
+ if((*itr)->isAffectedOnSpell(m_spellProto))
+ {
+ // Glyph of Fear, Glyph of Frost nova and similar auras
+ if ((*itr)->GetMiscValue() == 7801)
+ {
+ damageCap += (int32)(damageCap*(*itr)->GetAmount()/100.0f);
+ break;
+ }
+ }
+ }
+ return damageCap;
+}
diff --git a/src/game/SpellAuras.h b/src/game/SpellAuras.h
index 987c8b0db25..6a1c11e49c9 100644
--- a/src/game/SpellAuras.h
+++ b/src/game/SpellAuras.h
@@ -84,8 +84,6 @@ class TRINITY_DLL_SPEC Aura
int8 GetStackAmount() const {return m_stackAmount;}
void SetStackAmount(uint8 num, bool applied = true);
bool modStackAmount(int32 num); // return true if last charge dropped
- uint32 GetAuraStateMask(){return m_auraStateMask;}
- void SetAuraState(uint8 num){m_auraStateMask |= 1<<(num-1);} //modifies auras' aura state (not unit!)
void SetRemoveMode(AuraRemoveMode mode) { m_removeMode = mode; }
uint8 GetRemoveMode() const {return m_removeMode;}
@@ -119,6 +117,7 @@ class TRINITY_DLL_SPEC Aura
m_target->HandleAuraEffect(m_partAuras[i], apply);
}
void ApplyAllModifiers(bool apply, bool Real=false);
+ void HandleAuraSpecificMods(bool apply);
void Update(uint32 diff);
@@ -153,7 +152,6 @@ class TRINITY_DLL_SPEC Aura
uint8 m_auraLevel; // Aura level (store caster level for correct show level dep amount)
uint8 m_procCharges; // Aura charges (0 for infinite)
uint8 m_stackAmount; // Aura stack amount
- uint32 m_auraStateMask;
AuraEffect * m_partAuras[3];
uint32 m_procDamage; // used in aura proc code
@@ -334,6 +332,10 @@ class TRINITY_DLL_SPEC AuraEffect
void HandleCharmConvert(bool apply, bool Real, bool changeAmount);
void HandleReflectSpells( bool Apply, bool Real , bool changeAmount);
void HandleModArmorPenetrationPct(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraInitializeImages(bool Apply, bool Real, bool changeAmount);
+ void HandleAuraCloneCaster(bool Apply, bool Real, bool changeAmount);
+
+ int32 CalculateCrowdControlAuraAmount(Unit * caster);
// add/remove SPELL_AURA_MOD_SHAPESHIFT (36) linked auras
void HandleShapeshiftBoosts(bool apply);
@@ -348,9 +350,12 @@ class TRINITY_DLL_SPEC AuraEffect
uint32 GetEffIndex() const { return m_effIndex; }
int32 GetBasePoints() const { return m_currentBasePoints; }
int32 GetAuraAmplitude(){return m_amplitude;}
+ void ResetPeriodicTimer(){m_periodicTimer = m_amplitude;}
+
virtual void Update(uint32 diff);
uint32 GetTickNumber() const { return m_tickNumber; }
+ int32 GetTotalTicks () const { return m_amplitude ? (GetParentAura()->GetAuraMaxDuration() / m_amplitude) : 1;}
bool IsAreaAura() const { return m_isAreaAura; }
bool IsPeriodic() const { return m_isPeriodic; }
bool IsPersistent() const { return m_isPersistent; }
diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp
index 6d1c986d7b2..f68488e538b 100644
--- a/src/game/SpellEffects.cpp
+++ b/src/game/SpellEffects.cpp
@@ -123,7 +123,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
&Spell::EffectSummonPet, // 56 SPELL_EFFECT_SUMMON_PET
&Spell::EffectLearnPetSpell, // 57 SPELL_EFFECT_LEARN_PET_SPELL
&Spell::EffectWeaponDmg, // 58 SPELL_EFFECT_WEAPON_DAMAGE
- &Spell::EffectOpenSecretSafe, // 59 SPELL_EFFECT_OPEN_LOCK_ITEM
+ &Spell::EffectCreateRandomItem, // 59 SPELL_EFFECT_CREATE_RANDOM_ITEM create item base at spell specific loot
&Spell::EffectProficiency, // 60 SPELL_EFFECT_PROFICIENCY
&Spell::EffectSendEvent, // 61 SPELL_EFFECT_SEND_EVENT
&Spell::EffectPowerBurn, // 62 SPELL_EFFECT_POWER_BURN
@@ -196,7 +196,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
&Spell::EffectApplyAreaAura, //129 SPELL_EFFECT_APPLY_AREA_AURA_ENEMY
&Spell::EffectRedirectThreat, //130 SPELL_EFFECT_REDIRECT_THREAT
&Spell::EffectUnused, //131 SPELL_EFFECT_131 used in some test spells
- &Spell::EffectNULL, //132 SPELL_EFFECT_PLAY_MUSIC sound id in misc value (SoundEntries.dbc)
+ &Spell::EffectPlayMusic, //132 SPELL_EFFECT_PLAY_MUSIC sound id in misc value (SoundEntries.dbc)
&Spell::EffectUnlearnSpecialization, //133 SPELL_EFFECT_UNLEARN_SPECIALIZATION unlearn profession specialization
&Spell::EffectKillCredit, //134 SPELL_EFFECT_KILL_CREDIT misc value is creature entry
&Spell::EffectNULL, //135 SPELL_EFFECT_CALL_PET
@@ -213,7 +213,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
&Spell::EffectActivateRune, //146 SPELL_EFFECT_ACTIVATE_RUNE
&Spell::EffectQuestFail, //147 SPELL_EFFECT_QUEST_FAIL quest fail
&Spell::EffectUnused, //148 SPELL_EFFECT_148 unused
- &Spell::EffectNULL, //149 SPELL_EFFECT_149 swoop
+ &Spell::EffectCharge2, //149 SPELL_EFFECT_CHARGE2 swoop
&Spell::EffectUnused, //150 SPELL_EFFECT_150 unused
&Spell::EffectTriggerRitualOfSummoning, //151 SPELL_EFFECT_TRIGGER_SPELL_2
&Spell::EffectNULL, //152 SPELL_EFFECT_152 summon Refer-a-Friend
@@ -221,7 +221,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
&Spell::EffectNULL, //154 unused
&Spell::EffectTitanGrip, //155 SPELL_EFFECT_TITAN_GRIP Allows you to equip two-handed axes, maces and swords in one hand, but you attack $49152s1% slower than normal.
&Spell::EffectEnchantItemPrismatic, //156 SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC
- &Spell::EffectCreateItem2, //157 SPELL_EFFECT_CREATE_ITEM_2 create/learn item/spell for profession
+ &Spell::EffectCreateItem2, //157 SPELL_EFFECT_CREATE_ITEM_2 create item or create item template and replace by some randon spell loot item
&Spell::EffectMilling, //158 SPELL_EFFECT_MILLING milling
&Spell::EffectRenamePet, //159 SPELL_EFFECT_ALLOW_RENAME_PET allow rename pet once again
&Spell::EffectNULL, //160 SPELL_EFFECT_160 unused
@@ -315,18 +315,14 @@ void Spell::EffectSchoolDMG(uint32 effect_idx)
void Spell::SpellDamageSchoolDmg(uint32 effect_idx)
{
+ bool apply_direct_bonus=true;
+
if( unitTarget && unitTarget->isAlive())
{
switch(m_spellInfo->SpellFamilyName)
{
case SPELLFAMILY_GENERIC:
{
- //Gore
- if(m_spellInfo->SpellIconID == 2269 )
- {
- damage += (rand()%2 ? damage : 0);
- }
-
// Meteor like spells (divided damage to targets)
if(m_customAttr & SPELL_ATTR_CU_SHARE_DAMAGE)
{
@@ -390,13 +386,6 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx)
damage = 200;
break;
}
- // Intercept (warrior spell trigger)
- case 20253:
- case 61491:
- {
- damage+= uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.12f);
- break;
- }
// arcane charge. must only affect demons (also undead?)
case 45072:
{
@@ -430,9 +419,7 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx)
{
// Bloodthirst
if(m_spellInfo->SpellFamilyFlags[1] & 0x400)
- {
damage = uint32(damage * (m_caster->GetTotalAttackPowerValue(BASE_ATTACK)) / 100);
- }
// Shield Slam
else if(m_spellInfo->SpellFamilyFlags[1] & 0x200 && m_spellInfo->Category==1209)
damage += int32(m_caster->GetShieldBlockValue());
@@ -442,12 +429,6 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx)
damage = uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
m_caster->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, false);
}
- // Revenge ${$m1+$AP*0.207} to ${$M1+$AP*0.207}
- else if(m_spellInfo->SpellFamilyFlags[0] & 0x400)
- damage+= uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.207f);
- // Heroic Throw ${$m1+$AP*.50}
- else if(m_spellInfo->SpellFamilyFlags[1] & 0x00000001)
- damage+= uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.5f);
// Shockwave ${$m3/100*$AP}
else if(m_spellInfo->SpellFamilyFlags[1] & 0x00008000)
{
@@ -456,12 +437,6 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx)
damage+= int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * pct / 100);
break;
}
- // Thunder Clap
- else if(m_spellInfo->SpellFamilyFlags[0] & 0x80)
- {
- damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 12 / 100);
- break;
- }
break;
}
case SPELLFAMILY_WARLOCK:
@@ -469,26 +444,51 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx)
// Incinerate Rank 1 & 2
if((m_spellInfo->SpellFamilyFlags[1] & 0x000040) && m_spellInfo->SpellIconID==2128)
{
- // Incinerate does more dmg (dmg*0.25) if the target is Immolated.
- if(unitTarget->HasAuraState(AURA_STATE_IMMOLATE, m_spellInfo, m_caster))
- damage += int32(damage*0.25f);
+ // Incinerate does more dmg (dmg*0.25) if the target have Immolate debuff.
+ // Check aura state for speed but aura state set not only for Immolate spell
+ if(unitTarget->HasAuraState(AURA_STATE_CONFLAGRATE))
+ {
+ if (unitTarget->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_WARLOCK, 0x4))
+ damage += damage/4;
+ }
}
- // Conflagrate - consumes immolate
- else if (m_spellInfo->TargetAuraState == AURA_STATE_IMMOLATE)
+ // Conflagrate - consumes Immolate or Shadowflame
+ else if (m_spellInfo->TargetAuraState == AURA_STATE_CONFLAGRATE)
{
- // Glyph of Conflagrate
- if (m_caster->HasAura(56235))
- break;
- // for caster applied auras only
+ AuraEffect const* aura = NULL; // found req. aura for damage calculation
+
Unit::AuraEffectList const &mPeriodic = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
for(Unit::AuraEffectList::const_iterator i = mPeriodic.begin(); i != mPeriodic.end(); ++i)
{
- if( (*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && ((*i)->GetSpellProto()->SpellFamilyFlags[0] & 4 || (*i)->GetSpellProto()->SpellFamilyFlags[2] & 2) &&
- (*i)->GetCasterGUID()==m_caster->GetGUID() )
+ // for caster applied auras only
+ if ((*i)->GetSpellProto()->SpellFamilyName != SPELLFAMILY_WARLOCK ||
+ (*i)->GetCasterGUID()!=m_caster->GetGUID())
+ continue;
+
+ // Immolate
+ if ((*i)->GetSpellProto()->SpellFamilyFlags[0] & 0x4)
{
- unitTarget->RemoveAurasDueToSpell((*i)->GetId(), m_caster->GetGUID());
+ aura = *i; // it selected always if exist
break;
}
+
+ // Shadowflame
+ if ((*i)->GetSpellProto()->SpellFamilyFlags[2] & 0x00000002)
+ aura = *i; // remember but wait possible Immolate as primary priority
+ }
+
+ // found Immolate or Shadowflame
+ if (aura)
+ {
+ uint32 pdamage = aura->GetAmount() > 0 ? aura->GetAmount() : 0;
+ pdamage = m_caster->SpellDamageBonus(unitTarget, aura->GetSpellProto(), pdamage, DOT, aura->GetParentAura()->GetStackAmount());
+ damage += pdamage * 4; // 4 ticks of 3 seconds = 12 secs
+ apply_direct_bonus = false;
+ // Glyph of Conflagrate
+ if (!m_caster->HasAura(56235))
+ unitTarget->RemoveAurasDueToSpell(aura->GetId(), m_caster->GetGUID());
+
+ break;
}
}
// Shadow Bite
@@ -517,31 +517,9 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx)
// converts each extra point of energy into ($f1+$AP/410) additional damage
float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
float multiple = ap / 410 + m_spellInfo->DmgMultiplier[effect_idx];
- damage += int32(m_caster->GetPower(POWER_ENERGY) * multiple);
+ int32 energy = -(m_caster->ModifyPower(POWER_ENERGY, -30));
+ damage += int32(energy * multiple);
damage += int32(((Player*)m_caster)->GetComboPoints() * ap * 7 / 100);
- m_caster->SetPower(POWER_ENERGY,0);
- }
- // Rake
- else if(m_spellInfo->SpellFamilyFlags[0] & 0x1000)
- {
- damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
- }
- // Swipe
- else if(m_spellInfo->SpellFamilyFlags[1] & 0x00100000)
- {
- damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.08f);
- }
- //Mangle Bonus for the initial damage of Lacerate and Rake
- if((m_spellInfo->SpellFamilyFlags.IsEqual(0x1000,0,0) && m_spellInfo->SpellIconID==494) ||
- (m_spellInfo->SpellFamilyFlags.IsEqual(0,0x100,0) && m_spellInfo->SpellIconID==2246))
- {
- Unit::AuraEffectList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
- for(Unit::AuraEffectList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
- if((*i)->GetSpellProto()->SpellFamilyFlags[1] & 0x00000440 && (*i)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_DRUID)
- {
- damage = int32(damage*(100.0f+(*i)->GetAmount())/100.0f);
- break;
- }
}
break;
}
@@ -553,22 +531,13 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx)
// consume from stack dozes not more that have combo-points
if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
{
- Aura *poison = 0;
// Lookup for Deadly poison (only attacker applied)
- Unit::AuraEffectList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
- for(Unit::AuraEffectList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
- if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_ROGUE &&
- (*itr)->GetSpellProto()->SpellFamilyFlags[0] & 0x10000 &&
- (*itr)->GetCasterGUID()==m_caster->GetGUID() )
- {
- poison = (*itr)->GetParentAura();
- break;
- }
- // count consumed deadly poison doses at target
- if (poison)
+ if (AuraEffect const * aurEff = unitTarget->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_ROGUE, 0x10000, 0, 0, m_caster->GetGUID()))
{
- uint32 spellId = poison->GetId();
- uint32 doses = poison->GetStackAmount();
+ // count consumed deadly poison doses at target
+ Aura *poison = 0;
+ uint32 spellId = aurEff->GetId();
+ uint32 doses = aurEff->GetParentAura()->GetStackAmount();
if (doses > combo)
doses = combo;
for (int i=0; i< doses; i++)
@@ -577,7 +546,7 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx)
damage += int32(((Player*)m_caster)->GetTotalAttackPowerValue(BASE_ATTACK) * 0.03f * doses);
}
// Eviscerate and Envenom Bonus Damage (item set effect)
- if(m_caster->GetDummyAura(37169))
+ if(m_caster->HasAura(37169))
damage += ((Player*)m_caster)->GetComboPoints()*40;
}
}
@@ -590,52 +559,24 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx)
damage += irand(int32(ap * combo * 0.03f), int32(ap * combo * 0.07f));
// Eviscerate and Envenom Bonus Damage (item set effect)
- if(m_caster->GetDummyAura(37169))
+ if(m_caster->HasAura(37169))
damage += combo*40;
}
}
- // Gouge
- else if(m_spellInfo->SpellFamilyFlags[0] & 0x8)
- {
- damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.21f);
- }
- // Instant Poison
- else if(m_spellInfo->SpellFamilyFlags[0] & 0x2000)
- {
- damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.10f);
- }
- // Wound Poison
- else if(m_spellInfo->SpellFamilyFlags[0] & 0x10000000)
- {
- damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.04f);
- }
break;
}
case SPELLFAMILY_HUNTER:
{
- // Mongoose Bite
- if((m_spellInfo->SpellFamilyFlags[0] & 0x2) && m_spellInfo->SpellVisual[0]==342)
- {
- damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
- }
- // Counterattack
- else if(m_spellInfo->SpellFamilyFlags[1] & 0x00080000)
- {
- damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
- }
- // Arcane Shot
- else if((m_spellInfo->SpellFamilyFlags[0] & 0x00000800) && m_spellInfo->maxLevel > 0)
+ //Gore
+ if (m_spellInfo->SpellIconID == 1578)
{
- damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.15f);
+ if (m_caster->HasAura(57627)) // Charge 6 sec post-affect
+ damage *= 2;
}
// Steady Shot
else if(m_spellInfo->SpellFamilyFlags[1] & 0x1)
{
- int32 base = irand((int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MINDAMAGE),(int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MAXDAMAGE));
- damage += int32(float(base)/m_caster->GetAttackTime(RANGED_ATTACK)*2800 + m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.1f);
-
bool found = false;
-
// check dazed affect
Unit::AuraEffectList const& decSpeedList = unitTarget->GetAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
for(Unit::AuraEffectList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter)
@@ -651,29 +592,12 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx)
if(found)
damage += m_spellInfo->EffectBasePoints[1];
}
- // Explosive Trap Effect
- else if(m_spellInfo->SpellFamilyFlags[0] & 0x00000004)
- {
- damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.1f);
- }
break;
}
case SPELLFAMILY_PALADIN:
{
- // Avenger's Shield ($m1+0.07*$SPH+0.07*$AP)
- if(m_spellInfo->SpellFamilyFlags[0] & 0x4000)
- {
- float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
- damage += int32(ap * 0.07f);
- }
- // Hammer of Wrath ($m1+0.15*$SPH+0.15*$AP)
- else if(m_spellInfo->SpellFamilyFlags[1] & 0x00000080)
- {
- float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
- damage += int32(ap * 0.15f);
- }
// Hammer of the Righteous
- else if(m_spellInfo->SpellFamilyFlags[1]&0x00040000)
+ if(m_spellInfo->SpellFamilyFlags[1]&0x00040000)
{
// Add main hand dps * effect[2] amount
float average = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE)) / 2;
@@ -683,13 +607,23 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx)
// Shield of Righteousness
else if(m_spellInfo->SpellFamilyFlags[1]&0x00100000)
{
- damage+=int32(m_caster->GetShieldBlockValue());
+ damage += int32(m_caster->GetShieldBlockValue() * 1.3f);
+ }
+ break;
+ }
+ case SPELLFAMILY_DEATHKNIGHT:
+ {
+ // Blood Boil - bonus for diseased targets
+ if (m_spellInfo->SpellFamilyFlags[0] & 0x00040000 && unitTarget->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DEATHKNIGHT, 0, 0, 0x00000002, m_caster->GetGUID()))
+ {
+ damage += m_damage / 2;
+ damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)* 0.035f);
}
break;
}
}
- if(m_originalCaster && damage > 0)
+ if(m_originalCaster && damage > 0 && apply_direct_bonus)
damage = m_originalCaster->SpellDamageBonus(unitTarget, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE);
m_damage += damage;
@@ -740,14 +674,11 @@ void Spell::EffectDummy(uint32 i)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || ((Creature*)unitTarget)->isPet()) return;
- Creature* creatureTarget = (Creature*)unitTarget;
GameObject* pGameObj = new GameObject;
- if (!creatureTarget || !pGameObj) return;
-
- if (!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), 181574, creatureTarget->GetMap(), creatureTarget->GetPhaseMask(),
- creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(),
- creatureTarget->GetOrientation(), 0, 0, 0, 0, 100, GO_STATE_READY))
+ if (!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), 181574, unitTarget->GetMap(), unitTarget->GetPhaseMask(),
+ unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(),
+ unitTarget->GetOrientation(), 0, 0, 0, 0, 100, GO_STATE_READY))
{
delete pGameObj;
return;
@@ -758,7 +689,7 @@ void Spell::EffectDummy(uint32 i)
//pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel());
pGameObj->SetSpellId(m_spellInfo->Id);
- MapManager::Instance().GetMap(creatureTarget->GetMapId(), pGameObj)->Add(pGameObj);
+ unitTarget->GetMap()->Add(pGameObj);
WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
data << uint64(pGameObj->GetGUID());
@@ -841,15 +772,24 @@ void Spell::EffectDummy(uint32 i)
switch (m_spellInfo->Id)
{
- case 12850: damage *= 0.2f; break;
- case 12162: damage *= 0.4f; break;
- case 12868: damage *= 0.6f; break;
+ case 12162: damage *= 0.16f; break; // Rank 1
+ case 12850: damage *= 0.32f; break; // Rank 2
+ case 12868: damage *= 0.48f; break; // Rank 3
default:
sLog.outError("Spell::EffectDummy: Spell %u not handled in DW",m_spellInfo->Id);
return;
};
- int32 deepWoundsDotBasePoints0 = int32(damage / 4);
+ // get remaining damage of old Deep Wound aura
+ AuraEffect* deepWound = unitTarget->GetAuraEffect(12721, 0);
+ if(deepWound)
+ {
+ int32 remainingTicks = deepWound->GetParentAura()->GetAuraDuration() / deepWound->GetAuraAmplitude();
+ damage += remainingTicks * deepWound->GetAmount();
+ }
+
+ // 1 tick/sec * 6 sec = 6 ticks
+ int32 deepWoundsDotBasePoints0 = int32(damage / 6);
m_caster->CastCustomSpell(unitTarget, 12721, &deepWoundsDotBasePoints0, NULL, NULL, true, NULL);
return;
}
@@ -895,9 +835,7 @@ void Spell::EffectDummy(uint32 i)
if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
- Creature* creatureTarget = (Creature*)unitTarget;
-
- creatureTarget->ForcedDespawn();
+ ((Creature*)unitTarget)->ForcedDespawn();
return;
}
case 16589: // Noggenfogger Elixir
@@ -934,7 +872,9 @@ void Spell::EffectDummy(uint32 i)
if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
return;
- uint32 spell_id = roll_chance_i(50) ? 17269 : 17270;
+ uint32 spell_id = roll_chance_i(50)
+ ? 17269 // Create Resonating Skull
+ : 17270; // Create Bone Dust
m_caster->CastSpell(m_caster, spell_id, true, NULL);
return;
@@ -949,8 +889,6 @@ void Spell::EffectDummy(uint32 i)
return;
Creature* creatureTarget = (Creature*)unitTarget;
- if(creatureTarget->isPet())
- return;
GameObject* Crystal_Prison = m_caster->SummonGameObject(179644, creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(), creatureTarget->GetOrientation(), 0, 0, 0, 0, creatureTarget->GetRespawnTime()-time(NULL));
sLog.outDebug("SummonGameObject at SpellEfects.cpp EffectDummy for Spell 23019");
@@ -979,25 +917,25 @@ void Spell::EffectDummy(uint32 i)
if (!m_CastItem) return;
m_caster->CastSpell(m_caster, 13166, true, m_CastItem);
return;
- case 23448: // Ultrasafe Transporter: Gadgetzan - backfires
+ case 23448: // Transporter Arrival - Ultrasafe Transporter: Gadgetzan - backfires
{
int32 r = irand(0, 119);
- if ( r < 20 ) // 1/6 polymorph
+ if ( r < 20 ) // Transporter Malfunction - 1/6 polymorph
m_caster->CastSpell(m_caster, 23444, true);
- else if ( r < 100 ) // 4/6 evil twin
+ else if ( r < 100 ) // Evil Twin - 4/6 evil twin
m_caster->CastSpell(m_caster, 23445, true);
- else // 1/6 miss the target
+ else // Transporter Malfunction - 1/6 miss the target
m_caster->CastSpell(m_caster, 36902, true);
return;
}
- case 23453: // Ultrasafe Transporter: Gadgetzan
- if ( roll_chance_i(50) ) // success
+ case 23453: // Gnomish Transporter - Ultrasafe Transporter: Gadgetzan
+ if ( roll_chance_i(50) ) // Gadgetzan Transporter - success
m_caster->CastSpell(m_caster, 23441, true);
- else // failure
+ else // Gadgetzan Transporter Failure - failure
m_caster->CastSpell(m_caster, 23446, true);
return;
case 23645: // Hourglass Sand
- m_caster->RemoveAurasDueToSpell(23170);
+ m_caster->RemoveAurasDueToSpell(23170); // Brood Affliction: Bronze
return;
case 23725: // Gift of Life (warrior bwl trinket)
m_caster->CastSpell(m_caster, 23782, true);
@@ -1015,23 +953,30 @@ void Spell::EffectDummy(uint32 i)
//5 different spells used depending on mounted speed and if mount can fly or not
if (flyspeed >= 4.1f)
+ // Flying Reindeer
m_caster->CastSpell(m_caster, 44827, true); //310% flying Reindeer
else if (flyspeed >= 3.8f)
+ // Flying Reindeer
m_caster->CastSpell(m_caster, 44825, true); //280% flying Reindeer
else if (flyspeed >= 1.6f)
+ // Flying Reindeer
m_caster->CastSpell(m_caster, 44824, true); //60% flying Reindeer
else if (speed >= 2.0f)
+ // Reindeer
m_caster->CastSpell(m_caster, 25859, true); //100% ground Reindeer
else
+ // Reindeer
m_caster->CastSpell(m_caster, 25858, true); //60% ground Reindeer
return;
}
- //case 26074: // Holiday Cheer
- // return; -- implemented at client side
+ case 26074: // Holiday Cheer
+ // implemented at client side
+ return;
case 28006: // Arcane Cloaking
{
if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER )
+ // Naxxramas Entry Flag Effect DND
m_caster->CastSpell(unitTarget, 29294, true);
return;
}
@@ -1050,7 +995,9 @@ void Spell::EffectDummy(uint32 i)
if( m_caster->GetTypeId() != TYPEID_PLAYER )
return;
- uint32 spell_id = roll_chance_i(50) ? 29277 : 29278;
+ uint32 spell_id = roll_chance_i(50)
+ ? 29277 // Summon Purified Helboar Meat
+ : 29278; // Summon Toxic Helboar Meat
m_caster->CastSpell(m_caster,spell_id,true,NULL);
return;
@@ -1062,26 +1009,19 @@ void Spell::EffectDummy(uint32 i)
return;
case 30458: // Nigh Invulnerability
if (!m_CastItem) return;
- if(roll_chance_i(86)) // success
+ if(roll_chance_i(86)) // Nigh-Invulnerability - success
m_caster->CastSpell(m_caster, 30456, true, m_CastItem);
- else // backfire in 14% casts
+ else // Complete Vulnerability - backfire in 14% casts
m_caster->CastSpell(m_caster, 30457, true, m_CastItem);
return;
case 30507: // Poultryizer
if (!m_CastItem) return;
- if(roll_chance_i(80)) // success
+ if(roll_chance_i(80)) // Poultryized! - success
m_caster->CastSpell(unitTarget, 30501, true, m_CastItem);
- else // backfire 20%
+ else // Poultryized! - backfire 20%
m_caster->CastSpell(unitTarget, 30504, true, m_CastItem);
return;
- case 55004: //Nitro Boosts
- if(!m_CastItem) return;
- if(roll_chance_i(95)) //success
- m_caster->CastSpell(m_caster, 54861, true, m_CastItem);
- else //backfire 5%
- m_caster->CastSpell(m_caster, 46014, true, m_CastItem);
- return;
- case 33060: // Make a Wish
+ case 33060: // Make a Wish
{
if(m_caster->GetTypeId()!=TYPEID_PLAYER)
return;
@@ -1090,23 +1030,23 @@ void Spell::EffectDummy(uint32 i)
switch(urand(1,5))
{
- case 1: spell_id = 33053; break;
- case 2: spell_id = 33057; break;
- case 3: spell_id = 33059; break;
- case 4: spell_id = 33062; break;
- case 5: spell_id = 33064; break;
+ case 1: spell_id = 33053; break; // Mr Pinchy's Blessing
+ case 2: spell_id = 33057; break; // Summon Mighty Mr. Pinchy
+ case 3: spell_id = 33059; break; // Summon Furious Mr. Pinchy
+ case 4: spell_id = 33062; break; // Tiny Magical Crawdad
+ case 5: spell_id = 33064; break; // Mr. Pinchy's Gift
}
m_caster->CastSpell(m_caster, spell_id, true, NULL);
return;
}
- case 35745:
+ case 35745: // Socrethar's Stone
{
uint32 spell_id;
switch(m_caster->GetAreaId())
{
- case 3900: spell_id = 35743; break;
- case 3742: spell_id = 35744; break;
+ case 3900: spell_id = 35743; break; // Socrethar Portal
+ case 3742: spell_id = 35744; break; // Socrethar Portal
default: return;
}
@@ -1171,9 +1111,7 @@ void Spell::EffectDummy(uint32 i)
if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
- Creature* creatureTarget = (Creature*)unitTarget;
-
- creatureTarget->ForcedDespawn();
+ ((Creature*)unitTarget)->ForcedDespawn();
//cast spell Raptor Capture Credit
m_caster->CastSpell(m_caster, 42337, true, NULL);
@@ -1181,33 +1119,15 @@ void Spell::EffectDummy(uint32 i)
}
case 34665: //Administer Antidote
{
- if(!unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER )
+ if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT
+ || unitTarget->GetEntry() != 16880 || ((Creature*)unitTarget)->isPet())
return;
- if(!unitTarget)
- return;
-
- TempSummon* tempSummon = dynamic_cast<TempSummon*>(unitTarget);
- if(!tempSummon)
- return;
-
- uint32 health = tempSummon->GetHealth();
+ ((Creature*)unitTarget)->UpdateEntry(16992);
+ ((Player*)m_caster)->RewardPlayerAndGroupAtEvent(16992, unitTarget);
- float x = tempSummon->GetPositionX();
- float y = tempSummon->GetPositionY();
- float z = tempSummon->GetPositionZ();
- float o = tempSummon->GetOrientation();
- tempSummon->UnSummon();
-
- Creature* pCreature = m_caster->SummonCreature(16992, x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,180000);
- if (!pCreature)
- return;
-
- pCreature->SetHealth(health);
- ((Player*)m_caster)->RewardPlayerAndGroupAtEvent(16992, pCreature);
-
- if (pCreature->IsAIEnabled)
- pCreature->AI()->AttackStart(m_caster);
+ if (unitTarget->IsAIEnabled)
+ ((Creature*)unitTarget)->AI()->AttackStart(m_caster);
return;
}
@@ -1223,6 +1143,13 @@ void Spell::EffectDummy(uint32 i)
m_caster->CastSpell(m_caster, 45088, true);
return;
}
+ case 55004: // Nitro Boosts
+ if(!m_CastItem) return;
+ if(roll_chance_i(95)) // Nitro Boosts - success
+ m_caster->CastSpell(m_caster, 54861, true, m_CastItem);
+ else // Knocked Up - backfire 5%
+ m_caster->CastSpell(m_caster, 46014, true, m_CastItem);
+ return;
case 50243: // Teach Language
{
if(m_caster->GetTypeId() != TYPEID_PLAYER)
@@ -1260,13 +1187,11 @@ void Spell::EffectDummy(uint32 i)
if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
- Creature* creatureTarget = (Creature*)unitTarget;
-
- creatureTarget->ForcedDespawn();
+ ((Creature*)unitTarget)->ForcedDespawn();
return;
}
- case 52308:
+ case 52308: // Take Sputum Sample
{
switch(i)
{
@@ -1289,15 +1214,31 @@ void Spell::EffectDummy(uint32 i)
return;
m_caster->CastCustomSpell(unitTarget, 52752, &damage, NULL, NULL, true);
return;
- case 53341:
- case 53343:
+ case 53341: // Rune of Cinderglacier
+ case 53343: // Rune of Razorice
{
+ // Runeforging Credit
m_caster->CastSpell(m_caster, 54586, true);
return;
}
case 58418: // Portal to Orgrimmar
case 58420: // Portal to Stormwind
return; // implemented in EffectScript[0]
+ case 59640: // Underbelly Elixir
+ {
+ if(m_caster->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ uint32 spell_id = 0;
+ switch(urand(1,3))
+ {
+ case 1: spell_id = 59645; break;
+ case 2: spell_id = 59831; break;
+ case 3: spell_id = 59843; break;
+ }
+ m_caster->CastSpell(m_caster,spell_id,true,NULL);
+ return;
+ }
}
//All IconID Check in there
@@ -1334,30 +1275,35 @@ void Spell::EffectDummy(uint32 i)
return;
// immediately finishes the cooldown on Frost spells
- const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
- for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
+ const SpellCooldowns& cm = ((Player *)m_caster)->GetSpellCooldownMap();
+ for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();)
{
- if (itr->second->state == PLAYERSPELL_REMOVED)
- continue;
-
- uint32 classspell = itr->first;
- SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
if( spellInfo->SpellFamilyName == SPELLFAMILY_MAGE &&
(GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) &&
spellInfo->Id != 11958 && GetSpellRecoveryTime(spellInfo) > 0 )
{
- ((Player*)m_caster)->RemoveSpellCooldown(classspell, true);
+ ((Player*)m_caster)->RemoveSpellCooldown((itr++)->first, true);
}
+ else
+ ++itr;
}
return;
}
- case 32826:
+ case 32826: // Polymorph Cast Visual
{
if ( unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT )
{
//Polymorph Cast Visual Rank 1
- const uint32 spell_list[6] = {32813, 32816, 32817, 32818, 32819, 32820};
+ const uint32 spell_list[6] = {
+ 32813, // Squirrel Form
+ 32816, // Giraffe Form
+ 32817, // Serpent Form
+ 32818, // Dragonhawk Form
+ 32819, // Worgen Form
+ 32820 // Sheep Form
+ };
unitTarget->CastSpell( unitTarget, spell_list[urand(0, 5)], true);
}
return;
@@ -1387,7 +1333,7 @@ void Spell::EffectDummy(uint32 i)
uint32 rage=0;
// Glyph of Execution bonus
- if (AuraEffect *aura = m_caster->GetDummyAura(58367))
+ if (AuraEffect *aura = m_caster->GetAuraEffect(58367, 0))
rage+=aura->GetAmount();
spell_id = 20647;
@@ -1407,7 +1353,7 @@ void Spell::EffectDummy(uint32 i)
}
bp = damage+int32(rage * m_spellInfo->DmgMultiplier[i] +
- m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
+ m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
break;
}
// Concussion Blow
@@ -1484,7 +1430,10 @@ void Spell::EffectDummy(uint32 i)
for(Unit::AuraEffectList::const_iterator itr = mod.begin(); itr != mod.end(); ++itr)
{
if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 1982)
- manaFeedVal+= (*itr)->GetAmount();
+ {
+ manaFeedVal = (*itr)->GetAmount();
+ break;
+ }
}
if(manaFeedVal > 0)
{
@@ -1517,9 +1466,9 @@ void Spell::EffectDummy(uint32 i)
return;
}
if (m_caster->IsFriendlyTo(unitTarget))
- m_caster->CastSpell(unitTarget, heal, true, 0);
+ m_caster->CastSpell(unitTarget, heal, false, 0);
else
- m_caster->CastSpell(unitTarget, hurt, true, 0);
+ m_caster->CastSpell(unitTarget, hurt, false, 0);
return;
}
break;
@@ -1587,20 +1536,21 @@ void Spell::EffectDummy(uint32 i)
m_caster->CastSpell(unitTarget, 5940, true);
return;
}
- case 14185: // Preparation Rogue
+ case 14185: // Preparation
{
if(m_caster->GetTypeId()!=TYPEID_PLAYER)
return;
//immediately finishes the cooldown on certain Rogue abilities
- const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
- for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
+ const SpellCooldowns& cm = ((Player *)m_caster)->GetSpellCooldownMap();
+ for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();)
{
- uint32 classspell = itr->first;
- SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags[1] & 0x00000240 || spellInfo->SpellFamilyFlags[0] & 0x00000860))
- ((Player*)m_caster)->RemoveSpellCooldown(classspell,true);
+ ((Player*)m_caster)->RemoveSpellCooldown((itr++)->first,true);
+ else
+ ++itr;
}
return;
}
@@ -1614,20 +1564,21 @@ void Spell::EffectDummy(uint32 i)
case SPELLFAMILY_HUNTER:
switch(m_spellInfo->Id)
{
- case 23989: //Readiness talent
+ case 23989: // Readiness talent
{
if(m_caster->GetTypeId()!=TYPEID_PLAYER)
return;
- //immediately finishes the cooldown for hunter abilities
- const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
- for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
+ // immediately finishes the cooldown on your other Hunter abilities except Bestial Wrath
+ const SpellCooldowns& cm = ((Player*)m_caster)->GetSpellCooldownMap();
+ for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();)
{
- uint32 classspell = itr->first;
- SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && GetSpellRecoveryTime(spellInfo) > 0 )
- ((Player*)m_caster)->RemoveSpellCooldown(classspell,true);
+ ((Player*)m_caster)->RemoveSpellCooldown((itr++)->first,true);
+ else
+ ++itr;
}
return;
}
@@ -1645,15 +1596,15 @@ void Spell::EffectDummy(uint32 i)
}
break;
case SPELLFAMILY_PALADIN:
+ // Divine Storm
+ if (m_spellInfo->SpellFamilyFlags[1] & 0x20000 && i == 1)
+ {
+ int32 dmg= m_damage * damage /100;
+ m_caster->CastCustomSpell(unitTarget, 54172, &dmg , 0, 0, true);
+ return;
+ }
switch(m_spellInfo->SpellIconID)
{
- // Divine Storm
- if (m_spellInfo->SpellFamilyFlags[1] & 0x20000)
- {
- int32 damage=m_currentBasePoints[0] * damage /100;
- m_caster->CastCustomSpell(unitTarget, 54172, &damage , 0, 0, true);
- return;
- }
case 156: // Holy Shock
{
if(!unitTarget)
@@ -1771,8 +1722,8 @@ void Spell::EffectDummy(uint32 i)
}
break;
case SPELLFAMILY_SHAMAN:
- //Shaman Rockbiter Weapon
- if (m_spellInfo->SpellFamilyFlags.IsEqual(0x400000))
+ // Rockbiter Weapon
+ if (m_spellInfo->SpellFamilyFlags[0] & 0x400000)
{
// TODO: use expect spell for enchant (if exist talent)
// In 3.0.3 no mods present for rockbiter
@@ -1820,10 +1771,12 @@ void Spell::EffectDummy(uint32 i)
}
return;
}
- // Cleansing Totem
+ // Cleansing Totem Pulse
if(m_spellInfo->SpellFamilyFlags[0] & 0x04000000 && m_spellInfo->SpellIconID==1673)
{
- m_caster->CastSpell(unitTarget, 52025, true, 0, 0, m_originalCasterGUID);
+ int32 bp1 = 1;
+ // Cleansing Totem Effect
+ m_caster->CastCustomSpell(unitTarget, 52025, NULL, &bp1, NULL, true, NULL, NULL, m_originalCasterGUID);
return;
}
// Healing Stream Totem
@@ -1845,9 +1798,8 @@ void Spell::EffectDummy(uint32 i)
if(!unitTarget || unitTarget->getPowerType() != POWER_MANA)
return;
// Glyph of Mana Tide
- Unit *owner = m_caster->GetOwner();
- if (owner)
- if (AuraEffect *dummy = owner->GetDummyAura(55441))
+ if(Unit *owner = m_caster->GetOwner())
+ if (AuraEffect *dummy = owner->GetAuraEffect(55441, 0))
damage+=dummy->GetAmount();
// Regenerate 6% of Total Mana Every 3 secs
int32 EffectBasePoints0 = unitTarget->GetMaxPower(POWER_MANA) * damage / 100;
@@ -1862,6 +1814,7 @@ void Spell::EffectDummy(uint32 i)
Item *item = ((Player*)m_caster)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
if (item)
{
+ // Damage is increased by 25% if your off-hand weapon is enchanted with Flametongue.
if (m_caster->GetAura(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 0x200000))
{
m_damage += m_damage * damage / 100;
@@ -1871,12 +1824,27 @@ void Spell::EffectDummy(uint32 i)
}
break;
case SPELLFAMILY_DEATHKNIGHT:
- // Death strike dummy aura apply
- // Used to proc healing later
+ // Death strike
if (m_spellInfo->SpellFamilyFlags[0] & 0x00000010)
{
- spell_id=45469;
- m_caster->CastSpell(m_caster,spell_id,true);
+ uint32 count = 0;
+ Unit::AuraMap const& auras = unitTarget->GetAuras();
+ for(Unit::AuraMap::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
+ {
+ if(itr->second->GetSpellProto()->Dispel == DISPEL_DISEASE &&
+ itr->second->GetCasterGUID() == m_caster->GetGUID())
+ {
+ ++count;
+ // max. 15%
+ if(count == 3)
+ break;
+ }
+ }
+ int32 bp = count * m_caster->GetMaxHealth() * m_spellInfo->DmgMultiplier[0] / 100;
+ // Improved Death Strike
+ if (AuraEffect const * aurEff = m_caster->GetAuraEffect(SPELL_AURA_ADD_PCT_MODIFIER, SPELLFAMILY_DEATHKNIGHT, 2751, 0))
+ bp = bp * (m_caster->CalculateSpellDamage(aurEff->GetSpellProto(), 2, aurEff->GetSpellProto()->EffectBasePoints[2], m_caster) + 100.0f) / 100.0f;
+ m_caster->CastCustomSpell(m_caster, 45470, &bp, NULL, NULL, true);
return;
}
// Scourge Strike
@@ -1890,9 +1858,6 @@ void Spell::EffectDummy(uint32 i)
{
if(m_caster->IsFriendlyTo(unitTarget))
{
- if(unitTarget->GetCreatureType() != CREATURE_TYPE_UNDEAD)
- return;
-
int32 bp = damage * 1.5f;
m_caster->CastCustomSpell(unitTarget, 47633, &bp, NULL, NULL, true);
}
@@ -1912,7 +1877,10 @@ void Spell::EffectDummy(uint32 i)
// Death Grip
if(m_spellInfo->Id == 49560)
{
- unitTarget->CastSpell(m_caster, damage, true);
+ if (unitTarget->m_Vehicle)
+ unitTarget->m_Vehicle->CastSpell(m_caster, damage, true);
+ else
+ unitTarget->CastSpell(m_caster, damage, true);
return;
}
else if(m_spellInfo->Id == 46584) // Raise dead
@@ -1950,6 +1918,48 @@ void Spell::EffectDummy(uint32 i)
spell_id = m_currentBasePoints[0];
}
+ // Corpse Explosion
+ else if(m_spellInfo->SpellIconID == 1737)
+ {
+ // Dummy effect 1 is used only for targeting and damage amount
+ if (i!=0)
+ return;
+ int32 bp = 0;
+ // Living ghoul as a target
+ if (unitTarget->isAlive())
+ {
+ bp = unitTarget->GetMaxHealth()*0.25f;
+ }
+ // Some corpse
+ else
+ {
+ bp = damage;
+ }
+ m_caster->CastCustomSpell(unitTarget,m_spellInfo->CalculateSimpleValue(1),&bp,NULL,NULL,true);
+ // Corpse Explosion (Suicide)
+ unitTarget->CastCustomSpell(unitTarget,43999,&bp,NULL,NULL,true);
+ // Set corpse look
+ unitTarget->SetDisplayId(25537+urand(0,3));
+ }
+ // Runic Power Feed ( keeping Gargoyle alive )
+ else if (m_spellInfo->Id == 50524)
+ {
+ // No power, dismiss Gargoyle
+ if (m_caster->GetPower(POWER_RUNIC_POWER)<30)
+ m_caster->CastSpell((Unit*)NULL,50515,true);
+ else
+ m_caster->ModifyPower(POWER_RUNIC_POWER,-30);
+
+ return;
+ }
+ // Dismiss Gargoyle
+ else if (m_spellInfo->Id == 50515)
+ {
+ // FIXME: gargoyle should fly away
+ unitTarget->setDeathState(JUST_DIED);
+ m_caster->RemoveAurasDueToSpell(50514);
+ return;
+ }
break;
}
@@ -1971,7 +1981,7 @@ void Spell::EffectDummy(uint32 i)
}
// pet auras
- if(PetAura const* petSpell = spellmgr.GetPetAura(m_spellInfo->Id))
+ if(PetAura const* petSpell = spellmgr.GetPetAura(m_spellInfo->Id,i))
{
m_caster->AddPetAura(petSpell);
return;
@@ -2043,7 +2053,10 @@ void Spell::EffectForceCast(uint32 i)
return;
}
- unitTarget->CastSpell(unitTarget, spellInfo, true, NULL, NULL, m_originalCasterGUID);
+ if (damage)
+ unitTarget->CastCustomSpell(unitTarget, spellInfo->Id, &damage, NULL, NULL, true, NULL, NULL, m_originalCasterGUID);
+ else
+ unitTarget->CastSpell(unitTarget, spellInfo, true, NULL, NULL, m_originalCasterGUID);
}
void Spell::EffectTriggerSpell(uint32 i)
@@ -2053,7 +2066,16 @@ void Spell::EffectTriggerSpell(uint32 i)
// special cases
switch(triggered_spell_id)
{
- // Vanish
+ // Mirror Image
+ case 58832:
+ {
+ // Glyph of Mirror Image
+ if (m_caster->HasAura(63093))
+ m_caster->CastSpell(m_caster, 65047, true); // Mirror Image
+
+ break;
+ }
+ // Vanish (not exist)
case 18461:
{
m_caster->RemoveMovementImpairingAuras();
@@ -2114,7 +2136,8 @@ void Spell::EffectTriggerSpell(uint32 i)
// Brittle Armor - (need add max stack of 24575 Brittle Armor)
case 29284:
{
- const SpellEntry *spell = sSpellStore.LookupEntry(24575);
+ // Brittle Armor
+ SpellEntry const* spell = sSpellStore.LookupEntry(24575);
if (!spell)
return;
@@ -2125,7 +2148,8 @@ void Spell::EffectTriggerSpell(uint32 i)
// Mercurial Shield - (need add max stack of 26464 Mercurial Shield)
case 29286:
{
- const SpellEntry *spell = sSpellStore.LookupEntry(26464);
+ // Mercurial Shield
+ SpellEntry const* spell = sSpellStore.LookupEntry(26464);
if (!spell)
return;
@@ -2140,7 +2164,7 @@ void Spell::EffectTriggerSpell(uint32 i)
return;
}
// Cloak of Shadows
- case 35729 :
+ case 35729:
{
uint32 dispelMask = GetDispellMask(DISPEL_ALL);
Unit::AuraMap& Auras = m_caster->GetAuras();
@@ -2436,7 +2460,7 @@ void Spell::EffectUnlearnSpecialization( uint32 i )
_player->removeSpell(spellToUnlearn);
- sLog.outDebug( "Spell: Player %u have unlearned spell %u from NpcGUID: %u", _player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow() );
+ sLog.outDebug( "Spell: Player %u has unlearned spell %u from NpcGUID: %u", _player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow() );
}
void Spell::EffectPowerDrain(uint32 i)
@@ -2495,7 +2519,7 @@ void Spell::EffectSendEvent(uint32 EffectIndex)
we do not handle a flag dropping or clicking on flag in battleground by sendevent system
*/
sLog.outDebug("Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->EffectMiscValue[EffectIndex], m_spellInfo->Id);
- sWorld.ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, focusObject);
+ m_caster->GetMap()->ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, focusObject);
}
void Spell::EffectPowerBurn(uint32 i)
@@ -2569,12 +2593,11 @@ void Spell::SpellDamageHeal(uint32 /*i*/)
{
// Amount of heal - depends from stacked Holy Energy
int damageAmount = 0;
- Unit::AuraEffectList const& mDummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
- for(Unit::AuraEffectList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
- if((*i)->GetId() == 45062)
- damageAmount+=(*i)->GetAmount();
- if (damageAmount)
+ if (AuraEffect const * aurEff = m_caster->GetAuraEffect(45062, 0))
+ {
+ damageAmount+= aurEff->GetAmount();
m_caster->RemoveAurasDueToSpell(45062);
+ }
addhealth += damageAmount;
}
@@ -2587,7 +2610,7 @@ void Spell::SpellDamageHeal(uint32 /*i*/)
for(Unit::AuraEffectList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
{
if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID
- && ((*i)->GetSpellProto()->SpellFamilyFlags.IsEqual(0x40) || (*i)->GetSpellProto()->SpellFamilyFlags.IsEqual(0x10)) )
+ && (*i)->GetSpellProto()->SpellFamilyFlags[0] & 0x50)
{
if(!targetAura || (*i)->GetParentAura()->GetAuraDuration() < targetAura->GetParentAura()->GetAuraDuration())
targetAura = *i;
@@ -2607,18 +2630,17 @@ void Spell::SpellDamageHeal(uint32 /*i*/)
//It is said that talent bonus should not be included
int32 tickcount = 0;
- if(targetAura->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID)
- {
- switch(targetAura->GetSpellProto()->SpellFamilyFlags[0])
- {
- case 0x10: tickcount = 4; break; // Rejuvenation
- case 0x40: tickcount = 6; break; // Regrowth
- }
- }
+ // Rejuvenation
+ if (targetAura->GetSpellProto()->SpellFamilyFlags[0] & 0x10)
+ tickcount = 4;
+ // Regrowth
+ else // if (targetAura->GetSpellProto()->SpellFamilyFlags[0] & 0x40)
+ tickcount = 6;
+
addhealth += tickheal * tickcount;
// Glyph of Swiftmend
- if(!caster->GetDummyAura(54824))
+ if(!caster->HasAura(54824))
unitTarget->RemoveAura(targetAura->GetId(), targetAura->GetCasterGUID());
//addhealth += tickheal * tickcount;
@@ -2635,6 +2657,11 @@ void Spell::SpellDamageHeal(uint32 /*i*/)
unitTarget->RemoveAura(aurEff->GetParentAura());
}
}
+ // Death Pact - return pct of max health to caster
+ else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && m_spellInfo->SpellFamilyFlags[0] & 0x00080000)
+ {
+ addhealth = int32(caster->GetMaxHealth()*damage/100.0f);
+ }
else
addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, addhealth, HEAL);
@@ -2827,27 +2854,34 @@ void Spell::EffectCreateItem2(uint32 i)
Player* player = (Player*)m_caster;
uint32 item_id = m_spellInfo->EffectItemType[i];
- if(item_id)
- DoCreateItem(i, item_id);
+
+ DoCreateItem(i, item_id);
// special case: fake item replaced by generate using spell_loot_template
if(IsLootCraftingSpell(m_spellInfo))
{
- if(item_id)
- {
- if(!player->HasItemCount(item_id, 1))
- return;
+ if(!player->HasItemCount(item_id, 1))
+ return;
- // remove reagent
- uint32 count = 1;
- player->DestroyItemCount(item_id, count, true);
- }
+ // remove reagent
+ uint32 count = 1;
+ player->DestroyItemCount(item_id, count, true);
// create some random items
player->AutoStoreLoot(m_spellInfo->Id, LootTemplates_Spell);
}
}
+void Spell::EffectCreateRandomItem(uint32 i)
+{
+ if(m_caster->GetTypeId()!=TYPEID_PLAYER)
+ return;
+ Player* player = (Player*)m_caster;
+
+ // create some random items
+ player->AutoStoreLoot(m_spellInfo->Id, LootTemplates_Spell);
+}
+
void Spell::EffectPersistentAA(uint32 i)
{
float radius = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
@@ -2880,31 +2914,31 @@ void Spell::EffectEnergize(uint32 i)
Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
// Some level depends spells
- int multiplier = 0;
+ int level_multiplier = 0;
int level_diff = 0;
switch (m_spellInfo->Id)
{
- // Restore Energy
- case 9512:
+ case 9512: // Restore Energy
level_diff = m_caster->getLevel() - 40;
- multiplier = 2;
+ level_multiplier = 2;
break;
- // Blood Fury
- case 24571:
+ case 24571: // Blood Fury
level_diff = m_caster->getLevel() - 60;
- multiplier = 10;
+ level_multiplier = 10;
break;
- // Burst of Energy
- case 24532:
+ case 24532: // Burst of Energy
level_diff = m_caster->getLevel() - 60;
- multiplier = 4;
+ level_multiplier = 4;
break;
+ case 31930: // Judgements of the Wise
+ case 63375: // Improved Stormstrike
+ damage = damage * unitTarget->GetCreateMana() / 100;
default:
break;
}
if (level_diff > 0)
- damage -= multiplier * level_diff;
+ damage -= level_multiplier * level_diff;
if(damage < 0)
return;
@@ -2912,6 +2946,12 @@ void Spell::EffectEnergize(uint32 i)
if(unitTarget->GetMaxPower(power) == 0)
return;
+ // Spells which use pct of max mana, but have wrong effect
+ if (m_spellInfo->Id == 48542)
+ {
+ damage = damage * unitTarget->GetMaxPower(power) / 100;
+ }
+
m_caster->EnergizeBySpell(unitTarget, m_spellInfo->Id, damage, power);
// Mad Alchemist's Potion
@@ -2993,7 +3033,7 @@ void Spell::SendLoot(uint64 guid, LootType loottype)
case GAMEOBJECT_TYPE_DOOR:
case GAMEOBJECT_TYPE_BUTTON:
gameObjTarget->UseDoorOrButton();
- sWorld.ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget);
+ player->GetMap()->ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget);
return;
case GAMEOBJECT_TYPE_QUESTGIVER:
@@ -3013,7 +3053,7 @@ void Spell::SendLoot(uint64 guid, LootType loottype)
if (gameObjTarget->GetGOInfo()->goober.eventId)
{
sLog.outDebug("Goober ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->goober.eventId,gameObjTarget->GetDBTableGUIDLow());
- sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->goober.eventId, player, gameObjTarget);
+ player->GetMap()->ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->goober.eventId, player, gameObjTarget);
gameObjTarget->EventInform(gameObjTarget->GetGOInfo()->goober.eventId);
}
@@ -3024,7 +3064,7 @@ void Spell::SendLoot(uint64 guid, LootType loottype)
return;
Script->GOHello(player, gameObjTarget);
- sWorld.ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget);
+ gameObjTarget->GetMap()->ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget);
gameObjTarget->AddUniqueUse(player);
gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
@@ -3046,7 +3086,7 @@ void Spell::SendLoot(uint64 guid, LootType loottype)
if (gameObjTarget->GetGOInfo()->chest.eventId)
{
sLog.outDebug("Chest ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->chest.eventId,gameObjTarget->GetDBTableGUIDLow());
- sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->chest.eventId, player, gameObjTarget);
+ player->GetMap()->ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->chest.eventId, player, gameObjTarget);
}
// triggering linked GO
@@ -3109,7 +3149,7 @@ void Spell::EffectOpenLock(uint32 effIndex)
// these objects must have been spawned by outdoorpvp!
else if(gameObjTarget->GetGOInfo()->type == GAMEOBJECT_TYPE_GOOBER && sOutdoorPvPMgr.HandleOpenGo(player, gameObjTarget->GetGUID()))
return;
- lockId = gameObjTarget->GetLockId();
+ lockId = goInfo->GetLockId();
guid = gameObjTarget->GetGUID();
}
else if(itemTarget)
@@ -3255,11 +3295,6 @@ void Spell::EffectSummonChangeItem(uint32 i)
delete pNewItem;
}
-void Spell::EffectOpenSecretSafe(uint32 i)
-{
- EffectOpenLock(i); //no difference for now
-}
-
void Spell::EffectProficiency(uint32 /*i*/)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
@@ -3327,6 +3362,11 @@ void Spell::EffectSummonType(uint32 i)
switch(properties->Category)
{
default:
+ if (properties->Flags & 512)
+ {
+ SummonGuardian(entry, properties);
+ break;
+ }
switch(properties->Type)
{
case SUMMON_TYPE_PET:
@@ -3409,7 +3449,12 @@ void Spell::EffectSummonType(uint32 i)
TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN;
- m_originalCaster->SummonCreature(entry,px,py,pz,m_caster->GetOrientation(),summonType,duration);
+ TempSummon * summon = m_originalCaster->SummonCreature(entry,px,py,pz,m_caster->GetOrientation(),summonType,duration);
+ if (!summon)
+ continue;
+ summon->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, m_originalCaster->GetGUID());
+ if (properties->Category == SUMMON_CATEGORY_ALLY)
+ summon->setFaction(m_originalCaster->getFaction());
}
break;
}
@@ -3464,7 +3509,7 @@ void Spell::EffectLearnSpell(uint32 i)
uint32 spellToLearn = ((m_spellInfo->Id==SPELL_ID_GENERIC_LEARN) || (m_spellInfo->Id==SPELL_ID_GENERIC_LEARN_PET)) ? damage : m_spellInfo->EffectTriggerSpell[i];
player->learnSpell(spellToLearn,false);
- sLog.outDebug( "Spell: Player %u have learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow() );
+ sLog.outDebug( "Spell: Player %u has learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow() );
}
void Spell::EffectDispel(uint32 i)
@@ -3554,26 +3599,12 @@ void Spell::EffectDispel(uint32 i)
}
m_caster->SendMessageToSet(&dataSuccess, true);
- // On succes dispel
+ // On success dispel
// Devour Magic
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == SPELLCATEGORY_DEVOUR_MAGIC)
{
- uint32 heal_spell = 0;
- switch (m_spellInfo->Id)
- {
- case 19505: heal_spell = 19658; break;
- case 19731: heal_spell = 19732; break;
- case 19734: heal_spell = 19733; break;
- case 19736: heal_spell = 19735; break;
- case 27276: heal_spell = 27278; break;
- case 27277: heal_spell = 27279; break;
- case 48011: heal_spell = 48010; break;
- default:
- sLog.outDebug("Spell for Devour Magic %d not handled in Spell::EffectDispel", m_spellInfo->Id);
- break;
- }
- if (heal_spell)
- m_caster->CastSpell(m_caster, heal_spell, true);
+ int32 heal_amount = m_spellInfo->CalculateSimpleValue(1);
+ m_caster->CastCustomSpell(m_caster, 19658, &heal_amount, NULL, NULL, true);
}
}
}
@@ -3992,7 +4023,7 @@ void Spell::EffectTameCreature(uint32 /*i*/)
if(!unitTarget)
return;
- if(unitTarget->GetTypeId() == TYPEID_PLAYER)
+ if(unitTarget->GetTypeId() != TYPEID_UNIT)
return;
Creature* creatureTarget = (Creature*)unitTarget;
@@ -4068,7 +4099,6 @@ void Spell::EffectSummonPet(uint32 i)
return;
OldSummon->GetMap()->Remove((Creature*)OldSummon,false);
- OldSummon->SetMapId(owner->GetMapId());
float px, py, pz;
owner->GetClosePoint(px, py, pz, OldSummon->GetObjectSize());
@@ -4211,11 +4241,11 @@ void Spell::SpellDamageWeaponDmg(uint32 i)
SpellEntry const *spellInfo = NULL;
uint32 stack = 0;
- if (AuraEffect * aur = unitTarget->GetAura(SPELL_AURA_MOD_RESISTANCE,SPELLFAMILY_WARRIOR,SPELLFAMILYFLAG_WARRIOR_SUNDERARMOR, 0, 0, m_caster->GetGUID()))
+ if (Aura * aur = unitTarget->GetAura(58567, m_caster->GetGUID()))
{
- aur->GetParentAura()->RefreshAura();
+ aur->RefreshAura();
spellInfo = aur->GetSpellProto();
- stack = aur->GetParentAura()->GetStackAmount();
+ stack = aur->GetStackAmount();
}
for(uint8 j = 0; j < 3; j++)
@@ -4254,7 +4284,7 @@ void Spell::SpellDamageWeaponDmg(uint32 i)
break;
int32 count = 1;
// Glyph of Devastate
- if (AuraEffect * aurEff = m_caster->GetDummyAura(58388))
+ if (AuraEffect * aurEff = m_caster->GetAuraEffect(58388, 0))
count += aurEff->GetAmount();
for (;count>0;count--)
m_caster->CastSpell(unitTarget, spellInfo, true);
@@ -4269,7 +4299,7 @@ void Spell::SpellDamageWeaponDmg(uint32 i)
if(m_spellInfo->SpellFamilyFlags[0] & 0x2000000)
{
if(m_caster->GetTypeId()==TYPEID_PLAYER)
- ((Player*)m_caster)->AddComboPoints(unitTarget, 1);
+ ((Player*)m_caster)->AddComboPoints(unitTarget, 1, this);
}
// Fan of Knives
else if(m_spellInfo->SpellFamilyFlags[1] & 0x40000)
@@ -4326,19 +4356,8 @@ void Spell::SpellDamageWeaponDmg(uint32 i)
{
// Skyshatter Harness item set bonus
// Stormstrike
- if(m_spellInfo->SpellFamilyFlags[1] & 0x0010)
- {
- Unit::AuraEffectList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
- for(Unit::AuraEffectList::const_iterator citr = m_OverrideClassScript.begin(); citr != m_OverrideClassScript.end(); ++citr)
- {
- // Stormstrike AP Buff
- if ( (*citr)->GetMiscValue() == 5634 )
- {
- m_caster->CastSpell(m_caster, 38430, true, NULL, *citr);
- break;
- }
- }
- }
+ if (AuraEffect * aurEff = m_caster->IsScriptOverriden(m_spellInfo, 5634))
+ m_caster->CastSpell(m_caster, 38430, true, NULL, aurEff);
break;
}
case SPELLFAMILY_DRUID:
@@ -4347,18 +4366,60 @@ void Spell::SpellDamageWeaponDmg(uint32 i)
if(m_spellInfo->SpellFamilyFlags.IsEqual(0,0x00000400))
{
if(m_caster->GetTypeId()==TYPEID_PLAYER)
- ((Player*)m_caster)->AddComboPoints(unitTarget,1);
+ ((Player*)m_caster)->AddComboPoints(unitTarget,1, this);
+ }
+ // Shred, Maul - Rend and Tear
+ else if (m_spellInfo->SpellFamilyFlags[0] & 0x00008800 && unitTarget->HasAuraState(AURA_STATE_BLEEDING, m_spellInfo, m_caster))
+ {
+ if (AuraEffect const* rendAndTear = m_caster->GetDummyAura(SPELLFAMILY_DRUID, 2859, 0))
+ {
+ totalDamagePercentMod *= float((rendAndTear->GetAmount() + 100.0f) / 100.0f);
+ }
}
break;
}
case SPELLFAMILY_DEATHKNIGHT:
{
+ // Plague Strike
+ if (m_spellInfo->SpellFamilyFlags[0] & 0x00000001)
+ {
+ // Glyph of Plague Strike
+ if (AuraEffect * aurEff = m_caster->GetAuraEffect(58657,0))
+ totalDamagePercentMod *= float((aurEff->GetAmount() + 100.0f) / 100.0f);
+ }
+ // Blood Strike
+ else if (m_spellInfo->SpellFamilyFlags[0] & 0x400000)
+ {
+ totalDamagePercentMod *= (float(unitTarget->GetDiseasesByCaster(m_caster->GetGUID())) * 12.5f + 100.0f) / 100.0f;
+
+ // Glyph of Blood Strike
+ if (AuraEffect * aurEff = m_caster->GetAuraEffect(59332,0))
+ {
+ if(unitTarget->HasAuraType(SPELL_AURA_MOD_DECREASE_SPEED))
+ totalDamagePercentMod *= float((20 + 100.0f) / 100.0f);
+ }
+ }
+ // Death Strike
+ else if (m_spellInfo->SpellFamilyFlags[0] & 0x00000010)
+ {
+ // Glyph of Death Strike
+ if (AuraEffect * aurEff = m_caster->GetAuraEffect(59336,0))
+ {
+ if(uint32 runic = m_caster->GetPower(POWER_RUNIC_POWER))
+ {
+ if (runic > 25)
+ runic = 25;
+
+ totalDamagePercentMod *= float((runic + 100.0f) / 100.0f);
+ }
+ }
+ }
// Obliterate (12.5% more damage per disease)
- if (m_spellInfo->SpellFamilyFlags[1] & 0x20000)
+ else if (m_spellInfo->SpellFamilyFlags[1] & 0x20000)
{
bool consumeDiseases = true;
// Annihilation
- if (AuraEffect * aurEff = m_caster->GetDummyAura(SPELLFAMILY_DEATHKNIGHT, 2710))
+ if (AuraEffect * aurEff = m_caster->GetDummyAura(SPELLFAMILY_DEATHKNIGHT, 2710, 0))
{
// Do not consume diseases if roll sucesses
if (roll_chance_i(aurEff->GetAmount()))
@@ -4366,8 +4427,8 @@ void Spell::SpellDamageWeaponDmg(uint32 i)
}
totalDamagePercentMod *= (float(CalculateDamage(2, unitTarget) * unitTarget->GetDiseasesByCaster(m_caster->GetGUID(), consumeDiseases) / 2) + 100.0f) / 100.0f;
}
- // Blood-Caked Strike - Blood-Caked Blade // Blood Strike
- else if (m_spellInfo->SpellIconID == 1736 || m_spellInfo->SpellFamilyFlags[0] & 0x400000)
+ // Blood-Caked Strike - Blood-Caked Blade
+ else if (m_spellInfo->SpellIconID == 1736)
totalDamagePercentMod *= (float(unitTarget->GetDiseasesByCaster(m_caster->GetGUID())) * 12.5f + 100.0f) / 100.0f;
break;
}
@@ -4536,44 +4597,45 @@ void Spell::EffectSummonObjectWild(uint32 i)
}
int32 duration = GetSpellDuration(m_spellInfo);
+
pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
pGameObj->SetSpellId(m_spellInfo->Id);
- if(pGameObj->GetGoType() != GAMEOBJECT_TYPE_FLAGDROP) // make dropped flag clickable for other players (not set owner guid (created by) for this)...
- m_caster->AddGameObject(pGameObj);
+ // Wild object not have owner and check clickable by players
map->Add(pGameObj);
- if(pGameObj->GetMapId() == 489 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //WS
+ if(pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP && m_caster->GetTypeId() == TYPEID_PLAYER)
{
- if(m_caster->GetTypeId() == TYPEID_PLAYER)
+ Player *pl = (Player*)m_caster;
+ BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
+
+ switch(pGameObj->GetMapId())
{
- Player *pl = (Player*)m_caster;
- BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
- if(bg && bg->GetTypeID()==BATTLEGROUND_WS && bg->GetStatus() == STATUS_IN_PROGRESS)
+ case 489: //WS
{
- uint32 team = ALLIANCE;
+ if(bg && bg->GetTypeID()==BATTLEGROUND_WS && bg->GetStatus() == STATUS_IN_PROGRESS)
+ {
+ uint32 team = ALLIANCE;
- if(pl->GetTeam() == team)
- team = HORDE;
+ if(pl->GetTeam() == team)
+ team = HORDE;
- ((BattleGroundWS*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID(),team);
+ ((BattleGroundWS*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID(),team);
+ }
+ break;
}
- }
- }
-
- if(pGameObj->GetMapId() == 566 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //EY
- {
- if(m_caster->GetTypeId() == TYPEID_PLAYER)
- {
- BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
- if(bg && bg->GetTypeID()==BATTLEGROUND_EY && bg->GetStatus() == STATUS_IN_PROGRESS)
+ case 566: //EY
{
- ((BattleGroundEY*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID());
+ if(bg && bg->GetTypeID()==BATTLEGROUND_EY && bg->GetStatus() == STATUS_IN_PROGRESS)
+ {
+ ((BattleGroundEY*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID());
+ }
+ break;
}
}
}
- if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
+ if(uint32 linkedEntry = pGameObj->GetGOInfo()->GetLinkedGameObjectEntry())
{
GameObject* linkedGO = new GameObject;
if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map,
@@ -4582,7 +4644,7 @@ void Spell::EffectSummonObjectWild(uint32 i)
linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
linkedGO->SetSpellId(m_spellInfo->Id);
- m_caster->AddGameObject(linkedGO);
+ // Wild object not have owner and check clickable by players
map->Add(linkedGO);
}
else
@@ -4604,6 +4666,31 @@ void Spell::EffectScriptEffect(uint32 effIndex)
{
switch(m_spellInfo->Id)
{
+ // Dispelling Analysis
+ case 37028:
+ {
+ if (unitTarget->HasAura(36904))
+ unitTarget->RemoveAurasDueToSpell(36904);
+
+ return;
+ }
+ case 45204: // Clone Me!
+ case 41055: // Copy Weapon
+ case 45206: // Copy Off-hand Weapon
+ unitTarget->CastSpell(m_caster, damage, false);
+ break;
+ case 45205: // Copy Offhand Weapon
+ case 41054: // Copy Weapon
+ m_caster->CastSpell(unitTarget, damage, false);
+ break;
+ // Despawn Horse
+ case 52267:
+ {
+ if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
+ return;
+ ((Creature*)unitTarget)->ForcedDespawn();
+ return;
+ }
// PX-238 Winter Wondervolt TRAP
case 26275:
{
@@ -4695,7 +4782,7 @@ void Spell::EffectScriptEffect(uint32 effIndex)
return;
// Onyxia Scale Cloak
- if(unitTarget->GetDummyAura(22683))
+ if(unitTarget->HasAura(22683))
return;
// Shadow Flame
@@ -4964,6 +5051,11 @@ void Spell::EffectScriptEffect(uint32 effIndex)
}
break;
}
+ case 52173: // Coyote Spirit Despawn
+ case 60243: // Blood Parrot Despawn
+ if (unitTarget->GetTypeId() == TYPEID_UNIT && ((Creature*)unitTarget)->isSummon())
+ ((TempSummon*)unitTarget)->UnSummon();
+ return;
// Sky Darkener Assault
case 52124:
if(unitTarget)
@@ -5039,6 +5131,24 @@ void Spell::EffectScriptEffect(uint32 effIndex)
}
}
return;
+ case 58983: // Big Blizzard Bear
+ {
+ if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ // Prevent stacking of mounts
+ unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED);
+
+ // Triggered spell id dependent of riding skill
+ if(uint16 skillval = ((Player*)unitTarget)->GetSkillValue(SKILL_RIDING))
+ {
+ if (skillval >= 150)
+ unitTarget->CastSpell(unitTarget, 58999, true);
+ else
+ unitTarget->CastSpell(unitTarget, 58997, true);
+ }
+ return;
+ }
case 59317: // Teleporting
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
@@ -5056,6 +5166,7 @@ void Spell::EffectScriptEffect(uint32 effIndex)
case 61177: // Northrend Inscription Research
case 61288: // Minor Inscription Research
case 61756: // Northrend Inscription Research (FAST QA VERSION)
+ case 64323: // Book of Glyph Mastery
{
if(m_caster->GetTypeId() != TYPEID_PLAYER)
return;
@@ -5176,6 +5287,14 @@ void Spell::EffectScriptEffect(uint32 effIndex)
}
return;
}
+ // Guarded by The Light
+ case 63521:
+ {
+ // Divine Plea
+ if(Aura *AuraDivinePlea = m_caster->GetAura(54428))
+ AuraDivinePlea->RefreshAura();
+ return;
+ }
}
break;
}
@@ -5193,16 +5312,6 @@ void Spell::EffectScriptEffect(uint32 effIndex)
aur->GetParentAura()->RefreshAura();
return;
}
- // Divine Hymn
- case 47951:
- {
- if (!unitTarget)
- return;
- Unit * target=NULL;
- unitTarget->CastSpell(target, 59600, false);
- unitTarget->CastSpell(target, 47953, false);
- return;
- }
default:
break;
}
@@ -5215,7 +5324,7 @@ void Spell::EffectScriptEffect(uint32 effIndex)
// Invigoration
case 53412:
{
- if (AuraEffect * aurEff = unitTarget->GetDummyAura(SPELLFAMILY_HUNTER, 3487))
+ if (AuraEffect * aurEff = unitTarget->GetDummyAura(SPELLFAMILY_HUNTER, 3487, 0))
{
if (roll_chance_i(aurEff->GetAmount()))
unitTarget->CastSpell(unitTarget, 53398, true);
@@ -5246,6 +5355,8 @@ void Spell::EffectScriptEffect(uint32 effIndex)
flag96 familyFlag = aura->GetSpellProto()->SpellFamilyFlags;
if (!(familyFlag[1] & 0x00000080 || familyFlag[0] & 0x0000C000))
continue;
+ if (!aura->GetPartAura(0))
+ continue;
// Serpent Sting - Instantly deals 40% of the damage done by your Serpent Sting.
if (familyFlag[0] & 0x4000)
@@ -5290,8 +5401,8 @@ void Spell::EffectScriptEffect(uint32 effIndex)
}
case SPELLFAMILY_PALADIN:
{
- // Judgement
- if (m_spellInfo->SpellFamilyFlags[0] & 0x800000 || m_spellInfo->SpellFamilyFlags[2] & 0x8)
+ // Judgement (seal trigger)
+ if (m_spellInfo->Category == SPELLCATEGORY_JUDGEMENT)
{
if(!unitTarget || !unitTarget->isAlive())
return;
@@ -5301,12 +5412,12 @@ void Spell::EffectScriptEffect(uint32 effIndex)
// Judgement self add switch
switch (m_spellInfo->Id)
{
- case 41467: break; // Judgement
case 53407: spellId1 = 20184; break; // Judgement of Justice
case 20271: // Judgement of Light
case 57774: spellId1 = 20185; break; // Judgement of Light
case 53408: spellId1 = 20186; break; // Judgement of Wisdom
default:
+ sLog.outError("Unsupported Judgement (seal trigger) spell (Id: %u) in Spell::EffectScriptEffect",m_spellInfo->Id);
return;
}
// all seals have aura dummy in 2 effect
@@ -5349,6 +5460,43 @@ void Spell::EffectScriptEffect(uint32 effIndex)
{
switch(m_spellInfo->Id)
{
+ // Death Knight Initiate Visual
+ case 51519:
+ {
+ if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
+ return;
+
+ uint32 iTmpSpellId = 0;
+ switch (unitTarget->GetDisplayId())
+ {
+ case 25369: iTmpSpellId = 51552; break; // bloodelf female
+ case 25373: iTmpSpellId = 51551; break; // bloodelf male
+ case 25363: iTmpSpellId = 51542; break; // draenei female
+ case 25357: iTmpSpellId = 51541; break; // draenei male
+ case 25361: iTmpSpellId = 51537; break; // dwarf female
+ case 25356: iTmpSpellId = 51538; break; // dwarf male
+ case 25372: iTmpSpellId = 51550; break; // forsaken female
+ case 25367: iTmpSpellId = 51549; break; // forsaken male
+ case 25362: iTmpSpellId = 51540; break; // gnome female
+ case 25359: iTmpSpellId = 51539; break; // gnome male
+ case 25355: iTmpSpellId = 51534; break; // human female
+ case 25354: iTmpSpellId = 51520; break; // human male
+ case 25360: iTmpSpellId = 51536; break; // nightelf female
+ case 25358: iTmpSpellId = 51535; break; // nightelf male
+ case 25368: iTmpSpellId = 51544; break; // orc female
+ case 25364: iTmpSpellId = 51543; break; // orc male
+ case 25371: iTmpSpellId = 51548; break; // tauren female
+ case 25366: iTmpSpellId = 51547; break; // tauren male
+ case 25370: iTmpSpellId = 51545; break; // troll female
+ case 25365: iTmpSpellId = 51546; break; // troll male
+ default: return;
+ }
+
+ unitTarget->CastSpell(unitTarget, iTmpSpellId, true);
+ Creature* npc = (Creature*)unitTarget;
+ npc->LoadEquipment(npc->GetEquipmentId());
+ return;
+ }
// Dreaming Glory
case 28698:
{
@@ -5413,11 +5561,24 @@ void Spell::EffectScriptEffect(uint32 effIndex)
}
break;
}
+ case SPELLFAMILY_WARRIOR:
+ {
+ // Shattering Throw
+ if ( m_spellInfo->SpellFamilyFlags[1] & 0x1 )
+ {
+ if(!unitTarget)
+ return;
+ // remove shields, will still display immune to damage part
+ unitTarget->RemoveAurasWithMechanic(1<<MECHANIC_IMMUNE_SHIELD);
+ return;
+ }
+ break;
+ }
}
// normal DB scripted effect
sLog.outDebug("Spell ScriptStart spellid %u in EffectScriptEffect ", m_spellInfo->Id);
- sWorld.ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget);
+ m_caster->GetMap()->ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget);
}
void Spell::EffectSanctuary(uint32 /*i*/)
@@ -5464,7 +5625,7 @@ void Spell::EffectAddComboPoints(uint32 /*i*/)
if(damage <= 0)
return;
- ((Player*)m_caster)->AddComboPoints(unitTarget, damage);
+ ((Player*)m_caster)->AddComboPoints(unitTarget, damage, this);
}
void Spell::EffectDuel(uint32 i)
@@ -5571,8 +5732,10 @@ void Spell::EffectStuck(uint32 /*i*/)
if(pTarget->isInFlight())
return;
+ PlayerInfo const *info = objmgr.GetPlayerInfo(pTarget->getRace(), pTarget->getClass());
+ pTarget->TeleportTo(info->mapId, info->positionX, info->positionY, info->positionZ, pTarget->GetOrientation(), (unitTarget==m_caster ? TELE_TO_SPELL : 0));
// homebind location is loaded always
- pTarget->TeleportTo(pTarget->m_homebindMapId,pTarget->m_homebindX,pTarget->m_homebindY,pTarget->m_homebindZ,pTarget->GetOrientation(), (unitTarget==m_caster ? TELE_TO_SPELL : 0));
+ // pTarget->TeleportTo(pTarget->m_homebindMapId,pTarget->m_homebindX,pTarget->m_homebindY,pTarget->m_homebindZ,pTarget->GetOrientation(), (unitTarget==m_caster ? TELE_TO_SPELL : 0));
// Stuck spell trigger Hearthstone cooldown
SpellEntry const *spellInfo = sSpellStore.LookupEntry(8690);
@@ -5588,7 +5751,7 @@ void Spell::EffectSummonPlayer(uint32 /*i*/)
return;
// Evil Twin (ignore player summon, but hide this for summoner)
- if(unitTarget->GetDummyAura(23445))
+ if(unitTarget->HasAura(23445))
return;
float x, y, z;
@@ -5619,7 +5782,7 @@ void Spell::EffectActivateObject(uint32 effect_idx)
int32 delay_secs = m_spellInfo->EffectMiscValue[effect_idx];
- sWorld.ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget);
+ gameObjTarget->GetMap()->ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget);
}
void Spell::EffectApplyGlyph(uint32 i)
@@ -5802,7 +5965,7 @@ void Spell::EffectSummonObject(uint32 i)
// Recast case - null spell id to make auras not be removed on object remove from world
if (m_spellInfo->Id == obj->GetSpellId())
obj->SetSpellId(0);
- obj->Delete();
+ m_caster->RemoveGameObject(obj, true);
}
m_caster->m_ObjectSlot[slot] = 0;
}
@@ -5955,23 +6118,23 @@ void Spell::EffectMomentMove(uint32 i)
dist = sqrt((x-destx)*(x-destx) + (y-desty)*(y-desty));
step = dist/10.0f;
}
-
+
int j = 0;
for(j; j<10 ;j++)
{
- if(fabs(z - destz) > 6)
- {
- destx -= step * cos(orientation);
- desty -= step * sin(orientation);
- ground = unitTarget->GetMap()->GetHeight(destx,desty,MAX_HEIGHT,true);
- floor = unitTarget->GetMap()->GetHeight(destx,desty,z, true);
- destz = fabs(ground - z) <= fabs(floor - z) ? ground:floor;
- }else
- break;
+ if(fabs(z - destz) > 6)
+ {
+ destx -= step * cos(orientation);
+ desty -= step * sin(orientation);
+ ground = unitTarget->GetMap()->GetHeight(destx,desty,MAX_HEIGHT,true);
+ floor = unitTarget->GetMap()->GetHeight(destx,desty,z, true);
+ destz = fabs(ground - z) <= fabs(floor - z) ? ground:floor;
+ }else
+ break;
}
if(j == 9)
{
- return;
+ return;
}
unitTarget->NearTeleportTo(destx, desty, destz + 0.07531, orientation, unitTarget==m_caster);
@@ -6087,6 +6250,28 @@ void Spell::EffectCharge(uint32 /*i*/)
m_caster->Attack(target, true);
}
+void Spell::EffectCharge2(uint32 /*i*/)
+{
+ float x, y, z;
+ if(m_targets.HasDst())
+ {
+ x = m_targets.m_destX;
+ y = m_targets.m_destY;
+ z = m_targets.m_destZ;
+ }
+ else if(Unit *target = m_targets.getUnitTarget())
+ {
+ target->GetContactPoint(m_caster, x, y, z);
+ // not all charge effects used in negative spells
+ if(!IsPositiveSpell(m_spellInfo->Id) && m_caster->GetTypeId() == TYPEID_PLAYER)
+ m_caster->Attack(target, true);
+ }
+ else
+ return;
+
+ m_caster->GetMotionMaster()->MoveCharge(x, y, z);
+}
+
void Spell::EffectKnockBack(uint32 i)
{
if(!unitTarget)
@@ -6330,7 +6515,7 @@ void Spell::EffectTransmitted(uint32 effIndex)
if(goinfo->type==GAMEOBJECT_TYPE_FISHINGNODE)
{
- if ( !cMap->IsInWater(fx, fy, fz-0.5f)) // Hack to prevent fishing bobber from failing to land on fishing hole
+ if ( !cMap->IsInWater(fx, fy, fz-0.5f, 0.5f)) // Hack to prevent fishing bobber from failing to land on fishing hole
{ // but this is not proper, we really need to ignore not materialized objects
SendCastResult(SPELL_FAILED_NOT_HERE);
SendChannelUpdate(0);
@@ -6390,16 +6575,14 @@ void Spell::EffectTransmitted(uint32 effIndex)
case GAMEOBJECT_TYPE_FISHINGHOLE:
case GAMEOBJECT_TYPE_CHEST:
default:
- {
break;
- }
}
pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
- pGameObj->SetOwnerGUID(m_caster->GetGUID() );
+ pGameObj->SetOwnerGUID(m_caster->GetGUID());
- //pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
+ //pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel());
pGameObj->SetSpellId(m_spellInfo->Id);
DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted");
@@ -6412,16 +6595,16 @@ void Spell::EffectTransmitted(uint32 effIndex)
data << uint64(pGameObj->GetGUID());
m_caster->SendMessageToSet(&data,true);
- if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
+ if(uint32 linkedEntry = pGameObj->GetGOInfo()->GetLinkedGameObjectEntry())
{
GameObject* linkedGO = new GameObject;
if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap,
m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY))
{
linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
- //linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
+ //linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel());
linkedGO->SetSpellId(m_spellInfo->Id);
- linkedGO->SetOwnerGUID(m_caster->GetGUID() );
+ linkedGO->SetOwnerGUID(m_caster->GetGUID());
linkedGO->GetMap()->Add(linkedGO);
}
@@ -6700,6 +6883,7 @@ void Spell::SummonGuardian(uint32 entry, SummonPropertiesEntry const *properties
switch(m_spellInfo->Id)
{
case 1122: // Inferno
+ amount = 1;
break;
}
int32 duration = GetSpellDuration(m_spellInfo);
@@ -6714,11 +6898,12 @@ void Spell::SummonGuardian(uint32 entry, SummonPropertiesEntry const *properties
TempSummon *summon = map->SummonCreature(entry, px, py, pz, m_caster->GetOrientation(), properties, duration, caster);
if(!summon)
return;
-
if(summon->HasSummonMask(SUMMON_MASK_GUARDIAN))
((Guardian*)summon)->InitStatsForLevel(level);
summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
+ if(summon->HasSummonMask(SUMMON_MASK_MINION) && m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
+ ((Minion*)summon)->SetFollowAngle(m_caster->GetAngle(summon));
summon->AI()->EnterEvadeMode();
}
@@ -6769,4 +6954,23 @@ void Spell::EffectRenamePet(uint32 /*eff_idx*/)
return;
unitTarget->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_ALLOWED);
-} \ No newline at end of file
+}
+
+void Spell::EffectPlayMusic(uint32 i)
+{
+ if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ uint32 soundid = m_spellInfo->EffectMiscValue[i];
+
+ if (!sSoundEntriesStore.LookupEntry(soundid))
+ {
+ sLog.outError("EffectPlayMusic: Sound (Id: %u) not exist in spell %u.",soundid,m_spellInfo->Id);
+ return;
+ }
+
+ WorldPacket data(SMSG_PLAY_MUSIC, 4);
+ data << uint32(soundid);
+ ((Player*)unitTarget)->GetSession()->SendPacket(&data);
+}
+
diff --git a/src/game/SpellHandler.cpp b/src/game/SpellHandler.cpp
index 74313eaa38b..dd88ef8e50a 100644
--- a/src/game/SpellHandler.cpp
+++ b/src/game/SpellHandler.cpp
@@ -537,3 +537,79 @@ void WorldSession::HandleSpellClick( WorldPacket & recv_data )
if(unit->isVehicle())
_player->EnterVehicle((Vehicle*)unit);
}
+
+void WorldSession::HandleMirrrorImageDataRequest( WorldPacket & recv_data )
+{
+ sLog.outDebug("WORLD: CMSG_GET_MIRRORIMAGE_DATA");
+ CHECK_PACKET_SIZE(recv_data, 8);
+ uint64 guid;
+ recv_data >> guid;
+
+ // Get unit for which data is needed by client
+ Unit *unit = ObjectAccessor::GetObjectInWorld(guid, (Unit*)NULL);
+ if(!unit)
+ return;
+ // Get creator of the unit
+ Unit *creator = ObjectAccessor::GetObjectInWorld(unit->GetCreatorGUID(),(Unit*)NULL);
+ if (!creator)
+ return;
+ WorldPacket data(SMSG_MIRRORIMAGE_DATA, 68);
+ data << (uint64)guid;
+ data << (uint32)creator->GetDisplayId();
+ if (creator->GetTypeId()==TYPEID_PLAYER)
+ {
+ Player * pCreator = (Player *)creator;
+ data << (uint8)pCreator->getRace();
+ data << (uint8)pCreator->getGender();
+ data << (uint8)pCreator->getClass();
+ data << (uint8)pCreator->GetByteValue(PLAYER_BYTES, 0); // skin
+
+ data << (uint8)pCreator->GetByteValue(PLAYER_BYTES, 1); // face
+ data << (uint8)pCreator->GetByteValue(PLAYER_BYTES, 2); // hair
+ data << (uint8)pCreator->GetByteValue(PLAYER_BYTES, 3); // haircolor
+ data << (uint8)pCreator->GetByteValue(PLAYER_BYTES_2, 0); // facialhair
+
+ data << (uint32)0; // unk
+ static const EquipmentSlots ItemSlots[] =
+ {
+ EQUIPMENT_SLOT_HEAD,
+ EQUIPMENT_SLOT_SHOULDERS,
+ EQUIPMENT_SLOT_BODY,
+ EQUIPMENT_SLOT_CHEST,
+ EQUIPMENT_SLOT_WAIST,
+ EQUIPMENT_SLOT_LEGS,
+ EQUIPMENT_SLOT_FEET,
+ EQUIPMENT_SLOT_WRISTS,
+ EQUIPMENT_SLOT_HANDS,
+ EQUIPMENT_SLOT_BACK,
+ EQUIPMENT_SLOT_TABARD,
+ EQUIPMENT_SLOT_END
+ };
+ // Display items in visible slots
+ for (EquipmentSlots const* itr = &ItemSlots[0];*itr!=EQUIPMENT_SLOT_END;++itr)
+ if (Item const *item = pCreator->GetItemByPos(INVENTORY_SLOT_BAG_0, *itr))
+ data << (uint32)item->GetProto()->DisplayInfoID;
+ else
+ data << (uint32)0;
+ }
+ else
+ {
+ // Skip player data for creatures
+ data << (uint32)0;
+ data << (uint32)0;
+ data << (uint32)0;
+ data << (uint32)0;
+ data << (uint32)0;
+ data << (uint32)0;
+ data << (uint32)0;
+ data << (uint32)0;
+ data << (uint32)0;
+ data << (uint32)0;
+ data << (uint32)0;
+ data << (uint32)0;
+ data << (uint32)0;
+ data << (uint32)0;
+ }
+ SendPacket( &data );
+}
+
diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp
index 513075ea2b6..ca01f4422b7 100644
--- a/src/game/SpellMgr.cpp
+++ b/src/game/SpellMgr.cpp
@@ -147,6 +147,7 @@ SpellMgr::SpellMgr()
case TARGET_UNIT_CONE_ALLY:
case TARGET_UNIT_CONE_ENTRY:
case TARGET_UNIT_CONE_ENEMY_UNKNOWN:
+ case TARGET_UNIT_AREA_PATH:
SpellTargetType[i] = TARGET_TYPE_AREA_CONE;
break;
case TARGET_DST_CASTER:
@@ -226,6 +227,7 @@ SpellMgr::SpellMgr()
case TARGET_UNIT_CONE_ENEMY:
case TARGET_UNIT_CONE_ALLY:
case TARGET_UNIT_CONE_ENEMY_UNKNOWN:
+ case TARGET_UNIT_AREA_PATH:
case TARGET_UNIT_RAID_CASTER:
IsAreaEffectTarget[i] = true;
break;
@@ -236,6 +238,7 @@ SpellMgr::SpellMgr()
}
}
+
SpellMgr::~SpellMgr()
{
}
@@ -246,6 +249,16 @@ SpellMgr& SpellMgr::Instance()
return spellMgr;
}
+bool SpellMgr::IsSrcTargetSpell(SpellEntry const *spellInfo) const
+{
+ for (uint8 i = 0; i< MAX_SPELL_EFFECTS; ++i)
+ {
+ if(SpellTargetType[spellInfo->EffectImplicitTargetA[i]] == TARGET_TYPE_AREA_SRC || SpellTargetType[spellInfo->EffectImplicitTargetB[i]] == TARGET_TYPE_AREA_SRC)
+ return true;
+ }
+ return false;
+}
+
int32 GetSpellDuration(SpellEntry const *spellInfo)
{
if(!spellInfo)
@@ -307,8 +320,6 @@ bool IsPassiveSpell(uint32 spellId)
return false;
if(spellInfo->Attributes & SPELL_ATTR_PASSIVE)
return true;
- if(spellInfo->activeIconID == 2158) //flight
- return true;
return false;
}
@@ -319,8 +330,6 @@ bool IsAutocastableSpell(uint32 spellId)
return false;
if(spellInfo->Attributes & SPELL_ATTR_PASSIVE)
return false;
- if(spellInfo->activeIconID == 2158)
- return false;
if(spellInfo->AttributesEx & SPELL_ATTR_EX_UNAUTOCASTABLE_BY_PET)
return false;
return true;
@@ -331,6 +340,127 @@ bool IsHigherHankOfSpell(uint32 spellId_1, uint32 spellId_2)
return spellmgr.GetSpellRank(spellId_1)<spellmgr.GetSpellRank(spellId_2);
}
+uint32 CalculatePowerCost(SpellEntry const * spellInfo, Unit const * caster, SpellSchoolMask schoolMask)
+{
+ // Spell drain all exist power on cast (Only paladin lay of Hands)
+ if (spellInfo->AttributesEx & SPELL_ATTR_EX_DRAIN_ALL_POWER)
+ {
+ // If power type - health drain all
+ if (spellInfo->powerType == POWER_HEALTH)
+ return caster->GetHealth();
+ // Else drain all power
+ if (spellInfo->powerType < MAX_POWERS)
+ return caster->GetPower(Powers(spellInfo->powerType));
+ sLog.outError("CalculateManaCost: Unknown power type '%d' in spell %d", spellInfo->powerType, spellInfo->Id);
+ return 0;
+ }
+
+ // Base powerCost
+ int32 powerCost = spellInfo->manaCost;
+ // PCT cost from total amount
+ if (spellInfo->ManaCostPercentage)
+ {
+ switch (spellInfo->powerType)
+ {
+ // health as power used
+ case POWER_HEALTH:
+ powerCost += spellInfo->ManaCostPercentage * caster->GetCreateHealth() / 100;
+ break;
+ case POWER_MANA:
+ powerCost += spellInfo->ManaCostPercentage * caster->GetCreateMana() / 100;
+ break;
+ case POWER_RAGE:
+ case POWER_FOCUS:
+ case POWER_ENERGY:
+ case POWER_HAPPINESS:
+ powerCost += spellInfo->ManaCostPercentage * caster->GetMaxPower(Powers(spellInfo->powerType)) / 100;
+ break;
+ case POWER_RUNE:
+ case POWER_RUNIC_POWER:
+ sLog.outDebug("CalculateManaCost: Not implemented yet!");
+ break;
+ default:
+ sLog.outError("CalculateManaCost: Unknown power type '%d' in spell %d", spellInfo->powerType, spellInfo->Id);
+ return 0;
+ }
+ }
+ SpellSchools school = GetFirstSchoolInMask(schoolMask);
+ // Flat mod from caster auras by spell school
+ powerCost += caster->GetInt32Value(UNIT_FIELD_POWER_COST_MODIFIER + school);
+ // Shiv - costs 20 + weaponSpeed*10 energy (apply only to non-triggered spell with energy cost)
+ if ( spellInfo->AttributesEx4 & SPELL_ATTR_EX4_SPELL_VS_EXTEND_COST )
+ powerCost += caster->GetAttackTime(OFF_ATTACK)/100;
+ // Apply cost mod by spell
+ if(Player* modOwner = caster->GetSpellModOwner())
+ modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COST, powerCost);
+
+ if(spellInfo->Attributes & SPELL_ATTR_LEVEL_DAMAGE_CALCULATION)
+ powerCost = int32(powerCost/ (1.117f* spellInfo->spellLevel / caster->getLevel() -0.1327f));
+
+ // PCT mod from user auras by school
+ powerCost = int32(powerCost * (1.0f+caster->GetFloatValue(UNIT_FIELD_POWER_COST_MULTIPLIER+school)));
+ if (powerCost < 0)
+ powerCost = 0;
+ return powerCost;
+}
+
+AuraState GetSpellAuraState(SpellEntry const * spellInfo)
+{
+ // Seals
+ if (IsSealSpell(spellInfo))
+ return (AURA_STATE_JUDGEMENT);
+
+ // Conflagrate aura state on Immolate and Shadowflame
+ if (spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK &&
+ // Immolate
+ ((spellInfo->SpellFamilyFlags[0] & 4) ||
+ // Shadowflame
+ (spellInfo->SpellFamilyFlags[2] & 2)))
+ return (AURA_STATE_CONFLAGRATE);
+
+ // Faerie Fire (druid versions)
+ if (spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && spellInfo->SpellFamilyFlags[0] & 0x400)
+ return (AURA_STATE_FAERIE_FIRE);
+
+ // Sting (hunter's pet ability)
+ if (spellInfo->Category == 1133)
+ return (AURA_STATE_FAERIE_FIRE);
+
+ // Victorious
+ if (spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR && spellInfo->SpellFamilyFlags[1] & 0x00040000)
+ return (AURA_STATE_WARRIOR_VICTORY_RUSH);
+
+ // Swiftmend state on Regrowth & Rejuvenation
+ if (spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && spellInfo->SpellFamilyFlags[0] & 0x50 )
+ return (AURA_STATE_SWIFTMEND);
+
+ // Deadly poison aura state
+ if(spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && spellInfo->SpellFamilyFlags[0] & 0x10000)
+ return (AURA_STATE_DEADLY_POISON);
+
+ // Enrage aura state
+ if(spellInfo->Dispel == DISPEL_ENRAGE)
+ return (AURA_STATE_ENRAGE);
+
+ // Bleeding aura state
+ if (GetAllSpellMechanicMask(spellInfo) & 1<<MECHANIC_BLEED)
+ return (AURA_STATE_BLEEDING);
+
+ if(GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST)
+ {
+ for (uint8 i = 0;i<MAX_SPELL_EFFECTS;++i)
+ {
+ if (spellInfo->EffectApplyAuraName[i]==SPELL_AURA_MOD_STUN
+ || spellInfo->EffectApplyAuraName[i]==SPELL_AURA_MOD_ROOT)
+ {
+ return (AURA_STATE_FROZEN);
+ break;
+ }
+ }
+ }
+ return AURA_STATE_NONE;
+}
+
SpellSpecific GetSpellSpecific(uint32 spellId)
{
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
@@ -428,8 +558,8 @@ SpellSpecific GetSpellSpecific(uint32 spellId)
if (spellInfo->Dispel == DISPEL_POISON)
return SPELL_STING;
- // only hunter aspects have this
- if( spellInfo->SpellFamilyFlags[1] & 0x00440000 || spellInfo->SpellFamilyFlags[0] & 0x00380000 || spellInfo->SpellFamilyFlags[2] & 0x00001010)
+ // only hunter aspects have this (but not all aspects in hunter family)
+ if( spellInfo->SpellFamilyFlags.HasFlag(0x00380000, 0x00440000, 0x00001010))
return SPELL_ASPECT;
break;
@@ -442,15 +572,17 @@ SpellSpecific GetSpellSpecific(uint32 spellId)
if (spellInfo->SpellFamilyFlags[0] & 0x11010002)
return SPELL_BLESSING;
- if ((spellInfo->SpellFamilyFlags[1] & 0x000008 || spellInfo->SpellFamilyFlags[0] & 0x20180400) && (spellInfo->AttributesEx3 & 0x200))
+ if (spellInfo->SpellFamilyFlags[0] & 0x00002190)
+ return SPELL_HAND;
+
+ // Judgement of Wisdom, Judgement of Light, Judgement of Justice
+ if (spellInfo->Id == 20184 || spellInfo->Id == 20185 || spellInfo->Id == 20186)
return SPELL_JUDGEMENT;
- for (int i = 0; i < 3; ++i)
- {
- // only paladin auras have this (for palaldin class family)
- if (spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_RAID)
- return SPELL_AURA;
- }
+ // only paladin auras have this (for palaldin class family)
+ if( spellInfo->SpellFamilyFlags[2] & 0x00000020 )
+ return SPELL_AURA;
+
break;
}
case SPELLFAMILY_SHAMAN:
@@ -465,7 +597,8 @@ SpellSpecific GetSpellSpecific(uint32 spellId)
return spellmgr.GetSpellElixirSpecific(spellInfo->Id);
case SPELLFAMILY_DEATHKNIGHT:
- if ((spellInfo->Attributes & 0x10) && (spellInfo->AttributesEx2 & 0x10) && (spellInfo->AttributesEx4 & 0x200000))
+ if (spellInfo->Id == SPELL_ID_BLOOD_PRESENCE || spellInfo->Id == SPELL_ID_FROST_PRESENCE || spellInfo->Id == SPELL_ID_UNHOLY_PRESENCE)
+ //if (spellInfo->Category == 47)
return SPELL_PRESENCE;
break;
}
@@ -501,6 +634,7 @@ bool IsSingleFromSpellSpecificPerCaster(uint32 spellSpec1,uint32 spellSpec2)
{
case SPELL_SEAL:
case SPELL_BLESSING:
+ case SPELL_HAND:
case SPELL_AURA:
case SPELL_STING:
case SPELL_CURSE:
@@ -569,13 +703,16 @@ bool IsPositiveTarget(uint32 targetA, uint32 targetB)
return true;
}
-bool IsPositiveEffect(uint32 spellId, uint32 effIndex, bool deep)
+bool SpellMgr::_isPositiveEffect(uint32 spellId, uint32 effIndex, bool deep) const
{
SpellEntry const *spellproto = sSpellStore.LookupEntry(spellId);
if (!spellproto) return false;
switch(spellId)
{
+ case 1852: // Silenced (GM)
+ case 46392: // Focused Assault
+ case 46393: // Brutal Assault
case 28441: // not positive dummy spell
case 37675: // Chaos Blast
case 41519: // Mark of Stormrage
@@ -584,6 +721,7 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex, bool deep)
case 31719: // Suspension
case 61987: // Avenging Wrath Marker
case 11196: // Recently Bandadged
+ case 50524: // Runic Power Feed
return false;
case 12042: // Arcane Power
return true;
@@ -631,6 +769,7 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex, bool deep)
case 38637: // Nether Exhaustion (red)
case 38638: // Nether Exhaustion (green)
case 38639: // Nether Exhaustion (blue)
+ case 11196: // Recently Bandaged
return false;
// some spells have unclear target modes for selection, so just make effect positive
case 27184:
@@ -673,7 +812,7 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex, bool deep)
continue;
// if non-positive trigger cast targeted to positive target this main cast is non-positive
// this will place this spell auras as debuffs
- if(IsPositiveTarget(spellTriggeredProto->EffectImplicitTargetA[effIndex],spellTriggeredProto->EffectImplicitTargetB[effIndex]) && !IsPositiveEffect(spellTriggeredId,i, true))
+ if(IsPositiveTarget(spellTriggeredProto->EffectImplicitTargetA[effIndex],spellTriggeredProto->EffectImplicitTargetB[effIndex]) && !_isPositiveEffect(spellTriggeredId,i, true))
return false;
}
}
@@ -759,7 +898,7 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex, bool deep)
for (uint8 i=0;i<MAX_SPELL_EFFECTS;++i)
{
if (i != effIndex)
- if (IsPositiveEffect(spellId, i, true))
+ if (_isPositiveEffect(spellId, i, true))
{
negative = false;
break;
@@ -806,14 +945,30 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex, bool deep)
if (!deep && spellproto->EffectTriggerSpell[effIndex]
&& !spellproto->EffectApplyAuraName[effIndex]
&& IsPositiveTarget(spellproto->EffectImplicitTargetA[effIndex],spellproto->EffectImplicitTargetB[effIndex])
- && !IsPositiveSpell(spellproto->EffectTriggerSpell[effIndex], true))
+ && !_isPositiveSpell(spellproto->EffectTriggerSpell[effIndex], true))
return false;
// ok, positive
return true;
}
-bool IsPositiveSpell(uint32 spellId, bool deep)
+bool IsPositiveSpell(uint32 spellId)
+{
+ return !(spellmgr.GetSpellCustomAttr(spellId) & SPELL_ATTR_CU_NEGATIVE);
+}
+
+bool IsPositiveEffect(uint32 spellId, uint32 effIndex)
+{
+ switch(effIndex)
+ {
+ default:
+ case 0: return !(spellmgr.GetSpellCustomAttr(spellId) & SPELL_ATTR_CU_NEGATIVE_EFF0);
+ case 1: return !(spellmgr.GetSpellCustomAttr(spellId) & SPELL_ATTR_CU_NEGATIVE_EFF1);
+ case 2: return !(spellmgr.GetSpellCustomAttr(spellId) & SPELL_ATTR_CU_NEGATIVE_EFF2);
+ }
+}
+
+bool SpellMgr::_isPositiveSpell(uint32 spellId, bool deep) const
{
SpellEntry const *spellproto = sSpellStore.LookupEntry(spellId);
if (!spellproto) return false;
@@ -821,7 +976,7 @@ bool IsPositiveSpell(uint32 spellId, bool deep)
// spells with at least one negative effect are considered negative
// some self-applied spells have negative effects but in self casting case negative check ignored.
for (int i = 0; i < 3; ++i)
- if (!IsPositiveEffect(spellId, i, deep))
+ if (!_isPositiveEffect(spellId, i, deep))
return false;
return true;
}
@@ -875,17 +1030,6 @@ bool IsSingleTargetSpells(SpellEntry const *spellInfo1, SpellEntry const *spellI
return false;
}
-bool IsAuraAddedBySpell(uint32 auraType, uint32 spellId)
-{
- SpellEntry const *spellproto = sSpellStore.LookupEntry(spellId);
- if (!spellproto) return false;
-
- for (int i = 0; i < 3; ++i)
- if (spellproto->EffectApplyAuraName[i] == auraType)
- return true;
- return false;
-}
-
SpellCastResult GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form)
{
// talents that learn spells can have stance requirements that need ignore
@@ -1062,77 +1206,6 @@ void SpellMgr::LoadSpellTargetPositions()
sLog.outString( ">> Loaded %u spell teleport coordinates", count );
}
-void SpellMgr::LoadSpellAffects()
-{
- mSpellAffectMap.clear(); // need for reload case
-
- uint32 count = 0;
-
- // 0 1 2 3 4
- QueryResult *result = WorldDatabase.Query("SELECT entry, effectId, SpellClassMask0, SpellClassMask1, SpellClassMask2 FROM spell_affect");
- if( !result )
- {
-
- barGoLink bar( 1 );
-
- bar.step();
-
- sLog.outString();
- sLog.outString( ">> Loaded %u spell affect definitions", count );
- return;
- }
-
- barGoLink bar( result->GetRowCount() );
-
- do
- {
- Field *fields = result->Fetch();
-
- bar.step();
-
- uint16 entry = fields[0].GetUInt16();
- uint8 effectId = fields[1].GetUInt8();
-
- SpellEntry const* spellInfo = sSpellStore.LookupEntry(entry);
-
- if (!spellInfo)
- {
- sLog.outErrorDb("Spell %u listed in `spell_affect` does not exist", entry);
- continue;
- }
-
- if (effectId >= 3)
- {
- sLog.outErrorDb("Spell %u listed in `spell_affect` have invalid effect index (%u)", entry,effectId);
- continue;
- }
-
- flag96 affect(fields[2].GetUInt32(), fields[3].GetUInt32(), fields[4].GetUInt32());
-
- // Spell.dbc have own data
- if (effectId>3)
- continue;
-
- flag96 dbc_affect;
- dbc_affect = spellInfo->EffectSpellClassMask[effectId];
- if(dbc_affect[0] == affect[0] && dbc_affect[1] == affect[1] && dbc_affect[2] == affect[2])
- {
- char text[]="ABC";
- sLog.outErrorDb("Spell %u listed in `spell_affect` have redundant (same with EffectSpellClassMask%c) data for effect index (%u) and not needed, skipped.", entry, text[effectId], effectId);
- continue;
- }
-
- mSpellAffectMap[(entry<<8) + effectId] = affect;
-
- ++count;
- } while( result->NextRow() );
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u custom spell affect definitions", count );
-}
-
bool SpellMgr::IsAffectedByMod(SpellEntry const *spellInfo, SpellModifier *mod) const
{
// false for spellInfo == NULL
@@ -1225,8 +1298,8 @@ void SpellMgr::LoadSpellBonusess()
{
mSpellBonusMap.clear(); // need for reload case
uint32 count = 0;
- // 0 1 2 3
- QueryResult *result = WorldDatabase.Query("SELECT entry, direct_bonus, dot_bonus, ap_bonus FROM spell_bonus_data");
+ // 0 1 2 3 4
+ QueryResult *result = WorldDatabase.Query("SELECT entry, direct_bonus, dot_bonus, ap_bonus, ap_dot_bonus FROM spell_bonus_data");
if( !result )
{
barGoLink bar( 1 );
@@ -1255,8 +1328,10 @@ void SpellMgr::LoadSpellBonusess()
sbe.direct_damage = fields[1].GetFloat();
sbe.dot_damage = fields[2].GetFloat();
sbe.ap_bonus = fields[3].GetFloat();
+ sbe.ap_dot_bonus = fields[4].GetFloat();
mSpellBonusMap[entry] = sbe;
+ ++count;
} while( result->NextRow() );
delete result;
@@ -1265,7 +1340,7 @@ void SpellMgr::LoadSpellBonusess()
sLog.outString( ">> Loaded %u extra spell bonus data", count);
}
-bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const* spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra)
+bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const* spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra, bool active)
{
// No extra req need
uint32 procEvent_procEx = PROC_EX_NONE;
@@ -1278,42 +1353,52 @@ bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const* spellPr
/* Check Periodic Auras
- * Both hots and dots can trigger if spell has no PROC_FLAG_SUCCESSFUL_DAMAGING_SPELL_HIT
- nor PROC_FLAG_SUCCESSFUL_HEALING_SPELL
+ *Dots can trigger if spell has no PROC_FLAG_SUCCESSFUL_NEGATIVE_MAGIC_SPELL
+ nor PROC_FLAG_TAKEN_POSITIVE_MAGIC_SPELL
+
+ *Only Hots can trigger if spell has PROC_FLAG_TAKEN_POSITIVE_MAGIC_SPELL
- *Only Hots can trigger if spell has PROC_FLAG_SUCCESSFUL_HEALING_SPELL
+ *Only dots can trigger if spell has both positivity flags or PROC_FLAG_SUCCESSFUL_NEGATIVE_MAGIC_SPELL
- *Only dots can trigger if spell has both positivity flags or PROC_FLAG_SUCCESSFUL_DAMAGING_SPELL_HIT
+ *Aura has to have PROC_FLAG_TAKEN_POSITIVE_MAGIC_SPELL or spellfamily specified to trigger from Hot
*/
if (procFlags & PROC_FLAG_ON_DO_PERIODIC)
{
- if (EventProcFlag & PROC_FLAG_SUCCESSFUL_DAMAGING_SPELL_HIT)
+ if (EventProcFlag & PROC_FLAG_SUCCESSFUL_NEGATIVE_MAGIC_SPELL)
{
if (!(procExtra & PROC_EX_INTERNAL_DOT))
return false;
}
- else if (EventProcFlag & PROC_FLAG_SUCCESSFUL_HEALING_SPELL
+ else if (EventProcFlag & PROC_FLAG_TAKEN_POSITIVE_MAGIC_SPELL
&& !(procExtra & PROC_EX_INTERNAL_HOT))
return false;
+ else if (procExtra & PROC_EX_INTERNAL_HOT)
+ procExtra |= PROC_EX_INTERNAL_REQ_FAMILY;
}
if (procFlags & PROC_FLAG_ON_TAKE_PERIODIC)
{
- if (EventProcFlag & PROC_FLAG_TAKEN_DAMAGING_SPELL_HIT)
+ if (EventProcFlag & PROC_FLAG_TAKEN_NEGATIVE_MAGIC_SPELL)
{
if (!(procExtra & PROC_EX_INTERNAL_DOT))
return false;
}
- else if (EventProcFlag & PROC_FLAG_TAKEN_HEALING_SPELL
+ else if (EventProcFlag & PROC_FLAG_TAKEN_POSITIVE_MAGIC_SPELL
&& !(procExtra & PROC_EX_INTERNAL_HOT))
return false;
+ else if (procExtra & PROC_EX_INTERNAL_HOT)
+ procExtra |= PROC_EX_INTERNAL_REQ_FAMILY;
}
+ // Trap casts are active by default
+ if (procFlags & PROC_FLAG_ON_TRAP_ACTIVATION)
+ active = true;
// Always trigger for this
- if (procFlags & (PROC_FLAG_KILLED | PROC_FLAG_KILL | PROC_FLAG_ON_TRAP_ACTIVATION))
+ if (procFlags & (PROC_FLAG_KILLED | PROC_FLAG_KILL | PROC_FLAG_DEATH))
return true;
+
if (spellProcEvent) // Exist event data
{
// Store extra req
@@ -1342,11 +1427,14 @@ bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const* spellPr
if ((spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags ) == 0)
return false;
hasFamilyMask = true;
+ // Some spells are not considered as active even with have spellfamilyflags
+ if (!(procEvent_procEx & PROC_EX_ONLY_ACTIVE_SPELL))
+ active = true;
}
}
}
- if (procExtra & PROC_EX_INTERNAL_REQ_FAMILY)
+ if (procExtra & (PROC_EX_INTERNAL_REQ_FAMILY))
{
if (!hasFamilyMask)
return false;
@@ -1355,15 +1443,27 @@ bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const* spellPr
// Check for extra req (if none) and hit/crit
if (procEvent_procEx == PROC_EX_NONE)
{
- // No extra req, so can trigger only for hit/crit
- if((procExtra & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)))
+ // No extra req, so can trigger only for hit/crit - spell has to be active
+ if((procExtra & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) && active)
return true;
}
else // Passive spells hits here only if resist/reflect/immune/evade
{
- // Exist req for PROC_EX_EX_TRIGGER_ALWAYS
- if ((procExtra & AURA_SPELL_PROC_EX_MASK) && (procEvent_procEx & PROC_EX_EX_TRIGGER_ALWAYS))
- return true;
+ if (procExtra & AURA_SPELL_PROC_EX_MASK)
+ {
+ // if spell marked as procing only from not active spells
+ if (active && procEvent_procEx & PROC_EX_NOT_ACTIVE_SPELL)
+ return false;
+ // if spell marked as procing only from active spells
+ if (!active && procEvent_procEx & PROC_EX_ONLY_ACTIVE_SPELL)
+ return false;
+ // Exist req for PROC_EX_EX_TRIGGER_ALWAYS
+ if (procEvent_procEx & PROC_EX_EX_TRIGGER_ALWAYS)
+ return true;
+ // PROC_EX_NOT_ACTIVE_SPELL and PROC_EX_ONLY_ACTIVE_SPELL flags handle: if passed checks before
+ if ((procExtra & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) && ((procEvent_procEx & (AURA_SPELL_PROC_EX_MASK | AURA_REMOVE_PROC_EX_MASK)) == 0))
+ return true;
+ }
// Check Extra Requirement like (hit/crit/miss/resist/parry/dodge/block/immune/reflect/absorb and other)
if (procEvent_procEx & procExtra)
return true;
@@ -1399,7 +1499,7 @@ void SpellMgr::LoadSpellElixirs()
bar.step();
- uint16 entry = fields[0].GetUInt16();
+ uint32 entry = fields[0].GetUInt32();
uint8 mask = fields[1].GetUInt8();
SpellEntry const* spellInfo = sSpellStore.LookupEntry(entry);
@@ -1423,12 +1523,50 @@ void SpellMgr::LoadSpellElixirs()
void SpellMgr::LoadSpellThreats()
{
- sSpellThreatStore.Free(); // for reload
+ mSpellThreatMap.clear(); // need for reload case
- sSpellThreatStore.Load();
+ uint32 count = 0;
+
+ // 0 1
+ QueryResult *result = WorldDatabase.Query("SELECT entry, Threat FROM spell_threat");
+ if( !result )
+ {
+
+ barGoLink bar( 1 );
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u aggro generating spells", count );
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ Field *fields = result->Fetch();
+
+ bar.step();
+
+ uint32 entry = fields[0].GetUInt32();
+ uint16 Threat = fields[1].GetUInt16();
+
+ if (!sSpellStore.LookupEntry(entry))
+ {
+ sLog.outErrorDb("Spell %u listed in `spell_threat` does not exist", entry);
+ continue;
+ }
+
+ mSpellThreatMap[entry] = Threat;
+
+ ++count;
+ } while( result->NextRow() );
+
+ delete result;
- sLog.outString( ">> Loaded %u aggro generating spells", sSpellThreatStore.RecordCount );
sLog.outString();
+ sLog.outString( ">> Loaded %u aggro generating spells", count );
}
bool SpellMgr::IsRankSpellDueToSpell(SpellEntry const *spellInfo_1,uint32 spellId_2) const
@@ -1666,7 +1804,13 @@ void SpellMgr::LoadSpellLearnSpells()
if(!sSpellStore.LookupEntry(node.spell))
{
- sLog.outErrorDb("Spell %u listed in `spell_learn_spell` does not exist",node.spell);
+ sLog.outErrorDb("Spell %u listed in `spell_learn_spell` learning not existed spell %u",spell_id,node.spell);
+ continue;
+ }
+
+ if(GetTalentSpellCost(node.spell))
+ {
+ sLog.outErrorDb("Spell %u listed in `spell_learn_spell` attempt learning talent spell %u, skipped",spell_id,node.spell);
continue;
}
@@ -1807,6 +1951,9 @@ void SpellMgr::LoadSpellScriptTarget()
}
break;
}
+ case SPELL_TARGET_TYPE_CONTROLLED:
+ if( targetEntry==0 )
+ sLog.outErrorDb("Table `spell_script_target`: creature template entry %u does not exist.",targetEntry);
default:
{
//players
@@ -1892,8 +2039,8 @@ void SpellMgr::LoadSpellPetAuras()
uint32 count = 0;
- // 0 1 2
- QueryResult *result = WorldDatabase.Query("SELECT spell, pet, aura FROM spell_pet_auras");
+ // 0 1 2 3
+ QueryResult *result = WorldDatabase.Query("SELECT spell, effectId, pet, aura FROM spell_pet_auras");
if( !result )
{
@@ -1914,11 +2061,12 @@ void SpellMgr::LoadSpellPetAuras()
bar.step();
- uint16 spell = fields[0].GetUInt16();
- uint16 pet = fields[1].GetUInt16();
- uint16 aura = fields[2].GetUInt16();
+ uint32 spell = fields[0].GetUInt32();
+ uint8 eff = fields[1].GetUInt8();
+ uint32 pet = fields[2].GetUInt32();
+ uint32 aura = fields[3].GetUInt32();
- SpellPetAuraMap::iterator itr = mSpellPetAuraMap.find(spell);
+ SpellPetAuraMap::iterator itr = mSpellPetAuraMap.find((spell<<8) + eff);
if(itr != mSpellPetAuraMap.end())
{
itr->second.AddAura(pet, aura);
@@ -1931,14 +2079,9 @@ void SpellMgr::LoadSpellPetAuras()
sLog.outErrorDb("Spell %u listed in `spell_pet_auras` does not exist", spell);
continue;
}
- int i = 0;
- for(; i < 3; ++i)
- if((spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA &&
- spellInfo->EffectApplyAuraName[i] == SPELL_AURA_DUMMY) ||
- spellInfo->Effect[i] == SPELL_EFFECT_DUMMY)
- break;
-
- if(i == 3)
+ if (spellInfo->Effect[eff] != SPELL_EFFECT_DUMMY &&
+ (spellInfo->Effect[eff] != SPELL_EFFECT_APPLY_AURA ||
+ spellInfo->EffectApplyAuraName[eff] != SPELL_AURA_DUMMY))
{
sLog.outError("Spell %u listed in `spell_pet_auras` does not have dummy aura or dummy effect", spell);
continue;
@@ -1951,8 +2094,8 @@ void SpellMgr::LoadSpellPetAuras()
continue;
}
- PetAura pa(pet, aura, spellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_PET, spellInfo->CalculateSimpleValue(i));
- mSpellPetAuraMap[spell] = pa;
+ PetAura pa(pet, aura, spellInfo->EffectImplicitTargetA[eff] == TARGET_UNIT_PET, spellInfo->CalculateSimpleValue(eff));
+ mSpellPetAuraMap[(spell<<8) + eff] = pa;
}
++count;
@@ -2159,8 +2302,9 @@ bool SpellMgr::IsSpellValid(SpellEntry const* spellInfo, Player* pl, bool msg)
case 0:
continue;
- // craft spell for crafting non-existed item (break client recipes list show)
+ // craft spell for crafting non-existed item (break client recipes list show)
case SPELL_EFFECT_CREATE_ITEM:
+ case SPELL_EFFECT_CREATE_ITEM_2:
{
if(!ObjectMgr::GetItemPrototype( spellInfo->EffectItemType[i] ))
{
@@ -2339,10 +2483,15 @@ void SpellMgr::LoadSpellAreas()
continue;
}
- if(spellInfo->EffectApplyAuraName[0]!=SPELL_AURA_DUMMY && spellInfo->EffectApplyAuraName[0]!=SPELL_AURA_PHASE)
+ switch(spellInfo->EffectApplyAuraName[0])
{
- sLog.outErrorDb("Spell %u listed in `spell_area` have aura spell requirement (%u) without dummy/phase aura in effect 0", spell,abs(spellArea.auraSpell));
- continue;
+ case SPELL_AURA_DUMMY:
+ case SPELL_AURA_PHASE:
+ case SPELL_AURA_GHOST:
+ break;
+ default:
+ sLog.outErrorDb("Spell %u listed in `spell_area` have aura spell requirement (%u) without dummy/phase/ghost aura in effect 0", spell,abs(spellArea.auraSpell));
+ continue;
}
if(abs(spellArea.auraSpell)==spellArea.spellId)
@@ -2435,8 +2584,12 @@ void SpellMgr::LoadSpellAreas()
SpellCastResult SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player)
{
+ // allow in GM-mode
+ if (player && player->isGameMaster())
+ return SPELL_CAST_OK;
+
// normal case
- if( spellInfo->AreaGroupId > 0)
+ if (spellInfo->AreaGroupId > 0)
{
bool found = false;
AreaGroupEntry const* groupEntry = sAreaGroupStore.LookupEntry(spellInfo->AreaGroupId);
@@ -2455,9 +2608,18 @@ SpellCastResult SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spell
return SPELL_FAILED_INCORRECT_AREA;
}
+ // continent limitation (virtual continent)
+ if (spellInfo->AttributesEx4 & SPELL_ATTR_EX4_CAST_ONLY_IN_OUTLAND)
+ {
+ uint32 v_map = GetVirtualMapForMapAndZone(map_id, zone_id);
+ MapEntry const* mapEntry = sMapStore.LookupEntry(v_map);
+ if(!mapEntry || mapEntry->addon < 1 || !mapEntry->IsContinent())
+ return SPELL_FAILED_INCORRECT_AREA;
+ }
+
// DB base check (if non empty then must fit at least single for allow)
SpellAreaMapBounds saBounds = spellmgr.GetSpellAreaMapBounds(spellInfo->Id);
- if(saBounds.first != saBounds.second)
+ if (saBounds.first != saBounds.second)
{
for(SpellAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
{
@@ -2484,21 +2646,21 @@ SpellCastResult SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spell
case 44535: // Spirit Heal (mana)
{
MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
- if(!mapEntry)
+ if (!mapEntry)
return SPELL_FAILED_INCORRECT_AREA;
return mapEntry->IsBattleGround() && player && player->InBattleGround() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA;
}
case 44521: // Preparation
{
- if(!player)
+ if (!player)
return SPELL_FAILED_REQUIRES_AREA;
MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
- if(!mapEntry)
+ if (!mapEntry)
return SPELL_FAILED_INCORRECT_AREA;
- if(!mapEntry->IsBattleGround())
+ if (!mapEntry->IsBattleGround())
return SPELL_FAILED_REQUIRES_AREA;
BattleGround* bg = player->GetBattleGround();
@@ -2510,14 +2672,14 @@ SpellCastResult SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spell
case 35775: // Green Team (Horde)
{
MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
- if(!mapEntry)
+ if (!mapEntry)
return SPELL_FAILED_INCORRECT_AREA;
return mapEntry->IsBattleArena() && player && player->InBattleGround() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA;
}
case 32727: // Arena Preparation
{
- if(!player)
+ if (!player)
return SPELL_FAILED_REQUIRES_AREA;
MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
@@ -2562,13 +2724,25 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto
// Explicit Diminishing Groups
switch(spellproto->SpellFamilyName)
{
+ case SPELLFAMILY_GENERIC:
+ // some generic arena related spells have by some strange reason MECHANIC_TURN
+ if (spellproto->Mechanic == MECHANIC_TURN)
+ return DIMINISHING_NONE;
+ break;
+ case SPELLFAMILY_MAGE:
+ {
+ // Frostbite 0x80000000
+ if (spellproto->SpellFamilyFlags[1] & 0x80000000)
+ return DIMINISHING_TRIGGER_ROOT;
+ // Frost Nova / Freeze (Water Elemental)
+ else if (spellproto->SpellIconID == 193)
+ return DIMINISHING_CONTROL_ROOT;
+ break;
+ }
case SPELLFAMILY_ROGUE:
{
- // Sap
- if (spellproto->SpellFamilyFlags[0] & 0x80)
- return DIMINISHING_POLYMORPH;
- // Gouge
- else if (spellproto->SpellFamilyFlags[0] & 0x8)
+ // Sap 0x80 Gouge 0x8
+ if (spellproto->SpellFamilyFlags[0] & 0x88)
return DIMINISHING_POLYMORPH;
// Blind
else if (spellproto->SpellFamilyFlags[0] & 0x1000000)
@@ -2576,6 +2750,9 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto
// Cheap Shot
else if (spellproto->SpellFamilyFlags[0] & 0x400)
return DIMINISHING_CHEAPSHOT_POUNCE;
+ // Crippling poison - Limit to 10 seconds in PvP (No SpellFamilyFlags)
+ else if (spellproto->SpellIconID == 163)
+ return DIMINISHING_LIMITONLY;
break;
}
case SPELLFAMILY_WARLOCK:
@@ -2596,17 +2773,15 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto
// Pounce
if (spellproto->SpellFamilyFlags[0] & 0x20000)
return DIMINISHING_CHEAPSHOT_POUNCE;
-
+ // Cyclone
+ else if (spellproto->SpellFamilyFlags[1] & 0x20)
+ return DIMINISHING_CYCLONE;
//Entangling Roots: to force natures grasp proc to be control root
else if (spellproto->SpellFamilyFlags[0] & 0x00000200)
return DIMINISHING_CONTROL_ROOT;
- break;
- }
- case SPELLFAMILY_MAGE:
- {
- // Frostbite
- if (spellproto->SpellFamilyFlags[1] & 0x80000000)
- return DIMINISHING_TRIGGER_ROOT;
+ // Faerie Fire
+ else if (spellproto->SpellFamilyFlags[0] & 0x400)
+ return DIMINISHING_LIMITONLY;
break;
}
case SPELLFAMILY_WARRIOR:
@@ -2617,8 +2792,8 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto
// Intimidating Shout
else if (spellproto->SpellFamilyFlags[0] & 0x40000)
return DIMINISHING_FEAR_BLIND;
- // Charge
- else if (spellproto->SpellFamilyFlags[0] & 0x1)
+ // Charge Stun
+ else if (spellproto->SpellFamilyFlags[0] & 0x01000000)
return DIMINISHING_NONE;
break;
}
@@ -2629,9 +2804,16 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto
return DIMINISHING_POLYMORPH;
break;
}
+ case SPELLFAMILY_PRIEST:
+ {
+ // Vampiric Embrace
+ if ((spellproto->SpellFamilyFlags[0] & 0x4) && spellproto->SpellIconID == 150)
+ return DIMINISHING_LIMITONLY;
+ break;
+ }
case SPELLFAMILY_DEATHKNIGHT:
{
- // Hungering Cold
+ // Hungering Cold (no flags)
if (spellproto->SpellIconID == 2797)
return DIMINISHING_POLYMORPH;
break;
@@ -2643,15 +2825,20 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto
// Get by mechanic
uint32 mechanic = GetAllSpellMechanicMask(spellproto);
if (mechanic == MECHANIC_NONE) return DIMINISHING_NONE;
- if (mechanic & (1<<MECHANIC_STUN)) return triggered ? DIMINISHING_TRIGGER_STUN : DIMINISHING_CONTROL_STUN;
- if (mechanic & ((1<<MECHANIC_SLEEP) | (1<<MECHANIC_FREEZE))) return DIMINISHING_SLEEP_FREEZE;
+ if (mechanic & ((1<<MECHANIC_STUN) |
+ (1<<MECHANIC_SHACKLE))) return triggered ? DIMINISHING_TRIGGER_STUN : DIMINISHING_CONTROL_STUN;
+ if (mechanic & ((1<<MECHANIC_SLEEP) |
+ (1<<MECHANIC_FREEZE))) return DIMINISHING_FREEZE_SLEEP;
if (mechanic & (1<<MECHANIC_POLYMORPH)) return DIMINISHING_POLYMORPH;
if (mechanic & (1<<MECHANIC_ROOT)) return triggered ? DIMINISHING_TRIGGER_ROOT : DIMINISHING_CONTROL_ROOT;
- if (mechanic & (1<<MECHANIC_FEAR)) return DIMINISHING_FEAR;
+ if (mechanic & ((1<<MECHANIC_FEAR) |
+ (1<<MECHANIC_TURN))) return DIMINISHING_FEAR_BLIND;
if (mechanic & (1<<MECHANIC_CHARM)) return DIMINISHING_CHARM;
if (mechanic & (1<<MECHANIC_SILENCE)) return DIMINISHING_SILENCE;
if (mechanic & (1<<MECHANIC_DISARM)) return DIMINISHING_DISARM;
- if (mechanic & ((1<<MECHANIC_KNOCKOUT) | (1<<MECHANIC_SAPPED))) return DIMINISHING_KNOCKOUT;
+ if (mechanic & (1<<MECHANIC_FREEZE)) return DIMINISHING_FREEZE_SLEEP;
+ if (mechanic & ((1<<MECHANIC_KNOCKOUT) |
+ (1<<MECHANIC_SAPPED))) return DIMINISHING_KNOCKOUT;
if (mechanic & (1<<MECHANIC_BANISH)) return DIMINISHING_BANISH;
if (mechanic & (1<<MECHANIC_HORROR)) return DIMINISHING_DEATHCOIL;
@@ -2664,20 +2851,63 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto
return DIMINISHING_NONE;
}
+int32 GetDiminishingReturnsLimitDuration(DiminishingGroup group, SpellEntry const* spellproto)
+{
+ if(!IsDiminishingReturnsGroupDurationLimited(group))
+ return 0;
+
+ // Explicit diminishing duration
+ switch(spellproto->SpellFamilyName)
+ {
+ case SPELLFAMILY_HUNTER:
+ {
+ // Wyvern Sting
+ if (spellproto->SpellFamilyFlags[1] & 0x1000)
+ return 6000;
+ break;
+ }
+ case SPELLFAMILY_PALADIN:
+ {
+ // Repentance - limit to 6 seconds in PvP
+ if (spellproto->SpellFamilyFlags[0] & 0x4)
+ return 6000;
+ break;
+ }
+ case SPELLFAMILY_DRUID:
+ {
+ // Faerie Fire - limit to 40 seconds in PvP (3.1)
+ if (spellproto->SpellFamilyFlags[0] & 0x400)
+ return 40000;
+ break;
+ }
+ case SPELLFAMILY_PRIEST:
+ {
+ // Vampiric Embrace - limit to 60 seconds in PvP (3.1)
+ if ((spellproto->SpellFamilyFlags[0] & 0x4) && spellproto->SpellIconID == 150)
+ return 60000;
+ break;
+ }
+ default:
+ break;
+ }
+
+ return 10000;
+}
+
bool IsDiminishingReturnsGroupDurationLimited(DiminishingGroup group)
{
switch(group)
{
case DIMINISHING_CONTROL_STUN:
case DIMINISHING_TRIGGER_STUN:
- case DIMINISHING_SLEEP_FREEZE:
+ case DIMINISHING_FREEZE_SLEEP:
case DIMINISHING_CONTROL_ROOT:
case DIMINISHING_TRIGGER_ROOT:
- case DIMINISHING_FEAR:
case DIMINISHING_FEAR_BLIND:
case DIMINISHING_CHARM:
case DIMINISHING_POLYMORPH:
case DIMINISHING_KNOCKOUT:
+ case DIMINISHING_CYCLONE:
case DIMINISHING_BANISH:
case DIMINISHING_LIMITONLY:
case DIMINISHING_CHEAPSHOT_POUNCE:
@@ -2696,18 +2926,18 @@ DiminishingReturnsType GetDiminishingReturnsGroupType(DiminishingGroup group)
case DIMINISHING_CONTROL_STUN:
case DIMINISHING_TRIGGER_STUN:
case DIMINISHING_CHEAPSHOT_POUNCE:
- case DIMINISHING_FEAR_BLIND:
+ case DIMINISHING_CYCLONE:
return DRTYPE_ALL;
- case DIMINISHING_BANISH:
+ case DIMINISHING_FEAR_BLIND:
case DIMINISHING_CONTROL_ROOT:
case DIMINISHING_TRIGGER_ROOT:
- case DIMINISHING_FEAR:
case DIMINISHING_CHARM:
case DIMINISHING_POLYMORPH:
case DIMINISHING_SILENCE:
case DIMINISHING_DISARM:
case DIMINISHING_DEATHCOIL:
- case DIMINISHING_SLEEP_FREEZE:
+ case DIMINISHING_FREEZE_SLEEP:
+ case DIMINISHING_BANISH:
case DIMINISHING_KNOCKOUT:
return DRTYPE_PLAYER;
default:
@@ -2784,7 +3014,7 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2, bool
SpellSpecific spellId_spec_2 = GetSpellSpecific(spellId_2);
if (spellId_spec_1 && spellId_spec_2)
if (IsSingleFromSpellSpecificPerTarget(spellId_spec_1, spellId_spec_2)
- ||(IsSingleFromSpellSpecificPerCaster(spellId_spec_1, spellId_spec_2) && sameCaster))
+ ||(sameCaster && IsSingleFromSpellSpecificPerCaster(spellId_spec_1, spellId_spec_2)))
return true;
if(spellInfo_1->SpellFamilyName != spellInfo_2->SpellFamilyName)
@@ -2795,6 +3025,11 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2, bool
for(uint32 i = 0; i < 3; ++i)
if (spellInfo_1->Effect[i] == SPELL_EFFECT_APPLY_AURA
|| spellInfo_1->Effect[i] == SPELL_EFFECT_PERSISTENT_AREA_AURA)
+ {
+ // not channeled AOE effects can stack
+ if(IsAreaEffectTarget[spellInfo_1->EffectImplicitTargetA[i]] || IsAreaEffectTarget[spellInfo_1->EffectImplicitTargetB[i]]
+ && !IsChanneledSpell(spellInfo_1))
+ continue;
// not area auras (shaman totem)
switch(spellInfo_1->EffectApplyAuraName[i])
{
@@ -2808,17 +3043,19 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2, bool
case SPELL_AURA_POWER_BURN_MANA:
case SPELL_AURA_OBS_MOD_ENERGY:
case SPELL_AURA_OBS_MOD_HEALTH:
+ case SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE:
return false;
default:
break;
}
+ }
}
spellId_2 = GetLastSpellInChain(spellId_2);
spellId_1 = GetLastSpellInChain(spellId_1);
// Hack for Incanter's Absorption
- if (spellId_1 == spellId_2 && spellId_1 == 44413)
+ if (spellId_1 == spellId_2 && (spellId_1 == 44413 || (!sameCaster && spellInfo_1->AttributesEx3 & SPELL_ATTR_EX3_STACKS_FOR_DIFFERENT_CASTERS)))
return false;
if (spellId_1 == spellId_2)
@@ -2852,7 +3089,7 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2, bool
|| spellInfo_1->EffectMiscValue[i] != spellInfo_2->EffectMiscValue[i]) // paladin resist aura
return false; // need itemtype check? need an example to add that check
- return true;
+ return (!(!sameCaster && spellInfo_1->AttributesEx3 & SPELL_ATTR_EX3_STACKS_FOR_DIFFERENT_CASTERS));
}
bool IsDispelableBySpell(SpellEntry const * dispelSpell, uint32 spellId, bool def)
@@ -3167,7 +3404,7 @@ void SpellMgr::LoadSpellChains()
for (itr2 = RankErrorMap.lower_bound(err_entry);itr2!=RankErrorMap.upper_bound(err_entry);itr2++)
{
sLog.outDebug("There is a duplicate rank entry (%s) for spell: %u",itr2->first,itr2->second->second.Id);
- if (!(itr2->second->second.Id==52375 || itr2->second->second.Id==45902))
+ if (!(itr2->second->second.Id==47541 || itr2->second->second.Id==45902 || itr2->second->second.Id==7620))
{
sLog.outDebug("Spell %u removed from chain data.",itr2->second->second.Id);
RankMap.erase(itr2->second);
@@ -3248,7 +3485,7 @@ void SpellMgr::LoadSpellChains()
}
}
-//uncomment these two lines to print yourself list of spell_chains on startup
+ //uncomment these two lines to print yourself list of spell_chains on startup
//for (UNORDERED_MAP<uint32, SpellChainNode>::iterator itr=mSpellChains.begin();itr!=mSpellChains.end();itr++)
//sLog.outString( "Id: %u, Rank: %d , %s, %u, %u, %u, %u",itr->first,itr->second.rank, sSpellStore.LookupEntry(itr->first)->Rank[sWorld.GetDefaultDbcLocale()], itr->second.first, itr->second.last,itr->second.next ,itr->second.prev);
@@ -3362,13 +3599,30 @@ void SpellMgr::LoadSpellCustomAttr()
mSpellCustomAttr[i] &= ~SPELL_ATTR_CU_MOVEMENT_IMPAIR;
break;
}
- }
+ }
+
+ if(!_isPositiveEffect(i, 0, false))
+ mSpellCustomAttr[i] |= SPELL_ATTR_CU_NEGATIVE_EFF0;
+ if(!_isPositiveEffect(i, 1, false))
+ mSpellCustomAttr[i] |= SPELL_ATTR_CU_NEGATIVE_EFF1;
+ if(!_isPositiveEffect(i, 2, false))
+ mSpellCustomAttr[i] |= SPELL_ATTR_CU_NEGATIVE_EFF2;
if(spellInfo->SpellVisual[0] == 3879)
mSpellCustomAttr[i] |= SPELL_ATTR_CU_CONE_BACK;
+ if(spellInfo->activeIconID == 2158) //flight
+ spellInfo->Attributes |= SPELL_ATTR_PASSIVE;
+
switch(i)
{
+ // Heart of the Crusader
+ case 20335:
+ case 20336:
+ case 20337:
+ // Entries were not updated after spell effect change, we have to do that manually:/
+ spellInfo->AttributesEx3 |= SPELL_ATTR_EX3_CAN_PROC_TRIGGERED;
+ break;
case 16007: // Draco-Incarcinatrix 900
// was 46, but effect is aura effect
spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_NEARBY_ENTRY;
@@ -3388,6 +3642,7 @@ void SpellMgr::LoadSpellCustomAttr()
case 40810: case 43267: case 43268: // Saber Lash
case 42384: // Brutal Swipe
case 45150: // Meteor Slash
+ case 64422: case 64688: // Sonic Screech
mSpellCustomAttr[i] |= SPELL_ATTR_CU_SHARE_DAMAGE;
break;
case 59725: // Improved Spell Reflection - aoe aura
@@ -3446,10 +3701,6 @@ void SpellMgr::LoadSpellCustomAttr()
case 54098: // Poison Bolt Volly - Faerlina (H)
spellInfo->MaxAffectedTargets = 10;
break;
- case 8122: case 8124: case 10888: case 10890: // Psychic Scream
- case 12494: // Frostbite
- spellInfo->Attributes |= SPELL_ATTR_BREAKABLE_BY_DAMAGE;
- break;
case 38794: case 33711: //Murmur's Touch
spellInfo->MaxAffectedTargets = 1;
spellInfo->EffectTriggerSpell[0] = 33760;
@@ -3465,10 +3716,12 @@ void SpellMgr::LoadSpellCustomAttr()
case 57761: // Fireball!
case 39805: // Lightning Overload
case 52437: // Sudden Death
+ case 64823: // Item - Druid T8 Balance 4P Bonus
spellInfo->procCharges=1;
break;
case 44544: // Fingers of Frost
spellInfo->procCharges=2;
+ spellInfo->EffectSpellClassMask[0] = flag96(685904631,1151048,0);
break;
case 28200: // Ascendance (Talisman of Ascendance trinket)
spellInfo->procCharges=6;
@@ -3479,6 +3732,20 @@ void SpellMgr::LoadSpellCustomAttr()
case 51904: // Summon Ghouls On Scarlet Crusade (core does not know the triggered spell is summon spell)
spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER;
break;
+ case 29809: // Desecration Arm - 36 instead of 37 - typo? :/
+ spellInfo->EffectRadiusIndex[0] = 37;
+ break;
+ // Master Shapeshifter: missing stance data for forms other than bear - bear version has correct data
+ // To prevent aura staying on target after talent unlearned
+ case 48420:
+ spellInfo->Stances = 1 << (FORM_CAT - 1);
+ break;
+ case 48421:
+ spellInfo->Stances = 1 << (FORM_MOONKIN - 1);
+ break;
+ case 48422:
+ spellInfo->Stances = 1 << (FORM_TREE - 1);
+ break;
default:
break;
}
diff --git a/src/game/SpellMgr.h b/src/game/SpellMgr.h
index 9871930a8fd..e651283fa48 100644
--- a/src/game/SpellMgr.h
+++ b/src/game/SpellMgr.h
@@ -25,7 +25,9 @@
// For more high level function for sSpellStore data
#include "SharedDefines.h"
+#include "SpellAuraDefines.h"
#include "DBCStructure.h"
+#include "DBCStores.h"
#include "Database/SQLStorage.h"
#include "Utilities/UnorderedMap.h"
@@ -36,14 +38,14 @@
class Player;
class Spell;
-
-extern SQLStorage sSpellThreatStore;
+struct SpellModifier;
// only used in code
enum SpellCategories
{
SPELLCATEGORY_HEALTH_MANA_POTIONS = 4,
- SPELLCATEGORY_DEVOUR_MAGIC = 12
+ SPELLCATEGORY_DEVOUR_MAGIC = 12,
+ SPELLCATEGORY_JUDGEMENT = 1210, // Judgement (seal trigger)
};
enum SpellDisableTypes
@@ -120,6 +122,7 @@ enum SpellSpecific
SPELL_MAGE_ARCANE_BRILLANCE = 24,
SPELL_WARRIOR_ENRAGE = 25,
SPELL_PRIEST_DIVINE_SPIRIT = 26,
+ SPELL_HAND = 27,
};
#define SPELL_LINKED_MAX_SPELLS 200000
@@ -133,6 +136,7 @@ enum SpellLinkedType
};
SpellSpecific GetSpellSpecific(uint32 spellId);
+AuraState GetSpellAuraState(SpellEntry const * spellInfo);
// Different spell properties
inline float GetSpellRadiusForHostile(SpellRadiusEntry const *radius) { return (radius ? radius->radiusHostile : 0); }
@@ -193,6 +197,14 @@ inline bool IsSpellHaveEffect(SpellEntry const *spellInfo, SpellEffects effect)
return false;
}
+inline bool IsSpellHaveAura(SpellEntry const *spellInfo, AuraType aura)
+{
+ for(int i= 0; i < 3; ++i)
+ if(AuraType(spellInfo->EffectApplyAuraName[i])==aura)
+ return true;
+ return false;
+}
+
//bool IsNoStackAuraDueToAura(uint32 spellId_1, uint32 effIndex_1, uint32 spellId_2, uint32 effIndex_2);
inline bool IsSealSpell(SpellEntry const *spellInfo)
@@ -213,15 +225,16 @@ inline bool IsElementalShield(SpellEntry const *spellInfo)
inline bool IsExplicitDiscoverySpell(SpellEntry const *spellInfo)
{
- return spellInfo->Effect[0]==SPELL_EFFECT_CREATE_ITEM_2 && spellInfo->Effect[1]==SPELL_EFFECT_SCRIPT_EFFECT;
+ return spellInfo->Effect[0] == SPELL_EFFECT_CREATE_RANDOM_ITEM
+ && spellInfo->Effect[1] == SPELL_EFFECT_SCRIPT_EFFECT
+ || spellInfo->Id == 64323; // Book of Glyph Mastery (Effect0==SPELL_EFFECT_SCRIPT_EFFECT without any other data)
}
inline bool IsLootCraftingSpell(SpellEntry const *spellInfo)
{
- return spellInfo->Effect[0]==SPELL_EFFECT_CREATE_ITEM_2 && (
- spellInfo->Effect[1]==SPELL_EFFECT_SCRIPT_EFFECT || // see IsExplicitDiscoverySpell
- !spellInfo->EffectItemType[0] || // result item not provided
- spellInfo->TotemCategory[0] == 121); // different random cards from Inscription (121==Virtuoso Inking Set category)
+ return spellInfo->Effect[0]==SPELL_EFFECT_CREATE_RANDOM_ITEM ||
+ // different random cards from Inscription (121==Virtuoso Inking Set category)
+ spellInfo->Effect[0]==SPELL_EFFECT_CREATE_ITEM_2 && spellInfo->TotemCategory[0] == 121;
}
bool IsHigherHankOfSpell(uint32 spellId_1,uint32 spellId_2);
@@ -230,6 +243,8 @@ bool IsSingleFromSpellSpecificPerTarget(uint32 spellSpec1, uint32 spellSpec2);
bool IsPassiveSpell(uint32 spellId);
bool IsAutocastableSpell(uint32 spellId);
+uint32 CalculatePowerCost(SpellEntry const * spellInfo, Unit const * caster, SpellSchoolMask schoolMask);
+
inline bool IsPassiveSpellStackableWithRanks(SpellEntry const* spellProto)
{
if(!IsPassiveSpell(spellProto->Id))
@@ -249,15 +264,14 @@ inline bool IsNonCombatSpell(SpellEntry const *spellInfo)
return (spellInfo->Attributes & SPELL_ATTR_CANT_USED_IN_COMBAT) != 0;
}
-bool IsPositiveSpell(uint32 spellId, bool deep = false);
-bool IsPositiveEffect(uint32 spellId, uint32 effIndex, bool deep = false);
+bool IsPositiveSpell(uint32 spellId);
+bool IsPositiveEffect(uint32 spellId, uint32 effIndex);
bool IsPositiveTarget(uint32 targetA, uint32 targetB);
bool IsDispelableBySpell(SpellEntry const * dispelSpell, uint32 spellId, bool def = false);
bool IsSingleTargetSpell(SpellEntry const *spellInfo);
bool IsSingleTargetSpells(SpellEntry const *spellInfo1, SpellEntry const *spellInfo2);
-bool IsAuraAddedBySpell(uint32 auraType, uint32 spellId);
extern bool IsAreaEffectTarget[TOTAL_SPELL_TARGETS];
@@ -317,7 +331,7 @@ inline bool IsAutoRepeatRangedSpell(SpellEntry const* spellInfo)
inline bool IsRangedWeaponSpell(SpellEntry const* spellInfo)
{
//spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED should be checked outside
- return (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER) // for 53352, cannot find better way
+ return (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && !(spellInfo->SpellFamilyFlags[1] & 0x10000000)) // for 53352, cannot find better way
|| (spellInfo->EquippedItemSubClassMask & ITEM_SUBCLASS_MASK_WEAPON_RANGED);
}
@@ -381,55 +395,53 @@ inline uint32 GetDispellMask(DispelType dispel)
DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto, bool triggered);
bool IsDiminishingReturnsGroupDurationLimited(DiminishingGroup group);
DiminishingReturnsType GetDiminishingReturnsGroupType(DiminishingGroup group);
-
-// Spell affects related declarations (accessed using SpellMgr functions)
-typedef UNORDERED_MAP<uint32, flag96> SpellAffectMap;
+int32 GetDiminishingReturnsLimitDuration(DiminishingGroup group, SpellEntry const* spellproto);
// Spell proc event related declarations (accessed using SpellMgr functions)
enum ProcFlags
{
- PROC_FLAG_NONE = 0x00000000,
+ PROC_FLAG_NONE = 0x00000000,
- PROC_FLAG_KILLED = 0x00000001, // 00 Killed by agressor
- PROC_FLAG_KILL = 0x00000002, // 01 Kill target (in most cases need XP/Honor reward)
+ PROC_FLAG_KILLED = 0x00000001, // 00 Killed by agressor
+ PROC_FLAG_KILL = 0x00000002, // 01 Kill target (in most cases need XP/Honor reward)
- PROC_FLAG_SUCCESSFUL_MILEE_HIT = 0x00000004, // 02 Successful melee auto attack
- PROC_FLAG_TAKEN_MELEE_HIT = 0x00000008, // 03 Taken damage from melee auto attack hit
+ PROC_FLAG_SUCCESSFUL_MELEE_HIT = 0x00000004, // 02 Successful melee auto attack
+ PROC_FLAG_TAKEN_MELEE_HIT = 0x00000008, // 03 Taken damage from melee auto attack hit
- PROC_FLAG_SUCCESSFUL_MELEE_SPELL_HIT = 0x00000010, // 04 Successful attack by Spell that use melee weapon
- PROC_FLAG_TAKEN_MELEE_SPELL_HIT = 0x00000020, // 05 Taken damage by Spell that use melee weapon
+ PROC_FLAG_SUCCESSFUL_MELEE_SPELL_HIT = 0x00000010, // 04 Successful attack by Spell that use melee weapon
+ PROC_FLAG_TAKEN_MELEE_SPELL_HIT = 0x00000020, // 05 Taken damage by Spell that use melee weapon
- PROC_FLAG_SUCCESSFUL_RANGED_HIT = 0x00000040, // 06 Successful Ranged auto attack
- PROC_FLAG_TAKEN_RANGED_HIT = 0x00000080, // 07 Taken damage from ranged auto attack
+ PROC_FLAG_SUCCESSFUL_RANGED_HIT = 0x00000040, // 06 Successful Ranged auto attack
+ PROC_FLAG_TAKEN_RANGED_HIT = 0x00000080, // 07 Taken damage from ranged auto attack
- PROC_FLAG_SUCCESSFUL_RANGED_SPELL_HIT = 0x00000100, // 08 Successful Ranged attack by Spell that use ranged weapon
- PROC_FLAG_TAKEN_RANGED_SPELL_HIT = 0x00000200, // 09 Taken damage by Spell that use ranged weapon
+ PROC_FLAG_SUCCESSFUL_RANGED_SPELL_HIT = 0x00000100, // 08 Successful Ranged attack by Spell that use ranged weapon
+ PROC_FLAG_TAKEN_RANGED_SPELL_HIT = 0x00000200, // 09 Taken damage by Spell that use ranged weapon
- PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL = 0x00000400, // 10 Successful Positive spell hit
- PROC_FLAG_TAKEN_POSITIVE_SPELL = 0x00000800, // 11 Taken Positive spell hit
+ PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL_HIT = 0x00000400, // 10 Successful Positive spell hit
+ PROC_FLAG_TAKEN_POSITIVE_SPELL = 0x00000800, // 11 Taken Positive spell hit
- PROC_FLAG_SUCCESSFUL_NEGATIVE_SPELL_HIT = 0x00001000, // 12 Successful Negative spell hit
- PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT = 0x00002000, // 13 Taken Negative spell hit
+ PROC_FLAG_SUCCESSFUL_NEGATIVE_SPELL_HIT = 0x00001000, // 12 Successful Negative spell hit
+ PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT = 0x00002000, // 13 Taken Negative spell hit
- PROC_FLAG_SUCCESSFUL_HEALING_SPELL = 0x00004000, // 14 Successful Direct Heal spell hit
- PROC_FLAG_TAKEN_HEALING_SPELL = 0x00008000, // 15 Taken Direct Heal spell hit
+ PROC_FLAG_SUCCESSFUL_POSITIVE_MAGIC_SPELL = 0x00004000, // 14 Successful Positive Magic spell hit
+ PROC_FLAG_TAKEN_POSITIVE_MAGIC_SPELL = 0x00008000, // 15 Taken Positive Magic spell hit
- PROC_FLAG_SUCCESSFUL_DAMAGING_SPELL_HIT = 0x00010000, // 16 Successful Direct Damage spell hit
- PROC_FLAG_TAKEN_DAMAGING_SPELL_HIT = 0x00020000, // 17 Taken Direct Damage spell hit
+ PROC_FLAG_SUCCESSFUL_NEGATIVE_MAGIC_SPELL = 0x00010000, // 16 Successful Negative Magic spell hit
+ PROC_FLAG_TAKEN_NEGATIVE_MAGIC_SPELL = 0x00020000, // 17 Taken Negative Magic spell hit
- PROC_FLAG_ON_DO_PERIODIC = 0x00040000, // 18 Successful do periodic (damage / healing, determined from 14,16 flags)
- PROC_FLAG_ON_TAKE_PERIODIC = 0x00080000, // 19 Taken spell periodic (damage / healing, determined from 15,17 flags)
+ PROC_FLAG_ON_DO_PERIODIC = 0x00040000, // 18 Successful do periodic (damage / healing, determined from 14,16 flags)
+ PROC_FLAG_ON_TAKE_PERIODIC = 0x00080000, // 19 Taken spell periodic (damage / healing, determined from 15,17 flags)
- PROC_FLAG_TAKEN_ANY_DAMAGE = 0x00100000, // 20 Taken any damage
- PROC_FLAG_ON_TRAP_ACTIVATION = 0x00200000, // 21 On trap activation
+ PROC_FLAG_TAKEN_ANY_DAMAGE = 0x00100000, // 20 Taken any damage
+ PROC_FLAG_ON_TRAP_ACTIVATION = 0x00200000, // 21 On trap activation (possibly needs name change to ON_GAMEOBJECT_CAST or USE)
- PROC_FLAG_TAKEN_OFFHAND_HIT = 0x00400000, // 22 Taken off-hand melee attacks(not used)
- PROC_FLAG_SUCCESSFUL_OFFHAND_HIT = 0x00800000, // 23 Successful off-hand melee attacks ( this is probably wrong )
+ PROC_FLAG_TAKEN_OFFHAND_HIT = 0x00400000, // 22 Taken off-hand melee attacks ( this is probably wrong )
+ PROC_FLAG_SUCCESSFUL_OFFHAND_HIT = 0x00800000, // 23 Successful off-hand melee attacks ( this is probably wrong )
- PROC_FLAG_DEATH = 0x01000000 // 24 Died in any way
+ PROC_FLAG_DEATH = 0x01000000 // 24 Died in any way
};
-#define MELEE_BASED_TRIGGER_MASK (PROC_FLAG_SUCCESSFUL_MILEE_HIT | \
+#define MELEE_BASED_TRIGGER_MASK (PROC_FLAG_SUCCESSFUL_MELEE_HIT | \
PROC_FLAG_TAKEN_MELEE_HIT | \
PROC_FLAG_SUCCESSFUL_MELEE_SPELL_HIT | \
PROC_FLAG_TAKEN_MELEE_SPELL_HIT | \
@@ -454,15 +466,19 @@ enum ProcFlagsEx
PROC_EX_ABSORB = 0x0000400,
PROC_EX_REFLECT = 0x0000800,
PROC_EX_INTERRUPT = 0x0001000, // Melee hit result can be Interrupt (not used)
- PROC_EX_AURA_REMOVE_DESTROY = 0x0002000, // aura absorb destroy or dispel
- PROC_EX_AURA_REMOVE_EXPIRE = 0x0004000, // aura remove by default and by cancel
- PROC_EX_EX_TRIGGER_ALWAYS = 0x0010000, // If set trigger always ( no matter another flags) used for drop charges
- PROC_EX_EX_ONE_TIME_TRIGGER = 0x0020000, // If set trigger always but only one time (not used)
+ PROC_EX_AURA_REMOVE_DESTROY = 0x0002000, // Aura absorb destroy or dispel
+ PROC_EX_AURA_REMOVE_EXPIRE = 0x0004000, // Aura remove by default and by cancel
+ PROC_EX_NOT_ACTIVE_SPELL = 0x0008000, // Spell mustn't do damage/heal to proc
+ PROC_EX_EX_TRIGGER_ALWAYS = 0x0010000, // If set trigger always no matter of hit result
+ PROC_EX_EX_ONE_TIME_TRIGGER = 0x0020000, // If set trigger always but only one time (not implemented yet)
+ PROC_EX_ONLY_ACTIVE_SPELL = 0x0040000, // Spell has to do damage/heal to proc
+
+ // Flags for internal use - do not use these in db!
PROC_EX_INTERNAL_CANT_PROC = 0x0800000,
- PROC_EX_INTERNAL_DOT = 0x1000000, // Only for internal use
- PROC_EX_INTERNAL_HOT = 0x2000000, // Only for internal use
- PROC_EX_INTERNAL_TRIGGERED = 0x4000000, // Only for internal use
- PROC_EX_INTERNAL_REQ_FAMILY = 0x8000000 // Only for internal use
+ PROC_EX_INTERNAL_DOT = 0x1000000,
+ PROC_EX_INTERNAL_HOT = 0x2000000,
+ PROC_EX_INTERNAL_TRIGGERED = 0x4000000,
+ PROC_EX_INTERNAL_REQ_FAMILY = 0x8000000
};
#define AURA_REMOVE_PROC_EX_MASK \
(PROC_EX_AURA_REMOVE_DESTROY | PROC_EX_AURA_REMOVE_EXPIRE)
@@ -490,6 +506,7 @@ struct SpellBonusEntry
float direct_damage;
float dot_damage;
float ap_bonus;
+ float ap_dot_bonus;
};
typedef UNORDERED_MAP<uint32, SpellProcEventEntry> SpellProcEventMap;
@@ -511,16 +528,18 @@ typedef UNORDERED_MAP<uint32, SpellBonusEntry> SpellBonusMap;
#define ELIXIR_SHATTRATH_MASK 0x8
typedef std::map<uint32, uint8> SpellElixirMap;
+typedef std::map<uint32, uint16> SpellThreatMap;
// Spell script target related declarations (accessed using SpellMgr functions)
enum SpellScriptTargetType
{
SPELL_TARGET_TYPE_GAMEOBJECT = 0,
SPELL_TARGET_TYPE_CREATURE = 1,
- SPELL_TARGET_TYPE_DEAD = 2
+ SPELL_TARGET_TYPE_DEAD = 2,
+ SPELL_TARGET_TYPE_CONTROLLED = 3,
};
-#define MAX_SPELL_TARGET_TYPE 3
+#define MAX_SPELL_TARGET_TYPE 4
struct SpellTargetEntry
{
@@ -552,28 +571,24 @@ class PetAura
auras.clear();
}
- PetAura(uint16 petEntry, uint16 aura, bool _removeOnChangePet, int _damage) :
+ PetAura(uint32 petEntry, uint32 aura, bool _removeOnChangePet, int _damage) :
removeOnChangePet(_removeOnChangePet), damage(_damage)
{
auras[petEntry] = aura;
}
- uint16 GetAura(uint16 petEntry) const
+ uint32 GetAura(uint32 petEntry) const
{
- std::map<uint16, uint16>::const_iterator itr = auras.find(petEntry);
+ std::map<uint32, uint32>::const_iterator itr = auras.find(petEntry);
if(itr != auras.end())
return itr->second;
- else
- {
- std::map<uint16, uint16>::const_iterator itr2 = auras.find(0);
- if(itr2 != auras.end())
- return itr2->second;
- else
- return 0;
- }
+ std::map<uint32, uint32>::const_iterator itr2 = auras.find(0);
+ if(itr2 != auras.end())
+ return itr2->second;
+ return 0;
}
- void AddAura(uint16 petEntry, uint16 aura)
+ void AddAura(uint32 petEntry, uint32 aura)
{
auras[petEntry] = aura;
}
@@ -589,11 +604,11 @@ class PetAura
}
private:
- std::map<uint16, uint16> auras;
+ std::map<uint32, uint32> auras;
bool removeOnChangePet;
int32 damage;
};
-typedef std::map<uint16, PetAura> SpellPetAuraMap;
+typedef std::map<uint32, PetAura> SpellPetAuraMap;
struct SpellArea
{
@@ -688,7 +703,6 @@ inline bool IsProfessionSkill(uint32 skill)
return IsPrimaryProfessionSkill(skill) || skill == SKILL_FISHING || skill == SKILL_COOKING || skill == SKILL_FIRST_AID;
}
-//#define SPELL_ATTR_CU_PLAYERS_ONLY 0x00000001
#define SPELL_ATTR_CU_CONE_BACK 0x00000002
#define SPELL_ATTR_CU_CONE_LINE 0x00000004
#define SPELL_ATTR_CU_SHARE_DAMAGE 0x00000008
@@ -704,7 +718,10 @@ inline bool IsProfessionSkill(uint32 skill)
#define SPELL_ATTR_CU_LINK_REMOVE 0x00002000
#define SPELL_ATTR_CU_MOVEMENT_IMPAIR 0x00004000
#define SPELL_ATTR_CU_EXCLUDE_SELF 0x00008000
-
+#define SPELL_ATTR_CU_NEGATIVE_EFF0 0x00010000
+#define SPELL_ATTR_CU_NEGATIVE_EFF1 0x00020000
+#define SPELL_ATTR_CU_NEGATIVE_EFF2 0x00040000
+#define SPELL_ATTR_CU_NEGATIVE 0x00070000
typedef std::vector<uint32> SpellCustomAttribute;
typedef std::vector<bool> EnchantCustomAttribute;
@@ -725,14 +742,6 @@ class SpellMgr
// Accessors (const or static functions)
public:
- // Spell affects
- flag96 const*GetSpellAffect(uint16 spellId, uint8 effectId) const
- {
- SpellAffectMap::const_iterator itr = mSpellAffectMap.find((spellId<<8) + effectId);
- if( itr != mSpellAffectMap.end( ) )
- return &itr->second;
- return 0;
- }
bool IsAffectedByMod(SpellEntry const *spellInfo, SpellModifier *mod) const;
@@ -760,6 +769,15 @@ class SpellMgr
return SPELL_NORMAL;
}
+ uint16 GetSpellThreat(uint32 spellid) const
+ {
+ SpellThreatMap::const_iterator itr = mSpellThreatMap.find(spellid);
+ if(itr==mSpellThreatMap.end())
+ return 0;
+
+ return itr->second;
+ }
+
// Spell proc events
SpellProcEventEntry const* GetSpellProcEvent(uint32 spellId) const
{
@@ -769,7 +787,7 @@ class SpellMgr
return NULL;
}
- bool IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra);
+ bool IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra, bool active);
SpellEnchantProcEntry const* GetSpellEnchantProcEvent(uint32 enchId) const
{
@@ -850,8 +868,6 @@ class SpellMgr
SpellsRequiringSpellMap const& GetSpellsRequiringSpell() const { return mSpellsReqSpell; }
- // Note: not use rank for compare to spell ranks: spell chains isn't linear order
- // Use IsHighRankOfSpell instead
uint8 GetSpellRank(uint32 spell_id) const
{
if(SpellChainNode const* node = GetSpellChainNode(spell_id))
@@ -965,9 +981,9 @@ class SpellMgr
return mSkillLineAbilityMap.upper_bound(spell_id);
}
- PetAura const* GetPetAura(uint16 spell_id)
+ PetAura const* GetPetAura(uint32 spell_id, uint8 eff)
{
- SpellPetAuraMap::const_iterator itr = mSpellPetAuraMap.find(spell_id);
+ SpellPetAuraMap::const_iterator itr = mSpellPetAuraMap.find((spell_id<<8) + eff);
if(itr != mSpellPetAuraMap.end())
return &itr->second;
else
@@ -1039,6 +1055,30 @@ class SpellMgr
return SpellAreaForAreaMapBounds(mSpellAreaForAreaMap.lower_bound(area_id),mSpellAreaForAreaMap.upper_bound(area_id));
}
+ bool IsSrcTargetSpell(SpellEntry const *spellInfo) const;
+
+ inline bool IsCasterSourceTarget(uint32 target)
+ {
+ switch (SpellTargetType[target])
+ {
+ case TARGET_TYPE_UNIT_TARGET:
+ case TARGET_TYPE_DEST_TARGET:
+ return false;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ inline bool IsSpellWithCasterSourceTargetsOnly(SpellEntry const* spellInfo)
+ {
+ for(int i = 0; i < 3; ++i)
+ if(uint32 target = spellInfo->EffectImplicitTargetA[i])
+ if(!IsCasterSourceTarget(target))
+ return false;
+ return true;
+ }
+
// Modifiers
public:
static SpellMgr& Instance();
@@ -1049,7 +1089,6 @@ class SpellMgr
void LoadSpellLearnSkills();
void LoadSpellLearnSpells();
void LoadSpellScriptTarget();
- void LoadSpellAffects();
void LoadSpellElixirs();
void LoadSpellProcEvents();
void LoadSpellBonusess();
@@ -1068,6 +1107,9 @@ class SpellMgr
bool CheckDB() const;
private:
+ bool _isPositiveSpell(uint32 spellId, bool deep) const;
+ bool _isPositiveEffect(uint32 spellId, uint32 effIndex, bool deep) const;
+
SpellScriptTarget mSpellScriptTarget;
SpellChainMap mSpellChains;
SpellsRequiringSpellMap mSpellsReqSpell;
@@ -1075,8 +1117,8 @@ class SpellMgr
SpellLearnSkillMap mSpellLearnSkills;
SpellLearnSpellMap mSpellLearnSpells;
SpellTargetPositionMap mSpellTargetPositions;
- SpellAffectMap mSpellAffectMap;
SpellElixirMap mSpellElixirs;
+ SpellThreatMap mSpellThreatMap;
SpellProcEventMap mSpellProcEventMap;
SpellBonusMap mSpellBonusMap;
SkillLineAbilityMap mSkillLineAbilityMap;
diff --git a/src/game/StatSystem.cpp b/src/game/StatSystem.cpp
index bb7b1273ac0..36d88e065a6 100644
--- a/src/game/StatSystem.cpp
+++ b/src/game/StatSystem.cpp
@@ -881,10 +881,9 @@ void Creature::UpdateDamagePhysical(WeaponAttackType attType)
float weapon_mindamage = GetWeaponDamageRange(attType, MINDAMAGE);
float weapon_maxdamage = GetWeaponDamageRange(attType, MAXDAMAGE);
- //float base_value = GetModifierValue(unitMod, BASE_VALUE)
- // + (weapon_mindamage + weapon_maxdamage)
- // * GetTotalAttackPowerValue(attType) / (getLevel() * 30);
- float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType);
+ /* difference in AP between current attack power and base value from DB */
+ float att_pwr_change = GetTotalAttackPowerValue(attType) - GetCreatureInfo()->attackpower;
+ float base_value = GetModifierValue(unitMod, BASE_VALUE) + (att_pwr_change * GetAPMultiplier(attType, false) / 14.0f);
float base_pct = GetModifierValue(unitMod, BASE_PCT);
float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
float total_pct = GetModifierValue(unitMod, TOTAL_PCT);
diff --git a/src/game/TargetedMovementGenerator.cpp b/src/game/TargetedMovementGenerator.cpp
index c40568318d4..c1c601921b3 100644
--- a/src/game/TargetedMovementGenerator.cpp
+++ b/src/game/TargetedMovementGenerator.cpp
@@ -53,7 +53,7 @@ template<class T>
bool
TargetedMovementGenerator<T>::_setTargetLocation(T &owner)
{
- if( !i_target.isValid() || !&owner )
+ if (!i_target.isValid() || !i_target->IsInWorld())
return false;
if( owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED) )
@@ -170,7 +170,7 @@ template<class T>
bool
TargetedMovementGenerator<T>::Update(T &owner, const uint32 & time_diff)
{
- if(!i_target.isValid())
+ if (!i_target.isValid() || !i_target->IsInWorld())
return false;
if( !&owner || !owner.isAlive())
diff --git a/src/game/TaxiHandler.cpp b/src/game/TaxiHandler.cpp
index 0928b8ba96a..5655bfd57bb 100644
--- a/src/game/TaxiHandler.cpp
+++ b/src/game/TaxiHandler.cpp
@@ -253,13 +253,11 @@ void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& /*recv_data*/)
SendDoFlight( mountDisplayId, path, 1 ); // skip start fly node
else
GetPlayer()->m_taxi.ClearTaxiDestinations(); // clear problematic path and next
+ return;
}
- GetPlayer()->m_taxi.ClearTaxiDestinations(); // not destinations, clear source node
- GetPlayer()->Unmount();
- GetPlayer()->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
+ GetPlayer()->CleanupAfterTaxiFlight();
GetPlayer()->SetFallInformation(0, GetPlayer()->GetPositionZ());
- GetPlayer()->getHostilRefManager().setOnlineOfflineState(true);
if(GetPlayer()->pvpInfo.inHostileArea)
GetPlayer()->CastSpell(GetPlayer(), 2479, true);
}
diff --git a/src/game/TemporarySummon.cpp b/src/game/TemporarySummon.cpp
index 724d68c568b..434750c8744 100644
--- a/src/game/TemporarySummon.cpp
+++ b/src/game/TemporarySummon.cpp
@@ -224,13 +224,18 @@ void TempSummon::SetTempSummonType(TempSummonType type)
void TempSummon::UnSummon()
{
- assert(!isPet());
+ //assert(!isPet());
+ if(isPet())
+ {
+ ((Pet*)this)->Remove(PET_SAVE_NOT_IN_SLOT);
+ assert(!IsInWorld());
+ return;
+ }
Unit* owner = GetSummoner();
if(owner && owner->GetTypeId() == TYPEID_UNIT && ((Creature*)owner)->IsAIEnabled)
((Creature*)owner)->AI()->SummonedCreatureDespawn(this);
- CleanupsBeforeDelete();
AddObjectToRemoveList();
}
@@ -266,6 +271,7 @@ Minion::Minion(SummonPropertiesEntry const *properties, Unit *owner) : TempSummo
{
assert(m_owner);
m_summonMask |= SUMMON_MASK_MINION;
+ m_followAngle = PET_FOLLOW_ANGLE;
}
void Minion::InitStats(uint32 duration)
@@ -287,7 +293,7 @@ void Minion::InitSummon()
if(m_owner->GetTypeId() == TYPEID_PLAYER
&& m_owner->GetMinionGUID() == GetGUID()
&& !m_owner->GetCharmGUID())
- ((Player*)m_owner)->CharmSpellInitialize();
+ ((Player*)m_owner)->CharmSpellInitialize();
}
void Minion::RemoveFromWorld()
@@ -303,7 +309,11 @@ Guardian::Guardian(SummonPropertiesEntry const *properties, Unit *owner) : Minio
, m_bonusdamage(0)
{
m_summonMask |= SUMMON_MASK_GUARDIAN;
- InitCharmInfo();
+ if (properties && properties->Type == SUMMON_TYPE_PET)
+ {
+ m_summonMask |= SUMMON_MASK_CONTROLABLE_GUARDIAN;
+ InitCharmInfo();
+ }
}
void Guardian::InitStats(uint32 duration)
@@ -312,7 +322,7 @@ void Guardian::InitStats(uint32 duration)
InitStatsForLevel(m_owner->getLevel());
- if(m_owner->GetTypeId() == TYPEID_PLAYER)
+ if(m_owner->GetTypeId() == TYPEID_PLAYER && HasSummonMask(SUMMON_MASK_CONTROLABLE_GUARDIAN))
m_charmInfo->InitCharmCreateSpells();
SetReactState(REACT_AGGRESSIVE);
@@ -335,7 +345,8 @@ void Puppet::InitStats(uint32 duration)
void Puppet::InitSummon()
{
Minion::InitSummon();
- SetCharmedBy(m_owner, CHARM_TYPE_POSSESS);
+ if (!SetCharmedBy(m_owner, CHARM_TYPE_POSSESS))
+ assert(false);
}
void Puppet::Update(uint32 time)
diff --git a/src/game/TemporarySummon.h b/src/game/TemporarySummon.h
index 47961d714ec..aa4650a02c9 100644
--- a/src/game/TemporarySummon.h
+++ b/src/game/TemporarySummon.h
@@ -54,9 +54,12 @@ class Minion : public TempSummon
void InitSummon();
void RemoveFromWorld();
Unit *GetOwner() { return m_owner; }
+ float GetFollowAngle() const { return m_followAngle; }
+ void SetFollowAngle(float angle) { m_followAngle = angle; }
bool IsPetGhoul() const {return GetEntry() == 26125;} // Ghoul may be guardian or pet
protected:
Unit * const m_owner;
+ float m_followAngle;
};
class Guardian : public Minion
diff --git a/src/game/ThreatManager.cpp b/src/game/ThreatManager.cpp
index a0459aa81dc..60c46c2307d 100644
--- a/src/game/ThreatManager.cpp
+++ b/src/game/ThreatManager.cpp
@@ -34,11 +34,9 @@
// The pHatingUnit is not used yet
float ThreatCalcHelper::calcThreat(Unit* pHatedUnit, Unit* pHatingUnit, float pThreat, SpellSchoolMask schoolMask, SpellEntry const *pThreatSpell)
{
- if(pThreatSpell)
- {
- if( Player* modOwner = pHatingUnit->GetSpellModOwner() )
+ if (pThreatSpell)
+ if (Player* modOwner = pHatedUnit->GetSpellModOwner())
modOwner->ApplySpellMod(pThreatSpell->Id, SPELLMOD_THREAT, pThreat);
- }
float threat = pHatedUnit->ApplyTotalThreatModifier(pThreat, schoolMask);
return threat;
@@ -346,7 +344,7 @@ HostilReference* ThreatContainer::selectNextVictim(Creature* pAttacker, HostilRe
//=================== ThreatManager ==========================
//============================================================
-ThreatManager::ThreatManager(Unit* owner) : iCurrentVictim(NULL), iOwner(owner)
+ThreatManager::ThreatManager(Unit* owner) : iCurrentVictim(NULL), iOwner(owner), iUpdateTimer(THREAT_UPDATE_INTERVAL)
{
}
@@ -357,6 +355,7 @@ void ThreatManager::clearReferences()
iThreatContainer.clearReferences();
iThreatOfflineContainer.clearReferences();
iCurrentVictim = NULL;
+ iUpdateTimer = THREAT_UPDATE_INTERVAL;
}
//============================================================
@@ -470,6 +469,10 @@ void ThreatManager::tauntFadeOut(Unit *pTaunter)
void ThreatManager::setCurrentVictim(HostilReference* pHostilReference)
{
+ if (pHostilReference && pHostilReference != iCurrentVictim)
+ {
+ iOwner->SendChangeCurrentVictimOpcode(pHostilReference);
+ }
iCurrentVictim = pHostilReference;
}
@@ -515,6 +518,7 @@ void ThreatManager::processThreatEvent(ThreatRefStatusChangeEvent* threatRefStat
setCurrentVictim(NULL);
setDirty(true);
}
+ iOwner->SendRemoveFromThreatListOpcode(hostilReference);
if(hostilReference->isOnline())
iThreatContainer.remove(hostilReference);
else
@@ -523,3 +527,16 @@ void ThreatManager::processThreatEvent(ThreatRefStatusChangeEvent* threatRefStat
}
}
+bool ThreatManager::isNeedUpdateToClient(uint32 time)
+{
+ if (isThreatListEmpty())
+ return false;
+ if (time >= iUpdateTimer)
+ {
+ iUpdateTimer = THREAT_UPDATE_INTERVAL;
+ return true;
+ }
+ iUpdateTimer -= time;
+ return false;
+}
+
diff --git a/src/game/ThreatManager.h b/src/game/ThreatManager.h
index aa84cb7d52c..1dba6277cfc 100644
--- a/src/game/ThreatManager.h
+++ b/src/game/ThreatManager.h
@@ -35,6 +35,8 @@ class Creature;
class ThreatManager;
struct SpellEntry;
+#define THREAT_UPDATE_INTERVAL 1 * IN_MILISECONDS // Server should send threat update to client periodically each second
+
//==============================================================
// Class to calculate the real threat based
@@ -187,6 +189,8 @@ class TRINITY_DLL_SPEC ThreatManager
void processThreatEvent(ThreatRefStatusChangeEvent* threatRefStatusChangeEvent);
+ bool isNeedUpdateToClient(uint32 time);
+
HostilReference* getCurrentVictim() { return iCurrentVictim; }
Unit* getOwner() { return iOwner; }
@@ -211,6 +215,7 @@ class TRINITY_DLL_SPEC ThreatManager
HostilReference* iCurrentVictim;
Unit* iOwner;
+ uint32 iUpdateTimer;
ThreatContainer iThreatContainer;
ThreatContainer iThreatOfflineContainer;
};
diff --git a/src/game/Totem.cpp b/src/game/Totem.cpp
index 67fa0281d91..d35ba9e30b9 100644
--- a/src/game/Totem.cpp
+++ b/src/game/Totem.cpp
@@ -57,9 +57,9 @@ void Totem::InitStats(uint32 duration)
Minion::InitStats(duration);
CreatureInfo const *cinfo = GetCreatureInfo();
- if (m_owner->GetTypeId()==TYPEID_PLAYER && cinfo)
+ if(m_owner->GetTypeId() == TYPEID_PLAYER && cinfo)
{
- uint32 display_id = objmgr.ChooseDisplayId(((Player*)m_owner)->GetTeam(),cinfo);
+ uint32 display_id = objmgr.ChooseDisplayId(((Player*)m_owner)->GetTeam(), cinfo);
CreatureModelInfo const *minfo = objmgr.GetCreatureModelRandomGender(display_id);
if (minfo)
display_id = minfo->modelid;
@@ -91,6 +91,9 @@ void Totem::InitSummon()
if(m_type == TOTEM_PASSIVE)
CastSpell(this, GetSpell(), true);
+ // Some totems can have both instant effect and passive spell
+ if (GetSpell(1))
+ CastSpell(this, GetSpell(1), true);
}
void Totem::UnSummon()
@@ -129,13 +132,12 @@ void Totem::UnSummon()
}
}
- CleanupsBeforeDelete();
AddObjectToRemoveList();
}
bool Totem::IsImmunedToSpellEffect(SpellEntry const* spellInfo, uint32 index) const
{
- // TODO: possibly all negative auras immuned?
+ // TODO: possibly all negative auras immune?
switch(spellInfo->EffectApplyAuraName[index])
{
case SPELL_AURA_PERIODIC_DAMAGE:
@@ -148,4 +150,3 @@ bool Totem::IsImmunedToSpellEffect(SpellEntry const* spellInfo, uint32 index) co
}
return Creature::IsImmunedToSpellEffect(spellInfo, index);
}
-
diff --git a/src/game/Totem.h b/src/game/Totem.h
index 134ca6d6d3f..9975cd4deae 100644
--- a/src/game/Totem.h
+++ b/src/game/Totem.h
@@ -40,7 +40,7 @@ class Totem : public Minion
void InitStats(uint32 duration);
void InitSummon();
void UnSummon();
- uint32 GetSpell() const { return m_spells[0]; }
+ uint32 GetSpell(uint8 slot=0) const { return m_spells[slot]; }
uint32 GetTotemDuration() const { return m_duration; }
TotemType GetTotemType() const { return m_type; }
diff --git a/src/game/Transports.cpp b/src/game/Transports.cpp
index 11089f053d1..25248b7b9d2 100644
--- a/src/game/Transports.cpp
+++ b/src/game/Transports.cpp
@@ -106,8 +106,9 @@ void MapManager::LoadTransports()
m_TransportsByMap[*i].insert(t);
//If we someday decide to use the grid to track transports, here:
- //MapManager::Instance().LoadGrid(mapid,x,y,true);
- //MapManager::Instance().GetMap(t->GetMapId())->Add<GameObject>((GameObject *)t);
+ t->SetMap(MapManager::Instance().CreateMap(mapid, t, 0));
+
+ //t->GetMap()->Add<GameObject>((GameObject *)t);
++count;
} while(result->NextRow());
delete result;
@@ -142,8 +143,6 @@ Transport::Transport() : GameObject()
bool Transport::Create(uint32 guidlow, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress, uint32 dynflags)
{
Relocate(x,y,z,ang);
-
- SetMapId(mapid);
// instance id and phaseMask isn't set to values different from std.
if(!IsPositionValid())
@@ -439,7 +438,6 @@ Transport::WayPointMap::const_iterator Transport::GetNextWayPoint()
void Transport::TeleportTransport(uint32 newMapid, float x, float y, float z)
{
Map const* oldMap = GetMap();
- SetMapId(newMapid);
Relocate(x, y, z);
for(PlayerSet::const_iterator itr = m_passengers.begin(); itr != m_passengers.end();)
@@ -458,7 +456,15 @@ void Transport::TeleportTransport(uint32 newMapid, float x, float y, float z)
//plr->GetSession()->SendPacket(&data);
}
- Map const* newMap = GetMap();
+ //we need to create and save new Map object with 'newMapid' because if not done -> lead to invalid Map object reference...
+ //player far teleport would try to create same instance, but we need it NOW for transport...
+ //correct me if I'm wrong O.o
+ //yes, you're right
+
+ ResetMap();
+ Map * newMap = MapManager::Instance().CreateMap(newMapid, this, 0);
+ SetMap(newMap);
+ assert (GetMap());
if(oldMap != newMap)
{
@@ -485,7 +491,7 @@ void Transport::CheckForEvent(uint32 entry, uint32 wp_id)
{
uint32 key = entry*100+wp_id;
if(objmgr.TransportEventMap.find(key) != objmgr.TransportEventMap.end())
- sWorld.ScriptsStart(sEventScripts, objmgr.TransportEventMap[key], this, NULL);
+ GetMap()->ScriptsStart(sEventScripts, objmgr.TransportEventMap[key], this, NULL);
}
void Transport::Update(uint32 /*p_time*/)
diff --git a/src/game/Transports.h b/src/game/Transports.h
index d72fa3b2124..e05a6006971 100644
--- a/src/game/Transports.h
+++ b/src/game/Transports.h
@@ -56,24 +56,11 @@ class TransportPath
std::vector<PathNode> i_nodes;
};
-class Transport : protected GameObject
+class Transport : public GameObject
{
public:
explicit Transport();
- // prevent using Transports as normal GO, but allow call some inherited functions
- using GameObject::IsTransport;
- using GameObject::GetEntry;
- using GameObject::GetGUID;
- using GameObject::GetGUIDLow;
- using GameObject::GetMapId;
- using GameObject::GetPositionX;
- using GameObject::GetPositionY;
- using GameObject::GetPositionZ;
- using GameObject::BuildCreateUpdateBlockForPlayer;
- using GameObject::BuildOutOfRangeUpdateBlock;
- using GameObject::GetPackGUID;
-
bool Create(uint32 guidlow, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress, uint32 dynflags);
bool GenerateWaypoints(uint32 pathid, std::set<uint32> &mapids);
void Update(uint32 p_time);
diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp
index e107eb90f55..74eda6482d0 100644
--- a/src/game/Unit.cpp
+++ b/src/game/Unit.cpp
@@ -60,7 +60,7 @@ float baseMoveSpeed[MAX_MOVE_TYPE] =
{
2.5f, // MOVE_WALK
7.0f, // MOVE_RUN
- 1.25f, // MOVE_RUN_BACK
+ 3.0f, // MOVE_RUN_BACK
4.722222f, // MOVE_SWIM
4.5f, // MOVE_SWIM_BACK
3.141594f, // MOVE_TURN_RATE
@@ -211,13 +211,20 @@ void Unit::Update( uint32 p_time )
m_Events.Update( p_time );
_UpdateSpells( p_time );
- // update combat timer only for players and pets
- if (isInCombat() && IsControlledByPlayer())
+ // If this is set during update SetCantProc(false) call is missing somewhere in the code
+ // Having this would prevent spells from being proced, so let's crash
+ assert(!m_procDeep);
+
+ if (CanHaveThreatList() && getThreatManager().isNeedUpdateToClient(p_time))
+ SendThreatListUpdate();
+
+ // update combat timer only for players and pets (only pets with PetAI)
+ if (isInCombat() && (GetTypeId() == TYPEID_PLAYER || (((Creature *)this)->isPet() && IsControlledByPlayer())))
{
// Check UNIT_STAT_MELEE_ATTACKING or UNIT_STAT_CHASE (without UNIT_STAT_FOLLOW in this case) so pets can reach far away
// targets without stopping half way there and running off.
// These flags are reset after target dies or another command is given.
- if( m_HostilRefManager.isEmpty() )
+ if( m_HostilRefManager.isEmpty())
{
// m_CombatTimer set at aura start and it will be freeze until aura removing
if ( m_CombatTimer <= p_time )
@@ -546,6 +553,22 @@ void Unit::RemoveAurasWithFamily(uint32 family, uint32 familyFlag1, uint32 famil
}
}
+void Unit::RemoveAurasWithMechanic(uint32 mechanic_mask, uint32 except)
+{
+ for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();)
+ {
+ if (!except || iter->second->GetId() != except)
+ {
+ if(GetAllSpellMechanicMask(iter->second->GetSpellProto()) & mechanic_mask)
+ {
+ RemoveAura(iter, AURA_REMOVE_BY_ENEMY_SPELL);
+ continue;
+ }
+ }
+ ++iter;
+ }
+}
+
void Unit::UpdateInterruptMask()
{
m_interruptMask = 0;
@@ -570,29 +593,6 @@ bool Unit::HasAuraTypeWithFamilyFlags(AuraType auraType, uint32 familyName, uint
return false;
}
-/* Called by DealDamage for auras that have a chance to be dispelled on damage taken. */
-void Unit::RemoveSpellbyDamageTaken(uint32 damage, uint32 spell)
-{
- // The chance to dispel an aura depends on the damage taken with respect to the casters level.
- uint32 max_dmg = getLevel() > 8 ? 25 * getLevel() - 150 : 50;
- float chance = float(damage) / max_dmg * 100.0f;
-
- std::queue < std::pair < uint32, uint64 > > remove_list;
-
- for (AuraList::iterator iter = m_ccAuras.begin(); iter != m_ccAuras.end();++iter)
- {
- if((!spell || (*iter)->GetId() != spell) && roll_chance_f(chance))
- {
- remove_list.push(std::make_pair((*iter)->GetId(), (*iter)->GetCasterGUID() ) );
- }
- }
-
- for(;remove_list.size();remove_list.pop())
- {
- RemoveAura(remove_list.front().first, remove_list.front().second, AURA_REMOVE_BY_ENEMY_SPELL);
- }
-}
-
void Unit::DealDamageMods(Unit *pVictim, uint32 &damage, uint32* absorb)
{
if (!pVictim->isAlive() || pVictim->hasUnitState(UNIT_STAT_UNATTACKABLE) || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
@@ -605,10 +605,10 @@ void Unit::DealDamageMods(Unit *pVictim, uint32 &damage, uint32* absorb)
//You don't lose health from damage taken from another player while in a sanctuary
//You still see it in the combat log though
- if(pVictim != this && GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER)
+ if(pVictim != this && IsControlledByPlayer() && pVictim->IsControlledByPlayer())
{
const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId());
- if(area && area->flags & AREA_FLAG_SANCTUARY) //sanctuary
+ if(area && area->IsSanctuary()) //sanctuary
{
if(absorb)
absorb += damage;
@@ -639,14 +639,13 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
{
// interrupting auras with AURA_INTERRUPT_FLAG_DAMAGE before checking !damage (absorbed damage breaks that type of auras)
pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TAKE_DAMAGE, spellProto ? spellProto->Id : 0);
- pVictim->RemoveSpellbyDamageTaken(damage, spellProto ? spellProto->Id : 0);
}
if(!damage)
{
- // Rage from physical damage received .
- if(cleanDamage && cleanDamage->damage && (damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL) && pVictim->GetTypeId() == TYPEID_PLAYER && (pVictim->getPowerType() == POWER_RAGE))
- ((Player*)pVictim)->RewardRage(cleanDamage->damage, 0, false);
+ // Rage from absorbed damage
+ if(cleanDamage && cleanDamage->absorbed_damage && pVictim->getPowerType() == POWER_RAGE)
+ pVictim->RewardRage(cleanDamage->absorbed_damage, 0, false);
return 0;
}
@@ -666,7 +665,7 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
// some critters required for quests
if(GetTypeId() == TYPEID_PLAYER)
- ((Player*)this)->KilledMonster(pVictim->GetEntry(),pVictim->GetGUID());
+ ((Player*)this)->KilledMonster(cInfo ,pVictim->GetGUID());
}
else
pVictim->ModifyHealth(- (int32)damage);
@@ -691,9 +690,10 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
}
// Rage from Damage made (only from direct weapon damage)
- if( cleanDamage && damagetype==DIRECT_DAMAGE && this != pVictim && GetTypeId() == TYPEID_PLAYER && (getPowerType() == POWER_RAGE))
+ if(cleanDamage && damagetype==DIRECT_DAMAGE && this != pVictim && getPowerType() == POWER_RAGE)
{
uint32 weaponSpeedHitFactor;
+ uint32 rage_damage = damage + cleanDamage->absorbed_damage;
switch(cleanDamage->attackType)
{
@@ -704,7 +704,7 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
else
weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 3.5f);
- ((Player*)this)->RewardRage(damage, weaponSpeedHitFactor, true);
+ RewardRage(rage_damage, weaponSpeedHitFactor, true);
break;
}
@@ -715,7 +715,7 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
else
weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 1.75f);
- ((Player*)this)->RewardRage(damage, weaponSpeedHitFactor, true);
+ RewardRage(rage_damage, weaponSpeedHitFactor, true);
break;
}
@@ -865,7 +865,11 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
if(!cVictim->isPet())
{
cVictim->DeleteThreatList();
- cVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
+ // only lootable if it has loot or can drop gold
+ if(cVictim->GetCreatureInfo()->lootid || cVictim->GetCreatureInfo()->maxgold > 0)
+ cVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
+ else
+ cVictim->lootForBody = true; // needed for skinning
}
// Call creature just died function
if (cVictim->AI())
@@ -949,13 +953,6 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
}
else // victim is a player
{
- // Rage from damage received
- if(this != pVictim && pVictim->getPowerType() == POWER_RAGE)
- {
- uint32 rage_damage = damage + (cleanDamage ? cleanDamage->damage : 0);
- ((Player*)pVictim)->RewardRage(rage_damage, 0, false);
- }
-
// random durability for items (HIT TAKEN)
if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_DAMAGE)))
{
@@ -964,6 +961,13 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
}
}
+ // Rage from damage received
+ if(this != pVictim && pVictim->getPowerType() == POWER_RAGE)
+ {
+ uint32 rage_damage = damage + (cleanDamage ? cleanDamage->absorbed_damage : 0);
+ pVictim->RewardRage(rage_damage, 0, false);
+ }
+
if(GetTypeId()==TYPEID_PLAYER)
{
// random durability for items (HIT DONE)
@@ -1200,7 +1204,7 @@ void Unit::CastCustomSpell(uint32 spellId, CustomSpellValues const &value, Unit*
}
// used for scripting
-void Unit::CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item *castItem, AuraEffect* triggeredByAura, uint64 originalCaster)
+void Unit::CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item *castItem, AuraEffect* triggeredByAura, uint64 originalCaster, Unit* OriginalVictim)
{
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId );
@@ -1220,6 +1224,8 @@ void Unit::CastSpell(float x, float y, float z, uint32 spellId, bool triggered,
SpellCastTargets targets;
targets.setDestination(x, y, z);
+ if(OriginalVictim)
+ targets.setUnitTarget(OriginalVictim);
spell->m_CastItem = castItem;
spell->prepare(&targets, triggeredByAura);
}
@@ -1276,6 +1282,9 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage *damageInfo, int32 dama
if (damage < 0)
return;
+ if(spellInfo->AttributesEx4 & SPELL_ATTR_EX4_FIXED_DAMAGE)
+ return;
+
Unit *pVictim = damageInfo->target;
if(!pVictim || !pVictim->isAlive())
return;
@@ -1380,7 +1389,7 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage *damageInfo, bool durabilityLoss)
Unit *pVictim = damageInfo->target;
- if(!this || !pVictim)
+ if(!pVictim)
return;
if (!pVictim->isAlive() || pVictim->hasUnitState(UNIT_STAT_UNATTACKABLE) || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
@@ -1395,15 +1404,15 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage *damageInfo, bool durabilityLoss)
//You don't lose health from damage taken from another player while in a sanctuary
//You still see it in the combat log though
- if(pVictim != this && GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER)
+ if(pVictim != this && IsControlledByPlayer() && pVictim->IsControlledByPlayer())
{
const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId());
- if(area && area->flags & AREA_FLAG_SANCTUARY) // sanctuary
+ if(area && area->IsSanctuary()) // sanctuary
return;
}
// Call default DealDamage
- CleanDamage cleanDamage(damageInfo->cleanDamage, BASE_ATTACK, MELEE_HIT_NORMAL);
+ CleanDamage cleanDamage(damageInfo->cleanDamage, damageInfo->absorb, BASE_ATTACK, MELEE_HIT_NORMAL);
DealDamage(pVictim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), spellProto, durabilityLoss);
}
@@ -1427,7 +1436,7 @@ void Unit::CalculateMeleeDamage(Unit *pVictim, uint32 damage, CalcDamageInfo *da
damageInfo->procEx = PROC_EX_NONE;
damageInfo->hitOutCome = MELEE_HIT_EVADE;
- if(!this || !pVictim)
+ if(!pVictim)
return;
if(!this->isAlive() || !pVictim->isAlive())
return;
@@ -1436,12 +1445,12 @@ void Unit::CalculateMeleeDamage(Unit *pVictim, uint32 damage, CalcDamageInfo *da
switch (attackType)
{
case BASE_ATTACK:
- damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_MILEE_HIT;
+ damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_MELEE_HIT;
damageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_HIT;
damageInfo->HitInfo = HITINFO_NORMALSWING2;
break;
case OFF_ATTACK:
- damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_MILEE_HIT | PROC_FLAG_SUCCESSFUL_OFFHAND_HIT;
+ damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_MELEE_HIT | PROC_FLAG_SUCCESSFUL_OFFHAND_HIT;
damageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_HIT;//|PROC_FLAG_TAKEN_OFFHAND_HIT // not used
damageInfo->HitInfo = HITINFO_LEFTSWING;
break;
@@ -1623,7 +1632,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
if (damageInfo==0) return;
Unit *pVictim = damageInfo->target;
- if(!this || !pVictim)
+ if(!pVictim)
return;
if (!pVictim->isAlive() || pVictim->hasUnitState(UNIT_STAT_UNATTACKABLE) || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
@@ -1631,10 +1640,10 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
//You don't lose health from damage taken from another player while in a sanctuary
//You still see it in the combat log though
- if(pVictim != this && GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER)
+ if(pVictim != this && IsControlledByPlayer() && pVictim->IsControlledByPlayer())
{
const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId());
- if(area && area->flags & AREA_FLAG_SANCTUARY) // sanctuary
+ if(area && area->IsSanctuary()) // sanctuary
return;
}
@@ -1681,7 +1690,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
}
// Call default DealDamage
- CleanDamage cleanDamage(damageInfo->cleanDamage,damageInfo->attackType,damageInfo->hitOutCome);
+ CleanDamage cleanDamage(damageInfo->cleanDamage,damageInfo->absorb,damageInfo->attackType,damageInfo->hitOutCome);
DealDamage(pVictim, damageInfo->damage, &cleanDamage, DIRECT_DAMAGE, SpellSchoolMask(damageInfo->damageSchoolMask), NULL, durabilityLoss);
// If this is a creature and it attacks from behind it has a probability to daze it's victim
@@ -1709,34 +1718,8 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
CastSpell(pVictim, 1604, true);
}
- if(GetTypeId() == TYPEID_PLAYER && pVictim->isAlive())
- {
- for(uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
- {
- // If usable, try to cast item spell
- if (Item * item = ((Player*)this)->GetUseableItemByPos(INVENTORY_SLOT_BAG_0,i))
- if(!item->IsBroken())
- if (ItemPrototype const *proto = item->GetProto())
- {
- // Additional check for weapons
- if (proto->Class==ITEM_CLASS_WEAPON)
- {
- // offhand item cannot proc from main hand hit etc
- EquipmentSlots slot;
- switch (damageInfo->attackType)
- {
- case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break;
- case OFF_ATTACK: slot = EQUIPMENT_SLOT_OFFHAND; break;
- case RANGED_ATTACK: slot = EQUIPMENT_SLOT_RANGED; break;
- default: slot = EQUIPMENT_SLOT_END; break;
- }
- if (slot != i)
- continue;
- }
- ((Player*)this)->CastItemCombatSpell(item, damageInfo, proto);
- }
- }
- }
+ if(GetTypeId() == TYPEID_PLAYER)
+ ((Player *)this)->CastItemCombatSpell(pVictim, damageInfo->attackType, damageInfo->procVictim, damageInfo->procEx);
// Do effect if any damage done to target
if (damageInfo->damage)
@@ -1903,6 +1886,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
// Reflect damage spells (not cast any damage spell in aura lookup)
uint32 reflectSpell = 0;
int32 reflectDamage = 0;
+ AuraEffect* reflectTriggeredBy = NULL; // expected as not expired at reflect as in current cases
uint32 healSpell = 0;
int32 healAmount = 0;
Unit * healCaster = NULL;
@@ -1968,6 +1952,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
else
reflectDamage = currentAbsorb / 2;
reflectSpell = 33619;
+ reflectTriggeredBy = *i;
break;
}
if (spellProto->Id == 39228 || // Argussian Compass
@@ -2037,13 +2022,13 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
{
case 5065: // Rank 1
case 5064: // Rank 2
- case 5063: // Rank 3
{
if(RemainingDamage >= currentAbsorb)
reflectDamage = (*k)->GetAmount() * currentAbsorb/100;
else
reflectDamage = (*k)->GetAmount() * RemainingDamage/100;
reflectSpell = 33619;
+ reflectTriggeredBy = *i;
} break;
}
}
@@ -2064,9 +2049,20 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
}
case SPELLFAMILY_DEATHKNIGHT:
{
- // Shadow of Death
- if (spellProto->Id == 49157)
+ // Unbreakable Armor
+ if (spellProto->Id == 51271)
{
+ Unit* caster = (*i)->GetCaster();
+ if (!caster)
+ continue;
+
+ uint32 absorbed = uint32( currentAbsorb * caster->GetArmor() * 0.01f );
+
+ // Glyph of Unbreakable Armor
+ if (AuraEffect *aurEff = caster->GetAuraEffect(58635, 0))
+ absorbed += uint32( absorbed * aurEff->GetAmount() / 100 );
+
+ RemainingDamage -= absorbed;
continue;
}
// Anti-Magic Shell (on self)
@@ -2146,7 +2142,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
// Cast back reflect damage spell
if (reflectSpell)
- pVictim->CastCustomSpell(this, reflectSpell, &reflectDamage, NULL, NULL, true);
+ pVictim->CastCustomSpell(this, reflectSpell, &reflectDamage, NULL, NULL, true, NULL, reflectTriggeredBy);
// absorb by mana cost
AuraEffectList const& vManaShield = pVictim->GetAurasByType(SPELL_AURA_MANA_SHIELD);
@@ -2217,7 +2213,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, splitted, schoolMask, splitted_absorb, 0, false, 0, false);
- CleanDamage cleanDamage = CleanDamage(splitted, BASE_ATTACK, MELEE_HIT_NORMAL);
+ CleanDamage cleanDamage = CleanDamage(splitted, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*i)->GetSpellProto(), false);
}
@@ -2244,7 +2240,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, splitted, schoolMask, split_absorb, 0, false, 0, false);
- CleanDamage cleanDamage = CleanDamage(splitted, BASE_ATTACK, MELEE_HIT_NORMAL);
+ CleanDamage cleanDamage = CleanDamage(splitted, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*i)->GetSpellProto(), false);
}
}
@@ -2364,6 +2360,7 @@ void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool ex
// Send log damage message to client
DealDamageMods(pVictim,damageInfo.damage,&damageInfo.absorb);
SendAttackStateUpdate(&damageInfo);
+
ProcDamageAndSpell(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage, damageInfo.attackType);
DealMeleeDamage(&damageInfo,true);
@@ -2795,6 +2792,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell)
bool canDodge = true;
bool canParry = true;
+ bool canBlock = spell->AttributesEx3 & SPELL_ATTR_EX3_BLOCKABLE_SPELL;
// Same spells cannot be parry/dodge
if (spell->Attributes & SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK)
@@ -2805,11 +2803,9 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell)
tmp += resist_chance;
if (roll < tmp)
return SPELL_MISS_RESIST;
-
- // Ranged attack cannot be parry/dodge only deflect
- // Check damage class instead of attack type to correctly handle judgements
- // - they are meele, but can't be dodged/parried/deflected because of ranged dmg class
- if (spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
+
+ // Ranged attacks can only miss, resist and deflect
+ if (attType == RANGED_ATTACK)
{
// only if in front
if (pVictim->HasInArc(M_PI,this))
@@ -2826,10 +2822,11 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell)
if (!pVictim->HasInArc(M_PI,this))
{
// Can`t dodge from behind in PvP (but its possible in PvE)
- if (GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER)
+ if (pVictim->GetTypeId() == TYPEID_PLAYER)
canDodge = false;
- // Can`t parry
+ // Can`t parry or block
canParry = false;
+ canBlock = false;
}
// Check creatures flags_extra for disable parry
if(pVictim->GetTypeId()==TYPEID_UNIT)
@@ -2837,6 +2834,9 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell)
uint32 flagEx = ((Creature*)pVictim)->GetCreatureInfo()->flags_extra;
if( flagEx & CREATURE_FLAG_EXTRA_NO_PARRY )
canParry = false;
+ // Check creatures flags_extra for disable block
+ if( flagEx & CREATURE_FLAG_EXTRA_NO_BLOCK )
+ canBlock = false;
}
// Ignore combat result aura
AuraEffectList const& ignore = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT);
@@ -2847,7 +2847,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell)
switch((*i)->GetMiscValue())
{
case MELEE_HIT_DODGE: canDodge = false; break;
- case MELEE_HIT_BLOCK: break; // Block check in hit step
+ case MELEE_HIT_BLOCK: canBlock = false; break;
case MELEE_HIT_PARRY: canParry = false; break;
default:
DEBUG_LOG("Spell %u SPELL_AURA_IGNORE_COMBAT_RESULT have unhandled state %d", (*i)->GetId(), (*i)->GetMiscValue());
@@ -2888,6 +2888,17 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell)
return SPELL_MISS_PARRY;
}
+ if (canBlock)
+ {
+ int32 blockChance = int32(pVictim->GetUnitBlockChance()*100.0f) - skillDiff * 4;
+ if ( blockChance < 0 )
+ blockChance = 0;
+ tmp += blockChance;
+
+ if (roll < tmp)
+ return SPELL_MISS_BLOCK;
+ }
+
return SPELL_MISS_NONE;
}
@@ -3002,7 +3013,7 @@ SpellMissInfo Unit::SpellHitResult(Unit *pVictim, SpellEntry const *spell, bool
if (reflectchance > 0 && roll_chance_i(reflectchance))
{
// Start triggers for remove charges if need (trigger only for victim, and mark as active spell)
- ProcDamageAndSpell(pVictim, PROC_FLAG_NONE, PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT, PROC_EX_REFLECT, 0, BASE_ATTACK, spell);
+ ProcDamageAndSpell(pVictim, PROC_FLAG_NONE, PROC_FLAG_TAKEN_NEGATIVE_MAGIC_SPELL, PROC_EX_REFLECT , 1, BASE_ATTACK, spell);
return SPELL_MISS_REFLECT;
}
}
@@ -3491,8 +3502,8 @@ void Unit::InterruptSpell(uint32 spellType, bool withDelayed, bool withInstant)
// send autorepeat cancel message for autorepeat spells
if (spellType == CURRENT_AUTOREPEAT_SPELL)
{
- if(GetTypeId()==TYPEID_PLAYER)
- ((Player*)this)->SendAutoRepeatCancel();
+ if(GetTypeId() == TYPEID_PLAYER)
+ ((Player*)this)->SendAutoRepeatCancel(this);
}
if (spell->getState() != SPELL_STATE_FINISHED)
@@ -3510,15 +3521,17 @@ bool Unit::IsNonMeleeSpellCasted(bool withDelayed, bool skipChanneled, bool skip
if ( m_currentSpells[CURRENT_GENERIC_SPELL] &&
(m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_FINISHED) &&
(withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED) )
+ {
if (!isAutoshoot || !(m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_NOT_RESET_AUTOSHOT))
return(true);
-
+ }
// channeled spells may be delayed, but they are still considered casted
else if ( !skipChanneled && m_currentSpells[CURRENT_CHANNELED_SPELL] &&
(m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED) )
+ {
if (!isAutoshoot || !(m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_NOT_RESET_AUTOSHOT))
return(true);
-
+ }
// autorepeat spells may be finished or delayed, but they are still considered casted
else if ( !skipAutorepeat && m_currentSpells[CURRENT_AUTOREPEAT_SPELL] )
return(true);
@@ -3549,6 +3562,13 @@ Spell* Unit::FindCurrentSpellBySpellId(uint32 spell_id) const
return NULL;
}
+int32 Unit::GetCurrentSpellCastTime(uint32 spell_id) const
+{
+ if (Spell const * spell = FindCurrentSpellBySpellId(spell_id))
+ return spell->GetCastTime();
+ return 0;
+}
+
bool Unit::isInFrontInMap(Unit const* target, float distance, float arc) const
{
return IsWithinDistInMap(target, distance) && HasInArc( arc, target );
@@ -3779,8 +3799,11 @@ bool Unit::AddAura(Aura *Aur, bool handleEffects)
return false;
}
+ SpellEntry const* aurSpellInfo = Aur->GetSpellProto();
+
// ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
- if( !isAlive() && Aur->GetId() != 20584 && Aur->GetId() != 8326 && Aur->GetId() != 2584 &&
+ if( !isAlive() && !IsDeathPersistentSpell(aurSpellInfo) &&
+ //Aur->GetId() != 2584 && // Waiting to Resurrect (not have death persistence flag)
(GetTypeId()!=TYPEID_PLAYER || !((Player*)this)->GetSession()->PlayerLoading()) )
{
delete Aur;
@@ -3796,7 +3819,6 @@ bool Unit::AddAura(Aura *Aur, bool handleEffects)
return false;
}
- SpellEntry const* aurSpellInfo = Aur->GetSpellProto();
uint32 aurId = aurSpellInfo->Id;
// passive and persistent and Incanter's Absorption auras can stack with themselves any number of times
@@ -3890,6 +3912,16 @@ bool Unit::AddAura(Aura *Aur, bool handleEffects)
// add aura, register in lists and arrays
Aur->_AddAura();
+
+ //*****************************************************
+ // Update target aura state flag
+ //*****************************************************
+ if(AuraState aState = GetSpellAuraState(Aur->GetSpellProto()))
+ {
+ m_auraStateAuras.insert(AuraStateAurasMap::value_type(aState, Aur));
+ ModifyAuraState(aState, true);
+ }
+
m_Auras.insert(AuraMap::value_type(aurId, Aur));
if(aurSpellInfo->AuraInterruptFlags)
@@ -3897,12 +3929,6 @@ bool Unit::AddAura(Aura *Aur, bool handleEffects)
m_interruptableAuras.push_back(Aur);
AddInterruptMask(aurSpellInfo->AuraInterruptFlags);
}
- if((aurSpellInfo->Attributes & SPELL_ATTR_BREAKABLE_BY_DAMAGE
- && !Aur->IsAuraType(SPELL_AURA_MOD_POSSESS)) //only dummy aura is breakable
- || ((GetAllSpellMechanicMask(aurSpellInfo) & 1<<MECHANIC_KNOCKOUT) && Aur->IsAuraType(SPELL_AURA_MOD_STUN)))
- {
- m_ccAuras.push_back(Aur);
- }
if (handleEffects)
Aur->HandleEffects(true);
@@ -4173,13 +4199,24 @@ void Unit::RemoveAurasByTypeWithDispel(AuraType auraType, Spell * spell)
}
}
-void Unit::RemoveNotOwnSingleTargetAuras()
+void Unit::RemoveNotOwnSingleTargetAuras(uint32 newPhase)
{
// single target auras from other casters
for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); )
{
if (iter->second->GetCasterGUID()!=GetGUID() && IsSingleTargetSpell(iter->second->GetSpellProto()))
- RemoveAura(iter);
+ {
+ if(!newPhase)
+ RemoveAura(iter);
+ else
+ {
+ Unit* caster = iter->second->GetCaster();
+ if(!caster || !caster->InSamePhase(newPhase))
+ RemoveAura(iter);
+ else
+ ++iter;
+ }
+ }
else
++iter;
}
@@ -4188,12 +4225,12 @@ void Unit::RemoveNotOwnSingleTargetAuras()
AuraList& scAuras = GetSingleCastAuras();
for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end();)
{
- Aura * aur=*iter;
+ Aura * aura=*iter;
++iter;
- if (aur->GetTarget()!=this)
+ if (aura->GetTarget() != this && !aura->GetTarget()->InSamePhase(newPhase))
{
uint32 removedAuras = m_removedAurasCount;
- aur->GetTarget()->RemoveAura(aur->GetId(),aur->GetCasterGUID());
+ aura->GetTarget()->RemoveAura(aura->GetId(),aura->GetCasterGUID());
if (removedAuras+1<m_removedAurasCount)
iter=scAuras.begin();
}
@@ -4217,13 +4254,6 @@ void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode)
UpdateInterruptMask();
}
- if((Aur->GetSpellProto()->Attributes & SPELL_ATTR_BREAKABLE_BY_DAMAGE
- && !Aur->IsAuraType(SPELL_AURA_MOD_POSSESS)) //only dummy aura is breakable
- || ((GetAllSpellMechanicMask(Aur->GetSpellProto()) & 1<<MECHANIC_KNOCKOUT) && Aur->IsAuraType(SPELL_AURA_MOD_STUN)))
- {
- m_ccAuras.remove(Aur);
- }
-
Aur->SetRemoveMode(mode);
sLog.outDebug("Aura %u now is remove mode %d", Aur->GetId(), mode);
@@ -4234,8 +4264,30 @@ void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode)
Aur->_RemoveAura();
+ bool auraStateFound = false;
+ if (AuraState auraState = GetSpellAuraState(Aur->GetSpellProto()))
+ {
+ bool canBreak = false;
+ // Get mask of all aurastates from remaining auras
+ for(AuraStateAurasMap::iterator itr = m_auraStateAuras.lower_bound(auraState); itr != m_auraStateAuras.upper_bound(auraState) && !(auraStateFound && canBreak);)
+ {
+ if (itr->second == Aur)
+ {
+ m_auraStateAuras.erase(itr);
+ itr = m_auraStateAuras.lower_bound(auraState);
+ canBreak = true;
+ continue;
+ }
+ auraStateFound = true;
+ ++itr;
+ }
+ // Remove only aurastates which were not found
+ if (!auraStateFound)
+ ModifyAuraState(auraState, false);
+ }
+
// Remove totem at next update if totem looses its aura
- if (GetTypeId()==TYPEID_UNIT && ((Creature*)this)->isTotem()&& ((TempSummon*)this)->GetSummonerGUID()==Aur->GetCasterGUID())
+ if (Aur->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE && GetTypeId()==TYPEID_UNIT && ((Creature*)this)->isTotem()&& ((TempSummon*)this)->GetSummonerGUID()==Aur->GetCasterGUID())
{
if (((Totem*)this)->GetSpell()==Aur->GetId() && ((Totem*)this)->GetTotemType()==TOTEM_PASSIVE)
((Totem*)this)->setDeathState(JUST_DIED);
@@ -4401,6 +4453,18 @@ AuraEffect* Unit::GetAura(AuraType type, uint32 family, uint32 familyFlag1, uint
return NULL;
}
+AuraEffect * Unit::IsScriptOverriden(SpellEntry const * spell, int32 script) const
+{
+ AuraEffectList const& auras = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
+ for(AuraEffectList::const_iterator i = auras.begin();i != auras.end(); ++i)
+ {
+ if ((*i)->GetMiscValue() == script)
+ if ((*i)->isAffectedOnSpell(spell))
+ return (*i);
+ }
+ return NULL;
+}
+
uint32 Unit::GetDiseasesByCaster(uint64 casterGUID, bool remove)
{
static const AuraType diseaseAuraTypes[] =
@@ -4685,13 +4749,13 @@ void Unit::SendPeriodicAuraLog(SpellPeriodicAuraLogInfo *pInfo)
data << uint32(GetSpellSchoolMask(aura->GetSpellProto()));
data << uint32(pInfo->absorb); // absorb
data << uint32(pInfo->resist); // resist
- data << uint8(0); // new 3.1.2
+ data << uint8(pInfo->critical); // new 3.1.2 critical tick
break;
case SPELL_AURA_PERIODIC_HEAL:
case SPELL_AURA_OBS_MOD_HEALTH:
data << uint32(pInfo->damage); // damage
data << uint32(pInfo->overDamage); // overheal?
- data << uint8(0); // new 3.1.2
+ data << uint8(pInfo->critical); // new 3.1.2 critical tick
break;
case SPELL_AURA_OBS_MOD_ENERGY:
case SPELL_AURA_PERIODIC_ENERGIZE:
@@ -4827,7 +4891,7 @@ bool Unit::HandleHasteAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
case 33735:
{
target = SelectNearbyTarget();
- if(!target)
+ if(!target || target == pVictim)
return false;
basepoints0 = damage;
triggered_spell_id = 22482;
@@ -4851,7 +4915,7 @@ bool Unit::HandleHasteAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
}
// default case
- if(!target || target!=this && !target->isAlive())
+ if((!target && !spellmgr.IsSrcTargetSpell(triggerEntry)) || (target && target!=this && !target->isAlive()))
return false;
if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id))
@@ -4880,6 +4944,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
uint32 triggered_spell_id = 0;
Unit* target = pVictim;
int32 basepoints0 = 0;
+ uint64 originalCaster = 0;
// Master of subtlety (checked here because ranks have different spellfamilynames)
if (dummySpell->Id == 31223 || dummySpell->Id == 31221 || dummySpell->Id == 31222)
@@ -4898,6 +4963,18 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
{
switch (dummySpell->Id)
{
+ // BloodWorms Health Leech
+ case 50453:
+ {
+ if (Unit *owner = this->GetOwner())
+ {
+ basepoints0 = int32(damage*1.50);
+ target = owner;
+ triggered_spell_id = 50454;
+ break;
+ }
+ return false;
+ }
// Improved Divine Spirit
case 33174:
case 33182:
@@ -4939,14 +5016,9 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
break;
}
// Sweeping Strikes
- case 12328:
case 18765:
case 35429:
{
- // prevent chain of triggered spell from same triggered spell
- if(procSpell && procSpell->Id==26654)
- return false;
-
target = SelectNearbyTarget();
if(!target)
return false;
@@ -5411,11 +5483,20 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
}
switch(dummySpell->Id)
{
+ // Glyph of Polymorph
+ case 56375:
+ {
+ target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
+ target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT);
+ return true;
+ }
// Glyph of Icy Veins
case 56374:
+ {
RemoveAurasByType(SPELL_AURA_MOD_HASTE, 0, 0, true, false);
RemoveAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
- return true;
+ return true;
+ }
// Ignite
case 11119:
case 11120:
@@ -5474,6 +5555,28 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
}
case SPELLFAMILY_WARRIOR:
{
+ switch(dummySpell->Id)
+ {
+ // Sweeping Strikes
+ case 12328:
+ {
+ target = SelectNearbyTarget();
+ if(!target)
+ return false;
+
+ triggered_spell_id = 26654;
+ break;
+ }
+ // Improved Spell Reflection
+ case 59088:
+ case 59089:
+ {
+ triggered_spell_id = 59725;
+ target = this;
+ break;
+ }
+ }
+
// Retaliation
if(dummySpell->SpellFamilyFlags.IsEqual(0, 0x8, 0))
{
@@ -5484,14 +5587,6 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
triggered_spell_id = 22858;
break;
}
- // Improved Spell Reflection
- if(dummySpell->Id==59088
- || dummySpell->Id==59089)
- {
- triggered_spell_id = 59725;
- target = this;
- break;
- }
// Second Wind
if (dummySpell->SpellIconID == 1697)
{
@@ -5613,6 +5708,8 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
{
if ((*i)->GetId()==54117 || (*i)->GetId()==54118)
{
+ if ((*i)->GetEffIndex() != 0)
+ continue;
basepoints0 = int32((*i)->GetAmount());
if (target = GetGuardianPet())
{
@@ -5621,6 +5718,15 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
}
// regen mana for caster
CastCustomSpell(this,59117,&basepoints0,NULL,NULL,true,castItem,triggeredByAura);
+ // Get second aura of spell for replenishment effect on party
+ if (AuraEffect const * aurEff = (*i)->GetParentAura()->GetPartAura(1))
+ {
+ // Replenishment - roll chance
+ if (roll_chance_i(aurEff->GetAmount()))
+ {
+ CastSpell(this,57669,true, castItem, triggeredByAura);
+ }
+ }
break;
}
}
@@ -5806,22 +5912,6 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
}
break;
}
- // Psychic Horror
- case 47571:
- {
- if(!pVictim || !pVictim->isAlive())
- return false;
- pVictim->CastSpell(pVictim, 59980,true, castItem, triggeredByAura);
- return true;
- }
- // Psychic Horror (Rank 2)
- case 47572:
- {
- if(!pVictim || !pVictim->isAlive())
- return false;
- pVictim->CastSpell(pVictim, 59981,true, castItem, triggeredByAura);
- return true;
- }
// Glyph of Dispel Magic
case 55677:
{
@@ -5884,10 +5974,13 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
basepoints0 = triggerAmount * GetMaxHealth() / 100;
target = this;
triggered_spell_id = 34299;
- if (triggeredByAura->GetCaster() != this)
+ if (triggeredByAura->GetCasterGUID() != GetGUID())
break;
int32 basepoints1 = triggerAmount * 2;
- CastCustomSpell(this,60889,&basepoints1,0,0,true,0,triggeredByAura);
+ // Improved Leader of the Pack
+ // Check cooldown of heal spell cooldown
+ if (GetTypeId()==TYPEID_PLAYER && !((Player *)this)->HasSpellCooldown(34299))
+ CastCustomSpell(this,60889,&basepoints1,0,0,true,0,triggeredByAura);
break;
}
// Healing Touch (Dreamwalker Raiment set)
@@ -5940,7 +6033,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
triggered_spell_id = 40446;
chance = 25.0f;
}
- // Mangle (cat/bear)
+ // Mangle (Bear) and Mangle (Cat)
else if( procSpell->SpellFamilyFlags[1] & 0x00000440)
{
triggered_spell_id = 40452;
@@ -5998,6 +6091,30 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
basepoints0 = triggerAmount * damage / 100;
break;
}
+ // King of the Jungle
+ else if (dummySpell->SpellIconID == 2850)
+ {
+ // Effect 0 - mod damage while having Enrage
+ if (effIndex==0)
+ {
+ if (!(procSpell->SpellFamilyFlags[0] & 0x00080000))
+ return false;
+ triggered_spell_id = 51185;
+ basepoints0 = triggerAmount;
+ target = this;
+ break;
+ }
+ // Effect 1 - Tiger's Fury restore energy
+ else if (effIndex==1)
+ {
+ if (!(procSpell->SpellFamilyFlags[2] & 0x00000800))
+ return false;
+ triggered_spell_id = 51178;
+ basepoints0 = triggerAmount;
+ target = this;
+ break;
+ }
+ }
break;
}
case SPELLFAMILY_ROGUE:
@@ -6114,36 +6231,26 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
// Light's Beacon - Beacon of Light
if ( dummySpell->Id == 53651 )
{
- if (Unit * caster = triggeredByAura->GetCaster())
+ if (Unit * source = triggeredByAura->GetSource())
{
// do not proc when target of beacon of light is healed
- if (caster == pVictim)
+ if (source == this)
return false;
- if (Aura const* aur = caster->GetAura(53563))
+ if (Unit * caster = triggeredByAura->GetCaster())
{
- if (Unit * paladin = aur->GetCaster())
- {
- if (paladin != this)
- return false;
- basepoints0 = damage;
- triggered_spell_id = 53654;
- target = caster;
- break;
- }
- else
- {
- pVictim->RemoveAura(triggeredByAura->GetParentAura());
+ if (caster != pVictim)
return false;
- }
+ basepoints0 = damage;
+ triggered_spell_id = 53654;
+ target = source;
+ break;
}
}
- else return false;
+ return false;
}
// Judgements of the Wise
if (dummySpell->SpellIconID == 3017)
{
- // hardcoded amount
- basepoints0 = 15 * GetCreatePowers(POWER_MANA)/100;
target = this;
triggered_spell_id = 31930;
// replenishment
@@ -6184,17 +6291,19 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
}
switch(dummySpell->Id)
{
+ // Heart of the Crusader
+ case 20335: // rank 1
+ triggered_spell_id = 21183;
+ break;
+ case 20336: // rank 2
+ triggered_spell_id = 54498;
+ break;
+ case 20337: // rank 3
+ triggered_spell_id = 54499;
+ break;
// Judgement of Light
case 20185:
{
- // Get judgement caster
- Unit *caster = triggeredByAura->GetCaster();
- if (!caster)
- return false;
- float ap = caster->GetTotalAttackPowerValue(BASE_ATTACK);
- int32 holy = caster->SpellBaseDamageBonus(SPELL_SCHOOL_MASK_HOLY) +
- caster->SpellBaseDamageBonusForVictim(SPELL_SCHOOL_MASK_HOLY, this);
- basepoints0 = int32(ap*0.10f + 0.10f*holy);
pVictim->CastCustomSpell(pVictim, 20267, &basepoints0, 0, 0, true, 0, triggeredByAura);
return true;
}
@@ -6269,7 +6378,9 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
// heal amount
basepoints0 = triggerAmount*damage/100;
target = this;
- triggered_spell_id = 31786;
+
+ if(basepoints0)
+ triggered_spell_id = 31786;
break;
}
// Seal of Blood do damage trigger
@@ -6320,8 +6431,8 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
triggered_spell_id = 40471;
chance = 15.0f;
}
- // Judgement
- else if( procSpell->SpellFamilyFlags[0] & 0x800000 )
+ // Judgement (any)
+ else if (GetSpellSpecific(procSpell->Id)==SPELL_JUDGEMENT)
{
triggered_spell_id = 40472;
chance = 50.0f;
@@ -6433,6 +6544,9 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
if( cooldown && ((Player*)this)->HasSpellCooldown(dummySpell->Id))
return false;
+ if(triggeredByAura->GetParentAura() && castItem->GetGUID() != triggeredByAura->GetParentAura()->GetCastItemGUID())
+ return false;
+
// Now amount of extra power stored in 1 effect of Enchant spell
// Get it by item enchant id
uint32 spellId;
@@ -6463,20 +6577,21 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
int32 extra_attack_power = CalculateSpellDamage(windfurySpellEntry, 1, windfurySpellEntry->EffectBasePoints[1], pVictim);
- // Off-Hand case
- if ( castItem->GetSlot() == EQUIPMENT_SLOT_OFFHAND && isAttackReady(OFF_ATTACK) )
- {
- // Value gained from additional AP
- basepoints0 = int32(extra_attack_power/14.0f * GetAttackTime(OFF_ATTACK)/1000/2);
- triggered_spell_id = 33750;
- }
// Main-Hand case
- else if ( isAttackReady(BASE_ATTACK) )
+ if ( castItem->GetSlot() == EQUIPMENT_SLOT_MAINHAND && isAttackReady(BASE_ATTACK) )
{
// Value gained from additional AP
basepoints0 = int32(extra_attack_power/14.0f * GetAttackTime(BASE_ATTACK)/1000);
triggered_spell_id = 25504;
}
+ // Off-Hand case
+ else if ( castItem->GetSlot() == EQUIPMENT_SLOT_OFFHAND && isAttackReady(OFF_ATTACK) )
+ {
+ // Value gained from additional AP
+ basepoints0 = int32(extra_attack_power/14.0f * GetAttackTime(OFF_ATTACK)/1000/2);
+ triggered_spell_id = 33750;
+ }
+
else
return false;
@@ -6543,6 +6658,13 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
triggered_spell_id = 58879;
break;
}
+ // Shaman T8 Elemental 4P Bonus
+ case 64928:
+ {
+ basepoints0 = int32( triggerAmount * damage / 100 );
+ triggered_spell_id = 64930; // Electrified
+ break;
+ }
}
// Storm, Earth and Fire
if (dummySpell->SpellIconID == 3063)
@@ -6569,6 +6691,8 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
// Earth Shield
if(dummySpell->SpellFamilyFlags[1] & 0x00000400)
{
+ // 3.0.8: Now correctly uses the Shaman's own spell critical strike chance to determine the chance of a critical heal.
+ originalCaster = triggeredByAura->GetCasterGUID();
basepoints0 = triggerAmount;
target = this;
triggered_spell_id = 379;
@@ -6816,13 +6940,6 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
triggered_spell_id = 50526;
break;
}
- // Death Strike healing effect
- if (dummySpell->Id == 45469)
- {
- int32 heal=pVictim->GetDiseasesByCaster(GetGUID()) * GetMaxHealth()* 5 /100;
- CastCustomSpell(this,45470,&heal,NULL,NULL,true);
- return true;
- }
// Sudden Doom
if (dummySpell->SpellIconID == 1939 && GetTypeId() == TYPEID_PLAYER)
{
@@ -6925,23 +7042,22 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
}
// default case
- if(!target || target!=this && !target->isAlive())
+ if((!target && !spellmgr.IsSrcTargetSpell(triggerEntry)) || (target && target!=this && !target->isAlive()))
return false;
if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id))
return false;
if(basepoints0)
- CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura);
+ CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura, originalCaster);
else
- CastSpell(target,triggered_spell_id,true,castItem,triggeredByAura);
+ CastSpell(target,triggered_spell_id,true,castItem,triggeredByAura, originalCaster);
if( cooldown && GetTypeId()==TYPEID_PLAYER )
((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown);
return true;
}
-
bool Unit::HandleObsModEnergyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const * procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown)
{
SpellEntry const *dummySpell = triggeredByAura->GetSpellProto ();
@@ -6964,7 +7080,6 @@ bool Unit::HandleObsModEnergyAuraProc(Unit *pVictim, uint32 damage, AuraEffect*
{
uint32 maxmana = GetMaxPower(POWER_MANA);
basepoints0 = maxmana* GetAttackTime(RANGED_ATTACK)/1000.0f/100.0f;
-
target = this;
triggered_spell_id = 34075;
break;
@@ -6978,6 +7093,7 @@ bool Unit::HandleObsModEnergyAuraProc(Unit *pVictim, uint32 damage, AuraEffect*
SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
+ // Try handle unknown trigger spells
if(!triggerEntry)
{
sLog.outError("Unit::HandleObsModEnergyAuraProc: Spell %u have not existed triggered spell %u",dummySpell->Id,triggered_spell_id);
@@ -6985,12 +7101,11 @@ bool Unit::HandleObsModEnergyAuraProc(Unit *pVictim, uint32 damage, AuraEffect*
}
// default case
- if(!target || target!=this && !target->isAlive())
+ if((!target && !spellmgr.IsSrcTargetSpell(triggerEntry)) || (target && target!=this && !target->isAlive()))
return false;
if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id))
return false;
-
if(basepoints0)
CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura);
else
@@ -6998,10 +7113,8 @@ bool Unit::HandleObsModEnergyAuraProc(Unit *pVictim, uint32 damage, AuraEffect*
if( cooldown && GetTypeId()==TYPEID_PLAYER )
((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown);
-
return true;
}
-
bool Unit::HandleModDamagePctTakenAuraProc(Unit *pVictim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const * procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown)
{
SpellEntry const *dummySpell = triggeredByAura->GetSpellProto ();
@@ -7025,8 +7138,6 @@ bool Unit::HandleModDamagePctTakenAuraProc(Unit *pVictim, uint32 damage, AuraEff
switch (getPowerType())
{
case POWER_MANA: triggered_spell_id = 57319; break;
- case POWER_RAGE: triggered_spell_id = 57320; break;
- case POWER_RUNIC_POWER: triggered_spell_id = 57321; break;
default:
return false;
}
@@ -7047,7 +7158,7 @@ bool Unit::HandleModDamagePctTakenAuraProc(Unit *pVictim, uint32 damage, AuraEff
}
// default case
- if(!target || target!=this && !target->isAlive())
+ if((!target && !spellmgr.IsSrcTargetSpell(triggerEntry)) || (target && target!=this && !target->isAlive()))
return false;
if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id))
@@ -7074,12 +7185,66 @@ bool Unit::HandleAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAura, S
{
case SPELLFAMILY_DEATHKNIGHT:
{
+ // Blood of the North
+ // Reaping
+ // Death Rune Mastery
+ if (dummySpell->SpellIconID == 3041 || dummySpell->SpellIconID == 22 || dummySpell->SpellIconID == 2622)
+ {
+ *handled = true;
+ // Convert recently used Blood Rune to Death Rune
+ if (GetTypeId() == TYPEID_PLAYER)
+ {
+ if(((Player*)this)->getClass() != CLASS_DEATH_KNIGHT)
+ return false;
+ RuneType rune = ((Player*)this)->GetLastUsedRune();
+ // can't proc from death rune use
+ if (rune == RUNE_DEATH)
+ return false;
+ AuraEffect * aurEff = triggeredByAura->GetPartAura(0);
+ if (!aurEff)
+ return false;
+ // Reset amplitude - set death rune remove timer to 30s
+ aurEff->ResetPeriodicTimer();
+ uint32 runesLeft;
+
+ if (dummySpell->SpellIconID == 2622)
+ runesLeft = 2;
+ else
+ runesLeft = 1;
+
+ for (uint8 i=0;i<MAX_RUNES && runesLeft;++i)
+ {
+ if (dummySpell->SpellIconID == 2622)
+ {
+ if (((Player*)this)->GetCurrentRune(i) == RUNE_DEATH ||
+ ((Player*)this)->GetBaseRune(i) == RUNE_BLOOD )
+ continue;
+ }
+ else
+ {
+ if (((Player*)this)->GetCurrentRune(i) == RUNE_DEATH ||
+ ((Player*)this)->GetBaseRune(i) != RUNE_BLOOD )
+ continue;
+ }
+ if (((Player*)this)->GetRuneCooldown(i) != RUNE_COOLDOWN)
+ continue;
+
+ --runesLeft;
+ // Mark aura as used
+ aurEff->SetAmount(aurEff->GetAmount() | (1<<i));
+ ((Player*)this)->ConvertRune(i,RUNE_DEATH);
+ }
+ return true;
+ }
+ return false;
+ }
+
switch(dummySpell->Id)
{
// Hungering Cold aura drop
case 51209:
*handled = true;
- // Drop only in disease case
+ // Drop only in not disease case
if (procSpell && procSpell->Dispel == DISPEL_DISEASE)
return false;
return true;
@@ -7273,38 +7438,8 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig
break;
case SPELLFAMILY_WARLOCK:
{
- // Pyroclasm
- if (auraSpellInfo->SpellIconID == 1137)
- {
- if(!pVictim || !pVictim->isAlive() || pVictim == this || procSpell == NULL)
- return false;
- // Calculate spell tick count for spells
- uint32 tick;
-
- // Hellfire have 15 tick
- if (procSpell->SpellFamilyFlags[0]&0x40)
- tick = 15;
- // Rain of Fire have 4 tick
- else if (procSpell->SpellFamilyFlags[0]&0x20)
- tick = 4;
- else
- tick = 1;
-
- // Calculate chance = baseChance / tick
- float chance = 0;
- switch (auraSpellInfo->Id)
- {
- case 18096: chance = 13.0f / tick; break;
- case 18073: chance = 26.0f / tick; break;
- }
- // Roll chance
- if (!roll_chance_f(chance))
- return false;
-
- trigger_spell_id = 18093;
- }
// Improved Drain Soul
- else if (auraSpellInfo->SpellFamilyFlags[0] & 0x4000)
+ if (auraSpellInfo->SpellFamilyFlags[0] & 0x4000)
{
Unit::AuraEffectList const& mAddFlatModifier = GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraEffectList::const_iterator i = mAddFlatModifier.begin(); i != mAddFlatModifier.end(); ++i)
@@ -7387,7 +7522,28 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig
break;
}
case SPELLFAMILY_HUNTER:
+ {
+ if (auraSpellInfo->SpellIconID == 3247) // Piercing Shots
+ {
+ switch (auraSpellInfo->Id)
+ {
+ case 53234: // Rank 1
+ case 53237: // Rank 2
+ case 53238: // Rank 3
+ trigger_spell_id = 63468;
+ break;
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Piercing Shots",auraSpellInfo->Id);
+ return false;
+ }
+ SpellEntry const *TriggerPS = sSpellStore.LookupEntry(trigger_spell_id);
+ if(!TriggerPS)
+ return false;
+ basepoints0 = int32(damage * triggerAmount / 100 / (GetSpellMaxDuration(TriggerPS) / TriggerPS->EffectAmplitude[0]));
+ target = pVictim;
+ }
break;
+ }
case SPELLFAMILY_PALADIN:
{
/*
@@ -7462,9 +7618,9 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig
// stacking
CastSpell(this, 37658, true, NULL, triggeredByAura);
- AuraEffect * dummy = GetDummyAura(37658);
+ Aura * dummy = GetAura(37658);
// release at 3 aura in stack (cont contain in basepoint of trigger aura)
- if(!dummy || dummy->GetParentAura()->GetStackAmount() < triggerAmount)
+ if(!dummy || dummy->GetStackAmount() < triggerAmount)
return false;
RemoveAurasDueToSpell(37658);
@@ -7480,9 +7636,9 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig
CastSpell(this, 54842, true, NULL, triggeredByAura);
// counting
- AuraEffect * dummy = GetDummyAura(54842);
+ Aura * dummy = GetAura(54842);
// release at 3 aura in stack (cont contain in basepoint of trigger aura)
- if(!dummy || dummy->GetParentAura()->GetStackAmount() < triggerAmount)
+ if(!dummy || dummy->GetStackAmount() < triggerAmount)
return false;
RemoveAurasDueToSpell(54842);
@@ -7580,8 +7736,8 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig
return false;
}
}
- // Blood Presence
- else if (auraSpellInfo->Id == 48266)
+ // Blood Presence (Improved)
+ else if (auraSpellInfo->Id == 63611)
{
if (GetTypeId() != TYPEID_PLAYER)
return false;
@@ -7761,7 +7917,7 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig
case 22959:
{
// Glyph of Improved Scorch
- if (AuraEffect * aurEff = GetDummyAura(56371))
+ if (AuraEffect * aurEff = GetAuraEffect(56371,0))
{
for (int32 count = aurEff->GetAmount();count>0;count--)
CastSpell(pVictim, 22959, true);
@@ -7795,10 +7951,9 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig
if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet())
if (Unit * owner = GetOwner())
{
- if (AuraEffect * aurEff = owner->GetDummyAura(SPELLFAMILY_WARLOCK, 3220))
+ if (AuraEffect * aurEff = owner->GetDummyAura(SPELLFAMILY_WARLOCK, 3220, 0))
{
- if (owner->GetTypeId() == TYPEID_PLAYER)
- basepoints0 = (aurEff->GetAmount() * ((Player*)owner)->GetBaseSpellDamageBonus() + 100.0f) / 100;
+ basepoints0 = int32((aurEff->GetAmount() * owner->SpellBaseDamageBonus(SpellSchoolMask(SPELL_SCHOOL_MASK_MAGIC)) + 100.0f) / 100.0f);
CastCustomSpell(this,trigger_spell_id,&basepoints0,&basepoints0,NULL,true,castItem,triggeredByAura);
return true;
}
@@ -7808,14 +7963,20 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig
// Sword and Board
case 50227:
{
- // remove cooldown of Shield Slam
+ // Remove cooldown on Shield Slam
if (GetTypeId()==TYPEID_PLAYER)
- ((Player*)this)->RemoveCategoryCooldown(1209);
+ ((Player*)this)->RemoveSpellCategoryCooldown(1209, true);
break;
}
- case 63375: // Improved Stormstrike
+ // Maelstrom Weapon
+ case 53817:
{
- basepoints0 = GetCreateMana() * 0.20f;
+ // have rank dependent proc chance, ignore too often cases
+ // PPM = 2.5 * (rank of talent),
+ uint32 rank = spellmgr.GetSpellRank(auraSpellInfo->Id);
+ // 5 rank -> 100% 4 rank -> 80% and etc from full rate
+ if(!roll_chance_i(20*rank))
+ return false;
break;
}
// Brain Freeze
@@ -7867,7 +8028,15 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig
case 56453:
{
// Proc only from trap activation (from periodic proc another aura of this spell)
- if (!(procFlags & PROC_FLAG_ON_TRAP_ACTIVATION))
+ if (!(procFlags & PROC_FLAG_ON_TRAP_ACTIVATION) || !roll_chance_i(triggerAmount))
+ return false;
+ break;
+ }
+ // Glyph of Death's Embrace
+ case 58679:
+ {
+ // Proc only from healing part of Death Coil. Check is essential as all Death Coil spells have 0x2000 mask in SpellFamilyFlags
+ if (!procSpell || !(procSpell->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && procSpell->SpellFamilyFlags[0] == 0x80002000))
return false;
break;
}
@@ -7879,6 +8048,12 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig
((Player*)this)->RemoveCategoryCooldown(82);
return true;
}
+ // Savage Defense
+ case 62606:
+ {
+ basepoints0 = int32(GetTotalAttackPowerValue(BASE_ATTACK) * triggerAmount / 100.0f);
+ break;
+ }
}
if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(trigger_spell_id))
@@ -7886,16 +8061,14 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig
// try detect target manually if not set
if ( target == NULL )
- target = !(procFlags & PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL) && IsPositiveSpell(trigger_spell_id) ? this : pVictim;
+ target = !(procFlags & (PROC_FLAG_SUCCESSFUL_POSITIVE_MAGIC_SPELL | PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL_HIT)) && IsPositiveSpell(trigger_spell_id) ? this : pVictim;
// default case
- if(!target || target!=this && !target->isAlive())
+ if((!target && !spellmgr.IsSrcTargetSpell(triggerEntry)) || (target && target!=this && !target->isAlive()))
return false;
if(basepoints0)
CastCustomSpell(target,trigger_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura);
- //else if(spellmgr.GetSpellCustomAttr(trigger_spell_id) & SPELL_ATTR_CU_AURA_SPELL)
- // AddAura(trigger_spell_id, target);
else
CastSpell(target,trigger_spell_id,true,castItem,triggeredByAura);
@@ -7982,6 +8155,21 @@ bool Unit::HandleOverrideClassScriptAuraProc(Unit *pVictim, uint32 damage, AuraE
CastCustomSpell(this, 47762, &basepoints0, 0, 0, true, 0, triggeredByAura);
return true;
}
+ case 7010: // Revitalize - can proc on full hp target
+ case 7011:
+ case 7012:
+ {
+ if (!roll_chance_i(triggeredByAura->GetAmount()))
+ return false;
+ switch(pVictim->getPowerType())
+ {
+ case POWER_MANA: triggered_spell_id = 48542; break;
+ case POWER_RAGE: triggered_spell_id = 48541; break;
+ case POWER_ENERGY: triggered_spell_id = 48540; break;
+ case POWER_RUNIC_POWER: triggered_spell_id = 48543; break;
+ }
+ break;
+ }
}
// not processed
@@ -8329,7 +8517,7 @@ bool Unit::Attack(Unit *victim, bool meleeAttack)
return false;
// dead units can neither attack nor be attacked
- if(!isAlive() || !victim->isAlive())
+ if(!isAlive() || !victim->IsInWorld() || !victim->isAlive())
return false;
// player cannot attack in mount state
@@ -8388,7 +8576,7 @@ bool Unit::Attack(Unit *victim, bool meleeAttack)
//if(GetTypeId()==TYPEID_UNIT)
// ((Creature*)this)->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
- if(GetTypeId()==TYPEID_UNIT && !IsControlledByPlayer())
+ if(GetTypeId()==TYPEID_UNIT)
{
// should not let player enter combat by right clicking target
SetInCombatWith(victim);
@@ -8529,14 +8717,6 @@ void Unit::ModifyAuraState(AuraState flag, bool apply)
SpellEntry const* spellProto = (*itr).second->GetSpellProto();
if (spellProto->CasterAuraState == flag)
{
- // exceptions (applied at state but not removed at state change)
- // Rampage
- if(spellProto->SpellIconID==2006 && spellProto->SpellFamilyName==SPELLFAMILY_WARRIOR && spellProto->SpellFamilyFlags[0]==0x100000)
- {
- ++itr;
- continue;
- }
-
RemoveAura(itr);
}
else
@@ -8547,15 +8727,42 @@ void Unit::ModifyAuraState(AuraState flag, bool apply)
}
}
+uint32 Unit::BuildAuraStateUpdateForTarget(Unit * target) const
+{
+ uint32 auraStates = GetUInt32Value(UNIT_FIELD_AURASTATE) &~(PER_CASTER_AURA_STATE_MASK);
+ for(AuraStateAurasMap::const_iterator itr = m_auraStateAuras.begin(); itr != m_auraStateAuras.end();++itr)
+ {
+ if ((1<<(itr->first-1)) & PER_CASTER_AURA_STATE_MASK)
+ {
+ if (itr->second->GetCasterGUID() == target->GetGUID())
+ auraStates |= (1<<(itr->first-1));
+ }
+ }
+ return auraStates;
+}
+
bool Unit::HasAuraState(AuraState flag, SpellEntry const *spellProto, Unit * Caster) const
{
- if (Caster && spellProto)
+ if (Caster)
{
- AuraEffectList const& stateAuras = Caster->GetAurasByType(SPELL_AURA_ABILITY_IGNORE_AURASTATE);
- for(AuraEffectList::const_iterator j = stateAuras.begin();j != stateAuras.end(); ++j)
- if((*j)->isAffectedOnSpell(spellProto))
- return true;
+ if(spellProto)
+ {
+ AuraEffectList const& stateAuras = Caster->GetAurasByType(SPELL_AURA_ABILITY_IGNORE_AURASTATE);
+ for(AuraEffectList::const_iterator j = stateAuras.begin();j != stateAuras.end(); ++j)
+ if((*j)->isAffectedOnSpell(spellProto))
+ return true;
+ }
+ // Check per caster aura state
+ // If aura with aurastate by caster not found return false
+ if ((1<<(flag-1)) & PER_CASTER_AURA_STATE_MASK)
+ {
+ for(AuraStateAurasMap::const_iterator itr = m_auraStateAuras.lower_bound(flag); itr != m_auraStateAuras.upper_bound(flag);++itr)
+ if (itr->second->GetCasterGUID() == Caster->GetGUID())
+ return true;
+ return false;
+ }
}
+
return HasFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1));
}
@@ -8741,13 +8948,13 @@ void Unit::SetMinion(Minion *minion, bool apply)
assert((*itr)->GetOwnerGUID() == GetGUID());
assert((*itr)->GetTypeId() == TYPEID_UNIT);
- if(!((Creature*)(*itr))->HasSummonMask(SUMMON_MASK_GUARDIAN))
+ if(!((Creature*)(*itr))->HasSummonMask(SUMMON_MASK_CONTROLABLE_GUARDIAN))
continue;
if(AddUInt64Value(UNIT_FIELD_SUMMON, (*itr)->GetGUID()))
{
//show another pet bar if there is no charm bar
- if(GetTypeId() == TYPEID_PLAYER && !GetCharmGUID() && ((Creature*)(*itr))->HasSummonMask(SUMMON_MASK_GUARDIAN))
+ if(GetTypeId() == TYPEID_PLAYER && !GetCharmGUID() && ((Creature*)(*itr))->HasSummonMask(SUMMON_MASK_CONTROLABLE_GUARDIAN))
{
if(((Creature*)(*itr))->isPet())
((Player*)this)->PetSpellInitialize();
@@ -8835,19 +9042,24 @@ int32 Unit::DealHeal(Unit *pVictim, uint32 addhealth, SpellEntry const *spellPro
{
int32 gain = pVictim->ModifyHealth(int32(addhealth));
- if (GetTypeId()==TYPEID_PLAYER)
+ Unit* unit = this;
+
+ if( GetTypeId()==TYPEID_UNIT && ((Creature*)this)->isTotem())
+ unit = GetOwner();
+
+ if (unit->GetTypeId()==TYPEID_PLAYER)
{
// overheal = addhealth - gain
- SendHealSpellLog(pVictim, spellProto->Id, addhealth, addhealth > gain ? addhealth - gain : 0, critical);
+ unit->SendHealSpellLog(pVictim, spellProto->Id, addhealth, addhealth - gain, critical);
- if (BattleGround *bg = ((Player*)this)->GetBattleGround())
- bg->UpdatePlayerScore((Player*)this, SCORE_HEALING_DONE, gain);
+ if (BattleGround *bg = ((Player*)unit)->GetBattleGround())
+ bg->UpdatePlayerScore((Player*)unit, SCORE_HEALING_DONE, gain);
// use the actual gain, as the overheal shall not be counted, skip gain 0 (it ignored anyway in to criteria)
if (gain)
- ((Player*)this)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE, gain, 0, pVictim);
+ ((Player*)unit)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE, gain, 0, pVictim);
- ((Player*)this)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CASTED, addhealth);
+ ((Player*)unit)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CASTED, addhealth);
}
if (pVictim->GetTypeId()==TYPEID_PLAYER)
@@ -8926,9 +9138,7 @@ void Unit::RemoveAllControlled()
&& target->GetTypeId() == TYPEID_UNIT
&& ((Creature*)target)->HasSummonMask(SUMMON_MASK_SUMMON))
{
-
- if(!((TempSummon*)target)->isPet())
- ((TempSummon*)target)->UnSummon();
+ ((TempSummon*)target)->UnSummon();
}
else
{
@@ -9073,7 +9283,7 @@ void Unit::EnergizeBySpell(Unit *pVictim, uint32 SpellID, uint32 Damage, Powers
{
SendEnergizeSpellLog(pVictim, SpellID, Damage, powertype);
// needs to be called after sending spell log
- ModifyPower(powertype, Damage);
+ pVictim->ModifyPower(powertype, Damage);
}
uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack)
@@ -9202,7 +9412,8 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3
}
else // Tundra Stalker
{
- if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DEATHKNIGHT,0, 0x4000000,0))
+ // Frost Fever (target debuff)
+ if (pVictim->GetAura(SPELL_AURA_MOD_HASTE, SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DEATHKNIGHT, 0, 0, 0x2))
DoneTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f;
break;
}
@@ -9265,13 +9476,12 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3
}
}
break;
-
// Glyph of Shadow Word: Pain
case SPELLFAMILY_PRIEST:
if (spellProto->SpellFamilyFlags[0] & 0x800000)
{
// Increase Mind Flay damage
- if (AuraEffect * aurEff = GetDummyAura(55687))
+ if (AuraEffect * aurEff = GetAuraEffect(55687, 0))
// if Shadow Word: Pain present
if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x8000, 0,0, GetGUID()))
DoneTotalMod *= (aurEff->GetAmount() + 100.0f) / 100.f;
@@ -9300,17 +9510,17 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3
// Improved Icy Touch
if (spellProto->SpellFamilyFlags[0] & 0x2)
{
- if (AuraEffect * aurEff = GetDummyAura(SPELLFAMILY_DEATHKNIGHT, 2721))
+ if (AuraEffect * aurEff = GetDummyAura(SPELLFAMILY_DEATHKNIGHT, 2721, 0))
DoneTotalMod *= (100.0f + aurEff->GetAmount()) / 100.0f ;
}
// Glacier Rot
if (spellProto->SpellFamilyFlags[0] & 0x2 || spellProto->SpellFamilyFlags[1] & 0x6)
{
- if (AuraEffect * aurEff = GetDummyAura(SPELLFAMILY_DEATHKNIGHT, 196))
+ if (AuraEffect * aurEff = GetDummyAura(SPELLFAMILY_DEATHKNIGHT, 196, 0))
DoneTotalMod *= (100.0f + aurEff->GetAmount()) / 100.0f;
}
// This is not a typo - Impurity has SPELLFAMILY_DRUID
- if (AuraEffect * aurEff = GetDummyAura(SPELLFAMILY_DRUID, 1986))
+ if (AuraEffect * aurEff = GetDummyAura(SPELLFAMILY_DRUID, 1986, 0))
ApCoeffMod *= (100.0f + aurEff->GetAmount()) / 100.0f;
break;
}
@@ -9325,7 +9535,7 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3
if (pVictim->GetTypeId() == TYPEID_PLAYER)
{
//Cheat Death
- if (AuraEffect *dummy = pVictim->GetDummyAura(45182))
+ if (AuraEffect *dummy = pVictim->GetAuraEffect(45182, 0))
{
float mod = -((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL)*2*4;
if (mod < dummy->GetAmount())
@@ -9341,14 +9551,11 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3
TakenTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f;
// Mod damage from spell mechanic
- uint32 mechanicMask = GetAllSpellMechanicMask(spellProto);
- if (mechanicMask)
+ if (uint32 mechanicMask = GetAllSpellMechanicMask(spellProto))
{
AuraEffectList const& mDamageDoneMechanic = pVictim->GetAurasByType(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT);
for(AuraEffectList::const_iterator i = mDamageDoneMechanic.begin();i != mDamageDoneMechanic.end(); ++i)
- if((mechanicMask & uint32(1<<((*i)->GetMiscValue())))
- // Shred - "Effects which increase Bleed damage also increase Shred damage"
- || ((*i)->GetMiscValue() == MECHANIC_BLEED && spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[0] & 0x8000))
+ if(mechanicMask & uint32(1<<((*i)->GetMiscValue())))
TakenTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f;
}
@@ -9361,21 +9568,29 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3
DoneAdvertisedBenefit += ((Guardian*)this)->GetBonusDamage();
// Check for table values
- float coeff;
+ float coeff = 0;
SpellBonusEntry const* bonus = spellmgr.GetSpellBonusData(spellProto->Id);
if (bonus)
{
if (damagetype == DOT)
+ {
coeff = bonus->dot_damage;
+ if (bonus->ap_dot_bonus > 0)
+ DoneTotal+=bonus->ap_dot_bonus * stack * ApCoeffMod * GetTotalAttackPowerValue(
+ (IsRangedWeaponSpell(spellProto) && spellProto->DmgClass !=SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK);
+ }
else
+ {
coeff = bonus->direct_damage;
- if (bonus->ap_bonus)
- DoneTotal+=bonus->ap_bonus * GetTotalAttackPowerValue(BASE_ATTACK) * stack * ApCoeffMod;
+ if (bonus->ap_bonus > 0)
+ DoneTotal+=bonus->ap_bonus * stack * ApCoeffMod * GetTotalAttackPowerValue(
+ (IsRangedWeaponSpell(spellProto) && spellProto->DmgClass !=SPELL_DAMAGE_CLASS_MELEE)? RANGED_ATTACK : BASE_ATTACK);
+ }
}
// Default calculation
if (DoneAdvertisedBenefit || TakenAdvertisedBenefit)
{
- if(!bonus)
+ if(!bonus || coeff < 0)
{
// Damage Done from spell damage bonus
int32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto);
@@ -9520,8 +9735,9 @@ bool Unit::isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolM
float crit_chance = 0.0f;
switch(spellProto->DmgClass)
{
- case SPELL_DAMAGE_CLASS_NONE:
- return false;
+ case SPELL_DAMAGE_CLASS_NONE: // Exception for earth shield
+ if (spellProto->Id != 379) // We need more spells to find a general way (if there is any)
+ return false;
case SPELL_DAMAGE_CLASS_MAGIC:
{
if (schoolMask & SPELL_SCHOOL_MASK_NORMAL)
@@ -9590,11 +9806,18 @@ bool Unit::isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolM
// Sacred Shield
if (spellProto->SpellFamilyFlags[0] & 0x40000000)
{
- AuraEffect const* aura = pVictim->GetDummyAura(58597);
+ AuraEffect const* aura = pVictim->GetAuraEffect(58597,1);
if (aura && aura->GetCasterGUID() == GetGUID())
crit_chance+=aura->GetAmount();
break;
}
+ // Exorcism
+ else if (spellProto->Category == 19)
+ {
+ if (pVictim->GetCreatureTypeMask() & CREATURE_TYPEMASK_DEMON_OR_UNDEAD)
+ return true;
+ break;
+ }
break;
case SPELLFAMILY_SHAMAN:
// Lava Burst
@@ -9616,12 +9839,30 @@ bool Unit::isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolM
break;
}
case SPELL_DAMAGE_CLASS_MELEE:
+ if (pVictim)
+ {
+ // Custom crit by class
+ switch(spellProto->SpellFamilyName)
+ {
+ case SPELLFAMILY_DRUID:
+ // Rend and Tear - bonus crit chance for bleeding targets of Ferocious Bite
+ if (spellProto->SpellFamilyFlags[0] & 0x00800000 && pVictim->HasAuraState(AURA_STATE_BLEEDING, spellProto, this))
+ {
+ if (AuraEffect const* rendAndTear = GetDummyAura(SPELLFAMILY_DRUID, 2859, 1))
+ {
+ crit_chance += rendAndTear->GetAmount();
+ }
+ break;
+ }
+ break;
+ }
+ }
case SPELL_DAMAGE_CLASS_RANGED:
{
if (pVictim)
{
- crit_chance = GetUnitCriticalChance(attackType, pVictim);
- crit_chance+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask);
+ crit_chance += GetUnitCriticalChance(attackType, pVictim);
+ crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask);
}
break;
}
@@ -9801,16 +10042,24 @@ uint32 Unit::SpellHealingBonus(Unit *pVictim, SpellEntry const *spellProto, uint
// Check for table values
SpellBonusEntry const* bonus = !scripted ? spellmgr.GetSpellBonusData(spellProto->Id) : NULL;
- float coeff;
+ float coeff = 0;
float factorMod = 1.0f;
if (bonus)
{
if (damagetype == DOT)
+ {
coeff = bonus->dot_damage;
+ if (bonus->ap_dot_bonus > 0)
+ DoneTotal+=bonus->ap_dot_bonus * stack * GetTotalAttackPowerValue(
+ (IsRangedWeaponSpell(spellProto) && spellProto->DmgClass !=SPELL_DAMAGE_CLASS_MELEE)? RANGED_ATTACK : BASE_ATTACK);
+ }
else
+ {
coeff = bonus->direct_damage;
- if (bonus->ap_bonus)
- DoneTotal+=bonus->ap_bonus * GetTotalAttackPowerValue(BASE_ATTACK) * stack;
+ if (bonus->ap_bonus > 0)
+ DoneTotal+=bonus->ap_bonus * stack * GetTotalAttackPowerValue(
+ (IsRangedWeaponSpell(spellProto) && spellProto->DmgClass !=SPELL_DAMAGE_CLASS_MELEE)? RANGED_ATTACK : BASE_ATTACK);
+ }
}
else // scripted bonus
{
@@ -9836,6 +10085,7 @@ uint32 Unit::SpellHealingBonus(Unit *pVictim, SpellEntry const *spellProto, uint
// No heal coeff for SPELL_DAMAGE_CLASS_NONE class spells by default
else if (scripted || spellProto->DmgClass == SPELL_DAMAGE_CLASS_NONE)
{
+ scripted = true;
coeff = 0.0f;
}
}
@@ -9843,7 +10093,7 @@ uint32 Unit::SpellHealingBonus(Unit *pVictim, SpellEntry const *spellProto, uint
// Default calculation
if (DoneAdvertisedBenefit || TakenAdvertisedBenefit)
{
- if(!bonus && !scripted)
+ if((!bonus && !scripted) || coeff < 0)
{
// Damage Done from spell damage bonus
int32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto);
@@ -10204,6 +10454,9 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT
}
}
}
+ // This is not a typo - Impurity has SPELLFAMILY_DRUID
+ if (AuraEffect const * aurEff = GetDummyAura(SPELLFAMILY_DRUID, 1986, 0))
+ APbonus *= (100.0f + aurEff->GetAmount()) / 100.0f;
DoneFlatBenefit += int32(APbonus/14.0f * GetAPMultiplier(attType,normalized));
}
@@ -10238,6 +10491,22 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT
if((*i)->GetMiscValue() & GetMeleeDamageSchoolMask())
TakenTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f;
+ // .. taken pct (special attacks)
+ if (spellProto)
+ {
+ // Mod damage from spell mechanic
+ uint32 mechanicMask = GetAllSpellMechanicMask(spellProto);
+ if (mechanicMask)
+ {
+ AuraEffectList const& mDamageDoneMechanic = pVictim->GetAurasByType(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT);
+ for(AuraEffectList::const_iterator i = mDamageDoneMechanic.begin();i != mDamageDoneMechanic.end(); ++i)
+ if((mechanicMask & uint32(1<<((*i)->GetMiscValue())))
+ // Shred - "Effects which increase Bleed damage also increase Shred damage"
+ || ((*i)->GetMiscValue() == MECHANIC_BLEED && spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[0] & 0x8000))
+ TakenTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f;
+ }
+ }
+
// .. taken pct: dummy auras
AuraEffectList const& mDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
for(AuraEffectList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
@@ -10256,14 +10525,6 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT
TakenTotalMod *= (mod+100.0f)/100.0f;
}
break;
- //Mangle
- case 2312:
- if(spellProto==NULL)
- break;
- // Should increase Shred (initial Damage of Lacerate and Rake handled in Spell::EffectSchoolDMG)
- if(spellProto->SpellFamilyName==SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags.IsEqual (0x00008000,0,0))
- TakenTotalMod *= (100.0f+(*i)->GetAmount())/100.0f;
- break;
}
}
@@ -10394,8 +10655,7 @@ float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM, const SpellEntry * s
if(Player* modOwner = GetSpellModOwner())
modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_PROC_PER_MINUTE,PPM);
- uint32 result = uint32((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
- return result;
+ return uint32((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
}
void Unit::Mount(uint32 mount)
@@ -10471,20 +10731,22 @@ void Unit::SetInCombatWith(Unit* enemy)
SetInCombatState(false,enemy);
}
-void Unit::CombatStart(Unit* target)
+void Unit::CombatStart(Unit* target, bool initialAggro)
{
- if(!target->IsStandState()/* && !target->hasUnitState(UNIT_STAT_STUNNED)*/)
- target->SetStandState(UNIT_STAND_STATE_STAND);
-
- if(!target->isInCombat() && target->GetTypeId() != TYPEID_PLAYER
- && !((Creature*)target)->HasReactState(REACT_PASSIVE) && ((Creature*)target)->IsAIEnabled)
+ if (initialAggro)
{
- ((Creature*)target)->AI()->AttackStart(this);
- }
+ if(!target->IsStandState()/* && !target->hasUnitState(UNIT_STAT_STUNNED)*/)
+ target->SetStandState(UNIT_STAND_STATE_STAND);
- SetInCombatWith(target);
- target->SetInCombatWith(this);
+ if(!target->isInCombat() && target->GetTypeId() != TYPEID_PLAYER
+ && !((Creature*)target)->HasReactState(REACT_PASSIVE) && ((Creature*)target)->IsAIEnabled)
+ {
+ ((Creature*)target)->AI()->AttackStart(this);
+ }
+ SetInCombatWith(target);
+ target->SetInCombatWith(this);
+ }
Unit *who = target->GetCharmerOrOwnerOrSelf();
if(who->GetTypeId() == TYPEID_PLAYER)
SetContestedPvP((Player*)who);
@@ -10515,8 +10777,10 @@ void Unit::SetInCombatState(bool PvP, Unit* enemy)
if(GetTypeId() != TYPEID_PLAYER)
{
- //if(GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_IDLE) != IDLE_MOTION_TYPE)
- ((Creature*)this)->SetHomePosition(GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
+ // Set home position at place of engaging combat for escorted creatures
+ if(((Creature*)this)->IsAIEnabled)
+ if (((Creature *)this)->AI()->IsEscorted())
+ ((Creature*)this)->SetHomePosition(GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
if(enemy)
{
if(((Creature*)this)->IsAIEnabled)
@@ -10581,6 +10845,9 @@ bool Unit::canAttack(Unit const* target, bool force) const
else if(!IsHostileTo(target))
return false;
+ //if(m_Vehicle && m_Vehicle == target->m_Vehicle)
+ // return true;
+
if(!target->isAttackableByAOE() || target->hasUnitState(UNIT_STAT_DIED))
return false;
@@ -10782,6 +11049,7 @@ bool Unit::canDetectStealthOf(Unit const* target, float distance) const
//-Stealth Mod(positive like Master of Deception) and Stealth Detection(negative like paranoia)
//based on wowwiki every 5 mod we have 1 more level diff in calculation
visibleDistance += (float)(GetTotalAuraModifier(SPELL_AURA_MOD_DETECT) - target->GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL)) / 5.0f;
+ visibleDistance = visibleDistance > MAX_PLAYER_STEALTH_DETECT_RANGE ? MAX_PLAYER_STEALTH_DETECT_RANGE : visibleDistance;
return distance < visibleDistance;
}
@@ -10823,6 +11091,11 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced)
switch(mtype)
{
+ // Only apply debuffs
+ case MOVE_FLIGHT_BACK:
+ case MOVE_RUN_BACK:
+ case MOVE_SWIM_BACK:
+ break;
case MOVE_WALK:
return;
case MOVE_RUN:
@@ -10841,15 +11114,11 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced)
}
break;
}
- case MOVE_RUN_BACK:
- return;
case MOVE_SWIM:
{
main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SWIM_SPEED);
break;
}
- case MOVE_SWIM_BACK:
- return;
case MOVE_FLIGHT:
{
if (GetTypeId()==TYPEID_UNIT && IsControlledByPlayer()) // not sure if good for pet
@@ -10881,14 +11150,13 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced)
vehicle->UpdateSpeed(MOVE_FLIGHT, true);
break;
}
- case MOVE_FLIGHT_BACK:
- return;
default:
sLog.outError("Unit::UpdateSpeed: Unsupported move type (%d)", mtype);
return;
}
float bonus = non_stack_bonus > stack_bonus ? non_stack_bonus : stack_bonus;
+
// now we ready for speed calculation
float speed = main_speed_mod ? bonus*(100.0f + main_speed_mod)/100.0f : bonus;
@@ -10898,6 +11166,10 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced)
case MOVE_SWIM:
case MOVE_FLIGHT:
{
+ // Set creature speed rate from CreatureInfo
+ if (GetTypeId() == TYPEID_UNIT)
+ speed *= ((Creature*)this)->GetCreatureInfo()->speed;
+
// Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need
// TODO: possible affect only on MOVE_RUN
if(int32 normalization = GetMaxPositiveAuraModifier(SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED))
@@ -11089,6 +11361,8 @@ void Unit::setDeathState(DeathState s)
if (m_deathState != ALIVE && s == ALIVE)
{
//_ApplyAllAuraMods();
+ // Reset display id on resurection - needed by corpse explosion to cleanup after display change
+ SetDisplayId(GetNativeDisplayId());
}
m_deathState = s;
}
@@ -11116,8 +11390,8 @@ bool Unit::CanHaveThreatList() const
//if( ((Creature*)this)->isVehicle() )
// return false;
- // pets can not have a threat list, unless they are controlled by a creature
- if( ((Creature*)this)->isPet() && IS_PLAYER_GUID(((Pet*)this)->GetOwnerGUID()) )
+ // summons can not have a threat list, unless they are controlled by a creature
+ if( ((Creature*)this)->HasSummonMask(SUMMON_MASK_MINION | SUMMON_MASK_GUARDIAN | SUMMON_MASK_CONTROLABLE_GUARDIAN) && IS_PLAYER_GUID(((Pet*)this)->GetOwnerGUID()) )
return false;
return true;
@@ -11148,6 +11422,8 @@ void Unit::AddThreat(Unit* pVictim, float threat, SpellSchoolMask schoolMask, Sp
void Unit::DeleteThreatList()
{
+ if(CanHaveThreatList() && !m_ThreatManager.isThreatListEmpty())
+ SendClearThreatListOpcode();
m_ThreatManager.clearReferences();
}
@@ -11222,10 +11498,6 @@ Unit* Creature::SelectVictim()
//next-victim-selection algorithm and evade mode are called
//threat list sorting etc.
- //This should not be called by unit who does not have a threatlist
- //or who does not have threat (totem/pet/critter)
- //otherwise enterevademode every update
-
Unit* target = NULL;
// First checking if we have some taunt on us
const AuraEffectList& tauntAuras = GetAurasByType(SPELL_AURA_MOD_TAUNT);
@@ -11258,9 +11530,38 @@ Unit* Creature::SelectVictim()
target = getVictim();
}
- if ( !target && !m_ThreatManager.isThreatListEmpty() )
- // No taunt aura or taunt aura caster is dead standart target selection
- target = m_ThreatManager.getHostilTarget();
+ if (CanHaveThreatList())
+ {
+ if ( !target && !m_ThreatManager.isThreatListEmpty() )
+ // No taunt aura or taunt aura caster is dead standart target selection
+ target = m_ThreatManager.getHostilTarget();
+ }
+ else if(!HasReactState(REACT_PASSIVE))
+ {
+ // We have player pet probably
+ target = getAttackerForHelper();
+ if (!target && isSummon())
+ {
+ if (Unit * owner = ((TempSummon*)this)->GetOwner())
+ {
+ if (owner->isInCombat())
+ target = owner->getAttackerForHelper();
+ if (!target)
+ {
+ for(ControlList::const_iterator itr = owner->m_Controlled.begin(); itr != owner->m_Controlled.end(); ++itr)
+ {
+ if ((*itr)->isInCombat())
+ {
+ target = (*itr)->getAttackerForHelper();
+ if (target) break;
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ return NULL;
if(target)
{
@@ -11273,16 +11574,11 @@ Unit* Creature::SelectVictim()
// it in combat but attacker not make any damage and not enter to aggro radius to have record in threat list
// for example at owner command to pet attack some far away creature
// Note: creature not have targeted movement generator but have attacker in this case
- if(m_attackers.size())
- return NULL;
- /*if( GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE )
+ for(AttackerSet::const_iterator itr = m_attackers.begin(); itr != m_attackers.end(); ++itr)
{
- for(AttackerSet::const_iterator itr = m_attackers.begin(); itr != m_attackers.end(); ++itr)
- {
- if( (*itr)->IsInMap(this) && canAttack(*itr) && (*itr)->isInAccessiblePlaceFor((Creature*)this) )
- return NULL;
- }
- }*/
+ if( (*itr)->IsInMap(this) && canAttack(*itr) && (*itr)->isInAccessiblePlaceFor((Creature*)this) && ((*itr)->GetTypeId() != TYPEID_PLAYER && (!((Creature*)(*itr))->HasSummonMask(SUMMON_MASK_CONTROLABLE_GUARDIAN))))
+ return NULL;
+ }
// search nearby enemy before enter evade mode
if(HasReactState(REACT_AGGRESSIVE))
@@ -11368,8 +11664,8 @@ int32 Unit::CalculateSpellDamage(SpellEntry const* spellProto, uint8 effect_inde
spellProto->EffectApplyAuraName[effect_index] != SPELL_AURA_MOD_INCREASE_SPEED &&
spellProto->EffectApplyAuraName[effect_index] != SPELL_AURA_MOD_DECREASE_SPEED)
//there are many more: slow speed, -healing pct
- //value = int32(value*0.25f*exp(getLevel()*(70-spellProto->spellLevel)/1000.0f));
- value = int32(value * (int32)getLevel() / (int32)(spellProto->spellLevel ? spellProto->spellLevel : 1));
+ value = int32(value*0.25f*exp(getLevel()*(70-spellProto->spellLevel)/1000.0f));
+ //value = int32(value * (int32)getLevel() / (int32)(spellProto->spellLevel ? spellProto->spellLevel : 1));
return value;
}
@@ -11509,29 +11805,29 @@ void Unit::IncrDiminishing(DiminishingGroup group)
m_Diminishing.push_back(DiminishingReturn(group,getMSTime(),DIMINISHING_LEVEL_2));
}
-void Unit::ApplyDiminishingToDuration(DiminishingGroup group, int32 &duration,Unit* caster,DiminishingLevels Level)
+void Unit::ApplyDiminishingToDuration(DiminishingGroup group, int32 &duration,Unit* caster,DiminishingLevels Level, int32 limitduration)
{
if(duration == -1 || group == DIMINISHING_NONE || caster->IsFriendlyTo(this) )
return;
- // test pet/charm masters instead pets/charmeds
+ // test pet/charm masters instead pets/charmeds
Unit const* targetOwner = GetCharmerOrOwner();
Unit const* casterOwner = caster->GetCharmerOrOwner();
// Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0)
- if(duration > 10000 && IsDiminishingReturnsGroupDurationLimited(group))
+ if(limitduration > 0 && duration > limitduration)
{
Unit const* target = targetOwner ? targetOwner : this;
Unit const* source = casterOwner ? casterOwner : caster;
if(target->GetTypeId() == TYPEID_PLAYER && source->GetTypeId() == TYPEID_PLAYER)
- duration = 10000;
+ duration = limitduration;
}
float mod = 1.0f;
// Some diminishings applies to mobs too (for example, Stun)
- if((GetDiminishingReturnsGroupType(group) == DRTYPE_PLAYER && (targetOwner ? targetOwner->GetTypeId():GetTypeId()) == TYPEID_PLAYER) || GetDiminishingReturnsGroupType(group) == DRTYPE_ALL)
+ if((GetDiminishingReturnsGroupType(group) == DRTYPE_PLAYER && (targetOwner ? (targetOwner->GetTypeId() == TYPEID_PLAYER) : (GetTypeId() == TYPEID_PLAYER))) || GetDiminishingReturnsGroupType(group) == DRTYPE_ALL)
{
DiminishingLevels diminish = Level;
switch(diminish)
@@ -11884,6 +12180,8 @@ void Unit::SetHealth(uint32 val)
void Unit::SetMaxHealth(uint32 val)
{
+ if(!val) val = 1;
+
uint32 health = GetHealth();
SetUInt32Value(UNIT_FIELD_MAXHEALTH, val);
@@ -12066,7 +12364,7 @@ void Unit::RemoveFromWorld()
if(m_NotifyListPos >= 0)
{
- GetMap()->RemoveUnitFromNotify(m_NotifyListPos);
+ GetMap()->RemoveUnitFromNotify(this, m_NotifyListPos);
m_NotifyListPos = -1;
}
@@ -12148,11 +12446,9 @@ void Unit::DeleteCharmInfo()
CharmInfo::CharmInfo(Unit* unit)
: m_unit(unit), m_CommandState(COMMAND_FOLLOW), m_petnumber(0), m_barInit(false)
{
- for(uint8 i =0; i<MAX_SPELL_CHARM; ++i)
- {
- m_charmspells[i].spellId = 0;
- m_charmspells[i].active = ACT_DISABLED;
- }
+ for(uint8 i = 0; i < MAX_SPELL_CHARM; ++i)
+ m_charmspells[i].SetActionAndType(0,ACT_DISABLED);
+
if(m_unit->GetTypeId() == TYPEID_UNIT)
{
m_oldReactState = ((Creature*)m_unit)->GetReactState();
@@ -12229,18 +12525,21 @@ void CharmInfo::InitCharmCreateSpells()
if(spellInfo && spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_DEAD)
spellId = 0;
- m_charmspells[x].spellId = spellId;
-
if(!spellId)
+ {
+ m_charmspells[x].SetActionAndType(spellId,ACT_DISABLED);
continue;
+ }
if (IsPassiveSpell(spellId))
{
m_unit->CastSpell(m_unit, spellId, true);
- m_charmspells[x].active = ACT_PASSIVE;
+ m_charmspells[x].SetActionAndType(spellId,ACT_PASSIVE);
}
else
{
+ m_charmspells[x].SetActionAndType(spellId,ACT_DISABLED);
+
ActiveStates newstate;
if(spellInfo)
{
@@ -12275,11 +12574,11 @@ bool CharmInfo::AddSpellToActionBar(uint32 spell_id, ActiveStates newstate)
// new spell rank can be already listed
for(uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
{
- if (PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell())
+ if (uint32 action = PetActionBar[i].GetAction())
{
- if (spellmgr.GetFirstSpellInChain(PetActionBar[i].SpellOrAction) == first_id)
+ if (PetActionBar[i].IsActionBarForSpell() && spellmgr.GetFirstSpellInChain(action) == first_id)
{
- PetActionBar[i].SpellOrAction = spell_id;
+ PetActionBar[i].SetAction(spell_id);
return true;
}
}
@@ -12288,7 +12587,7 @@ bool CharmInfo::AddSpellToActionBar(uint32 spell_id, ActiveStates newstate)
// or use empty slot in other case
for(uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
{
- if (!PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell())
+ if (!PetActionBar[i].GetAction() && PetActionBar[i].IsActionBarForSpell())
{
SetActionBar(i,spell_id,newstate == ACT_DECIDE ? IsAutocastableSpell(spell_id) ? ACT_DISABLED : ACT_PASSIVE : newstate);
return true;
@@ -12303,9 +12602,9 @@ bool CharmInfo::RemoveSpellFromActionBar(uint32 spell_id)
for(uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
{
- if (PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell())
+ if (uint32 action = PetActionBar[i].GetAction())
{
- if (spellmgr.GetFirstSpellInChain(PetActionBar[i].SpellOrAction) == first_id)
+ if (PetActionBar[i].IsActionBarForSpell() && spellmgr.GetFirstSpellInChain(action) == first_id)
{
SetActionBar(i,0,ACT_PASSIVE);
return true;
@@ -12322,12 +12621,8 @@ void CharmInfo::ToggleCreatureAutocast(uint32 spellid, bool apply)
return;
for(uint32 x = 0; x < MAX_SPELL_CHARM; ++x)
- {
- if(spellid == m_charmspells[x].spellId)
- {
- m_charmspells[x].active = apply ? ACT_ENABLED : ACT_DISABLED;
- }
- }
+ if(spellid == m_charmspells[x].GetAction())
+ m_charmspells[x].SetType(apply ? ACT_ENABLED : ACT_DISABLED);
}
void CharmInfo::SetPetNumber(uint32 petnumber, bool statwindow)
@@ -12353,17 +12648,19 @@ void CharmInfo::LoadPetActionBar(const std::string& data )
for(iter = tokens.begin(), index = ACTION_BAR_INDEX_PET_SPELL_START; index < ACTION_BAR_INDEX_PET_SPELL_END; ++iter, ++index )
{
// use unsigned cast to avoid sign negative format use at long-> ActiveStates (int) conversion
- PetActionBar[index].Type = atol((*iter).c_str());
+ uint8 type = atol((*iter).c_str());
++iter;
- PetActionBar[index].SpellOrAction = atol((*iter).c_str());
+ uint32 action = atol((*iter).c_str());
+
+ PetActionBar[index].SetActionAndType(action,ActiveStates(type));
// check correctness
if(PetActionBar[index].IsActionBarForSpell())
{
- if(!sSpellStore.LookupEntry(PetActionBar[index].SpellOrAction))
+ if(!sSpellStore.LookupEntry(PetActionBar[index].GetAction()))
SetActionBar(index,0,ACT_PASSIVE);
- else if(!IsAutocastableSpell(PetActionBar[index].SpellOrAction))
- SetActionBar(index,PetActionBar[index].SpellOrAction,ACT_PASSIVE);
+ else if(!IsAutocastableSpell(PetActionBar[index].GetAction()))
+ SetActionBar(index,PetActionBar[index].GetAction(),ACT_PASSIVE);
}
}
}
@@ -12371,19 +12668,16 @@ void CharmInfo::LoadPetActionBar(const std::string& data )
void CharmInfo::BuildActionBar( WorldPacket* data )
{
for(uint32 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
- {
- *data << uint16(PetActionBar[i].SpellOrAction);
- *data << uint16(PetActionBar[i].Type);
- }
+ *data << uint32(PetActionBar[i].packedData);
}
void CharmInfo::SetSpellAutocast( uint32 spell_id, bool state )
{
for(uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
{
- if(spell_id == PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell())
+ if(spell_id == PetActionBar[i].GetAction() && PetActionBar[i].IsActionBarForSpell())
{
- PetActionBar[i].Type = state ? ACT_ENABLED : ACT_DISABLED;
+ PetActionBar[i].SetType(state ? ACT_ENABLED : ACT_DISABLED);
break;
}
}
@@ -12427,8 +12721,10 @@ bool InitTriggerAuraData()
isTriggerAura[SPELL_AURA_MOD_DAMAGE_DONE] = true;
isTriggerAura[SPELL_AURA_MOD_DAMAGE_TAKEN] = true;
isTriggerAura[SPELL_AURA_MOD_RESISTANCE] = true;
- isTriggerAura[SPELL_AURA_MOD_STEALTH] = true; // Aura not have charges but need remove him on trigger
+ isTriggerAura[SPELL_AURA_MOD_STEALTH] = true;
+ isTriggerAura[SPELL_AURA_MOD_FEAR] = true; // Aura not have charges but need remove him on trigger
isTriggerAura[SPELL_AURA_MOD_ROOT] = true;
+ isTriggerAura[SPELL_AURA_TRANSFORM] = true;
isTriggerAura[SPELL_AURA_REFLECT_SPELLS] = true;
isTriggerAura[SPELL_AURA_DAMAGE_IMMUNITY] = true;
isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL] = true;
@@ -12499,8 +12795,11 @@ uint32 createProcExtendMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missC
void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage , SpellEntry const * procAura)
{
- // For melee/ranged based attack need update skills and set some Aura states
- if (procFlag & MELEE_BASED_TRIGGER_MASK)
+ // Player is loaded now - do not allow passive spell casts to proc
+ if (GetTypeId() == TYPEID_PLAYER && ((Player*)this)->GetSession()->PlayerLoading())
+ return;
+ // For melee/ranged based attack need update skills and set some Aura states if victim present
+ if (procFlag & MELEE_BASED_TRIGGER_MASK && pTarget)
{
// Update skills here for players
if (GetTypeId() == TYPEID_PLAYER)
@@ -12616,6 +12915,9 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag
if (GetTypeId() == TYPEID_PLAYER && i->spellProcEvent && i->spellProcEvent->cooldown)
cooldown = i->spellProcEvent->cooldown;
+ if (spellInfo->AttributesEx3 & SPELL_ATTR_EX3_DISABLE_PROC)
+ SetCantProc(true);
+
// This bool is needed till separate aura effect procs are still here
bool handled = false;
if (HandleAuraProc(pTarget, damage, i->aura, procSpell, procFlag, procExtra, cooldown, &handled))
@@ -12640,8 +12942,8 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag
{
sLog.outDebug("ProcDamageAndSpell: casting spell %u (triggered by %s aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
// Don`t drop charge or add cooldown for not started trigger
- if (!HandleProcTriggerSpell(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
- continue;
+ if (HandleProcTriggerSpell(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
+ takeCharges=true;
break;
}
case SPELL_AURA_PROC_TRIGGER_DAMAGE:
@@ -12653,53 +12955,64 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag
DealDamageMods(damageInfo.target,damageInfo.damage,&damageInfo.absorb);
SendSpellNonMeleeDamageLog(&damageInfo);
DealSpellDamage(&damageInfo, true);
+ takeCharges=true;
break;
}
case SPELL_AURA_MANA_SHIELD:
case SPELL_AURA_DUMMY:
{
sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s dummy aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
- if (!HandleDummyAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
- continue;
- if (procDebug & 1)
- sLog.outError("Dummy aura of spell %d procs twice from one effect!",spellInfo->Id);
- procDebug |= 1;
+ if (HandleDummyAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
+ {
+ takeCharges=true;
+ if (procDebug & 1)
+ sLog.outError("Dummy aura of spell %d procs twice from one effect!",spellInfo->Id);
+ procDebug |= 1;
+ }
break;
}
case SPELL_AURA_OBS_MOD_ENERGY:
sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
- if (!HandleObsModEnergyAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
- continue;
- if (procDebug & 2)
- sLog.outError("ObsModEnergy aura of spell %d procs twice from one effect!",spellInfo->Id);
- procDebug |= 2;
+ if (HandleObsModEnergyAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
+ {
+ takeCharges=true;
+ if (procDebug & 2)
+ sLog.outError("ObsModEnergy aura of spell %d procs twice from one effect!",spellInfo->Id);
+ procDebug |= 2;
+ }
break;
case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN:
sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
- if (!HandleModDamagePctTakenAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
- continue;
- if (procDebug & 16)
- sLog.outError("ModDamagePctTaken aura of spell %d procs twice from one effect!",spellInfo->Id);
- procDebug |= 16;
+ if (HandleModDamagePctTakenAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
+ {
+ takeCharges=true;
+ if (procDebug & 16)
+ sLog.outError("ModDamagePctTaken aura of spell %d procs twice from one effect!",spellInfo->Id);
+ procDebug |= 16;
+ }
break;
case SPELL_AURA_MOD_HASTE:
{
sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s haste aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
- if (!HandleHasteAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
- continue;
- if (procDebug & 4)
- sLog.outError("Haste aura of spell %d procs twice from one effect!",spellInfo->Id);
- procDebug |= 4;
+ if (HandleHasteAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
+ {
+ takeCharges=true;
+ if (procDebug & 4)
+ sLog.outError("Haste aura of spell %d procs twice from one effect!",spellInfo->Id);
+ procDebug |= 4;
+ }
break;
}
case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS:
{
sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
- if (!HandleOverrideClassScriptAuraProc(pTarget, damage, triggeredByAura, procSpell, cooldown))
- continue;
- if (procDebug & 8)
- sLog.outError("OverrideClassScripts aura of spell %d procs twice from one effect!",spellInfo->Id);
- procDebug |= 8;
+ if (HandleOverrideClassScriptAuraProc(pTarget, damage, triggeredByAura, procSpell, cooldown))
+ {
+ takeCharges=true;
+ if (procDebug & 8)
+ sLog.outError("OverrideClassScripts aura of spell %d procs twice from one effect!",spellInfo->Id);
+ procDebug |= 8;
+ }
break;
}
case SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE:
@@ -12708,6 +13021,7 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag
(isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
HandleAuraRaidProcFromChargeWithValue(triggeredByAura);
+ takeCharges=true;
break;
}
case SPELL_AURA_RAID_PROC_FROM_CHARGE:
@@ -12716,68 +13030,92 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag
(isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
HandleAuraRaidProcFromCharge(triggeredByAura);
+ takeCharges=true;
break;
}
case SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE:
{
sLog.outDebug("ProcDamageAndSpell: casting spell %u (triggered with value by %s aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
- if (!HandleProcTriggerSpell(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
- continue;
+ if (HandleProcTriggerSpell(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
+ takeCharges=true;
break;
}
case SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK:
// Skip melee hits or instant cast spells
- if (procSpell == NULL || GetSpellCastTime(procSpell) == 0)
- continue;
+ if (procSpell && GetSpellCastTime(procSpell) != 0)
+ takeCharges=true;
break;
case SPELL_AURA_REFLECT_SPELLS_SCHOOL:
// Skip Melee hits and spells ws wrong school
- if (procSpell == NULL || (triggeredByAura->GetMiscValue() & procSpell->SchoolMask) == 0)
- continue;
+ if (procSpell && (triggeredByAura->GetMiscValue() & procSpell->SchoolMask)) // School check
+ takeCharges=true;
break;
case SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT:
case SPELL_AURA_MOD_POWER_COST_SCHOOL:
// Skip melee hits and spells ws wrong school or zero cost
- if (procSpell == NULL ||
- (procSpell->manaCost == 0 && procSpell->ManaCostPercentage == 0) || // Cost check
+ if (procSpell &&
+ (procSpell->manaCost != 0 || procSpell->ManaCostPercentage != 0) && // Cost check
(triggeredByAura->GetMiscValue() & procSpell->SchoolMask) == 0) // School check
- continue;
+ takeCharges=true;
break;
case SPELL_AURA_MECHANIC_IMMUNITY:
// Compare mechanic
- if (procSpell==NULL || procSpell->Mechanic != triggeredByAura->GetMiscValue())
- continue;
+ if (procSpell && procSpell->Mechanic == triggeredByAura->GetMiscValue())
+ takeCharges=true;
break;
case SPELL_AURA_MOD_MECHANIC_RESISTANCE:
// Compare mechanic
- if (procSpell==NULL || procSpell->Mechanic != triggeredByAura->GetMiscValue())
- continue;
+ if (procSpell && procSpell->Mechanic == triggeredByAura->GetMiscValue())
+ takeCharges=true;
break;
case SPELL_AURA_MOD_DAMAGE_FROM_CASTER:
// Compare casters
- if (triggeredByAura->GetCasterGUID() != pTarget->GetGUID())
- continue;
+ if (triggeredByAura->GetCasterGUID() == pTarget->GetGUID())
+ takeCharges=true;
break;
case SPELL_AURA_MOD_SPELL_CRIT_CHANCE:
- if (!procSpell)
- continue;
+ if (procSpell)
+ takeCharges=true;
break;
- /*case SPELL_AURA_ADD_FLAT_MODIFIER:
- case SPELL_AURA_ADD_PCT_MODIFIER:
+ // CC Auras which use their amount amount to drop
+ // Are there any more auras which need this?
+ case SPELL_AURA_MOD_CONFUSE:
+ case SPELL_AURA_MOD_FEAR:
+ case SPELL_AURA_MOD_STUN:
+ case SPELL_AURA_MOD_ROOT:
+ case SPELL_AURA_TRANSFORM:
+ if (isVictim && damage)
+ {
+ // Damage is dealt after proc system - lets ignore auras which wasn't updated yet
+ // to make spell not remove its own aura
+ if (i->aura->GetAuraDuration() == i->aura->GetAuraMaxDuration())
+ break;
+ int32 damageLeft = triggeredByAura->GetAmount();
+ // No damage left
+ if (damageLeft < damage )
+ RemoveAura(i->aura);
+ else
+ triggeredByAura->SetAmount(damageLeft-damage);
+ }
+ break;
+ //case SPELL_AURA_ADD_FLAT_MODIFIER:
+ //case SPELL_AURA_ADD_PCT_MODIFIER:
// HandleSpellModAuraProc
- break;*/
+ //break;
default:
// nothing do, just charges counter
+ takeCharges=true;
break;
}
- takeCharges=true;
}
// Remove charge (aura can be removed by triggers)
if(useCharges && takeCharges)
{
i->aura->DropAuraCharge();
}
+ if (spellInfo->AttributesEx3 & SPELL_ATTR_EX3_DISABLE_PROC)
+ SetCantProc(false);
}
// Cleanup proc requirements
@@ -12845,33 +13183,6 @@ void Unit::SendPetTalk (uint32 pettalk)
((Player*)owner)->GetSession()->SendPacket(&data);
}
-void Unit::SendPetSpellCooldown (uint32 spellid, time_t cooltime)
-{
- Unit* owner = GetOwner();
- if(!owner || owner->GetTypeId() != TYPEID_PLAYER)
- return;
-
- WorldPacket data(SMSG_SPELL_COOLDOWN, 8+1+4+4);
- data << uint64(GetGUID());
- data << uint8(0x0); // flags (0x1, 0x2)
- data << uint32(spellid);
- data << uint32(cooltime);
-
- ((Player*)owner)->GetSession()->SendPacket(&data);
-}
-
-void Unit::SendPetClearCooldown (uint32 spellid)
-{
- Unit* owner = GetOwner();
- if(!owner || owner->GetTypeId() != TYPEID_PLAYER)
- return;
-
- WorldPacket data(SMSG_CLEAR_COOLDOWN, 4+8);
- data << uint32(spellid);
- data << uint64(GetGUID());
- ((Player*)owner)->GetSession()->SendPacket(&data);
-}
-
void Unit::SendPetAIReaction(uint64 guid)
{
Unit* owner = GetOwner();
@@ -13312,21 +13623,13 @@ float Unit::GetAPMultiplier(WeaponAttackType attType, bool normalized)
}
}
-AuraEffect* Unit::GetDummyAura( uint32 spell_id ) const
-{
- Unit::AuraEffectList const& mDummy = GetAurasByType(SPELL_AURA_DUMMY);
- for(Unit::AuraEffectList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr)
- if ((*itr)->GetId() == spell_id)
- return *itr;
-
- return NULL;
-}
-
-AuraEffect* Unit::GetDummyAura(SpellFamilyNames name, uint32 iconId) const
+AuraEffect* Unit::GetAuraEffect(AuraType type, SpellFamilyNames name, uint32 iconId, uint8 effIndex) const
{
- Unit::AuraEffectList const& mDummy = GetAurasByType(SPELL_AURA_DUMMY);
+ Unit::AuraEffectList const& mDummy = GetAurasByType(type);
for(Unit::AuraEffectList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr)
{
+ if (effIndex != (*itr)->GetEffIndex())
+ continue;
SpellEntry const * spell = (*itr)->GetSpellProto();
if (spell->SpellIconID == iconId && spell->SpellFamilyName == name
&& !spell->SpellFamilyFlags)
@@ -13368,12 +13671,6 @@ void Unit::AddPetAura(PetAura const* petSpell)
if(GetTypeId() != TYPEID_PLAYER)
return;
- // Aura already added - not need to add it twice
- // This check is to prevent existing pet having aura applied twice (passive auras can stack)
- // if aura has more than 1 dummy effect
- if (m_petAuras.find(petSpell)!= m_petAuras.end())
- return;
-
m_petAuras.insert(petSpell);
if(Pet* pet = ((Player*)this)->GetPet())
pet->CastPetAura(petSpell);
@@ -13445,15 +13742,15 @@ bool Unit::IsTriggeredAtSpellProcEvent(Unit *pVictim, Aura * aura, SpellEntry co
if (!EventProcFlag)
return false;
- // Additional checks for triggered spells
- if (procExtra & PROC_EX_INTERNAL_TRIGGERED)
+ // Additional checks for triggered spells (ignore trap casts)
+ if (procExtra & PROC_EX_INTERNAL_TRIGGERED && !(procFlag & PROC_FLAG_ON_TRAP_ACTIVATION))
{
if (!(spellProto->AttributesEx3 & SPELL_ATTR_EX3_CAN_PROC_TRIGGERED))
return false;
}
// Check spellProcEvent data requirements
- if(!spellmgr.IsSpellProcEventCanTriggeredBy(spellProcEvent, EventProcFlag, procSpell, procFlag, procExtra))
+ if(!spellmgr.IsSpellProcEventCanTriggeredBy(spellProcEvent, EventProcFlag, procSpell, procFlag, procExtra, active))
return false;
// In most cases req get honor or XP from kill
if (EventProcFlag & PROC_FLAG_KILL && GetTypeId() == TYPEID_PLAYER)
@@ -13465,7 +13762,7 @@ bool Unit::IsTriggeredAtSpellProcEvent(Unit *pVictim, Aura * aura, SpellEntry co
if (!allow)
return false;
}
- // Aura added by spell can`t trogger from self (prevent drop charges/do triggers)
+ // Aura added by spell can`t trigger from self (prevent drop charges/do triggers)
// But except periodic and kill triggers (can triggered from self)
if(procSpell && procSpell->Id == spellProto->Id
&& !(spellProto->procFlags&(PROC_FLAG_ON_TAKE_PERIODIC | PROC_FLAG_KILL)))
@@ -13504,10 +13801,18 @@ bool Unit::IsTriggeredAtSpellProcEvent(Unit *pVictim, Aura * aura, SpellEntry co
if(spellProcEvent && spellProcEvent->customChance)
chance = spellProcEvent->customChance;
// If PPM exist calculate chance from PPM
- if(!isVictim && spellProcEvent && spellProcEvent->ppmRate != 0)
+ if(spellProcEvent && spellProcEvent->ppmRate != 0)
{
- uint32 WeaponSpeed = GetAttackTime(attType);
- chance = GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate, spellProto);
+ if(!isVictim)
+ {
+ uint32 WeaponSpeed = GetAttackTime(attType);
+ chance = GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate, spellProto);
+ }
+ else
+ {
+ uint32 WeaponSpeed = pVictim->GetAttackTime(attType);
+ chance = pVictim->GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate, spellProto);
+ }
}
// Apply chance modifer aura
if(Player* modOwner = GetSpellModOwner())
@@ -13583,7 +13888,7 @@ bool Unit::HandleAuraRaidProcFromCharge( AuraEffect* triggeredByAura )
damageSpellId=43594;
break;
default:
- sLog.outDebug("Unit::HandleAuraRaidProcFromCharge, received not handled spell: %u", spellProto->Id);
+ sLog.outError("Unit::HandleAuraRaidProcFromCharge, received not handled spell: %u", spellProto->Id);
return false;
}
@@ -13664,6 +13969,9 @@ void Unit::Kill(Unit *pVictim, bool durabilityLoss)
player->ProcDamageAndSpell(pVictim, PROC_FLAG_NONE, PROC_FLAG_KILLED,PROC_EX_NONE, 0);
}
+ // Proc auras on death - must be before aura/combat remove
+ pVictim->ProcDamageAndSpell(NULL, PROC_FLAG_DEATH, PROC_FLAG_NONE, PROC_EX_NONE, 0, BASE_ATTACK, 0);
+
// if talent known but not triggered (check priest class for speedup check)
bool SpiritOfRedemption = false;
if(pVictim->GetTypeId()==TYPEID_PLAYER && pVictim->getClass()==CLASS_PRIEST )
@@ -13705,10 +14013,10 @@ void Unit::Kill(Unit *pVictim, bool durabilityLoss)
((Player*)pVictim)->SetPvPDeath(player!=NULL);
// only if not player and not controlled by player pet. And not at BG
- if (durabilityLoss && !player && !((Player*)pVictim)->InBattleGround())
+ if ( (durabilityLoss && !player && !((Player*)pVictim)->InBattleGround()) || ( player && sWorld.getConfig(CONFIG_DURABILITY_LOSS_IN_PVP) ) )
{
- DEBUG_LOG("We are dead, loosing 10 percents durability");
- ((Player*)pVictim)->DurabilityLossAll(0.10f,false);
+ DEBUG_LOG("We are dead, losing %u percent durability", sWorld.getRate(RATE_DURABILITY_LOSS_ON_DEATH));
+ ((Player*)pVictim)->DurabilityLossAll(sWorld.getRate(RATE_DURABILITY_LOSS_ON_DEATH),false);
// durability lost message
WorldPacket data(SMSG_DURABILITY_DAMAGE_DEATH, 0);
((Player*)pVictim)->GetSession()->SendPacket(&data);
@@ -13912,27 +14220,22 @@ void Unit::SetRooted(bool apply)
{
AddUnitMovementFlag(MOVEMENTFLAG_ROOT);
- if(GetTypeId() == TYPEID_PLAYER)
- {
- WorldPacket data(SMSG_FORCE_MOVE_ROOT, 10);
- data.append(GetPackGUID());
- data << (uint32)2;
- SendMessageToSet(&data,true);
- }
- else
+ WorldPacket data(SMSG_FORCE_MOVE_ROOT, 10);
+ data.append(GetPackGUID());
+ data << (uint32)2;
+ SendMessageToSet(&data,true);
+
+ if(GetTypeId() != TYPEID_PLAYER)
((Creature *)this)->StopMoving();
}
else
{
if(!hasUnitState(UNIT_STAT_STUNNED)) // prevent allow move if have also stun effect
{
- if(GetTypeId() == TYPEID_PLAYER)
- {
- WorldPacket data(SMSG_FORCE_MOVE_UNROOT, 10);
- data.append(GetPackGUID());
- data << (uint32)2;
- SendMessageToSet(&data,true);
- }
+ WorldPacket data(SMSG_FORCE_MOVE_UNROOT, 10);
+ data.append(GetPackGUID());
+ data << (uint32)2;
+ SendMessageToSet(&data,true);
RemoveUnitMovementFlag(MOVEMENTFLAG_ROOT);
}
@@ -13990,22 +14293,28 @@ void Unit::SetConfused(bool apply)
((Player*)this)->SetClientControl(this, !apply);
}
-void Unit::SetCharmedBy(Unit* charmer, CharmType type)
+bool Unit::SetCharmedBy(Unit* charmer, CharmType type)
{
if(!charmer)
- return;
+ return false;
assert(type != CHARM_TYPE_POSSESS || charmer->GetTypeId() == TYPEID_PLAYER);
assert(type != CHARM_TYPE_VEHICLE || GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isVehicle());
+ sLog.outDebug("SetCharmedBy: charmer %u, charmed %u, type %u.", charmer->GetEntry(), GetEntry(), (uint32)type);
+
if(this == charmer)
- return;
+ return false;
- if(hasUnitState(UNIT_STAT_UNATTACKABLE))
- return;
+ //if(hasUnitState(UNIT_STAT_UNATTACKABLE))
+ // return false;
if(GetTypeId() == TYPEID_PLAYER && ((Player*)this)->GetTransport())
- return;
+ return false;
+
+ // Already charmed
+ if(GetCharmerGUID())
+ return false;
CastStop();
CombatStop(); //TODO: CombatStop(true) may cause crash (interrupt spells)
@@ -14027,7 +14336,7 @@ void Unit::SetCharmedBy(Unit* charmer, CharmType type)
// StopCastingCharm may remove a possessed pet?
if(!IsInWorld())
- return;
+ return false;
// Set charmed
setFaction(charmer->getFaction());
@@ -14096,7 +14405,8 @@ void Unit::SetCharmedBy(Unit* charmer, CharmType type)
case CHARM_TYPE_CONVERT:
break;
}
- }
+ }
+ return true;
}
void Unit::RemoveCharmedBy(Unit *charmer)
@@ -14106,8 +14416,13 @@ void Unit::RemoveCharmedBy(Unit *charmer)
if(!charmer)
charmer = GetCharmer();
- else if(charmer != GetCharmer()) // one aura overrides another?
+ if(charmer != GetCharmer()) // one aura overrides another?
+ {
+// sLog.outCrash("Unit::RemoveCharmedBy: this: " UI64FMTD " true charmer: " UI64FMTD " false charmer: " UI64FMTD,
+// GetGUID(), GetCharmerGUID(), charmer->GetGUID());
+// assert(false);
return;
+ }
CharmType type;
if(hasUnitState(UNIT_STAT_POSSESSED))
@@ -14525,6 +14840,12 @@ float Unit::MeleeSpellMissChance(const Unit *pVictim, WeaponAttackType attType,
void Unit::SetPhaseMask(uint32 newPhaseMask, bool update)
{
+ if(newPhaseMask==GetPhaseMask())
+ return;
+
+ if(IsInWorld())
+ RemoveNotOwnSingleTargetAuras(newPhaseMask); // we can lost access to caster or target
+
WorldObject::SetPhaseMask(newPhaseMask,update);
if(!IsInWorld())
@@ -14626,7 +14947,6 @@ void Unit::EnterVehicle(Vehicle *vehicle, int8 seatId)
return;
}
- addUnitState(UNIT_STAT_ONVEHICLE);
SetControlled(true, UNIT_STAT_ROOT);
//movementInfo is set in AddPassenger
//packets are sent in AddPassenger
@@ -14671,7 +14991,6 @@ void Unit::ExitVehicle()
Vehicle *vehicle = m_Vehicle;
m_Vehicle = NULL;
- clearUnitState(UNIT_STAT_ONVEHICLE);
SetControlled(false, UNIT_STAT_ROOT);
RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
@@ -14682,6 +15001,8 @@ void Unit::ExitVehicle()
m_movementInfo.t_time = 0;
m_movementInfo.t_seat = 0;
+ Relocate(vehicle->GetPositionX(), vehicle->GetPositionY(), vehicle->GetPositionZ(), GetOrientation());
+
//Send leave vehicle, not correct
if(GetTypeId() == TYPEID_PLAYER)
{
@@ -14830,3 +15151,89 @@ void Unit::NearTeleportTo( float x, float y, float z, float orientation, bool ca
//SendMessageToSet(&data, false);
}
}
+
+void Unit::SendThreatListUpdate()
+{
+ if (uint32 count = getThreatManager().getThreatList().size())
+ {
+ sLog.outDebug( "WORLD: Send SMSG_THREAT_UPDATE Message" );
+ WorldPacket data(SMSG_THREAT_UPDATE, 8 + count * 8);
+ data.append(GetPackGUID());
+ data << uint32(count);
+ std::list<HostilReference*>& tlist = getThreatManager().getThreatList();
+ for (std::list<HostilReference*>::const_iterator itr = tlist.begin(); itr != tlist.end(); ++itr)
+ {
+ data.appendPackGUID((*itr)->getUnitGuid());
+ data << uint32((*itr)->getThreat());
+ }
+ SendMessageToSet(&data, false);
+ }
+}
+
+
+void Unit::SendChangeCurrentVictimOpcode(HostilReference* pHostilReference)
+{
+ if (uint32 count = getThreatManager().getThreatList().size())
+ {
+ sLog.outDebug( "WORLD: Send SMSG_HIGHEST_THREAT_UPDATE Message" );
+ WorldPacket data(SMSG_HIGHEST_THREAT_UPDATE, 8 + 8 + count * 8);
+ data.append(GetPackGUID());
+ data.appendPackGUID(pHostilReference->getUnitGuid());
+ data << uint32(count);
+ std::list<HostilReference*>& tlist = getThreatManager().getThreatList();
+ for (std::list<HostilReference*>::const_iterator itr = tlist.begin(); itr != tlist.end(); ++itr)
+ {
+ data.appendPackGUID((*itr)->getUnitGuid());
+ data << uint32((*itr)->getThreat());
+ }
+ SendMessageToSet(&data, false);
+ }
+}
+
+void Unit::SendClearThreatListOpcode()
+{
+ sLog.outDebug( "WORLD: Send SMSG_THREAT_CLEAR Message" );
+ WorldPacket data(SMSG_THREAT_CLEAR, 8);
+ data.append(GetPackGUID());
+ SendMessageToSet(&data, false);
+}
+
+void Unit::SendRemoveFromThreatListOpcode(HostilReference* pHostilReference)
+{
+ sLog.outDebug( "WORLD: Send SMSG_THREAT_REMOVE Message" );
+ WorldPacket data(SMSG_THREAT_REMOVE, 8 + 8);
+ data.append(GetPackGUID());
+ data.appendPackGUID(pHostilReference->getUnitGuid());
+ SendMessageToSet(&data, false);
+}
+
+void Unit::RewardRage( uint32 damage, uint32 weaponSpeedHitFactor, bool attacker )
+{
+ float addRage;
+
+ float rageconversion = ((0.0091107836 * getLevel()*getLevel())+3.225598133*getLevel())+4.2652911;
+
+ // Unknown if correct, but lineary adjust rage conversion above level 70
+ if (getLevel() > 70)
+ rageconversion += 13.27f*(getLevel()-70);
+
+ if(attacker)
+ {
+ addRage = ((damage/rageconversion*7.5 + weaponSpeedHitFactor)/2);
+
+ // talent who gave more rage on attack
+ addRage *= 1.0f + GetTotalAuraModifier(SPELL_AURA_MOD_RAGE_FROM_DAMAGE_DEALT) / 100.0f;
+ }
+ else
+ {
+ addRage = damage/rageconversion*2.5;
+
+ // Berserker Rage effect
+ if(HasAura(18499))
+ addRage *= 2.0;
+ }
+
+ addRage *= sWorld.getRate(RATE_POWER_RAGE_INCOME);
+
+ ModifyPower(POWER_RAGE, uint32(addRage*10));
+}
diff --git a/src/game/Unit.h b/src/game/Unit.h
index 03a02f0c512..0c96f6a17e6 100644
--- a/src/game/Unit.h
+++ b/src/game/Unit.h
@@ -56,6 +56,7 @@ enum SpellChannelInterruptFlags
CHANNEL_FLAG_MOVEMENT = 0x0008,
CHANNEL_FLAG_TURNING = 0x0010,
CHANNEL_FLAG_DAMAGE2 = 0x0080,
+ CHANNEL_FLAG_ONLY_IN_WATER = 0x0100,
CHANNEL_FLAG_DELAY = 0x4000
};
@@ -196,6 +197,7 @@ enum ShapeshiftForm
FORM_AMBIENT = 0x06,
FORM_GHOUL = 0x07,
FORM_DIREBEAR = 0x08,
+ FORM_SHADOW_DANCE = 0x0D,
FORM_CREATUREBEAR = 0x0E,
FORM_CREATURECAT = 0x0F,
FORM_GHOSTWOLF = 0x10,
@@ -205,6 +207,7 @@ enum ShapeshiftForm
FORM_TEST = 0x14,
FORM_ZOMBIE = 0x15,
FORM_METAMORPHOSIS = 0x16,
+ FORM_UNDEAD = 0x19,
FORM_FLIGHT_EPIC = 0x1B,
FORM_SHADOW = 0x1C,
FORM_FLIGHT = 0x1D,
@@ -580,6 +583,7 @@ enum UnitFlags2
UNIT_FLAG2_FEIGN_DEATH = 0x00000001,
UNIT_FLAG2_UNK1 = 0x00000002, // Hide unit model (show only player equip)
UNIT_FLAG2_COMPREHEND_LANG = 0x00000008,
+ UNIT_FLAG2_MIRROR_IMAGE = 0x00000010,
UNIT_FLAG2_FORCE_MOVE = 0x00000040,
UNIT_FLAG2_DISARM_OFFHAND = 0x00000080,
UNIT_FLAG2_DISARM_RANGED = 0x00000400, //this does not disable ranged weapon display (maybe additional flag needed?)
@@ -768,10 +772,12 @@ enum MeleeHitOutcome
struct CleanDamage
{
- CleanDamage(uint32 _damage, WeaponAttackType _attackType, MeleeHitOutcome _hitOutCome) :
- damage(_damage), attackType(_attackType), hitOutCome(_hitOutCome) {}
+ CleanDamage(uint32 mitigated, uint32 absorbed, WeaponAttackType _attackType, MeleeHitOutcome _hitOutCome) :
+ mitigated_damage(mitigated), absorbed_damage(absorbed), attackType(_attackType), hitOutCome(_hitOutCome) {}
+
+ uint32 absorbed_damage;
+ uint32 mitigated_damage;
- uint32 damage;
WeaponAttackType attackType;
MeleeHitOutcome hitOutCome;
};
@@ -823,8 +829,8 @@ struct SpellNonMeleeDamage{
struct SpellPeriodicAuraLogInfo
{
- SpellPeriodicAuraLogInfo(AuraEffect *_auraEff, uint32 _damage, uint32 _overDamage, uint32 _absorb, uint32 _resist, float _multiplier)
- : auraEff(_auraEff), damage(_damage), overDamage(_overDamage), absorb(_absorb), resist(_resist), multiplier(_multiplier) {}
+ SpellPeriodicAuraLogInfo(AuraEffect *_auraEff, uint32 _damage, uint32 _overDamage, uint32 _absorb, uint32 _resist, float _multiplier, bool _critical)
+ : auraEff(_auraEff), damage(_damage), overDamage(_overDamage), absorb(_absorb), resist(_resist), multiplier(_multiplier), critical(_critical){}
AuraEffect *auraEff;
uint32 damage;
@@ -832,6 +838,7 @@ struct SpellPeriodicAuraLogInfo
uint32 resist;
uint32 overDamage; // overkill/overheal
float multiplier;
+ bool critical;
};
uint32 createProcExtendMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition);
@@ -855,12 +862,12 @@ enum CurrentSpellTypes
enum ActiveStates
{
- ACT_PASSIVE = 0x0100, // 0x0100 - passive
- ACT_DISABLED = 0x8100, // 0x8000 - castable
- ACT_ENABLED = 0xC100, // 0x4000 | 0x8000 - auto cast + castable
- ACT_COMMAND = 0x0700, // 0x0100 | 0x0200 | 0x0400
- ACT_REACTION = 0x0600, // 0x0200 | 0x0400
- ACT_DECIDE = 0x0001 // what is it?
+ ACT_PASSIVE = 0x01, // 0x01 - passive
+ ACT_DISABLED = 0x81, // 0x80 - castable
+ ACT_ENABLED = 0xC1, // 0x40 | 0x80 - auto cast + castable
+ ACT_COMMAND = 0x07, // 0x01 | 0x02 | 0x04
+ ACT_REACTION = 0x06, // 0x02 | 0x04
+ ACT_DECIDE = 0x00 // custom
};
enum ReactStates
@@ -878,24 +885,40 @@ enum CommandStates
COMMAND_ABANDON = 3
};
+#define UNIT_ACTION_BUTTON_ACTION(X) (uint32(X) & 0x00FFFFFF)
+#define UNIT_ACTION_BUTTON_TYPE(X) ((uint32(X) & 0xFF000000) >> 24)
+#define MAX_UNIT_ACTION_BUTTON_ACTION_VALUE (0x00FFFFFF+1)
+#define MAKE_UNIT_ACTION_BUTTON(A,T) (uint32(A) | (uint32(T) << 24))
+
struct UnitActionBarEntry
{
- UnitActionBarEntry() : SpellOrAction(0), Type(ACT_DISABLED) {}
+ UnitActionBarEntry() : packedData(uint32(ACT_DISABLED) << 24) {}
- uint16 SpellOrAction;
- uint16 Type;
+ uint32 packedData;
// helper
+ ActiveStates GetType() const { return ActiveStates(UNIT_ACTION_BUTTON_TYPE(packedData)); }
+ uint32 GetAction() const { return UNIT_ACTION_BUTTON_ACTION(packedData); }
bool IsActionBarForSpell() const
{
+ ActiveStates Type = GetType();
return Type == ACT_DISABLED || Type == ACT_ENABLED || Type == ACT_PASSIVE;
}
-};
-struct CharmSpellEntry
-{
- uint16 spellId;
- uint16 active;
+ void SetActionAndType(uint32 action, ActiveStates type)
+ {
+ packedData = MAKE_UNIT_ACTION_BUTTON(action,type);
+ }
+
+ void SetType(ActiveStates type)
+ {
+ packedData = MAKE_UNIT_ACTION_BUTTON(UNIT_ACTION_BUTTON_ACTION(packedData),type);
+ }
+
+ void SetAction(uint32 action)
+ {
+ packedData = (packedData & 0xFF000000) | UNIT_ACTION_BUTTON_ACTION(action);
+ }
};
typedef std::list<Player*> SharedVisionList;
@@ -908,6 +931,8 @@ enum CharmType
CHARM_TYPE_CONVERT,
};
+typedef UnitActionBarEntry CharmSpellEntry;
+
enum ActionBarIndex
{
ACTION_BAR_INDEX_START = 0,
@@ -946,8 +971,7 @@ struct CharmInfo
void SetSpellAutocast(uint32 spell_id, bool state);
void SetActionBar(uint8 index, uint32 spellOrAction,ActiveStates type)
{
- PetActionBar[index].Type = type;
- PetActionBar[index].SpellOrAction = spellOrAction;
+ PetActionBar[index].SetActionAndType(spellOrAction,type);
}
UnitActionBarEntry const* GetActionBarEntry(uint8 index) const { return &(PetActionBar[index]); }
@@ -988,6 +1012,7 @@ enum ReactiveType
// delay time next attack to prevent client attack animation problems
#define ATTACK_DISPLAY_DELAY 200
+#define MAX_PLAYER_STEALTH_DETECT_RANGE 45.0f // max distance for detection targets by player
struct SpellProcEventEntry; // used only privately
@@ -998,6 +1023,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
typedef std::set<Unit*> ControlList;
typedef std::pair<uint32, uint8> spellEffectPair;
typedef std::multimap<uint32, Aura*> AuraMap;
+ typedef std::multimap<AuraState, Aura*> AuraStateAurasMap;
typedef std::list<AuraEffect *> AuraEffectList;
typedef std::list<Aura *> AuraList;
typedef std::list<DiminishingReturn> Diminishing;
@@ -1014,7 +1040,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
DiminishingLevels GetDiminishing(DiminishingGroup group);
void IncrDiminishing(DiminishingGroup group);
- void ApplyDiminishingToDuration(DiminishingGroup group, int32 &duration,Unit* caster, DiminishingLevels Level);
+ void ApplyDiminishingToDuration(DiminishingGroup group, int32 &duration,Unit* caster, DiminishingLevels Level, int32 limitduration);
void ApplyDiminishingAura(DiminishingGroup group, bool apply);
void ClearDiminishings() { m_Diminishing.clear(); }
@@ -1177,7 +1203,6 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
void Unmount();
uint16 GetMaxSkillValueForLevel(Unit const* target = NULL) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; }
- void RemoveSpellbyDamageTaken(uint32 damage, uint32 spell);
void DealDamageMods(Unit *pVictim, uint32 &damage, uint32* absorb);
uint32 DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDamage = NULL, DamageEffectType damagetype = DIRECT_DAMAGE, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellEntry const *spellProto = NULL, bool durabilityLoss = true);
void Kill(Unit *pVictim, bool durabilityLoss = true);
@@ -1258,7 +1283,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
bool isInFlight() const { return hasUnitState(UNIT_STAT_IN_FLIGHT); }
bool isInCombat() const { return HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); }
- void CombatStart(Unit* target);
+ void CombatStart(Unit* target, bool initialAggro = true);
void SetInCombatState(bool PvP, Unit* enemy = NULL);
void SetInCombatWith(Unit* enemy);
void ClearInCombat();
@@ -1288,7 +1313,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
uint32 SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage);
void CastSpell(Unit* Victim, uint32 spellId, bool triggered, Item *castItem = NULL, AuraEffect* triggeredByAura = NULL, uint64 originalCaster = 0);
void CastSpell(Unit* Victim, SpellEntry const *spellInfo, bool triggered, Item *castItem= NULL, AuraEffect* triggeredByAura = NULL, uint64 originalCaster = 0);
- void CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item *castItem = NULL, AuraEffect* triggeredByAura = NULL, uint64 originalCaster = 0);
+ void CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item *castItem = NULL, AuraEffect* triggeredByAura = NULL, uint64 originalCaster = 0, Unit* originalVictim = 0);
void CastCustomSpell(Unit* Victim, uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item *castItem= NULL, AuraEffect* triggeredByAura = NULL, uint64 originalCaster = 0);
void CastCustomSpell(uint32 spellId, SpellValueMod mod, int32 value, Unit* Victim = NULL, bool triggered = true, Item *castItem = NULL, AuraEffect* triggeredByAura = NULL, uint64 originalCaster = 0);
void CastCustomSpell(uint32 spellId, CustomSpellValues const &value, Unit* Victim = NULL, bool triggered = true, Item *castItem = NULL, AuraEffect* triggeredByAura = NULL, uint64 originalCaster = 0);
@@ -1325,6 +1350,11 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
void SendMonsterMoveWithSpeedToCurrentDestination(Player* player = NULL);
void SendMovementFlagUpdate();
+ void SendChangeCurrentVictimOpcode(HostilReference* pHostilReference);
+ void SendClearThreatListOpcode();
+ void SendRemoveFromThreatListOpcode(HostilReference* pHostilReference);
+ void SendThreatListUpdate();
+
void BuildHeartBeatMsg(WorldPacket *data) const;
void OutMovementInfo() const;
@@ -1374,7 +1404,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
void SetMinion(Minion *minion, bool apply);
void SetCharm(Unit* target, bool apply);
Unit* GetNextRandomRaidMemberOrPet(float radius);
- void SetCharmedBy(Unit* charmer, CharmType type);
+ bool SetCharmedBy(Unit* charmer, CharmType type);
void RemoveCharmedBy(Unit* charmer);
void RestoreFaction();
@@ -1420,11 +1450,15 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
void RemoveAurasDueToItemSpell(Item* castItem,uint32 spellId);
void RemoveAurasByType(AuraType auraType, uint64 casterGUID = 0, Aura * except=NULL, bool negative = true, bool positive = true);
void RemoveAurasByTypeWithDispel(AuraType auraType, Spell * spell = NULL);
- void RemoveNotOwnSingleTargetAuras();
+ void RemoveNotOwnSingleTargetAuras(uint32 newPhase = 0x0);
+
+ void RemoveSpellsCausingAura(AuraType auraType);
+ void RemoveRankAurasDueToSpell(uint32 spellId);
bool RemoveNoStackAurasDueToAura(Aura *Aur);
void RemoveAurasWithInterruptFlags(uint32 flag, uint32 except = NULL);
void RemoveAurasWithFamily(uint32 family, uint32 familyFlag1, uint32 familyFlag2, uint32 familyFlag3, uint64 casterGUID);
void RemoveMovementImpairingAuras();
+ void RemoveAurasWithMechanic(uint32 mechanic_mask, uint32 except=0);
void RemoveAllAuras();
void RemoveArenaAuras(bool onleave = false);
void RemoveAllAurasOnDeath();
@@ -1469,6 +1503,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid = 0, bool withInstant = true);
Spell* FindCurrentSpellBySpellId(uint32 spell_id) const;
+ int32 GetCurrentSpellCastTime(uint32 spell_id) const;
Spell* m_currentSpells[CURRENT_MAX_SPELL];
@@ -1572,14 +1607,15 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
AuraEffect * GetAuraEffect(uint32 spellId, uint8 effIndex, uint64 casterGUID = 0) const;
Aura * GetAura(uint32 spellId, uint64 casterGUID = 0) const;
- AuraEffect* GetAura(AuraType type, uint32 family, uint32 familyFlag1 , uint32 familyFlag2=0, uint32 familyFlag3=0, uint64 casterGUID=0);
+ AuraEffect * GetAura(AuraType type, uint32 family, uint32 familyFlag1 , uint32 familyFlag2=0, uint32 familyFlag3=0, uint64 casterGUID=0);
+ AuraEffect * IsScriptOverriden(SpellEntry const * spell, int32 script) const;
bool HasAuraEffect(uint32 spellId, uint8 effIndex, uint64 caster = 0) const;
bool HasAura(uint32 spellId, uint64 caster = 0) const;
bool HasAura(Aura * aur) const;
bool HasAuraType(AuraType auraType) const;
bool HasAuraTypeWithMiscvalue(AuraType auratype, uint32 miscvalue) const;
- AuraEffect* GetDummyAura(uint32 spell_id) const;
- AuraEffect* GetDummyAura(SpellFamilyNames name, uint32 iconId) const;
+ inline AuraEffect* GetDummyAura(SpellFamilyNames name, uint32 iconId, uint8 effIndex) const { return GetAuraEffect(SPELL_AURA_DUMMY, name, iconId, effIndex);}
+ AuraEffect* GetAuraEffect(AuraType type, SpellFamilyNames name, uint32 iconId, uint8 effIndex) const;
uint32 GetDiseasesByCaster(uint64 casterGUID, bool remove = false);
uint32 GetDoTsByCaster(uint64 casterGUID) const;
@@ -1625,6 +1661,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
uint32 CalculateDamage(WeaponAttackType attType, bool normalized);
float GetAPMultiplier(WeaponAttackType attType, bool normalized);
void ModifyAuraState(AuraState flag, bool apply);
+ uint32 BuildAuraStateUpdateForTarget(Unit * target) const;
bool HasAuraState(AuraState flag, SpellEntry const *spellProto = NULL, Unit * Caster = NULL) const ;
void UnsummonAllTotems();
Unit* SelectMagnetTarget(Unit *victim, SpellEntry const *spellInfo = NULL);
@@ -1705,8 +1742,6 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
void SendPetCastFail(uint32 spellid, SpellCastResult msg);
void SendPetActionFeedback (uint8 msg);
void SendPetTalk (uint32 pettalk);
- void SendPetSpellCooldown (uint32 spellid, time_t cooltime);
- void SendPetClearCooldown (uint32 spellid);
void SendPetAIReaction(uint64 guid);
///----------End of Pet responses methods----------
@@ -1780,6 +1815,10 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
bool canFly() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_FLY_MODE); }
bool IsFlying() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_FLYING); }
void SetFlying(bool apply);
+
+ void RewardRage( uint32 damage, uint32 weaponSpeedHitFactor, bool attacker );
+
+ virtual float GetFollowAngle() const { return M_PI/2; }
protected:
explicit Unit ();
@@ -1819,14 +1858,13 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
AuraEffectList m_modAuras[TOTAL_AURAS];
AuraList m_scAuras; // casted singlecast auras
AuraList m_interruptableAuras;
- AuraList m_ccAuras;
AuraList m_removedAuras;
+ AuraStateAurasMap m_auraStateAuras; // Used for improve performance of aura state checks on aura apply/remove
uint32 m_interruptMask;
float m_auraModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_END];
float m_weaponDamage[MAX_ATTACK][2];
bool m_canModifyStats;
- //std::list< spellEffectPair > AuraSpells[TOTAL_AURAS]; // TODO: use this if ok for mem
VisibleAuraMap m_visibleAuras;
float m_speed_rate[MAX_MOVE_TYPE];
diff --git a/src/game/UnitAI.cpp b/src/game/UnitAI.cpp
index c159861697c..a41ad894097 100644
--- a/src/game/UnitAI.cpp
+++ b/src/game/UnitAI.cpp
@@ -325,6 +325,10 @@ void UnitAI::FillAISpellInfo()
}
}
}
+ AIInfo->realCooldown = spellInfo->RecoveryTime + spellInfo->StartRecoveryTime;
+ SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex);
+ if (srange)
+ AIInfo->maxRange = srange->maxRangeHostile * 3 / 4;
}
}
@@ -348,7 +352,7 @@ void SimpleCharmedAI::UpdateAI(const uint32 /*diff*/)
}
if(!charmer->isInCombat())
- me->GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
+ me->GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, me->GetFollowAngle());
Unit *target = me->getVictim();
if(!target || !charmer->canAttack(target))
diff --git a/src/game/UnitAI.h b/src/game/UnitAI.h
index 9530405ed4d..3e6ce4f4a6f 100644
--- a/src/game/UnitAI.h
+++ b/src/game/UnitAI.h
@@ -23,6 +23,7 @@
#include "Platform/Define.h"
#include <list>
+#include "Unit.h"
class Unit;
class Player;
@@ -47,7 +48,7 @@ class TRINITY_DLL_SPEC UnitAI
virtual void AttackStart(Unit *);
virtual void UpdateAI(const uint32 diff) = 0;
- virtual void InitializeAI() { Reset(); }
+ virtual void InitializeAI() { if(!me->isDead()) Reset(); }
virtual void Reset() {};
diff --git a/src/game/UpdateData.cpp b/src/game/UpdateData.cpp
index a3192b74b0e..e461d63e248 100644
--- a/src/game/UpdateData.cpp
+++ b/src/game/UpdateData.cpp
@@ -128,7 +128,7 @@ bool UpdateData::BuildPacket(WorldPacket *packet)
if (pSize > 100 ) // compress large packets
{
- uint32 destsize = pSize;
+ uint32 destsize = compressBound(pSize);
packet->resize( destsize + sizeof(uint32) );
packet->put<uint32>(0, pSize);
diff --git a/src/game/Vehicle.cpp b/src/game/Vehicle.cpp
index 0aa0d48a24c..3cad7963d0b 100644
--- a/src/game/Vehicle.cpp
+++ b/src/game/Vehicle.cpp
@@ -65,9 +65,9 @@ void Vehicle::AddToWorld()
}
}
+ Unit::AddToWorld();
InstallAllAccessories();
- Unit::AddToWorld();
AIM_Initialize();
}
}
@@ -90,9 +90,11 @@ void Vehicle::InstallAllAccessories()
InstallAccessory(33139,7);
break;
case 33114:
- InstallAccessory(33143,1);
- //InstallAccessory(33142,0);
- InstallAccessory(33142,2);
+ InstallAccessory(33142,0);
+ //InstallAccessory(33143,1);
+ //InstallAccessory(33142,2);
+ InstallAccessory(33143,2);
+ InstallAccessory(33142,1);
break;
}
}
@@ -266,8 +268,7 @@ void Vehicle::InstallAccessory(uint32 entry, int8 seatId)
if(!accessory)
return;
- accessory->m_Vehicle = this;
- AddPassenger(accessory, seatId);
+ accessory->EnterVehicle(this, seatId);
// This is not good, we have to send update twice
accessory->SendMovementFlagUpdate();
}
@@ -310,6 +311,9 @@ bool Vehicle::AddPassenger(Unit *unit, int8 seatId)
RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
}
+ if(!(seat->second.seatInfo->m_flags & 0x4000))
+ unit->addUnitState(UNIT_STAT_ONVEHICLE);
+
//SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_24);
unit->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
@@ -321,11 +325,15 @@ bool Vehicle::AddPassenger(Unit *unit, int8 seatId)
unit->m_movementInfo.t_time = 0; // 1 for player
unit->m_movementInfo.t_seat = seat->first;
- if(unit->GetTypeId() == TYPEID_PLAYER && seat->first == 0 && seat->second.seatInfo->IsUsable()) // not right
- SetCharmedBy(unit, CHARM_TYPE_VEHICLE);
+ if(unit->GetTypeId() == TYPEID_PLAYER && seat->first == 0 && seat->second.seatInfo->m_flags & 0x800) // not right
+ if (!SetCharmedBy(unit, CHARM_TYPE_VEHICLE))
+ assert(false);
if(IsInWorld())
+ {
unit->SendMonsterMoveTransport(this);
+ GetMap()->CreatureRelocation(this, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
+ }
//if(unit->GetTypeId() == TYPEID_PLAYER)
// ((Player*)unit)->SendTeleportAckMsg();
@@ -341,27 +349,27 @@ void Vehicle::RemovePassenger(Unit *unit)
SeatMap::iterator seat;
for(seat = m_Seats.begin(); seat != m_Seats.end(); ++seat)
- {
if(seat->second.passenger == unit)
- {
- seat->second.passenger = NULL;
- if(seat->second.seatInfo->IsUsable())
- {
- if(!m_usableSeatNum)
- SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
- ++m_usableSeatNum;
- }
break;
- }
- }
assert(seat != m_Seats.end());
- sLog.outDebug("Unit %s exit vehicle entry %u id %u dbguid %u", unit->GetName(), GetEntry(), m_vehicleInfo->m_ID, GetDBTableGUIDLow());
+ sLog.outDebug("Unit %s exit vehicle entry %u id %u dbguid %u seat %d", unit->GetName(), GetEntry(), m_vehicleInfo->m_ID, GetDBTableGUIDLow(), (int32)seat->first);
+
+ seat->second.passenger = NULL;
+ if(seat->second.seatInfo->IsUsable())
+ {
+ if(!m_usableSeatNum)
+ SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
+ ++m_usableSeatNum;
+ }
+
+ if(!(seat->second.seatInfo->m_flags & 0x4000))
+ unit->clearUnitState(UNIT_STAT_ONVEHICLE);
//SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
- if(unit->GetTypeId() == TYPEID_PLAYER && seat->first == 0 && seat->second.seatInfo->IsUsable())
+ if(unit->GetTypeId() == TYPEID_PLAYER && seat->first == 0 && seat->second.seatInfo->m_flags & 0x800)
RemoveCharmedBy(unit);
// only for flyable vehicles?
@@ -382,7 +390,6 @@ void Vehicle::Dismiss()
RemoveAllPassengers();
SendObjectDeSpawnAnim(GetGUID());
CombatStop();
- CleanupsBeforeDelete();
AddObjectToRemoveList();
}
diff --git a/src/game/WaypointMovementGenerator.cpp b/src/game/WaypointMovementGenerator.cpp
index 34be9d3179b..92fd9bca2d7 100644
--- a/src/game/WaypointMovementGenerator.cpp
+++ b/src/game/WaypointMovementGenerator.cpp
@@ -198,7 +198,7 @@ WaypointMovementGenerator<Creature>::Update(Creature &unit, const uint32 &diff)
//note: disable "start" for mtmap
if(node->event_id && rand()%100 < node->event_chance)
- sWorld.ScriptsStart(sWaypointScripts, node->event_id, &unit, NULL, false);
+ unit.GetMap()->ScriptsStart(sWaypointScripts, node->event_id, &unit, NULL/*, false*/);
MovementInform(unit);
unit.UpdateWaypointID(i_currentNode);
diff --git a/src/game/World.cpp b/src/game/World.cpp
index 608aaec01d5..f7cc552342a 100644
--- a/src/game/World.cpp
+++ b/src/game/World.cpp
@@ -63,7 +63,6 @@
#include "GridNotifiersImpl.h"
#include "CellImpl.h"
#include "InstanceSaveMgr.h"
-#include "WaypointManager.h"
#include "Util.h"
#include "Language.h"
#include "CreatureGroups.h"
@@ -83,14 +82,6 @@ float World::m_MaxVisibleDistanceInFlight = DEFAULT_VISIBILITY_DISTANCE;
float World::m_VisibleUnitGreyDistance = 0;
float World::m_VisibleObjectGreyDistance = 0;
-struct ScriptAction
-{
- uint64 sourceGUID;
- uint64 targetGUID;
- uint64 ownerGUID; // owner of source if source is item
- ScriptInfo const* script; // pointer to static script data
-};
-
/// World constructor
World::World()
{
@@ -102,8 +93,11 @@ World::World()
m_startTime=m_gameTime;
m_maxActiveSessionCount = 0;
m_maxQueuedSessionCount = 0;
+ m_PlayerCount = 0;
+ m_MaxPlayerCount = 0;
m_resultQueue = NULL;
m_NextDailyQuestReset = 0;
+ m_scheduledScripts = 0;
m_defaultDbcLocale = LOCALE_enUS;
m_availableDbcLocaleMask = 0;
@@ -266,7 +260,7 @@ World::AddSession_ (WorldSession* s)
float popu = GetActiveSessionCount (); //updated number of users on the server
popu /= pLimit;
popu *= 2;
- LoginDatabase.PExecute ("UPDATE realmlist SET population = '%f' WHERE id = '%d'", popu, realmID);
+ loginDatabase.PExecute ("UPDATE realmlist SET population = '%f' WHERE id = '%d'", popu, realmID);
sLog.outDetail ("Server Population (%f).", popu);
}
}
@@ -475,6 +469,12 @@ void World::LoadConfigSettings(bool reload)
rate_values[RATE_XP_KILL] = sConfig.GetFloatDefault("Rate.XP.Kill", 1.0f);
rate_values[RATE_XP_QUEST] = sConfig.GetFloatDefault("Rate.XP.Quest", 1.0f);
rate_values[RATE_XP_EXPLORE] = sConfig.GetFloatDefault("Rate.XP.Explore", 1.0f);
+ rate_values[RATE_REPAIRCOST] = sConfig.GetFloatDefault("Rate.RepairCost", 1.0f);
+ if(rate_values[RATE_REPAIRCOST] < 0.0f)
+ {
+ sLog.outError("Rate.RepairCost (%f) must be >=0. Using 0.0 instead.",rate_values[RATE_REPAIRCOST]);
+ rate_values[RATE_REPAIRCOST] = 0.0f;
+ }
rate_values[RATE_REPUTATION_GAIN] = sConfig.GetFloatDefault("Rate.Reputation.Gain", 1.0f);
rate_values[RATE_REPUTATION_LOWLEVEL_KILL] = sConfig.GetFloatDefault("Rate.Reputation.LowLevel.Kill", 1.0f);
rate_values[RATE_REPUTATION_LOWLEVEL_QUEST] = sConfig.GetFloatDefault("Rate.Reputation.LowLevel.Quest", 1.0f);
@@ -526,6 +526,19 @@ void World::LoadConfigSettings(bool reload)
rate_values[RATE_TARGET_POS_RECALCULATION_RANGE] = NOMINAL_MELEE_RANGE;
}
+ rate_values[RATE_DURABILITY_LOSS_ON_DEATH] = sConfig.GetFloatDefault("DurabilityLoss.OnDeath", 10.0f);
+ if(rate_values[RATE_DURABILITY_LOSS_ON_DEATH] < 0.0f)
+ {
+ sLog.outError("DurabilityLoss.OnDeath (%f) must be >=0. Using 0.0 instead.",rate_values[RATE_DURABILITY_LOSS_ON_DEATH]);
+ rate_values[RATE_DURABILITY_LOSS_ON_DEATH] = 0.0f;
+ }
+ if(rate_values[RATE_DURABILITY_LOSS_ON_DEATH] > 100.0f)
+ {
+ sLog.outError("DurabilityLoss.OnDeath (%f) must be <=100. Using 100.0 instead.",rate_values[RATE_DURABILITY_LOSS_ON_DEATH]);
+ rate_values[RATE_DURABILITY_LOSS_ON_DEATH] = 0.0f;
+ }
+ rate_values[RATE_DURABILITY_LOSS_ON_DEATH] = rate_values[RATE_DURABILITY_LOSS_ON_DEATH] / 100.0f;
+
rate_values[RATE_DURABILITY_LOSS_DAMAGE] = sConfig.GetFloatDefault("DurabilityLossChance.Damage",0.5f);
if(rate_values[RATE_DURABILITY_LOSS_DAMAGE] < 0.0f)
{
@@ -553,6 +566,8 @@ void World::LoadConfigSettings(bool reload)
///- Read other configuration items from the config file
+ m_configs[CONFIG_DURABILITY_LOSS_IN_PVP] = sConfig.GetBoolDefault("DurabilityLoss.InPvP", false);
+
m_configs[CONFIG_COMPRESSION] = sConfig.GetIntDefault("Compression", 1);
if(m_configs[CONFIG_COMPRESSION] < 1 || m_configs[CONFIG_COMPRESSION] > 9)
{
@@ -639,6 +654,27 @@ void World::LoadConfigSettings(bool reload)
m_configs[CONFIG_STRICT_CHARTER_NAMES] = sConfig.GetIntDefault ("StrictCharterNames", 0);
m_configs[CONFIG_STRICT_PET_NAMES] = sConfig.GetIntDefault ("StrictPetNames", 0);
+ m_configs[CONFIG_MIN_PLAYER_NAME] = sConfig.GetIntDefault ("MinPlayerName", 2);
+ if(m_configs[CONFIG_MIN_PLAYER_NAME] < 1 || m_configs[CONFIG_MIN_PLAYER_NAME] > MAX_PLAYER_NAME)
+ {
+ sLog.outError("MinPlayerName (%i) must be in range 1..%u. Set to 2.",m_configs[CONFIG_MIN_PLAYER_NAME],MAX_PLAYER_NAME);
+ m_configs[CONFIG_MIN_PLAYER_NAME] = 2;
+ }
+
+ m_configs[CONFIG_MIN_CHARTER_NAME] = sConfig.GetIntDefault ("MinCharterName", 2);
+ if(m_configs[CONFIG_MIN_CHARTER_NAME] < 1 || m_configs[CONFIG_MIN_CHARTER_NAME] > MAX_CHARTER_NAME)
+ {
+ sLog.outError("MinCharterName (%i) must be in range 1..%u. Set to 2.",m_configs[CONFIG_MIN_CHARTER_NAME],MAX_CHARTER_NAME);
+ m_configs[CONFIG_MIN_CHARTER_NAME] = 2;
+ }
+
+ m_configs[CONFIG_MIN_PET_NAME] = sConfig.GetIntDefault ("MinPetName", 2);
+ if(m_configs[CONFIG_MIN_PET_NAME] < 1 || m_configs[CONFIG_MIN_PET_NAME] > MAX_PET_NAME)
+ {
+ sLog.outError("MinPetName (%i) must be in range 1..%u. Set to 2.",m_configs[CONFIG_MIN_PET_NAME],MAX_PET_NAME);
+ m_configs[CONFIG_MIN_PET_NAME] = 2;
+ }
+
m_configs[CONFIG_CHARACTERS_CREATING_DISABLED] = sConfig.GetIntDefault ("CharactersCreatingDisabled", 0);
m_configs[CONFIG_CHARACTERS_PER_REALM] = sConfig.GetIntDefault("CharactersPerRealm", 10);
@@ -790,8 +826,9 @@ void World::LoadConfigSettings(bool reload)
//m_configs[CONFIG_GM_ACCEPT_TICKETS] = sConfig.GetIntDefault("GM.AcceptTickets", 2);
m_configs[CONFIG_GM_CHAT] = sConfig.GetIntDefault("GM.Chat", 2);
m_configs[CONFIG_GM_WISPERING_TO] = sConfig.GetIntDefault("GM.WhisperingTo", 2);
- m_configs[CONFIG_GM_IN_GM_LIST] = sConfig.GetBoolDefault("GM.InGMList", false);
- m_configs[CONFIG_GM_IN_WHO_LIST] = sConfig.GetBoolDefault("GM.InWhoList", false);
+
+ m_configs[CONFIG_GM_LEVEL_IN_GM_LIST] = sConfig.GetIntDefault("GM.InGMList.Level", SEC_ADMINISTRATOR);
+ m_configs[CONFIG_GM_LEVEL_IN_WHO_LIST] = sConfig.GetIntDefault("GM.InWhoList.Level", SEC_ADMINISTRATOR);
m_configs[CONFIG_GM_LOG_TRADE] = sConfig.GetBoolDefault("GM.LogTrade", false);
m_configs[CONFIG_START_GM_LEVEL] = sConfig.GetIntDefault("GM.StartLevel", 1);
m_configs[CONFIG_ALLOW_GM_GROUP] = sConfig.GetBoolDefault("GM.AllowInvite", false);
@@ -1156,7 +1193,7 @@ void World::SetInitialWorldSettings()
// not send custom type REALM_FFA_PVP to realm list
uint32 server_type = IsFFAPvPRealm() ? REALM_TYPE_PVP : getConfig(CONFIG_GAME_TYPE);
uint32 realm_zone = getConfig(CONFIG_REALM_ZONE);
- LoginDatabase.PExecute("UPDATE realmlist SET icon = %u, timezone = %u WHERE id = '%d'", server_type, realm_zone, realmID);
+ loginDatabase.PExecute("UPDATE realmlist SET icon = %u, timezone = %u WHERE id = '%d'", server_type, realm_zone, realmID);
///- Remove the bones after a restart
CharacterDatabase.PExecute("DELETE FROM corpse WHERE corpse_type = '0'");
@@ -1340,9 +1377,6 @@ void World::SetInitialWorldSettings()
sLog.outString( "Loading Spell target coordinates..." );
spellmgr.LoadSpellTargetPositions();
- sLog.outString( "Loading SpellAffect definitions..." );
- spellmgr.LoadSpellAffects();
-
sLog.outString( "Loading spell pet auras..." );
spellmgr.LoadSpellPetAuras();
@@ -1514,9 +1548,11 @@ void World::SetInitialWorldSettings()
sprintf( isoDate, "%04d-%02d-%02d %02d:%02d:%02d",
local.tm_year+1900, local.tm_mon+1, local.tm_mday, local.tm_hour, local.tm_min, local.tm_sec);
- LoginDatabase.PExecute("INSERT INTO uptime (realmid, starttime, startstring, uptime) VALUES('%u', " UI64FMTD ", '%s', 0)",
+ loginDatabase.PExecute("INSERT INTO uptime (realmid, starttime, startstring, uptime) VALUES('%u', " UI64FMTD ", '%s', 0)",
realmID, uint64(m_startTime), isoDate);
+ static uint32 abtimer = 0;
+ abtimer = sConfig.GetIntDefault("AutoBroadcast.Timer", 60000);
m_timers[WUPDATE_OBJECTS].SetInterval(IN_MILISECONDS/2);
m_timers[WUPDATE_SESSIONS].SetInterval(0);
m_timers[WUPDATE_WEATHERS].SetInterval(1*IN_MILISECONDS);
@@ -1527,6 +1563,7 @@ void World::SetInitialWorldSettings()
//erase corpses every 20 minutes
m_timers[WUPDATE_CLEANDB].SetInterval(m_configs[CONFIG_LOGDB_CLEARINTERVAL]*MINUTE*IN_MILISECONDS);
// clean logs table every 14 days by default
+ m_timers[WUPDATE_AUTOBROADCAST].SetInterval(abtimer);
//to set mailtimer to return mails every day between 4 and 5 am
//mailtimer is increased when updating auctions
@@ -1565,7 +1602,7 @@ void World::SetInitialWorldSettings()
objmgr.LoadTransportEvents();
sLog.outString("Deleting expired bans..." );
- LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
+ loginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
sLog.outString("Calculate next daily quest reset time..." );
InitDailyQuestResetTime();
@@ -1574,7 +1611,7 @@ void World::SetInitialWorldSettings()
poolhandler.Initialize();
sLog.outString("Initialize AuctionHouseBot...");
- AuctionHouseBotInit();
+ auctionbot.Initialize();
// possibly enable db logging; avoid massive startup spam by doing it here.
if (sLog.GetLogDBLater())
@@ -1700,7 +1737,7 @@ void World::Update(uint32 diff)
/// <ul><li> Handle auctions when the timer has passed
if (m_timers[WUPDATE_AUCTIONS].Passed())
{
- AuctionHouseBot();
+ auctionbot.Update();
m_timers[WUPDATE_AUCTIONS].Reset();
///- Update mails (return old mails with item, or delete them)
@@ -1748,7 +1785,7 @@ void World::Update(uint32 diff)
uint32 maxClientsNum = GetMaxActiveSessionCount();
m_timers[WUPDATE_UPTIME].Reset();
- LoginDatabase.PExecute("UPDATE uptime SET uptime = %u, maxplayers = %u WHERE realmid = %u AND starttime = " UI64FMTD, tmpDiff, maxClientsNum, realmID, uint64(m_startTime));
+ loginDatabase.PExecute("UPDATE uptime SET uptime = %u, maxplayers = %u WHERE realmid = %u AND starttime = " UI64FMTD, tmpDiff, maxClientsNum, realmID, uint64(m_startTime));
}
/// <li> Clean logs table
@@ -1760,7 +1797,7 @@ void World::Update(uint32 diff)
uint32 maxClientsNum = sWorld.GetMaxActiveSessionCount();
m_timers[WUPDATE_CLEANDB].Reset();
- LoginDatabase.PExecute("DELETE FROM logs WHERE (time + %u) < "UI64FMTD";",
+ loginDatabase.PExecute("DELETE FROM logs WHERE (time + %u) < "UI64FMTD";",
sWorld.getConfig(CONFIG_LOGDB_CLEARTIME), uint64(time(0)));
}
}
@@ -1775,12 +1812,15 @@ void World::Update(uint32 diff)
MapManager::Instance().DoDelayedMovesAndRemoves();
}*/
- ///- Process necessary scripts
- if (!m_scriptSchedule.empty())
+ static uint32 autobroadcaston = 0;
+ autobroadcaston = sConfig.GetIntDefault("AutoBroadcast.On", 0);
+ if(autobroadcaston == 1)
{
- RecordTimeDiff(NULL);
- ScriptsProcess();
- RecordTimeDiff("UpdateScriptsProcess");
+ if (m_timers[WUPDATE_AUTOBROADCAST].Passed())
+ {
+ m_timers[WUPDATE_AUTOBROADCAST].Reset();
+ SendRNDBroadcast();
+ }
}
sBattleGroundMgr.Update(diff);
@@ -1827,831 +1867,6 @@ void World::ForceGameEventUpdate()
m_timers[WUPDATE_EVENTS].Reset();
}
-/// Put scripts in the execution queue
-void World::ScriptsStart(ScriptMapMap const& scripts, uint32 id, Object* source, Object* target, bool start)
-{
- ///- Find the script map
- ScriptMapMap::const_iterator s = scripts.find(id);
- if (s == scripts.end())
- return;
-
- // prepare static data
- uint64 sourceGUID = source ? source->GetGUID() : (uint64)0; //some script commands doesn't have source
- uint64 targetGUID = target ? target->GetGUID() : (uint64)0;
- uint64 ownerGUID = (source->GetTypeId()==TYPEID_ITEM) ? ((Item*)source)->GetOwnerGUID() : (uint64)0;
-
- ///- Schedule script execution for all scripts in the script map
- ScriptMap const *s2 = &(s->second);
- bool immedScript = false;
- for (ScriptMap::const_iterator iter = s2->begin(); iter != s2->end(); ++iter)
- {
- ScriptAction sa;
- sa.sourceGUID = sourceGUID;
- sa.targetGUID = targetGUID;
- sa.ownerGUID = ownerGUID;
-
- sa.script = &iter->second;
- m_scriptSchedule.insert(std::pair<time_t, ScriptAction>(m_gameTime + iter->first, sa));
- if (iter->first == 0)
- immedScript = true;
- }
- ///- If one of the effects should be immediate, launch the script execution
- if (start && immedScript)
- ScriptsProcess();
-}
-
-void World::ScriptCommandStart(ScriptInfo const& script, uint32 delay, Object* source, Object* target)
-{
- // NOTE: script record _must_ exist until command executed
-
- // prepare static data
- uint64 sourceGUID = source ? source->GetGUID() : (uint64)0;
- uint64 targetGUID = target ? target->GetGUID() : (uint64)0;
- uint64 ownerGUID = (source->GetTypeId()==TYPEID_ITEM) ? ((Item*)source)->GetOwnerGUID() : (uint64)0;
-
- ScriptAction sa;
- sa.sourceGUID = sourceGUID;
- sa.targetGUID = targetGUID;
- sa.ownerGUID = ownerGUID;
-
- sa.script = &script;
- m_scriptSchedule.insert(std::pair<time_t, ScriptAction>(m_gameTime + delay, sa));
-
- ///- If effects should be immediate, launch the script execution
- if(delay == 0)
- ScriptsProcess();
-}
-
-/// Process queued scripts
-void World::ScriptsProcess()
-{
- if (m_scriptSchedule.empty())
- return;
-
- ///- Process overdue queued scripts
- std::multimap<time_t, ScriptAction>::iterator iter = m_scriptSchedule.begin();
- // ok as multimap is a *sorted* associative container
- while (!m_scriptSchedule.empty() && (iter->first <= m_gameTime))
- {
- ScriptAction const& step = iter->second;
-
- Object* source = NULL;
-
- if(step.sourceGUID)
- {
- switch(GUID_HIPART(step.sourceGUID))
- {
- case HIGHGUID_ITEM:
- // case HIGHGUID_CONTAINER: ==HIGHGUID_ITEM
- {
- Player* player = HashMapHolder<Player>::Find(step.ownerGUID);
- if(player)
- source = player->GetItemByGuid(step.sourceGUID);
- break;
- }
- case HIGHGUID_UNIT:
- source = HashMapHolder<Creature>::Find(step.sourceGUID);
- break;
- case HIGHGUID_PET:
- source = HashMapHolder<Pet>::Find(step.sourceGUID);
- break;
- case HIGHGUID_VEHICLE:
- source = HashMapHolder<Vehicle>::Find(step.sourceGUID);
- break;
- case HIGHGUID_PLAYER:
- source = HashMapHolder<Player>::Find(step.sourceGUID);
- break;
- case HIGHGUID_GAMEOBJECT:
- source = HashMapHolder<GameObject>::Find(step.sourceGUID);
- break;
- case HIGHGUID_CORPSE:
- source = HashMapHolder<Corpse>::Find(step.sourceGUID);
- break;
- case HIGHGUID_MO_TRANSPORT:
- for (MapManager::TransportSet::iterator iter = MapManager::Instance().m_Transports.begin(); iter != MapManager::Instance().m_Transports.end(); ++iter)
- {
- if((*iter)->GetGUID() == step.sourceGUID)
- {
- source = reinterpret_cast<Object*>(*iter);
- break;
- }
- }
- break;
- default:
- sLog.outError("*_script source with unsupported high guid value %u",GUID_HIPART(step.sourceGUID));
- break;
- }
- }
-
- //if(source && !source->IsInWorld()) source = NULL;
-
- Object* target = NULL;
-
- if(step.targetGUID)
- {
- switch(GUID_HIPART(step.targetGUID))
- {
- case HIGHGUID_UNIT:
- target = HashMapHolder<Creature>::Find(step.targetGUID);
- break;
- case HIGHGUID_PET:
- target = HashMapHolder<Pet>::Find(step.targetGUID);
- break;
- case HIGHGUID_VEHICLE:
- target = HashMapHolder<Vehicle>::Find(step.targetGUID);
- break;
- case HIGHGUID_PLAYER: // empty GUID case also
- target = HashMapHolder<Player>::Find(step.targetGUID);
- break;
- case HIGHGUID_GAMEOBJECT:
- target = HashMapHolder<GameObject>::Find(step.targetGUID);
- break;
- case HIGHGUID_CORPSE:
- target = HashMapHolder<Corpse>::Find(step.targetGUID);
- break;
- default:
- sLog.outError("*_script source with unsupported high guid value %u",GUID_HIPART(step.targetGUID));
- break;
- }
- }
-
- //if(target && !target->IsInWorld()) target = NULL;
-
- switch (step.script->command)
- {
- case SCRIPT_COMMAND_TALK:
- {
- if(!source)
- {
- sLog.outError("SCRIPT_COMMAND_TALK call for NULL creature.");
- break;
- }
-
- if(source->GetTypeId()!=TYPEID_UNIT)
- {
- sLog.outError("SCRIPT_COMMAND_TALK call for non-creature (TypeId: %u), skipping.",source->GetTypeId());
- break;
- }
- if(step.script->datalong > 3)
- {
- sLog.outError("SCRIPT_COMMAND_TALK invalid chat type (%u), skipping.",step.script->datalong);
- break;
- }
-
- uint64 unit_target = target ? target->GetGUID() : 0;
-
- //datalong 0=normal say, 1=whisper, 2=yell, 3=emote text
- switch(step.script->datalong)
- {
- case 0: // Say
- ((Creature *)source)->Say(step.script->dataint, LANG_UNIVERSAL, unit_target);
- break;
- case 1: // Whisper
- if(!unit_target)
- {
- sLog.outError("SCRIPT_COMMAND_TALK attempt to whisper (%u) NULL, skipping.",step.script->datalong);
- break;
- }
- ((Creature *)source)->Whisper(step.script->dataint,unit_target);
- break;
- case 2: // Yell
- ((Creature *)source)->Yell(step.script->dataint, LANG_UNIVERSAL, unit_target);
- break;
- case 3: // Emote text
- ((Creature *)source)->TextEmote(step.script->dataint, unit_target);
- break;
- default:
- break; // must be already checked at load
- }
- break;
- }
-
- case SCRIPT_COMMAND_EMOTE:
- if(!source)
- {
- sLog.outError("SCRIPT_COMMAND_EMOTE call for NULL creature.");
- break;
- }
-
- if(source->GetTypeId()!=TYPEID_UNIT)
- {
- sLog.outError("SCRIPT_COMMAND_EMOTE call for non-creature (TypeId: %u), skipping.",source->GetTypeId());
- break;
- }
-
- ((Creature *)source)->HandleEmoteCommand(step.script->datalong);
- break;
- case SCRIPT_COMMAND_FIELD_SET:
- if(!source)
- {
- sLog.outError("SCRIPT_COMMAND_FIELD_SET call for NULL object.");
- break;
- }
- if(step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= source->GetValuesCount())
- {
- sLog.outError("SCRIPT_COMMAND_FIELD_SET call for wrong field %u (max count: %u) in object (TypeId: %u).",
- step.script->datalong,source->GetValuesCount(),source->GetTypeId());
- break;
- }
-
- source->SetUInt32Value(step.script->datalong, step.script->datalong2);
- break;
- case SCRIPT_COMMAND_MOVE_TO:
- if(!source)
- {
- sLog.outError("SCRIPT_COMMAND_MOVE_TO call for NULL creature.");
- break;
- }
-
- if(source->GetTypeId()!=TYPEID_UNIT)
- {
- sLog.outError("SCRIPT_COMMAND_MOVE_TO call for non-creature (TypeId: %u), skipping.",source->GetTypeId());
- break;
- }
- ((Unit *)source)->SendMonsterMoveWithSpeed(step.script->x, step.script->y, step.script->z, step.script->datalong2 );
- ((Unit *)source)->GetMap()->CreatureRelocation(((Creature *)source), step.script->x, step.script->y, step.script->z, 0);
- break;
- case SCRIPT_COMMAND_FLAG_SET:
- if(!source)
- {
- sLog.outError("SCRIPT_COMMAND_FLAG_SET call for NULL object.");
- break;
- }
- if(step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= source->GetValuesCount())
- {
- sLog.outError("SCRIPT_COMMAND_FLAG_SET call for wrong field %u (max count: %u) in object (TypeId: %u).",
- step.script->datalong,source->GetValuesCount(),source->GetTypeId());
- break;
- }
-
- source->SetFlag(step.script->datalong, step.script->datalong2);
- break;
- case SCRIPT_COMMAND_FLAG_REMOVE:
- if(!source)
- {
- sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE call for NULL object.");
- break;
- }
- if(step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= source->GetValuesCount())
- {
- sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE call for wrong field %u (max count: %u) in object (TypeId: %u).",
- step.script->datalong,source->GetValuesCount(),source->GetTypeId());
- break;
- }
-
- source->RemoveFlag(step.script->datalong, step.script->datalong2);
- break;
-
- case SCRIPT_COMMAND_TELEPORT_TO:
- {
- // accept player in any one from target/source arg
- if (!target && !source)
- {
- sLog.outError("SCRIPT_COMMAND_TELEPORT_TO call for NULL object.");
- break;
- }
-
- // must be only Player
- if((!target || target->GetTypeId() != TYPEID_PLAYER) && (!source || source->GetTypeId() != TYPEID_PLAYER))
- {
- sLog.outError("SCRIPT_COMMAND_TELEPORT_TO call for non-player (TypeIdSource: %u)(TypeIdTarget: %u), skipping.", source ? source->GetTypeId() : 0, target ? target->GetTypeId() : 0);
- break;
- }
-
- Player* pSource = target && target->GetTypeId() == TYPEID_PLAYER ? (Player*)target : (Player*)source;
-
- pSource->TeleportTo(step.script->datalong, step.script->x, step.script->y, step.script->z, step.script->o);
- break;
- }
-
- case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE:
- {
- if(!step.script->datalong) // creature not specified
- {
- sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE call for NULL creature.");
- break;
- }
-
- if(!source)
- {
- sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE call for NULL world object.");
- break;
- }
-
- WorldObject* summoner = dynamic_cast<WorldObject*>(source);
-
- if(!summoner)
- {
- sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE call for non-WorldObject (TypeId: %u), skipping.",source->GetTypeId());
- break;
- }
-
- float x = step.script->x;
- float y = step.script->y;
- float z = step.script->z;
- float o = step.script->o;
-
- Creature* pCreature = summoner->SummonCreature(step.script->datalong, x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,step.script->datalong2);
- if (!pCreature)
- {
- sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON failed for creature (entry: %u).",step.script->datalong);
- break;
- }
-
- break;
- }
-
- case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT:
- {
- if(!step.script->datalong) // gameobject not specified
- {
- sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT call for NULL gameobject.");
- break;
- }
-
- if(!source)
- {
- sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT call for NULL world object.");
- break;
- }
-
- WorldObject* summoner = dynamic_cast<WorldObject*>(source);
-
- if(!summoner)
- {
- sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT call for non-WorldObject (TypeId: %u), skipping.",source->GetTypeId());
- break;
- }
-
- GameObject *go = NULL;
- int32 time_to_despawn = step.script->datalong2<5 ? 5 : (int32)step.script->datalong2;
-
- CellPair p(Trinity::ComputeCellPair(summoner->GetPositionX(), summoner->GetPositionY()));
- Cell cell(p);
- cell.data.Part.reserved = ALL_DISTRICT;
-
- MaNGOS::GameObjectWithDbGUIDCheck go_check(*summoner,step.script->datalong);
- MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck> checker(summoner, go,go_check);
-
- TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > object_checker(checker);
- CellLock<GridReadGuard> cell_lock(cell, p);
- cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(summoner->GetMapId(), summoner));
-
- if ( !go )
- {
- sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT failed for gameobject(guid: %u).", step.script->datalong);
- break;
- }
-
- if( go->GetGoType()==GAMEOBJECT_TYPE_FISHINGNODE ||
- go->GetGoType()==GAMEOBJECT_TYPE_DOOR ||
- go->GetGoType()==GAMEOBJECT_TYPE_BUTTON ||
- go->GetGoType()==GAMEOBJECT_TYPE_TRAP )
- {
- sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT can not be used with gameobject of type %u (guid: %u).", uint32(go->GetGoType()), step.script->datalong);
- break;
- }
-
- if( go->isSpawned() )
- break; //gameobject already spawned
-
- go->SetLootState(GO_READY);
- go->SetRespawnTime(time_to_despawn); //despawn object in ? seconds
-
- go->GetMap()->Add(go);
- break;
- }
- case SCRIPT_COMMAND_OPEN_DOOR:
- {
- if(!step.script->datalong) // door not specified
- {
- sLog.outError("SCRIPT_COMMAND_OPEN_DOOR call for NULL door.");
- break;
- }
-
- if(!source)
- {
- sLog.outError("SCRIPT_COMMAND_OPEN_DOOR call for NULL unit.");
- break;
- }
-
- if(!source->isType(TYPEMASK_UNIT)) // must be any Unit (creature or player)
- {
- sLog.outError("SCRIPT_COMMAND_OPEN_DOOR call for non-unit (TypeId: %u), skipping.",source->GetTypeId());
- break;
- }
-
- Unit* caster = (Unit*)source;
-
- GameObject *door = NULL;
- int32 time_to_close = step.script->datalong2 < 15 ? 15 : (int32)step.script->datalong2;
-
- CellPair p(Trinity::ComputeCellPair(caster->GetPositionX(), caster->GetPositionY()));
- Cell cell(p);
- cell.data.Part.reserved = ALL_DISTRICT;
-
- MaNGOS::GameObjectWithDbGUIDCheck go_check(*caster,step.script->datalong);
- MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck> checker(caster,door,go_check);
-
- TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > object_checker(checker);
- CellLock<GridReadGuard> cell_lock(cell, p);
- cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(caster->GetMapId(), (Unit*)source));
-
- if (!door)
- {
- sLog.outError("SCRIPT_COMMAND_OPEN_DOOR failed for gameobject(guid: %u).", step.script->datalong);
- break;
- }
- if (door->GetGoType() != GAMEOBJECT_TYPE_DOOR)
- {
- sLog.outError("SCRIPT_COMMAND_OPEN_DOOR failed for non-door(GoType: %u).", door->GetGoType());
- break;
- }
-
- if (door->GetGoState() != GO_STATE_READY)
- break; //door already open
-
- door->UseDoorOrButton(time_to_close);
-
- if(target && target->isType(TYPEMASK_GAMEOBJECT) && ((GameObject*)target)->GetGoType()==GAMEOBJECT_TYPE_BUTTON)
- ((GameObject*)target)->UseDoorOrButton(time_to_close);
- break;
- }
- case SCRIPT_COMMAND_CLOSE_DOOR:
- {
- if(!step.script->datalong) // guid for door not specified
- {
- sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR call for NULL door.");
- break;
- }
-
- if(!source)
- {
- sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR call for NULL unit.");
- break;
- }
-
- if(!source->isType(TYPEMASK_UNIT)) // must be any Unit (creature or player)
- {
- sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR call for non-unit (TypeId: %u), skipping.",source->GetTypeId());
- break;
- }
-
- Unit* caster = (Unit*)source;
-
- GameObject *door = NULL;
- int32 time_to_open = step.script->datalong2 < 15 ? 15 : (int32)step.script->datalong2;
-
- CellPair p(Trinity::ComputeCellPair(caster->GetPositionX(), caster->GetPositionY()));
- Cell cell(p);
- cell.data.Part.reserved = ALL_DISTRICT;
-
- MaNGOS::GameObjectWithDbGUIDCheck go_check(*caster,step.script->datalong);
- MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck> checker(caster,door,go_check);
-
- TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > object_checker(checker);
- CellLock<GridReadGuard> cell_lock(cell, p);
- cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(caster->GetMapId(), (Unit*)source));
-
- if ( !door )
- {
- sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR failed for gameobject(guid: %u).", step.script->datalong);
- break;
- }
- if ( door->GetGoType() != GAMEOBJECT_TYPE_DOOR )
- {
- sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR failed for non-door(GoType: %u).", door->GetGoType());
- break;
- }
-
- if( door->GetGoState() == GO_STATE_READY )
- break; //door already closed
-
- door->UseDoorOrButton(time_to_open);
-
- if(target && target->isType(TYPEMASK_GAMEOBJECT) && ((GameObject*)target)->GetGoType()==GAMEOBJECT_TYPE_BUTTON)
- ((GameObject*)target)->UseDoorOrButton(time_to_open);
-
- break;
- }
- case SCRIPT_COMMAND_QUEST_EXPLORED:
- {
- if(!source)
- {
- sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for NULL source.");
- break;
- }
-
- if(!target)
- {
- sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for NULL target.");
- break;
- }
-
- // when script called for item spell casting then target == (unit or GO) and source is player
- WorldObject* worldObject;
- Player* player;
-
- if(target->GetTypeId()==TYPEID_PLAYER)
- {
- if(source->GetTypeId()!=TYPEID_UNIT && source->GetTypeId()!=TYPEID_GAMEOBJECT)
- {
- sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for non-creature and non-gameobject (TypeId: %u), skipping.",source->GetTypeId());
- break;
- }
-
- worldObject = (WorldObject*)source;
- player = (Player*)target;
- }
- else
- {
- if(target->GetTypeId()!=TYPEID_UNIT && target->GetTypeId()!=TYPEID_GAMEOBJECT)
- {
- sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for non-creature and non-gameobject (TypeId: %u), skipping.",target->GetTypeId());
- break;
- }
-
- if(source->GetTypeId()!=TYPEID_PLAYER)
- {
- sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for non-player(TypeId: %u), skipping.",source->GetTypeId());
- break;
- }
-
- worldObject = (WorldObject*)target;
- player = (Player*)source;
- }
-
- // quest id and flags checked at script loading
- if( (worldObject->GetTypeId()!=TYPEID_UNIT || ((Unit*)worldObject)->isAlive()) &&
- (step.script->datalong2==0 || worldObject->IsWithinDistInMap(player,float(step.script->datalong2))) )
- player->AreaExploredOrEventHappens(step.script->datalong);
- else
- player->FailQuest(step.script->datalong);
-
- break;
- }
-
- case SCRIPT_COMMAND_ACTIVATE_OBJECT:
- {
- if(!source)
- {
- sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT must have source caster.");
- break;
- }
-
- if(!source->isType(TYPEMASK_UNIT))
- {
- sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT source caster isn't unit (TypeId: %u), skipping.",source->GetTypeId());
- break;
- }
-
- if(!target)
- {
- sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT call for NULL gameobject.");
- break;
- }
-
- if(target->GetTypeId()!=TYPEID_GAMEOBJECT)
- {
- sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT call for non-gameobject (TypeId: %u), skipping.",target->GetTypeId());
- break;
- }
-
- Unit* caster = (Unit*)source;
-
- GameObject *go = (GameObject*)target;
-
- go->Use(caster);
- break;
- }
-
- case SCRIPT_COMMAND_REMOVE_AURA:
- {
- Object* cmdTarget = step.script->datalong2 ? source : target;
-
- if(!cmdTarget)
- {
- sLog.outError("SCRIPT_COMMAND_REMOVE_AURA call for NULL %s.",step.script->datalong2 ? "source" : "target");
- break;
- }
-
- if(!cmdTarget->isType(TYPEMASK_UNIT))
- {
- sLog.outError("SCRIPT_COMMAND_REMOVE_AURA %s isn't unit (TypeId: %u), skipping.",step.script->datalong2 ? "source" : "target",cmdTarget->GetTypeId());
- break;
- }
-
- ((Unit*)cmdTarget)->RemoveAurasDueToSpell(step.script->datalong);
- break;
- }
-
- case SCRIPT_COMMAND_CAST_SPELL:
- {
- if(!source)
- {
- sLog.outError("SCRIPT_COMMAND_CAST_SPELL must have source caster.");
- break;
- }
-
- Object* cmdTarget = step.script->datalong2 & 0x01 ? source : target;
-
- if(!cmdTarget)
- {
- sLog.outError("SCRIPT_COMMAND_CAST_SPELL call for NULL %s.",step.script->datalong2 & 0x01 ? "source" : "target");
- break;
- }
-
- if(!cmdTarget->isType(TYPEMASK_UNIT))
- {
- sLog.outError("SCRIPT_COMMAND_CAST_SPELL %s isn't unit (TypeId: %u), skipping.",step.script->datalong2 & 0x01 ? "source" : "target",cmdTarget->GetTypeId());
- break;
- }
-
- Unit* spellTarget = (Unit*)cmdTarget;
-
- Object* cmdSource = step.script->datalong2 & 0x02 ? target : source;
-
- if(!cmdSource)
- {
- sLog.outError("SCRIPT_COMMAND_CAST_SPELL call for NULL %s.",step.script->datalong2 & 0x02 ? "target" : "source");
- break;
- }
-
- if(!cmdSource->isType(TYPEMASK_UNIT))
- {
- sLog.outError("SCRIPT_COMMAND_CAST_SPELL %s isn't unit (TypeId: %u), skipping.",step.script->datalong2 & 0x02 ? "target" : "source", cmdSource->GetTypeId());
- break;
- }
-
- Unit* spellSource = (Unit*)cmdSource;
-
- //TODO: when GO cast implemented, code below must be updated accordingly to also allow GO spell cast
- spellSource->CastSpell(spellTarget,step.script->datalong,false);
-
- break;
- }
-
- case SCRIPT_COMMAND_LOAD_PATH:
- {
- if(!source)
- {
- sLog.outError("SCRIPT_COMMAND_START_MOVE is tried to apply to NON-existing unit.");
- break;
- }
-
- if(!source->isType(TYPEMASK_UNIT))
- {
- sLog.outError("SCRIPT_COMMAND_START_MOVE source mover isn't unit (TypeId: %u), skipping.",source->GetTypeId());
- break;
- }
-
- if(!WaypointMgr.GetPath(step.script->datalong))
- {
- sLog.outError("SCRIPT_COMMAND_START_MOVE source mover has an invallid path, skipping.", step.script->datalong2);
- break;
- }
-
- dynamic_cast<Unit*>(source)->GetMotionMaster()->MovePath(step.script->datalong, step.script->datalong2);
- break;
- }
-
- case SCRIPT_COMMAND_CALLSCRIPT_TO_UNIT:
- {
- if(!step.script->datalong || !step.script->datalong2)
- {
- sLog.outError("SCRIPT_COMMAND_CALLSCRIPT calls invallid db_script_id or lowguid not present: skipping.");
- break;
- }
- //our target
- Creature* target = NULL;
-
- if(source) //using grid searcher
- {
- CellPair p(Trinity::ComputeCellPair(((Unit*)source)->GetPositionX(), ((Unit*)source)->GetPositionY()));
- Cell cell(p);
- cell.data.Part.reserved = ALL_DISTRICT;
-
- //sLog.outDebug("Attempting to find Creature: Db GUID: %i", step.script->datalong);
- Trinity::CreatureWithDbGUIDCheck target_check(((Unit*)source), step.script->datalong);
- Trinity::CreatureSearcher<Trinity::CreatureWithDbGUIDCheck> checker(((Unit*)source), target, target_check);
-
- TypeContainerVisitor<Trinity::CreatureSearcher <Trinity::CreatureWithDbGUIDCheck>, GridTypeMapContainer > unit_checker(checker);
- CellLock<GridReadGuard> cell_lock(cell, p);
- cell_lock->Visit(cell_lock, unit_checker, *(((Unit*)source)->GetMap()));
- }
- else //check hashmap holders
- {
- if(CreatureData const* data = objmgr.GetCreatureData(step.script->datalong))
- target = ObjectAccessor::GetObjectInWorld<Creature>(data->mapid, data->posX, data->posY, MAKE_NEW_GUID(step.script->datalong, data->id, HIGHGUID_UNIT), target);
- }
- //sLog.outDebug("attempting to pass target...");
- if(!target)
- break;
- //sLog.outDebug("target passed");
- //Lets choose our ScriptMap map
- ScriptMapMap *datamap = NULL;
- switch(step.script->dataint)
- {
- case 1://QUEST END SCRIPTMAP
- datamap = &sQuestEndScripts;
- break;
- case 2://QUEST START SCRIPTMAP
- datamap = &sQuestStartScripts;
- break;
- case 3://SPELLS SCRIPTMAP
- datamap = &sSpellScripts;
- break;
- case 4://GAMEOBJECTS SCRIPTMAP
- datamap = &sGameObjectScripts;
- break;
- case 5://EVENTS SCRIPTMAP
- datamap = &sEventScripts;
- break;
- case 6://WAYPOINTS SCRIPTMAP
- datamap = &sWaypointScripts;
- break;
- default:
- sLog.outError("SCRIPT_COMMAND_CALLSCRIPT ERROR: no scriptmap present... ignoring");
- break;
- }
- //if no scriptmap present...
- if(!datamap)
- break;
-
- uint32 script_id = step.script->datalong2;
- //insert script into schedule but do not start it
- ScriptsStart(*datamap, script_id, target, NULL, false);
- break;
- }
-
- case SCRIPT_COMMAND_KILL:
- {
- if(!source || ((Creature*)source)->isDead())
- break;
-
- ((Creature*)source)->DealDamage(((Creature*)source), ((Creature*)source)->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
-
- switch(step.script->dataint)
- {
- case 0: break; //return false not remove corpse
- case 1: ((Creature*)source)->RemoveCorpse(); break;
- }
- break;
- }
-
- case SCRIPT_COMMAND_PLAY_SOUND:
- {
- if(!source)
- {
- sLog.outError("SCRIPT_COMMAND_PLAY_SOUND call for NULL creature.");
- break;
- }
-
- WorldObject* pSource = dynamic_cast<WorldObject*>(source);
- if(!pSource)
- {
- sLog.outError("SCRIPT_COMMAND_PLAY_SOUND call for non-world object (TypeId: %u), skipping.",source->GetTypeId());
- break;
- }
-
- // bitmask: 0/1=anyone/target, 0/2=with distance dependent
- Player* pTarget = NULL;
- if(step.script->datalong2 & 1)
- {
- if(!target)
- {
- sLog.outError("SCRIPT_COMMAND_PLAY_SOUND in targeted mode call for NULL target.");
- break;
- }
-
- if(target->GetTypeId()!=TYPEID_PLAYER)
- {
- sLog.outError("SCRIPT_COMMAND_PLAY_SOUND in targeted mode call for non-player (TypeId: %u), skipping.",target->GetTypeId());
- break;
- }
-
- pTarget = (Player*)target;
- }
-
- // bitmask: 0/1=anyone/target, 0/2=with distance dependent
- if(step.script->datalong2 & 2)
- pSource->PlayDistanceSound(step.script->datalong,pTarget);
- else
- pSource->PlayDirectSound(step.script->datalong,pTarget);
- break;
- }
- default:
- sLog.outError("Unknown script command %u called.",step.script->command);
- break;
- }
-
- m_scriptSchedule.erase(iter);
-
- iter = m_scriptSchedule.begin();
- }
- return;
-}
-
/// Send a packet to all players (except self if mentioned)
void World::SendGlobalMessage(WorldPacket *packet, WorldSession *self, uint32 team)
{
@@ -2851,10 +2066,10 @@ void World::KickAllLess(AccountTypes sec)
/// Ban an account or ban an IP address, duration will be parsed using TimeStringToSecs if it is positive, otherwise permban
BanReturn World::BanAccount(BanMode mode, std::string nameOrIP, std::string duration, std::string reason, std::string author)
{
- LoginDatabase.escape_string(nameOrIP);
- LoginDatabase.escape_string(reason);
+ loginDatabase.escape_string(nameOrIP);
+ loginDatabase.escape_string(reason);
std::string safe_author=author;
- LoginDatabase.escape_string(safe_author);
+ loginDatabase.escape_string(safe_author);
uint32 duration_secs = TimeStringToSecs(duration);
QueryResult *resultAccounts = NULL; //used for kicking
@@ -2864,12 +2079,12 @@ BanReturn World::BanAccount(BanMode mode, std::string nameOrIP, std::string dura
{
case BAN_IP:
//No SQL injection as strings are escaped
- resultAccounts = LoginDatabase.PQuery("SELECT id FROM account WHERE last_ip = '%s'",nameOrIP.c_str());
- LoginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+%u,'%s','%s')",nameOrIP.c_str(),duration_secs,safe_author.c_str(),reason.c_str());
+ resultAccounts = loginDatabase.PQuery("SELECT id FROM account WHERE last_ip = '%s'",nameOrIP.c_str());
+ loginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+%u,'%s','%s')",nameOrIP.c_str(),duration_secs,safe_author.c_str(),reason.c_str());
break;
case BAN_ACCOUNT:
//No SQL injection as string is escaped
- resultAccounts = LoginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'",nameOrIP.c_str());
+ resultAccounts = loginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'",nameOrIP.c_str());
break;
case BAN_CHARACTER:
//No SQL injection as string is escaped
@@ -2896,7 +2111,7 @@ BanReturn World::BanAccount(BanMode mode, std::string nameOrIP, std::string dura
if(mode!=BAN_IP)
{
//No SQL injection as strings are escaped
- LoginDatabase.PExecute("INSERT INTO account_banned VALUES ('%u', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+%u, '%s', '%s', '1')",
+ loginDatabase.PExecute("INSERT INTO account_banned VALUES ('%u', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+%u, '%s', '%s', '1')",
account,duration_secs,safe_author.c_str(),reason.c_str());
}
@@ -2915,8 +2130,8 @@ bool World::RemoveBanAccount(BanMode mode, std::string nameOrIP)
{
if (mode == BAN_IP)
{
- LoginDatabase.escape_string(nameOrIP);
- LoginDatabase.PExecute("DELETE FROM ip_banned WHERE ip = '%s'",nameOrIP.c_str());
+ loginDatabase.escape_string(nameOrIP);
+ loginDatabase.PExecute("DELETE FROM ip_banned WHERE ip = '%s'",nameOrIP.c_str());
}
else
{
@@ -2930,7 +2145,7 @@ bool World::RemoveBanAccount(BanMode mode, std::string nameOrIP)
return false;
//NO SQL injection as account is uint32
- LoginDatabase.PExecute("UPDATE account_banned SET active = '0' WHERE id = '%u'",account);
+ loginDatabase.PExecute("UPDATE account_banned SET active = '0' WHERE id = '%u'",account);
}
return true;
}
@@ -3104,6 +2319,45 @@ void World::ProcessCliCommands()
zprint("TC> ");
}
+void World::SendRNDBroadcast()
+{
+ std::string msg;
+ QueryResult *result = WorldDatabase.PQuery("SELECT `text` FROM autobroadcast AS r1 JOIN (SELECT ROUND(RAND() * (SELECT MAX(id) FROM autobroadcast)) AS id) AS r2 WHERE r1.id >= r2.id ORDER BY r1.id ASC LIMIT 1"); // ORDER BY RAND() is bad.. look it up to see why.
+
+ if(!result)
+ return;
+
+ msg = result->Fetch()[0].GetString();
+ delete result;
+
+ static uint32 abcenter = 0;
+ abcenter = sConfig.GetIntDefault("AutoBroadcast.Center", 0);
+ if(abcenter == 0)
+ {
+ sWorld.SendWorldText(LANG_AUTO_BROADCAST, msg.c_str());
+
+ sLog.outString("AutoBroadcast: '%s'",msg.c_str());
+ }
+ if(abcenter == 1)
+ {
+ WorldPacket data(SMSG_NOTIFICATION, (msg.size()+1));
+ data << msg;
+ sWorld.SendGlobalMessage(&data);
+
+ sLog.outString("AutoBroadcast: '%s'",msg.c_str());
+ }
+ if(abcenter == 2)
+ {
+ sWorld.SendWorldText(LANG_AUTO_BROADCAST, msg.c_str());
+
+ WorldPacket data(SMSG_NOTIFICATION, (msg.size()+1));
+ data << msg;
+ sWorld.SendGlobalMessage(&data);
+
+ sLog.outString("AutoBroadcast: '%s'",msg.c_str());
+ }
+}
+
void World::InitResultQueue()
{
m_resultQueue = new SqlResultQueue;
@@ -3128,8 +2382,8 @@ void World::_UpdateRealmCharCount(QueryResult *resultCharCount, uint32 accountId
Field *fields = resultCharCount->Fetch();
uint32 charCount = fields[0].GetUInt32();
delete resultCharCount;
- LoginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid= '%d' AND realmid = '%d'", accountId, realmID);
- LoginDatabase.PExecute("INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (%u, %u, %u)", charCount, accountId, realmID);
+ loginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid= '%d' AND realmid = '%d'", accountId, realmID);
+ loginDatabase.PExecute("INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (%u, %u, %u)", charCount, accountId, realmID);
}
}
@@ -3192,7 +2446,7 @@ void World::SetPlayerLimit( int32 limit, bool needUpdate )
m_playerLimit = limit;
if(db_update_need)
- LoginDatabase.PExecute("UPDATE realmlist SET allowedSecurityLevel = '%u' WHERE id = '%d'",uint8(GetPlayerSecurityLimit()),realmID);
+ loginDatabase.PExecute("UPDATE realmlist SET allowedSecurityLevel = '%u' WHERE id = '%d'",uint8(GetPlayerSecurityLimit()),realmID);
}
void World::UpdateMaxSessionCounters()
@@ -3203,14 +2457,14 @@ void World::UpdateMaxSessionCounters()
void World::LoadDBVersion()
{
- QueryResult* result = WorldDatabase.Query("SELECT db_version FROM version LIMIT 1");
+ QueryResult* result = WorldDatabase.Query("SELECT db_version, script_version FROM version LIMIT 1");
//QueryResult* result = WorldDatabase.Query("SELECT version, creature_ai_version FROM db_version LIMIT 1");
if(result)
{
Field* fields = result->Fetch();
m_DBVersion = fields[0].GetCppString();
- //m_CreatureEventAIVersion = fields[1].GetCppString();
+ m_CreatureEventAIVersion = fields[1].GetCppString();
delete result;
}
diff --git a/src/game/World.h b/src/game/World.h
index 4fbde8ccb71..0bd2abb4c9b 100644
--- a/src/game/World.h
+++ b/src/game/World.h
@@ -29,6 +29,7 @@
#include "Timer.h"
#include "Policies/Singleton.h"
#include "SharedDefines.h"
+#include "ace/Atomic_Op.h"
#include <map>
#include <set>
@@ -79,7 +80,8 @@ enum WorldTimers
WUPDATE_CORPSES = 5,
WUPDATE_EVENTS = 6,
WUPDATE_CLEANDB = 7,
- WUPDATE_COUNT = 8
+ WUPDATE_AUTOBROADCAST = 8,
+ WUPDATE_COUNT = 9
};
/// Configuration elements
@@ -112,6 +114,9 @@ enum WorldConfigs
CONFIG_STRICT_PLAYER_NAMES,
CONFIG_STRICT_CHARTER_NAMES,
CONFIG_STRICT_PET_NAMES,
+ CONFIG_MIN_PLAYER_NAME,
+ CONFIG_MIN_CHARTER_NAME,
+ CONFIG_MIN_PET_NAME,
CONFIG_CHARACTERS_CREATING_DISABLED,
CONFIG_CHARACTERS_PER_ACCOUNT,
CONFIG_CHARACTERS_PER_REALM,
@@ -138,8 +143,8 @@ enum WorldConfigs
CONFIG_GM_ACCEPT_TICKETS,
CONFIG_GM_CHAT,
CONFIG_GM_WISPERING_TO,
- CONFIG_GM_IN_GM_LIST,
- CONFIG_GM_IN_WHO_LIST,
+ CONFIG_GM_LEVEL_IN_GM_LIST,
+ CONFIG_GM_LEVEL_IN_WHO_LIST,
CONFIG_GM_LOG_TRADE,
CONFIG_START_GM_LEVEL,
CONFIG_ALLOW_GM_GROUP,
@@ -160,6 +165,7 @@ enum WorldConfigs
CONFIG_SKILL_GAIN_DEFENSE,
CONFIG_SKILL_GAIN_GATHERING,
CONFIG_SKILL_GAIN_WEAPON,
+ CONFIG_DURABILITY_LOSS_IN_PVP,
CONFIG_MAX_OVERSPEED_PINGS,
CONFIG_SAVE_RESPAWN_TIME_IMMEDIATELY,
CONFIG_ALWAYS_MAX_SKILL_FOR_LEVEL,
@@ -275,6 +281,7 @@ enum Rates
RATE_XP_KILL,
RATE_XP_QUEST,
RATE_XP_EXPLORE,
+ RATE_REPAIRCOST,
RATE_REPUTATION_GAIN,
RATE_REPUTATION_LOWLEVEL_KILL,
RATE_REPUTATION_LOWLEVEL_QUEST,
@@ -308,6 +315,7 @@ enum Rates
RATE_CORPSE_DECAY_LOOTED,
RATE_INSTANCE_RESET_TIME,
RATE_TARGET_POS_RECALCULATION_RANGE,
+ RATE_DURABILITY_LOSS_ON_DEATH,
RATE_DURABILITY_LOSS_DAMAGE,
RATE_DURABILITY_LOSS_PARRY,
RATE_DURABILITY_LOSS_ABSORB,
@@ -412,6 +420,7 @@ class World
WorldSession* FindSession(uint32 id) const;
void AddSession(WorldSession *s);
+ void SendRNDBroadcast();
bool RemoveSession(uint32 id);
/// Get the number of current active sessions
void UpdateMaxSessionCounters();
@@ -421,8 +430,18 @@ class World
/// Get the maximum number of parallel sessions on the server since last reboot
uint32 GetMaxQueuedSessionCount() const { return m_maxQueuedSessionCount; }
uint32 GetMaxActiveSessionCount() const { return m_maxActiveSessionCount; }
- Player* FindPlayerInZone(uint32 zone);
+ /// Get number of players
+ inline uint32 GetPlayerCount() const { return m_PlayerCount; }
+ inline uint32 GetMaxPlayerCount() const { return m_MaxPlayerCount; }
+ /// Increase/Decrease number of players
+ inline void IncreasePlayerCount()
+ {
+ m_PlayerCount++;
+ m_MaxPlayerCount = std::max(m_MaxPlayerCount, m_PlayerCount);
+ }
+ inline void DecreasePlayerCount() { m_PlayerCount--; }
+ Player* FindPlayerInZone(uint32 zone);
Weather* FindWeather(uint32 id) const;
Weather* AddWeather(uint32 zone_id);
void RemoveWeather(uint32 zone_id);
@@ -540,9 +559,10 @@ class World
BanReturn BanAccount(BanMode mode, std::string nameOrIP, std::string duration, std::string reason, std::string author);
bool RemoveBanAccount(BanMode mode, std::string nameOrIP);
- void ScriptsStart(std::map<uint32, std::multimap<uint32, ScriptInfo> > const& scripts, uint32 id, Object* source, Object* target, bool start = true);
- void ScriptCommandStart(ScriptInfo const& script, uint32 delay, Object* source, Object* target);
- bool IsScriptScheduled() const { return !m_scriptSchedule.empty(); }
+ uint32 IncreaseScheduledScriptsCount() { return (uint32)++m_scheduledScripts; }
+ uint32 DecreaseScheduledScriptCount() { return (uint32)--m_scheduledScripts; }
+ uint32 DecreaseScheduledScriptCount(size_t count) { return (uint32)(m_scheduledScripts -= count); }
+ bool IsScriptScheduled() const { return m_scheduledScripts > 0; }
bool IsAllowedMap(uint32 mapid) { return m_forbiddenMapIds.count(mapid) == 0 ;}
@@ -579,7 +599,6 @@ class World
void RecordTimeDiff(const char * text, ...);
protected:
void _UpdateGameTime();
- void ScriptsProcess();
// callback for UpdateRealmCharacters
void _UpdateRealmCharCount(QueryResult *resultCharCount, uint32 accountId);
@@ -593,6 +612,9 @@ class World
bool m_isClosed;
+ //atomic op counter for active scripts amount
+ ACE_Atomic_Op<ACE_Thread_Mutex, long> m_scheduledScripts;
+
time_t m_startTime;
time_t m_gameTime;
IntervalTimer m_timers[WUPDATE_COUNT];
@@ -610,8 +632,8 @@ class World
DisconnectMap m_disconnects;
uint32 m_maxActiveSessionCount;
uint32 m_maxQueuedSessionCount;
-
- std::multimap<time_t, ScriptAction> m_scriptSchedule;
+ uint32 m_PlayerCount;
+ uint32 m_MaxPlayerCount;
std::string m_newCharString;
diff --git a/src/game/WorldSession.cpp b/src/game/WorldSession.cpp
index 44bab655886..3b32eefcda7 100644
--- a/src/game/WorldSession.cpp
+++ b/src/game/WorldSession.cpp
@@ -53,6 +53,7 @@ m_latency(0), m_TutorialsChanged(false)
{
m_Address = sock->GetRemoteAddress ();
sock->AddReference ();
+ loginDatabase.PExecute("UPDATE account SET online = 1 WHERE id = %u;", GetAccountId());
}
}
@@ -77,11 +78,13 @@ WorldSession::~WorldSession()
WorldPacket *packet = _recvQueue.next ();
delete packet;
}
+ loginDatabase.PExecute("UPDATE account SET online = 0 WHERE id = %u;", GetAccountId());
+ CharacterDatabase.PExecute("UPDATE characters SET online = 0 WHERE account = %u;", GetAccountId());
}
void WorldSession::SizeError(WorldPacket const& packet, uint32 size) const
{
- sLog.outError("Client (account %u) send packet %s (%u) with size %u but expected %u (attempt crash server?), skipped",
+ sLog.outError("Client (account %u) send packet %s (%u) with size " SIZEFMTD " but expected %u (attempt crash server?), skipped",
GetAccountId(),LookupOpcodeName(packet.GetOpcode()),packet.GetOpcode(),packet.size(),size);
}
@@ -323,10 +326,10 @@ void WorldSession::LogoutPlayer(bool Save)
}
}
- ///- Reset the online field in the account table
- // no point resetting online in character table here as Player::SaveToDB() will set it to 1 since player has not been removed from world at this stage
- //No SQL injection as AccountID is uint32
- LoginDatabase.PExecute("UPDATE account SET online = 0 WHERE id = '%u'", GetAccountId());
+ // Repop at GraveYard or other player far teleport will prevent saving player because of not present map
+ // Teleport player immediately for correct player save
+ while(_player->IsBeingTeleportedFar())
+ HandleMoveWorldportAckOpcode();
///- If the player is in a guild, update the guild roster and broadcast a logout message to other guild members
Guild *guild = objmgr.GetGuildById(_player->GetGuildId());
@@ -380,19 +383,13 @@ void WorldSession::LogoutPlayer(bool Save)
sSocialMgr.SendFriendStatus(_player, FRIEND_OFFLINE, _player->GetGUIDLow(), true);
sSocialMgr.RemovePlayerSocial (_player->GetGUIDLow ());
- ///- Delete the player object
- _player->CleanupsBeforeDelete(); // do some cleanup before deleting to prevent crash at crossreferences to already deleted data
-
///- Remove the player from the world
// the player may not be in the world when logging out
// e.g if he got disconnected during a transfer to another map
// calls to GetMap in this case may cause crashes
- if(_player->IsInWorld()) _player->GetMap()->Remove(_player, false);
- // RemoveFromWorld does cleanup that requires the player to be in the accessor
- ObjectAccessor::Instance().RemoveObject(_player);
-
- delete _player;
- _player = NULL;
+ Map* _map = _player->GetMap();
+ _map->Remove(_player, true);
+ _player = NULL; // deleted in Remove call
///- Send the 'logout complete' packet to the client
WorldPacket data( SMSG_LOGOUT_COMPLETE, 0 );
diff --git a/src/game/WorldSession.h b/src/game/WorldSession.h
index f4842c0f0bc..22ab100197c 100644
--- a/src/game/WorldSession.h
+++ b/src/game/WorldSession.h
@@ -711,6 +711,7 @@ class TRINITY_DLL_SPEC WorldSession
void HandleCalendarGetNumPending(WorldPacket& recv_data);
void HandleSpellClick(WorldPacket& recv_data);
+ void HandleMirrrorImageDataRequest( WorldPacket & recv_data );
void HandleAlterAppearance(WorldPacket& recv_data);
void HandleRemoveGlyph(WorldPacket& recv_data);
void HandleCharCustomize(WorldPacket& recv_data);
diff --git a/src/game/WorldSocket.cpp b/src/game/WorldSocket.cpp
index 440eeb31790..0efb0cd3d4e 100644
--- a/src/game/WorldSocket.cpp
+++ b/src/game/WorldSocket.cpp
@@ -678,7 +678,7 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
BigNumber K;
- if (recvPacket.size () < (4 + 4 + 1 + 4 + 20))
+ if (recvPacket.size () < (4 + 4 + 1 + 4 + 4 + 20))
{
sLog.outError ("WorldSocket::HandleAuthSession: wrong packet size");
return -1;
@@ -700,7 +700,7 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
recvPacket >> account;
recvPacket >> unk3;
- if (recvPacket.size () < (4 + 4 + (account.size () + 1) + 4 + 20))
+ if (recvPacket.size () < (4 + 4 + (account.size () + 1) + 4 + 4 + 20))
{
sLog.outError ("WorldSocket::HandleAuthSession: wrong packet size second check");
return -1;
@@ -709,19 +709,20 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
recvPacket >> clientSeed;
recvPacket.read (digest, 20);
- DEBUG_LOG ("WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, clientseed %u",
+ DEBUG_LOG ("WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, unk3 %u, clientseed %u",
BuiltNumberClient,
unk2,
account.c_str (),
+ unk3,
clientSeed);
// Get the account information from the realmd database
std::string safe_account = account; // Duplicate, else will screw the SHA hash verification below
- LoginDatabase.escape_string (safe_account);
+ loginDatabase.escape_string (safe_account);
// No SQL injection, username escaped.
QueryResult *result =
- LoginDatabase.PQuery ("SELECT "
+ loginDatabase.PQuery ("SELECT "
"id, " //0
"gmlevel, " //1
"sessionkey, " //2
@@ -786,7 +787,7 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
vold,
vStr);
- LoginDatabase.PExecute ("UPDATE account "
+ loginDatabase.PExecute ("UPDATE account "
"SET "
"v = '0', "
"s = '0' "
@@ -843,7 +844,7 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
// Re-check account ban (same check as in realmd)
QueryResult *banresult =
- LoginDatabase.PQuery ("SELECT "
+ loginDatabase.PQuery ("SELECT "
"bandate, "
"unbandate "
"FROM account_banned "
@@ -909,9 +910,9 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
// Update the last_ip in the database
// No SQL injection, username escaped.
- LoginDatabase.escape_string (address);
+ loginDatabase.escape_string (address);
- LoginDatabase.PExecute ("UPDATE account "
+ loginDatabase.PExecute ("UPDATE account "
"SET last_ip = '%s' "
"WHERE username = '%s'",
address.c_str (),
diff --git a/src/game/pchdef.h b/src/game/pchdef.h
index 4b5b9dfbe3e..7252e980e7d 100644
--- a/src/game/pchdef.h
+++ b/src/game/pchdef.h
@@ -9,8 +9,4 @@
#include "Database/SQLStorage.h"
#include "Opcodes.h"
#include "SharedDefines.h"
-
-#ifdef FASTBUILD
-//add additional headers here to speed up compilation in release builds even more
#include "ObjectMgr.h"
-#endif \ No newline at end of file