mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-31 01:23:47 +00:00
Merge branch 'master' into Playerbot
# Conflicts: # src/server/game/Server/WorldSession.cpp # src/server/game/Server/WorldSession.h
This commit is contained in:
@@ -52,6 +52,7 @@ GameObject::GameObject() : WorldObject(false), MovableMapObject(),
|
||||
m_respawnDelayTime = 300;
|
||||
m_despawnDelay = 0;
|
||||
m_despawnRespawnTime = 0s;
|
||||
m_restockTime = 0s;
|
||||
m_lootState = GO_NOT_READY;
|
||||
m_spawnedByDefault = true;
|
||||
m_allowModifyDestructibleBuilding = true;
|
||||
@@ -585,6 +586,16 @@ void GameObject::Update(uint32 diff)
|
||||
spellCaster->CastSpell(spellCaster, spellId, triggered);
|
||||
return;
|
||||
}
|
||||
case GAMEOBJECT_TYPE_CHEST:
|
||||
if (m_restockTime > GameTime::GetGameTime())
|
||||
{
|
||||
return;
|
||||
}
|
||||
// If there is no restock timer, or if the restock timer passed, the chest becomes ready to loot
|
||||
m_restockTime = 0s;
|
||||
m_lootState = GO_READY;
|
||||
AddToObjectUpdateIfNeeded();
|
||||
break;
|
||||
default:
|
||||
m_lootState = GO_READY; // for other GOis same switched without delay to GO_READY
|
||||
break;
|
||||
@@ -768,6 +779,14 @@ void GameObject::Update(uint32 diff)
|
||||
m_groupLootTimer -= diff;
|
||||
}
|
||||
}
|
||||
|
||||
// Non-consumable chest was partially looted and restock time passed, restock all loot now
|
||||
if (GetGOInfo()->chest.consumable == 0 && GameTime::GetGameTime() >= m_restockTime)
|
||||
{
|
||||
m_restockTime = 0s;
|
||||
m_lootState = GO_READY;
|
||||
AddToObjectUpdateIfNeeded();
|
||||
}
|
||||
break;
|
||||
case GAMEOBJECT_TYPE_TRAP:
|
||||
{
|
||||
@@ -826,21 +845,29 @@ void GameObject::Update(uint32 diff)
|
||||
|
||||
loot.clear();
|
||||
|
||||
//! If this is summoned by a spell with ie. SPELL_EFFECT_SUMMON_OBJECT_WILD, with or without owner, we check respawn criteria based on spell
|
||||
//! The GetOwnerGUID() check is mostly for compatibility with hacky scripts - 99% of the time summoning should be done trough spells.
|
||||
if (GetSpellId() || GetOwnerGUID())
|
||||
// Do not delete chests or goobers that are not consumed on loot, while still allowing them to despawn when they expire if summoned
|
||||
bool isSummonedAndExpired = (GetOwner() || GetSpellId()) && m_respawnTime == 0;
|
||||
if ((GetGoType() == GAMEOBJECT_TYPE_CHEST || GetGoType() == GAMEOBJECT_TYPE_GOOBER) && !GetGOInfo()->IsDespawnAtAction() && !isSummonedAndExpired)
|
||||
{
|
||||
//Don't delete spell spawned chests, which are not consumed on loot
|
||||
if (m_respawnTime > 0 && GetGoType() == GAMEOBJECT_TYPE_CHEST && !GetGOInfo()->IsDespawnAtAction())
|
||||
if (GetGoType() == GAMEOBJECT_TYPE_CHEST && GetGOInfo()->chest.chestRestockTime > 0)
|
||||
{
|
||||
UpdateObjectVisibility();
|
||||
SetLootState(GO_READY);
|
||||
// Start restock timer when the chest is fully looted
|
||||
m_restockTime = GameTime::GetGameTime() + Seconds(GetGOInfo()->chest.chestRestockTime);
|
||||
SetLootState(GO_NOT_READY);
|
||||
AddToObjectUpdateIfNeeded();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetRespawnTime(0);
|
||||
Delete();
|
||||
SetLootState(GO_READY);
|
||||
}
|
||||
|
||||
UpdateObjectVisibility();
|
||||
return;
|
||||
}
|
||||
else if (GetOwnerGUID() || GetSpellId())
|
||||
{
|
||||
SetRespawnTime(0);
|
||||
Delete();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2422,6 +2449,13 @@ void GameObject::SetLootState(LootState state, Unit* unit)
|
||||
|
||||
AI()->OnStateChanged(state, unit);
|
||||
sScriptMgr->OnGameObjectLootStateChanged(this, state, unit);
|
||||
|
||||
// Start restock timer if the chest is partially looted or not looted at all
|
||||
if (GetGoType() == GAMEOBJECT_TYPE_CHEST && state == GO_ACTIVATED && GetGOInfo()->chest.chestRestockTime > 0 && m_restockTime == 0s)
|
||||
{
|
||||
m_restockTime = GameTime::GetGameTime() + Seconds(GetGOInfo()->chest.chestRestockTime);
|
||||
}
|
||||
|
||||
// pussywizard: lootState has nothing to do with collision, it depends entirely on GOState. Loot state is for timed close/open door and respawning, which then sets GOState
|
||||
/*if (m_model)
|
||||
{
|
||||
|
||||
@@ -1072,9 +1072,10 @@ protected:
|
||||
uint32 m_respawnDelayTime; // (secs) if 0 then current GO state no dependent from timer
|
||||
uint32 m_despawnDelay;
|
||||
Seconds m_despawnRespawnTime; // override respawn time after delayed despawn
|
||||
Seconds m_restockTime;
|
||||
LootState m_lootState;
|
||||
bool m_spawnedByDefault;
|
||||
uint32 m_cooldownTime; // used as internal reaction delay time store (not state change reaction).
|
||||
uint32 m_cooldownTime; // used as internal reaction delay time store (not state change reaction).
|
||||
// For traps this: spell casting cooldown, for doors/buttons: reset time.
|
||||
std::unordered_map<ObjectGuid, int32> m_SkillupList;
|
||||
|
||||
|
||||
@@ -1737,7 +1737,7 @@ bool WorldObject::CanSeeOrDetect(WorldObject const* obj, bool ignoreStealth, boo
|
||||
// Creature scripts
|
||||
if (Creature const* cObj = obj->ToCreature())
|
||||
{
|
||||
if (Player const* player = this->ToPlayer())
|
||||
if (Player const* player = ToPlayer())
|
||||
{
|
||||
if (cObj->IsAIEnabled && !cObj->AI()->CanBeSeen(player))
|
||||
{
|
||||
@@ -1745,8 +1745,7 @@ bool WorldObject::CanSeeOrDetect(WorldObject const* obj, bool ignoreStealth, boo
|
||||
}
|
||||
|
||||
ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_CREATURE_VISIBILITY, cObj->GetEntry());
|
||||
|
||||
if (!sConditionMgr->IsObjectMeetToConditions((WorldObject*)this, conditions))
|
||||
if (!sConditionMgr->IsObjectMeetToConditions((WorldObject*)this, (WorldObject*)obj, conditions))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -1755,8 +1754,12 @@ bool WorldObject::CanSeeOrDetect(WorldObject const* obj, bool ignoreStealth, boo
|
||||
|
||||
// Gameobject scripts
|
||||
if (GameObject const* goObj = obj->ToGameObject())
|
||||
if (this->ToPlayer() && !goObj->AI()->CanBeSeen(this->ToPlayer()))
|
||||
{
|
||||
if (ToPlayer() && !goObj->AI()->CanBeSeen(ToPlayer()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// pussywizard: arena spectator
|
||||
if (obj->GetTypeId() == TYPEID_PLAYER)
|
||||
|
||||
@@ -1316,7 +1316,7 @@ public:
|
||||
void DestroyZoneLimitedItem(bool update, uint32 new_zone);
|
||||
void SplitItem(uint16 src, uint16 dst, uint32 count);
|
||||
void SwapItem(uint16 src, uint16 dst);
|
||||
void AddItemToBuyBackSlot(Item* pItem);
|
||||
void AddItemToBuyBackSlot(Item* pItem, uint32 money);
|
||||
Item* GetItemFromBuyBackSlot(uint32 slot);
|
||||
void RemoveItemFromBuyBackSlot(uint32 slot, bool del);
|
||||
[[nodiscard]] uint32 GetMaxKeyringSize() const { return KEYRING_SLOT_END - KEYRING_SLOT_START; }
|
||||
|
||||
@@ -3961,7 +3961,7 @@ void Player::SwapItem(uint16 src, uint16 dst)
|
||||
AutoUnequipOffhandIfNeed();
|
||||
}
|
||||
|
||||
void Player::AddItemToBuyBackSlot(Item* pItem)
|
||||
void Player::AddItemToBuyBackSlot(Item* pItem, uint32 money)
|
||||
{
|
||||
if (pItem)
|
||||
{
|
||||
@@ -4003,10 +4003,7 @@ void Player::AddItemToBuyBackSlot(Item* pItem)
|
||||
uint32 eslot = slot - BUYBACK_SLOT_START;
|
||||
|
||||
SetGuidValue(PLAYER_FIELD_VENDORBUYBACK_SLOT_1 + (eslot * 2), pItem->GetGUID());
|
||||
if (ItemTemplate const* proto = pItem->GetTemplate())
|
||||
SetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, proto->SellPrice * pItem->GetCount());
|
||||
else
|
||||
SetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, 0);
|
||||
SetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, money);
|
||||
SetUInt32Value(PLAYER_FIELD_BUYBACK_TIMESTAMP_1 + eslot, (uint32)etime);
|
||||
|
||||
// move to next (for non filled list is move most optimized choice)
|
||||
|
||||
@@ -1763,28 +1763,33 @@ void Player::UpdateForQuestWorldObjects()
|
||||
continue;
|
||||
|
||||
// check if this unit requires quest specific flags
|
||||
if (!obj->HasNpcFlag(UNIT_NPC_FLAG_SPELLCLICK))
|
||||
continue;
|
||||
|
||||
SpellClickInfoMapBounds clickPair = sObjectMgr->GetSpellClickInfoMapBounds(obj->GetEntry());
|
||||
for (SpellClickInfoContainer::const_iterator _itr = clickPair.first; _itr != clickPair.second; ++_itr)
|
||||
if (obj->HasNpcFlag(UNIT_NPC_FLAG_SPELLCLICK))
|
||||
{
|
||||
//! This code doesn't look right, but it was logically converted to condition system to do the exact
|
||||
//! same thing it did before. It definitely needs to be overlooked for intended functionality.
|
||||
ConditionList conds = sConditionMgr->GetConditionsForSpellClickEvent(obj->GetEntry(), _itr->second.spellId);
|
||||
bool buildUpdateBlock = false;
|
||||
for (ConditionList::const_iterator jtr = conds.begin(); jtr != conds.end() && !buildUpdateBlock; ++jtr)
|
||||
if ((*jtr)->ConditionType == CONDITION_QUESTREWARDED || (*jtr)->ConditionType == CONDITION_QUESTTAKEN)
|
||||
buildUpdateBlock = true;
|
||||
|
||||
if (buildUpdateBlock)
|
||||
SpellClickInfoMapBounds clickPair = sObjectMgr->GetSpellClickInfoMapBounds(obj->GetEntry());
|
||||
for (SpellClickInfoContainer::const_iterator _itr = clickPair.first; _itr != clickPair.second; ++_itr)
|
||||
{
|
||||
obj->BuildValuesUpdateBlockForPlayer(&udata, this);
|
||||
break;
|
||||
//! This code doesn't look right, but it was logically converted to condition system to do the exact
|
||||
//! same thing it did before. It definitely needs to be overlooked for intended functionality.
|
||||
ConditionList conds = sConditionMgr->GetConditionsForSpellClickEvent(obj->GetEntry(), _itr->second.spellId);
|
||||
bool buildUpdateBlock = false;
|
||||
for (ConditionList::const_iterator jtr = conds.begin(); jtr != conds.end() && !buildUpdateBlock; ++jtr)
|
||||
if ((*jtr)->ConditionType == CONDITION_QUESTREWARDED || (*jtr)->ConditionType == CONDITION_QUESTTAKEN)
|
||||
buildUpdateBlock = true;
|
||||
|
||||
if (buildUpdateBlock)
|
||||
{
|
||||
obj->BuildValuesUpdateBlockForPlayer(&udata, this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (obj->HasNpcFlag(UNIT_NPC_FLAG_VENDOR_MASK | UNIT_NPC_FLAG_TRAINER))
|
||||
{
|
||||
obj->BuildValuesUpdateBlockForPlayer(&udata, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
udata.BuildPacket(&packet);
|
||||
GetSession()->SendPacket(&packet);
|
||||
}
|
||||
|
||||
@@ -1031,7 +1031,7 @@ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage
|
||||
if (!attacker || attacker->IsControlledByPlayer() || attacker->IsCreatedByPlayer())
|
||||
{
|
||||
uint32 unDamage = health < damage ? health : damage;
|
||||
bool damagedByPlayer = unDamage && attacker && attacker->m_movedByPlayer != nullptr;
|
||||
bool damagedByPlayer = unDamage && attacker && (attacker->IsPlayer() || attacker->m_movedByPlayer != nullptr);
|
||||
victim->ToCreature()->LowerPlayerDamageReq(unDamage, damagedByPlayer);
|
||||
}
|
||||
}
|
||||
@@ -18215,6 +18215,11 @@ void Unit::SetControlled(bool apply, UnitState state)
|
||||
|
||||
void Unit::SetStunned(bool apply)
|
||||
{
|
||||
if (HasUnitState(UNIT_STATE_IN_FLIGHT))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (apply)
|
||||
{
|
||||
SetTarget();
|
||||
|
||||
@@ -2303,7 +2303,7 @@ public:
|
||||
void SendPetAIReaction(ObjectGuid guid);
|
||||
///----------End of Pet responses methods----------
|
||||
|
||||
void propagateSpeedChange() { GetMotionMaster()->propagateSpeedChange(); }
|
||||
void propagateSpeedChange() { GetMotionMaster()->PropagateSpeedChange(); }
|
||||
|
||||
// reactive attacks
|
||||
void ClearAllReactives();
|
||||
|
||||
Reference in New Issue
Block a user