Merge commit 'origin/master' into 320

This commit is contained in:
tomrus88 2009-07-08 22:08:09 +04:00
commit 87930a6d07
35 changed files with 719 additions and 467 deletions

View file

@ -20,19 +20,8 @@
SUBDIRS = dep doc sql src SUBDIRS = dep doc sql src
## Additional files to include when running 'make dist' ## Additional files to include when running 'make dist'
# Win32 project workspace for Visual Studio .NET 2003
EXTRA_DIST = \
win/mangosdVC71.sln \
win/VC71/framework.vcproj \
win/VC71/game.vcproj \
win/VC71/mangosd.vcproj \
win/VC71/realmd.vcproj \
win/VC71/shared.vcproj \
win/VC71/zlib.vcproj \
win/VC71/g3dlite.vcproj
# Win32 project workspace for Visual Studio .NET 2005 # Win32 project workspace for Visual Studio .NET 2005
EXTRA_DIST += \ EXTRA_DIST = \
win/mangosdVC80.sln \ win/mangosdVC80.sln \
win/VC80/framework.vcproj \ win/VC80/framework.vcproj \
win/VC80/game.vcproj \ win/VC80/game.vcproj \
@ -53,3 +42,14 @@ EXTRA_DIST += \
win/VC90/zlib.vcproj \ win/VC90/zlib.vcproj \
win/VC90/g3dlite.vcproj win/VC90/g3dlite.vcproj
# Win32 project workspace for Visual Studio .NET 2010
EXTRA_DIST += \
win/mangosdVC100.sln \
win/VC100/framework.vcxproj \
win/VC100/game.vcxproj \
win/VC100/mangosd.vcxproj \
win/VC100/realmd.vcxproj \
win/VC100/shared.vcxproj \
win/VC100/zlib.vcxproj \
win/VC100/g3dlite.vcxproj

View file

@ -23,7 +23,7 @@ DROP TABLE IF EXISTS `db_version`;
CREATE TABLE `db_version` ( CREATE TABLE `db_version` (
`version` varchar(120) default NULL, `version` varchar(120) default NULL,
`creature_ai_version` varchar(120) default NULL, `creature_ai_version` varchar(120) default NULL,
`required_8115_01_mangos_playercreateinfo_action` bit(1) default NULL `required_8140_01_mangos_spell_proc_event` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes';
-- --
@ -17123,9 +17123,9 @@ INSERT INTO `spell_proc_event` VALUES
(31836, 0x00000000, 10, 0x80000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0), (31836, 0x00000000, 10, 0x80000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(31871, 0x00000000, 10, 0x00000010, 0x00000000, 0x00000000, 0x00004000, 0x00000000, 0.000000, 0.000000, 0), (31871, 0x00000000, 10, 0x00000010, 0x00000000, 0x00000000, 0x00004000, 0x00000000, 0.000000, 0.000000, 0),
(31872, 0x00000000, 10, 0x00000010, 0x00000000, 0x00000000, 0x00004000, 0x00000000, 0.000000, 0.000000, 0), (31872, 0x00000000, 10, 0x00000010, 0x00000000, 0x00000000, 0x00004000, 0x00000000, 0.000000, 0.000000, 0),
(31876, 0x00000000, 10, 0x00800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0), (31876, 0x00000000, 10, 0x00800000, 0x00000000, 0x00000008, 0x00004110, 0x00000000, 0.000000, 0.000000, 0),
(31877, 0x00000000, 10, 0x00800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0), (31877, 0x00000000, 10, 0x00800000, 0x00000000, 0x00000008, 0x00004110, 0x00000000, 0.000000, 0.000000, 0),
(31878, 0x00000000, 10, 0x00800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0), (31878, 0x00000000, 10, 0x00800000, 0x00000000, 0x00000008, 0x00004110, 0x00000000, 0.000000, 0.000000, 0),
(31904, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000040, 0.000000, 0.000000, 0), (31904, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000040, 0.000000, 0.000000, 0),
(32385, 0x00000000, 5, 0x00000402, 0x00000011, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0), (32385, 0x00000000, 5, 0x00000402, 0x00000011, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(32387, 0x00000000, 5, 0x00000402, 0x00000011, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0), (32387, 0x00000000, 5, 0x00000402, 0x00000011, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),

View file

@ -0,0 +1,7 @@
ALTER TABLE db_version CHANGE COLUMN required_8115_01_mangos_playercreateinfo_action required_8140_01_mangos_spell_proc_event bit;
DELETE FROM spell_proc_event WHERE entry IN (31876, 31877, 31878);
INSERT INTO spell_proc_event VALUES
(31876, 0x00000000, 10, 0x00800000, 0x00000000, 0x00000008, 0x00004110, 0x00000000, 0.000000, 0.000000, 0),
(31877, 0x00000000, 10, 0x00800000, 0x00000000, 0x00000008, 0x00004110, 0x00000000, 0.000000, 0.000000, 0),
(31878, 0x00000000, 10, 0x00800000, 0x00000000, 0x00000008, 0x00004110, 0x00000000, 0.000000, 0.000000, 0);

View file

@ -242,6 +242,7 @@ pkgdata_DATA = \
8104_01_characters.sql \ 8104_01_characters.sql \
8112_01_mangos_spell_proc_event.sql \ 8112_01_mangos_spell_proc_event.sql \
8115_01_mangos_playercreateinfo_action.sql \ 8115_01_mangos_playercreateinfo_action.sql \
8140_01_mangos_spell_proc_event.sql \
README README
## Additional files to include when running 'make dist' ## Additional files to include when running 'make dist'
@ -464,4 +465,5 @@ EXTRA_DIST = \
8104_01_characters.sql \ 8104_01_characters.sql \
8112_01_mangos_spell_proc_event.sql \ 8112_01_mangos_spell_proc_event.sql \
8115_01_mangos_playercreateinfo_action.sql \ 8115_01_mangos_playercreateinfo_action.sql \
8140_01_mangos_spell_proc_event.sql \
README README

View file

@ -244,30 +244,31 @@ void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data )
} }
// prevent character creating with invalid name // 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 ); SendPacket( &data );
sLog.outError("Account:[%d] but tried to Create character with empty [name] ",GetAccountId()); sLog.outError("Account:[%d] but tried to Create character with empty [name] ",GetAccountId());
return; return;
} }
// check name limitations // 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 ); SendPacket( &data );
return; return;
} }
if(GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(name)) if (GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(name))
{ {
data << (uint8)CHAR_NAME_RESERVED; data << (uint8)CHAR_NAME_RESERVED;
SendPacket( &data ); SendPacket( &data );
return; return;
} }
if(objmgr.GetPlayerGUIDByName(name)) if (objmgr.GetPlayerGUIDByName(name))
{ {
data << (uint8)CHAR_CREATE_NAME_IN_USE; data << (uint8)CHAR_CREATE_NAME_IN_USE;
SendPacket( &data ); SendPacket( &data );
@ -275,7 +276,7 @@ void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data )
} }
QueryResult *resultacct = loginDatabase.PQuery("SELECT SUM(numchars) FROM realmcharacters WHERE acctid = '%d'", GetAccountId()); QueryResult *resultacct = loginDatabase.PQuery("SELECT SUM(numchars) FROM realmcharacters WHERE acctid = '%d'", GetAccountId());
if ( resultacct ) if (resultacct)
{ {
Field *fields=resultacct->Fetch(); Field *fields=resultacct->Fetch();
uint32 acctcharcount = fields[0].GetUInt32(); uint32 acctcharcount = fields[0].GetUInt32();
@ -967,7 +968,7 @@ void WorldSession::HandleCharRenameOpcode(WorldPacket& recv_data)
recv_data >> newname; recv_data >> newname;
// prevent character rename to invalid name // prevent character rename to invalid name
if(!normalizePlayerName(newname)) if (!normalizePlayerName(newname))
{ {
WorldPacket data(SMSG_CHAR_RENAME, 1); WorldPacket data(SMSG_CHAR_RENAME, 1);
data << uint8(CHAR_NAME_NO_NAME); data << uint8(CHAR_NAME_NO_NAME);
@ -975,16 +976,17 @@ void WorldSession::HandleCharRenameOpcode(WorldPacket& recv_data)
return; return;
} }
if(!ObjectMgr::IsValidName(newname, true)) uint8 res = ObjectMgr::CheckPlayerName(newname,true);
if (res != CHAR_NAME_SUCCESS)
{ {
WorldPacket data(SMSG_CHAR_RENAME, 1); WorldPacket data(SMSG_CHAR_RENAME, 1);
data << uint8(CHAR_NAME_INVALID_CHARACTER); data << uint8(res);
SendPacket( &data ); SendPacket( &data );
return; return;
} }
// check name limitations // check name limitations
if(GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(newname)) if (GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(newname))
{ {
WorldPacket data(SMSG_CHAR_RENAME, 1); WorldPacket data(SMSG_CHAR_RENAME, 1);
data << uint8(CHAR_NAME_RESERVED); data << uint8(CHAR_NAME_RESERVED);
@ -1240,7 +1242,7 @@ void WorldSession::HandleCharCustomize(WorldPacket& recv_data)
} }
// prevent character rename to invalid name // prevent character rename to invalid name
if(!normalizePlayerName(newname)) if (!normalizePlayerName(newname))
{ {
WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
data << uint8(CHAR_NAME_NO_NAME); data << uint8(CHAR_NAME_NO_NAME);
@ -1248,16 +1250,17 @@ void WorldSession::HandleCharCustomize(WorldPacket& recv_data)
return; return;
} }
if(!ObjectMgr::IsValidName(newname,true)) uint8 res = ObjectMgr::CheckPlayerName(newname,true);
if (res != CHAR_NAME_SUCCESS)
{ {
WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
data << uint8(CHAR_NAME_INVALID_CHARACTER); data << uint8(res);
SendPacket( &data ); SendPacket( &data );
return; return;
} }
// check name limitations // check name limitations
if(GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(newname)) if (GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(newname))
{ {
WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
data << uint8(CHAR_NAME_RESERVED); data << uint8(CHAR_NAME_RESERVED);
@ -1266,9 +1269,9 @@ void WorldSession::HandleCharCustomize(WorldPacket& recv_data)
} }
// character with this name already exist // 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); WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
data << uint8(CHAR_CREATE_NAME_IN_USE); data << uint8(CHAR_CREATE_NAME_IN_USE);

View file

@ -112,13 +112,6 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction
if (pHolder.Event.event_inverse_phase_mask & (1 << Phase)) if (pHolder.Event.event_inverse_phase_mask & (1 << Phase))
return false; 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; CreatureEventAI_Event const& event = pHolder.Event;
//Check event conditions based on the event type, also reset events //Check event conditions based on the event type, also reset events
@ -330,6 +323,13 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction
if (!(pHolder.Event.event_flags & EFLAG_REPEATABLE)) if (!(pHolder.Event.event_flags & EFLAG_REPEATABLE))
pHolder.Enabled = false; 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 //Process actions
for (uint32 j = 0; j < MAX_ACTIONS; j++) for (uint32 j = 0; j < MAX_ACTIONS; j++)
ProcessAction(pHolder.Event.action[j], rnd, pHolder.Event.event_id, pActionInvoker); ProcessAction(pHolder.Event.action[j], rnd, pHolder.Event.event_id, pActionInvoker);

View file

@ -473,9 +473,8 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
action.morph.modelId = 0; action.morph.modelId = 0;
} }
} }
break;
} }
break;
case ACTION_T_SOUND: case ACTION_T_SOUND:
if (!sSoundEntriesStore.LookupEntry(action.sound.soundId)) if (!sSoundEntriesStore.LookupEntry(action.sound.soundId))
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant SoundID %u.", i, j+1, action.sound.soundId); sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant SoundID %u.", i, j+1, action.sound.soundId);

View file

@ -65,7 +65,7 @@ typedef GridRefManager<GameObject> GameObjectMapType;
typedef GridRefManager<Player> PlayerMapType; typedef GridRefManager<Player> PlayerMapType;
typedef Grid<Player, AllWorldObjectTypes,AllGridObjectTypes> GridType; 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<AllGridObjectTypes> GridTypeMapContainer;
typedef TypeMapContainer<AllWorldObjectTypes> WorldTypeMapContainer; typedef TypeMapContainer<AllWorldObjectTypes> WorldTypeMapContainer;

View file

@ -673,7 +673,31 @@ void WorldSession::HandleBuyItemInSlotOpcode( WorldPacket & recv_data )
recv_data >> vendorguid >> item >> slot >> bagguid >> bagslot >> count; 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 ) void WorldSession::HandleBuyItemOpcode( WorldPacket & recv_data )

View file

@ -4504,9 +4504,6 @@ bool ChatHandler::HandleResetHonorCommand (const char * args)
static bool HandleResetStatsOrLevelHelper(Player* player) 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()); ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(player->getClass());
if(!cEntry) if(!cEntry)
{ {
@ -4529,21 +4526,7 @@ static bool HandleResetStatsOrLevelHelper(Player* player)
// reset only if player not in some form; // reset only if player not in some form;
if(player->m_form==FORM_NONE) if(player->m_form==FORM_NONE)
{ player->InitDisplayIds();
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->SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP ); player->SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP );
player->SetByteValue(UNIT_FIELD_BYTES_2, 3, player->m_form); player->SetByteValue(UNIT_FIELD_BYTES_2, 3, player->m_form);
@ -5623,18 +5606,18 @@ bool ChatHandler::HandlePDumpLoadCommand(const char *args)
char* name_str = strtok(NULL, " "); char* name_str = strtok(NULL, " ");
std::string name; std::string name;
if(name_str) if (name_str)
{ {
name = name_str; name = name_str;
// normalize the name if specified and check if it exists // normalize the name if specified and check if it exists
if(!normalizePlayerName(name)) if (!normalizePlayerName(name))
{ {
PSendSysMessage(LANG_INVALID_CHARACTER_NAME); PSendSysMessage(LANG_INVALID_CHARACTER_NAME);
SetSentErrorMessage(true); SetSentErrorMessage(true);
return false; return false;
} }
if(!ObjectMgr::IsValidName(name,true)) if (ObjectMgr::CheckPlayerName(name,true) != CHAR_NAME_SUCCESS)
{ {
PSendSysMessage(LANG_INVALID_CHARACTER_NAME); PSendSysMessage(LANG_INVALID_CHARACTER_NAME);
SetSentErrorMessage(true); SetSentErrorMessage(true);
@ -5646,17 +5629,17 @@ bool ChatHandler::HandlePDumpLoadCommand(const char *args)
uint32 guid = 0; uint32 guid = 0;
if(guid_str) if (guid_str)
{ {
guid = atoi(guid_str); guid = atoi(guid_str);
if(!guid) if (!guid)
{ {
PSendSysMessage(LANG_INVALID_CHARACTER_GUID); PSendSysMessage(LANG_INVALID_CHARACTER_GUID);
SetSentErrorMessage(true); SetSentErrorMessage(true);
return false; return false;
} }
if(objmgr.GetPlayerAccountIdByGUID(guid)) if (objmgr.GetPlayerAccountIdByGUID(guid))
{ {
PSendSysMessage(LANG_CHARACTER_GUID_IN_USE,guid); PSendSysMessage(LANG_CHARACTER_GUID_IN_USE,guid);
SetSentErrorMessage(true); SetSentErrorMessage(true);
@ -6562,8 +6545,7 @@ bool ChatHandler::HandleModifyGenderCommand(const char *args)
player->SetByteValue(PLAYER_BYTES_3, 0, gender); player->SetByteValue(PLAYER_BYTES_3, 0, gender);
// Change display ID // Change display ID
player->SetDisplayId(gender ? info->displayId_f : info->displayId_m); player->InitDisplayIds();
player->SetNativeDisplayId(gender ? info->displayId_f : info->displayId_m);
char const* gender_full = gender ? "female" : "male"; char const* gender_full = gender ? "female" : "male";

View file

@ -247,6 +247,10 @@ void WorldSession::HandleLootOpcode( WorldPacket & recv_data )
uint64 guid; uint64 guid;
recv_data >> guid; recv_data >> guid;
// Check possible cheat
if(!_player->isAlive())
return;
GetPlayer()->SendLoot(guid, LOOT_CORPSE); GetPlayer()->SendLoot(guid, LOOT_CORPSE);
} }

View file

@ -762,38 +762,40 @@ void WorldSession::HandleQueryNextMailTime(WorldPacket & /*recv_data*/ )
{ {
data << (uint32) 0; // float data << (uint32) 0; // float
data << (uint32) 0; // count data << (uint32) 0; // count
uint32 count = 0; uint32 count = 0;
time_t now = time(NULL);
for(PlayerMails::iterator itr = _player->GetmailBegin(); itr != _player->GetmailEnd(); ++itr) for(PlayerMails::iterator itr = _player->GetmailBegin(); itr != _player->GetmailEnd(); ++itr)
{ {
Mail *m = (*itr); Mail *m = (*itr);
// not checked yet, already must be delivered // must be not checked yet
if((m->checked & MAIL_CHECK_MASK_READ)==0 && (m->deliver_time <= time(NULL))) if(m->checked & MAIL_CHECK_MASK_READ)
continue;
// and already delivered
if(now < m->deliver_time)
continue;
data << (uint64) m->sender; // sender guid
switch(m->messageType)
{ {
++count; case MAIL_AUCTION:
data << (uint32) 2;
if(count > 2) data << (uint32) 2;
{ data << (uint32) m->stationery;
count = 2; break;
default:
data << (uint32) 0;
data << (uint32) 0;
data << (uint32) m->stationery;
break; break;
}
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
} }
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); data.put<uint32>(4, count);
} }

View file

@ -6645,18 +6645,24 @@ bool isValidString(std::wstring wstr, uint32 strictMask, bool numericOrSpace, bo
return false; return false;
} }
bool ObjectMgr::IsValidName( const std::string& name, bool create ) uint8 ObjectMgr::CheckPlayerName( const std::string& name, bool create )
{ {
std::wstring wname; std::wstring wname;
if(!Utf8toWStr(name,wname)) if(!Utf8toWStr(name,wname))
return false; return CHAR_NAME_INVALID_CHARACTER;
if(wname.size() < 1 || wname.size() > MAX_PLAYER_NAME) if(wname.size() > MAX_PLAYER_NAME)
return false; 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); 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 ) bool ObjectMgr::IsValidCharterName( const std::string& name )
@ -6665,7 +6671,11 @@ bool ObjectMgr::IsValidCharterName( const std::string& name )
if(!Utf8toWStr(name,wname)) if(!Utf8toWStr(name,wname))
return false; 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; return false;
uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_CHARTER_NAMES); uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_CHARTER_NAMES);
@ -6673,18 +6683,24 @@ bool ObjectMgr::IsValidCharterName( const std::string& name )
return isValidString(wname,strictMask,true); return isValidString(wname,strictMask,true);
} }
bool ObjectMgr::IsValidPetName( const std::string& name ) PetNameInvalidReason ObjectMgr::CheckPetName( const std::string& name )
{ {
std::wstring wname; std::wstring wname;
if(!Utf8toWStr(name,wname)) if(!Utf8toWStr(name,wname))
return false; return PET_NAME_INVALID;
if(wname.size() < 1) if(wname.size() > MAX_PET_NAME)
return false; 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); 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 ) int ObjectMgr::GetIndexForLocale( LocaleConstant loc )

View file

@ -279,8 +279,10 @@ enum SkillRangeType
SkillRangeType GetSkillRangeType(SkillLineEntry const *pSkill, bool racial); 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_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); bool normalizePlayerName(std::string& name);
@ -693,9 +695,9 @@ class ObjectMgr
bool IsReservedName(const std::string& name) const; bool IsReservedName(const std::string& name) const;
// name with valid structure and symbols // 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 IsValidCharterName( const std::string& name );
static bool IsValidPetName( const std::string& name );
static bool CheckDeclinedNames(std::wstring mainpart, DeclinedName const& names); static bool CheckDeclinedNames(std::wstring mainpart, DeclinedName const& names);

View file

@ -1459,13 +1459,16 @@ bool Pet::unlearnSpell(uint32 spell_id, bool learn_prev, bool clear_ab)
{ {
if(removeSpell(spell_id,learn_prev,clear_ab)) if(removeSpell(spell_id,learn_prev,clear_ab))
{ {
if(GetOwner()->GetTypeId() == TYPEID_PLAYER) if(!m_loading)
{ {
if(!m_loading) if (Unit* owner = GetOwner())
{ {
WorldPacket data(SMSG_PET_REMOVED_SPELL, 4); if(owner->GetTypeId() == TYPEID_PLAYER)
data << uint32(spell_id); {
((Player*)GetOwner())->GetSession()->SendPacket(&data); WorldPacket data(SMSG_PET_REMOVED_SPELL, 4);
data << uint32(spell_id);
((Player*)owner)->GetSession()->SendPacket(&data);
}
} }
} }
return true; return true;

View file

@ -91,6 +91,9 @@ enum PetTalk
enum PetNameInvalidReason enum PetNameInvalidReason
{ {
// custom, not send
PET_NAME_SUCCESS = 0,
PET_NAME_INVALID = 1, PET_NAME_INVALID = 1,
PET_NAME_NO_NAME = 2, PET_NAME_NO_NAME = 2,
PET_NAME_TOO_SHORT = 3, PET_NAME_TOO_SHORT = 3,

View file

@ -401,9 +401,10 @@ void WorldSession::HandlePetRename( WorldPacket & recv_data )
pet->GetOwnerGUID() != _player->GetGUID() || !pet->GetCharmInfo() ) pet->GetOwnerGUID() != _player->GetGUID() || !pet->GetCharmInfo() )
return; 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; return;
} }

View file

@ -556,27 +556,12 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8
SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, DEFAULT_WORLD_OBJECT_SIZE); SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, DEFAULT_WORLD_OBJECT_SIZE);
SetFloatValue(UNIT_FIELD_COMBATREACH, 1.5f); 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(race); setFactionForRace(race);
uint32 RaceClassGender = ( race ) | ( class_ << 8 ) | ( gender << 16 ); uint32 RaceClassGender = ( race ) | ( class_ << 8 ) | ( gender << 16 );
SetUInt32Value(UNIT_FIELD_BYTES_0, ( RaceClassGender | ( powertype << 24 ) ) ); SetUInt32Value(UNIT_FIELD_BYTES_0, ( RaceClassGender | ( powertype << 24 ) ) );
InitDisplayIds();
SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP ); SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP );
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE ); SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE );
SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_REGENERATE_POWER); SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_REGENERATE_POWER);
@ -1412,7 +1397,7 @@ bool Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
PlayerInfo const *info = objmgr.GetPlayerInfo(pRace, pClass); PlayerInfo const *info = objmgr.GetPlayerInfo(pRace, pClass);
if(!info) if(!info)
{ {
sLog.outError("Player %u have incorrect race/class pair. Don't build enum.", guid); sLog.outError("Player %u has incorrect race/class pair. Don't build enum.", guid);
return false; return false;
} }
@ -3354,6 +3339,22 @@ void Player::RemoveSpellCooldown( uint32 spell_id, bool update /* = false */ )
SendClearCooldown(spell_id, this); SendClearCooldown(spell_id, this);
} }
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() void Player::RemoveArenaSpellCooldowns()
{ {
// remove cooldowns on spells that has < 15 min CD // remove cooldowns on spells that has < 15 min CD
@ -3406,7 +3407,7 @@ void Player::_LoadSpellCooldowns(QueryResult *result)
if(!sSpellStore.LookupEntry(spell_id)) 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; continue;
} }
@ -12524,7 +12525,7 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i ) for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i )
{ {
if ( pQuest->ReqItemId[i] ) if (pQuest->ReqItemId[i])
DestroyItemCount( pQuest->ReqItemId[i], pQuest->ReqItemCount[i], true); DestroyItemCount( pQuest->ReqItemId[i], pQuest->ReqItemCount[i], true);
} }
@ -12532,12 +12533,12 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
// SetTimedQuest( 0 ); // SetTimedQuest( 0 );
m_timedquests.erase(pQuest->GetQuestId()); m_timedquests.erase(pQuest->GetQuestId());
if ( pQuest->GetRewChoiceItemsCount() > 0 ) if (pQuest->GetRewChoiceItemsCount() > 0)
{ {
if( pQuest->RewChoiceItemId[reward] ) if (pQuest->RewChoiceItemId[reward])
{ {
ItemPosCountVec dest; 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, pQuest->RewChoiceItemId[reward], pQuest->RewChoiceItemCount[reward] ) == EQUIP_ERR_OK)
{ {
Item* item = StoreNewItem( dest, pQuest->RewChoiceItemId[reward], true); Item* item = StoreNewItem( dest, pQuest->RewChoiceItemId[reward], true);
SendNewItem(item, pQuest->RewChoiceItemCount[reward], true, false); SendNewItem(item, pQuest->RewChoiceItemCount[reward], true, false);
@ -12545,14 +12546,14 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
} }
} }
if ( pQuest->GetRewItemsCount() > 0 ) if (pQuest->GetRewItemsCount() > 0)
{ {
for (uint32 i=0; i < pQuest->GetRewItemsCount(); ++i) for (uint32 i=0; i < pQuest->GetRewItemsCount(); ++i)
{ {
if( pQuest->RewItemId[i] ) if (pQuest->RewItemId[i])
{ {
ItemPosCountVec dest; 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, pQuest->RewItemId[i], pQuest->RewItemCount[i] ) == EQUIP_ERR_OK)
{ {
Item* item = StoreNewItem( dest, pQuest->RewItemId[i], true); Item* item = StoreNewItem( dest, pQuest->RewItemId[i], true);
SendNewItem(item, pQuest->RewItemCount[i], true, false); SendNewItem(item, pQuest->RewItemCount[i], true, false);
@ -12563,13 +12564,8 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
RewardReputation( pQuest ); 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 ); uint16 log_slot = FindQuestSlot( quest_id );
if( log_slot < MAX_QUEST_LOG_SIZE) if (log_slot < MAX_QUEST_LOG_SIZE)
SetQuestSlot(log_slot,0); SetQuestSlot(log_slot,0);
QuestStatusData& q_status = mQuestStatus[quest_id]; QuestStatusData& q_status = mQuestStatus[quest_id];
@ -12577,7 +12573,7 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
// Not give XP in case already completed once repeatable quest // 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)); 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 ); GiveXP( XP , NULL );
else else
{ {
@ -12587,33 +12583,33 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
} }
// Give player extra money if GetRewOrReqMoney > 0 and get ReqMoney if negative // Give player extra money if GetRewOrReqMoney > 0 and get ReqMoney if negative
if(pQuest->GetRewOrReqMoney()) if (pQuest->GetRewOrReqMoney())
{ {
ModifyMoney( pQuest->GetRewOrReqMoney() ); ModifyMoney( pQuest->GetRewOrReqMoney() );
if(pQuest->GetRewOrReqMoney() > 0) if (pQuest->GetRewOrReqMoney() > 0)
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD, pQuest->GetRewOrReqMoney()); GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD, pQuest->GetRewOrReqMoney());
} }
// honor reward // honor reward
if(pQuest->GetRewHonorableKills()) if (pQuest->GetRewHonorableKills())
RewardHonor(NULL, 0, MaNGOS::Honor::hk_honor_at_level(getLevel(), pQuest->GetRewHonorableKills())); RewardHonor(NULL, 0, MaNGOS::Honor::hk_honor_at_level(getLevel(), pQuest->GetRewHonorableKills()));
// title reward // 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); SetTitle(titleEntry);
} }
if(pQuest->GetBonusTalents()) if (pQuest->GetBonusTalents())
{ {
m_questRewardTalentCount+=pQuest->GetBonusTalents(); m_questRewardTalentCount+=pQuest->GetBonusTalents();
InitTalentForLevel(); InitTalentForLevel();
} }
// Send reward mail // Send reward mail
if(pQuest->GetRewMailTemplateId()) if (pQuest->GetRewMailTemplateId())
{ {
MailMessageType mailType; MailMessageType mailType;
uint32 senderGuidOrEntry; uint32 senderGuidOrEntry;
@ -12651,9 +12647,9 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
uint32 max_slot = questMailLoot.GetMaxSlotInLootFor(this); uint32 max_slot = questMailLoot.GetMaxSlotInLootFor(this);
for(uint32 i = 0; mi.size() < MAX_MAIL_ITEMS && i < max_slot; ++i) 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 item->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted
mi.AddItem(item->GetGUIDLow(), item->GetEntry(), item); mi.AddItem(item->GetGUIDLow(), item->GetEntry(), item);
@ -12664,23 +12660,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()); 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); SetDailyQuestStatus(quest_id);
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST, 1); GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST, 1);
} }
if ( !pQuest->IsRepeatable() ) if (!pQuest->IsRepeatable())
SetQuestStatus(quest_id, QUEST_STATUS_COMPLETE); SetQuestStatus(quest_id, QUEST_STATUS_COMPLETE);
else else
SetQuestStatus(quest_id, QUEST_STATUS_NONE); SetQuestStatus(quest_id, QUEST_STATUS_NONE);
q_status.m_rewarded = true; q_status.m_rewarded = true;
if (q_status.uState != QUEST_NEW)
q_status.uState = QUEST_CHANGED;
if(announce) if (announce)
SendQuestReward( pQuest, XP, questGiver ); 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) if (pQuest->GetZoneOrSort() > 0)
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE, pQuest->GetZoneOrSort()); GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE, pQuest->GetZoneOrSort());
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT); GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT);
@ -14028,7 +14031,8 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
m_name = fields[3].GetCppString(); m_name = fields[3].GetCppString();
// check name limitations // 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; delete result;
CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE guid ='%u'", uint32(AT_LOGIN_RENAME),guid); CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE guid ='%u'", uint32(AT_LOGIN_RENAME),guid);
@ -14060,6 +14064,8 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
SetUInt32Value(PLAYER_BYTES_3, (GetUInt32Value(PLAYER_BYTES_3) & ~1) | fields[6].GetUInt8()); SetUInt32Value(PLAYER_BYTES_3, (GetUInt32Value(PLAYER_BYTES_3) & ~1) | fields[6].GetUInt8());
SetUInt32Value(PLAYER_FLAGS, fields[12].GetUInt32()); SetUInt32Value(PLAYER_FLAGS, fields[12].GetUInt32());
InitDisplayIds();
// cleanup inventory related item value fields (its will be filled correctly in _LoadInventory) // cleanup inventory related item value fields (its will be filled correctly in _LoadInventory)
for(uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot) for(uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
{ {
@ -14921,7 +14927,7 @@ void Player::_LoadMailedItems(Mail *mail)
if(!proto) 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 mail_items WHERE item_guid = '%u'", item_guid_low);
CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", item_guid_low); CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", item_guid_low);
continue; continue;
@ -15514,7 +15520,6 @@ void Player::SaveToDB()
SetByteValue(UNIT_FIELD_BYTES_1, 0, UNIT_STAND_STATE_STAND); SetByteValue(UNIT_FIELD_BYTES_1, 0, UNIT_STAND_STATE_STAND);
SetByteValue(UNIT_FIELD_BYTES_2, 3, 0); // shapeshift SetByteValue(UNIT_FIELD_BYTES_2, 3, 0); // shapeshift
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
SetDisplayId(GetNativeDisplayId());
bool inworld = IsInWorld(); bool inworld = IsInWorld();
@ -15659,7 +15664,6 @@ void Player::SaveToDB()
CharacterDatabase.CommitTransaction(); CharacterDatabase.CommitTransaction();
// restore state (before aura apply, if aura remove flag then aura must set it ack by self) // 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_1, tmp_bytes);
SetUInt32Value(UNIT_FIELD_BYTES_2, tmp_bytes2); SetUInt32Value(UNIT_FIELD_BYTES_2, tmp_bytes2);
SetUInt32Value(UNIT_FIELD_FLAGS, tmp_flags); SetUInt32Value(UNIT_FIELD_FLAGS, tmp_flags);
@ -16103,28 +16107,17 @@ 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) void Player::Customize(uint64 guid, uint8 gender, uint8 skin, uint8 face, uint8 hairStyle, uint8 hairColor, uint8 facialHair)
{ {
// 0 1 2 3 4 // 0
QueryResult* result = CharacterDatabase.PQuery("SELECT data, race, class, playerBytes, playerBytes2 FROM characters WHERE guid = '%u'", GUID_LOPART(guid)); QueryResult* result = CharacterDatabase.PQuery("SELECT playerBytes2 FROM characters WHERE guid = '%u'", GUID_LOPART(guid));
if(!result) if(!result)
return; return;
Field* fields = result->Fetch(); Field* fields = result->Fetch();
Tokens tokens = StrSplit(fields[0].GetString(), " "); uint32 player_bytes2 = fields[0].GetUInt32();
PlayerInfo const* info = objmgr.GetPlayerInfo(fields[1].GetUInt8(), fields[2].GetUInt8());
if(!info)
return;
// TODO: do not access data field here
SetUInt32ValueInArray(tokens, UNIT_FIELD_DISPLAYID, gender ? info->displayId_f : info->displayId_m);
SetUInt32ValueInArray(tokens, UNIT_FIELD_NATIVEDISPLAYID, gender ? info->displayId_f : info->displayId_m);
uint32 player_bytes2 = fields[4].GetUInt32();
player_bytes2 &= ~0xFF; player_bytes2 &= ~0xFF;
player_bytes2 |= facialHair; player_bytes2 |= facialHair;
SaveValuesArrayInDB(tokens, guid);
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)); 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));
delete result; delete result;
@ -16379,9 +16372,7 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent)
if(pet->isControlled()) if(pet->isControlled())
{ {
WorldPacket data(SMSG_PET_SPELLS, 8); RemovePetActionBar();
data << uint64(0);
GetSession()->SendPacket(&data);
if(GetGroup()) if(GetGroup())
SetGroupUpdateFlag(GROUP_UPDATE_PET); SetGroupUpdateFlag(GROUP_UPDATE_PET);
@ -16643,6 +16634,13 @@ void Player::CharmSpellInitialize()
GetSession()->SendPacket(&data); GetSession()->SendPacket(&data);
} }
void Player::RemovePetActionBar()
{
WorldPacket data(SMSG_PET_SPELLS, 8);
data << uint64(0);
SendDirectMessage(&data);
}
bool Player::IsAffectedBySpellmod(SpellEntry const *spellInfo, SpellModifier *mod, Spell const* spell) bool Player::IsAffectedBySpellmod(SpellEntry const *spellInfo, SpellModifier *mod, Spell const* spell)
{ {
if (!mod || !spellInfo) if (!mod || !spellInfo)
@ -17156,17 +17154,43 @@ void Player::InitDataForForm(bool reapplyMods)
UpdateAttackPowerAndDamage(true); 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 // 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 // cheating attempt
if(count < 1) count = 1; if (count < 1) count = 1;
if(!isAlive()) if (!isAlive())
return false; return false;
ItemPrototype const *pProto = objmgr.GetItemPrototype( item ); ItemPrototype const *pProto = objmgr.GetItemPrototype( item );
if( !pProto ) if (!pProto)
{ {
SendBuyError( BUY_ERR_CANT_FIND_ITEM, NULL, item, 0); SendBuyError( BUY_ERR_CANT_FIND_ITEM, NULL, item, 0);
return false; return false;
@ -17188,7 +17212,7 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
} }
size_t vendor_slot = vItems->FindItemSlot(item); 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); SendBuyError( BUY_ERR_CANT_FIND_ITEM, pCreature, item, 0);
return false; return false;
@ -17197,39 +17221,39 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
VendorItem const* crItem = vItems->m_items[vendor_slot]; VendorItem const* crItem = vItems->m_items[vendor_slot];
// check current item amount if it limited // 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); SendBuyError( BUY_ERR_ITEM_ALREADY_SOLD, pCreature, item, 0);
return false; return false;
} }
} }
if( uint32(GetReputationRank(pProto->RequiredReputationFaction)) < pProto->RequiredReputationRank) if (uint32(GetReputationRank(pProto->RequiredReputationFaction)) < pProto->RequiredReputationRank)
{ {
SendBuyError( BUY_ERR_REPUTATION_REQUIRE, pCreature, item, 0); SendBuyError( BUY_ERR_REPUTATION_REQUIRE, pCreature, item, 0);
return false; return false;
} }
if(crItem->ExtendedCost) if (crItem->ExtendedCost)
{ {
ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(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); sLog.outError("Item %u have wrong ExtendedCost field value %u", pProto->ItemId, crItem->ExtendedCost);
return false; return false;
} }
// honor points price // honor points price
if(GetHonorPoints() < (iece->reqhonorpoints * count)) if (GetHonorPoints() < (iece->reqhonorpoints * count))
{ {
SendEquipError(EQUIP_ERR_NOT_ENOUGH_HONOR_POINTS, NULL, NULL); SendEquipError(EQUIP_ERR_NOT_ENOUGH_HONOR_POINTS, NULL, NULL);
return false; return false;
} }
// arena points price // arena points price
if(GetArenaPoints() < (iece->reqarenapoints * count)) if (GetArenaPoints() < (iece->reqarenapoints * count))
{ {
SendEquipError(EQUIP_ERR_NOT_ENOUGH_ARENA_POINTS, NULL, NULL); SendEquipError(EQUIP_ERR_NOT_ENOUGH_ARENA_POINTS, NULL, NULL);
return false; return false;
@ -17259,62 +17283,38 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
// reputation discount // reputation discount
price = uint32(floor(price * GetReputationPriceDiscount(pCreature))); price = uint32(floor(price * GetReputationPriceDiscount(pCreature)));
if( GetMoney() < price ) if (GetMoney() < price)
{ {
SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, item, 0); SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, item, 0);
return false; return false;
} }
uint8 bag = 0; // init for case invalid bagGUID if ((bag == NULL_BAG && slot == NULL_SLOT) || IsInventoryPos(bag, slot))
if (bagguid != NULL_BAG && slot != NULL_SLOT)
{
if( bagguid == GetGUID() )
{
bag = INVENTORY_SLOT_BAG_0;
}
else
{
for (int 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() )
{
bag = i;
break;
}
}
}
}
}
if( IsInventoryPos( bag, slot ) || (bagguid == NULL_BAG && slot == NULL_SLOT) )
{ {
ItemPosCountVec dest; ItemPosCountVec dest;
uint8 msg = CanStoreNewItem( bag, slot, dest, item, pProto->BuyCount * count ); uint8 msg = CanStoreNewItem( bag, slot, dest, item, pProto->BuyCount * count );
if( msg != EQUIP_ERR_OK ) if (msg != EQUIP_ERR_OK)
{ {
SendEquipError( msg, NULL, NULL ); SendEquipError( msg, NULL, NULL );
return false; return false;
} }
ModifyMoney( -(int32)price ); 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); ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost);
if(iece->reqhonorpoints) if (iece->reqhonorpoints)
ModifyHonorPoints( - int32(iece->reqhonorpoints * count)); ModifyHonorPoints( - int32(iece->reqhonorpoints * count));
if(iece->reqarenapoints) if (iece->reqarenapoints)
ModifyArenaPoints( - int32(iece->reqarenapoints * count)); ModifyArenaPoints( - int32(iece->reqarenapoints * count));
for (uint8 i = 0; i < 5; ++i) for (uint8 i = 0; i < 5; ++i)
{ {
if(iece->reqitem[i]) if (iece->reqitem[i])
DestroyItemCount(iece->reqitem[i], (iece->reqitemcount[i] * count), true); 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); uint32 new_count = pCreature->UpdateVendorItemCurrentCount(crItem,pProto->BuyCount * count);
@ -17328,9 +17328,9 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
SendNewItem(it, pProto->BuyCount*count, true, false, false); 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 ); SendEquipError( EQUIP_ERR_ITEM_CANT_BE_EQUIPPED, NULL, NULL );
return false; return false;
@ -17338,19 +17338,19 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
uint16 dest; uint16 dest;
uint8 msg = CanEquipNewItem( slot, dest, item, false ); uint8 msg = CanEquipNewItem( slot, dest, item, false );
if( msg != EQUIP_ERR_OK ) if (msg != EQUIP_ERR_OK)
{ {
SendEquipError( msg, NULL, NULL ); SendEquipError( msg, NULL, NULL );
return false; return false;
} }
ModifyMoney( -(int32)price ); 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); ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost);
if(iece->reqhonorpoints) if (iece->reqhonorpoints)
ModifyHonorPoints( - int32(iece->reqhonorpoints)); ModifyHonorPoints( - int32(iece->reqhonorpoints));
if(iece->reqarenapoints) if (iece->reqarenapoints)
ModifyArenaPoints( - int32(iece->reqarenapoints)); ModifyArenaPoints( - int32(iece->reqarenapoints));
for (uint8 i = 0; i < 5; ++i) for (uint8 i = 0; i < 5; ++i)
{ {
@ -17359,7 +17359,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); uint32 new_count = pCreature->UpdateVendorItemCurrentCount(crItem,pProto->BuyCount * count);
@ -17381,7 +17381,7 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
return false; return false;
} }
return crItem->maxcount!=0; return crItem->maxcount != 0;
} }
uint32 Player::GetMaxPersonalArenaRatingRequirement() uint32 Player::GetMaxPersonalArenaRatingRequirement()
@ -19394,7 +19394,7 @@ void Player::EnterVehicle(Vehicle *vehicle)
vehicle->SetCharmerGUID(GetGUID()); vehicle->SetCharmerGUID(GetGUID());
vehicle->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); vehicle->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
vehicle->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_24); vehicle->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
vehicle->setFaction(getFaction()); vehicle->setFaction(getFaction());
SetCharm(vehicle); // charm SetCharm(vehicle); // charm
@ -19446,7 +19446,7 @@ void Player::ExitVehicle(Vehicle *vehicle)
{ {
vehicle->SetCharmerGUID(0); vehicle->SetCharmerGUID(0);
vehicle->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); vehicle->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
vehicle->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_24); vehicle->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
vehicle->setFaction((GetTeam() == ALLIANCE) ? vehicle->GetCreatureInfo()->faction_A : vehicle->GetCreatureInfo()->faction_H); vehicle->setFaction((GetTeam() == ALLIANCE) ? vehicle->GetCreatureInfo()->faction_A : vehicle->GetCreatureInfo()->faction_H);
SetCharm(NULL); SetCharm(NULL);
@ -19468,9 +19468,7 @@ void Player::ExitVehicle(Vehicle *vehicle)
data << uint32(0); // fall time data << uint32(0); // fall time
GetSession()->SendPacket(&data); GetSession()->SendPacket(&data);
data.Initialize(SMSG_PET_SPELLS, 8); RemovePetActionBar();
data << uint64(0);
GetSession()->SendPacket(&data);
// maybe called at dummy aura remove? // maybe called at dummy aura remove?
// CastSpell(this, 45472, true); // Parachute // CastSpell(this, 45472, true); // Parachute

View file

@ -1191,7 +1191,7 @@ class MANGOS_DLL_SPEC Player : public Unit
return mainItem && mainItem->GetProto()->InventoryType == INVTYPE_2HWEAPON && !CanTitanGrip(); return mainItem && mainItem->GetProto()->InventoryType == INVTYPE_2HWEAPON && !CanTitanGrip();
} }
void SendNewItem( Item *item, uint32 count, bool received, bool created, bool broadcast = false ); void SendNewItem( Item *item, uint32 count, bool received, bool created, bool broadcast = false );
bool 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; float GetReputationPriceDiscount( Creature const* pCreature ) const;
Player* GetTrader() const { return pTrader; } Player* GetTrader() const { return pTrader; }
@ -1447,6 +1447,8 @@ class MANGOS_DLL_SPEC Player : public Unit
void PetSpellInitialize(); void PetSpellInitialize();
void CharmSpellInitialize(); void CharmSpellInitialize();
void PossessSpellInitialize(); void PossessSpellInitialize();
void RemovePetActionBar();
bool HasSpell(uint32 spell) const; bool HasSpell(uint32 spell) const;
bool HasActiveSpell(uint32 spell) const; // show in spellbook bool HasActiveSpell(uint32 spell) const; // show in spellbook
TrainerSpellState GetTrainerSpellState(TrainerSpell const* trainer_spell) const; TrainerSpellState GetTrainerSpellState(TrainerSpell const* trainer_spell) const;
@ -1497,6 +1499,8 @@ class MANGOS_DLL_SPEC Player : public Unit
PlayerSpellMap const& GetSpellMap() const { return m_spells; } PlayerSpellMap const& GetSpellMap() const { return m_spells; }
PlayerSpellMap & GetSpellMap() { return m_spells; } PlayerSpellMap & GetSpellMap() { return m_spells; }
SpellCooldowns const& GetSpellCooldownMap() const { return m_spellCooldowns; }
void AddSpellMod(SpellModifier* mod, bool apply); void AddSpellMod(SpellModifier* mod, bool apply);
bool IsAffectedBySpellmod(SpellEntry const *spellInfo, SpellModifier *mod, Spell const* spell = NULL); bool IsAffectedBySpellmod(SpellEntry const *spellInfo, SpellModifier *mod, Spell const* spell = NULL);
template <class T> T ApplySpellMod(uint32 spellId, SpellModOp op, T &basevalue, Spell const* spell = NULL); template <class T> T ApplySpellMod(uint32 spellId, SpellModOp op, T &basevalue, Spell const* spell = NULL);
@ -1520,6 +1524,7 @@ class MANGOS_DLL_SPEC Player : public Unit
void SendCooldownEvent(SpellEntry const *spellInfo, uint32 itemId = 0, Spell* spell = NULL); void SendCooldownEvent(SpellEntry const *spellInfo, uint32 itemId = 0, Spell* spell = NULL);
void ProhibitSpellScholl(SpellSchoolMask idSchoolMask, uint32 unTimeMs ); void ProhibitSpellScholl(SpellSchoolMask idSchoolMask, uint32 unTimeMs );
void RemoveSpellCooldown(uint32 spell_id, bool update = false); void RemoveSpellCooldown(uint32 spell_id, bool update = false);
void RemoveSpellCategoryCooldown(uint32 cat, bool update = false);
void SendClearCooldown( uint32 spell_id, Unit* target ); void SendClearCooldown( uint32 spell_id, Unit* target );
void RemoveArenaSpellCooldowns(); void RemoveArenaSpellCooldowns();
@ -1783,6 +1788,8 @@ class MANGOS_DLL_SPEC Player : public Unit
static uint32 getFactionForRace(uint8 race); static uint32 getFactionForRace(uint8 race);
void setFactionForRace(uint8 race); void setFactionForRace(uint8 race);
void InitDisplayIds();
bool IsAtGroupRewardDistance(WorldObject const* pRewardSource) const; bool IsAtGroupRewardDistance(WorldObject const* pRewardSource) const;
bool RewardPlayerAndGroupAtKill(Unit* pVictim); bool RewardPlayerAndGroupAtKill(Unit* pVictim);
void RewardPlayerAndGroupAtEvent(uint32 creature_id,WorldObject* pRewardSource); void RewardPlayerAndGroupAtEvent(uint32 creature_id,WorldObject* pRewardSource);

View file

@ -393,7 +393,7 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s
{ {
QueryResult *result = CharacterDatabase.PQuery("SELECT COUNT(guid) FROM characters WHERE account = '%d'", account); QueryResult *result = CharacterDatabase.PQuery("SELECT COUNT(guid) FROM characters WHERE account = '%d'", account);
uint8 charcount = 0; uint8 charcount = 0;
if ( result ) if (result)
{ {
Field *fields=result->Fetch(); Field *fields=result->Fetch();
charcount = fields[0].GetUInt8(); charcount = fields[0].GetUInt8();
@ -405,7 +405,7 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s
} }
FILE *fin = fopen(file.c_str(), "r"); FILE *fin = fopen(file.c_str(), "r");
if(!fin) if (!fin)
return DUMP_FILE_OPEN_ERROR; return DUMP_FILE_OPEN_ERROR;
QueryResult * result = NULL; QueryResult * result = NULL;
@ -413,7 +413,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 // make sure the same guid doesn't already exist and is safe to use
bool incHighest = true; 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); result = CharacterDatabase.PQuery("SELECT * FROM characters WHERE guid = '%d'", guid);
if (result) if (result)
@ -427,10 +427,10 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s
guid = objmgr.m_hiCharGuid; guid = objmgr.m_hiCharGuid;
// normalize the name if specified and check if it exists // normalize the name if specified and check if it exists
if(!normalizePlayerName(name)) if (!normalizePlayerName(name))
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 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()); result = CharacterDatabase.PQuery("SELECT * FROM characters WHERE name = '%s'", name.c_str());
@ -440,7 +440,8 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s
delete result; delete result;
} }
} }
else name = ""; else
name = "";
// name encoded or empty // name encoded or empty

View file

@ -395,6 +395,7 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi
m_castPositionX = m_castPositionY = m_castPositionZ = 0; m_castPositionX = m_castPositionY = m_castPositionZ = 0;
m_TriggerSpells.clear(); m_TriggerSpells.clear();
m_preCastSpells.clear();
m_IsTriggeredSpell = triggered; m_IsTriggeredSpell = triggered;
//m_AreaAura = false; //m_AreaAura = false;
m_CastItem = NULL; m_CastItem = NULL;
@ -405,7 +406,6 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi
focusObject = NULL; focusObject = NULL;
m_cast_count = 0; m_cast_count = 0;
m_glyphIndex = 0; m_glyphIndex = 0;
m_preCastSpell = 0;
m_triggeredByAuraSpell = NULL; m_triggeredByAuraSpell = NULL;
//Auto Shot & Shoot (wand) //Auto Shot & Shoot (wand)
@ -1146,15 +1146,17 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)
void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask) void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
{ {
if(!unit || !effectMask) if (!unit || !effectMask)
return; return;
Unit* realCaster = m_originalCaster ? m_originalCaster : m_caster;
// Recheck immune (only for delayed spells) // Recheck immune (only for delayed spells)
if( m_spellInfo->speed && ( if (m_spellInfo->speed && (
unit->IsImmunedToDamage(GetSpellSchoolMask(m_spellInfo)) || unit->IsImmunedToDamage(GetSpellSchoolMask(m_spellInfo)) ||
unit->IsImmunedToSpell(m_spellInfo))) unit->IsImmunedToSpell(m_spellInfo)))
{ {
m_caster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_IMMUNE); realCaster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_IMMUNE);
return; return;
} }
@ -1164,67 +1166,65 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
((Player*)unit)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2, m_spellInfo->Id); ((Player*)unit)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2, m_spellInfo->Id);
} }
if(m_caster->GetTypeId() == TYPEID_PLAYER) if (realCaster->GetTypeId() == TYPEID_PLAYER)
{ ((Player*)realCaster)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2, m_spellInfo->Id, 0, unit);
((Player*)m_caster)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2, m_spellInfo->Id, 0, unit);
}
if( m_caster != unit ) if (realCaster != unit)
{ {
// Recheck UNIT_FLAG_NON_ATTACKABLE for delayed spells // Recheck UNIT_FLAG_NON_ATTACKABLE for delayed spells
if (m_spellInfo->speed > 0.0f && if (m_spellInfo->speed > 0.0f &&
unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE) && unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE) &&
unit->GetCharmerOrOwnerGUID() != m_caster->GetGUID()) unit->GetCharmerOrOwnerGUID() != m_caster->GetGUID())
{ {
m_caster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_EVADE); realCaster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_EVADE);
return; return;
} }
if( !m_caster->IsFriendlyTo(unit) ) if (!realCaster->IsFriendlyTo(unit))
{ {
// for delayed spells ignore not visible explicit target // for delayed spells ignore not visible explicit target
if(m_spellInfo->speed > 0.0f && unit == m_targets.getUnitTarget() && !unit->isVisibleForOrDetect(m_caster,false)) if (m_spellInfo->speed > 0.0f && unit == m_targets.getUnitTarget() &&
!unit->isVisibleForOrDetect(m_caster,false))
{ {
m_caster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_EVADE); realCaster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_EVADE);
return; return;
} }
unit->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); unit->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
if( !(m_spellInfo->AttributesEx & SPELL_ATTR_EX_NO_INITIAL_AGGRO) ) if (!(m_spellInfo->AttributesEx & SPELL_ATTR_EX_NO_INITIAL_AGGRO))
{ {
if(!unit->IsStandState() && !unit->hasUnitState(UNIT_STAT_STUNNED)) if (!unit->IsStandState() && !unit->hasUnitState(UNIT_STAT_STUNNED))
unit->SetStandState(UNIT_STAND_STATE_STAND); unit->SetStandState(UNIT_STAND_STATE_STAND);
if(!unit->isInCombat() && unit->GetTypeId() != TYPEID_PLAYER && ((Creature*)unit)->AI()) if (!unit->isInCombat() && unit->GetTypeId() != TYPEID_PLAYER && ((Creature*)unit)->AI())
((Creature*)unit)->AI()->AttackedBy(m_caster); ((Creature*)unit)->AI()->AttackedBy(realCaster);
unit->AddThreat(m_caster, 0.0f); unit->AddThreat(realCaster, 0.0f);
unit->SetInCombatWith(m_caster); unit->SetInCombatWith(realCaster);
m_caster->SetInCombatWith(unit); realCaster->SetInCombatWith(unit);
if(Player *attackedPlayer = unit->GetCharmerOrOwnerPlayerOrPlayerItself()) if (Player *attackedPlayer = unit->GetCharmerOrOwnerPlayerOrPlayerItself())
{ realCaster->SetContestedPvP(attackedPlayer);
m_caster->SetContestedPvP(attackedPlayer);
}
} }
} }
else else
{ {
// for delayed spells ignore negative spells (after duel end) for friendly targets // for delayed spells ignore negative spells (after duel end) for friendly targets
if(m_spellInfo->speed > 0.0f && !IsPositiveSpell(m_spellInfo->Id)) if (m_spellInfo->speed > 0.0f && !IsPositiveSpell(m_spellInfo->Id))
{ {
m_caster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_EVADE); realCaster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_EVADE);
return; return;
} }
// assisting case, healing and resurrection // assisting case, healing and resurrection
if(unit->hasUnitState(UNIT_STAT_ATTACK_PLAYER)) if (unit->hasUnitState(UNIT_STAT_ATTACK_PLAYER))
m_caster->SetContestedPvP(); realCaster->SetContestedPvP();
if( unit->isInCombat() && !(m_spellInfo->AttributesEx & SPELL_ATTR_EX_NO_INITIAL_AGGRO) )
if (unit->isInCombat() && !(m_spellInfo->AttributesEx & SPELL_ATTR_EX_NO_INITIAL_AGGRO))
{ {
m_caster->SetInCombatState(unit->GetCombatTimer() > 0); realCaster->SetInCombatState(unit->GetCombatTimer() > 0);
unit->getHostilRefManager().threatAssist(m_caster, 0.0f); unit->getHostilRefManager().threatAssist(realCaster, 0.0f);
} }
} }
} }
@ -1233,12 +1233,17 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
m_diminishGroup = GetDiminishingReturnsGroupForSpell(m_spellInfo,m_triggeredByAuraSpell); m_diminishGroup = GetDiminishingReturnsGroupForSpell(m_spellInfo,m_triggeredByAuraSpell);
m_diminishLevel = unit->GetDiminishing(m_diminishGroup); m_diminishLevel = unit->GetDiminishing(m_diminishGroup);
// Increase Diminishing on unit, current informations for actually casts will use values above // Increase Diminishing on unit, current informations for actually casts will use values above
if((GetDiminishingReturnsGroupType(m_diminishGroup) == DRTYPE_PLAYER && unit->GetTypeId() == TYPEID_PLAYER) || GetDiminishingReturnsGroupType(m_diminishGroup) == DRTYPE_ALL) if ((GetDiminishingReturnsGroupType(m_diminishGroup) == DRTYPE_PLAYER && unit->GetTypeId() == TYPEID_PLAYER) ||
GetDiminishingReturnsGroupType(m_diminishGroup) == DRTYPE_ALL)
unit->IncrDiminishing(m_diminishGroup); unit->IncrDiminishing(m_diminishGroup);
// Apply additional spell effects to target // Apply additional spell effects to target
if (m_preCastSpell) while (!m_preCastSpells.empty())
m_caster->CastSpell(unit, m_preCastSpell, true, m_CastItem); {
uint32 spellId = *m_preCastSpells.begin();
m_caster->CastSpell(unit, spellId, true, m_CastItem);
m_preCastSpells.erase(m_preCastSpells.begin());
}
for(uint32 effectNumber = 0; effectNumber < 3; ++effectNumber) for(uint32 effectNumber = 0; effectNumber < 3; ++effectNumber)
{ {
@ -1250,7 +1255,7 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
// Get multiplier // Get multiplier
float multiplier = m_spellInfo->DmgMultiplier[effectNumber]; float multiplier = m_spellInfo->DmgMultiplier[effectNumber];
// Apply multiplier mods // Apply multiplier mods
if(Player* modOwner = m_originalCaster->GetSpellModOwner()) if(Player* modOwner = realCaster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_EFFECT_PAST_FIRST, multiplier, this); modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_EFFECT_PAST_FIRST, multiplier, this);
m_damageMultipliers[effectNumber] *= multiplier; m_damageMultipliers[effectNumber] *= multiplier;
} }
@ -2287,17 +2292,17 @@ void Spell::cast(bool skipCheck)
case SPELLFAMILY_GENERIC: case SPELLFAMILY_GENERIC:
{ {
if (m_spellInfo->Mechanic == MECHANIC_BANDAGE) // Bandages if (m_spellInfo->Mechanic == MECHANIC_BANDAGE) // Bandages
m_preCastSpell = 11196; // Recently Bandaged AddPrecastSpell(11196); // Recently Bandaged
else if(m_spellInfo->SpellIconID == 1662 && m_spellInfo->AttributesEx & 0x20) else if(m_spellInfo->SpellIconID == 1662 && m_spellInfo->AttributesEx & 0x20)
// Blood Fury (Racial) // Blood Fury (Racial)
m_preCastSpell = 23230; // Blood Fury - Healing Reduction AddPrecastSpell(23230); // Blood Fury - Healing Reduction
break; break;
} }
case SPELLFAMILY_MAGE: case SPELLFAMILY_MAGE:
{ {
// Ice Block // Ice Block
if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000008000000000)) if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000008000000000))
m_preCastSpell = 41425; // Hypothermia AddPrecastSpell(41425); // Hypothermia
break; break;
} }
case SPELLFAMILY_PRIEST: case SPELLFAMILY_PRIEST:
@ -2305,27 +2310,32 @@ void Spell::cast(bool skipCheck)
// Power Word: Shield // Power Word: Shield
if (m_spellInfo->Mechanic == MECHANIC_SHIELD && if (m_spellInfo->Mechanic == MECHANIC_SHIELD &&
(m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000000000000001))) (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000000000000001)))
m_preCastSpell = 6788; // Weakened Soul AddPrecastSpell(6788); // Weakened Soul
// Dispersion (transform) // Dispersion (transform)
if (m_spellInfo->Id == 47585) if (m_spellInfo->Id == 47585)
m_preCastSpell = 60069; // Dispersion (mana regen) AddPrecastSpell(60069); // Dispersion (mana regen)
break; break;
} }
case SPELLFAMILY_PALADIN: case SPELLFAMILY_PALADIN:
{ {
// Divine Shield, Divine Protection or Hand of Protection // Divine Shield, Divine Protection or Hand of Protection
if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000000000400080)) if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000000000400080))
m_preCastSpell = 25771; // Forbearance {
AddPrecastSpell(25771); // Forbearance
AddPrecastSpell(61987); // Avenging Wrath Marker
}
else if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x200000000000))
AddPrecastSpell(61987); // Avenging Wrath Marker
break; break;
} }
case SPELLFAMILY_SHAMAN: case SPELLFAMILY_SHAMAN:
{ {
// Bloodlust // Bloodlust
if (m_spellInfo->Id == 2825) if (m_spellInfo->Id == 2825)
m_preCastSpell = 57724; // Sated AddPrecastSpell(57724); // Sated
// Heroism // Heroism
else if (m_spellInfo->Id == 32182) else if (m_spellInfo->Id == 32182)
m_preCastSpell = 57723; // Exhaustion AddPrecastSpell(57723); // Exhaustion
break; break;
} }
default: default:
@ -3659,8 +3669,17 @@ SpellCastResult Spell::CheckCast(bool strict)
// Caster aura req check if need // Caster aura req check if need
if(m_spellInfo->casterAuraSpell && !m_caster->HasAura(m_spellInfo->casterAuraSpell)) if(m_spellInfo->casterAuraSpell && !m_caster->HasAura(m_spellInfo->casterAuraSpell))
return SPELL_FAILED_CASTER_AURASTATE; return SPELL_FAILED_CASTER_AURASTATE;
if(m_spellInfo->excludeCasterAuraSpell && m_caster->HasAura(m_spellInfo->excludeCasterAuraSpell)) if(m_spellInfo->excludeCasterAuraSpell)
return SPELL_FAILED_CASTER_AURASTATE; {
// Special cases of non existing auras handling
if(m_spellInfo->excludeCasterAuraSpell == 61988)
{
if(m_caster->HasAura(61987))
return SPELL_FAILED_CASTER_AURASTATE;
}
else if(m_caster->HasAura(m_spellInfo->excludeCasterAuraSpell))
return SPELL_FAILED_CASTER_AURASTATE;
}
// cancel autorepeat spells if cast start when moving // cancel autorepeat spells if cast start when moving
// (not wand currently autorepeat cast delayed to moving stop anyway in spell update code) // (not wand currently autorepeat cast delayed to moving stop anyway in spell update code)
@ -4093,6 +4112,14 @@ SpellCastResult Spell::CheckCast(bool strict)
break; 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: case SPELL_EFFECT_FEED_PET:
{ {
if (m_caster->GetTypeId() != TYPEID_PLAYER) if (m_caster->GetTypeId() != TYPEID_PLAYER)
@ -4356,8 +4383,13 @@ SpellCastResult Spell::CheckCast(bool strict)
break; break;
} }
case SPELL_AURA_MOD_POSSESS: case SPELL_AURA_MOD_POSSESS:
case SPELL_AURA_MOD_CHARM:
{ {
if(m_caster->GetTypeId() != TYPEID_PLAYER)
return SPELL_FAILED_UNKNOWN;
if(m_targets.getUnitTarget() == m_caster)
return SPELL_FAILED_BAD_TARGETS;
if(m_caster->GetPetGUID()) if(m_caster->GetPetGUID())
return SPELL_FAILED_ALREADY_HAVE_SUMMON; return SPELL_FAILED_ALREADY_HAVE_SUMMON;
@ -4378,6 +4410,51 @@ SpellCastResult Spell::CheckCast(bool strict)
break; break;
} }
case SPELL_AURA_MOD_CHARM:
{
if(m_targets.getUnitTarget() == m_caster)
return SPELL_FAILED_BAD_TARGETS;
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;
if(!m_targets.getUnitTarget())
return SPELL_FAILED_BAD_IMPLICIT_TARGETS;
if(m_targets.getUnitTarget()->GetCharmerGUID())
return SPELL_FAILED_CHARMED;
if(int32(m_targets.getUnitTarget()->getLevel()) > CalculateDamage(i,m_targets.getUnitTarget()))
return SPELL_FAILED_HIGHLEVEL;
break;
}
case SPELL_AURA_MOD_POSSESS_PET:
{
if(m_caster->GetTypeId() != TYPEID_PLAYER)
return SPELL_FAILED_UNKNOWN;
if(m_caster->GetCharmGUID())
return SPELL_FAILED_ALREADY_HAVE_CHARM;
if(m_caster->GetCharmerGUID())
return SPELL_FAILED_CHARMED;
Pet* pet = m_caster->GetPet();
if(!pet)
return SPELL_FAILED_NO_PET;
if(pet->GetCharmerGUID())
return SPELL_FAILED_CHARMED;
break;
}
case SPELL_AURA_MOUNTED: case SPELL_AURA_MOUNTED:
{ {
if (m_caster->IsInWater()) if (m_caster->IsInWater())

View file

@ -399,7 +399,6 @@ class Spell
Item* m_CastItem; Item* m_CastItem;
uint8 m_cast_count; uint8 m_cast_count;
uint32 m_glyphIndex; uint32 m_glyphIndex;
uint32 m_preCastSpell;
SpellCastTargets m_targets; SpellCastTargets m_targets;
int32 GetCastTime() const { return m_casttime; } int32 GetCastTime() const { return m_casttime; }
@ -440,6 +439,7 @@ class Spell
bool CheckTargetCreatureType(Unit* target) const; bool CheckTargetCreatureType(Unit* target) const;
void AddTriggeredSpell(SpellEntry const* spell) { m_TriggerSpells.push_back(spell); } void AddTriggeredSpell(SpellEntry const* spell) { m_TriggerSpells.push_back(spell); }
void AddPrecastSpell(uint32 spellId) { m_preCastSpells.push_back(spellId); }
void CleanupTargetList(); void CleanupTargetList();
protected: protected:
@ -559,7 +559,9 @@ class Spell
//List For Triggered Spells //List For Triggered Spells
typedef std::list<SpellEntry const*> TriggerSpells; typedef std::list<SpellEntry const*> TriggerSpells;
typedef std::list<uint32> SpellPrecasts;
TriggerSpells m_TriggerSpells; TriggerSpells m_TriggerSpells;
SpellPrecasts m_preCastSpells;
uint32 m_spellState; uint32 m_spellState;
uint32 m_timer; uint32 m_timer;

View file

@ -328,7 +328,7 @@ enum AuraType
SPELL_AURA_MOD_HEALING_RECEIVED = 283, // Possibly only for some spell family class spells SPELL_AURA_MOD_HEALING_RECEIVED = 283, // Possibly only for some spell family class spells
SPELL_AURA_284, SPELL_AURA_284,
SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR = 285, SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR = 285,
SPELL_AURA_286, SPELL_AURA_ABILITY_PERIODIC_CRIT = 286,
SPELL_AURA_DEFLECT_SPELLS, SPELL_AURA_DEFLECT_SPELLS,
SPELL_AURA_288, SPELL_AURA_288,
SPELL_AURA_289, SPELL_AURA_289,

View file

@ -336,7 +336,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=
&Aura::HandleNoImmediateEffect, //283 SPELL_AURA_MOD_HEALING_RECEIVED implemented in Unit::SpellHealingBonus &Aura::HandleNoImmediateEffect, //283 SPELL_AURA_MOD_HEALING_RECEIVED implemented in Unit::SpellHealingBonus
&Aura::HandleUnused, //284 not used by any spells (3.08a) &Aura::HandleUnused, //284 not used by any spells (3.08a)
&Aura::HandleAuraModAttackPowerOfArmor, //285 SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR implemented in Player::UpdateAttackPowerAndDamage &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 Aura::IsCritFromAbilityAura called from Aura::PeriodicTick
&Aura::HandleNoImmediateEffect, //287 SPELL_AURA_DEFLECT_SPELLS implemented in Unit::MagicSpellHitResult and Unit::MeleeSpellHitResult &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 not used by any spells (3.09) except 1 test spell.
&Aura::HandleUnused, //289 unused &Aura::HandleUnused, //289 unused
@ -1178,23 +1178,32 @@ void Aura::SendAuraUpdate(bool remove)
void Aura::SetStackAmount(uint8 stackAmount) void Aura::SetStackAmount(uint8 stackAmount)
{ {
if (stackAmount != m_stackAmount) if (stackAmount == m_stackAmount)
// Nothing changed
return;
Unit *target = GetTarget();
Unit *caster = GetCaster();
if (!target || !caster)
return;
bool refresh = stackAmount > m_stackAmount;
m_stackAmount = stackAmount;
int32 amount = m_stackAmount * caster->CalculateSpellDamage(m_spellProto, m_effIndex, m_currentBasePoints, target);
// Reapply if amount change
if (amount!=m_modifier.m_amount)
{ {
Unit *target = GetTarget(); ApplyModifier(false, true);
Unit *caster = GetCaster(); m_modifier.m_amount = amount;
if (!target || !caster) ApplyModifier(true, true);
return;
m_stackAmount = stackAmount;
int32 amount = m_stackAmount * caster->CalculateSpellDamage(m_spellProto, m_effIndex, m_currentBasePoints, target);
// Reapply if amount change
if (amount!=m_modifier.m_amount)
{
ApplyModifier(false, true);
m_modifier.m_amount = amount;
ApplyModifier(true, true);
}
} }
RefreshAura();
if (refresh)
// Stack increased refresh duration
RefreshAura();
else
// Stack decreased only send update
SendAuraUpdate(false);
} }
bool Aura::modStackAmount(int32 num) bool Aura::modStackAmount(int32 num)
@ -3065,33 +3074,33 @@ void Aura::HandleModPossess(bool apply, bool Real)
if(!Real) if(!Real)
return; return;
if(m_target->getLevel() > m_modifier.m_amount)
return;
// not possess yourself // not possess yourself
if(GetCasterGUID() == m_target->GetGUID()) if(GetCasterGUID() == m_target->GetGUID())
return; return;
Unit* caster = GetCaster(); Unit* caster = GetCaster();
if(!caster) if(!caster || caster->GetTypeId() != TYPEID_PLAYER)
return; return;
Player* p_caster = (Player*)caster;
if( apply ) if( apply )
{ {
m_target->SetCharmerGUID(GetCasterGUID()); m_target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
m_target->setFaction(caster->getFaction());
caster->SetCharm(m_target); m_target->SetCharmerGUID(p_caster->GetGUID());
m_target->setFaction(p_caster->getFaction());
if(caster->GetTypeId() == TYPEID_PLAYER) p_caster->SetCharm(m_target);
{
((Player*)caster)->SetFarSightGUID(m_target->GetGUID()); p_caster->SetFarSightGUID(m_target->GetGUID());
((Player*)caster)->SetClientControl(m_target, 1); p_caster->SetClientControl(m_target, 1);
((Player*)caster)->SetMover(m_target); p_caster->SetMover(m_target);
}
m_target->CombatStop(); m_target->CombatStop();
m_target->DeleteThreatList(); m_target->DeleteThreatList();
if(m_target->GetTypeId() == TYPEID_UNIT) if(m_target->GetTypeId() == TYPEID_UNIT)
{ {
m_target->StopMoving(); m_target->StopMoving();
@ -3106,13 +3115,14 @@ void Aura::HandleModPossess(bool apply, bool Real)
if(CharmInfo *charmInfo = m_target->InitCharmInfo(m_target)) if(CharmInfo *charmInfo = m_target->InitCharmInfo(m_target))
charmInfo->InitPossessCreateSpells(); charmInfo->InitPossessCreateSpells();
if(caster->GetTypeId() == TYPEID_PLAYER) p_caster->PossessSpellInitialize();
((Player*)caster)->PossessSpellInitialize();
} }
else else
{ {
m_target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
m_target->SetCharmerGUID(0); m_target->SetCharmerGUID(0);
caster->InterruptSpell(CURRENT_CHANNELED_SPELL); // the spell is not automatically canceled when interrupted, do it now p_caster->InterruptSpell(CURRENT_CHANNELED_SPELL); // the spell is not automatically canceled when interrupted, do it now
if(m_target->GetTypeId() == TYPEID_PLAYER) if(m_target->GetTypeId() == TYPEID_PLAYER)
{ {
@ -3125,18 +3135,13 @@ void Aura::HandleModPossess(bool apply, bool Real)
m_target->setFaction(cinfo->faction_A); m_target->setFaction(cinfo->faction_A);
} }
caster->SetCharm(NULL); p_caster->SetCharm(NULL);
if(caster->GetTypeId() == TYPEID_PLAYER) p_caster->SetFarSightGUID(0);
{ p_caster->SetClientControl(m_target, 0);
((Player*)caster)->SetFarSightGUID(0); p_caster->SetMover(NULL);
((Player*)caster)->SetClientControl(m_target, 0);
((Player*)caster)->SetMover(NULL);
WorldPacket data(SMSG_PET_SPELLS, 8); p_caster->RemovePetActionBar();
data << uint64(0);
((Player*)caster)->GetSession()->SendPacket(&data);
}
if(m_target->GetTypeId() == TYPEID_UNIT) if(m_target->GetTypeId() == TYPEID_UNIT)
{ {
@ -3161,14 +3166,16 @@ void Aura::HandleModPossessPet(bool apply, bool Real)
if(!pet || pet != m_target) if(!pet || pet != m_target)
return; return;
if(apply) Player* p_caster = (Player*)caster;
pet->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_24);
else
pet->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_24);
((Player*)caster)->SetFarSightGUID(apply ? pet->GetGUID() : 0); if(apply)
((Player*)caster)->SetCharm(apply ? pet : NULL); pet->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
((Player*)caster)->SetClientControl(pet, apply ? 1 : 0); else
pet->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
p_caster->SetFarSightGUID(apply ? pet->GetGUID() : 0);
p_caster->SetCharm(apply ? pet : NULL);
p_caster->SetClientControl(pet, apply ? 1 : 0);
((Player*)caster)->SetMover(apply ? pet : NULL); ((Player*)caster)->SetMover(apply ? pet : NULL);
if(apply) if(apply)
@ -3208,100 +3215,92 @@ void Aura::HandleModCharm(bool apply, bool Real)
if(!caster) if(!caster)
return; return;
if(int32(m_target->getLevel()) <= m_modifier.m_amount) if( apply )
{ {
if( apply ) m_target->SetCharmerGUID(GetCasterGUID());
m_target->setFaction(caster->getFaction());
m_target->CastStop(m_target == caster ? GetId() : 0);
caster->SetCharm(m_target);
m_target->CombatStop();
m_target->DeleteThreatList();
if(m_target->GetTypeId() == TYPEID_UNIT)
{ {
m_target->SetCharmerGUID(GetCasterGUID()); ((Creature*)m_target)->AIM_Initialize();
m_target->setFaction(caster->getFaction()); CharmInfo *charmInfo = m_target->InitCharmInfo(m_target);
m_target->CastStop(m_target == caster ? GetId() : 0); charmInfo->InitCharmCreateSpells();
caster->SetCharm(m_target); charmInfo->SetReactState( REACT_DEFENSIVE );
m_target->CombatStop(); if(caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK)
m_target->DeleteThreatList();
if(m_target->GetTypeId() == TYPEID_UNIT)
{
((Creature*)m_target)->AIM_Initialize();
CharmInfo *charmInfo = m_target->InitCharmInfo(m_target);
charmInfo->InitCharmCreateSpells();
charmInfo->SetReactState( REACT_DEFENSIVE );
if(caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK)
{
CreatureInfo const *cinfo = ((Creature*)m_target)->GetCreatureInfo();
if(cinfo && cinfo->type == CREATURE_TYPE_DEMON)
{
//does not appear to have relevance. Why code added initially? See note below at !apply
//to prevent client crash
//m_target->SetFlag(UNIT_FIELD_BYTES_0, 2048);
//just to enable stat window
charmInfo->SetPetNumber(objmgr.GeneratePetNumber(), true);
//if charmed two demons the same session, the 2nd gets the 1st one's name
m_target->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
}
}
}
if(caster->GetTypeId() == TYPEID_PLAYER)
{
((Player*)caster)->CharmSpellInitialize();
}
}
else
{
m_target->SetCharmerGUID(0);
if(m_target->GetTypeId() == TYPEID_PLAYER)
((Player*)m_target)->setFactionForRace(m_target->getRace());
else
{ {
CreatureInfo const *cinfo = ((Creature*)m_target)->GetCreatureInfo(); CreatureInfo const *cinfo = ((Creature*)m_target)->GetCreatureInfo();
if(cinfo && cinfo->type == CREATURE_TYPE_DEMON)
// restore faction
if(((Creature*)m_target)->isPet())
{ {
if(Unit* owner = m_target->GetOwner()) //does not appear to have relevance. Why code added initially? See note below at !apply
m_target->setFaction(owner->getFaction()); //to prevent client crash
else if(cinfo) //m_target->SetFlag(UNIT_FIELD_BYTES_0, 2048);
m_target->setFaction(cinfo->faction_A); //just to enable stat window
charmInfo->SetPetNumber(objmgr.GeneratePetNumber(), true);
//if charmed two demons the same session, the 2nd gets the 1st one's name
m_target->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
} }
else if(cinfo) // normal creature }
}
if(caster->GetTypeId() == TYPEID_PLAYER)
((Player*)caster)->CharmSpellInitialize();
}
else
{
m_target->SetCharmerGUID(0);
if(m_target->GetTypeId() == TYPEID_PLAYER)
((Player*)m_target)->setFactionForRace(m_target->getRace());
else
{
CreatureInfo const *cinfo = ((Creature*)m_target)->GetCreatureInfo();
// restore faction
if(((Creature*)m_target)->isPet())
{
if(Unit* owner = m_target->GetOwner())
m_target->setFaction(owner->getFaction());
else if(cinfo)
m_target->setFaction(cinfo->faction_A); m_target->setFaction(cinfo->faction_A);
// restore UNIT_FIELD_BYTES_0
if(cinfo && caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK && cinfo->type == CREATURE_TYPE_DEMON)
{
//does not appear to have relevance. Why code added initially? Class, gender, powertype should be same.
//db field removed and replaced with better way to set class, restore using this if problems
/*CreatureDataAddon const *cainfo = ((Creature*)m_target)->GetCreatureAddon();
if(cainfo && cainfo->bytes0 != 0)
m_target->SetUInt32Value(UNIT_FIELD_BYTES_0, cainfo->bytes0);
else
m_target->RemoveFlag(UNIT_FIELD_BYTES_0, 2048);*/
if(m_target->GetCharmInfo())
m_target->GetCharmInfo()->SetPetNumber(0, true);
else
sLog.outError("Aura::HandleModCharm: target (GUID: %u TypeId: %u) has a charm aura but no charm info!", m_target->GetGUIDLow(), m_target->GetTypeId());
}
} }
else if(cinfo) // normal creature
m_target->setFaction(cinfo->faction_A);
caster->SetCharm(NULL); // restore UNIT_FIELD_BYTES_0
if(cinfo && caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK && cinfo->type == CREATURE_TYPE_DEMON)
if(caster->GetTypeId() == TYPEID_PLAYER)
{ {
WorldPacket data(SMSG_PET_SPELLS, 8); //does not appear to have relevance. Why code added initially? Class, gender, powertype should be same.
data << uint64(0); //db field removed and replaced with better way to set class, restore using this if problems
((Player*)caster)->GetSession()->SendPacket(&data); /*CreatureDataAddon const *cainfo = ((Creature*)m_target)->GetCreatureAddon();
} if(cainfo && cainfo->bytes0 != 0)
if(m_target->GetTypeId() == TYPEID_UNIT) m_target->SetUInt32Value(UNIT_FIELD_BYTES_0, cainfo->bytes0);
{ else
((Creature*)m_target)->AIM_Initialize(); m_target->RemoveFlag(UNIT_FIELD_BYTES_0, 2048);*/
if (((Creature*)m_target)->AI())
((Creature*)m_target)->AI()->AttackedBy(caster); if(m_target->GetCharmInfo())
m_target->GetCharmInfo()->SetPetNumber(0, true);
else
sLog.outError("Aura::HandleModCharm: target (GUID: %u TypeId: %u) has a charm aura but no charm info!", m_target->GetGUIDLow(), m_target->GetTypeId());
} }
} }
caster->SetCharm(NULL);
if(caster->GetTypeId() == TYPEID_PLAYER)
((Player*)caster)->RemovePetActionBar();
if(m_target->GetTypeId() == TYPEID_UNIT)
{
((Creature*)m_target)->AIM_Initialize();
if (((Creature*)m_target)->AI())
((Creature*)m_target)->AI()->AttackedBy(caster);
}
} }
} }
@ -5887,6 +5886,9 @@ void Aura::PeriodicTick()
else else
pdamage = uint32(m_target->GetMaxHealth()*amount/100); pdamage = uint32(m_target->GetMaxHealth()*amount/100);
// This method can modify pdamage
bool isCrit = IsCritFromAbilityAura(pCaster, pdamage);
// As of 2.2 resilience reduces damage from DoT ticks as much as the chance to not be critically hit // 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 // Reduce dot damage from resilience for players
if (m_target->GetTypeId() == TYPEID_PLAYER) if (m_target->GetTypeId() == TYPEID_PLAYER)
@ -5899,7 +5901,7 @@ void Aura::PeriodicTick()
pCaster->DealDamageMods(m_target, pdamage, &absorb); pCaster->DealDamageMods(m_target, pdamage, &absorb);
SpellPeriodicAuraLogInfo pInfo(this, pdamage, 0, absorb, resist, 0.0f); SpellPeriodicAuraLogInfo pInfo(this, pdamage, 0, absorb, resist, 0.0f, isCrit);
m_target->SendPeriodicAuraLog(&pInfo); m_target->SendPeriodicAuraLog(&pInfo);
Unit* target = m_target; // aura can be deleted in DealDamage Unit* target = m_target; // aura can be deleted in DealDamage
@ -6021,10 +6023,13 @@ void Aura::PeriodicTick()
pdamage = pCaster->SpellHealingBonus(m_target, GetSpellProto(), pdamage, DOT, GetStackAmount()); pdamage = pCaster->SpellHealingBonus(m_target, GetSpellProto(), pdamage, DOT, GetStackAmount());
// This method can modify pdamage
bool isCrit = IsCritFromAbilityAura(pCaster, pdamage);
sLog.outDetail("PeriodicTick: %u (TypeId: %u) heal of %u (TypeId: %u) for %u health inflicted by %u", 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()); GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), m_target->GetGUIDLow(), m_target->GetTypeId(), pdamage, GetId());
SpellPeriodicAuraLogInfo pInfo(this, pdamage, 0, 0, 0, 0.0f); SpellPeriodicAuraLogInfo pInfo(this, pdamage, 0, 0, 0, 0.0f, isCrit);
m_target->SendPeriodicAuraLog(&pInfo); m_target->SendPeriodicAuraLog(&pInfo);
int32 gain = m_target->ModifyHealth(pdamage); int32 gain = m_target->ModifyHealth(pdamage);
@ -6912,3 +6917,19 @@ void Aura::HandleAuraSafeFall( bool Apply, bool Real )
if(Apply && Real && GetId() == 32474 && m_target->GetTypeId() == TYPEID_PLAYER) if(Apply && Real && GetId() == 32474 && m_target->GetTypeId() == TYPEID_PLAYER)
((Player*)m_target)->ActivateTaxiPathTo(506, GetId()); ((Player*)m_target)->ActivateTaxiPathTo(506, GetId());
} }
bool Aura::IsCritFromAbilityAura(Unit* caster, uint32& damage)
{
Unit::AuraList const& auras = caster->GetAurasByType(SPELL_AURA_ABILITY_PERIODIC_CRIT);
for(Unit::AuraList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
{
if (!(*itr)->isAffectedOnSpell(m_spellProto))
continue;
if (!caster->isSpellCrit(m_target, m_spellProto, GetSpellSchoolMask(m_spellProto)))
break;
damage = caster->SpellCriticalDamageBonus(m_spellProto, damage, m_target);
return true;
}
return false;
}

View file

@ -325,6 +325,8 @@ class MANGOS_DLL_SPEC Aura
protected: protected:
Aura(SpellEntry const* spellproto, uint32 eff, int32 *currentBasePoints, Unit *target, Unit *caster = NULL, Item* castItem = NULL); Aura(SpellEntry const* spellproto, uint32 eff, int32 *currentBasePoints, Unit *target, Unit *caster = NULL, Item* castItem = NULL);
bool IsCritFromAbilityAura(Unit* caster, uint32& damage);
Modifier m_modifier; Modifier m_modifier;
SpellModifier *m_spellmod; SpellModifier *m_spellmod;

View file

@ -1187,21 +1187,19 @@ void Spell::EffectDummy(uint32 i)
return; return;
// immediately finishes the cooldown on Frost spells // immediately finishes the cooldown on Frost spells
const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap(); const SpellCooldowns& cm = ((Player *)m_caster)->GetSpellCooldownMap();
for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();)
{ {
if (itr->second->state == PLAYERSPELL_REMOVED) SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
continue;
uint32 classspell = itr->first;
SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
if( spellInfo->SpellFamilyName == SPELLFAMILY_MAGE && if( spellInfo->SpellFamilyName == SPELLFAMILY_MAGE &&
(GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) && (GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) &&
spellInfo->Id != 11958 && GetSpellRecoveryTime(spellInfo) > 0 ) spellInfo->Id != 11958 && GetSpellRecoveryTime(spellInfo) > 0 )
{ {
((Player*)m_caster)->RemoveSpellCooldown(classspell, true); ((Player*)m_caster)->RemoveSpellCooldown((itr++)->first, true);
} }
else
++itr;
} }
return; return;
} }
@ -1436,14 +1434,15 @@ void Spell::EffectDummy(uint32 i)
return; return;
//immediately finishes the cooldown on certain Rogue abilities //immediately finishes the cooldown on certain Rogue abilities
const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap(); const SpellCooldowns& cm = ((Player *)m_caster)->GetSpellCooldownMap();
for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();)
{ {
uint32 classspell = itr->first; SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags & UI64LIT(0x0000024000000860))) if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags & UI64LIT(0x0000024000000860)))
((Player*)m_caster)->RemoveSpellCooldown(classspell,true); ((Player*)m_caster)->RemoveSpellCooldown((itr++)->first,true);
else
++itr;
} }
return; return;
} }
@ -1487,14 +1486,15 @@ void Spell::EffectDummy(uint32 i)
return; return;
//immediately finishes the cooldown for hunter abilities //immediately finishes the cooldown for hunter abilities
const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap(); const SpellCooldowns& cm = ((Player*)m_caster)->GetSpellCooldownMap();
for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();)
{ {
uint32 classspell = itr->first; SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && GetSpellRecoveryTime(spellInfo) > 0 ) 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; return;
} }
@ -2317,7 +2317,7 @@ void Spell::EffectUnlearnSpecialization( uint32 i )
_player->removeSpell(spellToUnlearn); _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) void Spell::EffectPowerDrain(uint32 i)
@ -3320,7 +3320,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]; 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); 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) void Spell::EffectDispel(uint32 i)
@ -4327,24 +4327,30 @@ void Spell::EffectWeaponDmg(uint32 i)
spell_bonus += m_caster->CalculateDamage (OFF_ATTACK, normalized); spell_bonus += m_caster->CalculateDamage (OFF_ATTACK, normalized);
} }
// Devastate bonus and sunder armor refresh // Devastate bonus and sunder armor refresh
else if(m_spellInfo->SpellVisual[0] == 671 && m_spellInfo->SpellIconID == 1508) else if(m_spellInfo->SpellVisual[0] == 12295 && m_spellInfo->SpellIconID == 1508)
{ {
uint32 stack = 0; uint32 stack = 0;
// Need refresh all Sunder Armor auras from this caster // Need refresh all Sunder Armor auras from this caster
Unit::AuraMap& suAuras = unitTarget->GetAuras(); Unit::AuraMap& suAuras = unitTarget->GetAuras();
SpellEntry const *spellInfo;
for(Unit::AuraMap::iterator itr = suAuras.begin(); itr != suAuras.end(); ++itr) for(Unit::AuraMap::iterator itr = suAuras.begin(); itr != suAuras.end(); ++itr)
{ {
SpellEntry const *spellInfo = (*itr).second->GetSpellProto(); spellInfo = (*itr).second->GetSpellProto();
if( spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR && if( spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR &&
(spellInfo->SpellFamilyFlags & UI64LIT(0x0000000000004000)) && (spellInfo->SpellFamilyFlags & UI64LIT(0x0000000000004000)) &&
(*itr).second->GetCasterGUID() == m_caster->GetGUID()) (*itr).second->GetCasterGUID() == m_caster->GetGUID())
{ {
(*itr).second->RefreshAura(); (*itr).second->RefreshAura();
stack = (*itr).second->GetStackAmount(); stack = (*itr).second->GetStackAmount();
break;
} }
} }
if (stack) if (stack)
spell_bonus += stack * CalculateDamage(2, unitTarget); spell_bonus += stack * CalculateDamage(2, unitTarget);
if (!stack || stack < spellInfo->StackAmount)
// Devastate causing Sunder Armor Effect
// and no need to cast over max stack amount
m_caster->CastSpell(unitTarget, 58567, true);
} }
break; break;
} }

View file

@ -27,6 +27,7 @@
#include "Spell.h" #include "Spell.h"
#include "ScriptCalls.h" #include "ScriptCalls.h"
#include "Totem.h" #include "Totem.h"
#include "SpellAuras.h"
void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket)
{ {
@ -377,10 +378,6 @@ void WorldSession::HandleCancelAuraOpcode( WorldPacket& recvPacket)
{ {
CHECK_PACKET_SIZE(recvPacket,4); CHECK_PACKET_SIZE(recvPacket,4);
// ignore for remote control state
if(_player->m_mover != _player)
return;
uint32 spellId; uint32 spellId;
recvPacket >> spellId; recvPacket >> spellId;
@ -388,10 +385,34 @@ void WorldSession::HandleCancelAuraOpcode( WorldPacket& recvPacket)
if (!spellInfo) if (!spellInfo)
return; return;
// not allow remove non positive spells and spells with attr SPELL_ATTR_CANT_CANCEL if (spellInfo->Attributes & SPELL_ATTR_CANT_CANCEL)
if(!IsPositiveSpell(spellId) || (spellInfo->Attributes & SPELL_ATTR_CANT_CANCEL))
return; return;
if(!IsPositiveSpell(spellId))
{
// ignore for remote control state
if (_player->m_mover != _player)
{
// except own aura spells
bool allow = false;
for(int k = 0; k < 3; ++k)
{
if (spellInfo->EffectApplyAuraName[k] == SPELL_AURA_MOD_POSSESS ||
spellInfo->EffectApplyAuraName[k] == SPELL_AURA_MOD_POSSESS_PET)
{
allow = true;
break;
}
}
// this also include case when aura not found
if(!allow)
return;
}
else
return;
}
// channeled spell case (it currently casted then) // channeled spell case (it currently casted then)
if (IsChanneledSpell(spellInfo)) if (IsChanneledSpell(spellInfo))
{ {

View file

@ -1126,7 +1126,7 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) cons
if(!spellInfo_1 || !spellInfo_2) if(!spellInfo_1 || !spellInfo_2)
return false; return false;
if(spellInfo_1->Id == spellId_2) if(spellId_1 == spellId_2)
return false; return false;
//I think we don't check this correctly because i need a exception for spell: //I think we don't check this correctly because i need a exception for spell:
@ -1193,6 +1193,11 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) cons
break; break;
} }
case SPELLFAMILY_MAGE:
// Arcane Intellect and Insight
if( spellInfo_2->SpellIconID == 125 && spellInfo_1->Id == 18820 )
return false;
break;
case SPELLFAMILY_WARRIOR: case SPELLFAMILY_WARRIOR:
{ {
// Scroll of Protection and Defensive Stance (multi-family check) // Scroll of Protection and Defensive Stance (multi-family check)
@ -1274,6 +1279,10 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) cons
if( spellInfo_1->Id == 11129 && spellInfo_2->SpellIconID == 33 && spellInfo_2->SpellVisual[0] == 321 ) if( spellInfo_1->Id == 11129 && spellInfo_2->SpellIconID == 33 && spellInfo_2->SpellVisual[0] == 321 )
return false; return false;
// Arcane Intellect and Insight
if( spellInfo_1->SpellIconID == 125 && spellInfo_2->Id == 18820 )
return false;
break; break;
case SPELLFAMILY_WARLOCK: case SPELLFAMILY_WARLOCK:
if( spellInfo_2->SpellFamilyName == SPELLFAMILY_WARLOCK ) if( spellInfo_2->SpellFamilyName == SPELLFAMILY_WARLOCK )

View file

@ -4278,13 +4278,13 @@ void Unit::SendPeriodicAuraLog(SpellPeriodicAuraLogInfo *pInfo)
data << uint32(GetSpellSchoolMask(aura->GetSpellProto())); data << uint32(GetSpellSchoolMask(aura->GetSpellProto()));
data << uint32(pInfo->absorb); // absorb data << uint32(pInfo->absorb); // absorb
data << uint32(pInfo->resist); // resist data << uint32(pInfo->resist); // resist
data << uint8(0); // new 3.1.2 data << uint8(pInfo->critical ? 1 : 0); // new 3.1.2 critical flag
break; break;
case SPELL_AURA_PERIODIC_HEAL: case SPELL_AURA_PERIODIC_HEAL:
case SPELL_AURA_OBS_MOD_HEALTH: case SPELL_AURA_OBS_MOD_HEALTH:
data << uint32(pInfo->damage); // damage data << uint32(pInfo->damage); // damage
data << uint32(pInfo->overDamage); // overheal? data << uint32(pInfo->overDamage); // overheal?
data << uint8(0); // new 3.1.2 data << uint8(pInfo->critical ? 1 : 0); // new 3.1.2 critical flag
break; break;
case SPELL_AURA_OBS_MOD_MANA: case SPELL_AURA_OBS_MOD_MANA:
case SPELL_AURA_PERIODIC_ENERGIZE: case SPELL_AURA_PERIODIC_ENERGIZE:
@ -5521,6 +5521,17 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
} }
return true; return true;
} }
// Judgements of the Wise
case 31876:
case 31877:
case 31878:
target = this;
basepoints0 = GetCreatePowers(POWER_MANA) * 25 / 100;
triggered_spell_id = 31930;
// Replenishment
CastSpell(this, 57669, true, NULL, triggeredByAura);
break;
// Holy Power (Redemption Armor set) // Holy Power (Redemption Armor set)
case 28789: case 28789:
{ {
@ -6767,6 +6778,14 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB
return false; return false;
break; break;
} }
// Sword and Board
case 50227:
{
// Remove cooldown on Shield Slam
if (GetTypeId() == TYPEID_PLAYER)
((Player*)this)->RemoveSpellCategoryCooldown(1209, true);
break;
}
// Brain Freeze // Brain Freeze
case 57761: case 57761:
{ {
@ -9788,7 +9807,8 @@ int32 Unit::CalculateSpellDamage(SpellEntry const* spellProto, uint8 effect_inde
if(spellProto->Attributes & SPELL_ATTR_LEVEL_DAMAGE_CALCULATION && spellProto->spellLevel && if(spellProto->Attributes & SPELL_ATTR_LEVEL_DAMAGE_CALCULATION && spellProto->spellLevel &&
spellProto->Effect[effect_index] != SPELL_EFFECT_WEAPON_PERCENT_DAMAGE && spellProto->Effect[effect_index] != SPELL_EFFECT_WEAPON_PERCENT_DAMAGE &&
spellProto->Effect[effect_index] != SPELL_EFFECT_KNOCK_BACK) spellProto->Effect[effect_index] != SPELL_EFFECT_KNOCK_BACK &&
(spellProto->Effect[effect_index] != SPELL_EFFECT_APPLY_AURA || spellProto->EffectApplyAuraName[effect_index] != SPELL_AURA_MOD_DECREASE_SPEED))
value = int32(value*0.25f*exp(getLevel()*(70-spellProto->spellLevel)/1000.0f)); value = int32(value*0.25f*exp(getLevel()*(70-spellProto->spellLevel)/1000.0f));
return value; return value;

View file

@ -514,7 +514,7 @@ enum UnitFlags
UNIT_FLAG_DISARMED = 0x00200000, // 3.0.3, disable melee spells casting..., "Required melee weapon" added to melee spells tooltip. UNIT_FLAG_DISARMED = 0x00200000, // 3.0.3, disable melee spells casting..., "Required melee weapon" added to melee spells tooltip.
UNIT_FLAG_CONFUSED = 0x00400000, UNIT_FLAG_CONFUSED = 0x00400000,
UNIT_FLAG_FLEEING = 0x00800000, UNIT_FLAG_FLEEING = 0x00800000,
UNIT_FLAG_UNK_24 = 0x01000000, // used in spell Eyes of the Beast for pet... UNIT_FLAG_PLAYER_CONTROLLED= 0x01000000, // used in spell Eyes of the Beast for pet... let attack by controlled creature
UNIT_FLAG_NOT_SELECTABLE = 0x02000000, UNIT_FLAG_NOT_SELECTABLE = 0x02000000,
UNIT_FLAG_SKINNABLE = 0x04000000, UNIT_FLAG_SKINNABLE = 0x04000000,
UNIT_FLAG_MOUNT = 0x08000000, UNIT_FLAG_MOUNT = 0x08000000,
@ -686,8 +686,8 @@ struct SpellNonMeleeDamage{
struct SpellPeriodicAuraLogInfo struct SpellPeriodicAuraLogInfo
{ {
SpellPeriodicAuraLogInfo(Aura *_aura, uint32 _damage, uint32 _overDamage, uint32 _absorb, uint32 _resist, float _multiplier) SpellPeriodicAuraLogInfo(Aura *_aura, uint32 _damage, uint32 _overDamage, uint32 _absorb, uint32 _resist, float _multiplier, bool _critical = false)
: aura(_aura), damage(_damage), overDamage(_overDamage), absorb(_absorb), resist(_resist), multiplier(_multiplier) {} : aura(_aura), damage(_damage), overDamage(_overDamage), absorb(_absorb), resist(_resist), multiplier(_multiplier), critical(_critical) {}
Aura *aura; Aura *aura;
uint32 damage; uint32 damage;
@ -695,6 +695,7 @@ struct SpellPeriodicAuraLogInfo
uint32 resist; uint32 resist;
uint32 overDamage; // overkill/overheal uint32 overDamage; // overkill/overheal
float multiplier; float multiplier;
bool critical;
}; };
uint32 createProcExtendMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition); uint32 createProcExtendMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition);

View file

@ -624,6 +624,27 @@ void World::LoadConfigSettings(bool reload)
m_configs[CONFIG_STRICT_CHARTER_NAMES] = sConfig.GetIntDefault ("StrictCharterNames", 0); m_configs[CONFIG_STRICT_CHARTER_NAMES] = sConfig.GetIntDefault ("StrictCharterNames", 0);
m_configs[CONFIG_STRICT_PET_NAMES] = sConfig.GetIntDefault ("StrictPetNames", 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_CREATING_DISABLED] = sConfig.GetIntDefault ("CharactersCreatingDisabled", 0);
m_configs[CONFIG_CHARACTERS_PER_REALM] = sConfig.GetIntDefault("CharactersPerRealm", 10); m_configs[CONFIG_CHARACTERS_PER_REALM] = sConfig.GetIntDefault("CharactersPerRealm", 10);

View file

@ -107,6 +107,9 @@ enum WorldConfigs
CONFIG_STRICT_PLAYER_NAMES, CONFIG_STRICT_PLAYER_NAMES,
CONFIG_STRICT_CHARTER_NAMES, CONFIG_STRICT_CHARTER_NAMES,
CONFIG_STRICT_PET_NAMES, CONFIG_STRICT_PET_NAMES,
CONFIG_MIN_PLAYER_NAME,
CONFIG_MIN_CHARTER_NAME,
CONFIG_MIN_PET_NAME,
CONFIG_CHARACTERS_CREATING_DISABLED, CONFIG_CHARACTERS_CREATING_DISABLED,
CONFIG_CHARACTERS_PER_ACCOUNT, CONFIG_CHARACTERS_PER_ACCOUNT,
CONFIG_CHARACTERS_PER_REALM, CONFIG_CHARACTERS_PER_REALM,

View file

@ -396,6 +396,18 @@ LogColors = ""
# (included in client by default, with active official localization or custom localization fonts in clientdir/Fonts). # (included in client by default, with active official localization or custom localization fonts in clientdir/Fonts).
# 3 basic latin characters + server timezone specific # 3 basic latin characters + server timezone specific
# #
# MinPlayerName
# Minimal name length (1..12)
# Default: 2
#
# MinCharterName
# Minimal name length (1..24)
# Default: 2
#
# MinPetName
# Minimal name length (1..12)
# Default: 2
#
# CharactersCreatingDisabled # CharactersCreatingDisabled
# Disable characters creating for specific team or any (non-player accounts not affected) # Disable characters creating for specific team or any (non-player accounts not affected)
# Default: 0 - enabled # Default: 0 - enabled
@ -579,6 +591,9 @@ DeclinedNames = 0
StrictPlayerNames = 0 StrictPlayerNames = 0
StrictCharterNames = 0 StrictCharterNames = 0
StrictPetNames = 0 StrictPetNames = 0
MinPlayerName = 2
MinCharterName = 2
MinPetName = 2
CharactersCreatingDisabled = 0 CharactersCreatingDisabled = 0
CharactersPerAccount = 50 CharactersPerAccount = 50
CharactersPerRealm = 10 CharactersPerRealm = 10

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__ #ifndef __REVISION_NR_H__
#define __REVISION_NR_H__ #define __REVISION_NR_H__
#define REVISION_NR "8118" #define REVISION_NR "8147"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__