Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2024-01-04 19:22:20 +08:00
57 changed files with 1900 additions and 551 deletions

View File

@@ -335,21 +335,22 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u
if (IsInstanceGameobject())
{
switch (GetStateSavedOnInstance())
if (InstanceScript* instance = GetInstanceScript())
{
case 0:
SetGoState(GO_STATE_READY);
SwitchDoorOrButton(true);
break;
case 1:
SetGoState(GO_STATE_READY);
break;
case 2:
SetGoState(GO_STATE_ACTIVE_ALTERNATIVE);
break;
default:
SetGoState(go_state);
break;
switch (uint8 state = instance->GetStoredGameObjectState(GetSpawnId()))
{
case 0:
SetGoState(GO_STATE_READY);
SwitchDoorOrButton(true);
break;
case 1:
case 2:
SetGoState((GOState)state);
break;
default:
SetGoState(go_state);
break;
}
}
}
else
@@ -2505,21 +2506,13 @@ void GameObject::SetGoState(GOState state)
* save it's state on the database to be loaded properly
* on server restart or crash.
*/
if (IsInstanceGameobject() && IsAbleToSaveOnDb())
if (IsInstanceGameobject() && IsAllowedToSaveToDB())
{
// Save the gameobject state on the Database
if (!FindStateSavedOnInstance())
{
SaveInstanceData(GameobjectStateToInt(&state));
}
else
{
UpdateInstanceData(GameobjectStateToInt(&state));
}
SaveStateToDB();
}
}
bool GameObject::IsInstanceGameobject()
bool GameObject::IsInstanceGameobject() const
{
// Avoid checking for unecessary gameobjects whose
// states don't matter for the dungeon progression
@@ -2538,7 +2531,7 @@ bool GameObject::IsInstanceGameobject()
return false;
}
bool GameObject::ValidateGameobjectType()
bool GameObject::ValidateGameobjectType() const
{
switch (m_goInfo->type)
{
@@ -2553,7 +2546,7 @@ bool GameObject::ValidateGameobjectType()
}
}
uint8 GameObject::GameobjectStateToInt(GOState* state)
uint8 GameObject::GameobjectStateToInt(GOState* state) const
{
uint8 m_state = 3;
@@ -2578,71 +2571,24 @@ uint8 GameObject::GameobjectStateToInt(GOState* state)
return m_state;
}
bool GameObject::IsAbleToSaveOnDb()
{
return m_saveStateOnDb;
}
void GameObject::UpdateSaveToDb(bool enable)
{
m_saveStateOnDb = enable;
if (enable)
{
SavingStateOnDB();
}
}
void GameObject::SavingStateOnDB()
void GameObject::SaveStateToDB()
{
if (IsInstanceGameobject())
{
GOState param = GetGoState();
if (!FindStateSavedOnInstance())
if (InstanceScript* instance = GetInstanceScript())
{
SaveInstanceData(GameobjectStateToInt(&param));
GOState param = GetGoState();
instance->StoreGameObjectState(GetSpawnId(), GameobjectStateToInt(&param));
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INSERT_INSTANCE_SAVED_DATA);
stmt->SetData(0, GetInstanceId());
stmt->SetData(1, GetSpawnId());
stmt->SetData(2, GameobjectStateToInt(&param));
CharacterDatabase.Execute(stmt);
}
}
}
void GameObject::SaveInstanceData(uint8 state)
{
uint32 id = GetInstanceId();
uint32 guid = GetSpawnId();
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INSERT_INSTANCE_SAVED_DATA);
stmt->SetData(0, id);
stmt->SetData(1, guid);
stmt->SetData(2, state);
CharacterDatabase.Execute(stmt);
sObjectMgr->NewInstanceSavedGameobjectState(id, guid, state);
}
void GameObject::UpdateInstanceData(uint8 state)
{
uint32 id = GetInstanceId();
uint32 guid = GetSpawnId();
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPDATE_INSTANCE_SAVED_DATA);
stmt->SetData(0, state);
stmt->SetData(1, guid);
stmt->SetData(2, id);
CharacterDatabase.Execute(stmt);
sObjectMgr->SetInstanceSavedGameobjectState(id, guid, state);
}
uint8 GameObject::GetStateSavedOnInstance()
{
return sObjectMgr->GetInstanceSavedGameobjectState(GetInstanceId(), GetSpawnId());
}
bool GameObject::FindStateSavedOnInstance()
{
return sObjectMgr->FindInstanceSavedGameobjectState(GetInstanceId(), GetSpawnId());
}
void GameObject::SetDisplayId(uint32 displayid)
{
SetUInt32Value(GAMEOBJECT_DISPLAYID, displayid);

View File

@@ -350,25 +350,21 @@ public:
static std::unordered_map<int, goEventFlag> gameObjectToEventFlag; // Gameobject -> event flag
void SaveInstanceData(uint8 state);
void UpdateInstanceData(uint8 state);
bool FindStateSavedOnInstance();
bool ValidateGameobjectType();
uint8 GetStateSavedOnInstance();
bool IsInstanceGameobject();
uint8 GameobjectStateToInt(GOState* state);
[[nodiscard]] bool ValidateGameobjectType() const;
[[nodiscard]] bool IsInstanceGameobject() const;
[[nodiscard]] uint8 GameobjectStateToInt(GOState* state) const;
/* A check to verify if this object is available to be saved on the DB when
* a state change occurs
*/
bool IsAbleToSaveOnDb();
[[nodiscard]] bool IsAllowedToSaveToDB() const { return m_saveStateOnDb; };
/* Enable or Disable the ability to save on the database this gameobject's state
* whenever it changes
*/
void UpdateSaveToDb(bool enable);
void AllowSaveToDB(bool enable) { m_saveStateOnDb = enable; };
void SavingStateOnDB();
void SaveStateToDB();
std::string GetDebugInfo() const override;
protected:

View File

@@ -105,6 +105,14 @@ void Pet::AddToWorld()
if (GetOwnerGUID().IsPlayer())
{
if (Player* owner = GetOwner())
{
if (getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK)
{
owner->SetLastPetSpell(GetUInt32Value(UNIT_CREATED_BY_SPELL));
}
}
sScriptMgr->OnPetAddToWorld(this);
}
}

View File

@@ -2524,6 +2524,11 @@ void Player::GiveLevel(uint8 level)
sScriptMgr->OnPlayerLevelChanged(this, oldLevel);
}
bool Player::IsMaxLevel() const
{
return GetLevel() >= GetUInt32Value(PLAYER_FIELD_MAX_LEVEL);
}
void Player::InitTalentForLevel()
{
uint32 talentPointsForLevel = CalculateTalentsPoints();
@@ -14166,24 +14171,21 @@ void Player::ResummonPetTemporaryUnSummonedIfAny()
bool Player::CanResummonPet(uint32 spellid)
{
switch (getClass())
if (getClass() == CLASS_DEATH_KNIGHT)
{
case CLASS_DEATH_KNIGHT:
if (CanSeeDKPet())
return true;
else if (spellid == 52150) //Raise Dead
return false;
break;
case CLASS_MAGE:
if (HasSpell(31687) && HasAura(70937)) //Has [Summon Water Elemental] spell and [Glyph of Eternal Water].
return true;
break;
case CLASS_HUNTER:
case CLASS_WARLOCK:
if (CanSeeDKPet())
return true;
break;
default:
break;
else if (spellid == 52150) // Raise Dead
return false;
}
else if (getClass() == CLASS_MAGE)
{
if (HasSpell(31687) && HasAura(70937)) //Has [Summon Water Elemental] spell and [Glyph of Eternal Water].
return true;
}
else if (getClass() == CLASS_HUNTER)
{
return true;
}
return HasSpell(spellid);

View File

@@ -1686,6 +1686,7 @@ public:
void SetFreeTalentPoints(uint32 points);
bool resetTalents(bool noResetCost = false);
[[nodiscard]] uint32 resetTalentsCost() const;
bool IsMaxLevel() const;
void InitTalentForLevel();
void BuildPlayerTalentsInfoData(WorldPacket* data);
void BuildPetTalentsInfoData(WorldPacket* data);

View File

@@ -2352,7 +2352,7 @@ void Player::SendQuestReward(Quest const* quest, uint32 XP)
WorldPacket data(SMSG_QUESTGIVER_QUEST_COMPLETE, (4 + 4 + 4 + 4 + 4));
data << uint32(questid);
if (GetLevel() < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
if (!IsMaxLevel())
{
data << uint32(XP);
data << uint32(quest->GetRewOrReqMoney(GetLevel()));

View File

@@ -4468,19 +4468,12 @@ void Unit::_ApplyAura(AuraApplication* aurApp, uint8 effMask)
SpellInfo const* spellInfo = aura->GetSpellInfo();
if (AuraStateType aState = spellInfo->GetAuraState())
{
if (aState != AURA_STATE_CONFLAGRATE)
{
// Sting (hunter's pet ability), Faerie Fire (druid versions)
if (aState == AURA_STATE_FAERIE_FIRE)
aurApp->GetTarget()->RemoveAurasByType(SPELL_AURA_MOD_STEALTH);
uint32 aStateMask = (1 << (aState - 1));
// force update so the new caster registers it
if ((aStateMask & PER_CASTER_AURA_STATE_MASK) && HasFlag(UNIT_FIELD_AURASTATE, aStateMask))
ForceValuesUpdateAtIndex(UNIT_FIELD_AURASTATE);
else
ModifyAuraState(aState, true);
}
else if (caster)
{
ConflagrateAuraStateDelayEvent* pEvent = new ConflagrateAuraStateDelayEvent(this, caster->GetGUID());
m_Events.AddEvent(pEvent, m_Events.CalculateTime(700)); // intended 700ms delay before allowing to cast conflagrate
}
}
if (aurApp->GetRemoveMode())
@@ -4575,9 +4568,19 @@ void Unit::_UnapplyAura(AuraApplicationMap::iterator& i, AuraRemoveMode removeMo
ToTotem()->setDeathState(DeathState::JustDied);
}
// Remove aurastates only if were not found
if (!auraStateFound)
ModifyAuraState(auraState, false);
// Remove aurastates only if needed and were not found
if (auraState)
{
if (!auraStateFound)
ModifyAuraState(auraState, false);
else
{
// update for casters, some shouldn't 'see' the aura state
uint32 aStateMask = (1 << (auraState - 1));
if ((aStateMask & PER_CASTER_AURA_STATE_MASK) != 0)
ForceValuesUpdateAtIndex(UNIT_FIELD_AURASTATE);
}
}
aura->HandleAuraSpecificMods(aurApp, caster, false, false);
@@ -20762,16 +20765,6 @@ int32 Unit::CalculateAOEDamageReduction(int32 damage, uint32 schoolMask, Unit* c
return damage;
}
bool ConflagrateAuraStateDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
{
if (m_owner->IsInWorld())
if (m_owner->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_WARLOCK, 0x4, 0, 0, m_casterGUID) || // immolate
m_owner->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_WARLOCK, 0, 0, 0x2, m_casterGUID)) // shadowflame
m_owner->ModifyAuraState(AURA_STATE_CONFLAGRATE, true);
return true;
}
void Unit::ExecuteDelayedUnitRelocationEvent()
{
this->RemoveFromNotify(NOTIFY_VISIBILITY_CHANGED);

View File

@@ -2674,17 +2674,6 @@ namespace Acore
};
}
class ConflagrateAuraStateDelayEvent : public BasicEvent
{
public:
ConflagrateAuraStateDelayEvent(Unit* owner, ObjectGuid casterGUID) : BasicEvent(), m_owner(owner), m_casterGUID(casterGUID) { }
bool Execute(uint64 e_time, uint32 p_time) override;
private:
Unit* m_owner;
ObjectGuid m_casterGUID;
};
class RedirectSpellEvent : public BasicEvent
{
public: