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

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

View file

@ -112,13 +112,6 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction
if (pHolder.Event.event_inverse_phase_mask & (1 << Phase))
return false;
//Store random here so that all random actions match up
uint32 rnd = rand();
//Return if chance for event is not met
if (pHolder.Event.event_chance <= rnd % 100)
return false;
CreatureEventAI_Event const& event = pHolder.Event;
//Check event conditions based on the event type, also reset events
@ -330,6 +323,13 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction
if (!(pHolder.Event.event_flags & EFLAG_REPEATABLE))
pHolder.Enabled = false;
//Store random here so that all random actions match up
uint32 rnd = rand();
//Return if chance for event is not met
if (pHolder.Event.event_chance <= rnd % 100)
return false;
//Process actions
for (uint32 j = 0; j < MAX_ACTIONS; j++)
ProcessAction(pHolder.Event.action[j], rnd, pHolder.Event.event_id, pActionInvoker);

View file

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

View file

@ -65,7 +65,7 @@ typedef GridRefManager<GameObject> GameObjectMapType;
typedef GridRefManager<Player> PlayerMapType;
typedef Grid<Player, AllWorldObjectTypes,AllGridObjectTypes> GridType;
typedef NGrid<8, Player, AllWorldObjectTypes, AllGridObjectTypes> NGridType;
typedef NGrid<MAX_NUMBER_OF_CELLS, Player, AllWorldObjectTypes, AllGridObjectTypes> NGridType;
typedef TypeMapContainer<AllGridObjectTypes> GridTypeMapContainer;
typedef TypeMapContainer<AllWorldObjectTypes> WorldTypeMapContainer;

View file

@ -673,7 +673,31 @@ void WorldSession::HandleBuyItemInSlotOpcode( WorldPacket & recv_data )
recv_data >> vendorguid >> item >> slot >> bagguid >> bagslot >> count;
GetPlayer()->BuyItemFromVendor(vendorguid,item,count,bagguid,bagslot);
uint8 bag = NULL_BAG; // init for case invalid bagGUID
// find bag slot by bag guid
if (bagguid == _player->GetGUID())
bag = INVENTORY_SLOT_BAG_0;
else
{
for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END;++i)
{
if (Bag *pBag = (Bag*)_player->GetItemByPos(INVENTORY_SLOT_BAG_0,i))
{
if (bagguid == pBag->GetGUID())
{
bag = i;
break;
}
}
}
}
// bag not found, cheating?
if (bag == NULL_BAG)
return;
GetPlayer()->BuyItemFromVendor(vendorguid,item,count,bag,bagslot);
}
void WorldSession::HandleBuyItemOpcode( WorldPacket & recv_data )

View file

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

View file

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

View file

@ -762,38 +762,40 @@ void WorldSession::HandleQueryNextMailTime(WorldPacket & /*recv_data*/ )
{
data << (uint32) 0; // float
data << (uint32) 0; // count
uint32 count = 0;
time_t now = time(NULL);
for(PlayerMails::iterator itr = _player->GetmailBegin(); itr != _player->GetmailEnd(); ++itr)
{
Mail *m = (*itr);
// not checked yet, already must be delivered
if((m->checked & MAIL_CHECK_MASK_READ)==0 && (m->deliver_time <= time(NULL)))
// must be not checked yet
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;
if(count > 2)
{
count = 2;
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 << (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);
}

View file

@ -6645,18 +6645,24 @@ bool isValidString(std::wstring wstr, uint32 strictMask, bool numericOrSpace, bo
return false;
}
bool ObjectMgr::IsValidName( const std::string& name, bool create )
uint8 ObjectMgr::CheckPlayerName( const std::string& name, bool create )
{
std::wstring wname;
if(!Utf8toWStr(name,wname))
return false;
return CHAR_NAME_INVALID_CHARACTER;
if(wname.size() < 1 || wname.size() > MAX_PLAYER_NAME)
return false;
if(wname.size() > MAX_PLAYER_NAME)
return CHAR_NAME_TOO_LONG;
uint32 minName = sWorld.getConfig(CONFIG_MIN_PLAYER_NAME);
if(wname.size() < minName)
return CHAR_NAME_TOO_SHORT;
uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_PLAYER_NAMES);
return isValidString(wname,strictMask,false,create);
if(!isValidString(wname,strictMask,false,create))
return CHAR_NAME_MIXED_LANGUAGES;
return CHAR_NAME_SUCCESS;
}
bool ObjectMgr::IsValidCharterName( const std::string& name )
@ -6665,7 +6671,11 @@ bool ObjectMgr::IsValidCharterName( const std::string& name )
if(!Utf8toWStr(name,wname))
return false;
if(wname.size() < 1)
if(wname.size() > MAX_CHARTER_NAME)
return false;
uint32 minName = sWorld.getConfig(CONFIG_MIN_CHARTER_NAME);
if(wname.size() < minName)
return false;
uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_CHARTER_NAMES);
@ -6673,18 +6683,24 @@ bool ObjectMgr::IsValidCharterName( const std::string& name )
return isValidString(wname,strictMask,true);
}
bool ObjectMgr::IsValidPetName( const std::string& name )
PetNameInvalidReason ObjectMgr::CheckPetName( const std::string& name )
{
std::wstring wname;
if(!Utf8toWStr(name,wname))
return false;
return PET_NAME_INVALID;
if(wname.size() < 1)
return false;
if(wname.size() > MAX_PET_NAME)
return PET_NAME_TOO_LONG;
uint32 minName = sWorld.getConfig(CONFIG_MIN_PET_NAME);
if(wname.size() < minName)
return PET_NAME_TOO_SHORT;
uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_PET_NAMES);
if(!isValidString(wname,strictMask,false))
return PET_NAME_MIXED_LANGUAGES;
return isValidString(wname,strictMask,false);
return PET_NAME_SUCCESS;
}
int ObjectMgr::GetIndexForLocale( LocaleConstant loc )

View file

@ -279,8 +279,10 @@ enum SkillRangeType
SkillRangeType GetSkillRangeType(SkillLineEntry const *pSkill, bool racial);
#define MAX_PLAYER_NAME 12 // max allowed by client name length
#define MAX_PLAYER_NAME 12 // max allowed by client name length
#define MAX_INTERNAL_PLAYER_NAME 15 // max server internal player name length ( > MAX_PLAYER_NAME for support declined names )
#define MAX_PET_NAME 12 // max allowed by client name length
#define MAX_CHARTER_NAME 24 // max allowed by client name length
bool normalizePlayerName(std::string& name);
@ -693,9 +695,9 @@ class ObjectMgr
bool IsReservedName(const std::string& name) const;
// name with valid structure and symbols
static bool IsValidName( const std::string& name, bool create = false );
static uint8 CheckPlayerName( const std::string& name, bool create = false );
static PetNameInvalidReason CheckPetName( const std::string& name );
static bool IsValidCharterName( const std::string& name );
static bool IsValidPetName( const std::string& name );
static bool CheckDeclinedNames(std::wstring mainpart, DeclinedName const& names);

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(GetOwner()->GetTypeId() == TYPEID_PLAYER)
if(!m_loading)
{
if(!m_loading)
if (Unit* owner = GetOwner())
{
WorldPacket data(SMSG_PET_REMOVED_SPELL, 4);
data << uint32(spell_id);
((Player*)GetOwner())->GetSession()->SendPacket(&data);
if(owner->GetTypeId() == TYPEID_PLAYER)
{
WorldPacket data(SMSG_PET_REMOVED_SPELL, 4);
data << uint32(spell_id);
((Player*)owner)->GetSession()->SendPacket(&data);
}
}
}
return true;

View file

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

View file

@ -335,4 +335,4 @@ void PetAI::AttackedBy(Unit *attacker)
if(!m_creature->getVictim() && m_creature->GetCharmInfo() && !m_creature->GetCharmInfo()->HasReactState(REACT_PASSIVE) &&
(!m_creature->GetCharmInfo()->HasCommandState(COMMAND_STAY) || m_creature->canReachWithAttack(attacker)))
AttackStart(attacker);
}
}

View file

@ -401,9 +401,10 @@ void WorldSession::HandlePetRename( WorldPacket & recv_data )
pet->GetOwnerGUID() != _player->GetGUID() || !pet->GetCharmInfo() )
return;
if(!ObjectMgr::IsValidPetName(name))
PetNameInvalidReason res = ObjectMgr::CheckPetName(name);
if(res != PET_NAME_SUCCESS)
{
SendPetNameInvalid(PET_NAME_INVALID, name, NULL);
SendPetNameInvalid(res, name, NULL);
return;
}

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_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);
uint32 RaceClassGender = ( race ) | ( class_ << 8 ) | ( gender << 16 );
SetUInt32Value(UNIT_FIELD_BYTES_0, ( RaceClassGender | ( powertype << 24 ) ) );
InitDisplayIds();
SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP );
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE );
SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_REGENERATE_POWER);
@ -1412,7 +1397,7 @@ bool Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
PlayerInfo const *info = objmgr.GetPlayerInfo(pRace, pClass);
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;
}
@ -3354,6 +3339,22 @@ void Player::RemoveSpellCooldown( uint32 spell_id, bool update /* = false */ )
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()
{
// remove cooldowns on spells that has < 15 min CD
@ -3406,7 +3407,7 @@ void Player::_LoadSpellCooldowns(QueryResult *result)
if(!sSpellStore.LookupEntry(spell_id))
{
sLog.outError("Player %u have unknown spell %u in `character_spell_cooldown`, skipping.",GetGUIDLow(),spell_id);
sLog.outError("Player %u has unknown spell %u in `character_spell_cooldown`, skipping.",GetGUIDLow(),spell_id);
continue;
}
@ -12524,7 +12525,7 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
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);
}
@ -12532,12 +12533,12 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
// SetTimedQuest( 0 );
m_timedquests.erase(pQuest->GetQuestId());
if ( pQuest->GetRewChoiceItemsCount() > 0 )
if (pQuest->GetRewChoiceItemsCount() > 0)
{
if( pQuest->RewChoiceItemId[reward] )
if (pQuest->RewChoiceItemId[reward])
{
ItemPosCountVec dest;
if( CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, pQuest->RewChoiceItemId[reward], pQuest->RewChoiceItemCount[reward] ) == EQUIP_ERR_OK )
if (CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, pQuest->RewChoiceItemId[reward], pQuest->RewChoiceItemCount[reward] ) == EQUIP_ERR_OK)
{
Item* item = StoreNewItem( dest, pQuest->RewChoiceItemId[reward], true);
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)
{
if( pQuest->RewItemId[i] )
if (pQuest->RewItemId[i])
{
ItemPosCountVec dest;
if( CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, pQuest->RewItemId[i], pQuest->RewItemCount[i] ) == EQUIP_ERR_OK )
if (CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, pQuest->RewItemId[i], pQuest->RewItemCount[i] ) == EQUIP_ERR_OK)
{
Item* item = StoreNewItem( dest, pQuest->RewItemId[i], true);
SendNewItem(item, pQuest->RewItemCount[i], true, false);
@ -12563,13 +12564,8 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
RewardReputation( pQuest );
if( pQuest->GetRewSpellCast() > 0 )
CastSpell( this, pQuest->GetRewSpellCast(), true);
else if( pQuest->GetRewSpell() > 0)
CastSpell( this, pQuest->GetRewSpell(), true);
uint16 log_slot = FindQuestSlot( quest_id );
if( log_slot < MAX_QUEST_LOG_SIZE)
if (log_slot < MAX_QUEST_LOG_SIZE)
SetQuestSlot(log_slot,0);
QuestStatusData& q_status = mQuestStatus[quest_id];
@ -12577,7 +12573,7 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
// Not give XP in case already completed once repeatable quest
uint32 XP = q_status.m_rewarded ? 0 : uint32(pQuest->XPValue( this )*sWorld.getRate(RATE_XP_QUEST));
if ( getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) )
if (getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
GiveXP( XP , NULL );
else
{
@ -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
if(pQuest->GetRewOrReqMoney())
if (pQuest->GetRewOrReqMoney())
{
ModifyMoney( pQuest->GetRewOrReqMoney() );
if(pQuest->GetRewOrReqMoney() > 0)
if (pQuest->GetRewOrReqMoney() > 0)
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD, pQuest->GetRewOrReqMoney());
}
// honor reward
if(pQuest->GetRewHonorableKills())
if (pQuest->GetRewHonorableKills())
RewardHonor(NULL, 0, MaNGOS::Honor::hk_honor_at_level(getLevel(), pQuest->GetRewHonorableKills()));
// title reward
if(pQuest->GetCharTitleId())
if (pQuest->GetCharTitleId())
{
if(CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(pQuest->GetCharTitleId()))
if (CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(pQuest->GetCharTitleId()))
SetTitle(titleEntry);
}
if(pQuest->GetBonusTalents())
if (pQuest->GetBonusTalents())
{
m_questRewardTalentCount+=pQuest->GetBonusTalents();
InitTalentForLevel();
}
// Send reward mail
if(pQuest->GetRewMailTemplateId())
if (pQuest->GetRewMailTemplateId())
{
MailMessageType mailType;
uint32 senderGuidOrEntry;
@ -12651,9 +12647,9 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
uint32 max_slot = questMailLoot.GetMaxSlotInLootFor(this);
for(uint32 i = 0; mi.size() < MAX_MAIL_ITEMS && i < max_slot; ++i)
{
if(LootItem* lootitem = questMailLoot.LootItemInSlot(i,this))
if (LootItem* lootitem = questMailLoot.LootItemInSlot(i,this))
{
if(Item* item = Item::CreateItem(lootitem->itemid,lootitem->count,this))
if (Item* item = Item::CreateItem(lootitem->itemid,lootitem->count,this))
{
item->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted
mi.AddItem(item->GetGUIDLow(), item->GetEntry(), item);
@ -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());
}
if(pQuest->IsDaily())
if (pQuest->IsDaily())
{
SetDailyQuestStatus(quest_id);
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST, 1);
}
if ( !pQuest->IsRepeatable() )
if (!pQuest->IsRepeatable())
SetQuestStatus(quest_id, QUEST_STATUS_COMPLETE);
else
SetQuestStatus(quest_id, QUEST_STATUS_NONE);
q_status.m_rewarded = true;
if (q_status.uState != QUEST_NEW)
q_status.uState = QUEST_CHANGED;
if(announce)
if (announce)
SendQuestReward( pQuest, XP, questGiver );
if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED;
// cast spells after mark quest complete (some spells have quest completed state reqyurements in spell_area data)
if (pQuest->GetRewSpellCast() > 0)
CastSpell( this, pQuest->GetRewSpellCast(), true);
else if ( pQuest->GetRewSpell() > 0)
CastSpell( this, pQuest->GetRewSpell(), true);
if (pQuest->GetZoneOrSort() > 0)
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE, pQuest->GetZoneOrSort());
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT);
@ -14028,7 +14031,8 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
m_name = fields[3].GetCppString();
// check name limitations
if(!ObjectMgr::IsValidName(m_name) || (GetSession()->GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(m_name)))
if (ObjectMgr::CheckPlayerName(m_name) != CHAR_NAME_SUCCESS ||
GetSession()->GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(m_name))
{
delete result;
CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE guid ='%u'", uint32(AT_LOGIN_RENAME),guid);
@ -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_FLAGS, fields[12].GetUInt32());
InitDisplayIds();
// cleanup inventory related item value fields (its will be filled correctly in _LoadInventory)
for(uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
{
@ -14921,7 +14927,7 @@ void Player::_LoadMailedItems(Mail *mail)
if(!proto)
{
sLog.outError( "Player %u have unknown item_template (ProtoType) in mailed items(GUID: %u template: %u) in mail (%u), deleted.", GetGUIDLow(), item_guid_low, item_template,mail->messageID);
sLog.outError( "Player %u has unknown item_template (ProtoType) in mailed items(GUID: %u template: %u) in mail (%u), deleted.", GetGUIDLow(), item_guid_low, item_template,mail->messageID);
CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid = '%u'", item_guid_low);
CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", item_guid_low);
continue;
@ -15514,7 +15520,6 @@ void Player::SaveToDB()
SetByteValue(UNIT_FIELD_BYTES_1, 0, UNIT_STAND_STATE_STAND);
SetByteValue(UNIT_FIELD_BYTES_2, 3, 0); // shapeshift
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
SetDisplayId(GetNativeDisplayId());
bool inworld = IsInWorld();
@ -15659,7 +15664,6 @@ void Player::SaveToDB()
CharacterDatabase.CommitTransaction();
// restore state (before aura apply, if aura remove flag then aura must set it ack by self)
SetDisplayId(tmp_displayid);
SetUInt32Value(UNIT_FIELD_BYTES_1, tmp_bytes);
SetUInt32Value(UNIT_FIELD_BYTES_2, tmp_bytes2);
SetUInt32Value(UNIT_FIELD_FLAGS, tmp_flags);
@ -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)
{
// 0 1 2 3 4
QueryResult* result = CharacterDatabase.PQuery("SELECT data, race, class, playerBytes, playerBytes2 FROM characters WHERE guid = '%u'", GUID_LOPART(guid));
// 0
QueryResult* result = CharacterDatabase.PQuery("SELECT playerBytes2 FROM characters WHERE guid = '%u'", GUID_LOPART(guid));
if(!result)
return;
Field* fields = result->Fetch();
Tokens tokens = StrSplit(fields[0].GetString(), " ");
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();
uint32 player_bytes2 = fields[0].GetUInt32();
player_bytes2 &= ~0xFF;
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));
delete result;
@ -16379,9 +16372,7 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent)
if(pet->isControlled())
{
WorldPacket data(SMSG_PET_SPELLS, 8);
data << uint64(0);
GetSession()->SendPacket(&data);
RemovePetActionBar();
if(GetGroup())
SetGroupUpdateFlag(GROUP_UPDATE_PET);
@ -16643,6 +16634,13 @@ void Player::CharmSpellInitialize()
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)
{
if (!mod || !spellInfo)
@ -17156,17 +17154,43 @@ void Player::InitDataForForm(bool reapplyMods)
UpdateAttackPowerAndDamage(true);
}
void Player::InitDisplayIds()
{
PlayerInfo const *info = objmgr.GetPlayerInfo(getRace(), getClass());
if(!info)
{
sLog.outError("Player %u has incorrect race/class pair. Can't init display ids.", GetGUIDLow());
return;
}
uint8 gender = getGender();
switch(gender)
{
case GENDER_FEMALE:
SetDisplayId(info->displayId_f );
SetNativeDisplayId(info->displayId_f );
break;
case GENDER_MALE:
SetDisplayId(info->displayId_m );
SetNativeDisplayId(info->displayId_m );
break;
default:
sLog.outError("Invalid gender %u for player",gender);
return;
}
}
// Return true is the bought item has a max count to force refresh of window by caller
bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint64 bagguid, uint8 slot)
bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint8 bag, uint8 slot)
{
// cheating attempt
if(count < 1) count = 1;
if (count < 1) count = 1;
if(!isAlive())
if (!isAlive())
return false;
ItemPrototype const *pProto = objmgr.GetItemPrototype( item );
if( !pProto )
if (!pProto)
{
SendBuyError( BUY_ERR_CANT_FIND_ITEM, NULL, item, 0);
return false;
@ -17188,7 +17212,7 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
}
size_t vendor_slot = vItems->FindItemSlot(item);
if(vendor_slot >= vItems->GetItemCount())
if (vendor_slot >= vItems->GetItemCount())
{
SendBuyError( BUY_ERR_CANT_FIND_ITEM, pCreature, item, 0);
return false;
@ -17197,39 +17221,39 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
VendorItem const* crItem = vItems->m_items[vendor_slot];
// check current item amount if it limited
if( crItem->maxcount != 0 )
if (crItem->maxcount != 0)
{
if(pCreature->GetVendorItemCurrentCount(crItem) < pProto->BuyCount * count )
if (pCreature->GetVendorItemCurrentCount(crItem) < pProto->BuyCount * count )
{
SendBuyError( BUY_ERR_ITEM_ALREADY_SOLD, pCreature, item, 0);
return false;
}
}
if( uint32(GetReputationRank(pProto->RequiredReputationFaction)) < pProto->RequiredReputationRank)
if (uint32(GetReputationRank(pProto->RequiredReputationFaction)) < pProto->RequiredReputationRank)
{
SendBuyError( BUY_ERR_REPUTATION_REQUIRE, pCreature, item, 0);
return false;
}
if(crItem->ExtendedCost)
if (crItem->ExtendedCost)
{
ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost);
if(!iece)
if (!iece)
{
sLog.outError("Item %u have wrong ExtendedCost field value %u", pProto->ItemId, crItem->ExtendedCost);
return false;
}
// honor points price
if(GetHonorPoints() < (iece->reqhonorpoints * count))
if (GetHonorPoints() < (iece->reqhonorpoints * count))
{
SendEquipError(EQUIP_ERR_NOT_ENOUGH_HONOR_POINTS, NULL, NULL);
return false;
}
// arena points price
if(GetArenaPoints() < (iece->reqarenapoints * count))
if (GetArenaPoints() < (iece->reqarenapoints * count))
{
SendEquipError(EQUIP_ERR_NOT_ENOUGH_ARENA_POINTS, NULL, NULL);
return false;
@ -17259,62 +17283,38 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
// reputation discount
price = uint32(floor(price * GetReputationPriceDiscount(pCreature)));
if( GetMoney() < price )
if (GetMoney() < price)
{
SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, item, 0);
return false;
}
uint8 bag = 0; // init for case invalid bagGUID
if (bagguid != NULL_BAG && slot != NULL_SLOT)
{
if( bagguid == GetGUID() )
{
bag = INVENTORY_SLOT_BAG_0;
}
else
{
for (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) )
if ((bag == NULL_BAG && slot == NULL_SLOT) || IsInventoryPos(bag, slot))
{
ItemPosCountVec dest;
uint8 msg = CanStoreNewItem( bag, slot, dest, item, pProto->BuyCount * count );
if( msg != EQUIP_ERR_OK )
if (msg != EQUIP_ERR_OK)
{
SendEquipError( msg, NULL, NULL );
return false;
}
ModifyMoney( -(int32)price );
if(crItem->ExtendedCost) // case for new honor system
if (crItem->ExtendedCost) // case for new honor system
{
ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost);
if(iece->reqhonorpoints)
if (iece->reqhonorpoints)
ModifyHonorPoints( - int32(iece->reqhonorpoints * count));
if(iece->reqarenapoints)
if (iece->reqarenapoints)
ModifyArenaPoints( - int32(iece->reqarenapoints * count));
for (uint8 i = 0; i < 5; ++i)
{
if(iece->reqitem[i])
if (iece->reqitem[i])
DestroyItemCount(iece->reqitem[i], (iece->reqitemcount[i] * count), true);
}
}
if(Item *it = StoreNewItem( dest, item, true ))
if (Item *it = StoreNewItem( dest, item, true ))
{
uint32 new_count = pCreature->UpdateVendorItemCurrentCount(crItem,pProto->BuyCount * count);
@ -17328,9 +17328,9 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
SendNewItem(it, pProto->BuyCount*count, true, false, false);
}
}
else if( IsEquipmentPos( bag, slot ) )
else if (IsEquipmentPos(bag, slot))
{
if(pProto->BuyCount * count != 1)
if (pProto->BuyCount * count != 1)
{
SendEquipError( EQUIP_ERR_ITEM_CANT_BE_EQUIPPED, NULL, NULL );
return false;
@ -17338,19 +17338,19 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
uint16 dest;
uint8 msg = CanEquipNewItem( slot, dest, item, false );
if( msg != EQUIP_ERR_OK )
if (msg != EQUIP_ERR_OK)
{
SendEquipError( msg, NULL, NULL );
return false;
}
ModifyMoney( -(int32)price );
if(crItem->ExtendedCost) // case for new honor system
if (crItem->ExtendedCost) // case for new honor system
{
ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost);
if(iece->reqhonorpoints)
if (iece->reqhonorpoints)
ModifyHonorPoints( - int32(iece->reqhonorpoints));
if(iece->reqarenapoints)
if (iece->reqarenapoints)
ModifyArenaPoints( - int32(iece->reqarenapoints));
for (uint8 i = 0; i < 5; ++i)
{
@ -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);
@ -17381,7 +17381,7 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
return false;
}
return crItem->maxcount!=0;
return crItem->maxcount != 0;
}
uint32 Player::GetMaxPersonalArenaRatingRequirement()
@ -19394,7 +19394,7 @@ void Player::EnterVehicle(Vehicle *vehicle)
vehicle->SetCharmerGUID(GetGUID());
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());
SetCharm(vehicle); // charm
@ -19446,7 +19446,7 @@ void Player::ExitVehicle(Vehicle *vehicle)
{
vehicle->SetCharmerGUID(0);
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);
SetCharm(NULL);
@ -19468,9 +19468,7 @@ void Player::ExitVehicle(Vehicle *vehicle)
data << uint32(0); // fall time
GetSession()->SendPacket(&data);
data.Initialize(SMSG_PET_SPELLS, 8);
data << uint64(0);
GetSession()->SendPacket(&data);
RemovePetActionBar();
// maybe called at dummy aura remove?
// 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();
}
void SendNewItem( Item *item, uint32 count, bool received, bool created, bool broadcast = false );
bool BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint64 bagguid, uint8 slot);
bool BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint8 bag, uint8 slot);
float GetReputationPriceDiscount( Creature const* pCreature ) const;
Player* GetTrader() const { return pTrader; }
@ -1447,6 +1447,8 @@ class MANGOS_DLL_SPEC Player : public Unit
void PetSpellInitialize();
void CharmSpellInitialize();
void PossessSpellInitialize();
void RemovePetActionBar();
bool HasSpell(uint32 spell) const;
bool HasActiveSpell(uint32 spell) const; // show in spellbook
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 & GetSpellMap() { return m_spells; }
SpellCooldowns const& GetSpellCooldownMap() const { return m_spellCooldowns; }
void AddSpellMod(SpellModifier* mod, bool apply);
bool IsAffectedBySpellmod(SpellEntry const *spellInfo, SpellModifier *mod, Spell 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 ProhibitSpellScholl(SpellSchoolMask idSchoolMask, uint32 unTimeMs );
void RemoveSpellCooldown(uint32 spell_id, bool update = false);
void RemoveSpellCategoryCooldown(uint32 cat, bool update = false);
void SendClearCooldown( uint32 spell_id, Unit* target );
void RemoveArenaSpellCooldowns();
@ -1783,6 +1788,8 @@ class MANGOS_DLL_SPEC Player : public Unit
static uint32 getFactionForRace(uint8 race);
void setFactionForRace(uint8 race);
void InitDisplayIds();
bool IsAtGroupRewardDistance(WorldObject const* pRewardSource) const;
bool RewardPlayerAndGroupAtKill(Unit* pVictim);
void RewardPlayerAndGroupAtEvent(uint32 creature_id,WorldObject* pRewardSource);

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);
uint8 charcount = 0;
if ( result )
if (result)
{
Field *fields=result->Fetch();
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");
if(!fin)
if (!fin)
return DUMP_FILE_OPEN_ERROR;
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
bool incHighest = true;
if(guid != 0 && guid < objmgr.m_hiCharGuid)
if (guid != 0 && guid < objmgr.m_hiCharGuid)
{
result = CharacterDatabase.PQuery("SELECT * FROM characters WHERE guid = '%d'", guid);
if (result)
@ -427,10 +427,10 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s
guid = objmgr.m_hiCharGuid;
// normalize the name if specified and check if it exists
if(!normalizePlayerName(name))
if (!normalizePlayerName(name))
name = "";
if(ObjectMgr::IsValidName(name,true))
if (ObjectMgr::CheckPlayerName(name,true) == CHAR_NAME_SUCCESS)
{
CharacterDatabase.escape_string(name); // for safe, we use name only for sql quearies anyway
result = CharacterDatabase.PQuery("SELECT * FROM characters WHERE name = '%s'", name.c_str());
@ -440,7 +440,8 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s
delete result;
}
}
else name = "";
else
name = "";
// 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_TriggerSpells.clear();
m_preCastSpells.clear();
m_IsTriggeredSpell = triggered;
//m_AreaAura = false;
m_CastItem = NULL;
@ -405,7 +406,6 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi
focusObject = NULL;
m_cast_count = 0;
m_glyphIndex = 0;
m_preCastSpell = 0;
m_triggeredByAuraSpell = NULL;
//Auto Shot & Shoot (wand)
@ -550,7 +550,7 @@ void Spell::FillTargetMap()
if(m_targets.getUnitTarget())
tmpUnitMap.push_back(m_targets.getUnitTarget());
else
tmpUnitMap.push_back(m_caster);
tmpUnitMap.push_back(m_caster);
break;
case TARGET_AREAEFFECT_INSTANT: // All 17/7 pairs used for dest teleportation, A processed in effect code
SetTargetMap(i, m_spellInfo->EffectImplicitTargetB[i], tmpUnitMap);
@ -1146,15 +1146,17 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)
void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
{
if(!unit || !effectMask)
if (!unit || !effectMask)
return;
Unit* realCaster = m_originalCaster ? m_originalCaster : m_caster;
// Recheck immune (only for delayed spells)
if( m_spellInfo->speed && (
if (m_spellInfo->speed && (
unit->IsImmunedToDamage(GetSpellSchoolMask(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;
}
@ -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);
}
if(m_caster->GetTypeId() == TYPEID_PLAYER)
{
((Player*)m_caster)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2, m_spellInfo->Id, 0, unit);
}
if (realCaster->GetTypeId() == TYPEID_PLAYER)
((Player*)realCaster)->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
if (m_spellInfo->speed > 0.0f &&
unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE) &&
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;
}
if( !m_caster->IsFriendlyTo(unit) )
if (!realCaster->IsFriendlyTo(unit))
{
// 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;
}
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);
if(!unit->isInCombat() && unit->GetTypeId() != TYPEID_PLAYER && ((Creature*)unit)->AI())
((Creature*)unit)->AI()->AttackedBy(m_caster);
if (!unit->isInCombat() && unit->GetTypeId() != TYPEID_PLAYER && ((Creature*)unit)->AI())
((Creature*)unit)->AI()->AttackedBy(realCaster);
unit->AddThreat(m_caster, 0.0f);
unit->SetInCombatWith(m_caster);
m_caster->SetInCombatWith(unit);
unit->AddThreat(realCaster, 0.0f);
unit->SetInCombatWith(realCaster);
realCaster->SetInCombatWith(unit);
if(Player *attackedPlayer = unit->GetCharmerOrOwnerPlayerOrPlayerItself())
{
m_caster->SetContestedPvP(attackedPlayer);
}
if (Player *attackedPlayer = unit->GetCharmerOrOwnerPlayerOrPlayerItself())
realCaster->SetContestedPvP(attackedPlayer);
}
}
else
{
// 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;
}
// assisting case, healing and resurrection
if(unit->hasUnitState(UNIT_STAT_ATTACK_PLAYER))
m_caster->SetContestedPvP();
if( unit->isInCombat() && !(m_spellInfo->AttributesEx & SPELL_ATTR_EX_NO_INITIAL_AGGRO) )
if (unit->hasUnitState(UNIT_STAT_ATTACK_PLAYER))
realCaster->SetContestedPvP();
if (unit->isInCombat() && !(m_spellInfo->AttributesEx & SPELL_ATTR_EX_NO_INITIAL_AGGRO))
{
m_caster->SetInCombatState(unit->GetCombatTimer() > 0);
unit->getHostilRefManager().threatAssist(m_caster, 0.0f);
realCaster->SetInCombatState(unit->GetCombatTimer() > 0);
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_diminishLevel = unit->GetDiminishing(m_diminishGroup);
// 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);
// Apply additional spell effects to target
if (m_preCastSpell)
m_caster->CastSpell(unit, m_preCastSpell, true, m_CastItem);
while (!m_preCastSpells.empty())
{
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)
{
@ -1250,7 +1255,7 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
// Get multiplier
float multiplier = m_spellInfo->DmgMultiplier[effectNumber];
// 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);
m_damageMultipliers[effectNumber] *= multiplier;
}
@ -2287,17 +2292,17 @@ void Spell::cast(bool skipCheck)
case SPELLFAMILY_GENERIC:
{
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)
// Blood Fury (Racial)
m_preCastSpell = 23230; // Blood Fury - Healing Reduction
AddPrecastSpell(23230); // Blood Fury - Healing Reduction
break;
}
case SPELLFAMILY_MAGE:
{
// Ice Block
if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000008000000000))
m_preCastSpell = 41425; // Hypothermia
AddPrecastSpell(41425); // Hypothermia
break;
}
case SPELLFAMILY_PRIEST:
@ -2305,27 +2310,32 @@ void Spell::cast(bool skipCheck)
// Power Word: Shield
if (m_spellInfo->Mechanic == MECHANIC_SHIELD &&
(m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000000000000001)))
m_preCastSpell = 6788; // Weakened Soul
AddPrecastSpell(6788); // Weakened Soul
// Dispersion (transform)
if (m_spellInfo->Id == 47585)
m_preCastSpell = 60069; // Dispersion (mana regen)
AddPrecastSpell(60069); // Dispersion (mana regen)
break;
}
case SPELLFAMILY_PALADIN:
{
// Divine Shield, Divine Protection or Hand of Protection
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;
}
case SPELLFAMILY_SHAMAN:
{
// Bloodlust
if (m_spellInfo->Id == 2825)
m_preCastSpell = 57724; // Sated
AddPrecastSpell(57724); // Sated
// Heroism
else if (m_spellInfo->Id == 32182)
m_preCastSpell = 57723; // Exhaustion
AddPrecastSpell(57723); // Exhaustion
break;
}
default:
@ -3659,8 +3669,17 @@ SpellCastResult Spell::CheckCast(bool strict)
// Caster aura req check if need
if(m_spellInfo->casterAuraSpell && !m_caster->HasAura(m_spellInfo->casterAuraSpell))
return SPELL_FAILED_CASTER_AURASTATE;
if(m_spellInfo->excludeCasterAuraSpell && m_caster->HasAura(m_spellInfo->excludeCasterAuraSpell))
return SPELL_FAILED_CASTER_AURASTATE;
if(m_spellInfo->excludeCasterAuraSpell)
{
// 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
// (not wand currently autorepeat cast delayed to moving stop anyway in spell update code)
@ -4093,6 +4112,14 @@ SpellCastResult Spell::CheckCast(bool strict)
break;
}
case SPELL_EFFECT_APPLY_GLYPH:
{
uint32 glyphId = m_spellInfo->EffectMiscValue[i];
if(GlyphPropertiesEntry const *gp = sGlyphPropertiesStore.LookupEntry(glyphId))
if(m_caster->HasAura(gp->SpellId))
return SPELL_FAILED_UNIQUE_GLYPH;
break;
}
case SPELL_EFFECT_FEED_PET:
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
@ -4356,8 +4383,13 @@ SpellCastResult Spell::CheckCast(bool strict)
break;
}
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())
return SPELL_FAILED_ALREADY_HAVE_SUMMON;
@ -4378,6 +4410,51 @@ SpellCastResult Spell::CheckCast(bool strict)
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:
{
if (m_caster->IsInWater())

View file

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

View file

@ -336,7 +336,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=
&Aura::HandleNoImmediateEffect, //283 SPELL_AURA_MOD_HEALING_RECEIVED implemented in Unit::SpellHealingBonus
&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::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::HandleUnused, //288 not used by any spells (3.09) except 1 test spell.
&Aura::HandleUnused, //289 unused
@ -1178,23 +1178,32 @@ void Aura::SendAuraUpdate(bool remove)
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();
Unit *caster = GetCaster();
if (!target || !caster)
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);
}
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)
@ -3065,33 +3074,33 @@ void Aura::HandleModPossess(bool apply, bool Real)
if(!Real)
return;
if(m_target->getLevel() > m_modifier.m_amount)
return;
// not possess yourself
if(GetCasterGUID() == m_target->GetGUID())
return;
Unit* caster = GetCaster();
if(!caster)
if(!caster || caster->GetTypeId() != TYPEID_PLAYER)
return;
Player* p_caster = (Player*)caster;
if( apply )
{
m_target->SetCharmerGUID(GetCasterGUID());
m_target->setFaction(caster->getFaction());
m_target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
caster->SetCharm(m_target);
m_target->SetCharmerGUID(p_caster->GetGUID());
m_target->setFaction(p_caster->getFaction());
if(caster->GetTypeId() == TYPEID_PLAYER)
{
((Player*)caster)->SetFarSightGUID(m_target->GetGUID());
((Player*)caster)->SetClientControl(m_target, 1);
((Player*)caster)->SetMover(m_target);
}
p_caster->SetCharm(m_target);
p_caster->SetFarSightGUID(m_target->GetGUID());
p_caster->SetClientControl(m_target, 1);
p_caster->SetMover(m_target);
m_target->CombatStop();
m_target->DeleteThreatList();
if(m_target->GetTypeId() == TYPEID_UNIT)
{
m_target->StopMoving();
@ -3106,13 +3115,14 @@ void Aura::HandleModPossess(bool apply, bool Real)
if(CharmInfo *charmInfo = m_target->InitCharmInfo(m_target))
charmInfo->InitPossessCreateSpells();
if(caster->GetTypeId() == TYPEID_PLAYER)
((Player*)caster)->PossessSpellInitialize();
p_caster->PossessSpellInitialize();
}
else
{
m_target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
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)
{
@ -3125,18 +3135,13 @@ void Aura::HandleModPossess(bool apply, bool Real)
m_target->setFaction(cinfo->faction_A);
}
caster->SetCharm(NULL);
p_caster->SetCharm(NULL);
if(caster->GetTypeId() == TYPEID_PLAYER)
{
((Player*)caster)->SetFarSightGUID(0);
((Player*)caster)->SetClientControl(m_target, 0);
((Player*)caster)->SetMover(NULL);
p_caster->SetFarSightGUID(0);
p_caster->SetClientControl(m_target, 0);
p_caster->SetMover(NULL);
WorldPacket data(SMSG_PET_SPELLS, 8);
data << uint64(0);
((Player*)caster)->GetSession()->SendPacket(&data);
}
p_caster->RemovePetActionBar();
if(m_target->GetTypeId() == TYPEID_UNIT)
{
@ -3161,14 +3166,16 @@ void Aura::HandleModPossessPet(bool apply, bool Real)
if(!pet || pet != m_target)
return;
if(apply)
pet->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_24);
else
pet->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_24);
Player* p_caster = (Player*)caster;
((Player*)caster)->SetFarSightGUID(apply ? pet->GetGUID() : 0);
((Player*)caster)->SetCharm(apply ? pet : NULL);
((Player*)caster)->SetClientControl(pet, apply ? 1 : 0);
if(apply)
pet->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
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);
if(apply)
@ -3208,100 +3215,92 @@ void Aura::HandleModCharm(bool apply, bool Real)
if(!caster)
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());
m_target->setFaction(caster->getFaction());
m_target->CastStop(m_target == caster ? GetId() : 0);
caster->SetCharm(m_target);
((Creature*)m_target)->AIM_Initialize();
CharmInfo *charmInfo = m_target->InitCharmInfo(m_target);
charmInfo->InitCharmCreateSpells();
charmInfo->SetReactState( REACT_DEFENSIVE );
m_target->CombatStop();
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
if(caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK)
{
CreatureInfo const *cinfo = ((Creature*)m_target)->GetCreatureInfo();
// restore faction
if(((Creature*)m_target)->isPet())
if(cinfo && cinfo->type == CREATURE_TYPE_DEMON)
{
if(Unit* owner = m_target->GetOwner())
m_target->setFaction(owner->getFaction());
else if(cinfo)
m_target->setFaction(cinfo->faction_A);
//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));
}
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);
// 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);
if(caster->GetTypeId() == TYPEID_PLAYER)
// restore UNIT_FIELD_BYTES_0
if(cinfo && caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK && cinfo->type == CREATURE_TYPE_DEMON)
{
WorldPacket data(SMSG_PET_SPELLS, 8);
data << uint64(0);
((Player*)caster)->GetSession()->SendPacket(&data);
}
if(m_target->GetTypeId() == TYPEID_UNIT)
{
((Creature*)m_target)->AIM_Initialize();
if (((Creature*)m_target)->AI())
((Creature*)m_target)->AI()->AttackedBy(caster);
//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());
}
}
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
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
// Reduce dot damage from resilience for players
if (m_target->GetTypeId() == TYPEID_PLAYER)
@ -5899,7 +5901,7 @@ void Aura::PeriodicTick()
pCaster->DealDamageMods(m_target, pdamage, &absorb);
SpellPeriodicAuraLogInfo pInfo(this, pdamage, 0, absorb, resist, 0.0f);
SpellPeriodicAuraLogInfo pInfo(this, pdamage, 0, absorb, resist, 0.0f, isCrit);
m_target->SendPeriodicAuraLog(&pInfo);
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());
// 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",
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);
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)
((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:
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;
SpellModifier *m_spellmod;

View file

@ -1187,21 +1187,19 @@ void Spell::EffectDummy(uint32 i)
return;
// immediately finishes the cooldown on Frost spells
const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
const SpellCooldowns& cm = ((Player *)m_caster)->GetSpellCooldownMap();
for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();)
{
if (itr->second->state == PLAYERSPELL_REMOVED)
continue;
uint32 classspell = itr->first;
SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
if( spellInfo->SpellFamilyName == SPELLFAMILY_MAGE &&
(GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) &&
spellInfo->Id != 11958 && GetSpellRecoveryTime(spellInfo) > 0 )
{
((Player*)m_caster)->RemoveSpellCooldown(classspell, true);
((Player*)m_caster)->RemoveSpellCooldown((itr++)->first, true);
}
else
++itr;
}
return;
}
@ -1436,14 +1434,15 @@ void Spell::EffectDummy(uint32 i)
return;
//immediately finishes the cooldown on certain Rogue abilities
const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
const SpellCooldowns& cm = ((Player *)m_caster)->GetSpellCooldownMap();
for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();)
{
uint32 classspell = itr->first;
SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags & UI64LIT(0x0000024000000860)))
((Player*)m_caster)->RemoveSpellCooldown(classspell,true);
((Player*)m_caster)->RemoveSpellCooldown((itr++)->first,true);
else
++itr;
}
return;
}
@ -1487,14 +1486,15 @@ void Spell::EffectDummy(uint32 i)
return;
//immediately finishes the cooldown for hunter abilities
const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
const SpellCooldowns& cm = ((Player*)m_caster)->GetSpellCooldownMap();
for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();)
{
uint32 classspell = itr->first;
SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && GetSpellRecoveryTime(spellInfo) > 0 )
((Player*)m_caster)->RemoveSpellCooldown(classspell,true);
((Player*)m_caster)->RemoveSpellCooldown((itr++)->first,true);
else
++itr;
}
return;
}
@ -2317,7 +2317,7 @@ void Spell::EffectUnlearnSpecialization( uint32 i )
_player->removeSpell(spellToUnlearn);
sLog.outDebug( "Spell: Player %u have unlearned spell %u from NpcGUID: %u", _player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow() );
sLog.outDebug( "Spell: Player %u has unlearned spell %u from NpcGUID: %u", _player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow() );
}
void Spell::EffectPowerDrain(uint32 i)
@ -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];
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)
@ -4327,24 +4327,30 @@ void Spell::EffectWeaponDmg(uint32 i)
spell_bonus += m_caster->CalculateDamage (OFF_ATTACK, normalized);
}
// 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;
// Need refresh all Sunder Armor auras from this caster
Unit::AuraMap& suAuras = unitTarget->GetAuras();
SpellEntry const *spellInfo;
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 &&
(spellInfo->SpellFamilyFlags & UI64LIT(0x0000000000004000)) &&
(*itr).second->GetCasterGUID() == m_caster->GetGUID())
{
(*itr).second->RefreshAura();
stack = (*itr).second->GetStackAmount();
break;
}
}
if (stack)
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;
}

View file

@ -27,6 +27,7 @@
#include "Spell.h"
#include "ScriptCalls.h"
#include "Totem.h"
#include "SpellAuras.h"
void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket)
{
@ -377,10 +378,6 @@ void WorldSession::HandleCancelAuraOpcode( WorldPacket& recvPacket)
{
CHECK_PACKET_SIZE(recvPacket,4);
// ignore for remote control state
if(_player->m_mover != _player)
return;
uint32 spellId;
recvPacket >> spellId;
@ -388,10 +385,34 @@ void WorldSession::HandleCancelAuraOpcode( WorldPacket& recvPacket)
if (!spellInfo)
return;
// not allow remove non positive spells and spells with attr SPELL_ATTR_CANT_CANCEL
if(!IsPositiveSpell(spellId) || (spellInfo->Attributes & SPELL_ATTR_CANT_CANCEL))
if (spellInfo->Attributes & SPELL_ATTR_CANT_CANCEL)
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)
if (IsChanneledSpell(spellInfo))
{

View file

@ -334,7 +334,7 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex)
case 11196: // Recently Bandaged
return false;
// some spells have unclear target modes for selection, so just make effect positive
case 27184:
case 27184:
case 27190:
case 27191:
case 27201:
@ -1126,7 +1126,7 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) cons
if(!spellInfo_1 || !spellInfo_2)
return false;
if(spellInfo_1->Id == spellId_2)
if(spellId_1 == spellId_2)
return false;
//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;
}
case SPELLFAMILY_MAGE:
// Arcane Intellect and Insight
if( spellInfo_2->SpellIconID == 125 && spellInfo_1->Id == 18820 )
return false;
break;
case SPELLFAMILY_WARRIOR:
{
// 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 )
return false;
// Arcane Intellect and Insight
if( spellInfo_1->SpellIconID == 125 && spellInfo_2->Id == 18820 )
return false;
break;
case SPELLFAMILY_WARLOCK:
if( spellInfo_2->SpellFamilyName == SPELLFAMILY_WARLOCK )
@ -2610,7 +2619,7 @@ SpellCastResult SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spell
// Try search in next group
groupEntry = sAreaGroupStore.LookupEntry(groupEntry->nextGroup);
}
if(!found)
return SPELL_FAILED_INCORRECT_AREA;
}

View file

@ -4278,13 +4278,13 @@ void Unit::SendPeriodicAuraLog(SpellPeriodicAuraLogInfo *pInfo)
data << uint32(GetSpellSchoolMask(aura->GetSpellProto()));
data << uint32(pInfo->absorb); // absorb
data << uint32(pInfo->resist); // resist
data << uint8(0); // new 3.1.2
data << uint8(pInfo->critical ? 1 : 0); // new 3.1.2 critical flag
break;
case SPELL_AURA_PERIODIC_HEAL:
case SPELL_AURA_OBS_MOD_HEALTH:
data << uint32(pInfo->damage); // damage
data << uint32(pInfo->overDamage); // overheal?
data << uint8(0); // new 3.1.2
data << uint8(pInfo->critical ? 1 : 0); // new 3.1.2 critical flag
break;
case SPELL_AURA_OBS_MOD_MANA:
case SPELL_AURA_PERIODIC_ENERGIZE:
@ -5521,6 +5521,17 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
}
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)
case 28789:
{
@ -6767,6 +6778,14 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB
return false;
break;
}
// Sword and Board
case 50227:
{
// Remove cooldown on Shield Slam
if (GetTypeId() == TYPEID_PLAYER)
((Player*)this)->RemoveSpellCategoryCooldown(1209, true);
break;
}
// Brain Freeze
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 &&
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));
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_CONFUSED = 0x00400000,
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_SKINNABLE = 0x04000000,
UNIT_FLAG_MOUNT = 0x08000000,
@ -686,8 +686,8 @@ struct SpellNonMeleeDamage{
struct SpellPeriodicAuraLogInfo
{
SpellPeriodicAuraLogInfo(Aura *_aura, uint32 _damage, uint32 _overDamage, uint32 _absorb, uint32 _resist, float _multiplier)
: aura(_aura), damage(_damage), overDamage(_overDamage), absorb(_absorb), resist(_resist), multiplier(_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), critical(_critical) {}
Aura *aura;
uint32 damage;
@ -695,6 +695,7 @@ struct SpellPeriodicAuraLogInfo
uint32 resist;
uint32 overDamage; // overkill/overheal
float multiplier;
bool critical;
};
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_PET_NAMES] = sConfig.GetIntDefault ("StrictPetNames", 0);
m_configs[CONFIG_MIN_PLAYER_NAME] = sConfig.GetIntDefault ("MinPlayerName", 2);
if(m_configs[CONFIG_MIN_PLAYER_NAME] < 1 || m_configs[CONFIG_MIN_PLAYER_NAME] > MAX_PLAYER_NAME)
{
sLog.outError("MinPlayerName (%i) must be in range 1..%u. Set to 2.",m_configs[CONFIG_MIN_PLAYER_NAME],MAX_PLAYER_NAME);
m_configs[CONFIG_MIN_PLAYER_NAME] = 2;
}
m_configs[CONFIG_MIN_CHARTER_NAME] = sConfig.GetIntDefault ("MinCharterName", 2);
if(m_configs[CONFIG_MIN_CHARTER_NAME] < 1 || m_configs[CONFIG_MIN_CHARTER_NAME] > MAX_CHARTER_NAME)
{
sLog.outError("MinCharterName (%i) must be in range 1..%u. Set to 2.",m_configs[CONFIG_MIN_CHARTER_NAME],MAX_CHARTER_NAME);
m_configs[CONFIG_MIN_CHARTER_NAME] = 2;
}
m_configs[CONFIG_MIN_PET_NAME] = sConfig.GetIntDefault ("MinPetName", 2);
if(m_configs[CONFIG_MIN_PET_NAME] < 1 || m_configs[CONFIG_MIN_PET_NAME] > MAX_PET_NAME)
{
sLog.outError("MinPetName (%i) must be in range 1..%u. Set to 2.",m_configs[CONFIG_MIN_PET_NAME],MAX_PET_NAME);
m_configs[CONFIG_MIN_PET_NAME] = 2;
}
m_configs[CONFIG_CHARACTERS_CREATING_DISABLED] = sConfig.GetIntDefault ("CharactersCreatingDisabled", 0);
m_configs[CONFIG_CHARACTERS_PER_REALM] = sConfig.GetIntDefault("CharactersPerRealm", 10);

View file

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

View file

@ -396,6 +396,18 @@ LogColors = ""
# (included in client by default, with active official localization or custom localization fonts in clientdir/Fonts).
# 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
# Disable characters creating for specific team or any (non-player accounts not affected)
# Default: 0 - enabled
@ -579,6 +591,9 @@ DeclinedNames = 0
StrictPlayerNames = 0
StrictCharterNames = 0
StrictPetNames = 0
MinPlayerName = 2
MinCharterName = 2
MinPetName = 2
CharactersCreatingDisabled = 0
CharactersPerAccount = 50
CharactersPerRealm = 10

View file

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