Merge branch 'master' into 330

This commit is contained in:
VladimirMangos 2010-04-07 06:58:42 +04:00
commit 6bcbbc321b
23 changed files with 574 additions and 196 deletions

View file

@ -390,7 +390,7 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa
m_currentBuybackSlot = BUYBACK_SLOT_START;
m_DailyQuestChanged = false;
m_lastDailyQuestTime = 0;
m_WeeklyQuestChanged = false;
for (int i=0; i<MAX_TIMERS; ++i)
m_MirrorTimer[i] = DISABLED_MIRROR_TIMER;
@ -1139,7 +1139,7 @@ void Player::Update( uint32 p_time )
if (!m_timedquests.empty())
{
std::set<uint32>::iterator iter = m_timedquests.begin();
QuestSet::iterator iter = m_timedquests.begin();
while (iter != m_timedquests.end())
{
QuestStatusData& q_status = mQuestStatus[*iter];
@ -4154,6 +4154,7 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC
CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE guid = '%u'",guid);
CharacterDatabase.PExecute("DELETE FROM character_queststatus WHERE guid = '%u'",guid);
CharacterDatabase.PExecute("DELETE FROM character_queststatus_daily WHERE guid = '%u'",guid);
CharacterDatabase.PExecute("DELETE FROM character_queststatus_weekly WHERE guid = '%u'",guid);
CharacterDatabase.PExecute("DELETE FROM character_reputation WHERE guid = '%u'",guid);
CharacterDatabase.PExecute("DELETE FROM character_skills WHERE guid = '%u'",guid);
CharacterDatabase.PExecute("DELETE FROM character_spell WHERE guid = '%u'",guid);
@ -6896,6 +6897,9 @@ void Player::_ApplyItemBonuses(ItemPrototype const *proto, uint8 slot, bool appl
case ITEM_MOD_SPELL_POWER:
ApplySpellPowerBonus(int32(val), apply);
break;
case ITEM_MOD_BLOCK_VALUE:
HandleBaseModValue(SHIELD_BLOCK_VALUE, FLAT_MOD, float(val), apply);
break;
// depricated item mods
case ITEM_MOD_FERAL_ATTACK_POWER:
case ITEM_MOD_SPELL_HEALING_DONE:
@ -12337,6 +12341,9 @@ void Player::ApplyEnchantment(Item *item, EnchantmentSlot slot, bool apply, bool
((Player*)this)->ApplySpellPowerBonus(enchant_amount, apply);
sLog.outDebug("+ %u SPELL_POWER", enchant_amount);
break;
case ITEM_MOD_BLOCK_VALUE:
HandleBaseModValue(SHIELD_BLOCK_VALUE, FLAT_MOD, float(enchant_amount), apply);
break;
case ITEM_MOD_FERAL_ATTACK_POWER:
case ITEM_MOD_SPELL_HEALING_DONE: // deprecated
case ITEM_MOD_SPELL_DAMAGE_DONE: // deprecated
@ -12886,7 +12893,7 @@ void Player::SendPreparedQuest(uint64 guid)
PlayerTalkClass->SendQuestGiverRequestItems(pQuest, guid, CanRewardQuest(pQuest, false), true);
// Send completable on repeatable and autoCompletable quest if player don't have quest
// TODO: verify if check for !pQuest->IsDaily() is really correct (possibly not)
else if (pQuest->IsAutoComplete() && pQuest->IsRepeatable() && !pQuest->IsDaily())
else if (pQuest->IsAutoComplete() && pQuest->IsRepeatable() && !pQuest->IsDailyOrWeekly())
PlayerTalkClass->SendQuestGiverRequestItems(pQuest, guid, CanCompleteRepeatableQuest(pQuest), true);
else
PlayerTalkClass->SendQuestGiverQuestDetails(pQuest, guid, true);
@ -13003,7 +13010,7 @@ bool Player::CanSeeStartQuest( Quest const *pQuest )
if( SatisfyQuestRace( pQuest, false ) && SatisfyQuestSkillOrClass( pQuest, false ) &&
SatisfyQuestExclusiveGroup( pQuest, false ) && SatisfyQuestReputation( pQuest, false ) &&
SatisfyQuestPreviousQuest( pQuest, false ) && SatisfyQuestNextChain( pQuest, false ) &&
SatisfyQuestPrevChain( pQuest, false ) && SatisfyQuestDay( pQuest, false ) )
SatisfyQuestPrevChain( pQuest, false ) && SatisfyQuestDay( pQuest, false ) && SatisfyQuestWeek( pQuest, false ) )
{
return getLevel() + sWorld.getConfig(CONFIG_UINT32_QUEST_HIGH_LEVEL_HIDE_DIFF) >= pQuest->GetMinLevel();
}
@ -13018,7 +13025,7 @@ bool Player::CanTakeQuest( Quest const *pQuest, bool msg )
&& SatisfyQuestSkillOrClass( pQuest, msg ) && SatisfyQuestReputation( pQuest, msg )
&& SatisfyQuestPreviousQuest( pQuest, msg ) && SatisfyQuestTimed( pQuest, msg )
&& SatisfyQuestNextChain( pQuest, msg ) && SatisfyQuestPrevChain( pQuest, msg )
&& SatisfyQuestDay( pQuest, msg );
&& SatisfyQuestDay( pQuest, msg ) && SatisfyQuestWeek( pQuest, msg );
}
bool Player::CanAddQuest( Quest const *pQuest, bool msg )
@ -13130,15 +13137,15 @@ bool Player::CanCompleteRepeatableQuest( Quest const *pQuest )
bool Player::CanRewardQuest( Quest const *pQuest, bool msg )
{
// not auto complete quest and not completed quest (only cheating case, then ignore without message)
if(!pQuest->IsAutoComplete() && GetQuestStatus(pQuest->GetQuestId()) != QUEST_STATUS_COMPLETE)
if (!pQuest->IsAutoComplete() && GetQuestStatus(pQuest->GetQuestId()) != QUEST_STATUS_COMPLETE)
return false;
// daily quest can't be rewarded (25 daily quest already completed)
if(!SatisfyQuestDay(pQuest,true))
if (!SatisfyQuestDay(pQuest,true) || !SatisfyQuestWeek(pQuest,true))
return false;
// rewarded and not repeatable quest (only cheating case, then ignore without message)
if(GetQuestRewardStatus(pQuest->GetQuestId()))
if (GetQuestRewardStatus(pQuest->GetQuestId()))
return false;
// prevent receive reward with quest items in bank
@ -13157,7 +13164,7 @@ bool Player::CanRewardQuest( Quest const *pQuest, bool msg )
}
// prevent receive reward with low money and GetRewOrReqMoney() < 0
if(pQuest->GetRewOrReqMoney() < 0 && GetMoney() < uint32(-pQuest->GetRewOrReqMoney()) )
if (pQuest->GetRewOrReqMoney() < 0 && GetMoney() < uint32(-pQuest->GetRewOrReqMoney()) )
return false;
return true;
@ -13421,6 +13428,9 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST, 1);
}
if (pQuest->IsWeekly())
SetWeeklyQuestStatus(quest_id);
if (!pQuest->IsRepeatable())
SetQuestStatus(quest_id, QUEST_STATUS_COMPLETE);
else
@ -13734,7 +13744,7 @@ bool Player::SatisfyQuestTimed(Quest const* qInfo, bool msg)
bool Player::SatisfyQuestExclusiveGroup( Quest const* qInfo, bool msg )
{
// non positive exclusive group, if > 0 then can be start if any other quest in exclusive group already started/completed
if(qInfo->GetExclusiveGroup() <= 0)
if (qInfo->GetExclusiveGroup() <= 0)
return true;
ObjectMgr::ExclusiveQuestGroups::const_iterator iter = sObjectMgr.mExclusiveQuestGroups.lower_bound(qInfo->GetExclusiveGroup());
@ -13747,12 +13757,12 @@ bool Player::SatisfyQuestExclusiveGroup( Quest const* qInfo, bool msg )
uint32 exclude_Id = iter->second;
// skip checked quest id, only state of other quests in group is interesting
if(exclude_Id == qInfo->GetQuestId())
if (exclude_Id == qInfo->GetQuestId())
continue;
// not allow have daily quest if daily quest from exclusive group already recently completed
Quest const* Nquest = sObjectMgr.GetQuestTemplate(exclude_Id);
if( !SatisfyQuestDay(Nquest, false) )
if (!SatisfyQuestDay(Nquest, false) || !SatisfyQuestWeek(Nquest, false))
{
if( msg )
SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ );
@ -13762,8 +13772,8 @@ bool Player::SatisfyQuestExclusiveGroup( Quest const* qInfo, bool msg )
QuestStatusMap::iterator i_exstatus = mQuestStatus.find( exclude_Id );
// alternative quest already started or completed
if( i_exstatus != mQuestStatus.end()
&& (i_exstatus->second.m_status == QUEST_STATUS_COMPLETE || i_exstatus->second.m_status == QUEST_STATUS_INCOMPLETE) )
if (i_exstatus != mQuestStatus.end()
&& (i_exstatus->second.m_status == QUEST_STATUS_COMPLETE || i_exstatus->second.m_status == QUEST_STATUS_INCOMPLETE))
{
if( msg )
SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ );
@ -13830,21 +13840,21 @@ bool Player::SatisfyQuestPrevChain( Quest const* qInfo, bool msg )
bool Player::SatisfyQuestDay( Quest const* qInfo, bool msg )
{
if(!qInfo->IsDaily())
if (!qInfo->IsDaily())
return true;
bool have_slot = false;
for(uint32 quest_daily_idx = 0; quest_daily_idx < PLAYER_MAX_DAILY_QUESTS; ++quest_daily_idx)
{
uint32 id = GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx);
if(qInfo->GetQuestId()==id)
if (qInfo->GetQuestId()==id)
return false;
if(!id)
have_slot = true;
}
if(!have_slot)
if (!have_slot)
{
if( msg )
SendCanTakeQuestResponse( INVALIDREASON_DAILY_QUESTS_REMAINING );
@ -13854,10 +13864,19 @@ bool Player::SatisfyQuestDay( Quest const* qInfo, bool msg )
return true;
}
bool Player::SatisfyQuestWeek( Quest const* qInfo, bool msg )
{
if (!qInfo->IsWeekly() || m_weeklyquests.empty())
return true;
// if not found in cooldown list
return m_weeklyquests.find(qInfo->GetQuestId()) == m_weeklyquests.end();
}
bool Player::GiveQuestSourceItem( Quest const *pQuest )
{
uint32 srcitem = pQuest->GetSrcItemId();
if( srcitem > 0 )
if (srcitem > 0)
{
uint32 count = pQuest->GetSrcItemCount();
if( count <= 0 )
@ -13865,14 +13884,14 @@ bool Player::GiveQuestSourceItem( Quest const *pQuest )
ItemPosCountVec dest;
uint8 msg = CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, srcitem, count );
if( msg == EQUIP_ERR_OK )
if (msg == EQUIP_ERR_OK)
{
Item * item = StoreNewItem(dest, srcitem, true);
SendNewItem(item, count, true, false);
return true;
}
// player already have max amount required item, just report success
else if( msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS )
else if (msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS)
return true;
else
SendEquipError( msg, NULL, NULL, srcitem );
@ -15154,6 +15173,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
// after spell load, learn rewarded spell if need also
_LoadQuestStatus(holder->GetResult(PLAYER_LOGIN_QUERY_LOADQUESTSTATUS));
_LoadDailyQuestStatus(holder->GetResult(PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS));
_LoadWeeklyQuestStatus(holder->GetResult(PLAYER_LOGIN_QUERY_LOADWEKLYQUESTSTATUS));
_LoadTalents(holder->GetResult(PLAYER_LOGIN_QUERY_LOADTALENTS));
@ -15901,7 +15921,7 @@ void Player::_LoadDailyQuestStatus(QueryResult *result)
for(uint32 quest_daily_idx = 0; quest_daily_idx < PLAYER_MAX_DAILY_QUESTS; ++quest_daily_idx)
SetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx,0);
//QueryResult *result = CharacterDatabase.PQuery("SELECT quest,time FROM character_queststatus_daily WHERE guid = '%u'", GetGUIDLow());
//QueryResult *result = CharacterDatabase.PQuery("SELECT quest FROM character_queststatus_daily WHERE guid = '%u'", GetGUIDLow());
if(result)
{
@ -15919,9 +15939,6 @@ void Player::_LoadDailyQuestStatus(QueryResult *result)
uint32 quest_id = fields[0].GetUInt32();
// save _any_ from daily quest times (it must be after last reset anyway)
m_lastDailyQuestTime = (time_t)fields[1].GetUInt64();
Quest const* pQuest = sObjectMgr.GetQuestTemplate(quest_id);
if( !pQuest )
continue;
@ -15939,6 +15956,35 @@ void Player::_LoadDailyQuestStatus(QueryResult *result)
m_DailyQuestChanged = false;
}
void Player::_LoadWeeklyQuestStatus(QueryResult *result)
{
m_weeklyquests.clear();
//QueryResult *result = CharacterDatabase.PQuery("SELECT quest FROM character_queststatus_weekly WHERE guid = '%u'", GetGUIDLow());
if (result)
{
do
{
Field *fields = result->Fetch();
uint32 quest_id = fields[0].GetUInt32();
Quest const* pQuest = sObjectMgr.GetQuestTemplate(quest_id);
if (!pQuest)
continue;
m_weeklyquests.insert(quest_id);
sLog.outDebug("Weekly quest {%u} cooldown for player (GUID: %u)", quest_id, GetGUIDLow());
}
while( result->NextRow() );
delete result;
}
m_WeeklyQuestChanged = false;
}
void Player::_LoadSpells(QueryResult *result)
{
//QueryResult *result = CharacterDatabase.PQuery("SELECT spell,active,disabled FROM character_spell WHERE guid = '%u'",GetGUIDLow());
@ -15975,7 +16021,7 @@ void Player::_LoadTalents(QueryResult *result)
do
{
Field *fields = result->Fetch();
uint32 talent_id = fields[0].GetUInt32();
TalentEntry const *talentInfo = sTalentStore.LookupEntry( talent_id );
@ -16517,13 +16563,14 @@ void Player::SaveToDB()
CharacterDatabase.Execute( ss.str().c_str() );
if(m_mailsUpdated) //save mails only when needed
if (m_mailsUpdated) //save mails only when needed
_SaveMail();
_SaveBGData();
_SaveInventory();
_SaveQuestStatus();
_SaveDailyQuestStatus();
_SaveWeeklyQuestStatus();
_SaveSpells();
_SaveSpellCooldowns();
_SaveActions();
@ -16538,8 +16585,13 @@ void Player::SaveToDB()
CharacterDatabase.CommitTransaction();
// check if stats should only be saved on logout
// save stats can be out of transaction
if (m_session->isLogingOut() || !sWorld.getConfig(CONFIG_BOOL_STATS_SAVE_ONLY_ON_LOGOUT))
_SaveStats();
// save pet (hunter pet level and experience and all type pets health/mana).
if(Pet* pet = GetPet())
if (Pet* pet = GetPet())
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
}
@ -16821,21 +16873,36 @@ void Player::_SaveQuestStatus()
void Player::_SaveDailyQuestStatus()
{
if(!m_DailyQuestChanged)
if (!m_DailyQuestChanged)
return;
m_DailyQuestChanged = false;
// save last daily quest time for all quests: we need only mostly reset time for reset check anyway
// we don't need transactions here.
CharacterDatabase.PExecute("DELETE FROM character_queststatus_daily WHERE guid = '%u'",GetGUIDLow());
for(uint32 quest_daily_idx = 0; quest_daily_idx < PLAYER_MAX_DAILY_QUESTS; ++quest_daily_idx)
if(GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx))
CharacterDatabase.PExecute("INSERT INTO character_queststatus_daily (guid,quest,time) VALUES ('%u', '%u','" UI64FMTD "')",
GetGUIDLow(), GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx),uint64(m_lastDailyQuestTime));
if (GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx))
CharacterDatabase.PExecute("INSERT INTO character_queststatus_daily (guid,quest) VALUES ('%u', '%u')",
GetGUIDLow(), GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx));
m_DailyQuestChanged = false;
}
void Player::_SaveWeeklyQuestStatus()
{
if (!m_WeeklyQuestChanged || m_weeklyquests.empty())
return;
// we don't need transactions here.
CharacterDatabase.PExecute("DELETE FROM character_queststatus_weekly WHERE guid = '%u'",GetGUIDLow());
for (QuestSet::const_iterator iter = m_weeklyquests.begin(); iter != m_weeklyquests.end(); ++iter)
{
uint32 quest_id = *iter;
CharacterDatabase.PExecute("INSERT INTO character_queststatus_weekly (guid,quest) VALUES ('%u', '%u')", GetGUIDLow(), quest_id);
}
m_WeeklyQuestChanged = false;
}
void Player::_SaveSkills()
{
@ -16927,6 +16994,40 @@ void Player::_SaveTalents()
}
}
// save player stats -- only for external usage
// real stats will be recalculated on player login
void Player::_SaveStats()
{
// check if stat saving is enabled and if char level is high enough
if(!sWorld.getConfig(CONFIG_UINT32_MIN_LEVEL_STAT_SAVE) || getLevel() < sWorld.getConfig(CONFIG_UINT32_MIN_LEVEL_STAT_SAVE))
return;
CharacterDatabase.PExecute("DELETE FROM character_stats WHERE guid = '%u'", GetGUIDLow());
std::ostringstream ss;
ss << "INSERT INTO character_stats (guid, maxhealth, maxpower1, maxpower2, maxpower3, maxpower4, maxpower5, maxpower6, maxpower7, "
"strength, agility, stamina, intellect, spirit, armor, resHoly, resFire, resNature, resFrost, resShadow, resArcane, "
"blockPct, dodgePct, parryPct, critPct, rangedCritPct, spellCritPct, attackPower, rangedAttackPower, spellPower) VALUES ("
<< GetGUIDLow() << ", "
<< GetMaxHealth() << ", ";
for(int i = 0; i < MAX_POWERS; ++i)
ss << GetMaxPower(Powers(i)) << ", ";
for(int i = 0; i < MAX_STATS; ++i)
ss << GetStat(Stats(i)) << ", ";
// armor + school resistances
for(int i = 0; i < MAX_SPELL_SCHOOL; ++i)
ss << GetResistance(SpellSchools(i)) << ",";
ss << GetFloatValue(PLAYER_BLOCK_PERCENTAGE) << ", "
<< GetFloatValue(PLAYER_DODGE_PERCENTAGE) << ", "
<< GetFloatValue(PLAYER_PARRY_PERCENTAGE) << ", "
<< GetFloatValue(PLAYER_CRIT_PERCENTAGE) << ", "
<< GetFloatValue(PLAYER_RANGED_CRIT_PERCENTAGE) << ", "
<< GetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1) << ", "
<< GetUInt32Value(UNIT_FIELD_ATTACK_POWER) << ", "
<< GetUInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER) << ", "
<< GetBaseSpellPowerBonus() << ")";
CharacterDatabase.Execute( ss.str().c_str() );
}
void Player::outDebugValues() const
{
if(!sLog.IsOutDebug()) // optimize disabled debug output
@ -18591,7 +18692,7 @@ bool Player::EnchantmentFitsRequirements(uint32 enchantmentcondition, int8 slot)
if(i == slot)
continue;
Item *pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, i );
if(pItem2 && pItem2->GetProto()->Socket[0].Color)
if(pItem2 && !pItem2->IsBroken() && pItem2->GetProto()->Socket[0].Color)
{
for(uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot)
{
@ -19497,13 +19598,18 @@ void Player::SetDailyQuestStatus( uint32 quest_id )
if(!GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx))
{
SetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx,quest_id);
m_lastDailyQuestTime = time(NULL); // last daily quest time
m_DailyQuestChanged = true;
break;
}
}
}
void Player::SetWeeklyQuestStatus( uint32 quest_id )
{
m_weeklyquests.insert(quest_id);
m_WeeklyQuestChanged = true;
}
void Player::ResetDailyQuestStatus()
{
for(uint32 quest_daily_idx = 0; quest_daily_idx < PLAYER_MAX_DAILY_QUESTS; ++quest_daily_idx)
@ -19511,7 +19617,16 @@ void Player::ResetDailyQuestStatus()
// DB data deleted in caller
m_DailyQuestChanged = false;
m_lastDailyQuestTime = 0;
}
void Player::ResetWeeklyQuestStatus()
{
if (m_weeklyquests.empty())
return;
m_weeklyquests.clear();
// DB data deleted in caller
m_WeeklyQuestChanged = false;
}
BattleGround* Player::GetBattleGround() const
@ -21281,7 +21396,7 @@ void Player::BuildPlayerTalentsInfoData(WorldPacket *data)
for(PlayerTalentMap::iterator iter = m_talents[specIdx].begin(); iter != m_talents[specIdx].end(); ++iter)
{
PlayerTalent talent = (*iter).second;
if (talent.state == PLAYERSPELL_REMOVED)
continue;
@ -21593,15 +21708,17 @@ void Player::ActivateSpec(uint8 specNum)
// remove any talent rank if talent not listed in temp spec
if (iterTempSpec == tempSpec.end() || iterTempSpec->second.state == PLAYERSPELL_REMOVED)
{
TalentEntry const *talentInfo = talent.m_talentEntry;
for(int r = 0; r < MAX_TALENT_RANK; ++r)
if (talent.m_talentEntry->RankID[r])
removeSpell(talent.m_talentEntry->RankID[r],!IsPassiveSpell(talent.m_talentEntry->RankID[r]),false);
if (talentInfo->RankID[r])
removeSpell(talentInfo->RankID[r],!IsPassiveSpell(talentInfo->RankID[r]),false);
specIter = m_talents[m_activeSpec].begin();
}
else
++specIter;
}
}
// now new spec data have only talents (maybe different rank) as in temp spec data, sync ranks then.
for (PlayerTalentMap::const_iterator tempIter = tempSpec.begin(); tempIter != tempSpec.end(); ++tempIter)