Merge branch 'master' into Playerbot

# Conflicts:
#	src/server/game/Entities/Player/Player.cpp
#	src/server/game/Entities/Player/Player.h
#	src/server/game/Entities/Unit/Unit.h
This commit is contained in:
郑佩茹
2022-08-16 16:13:26 -06:00
159 changed files with 5246 additions and 2794 deletions
@@ -3656,3 +3656,12 @@ uint32 Creature::GetPlayerDamageReq() const
{
return _playerDamageReq;
}
std::string Creature::GetDebugInfo() const
{
std::stringstream sstr;
sstr << Unit::GetDebugInfo() << "\n"
<< "AIName: " << GetAIName() << " ScriptName: " << GetScriptName()
<< " WaypointPath: " << GetWaypointPath() << " SpawnId: " << GetSpawnId();
return sstr.str();
}
@@ -385,6 +385,8 @@ public:
void ModifyThreatPercentTemp(Unit* victim, int32 percent, Milliseconds duration);
std::string GetDebugInfo() const override;
protected:
bool CreateFromProto(ObjectGuid::LowType guidlow, uint32 Entry, uint32 vehId, const CreatureData* data = nullptr);
bool InitEntry(uint32 entry, const CreatureData* data = nullptr);
@@ -320,6 +320,15 @@ void TempSummon::RemoveFromWorld()
Creature::RemoveFromWorld();
}
std::string TempSummon::GetDebugInfo() const
{
std::stringstream sstr;
sstr << Creature::GetDebugInfo() << "\n"
<< std::boolalpha
<< "TempSummonType : " << std::to_string(GetSummonType()) << " Summoner: " << GetSummonerGUID().ToString();
return sstr.str();
}
Minion::Minion(SummonPropertiesEntry const* properties, ObjectGuid owner, bool isWorldObject) : TempSummon(properties, owner, isWorldObject)
, m_owner(owner)
{
@@ -378,6 +387,15 @@ void Minion::setDeathState(DeathState s, bool despawn)
}
}
std::string Minion::GetDebugInfo() const
{
std::stringstream sstr;
sstr << TempSummon::GetDebugInfo() << "\n"
<< std::boolalpha
<< "Owner: " << (GetOwner() ? GetOwner()->GetGUID().ToString() : "");
return sstr.str();
}
Guardian::Guardian(SummonPropertiesEntry const* properties, ObjectGuid owner, bool isWorldObject) : Minion(properties, owner, isWorldObject)
{
m_unitTypeMask |= UNIT_MASK_GUARDIAN;
@@ -416,6 +434,13 @@ void Guardian::InitSummon()
}
}
std::string Guardian::GetDebugInfo() const
{
std::stringstream sstr;
sstr << Minion::GetDebugInfo();
return sstr.str();
}
Puppet::Puppet(SummonPropertiesEntry const* properties, ObjectGuid owner) : Minion(properties, owner, false), m_owner(owner) //maybe true?
{
ASSERT(owner.IsPlayer());
@@ -52,12 +52,14 @@ public:
[[nodiscard]] Unit* GetSummonerUnit() const;
[[nodiscard]] Creature* GetSummonerCreatureBase() const;
[[nodiscard]] GameObject* GetSummonerGameObject() const;
ObjectGuid GetSummonerGUID() { return m_summonerGUID; }
TempSummonType const& GetSummonType() { return m_type; }
ObjectGuid GetSummonerGUID() const { return m_summonerGUID; }
TempSummonType GetSummonType() const { return m_type; }
uint32 GetTimer() { return m_timer; }
void SetTimer(uint32 t) { m_timer = t; }
const SummonPropertiesEntry* const m_Properties;
std::string GetDebugInfo() const override;
private:
TempSummonType m_type;
uint32 m_timer;
@@ -77,6 +79,8 @@ public:
[[nodiscard]] bool IsPetGhoul() const {return GetEntry() == 26125 /*normal ghoul*/ || GetEntry() == 30230 /*Raise Ally ghoul*/;} // Ghoul may be guardian or pet
[[nodiscard]] bool IsGuardianPet() const;
void setDeathState(DeathState s, bool despawn = false) override; // override virtual Unit::setDeathState
std::string GetDebugInfo() const override;
protected:
const ObjectGuid m_owner;
float m_followAngle;
@@ -97,6 +101,8 @@ public:
void UpdateMaxPower(Powers power) override;
void UpdateAttackPowerAndDamage(bool ranged = false) override;
void UpdateDamagePhysical(WeaponAttackType attType) override;
std::string GetDebugInfo() const override;
};
class Puppet : public Minion
@@ -131,7 +131,7 @@ void GameObject::RemoveFromOwner()
return;
}
LOG_FATAL("entities.gameobject", "Delete GameObject ({} Entry: {} SpellId {} LinkedGO {}) that lost references to owner {} GO list. Crash possible later.",
LOG_DEBUG("entities.gameobject", "Delete GameObject ({} Entry: {} SpellId {} LinkedGO {}) that lost references to owner {} GO list.",
GetGUID().ToString(), GetGOInfo()->entry, m_spellId, GetGOInfo()->GetLinkedGameObjectEntry(), ownerGUID.ToString());
SetOwnerGUID(ObjectGuid::Empty);
@@ -3091,3 +3091,11 @@ bool GameObject::IsInSkillupList(ObjectGuid playerGuid) const
return false;
}
std::string GameObject::GetDebugInfo() const
{
std::stringstream sstr;
sstr << WorldObject::GetDebugInfo() << "\n"
<< "SpawnId: " << GetSpawnId() << " GoState: " << std::to_string(GetGoState()) << " ScriptId: " << GetScriptId() << " AIName: " << GetAIName();
return sstr.str();
}
@@ -1061,6 +1061,8 @@ public:
void UpdateSaveToDb(bool enable);
void SavingStateOnDB();
std::string GetDebugInfo() const override;
protected:
bool AIM_Initialize();
GameObjectModel* CreateModel();
@@ -239,3 +239,10 @@ Item* Bag::GetItemByPos(uint8 slot) const
return nullptr;
}
std::string Bag::GetDebugInfo() const
{
std::stringstream sstr;
sstr << Item::GetDebugInfo();
return sstr.str();
}
@@ -35,7 +35,6 @@ public:
bool Create(ObjectGuid::LowType guidlow, uint32 itemid, Player const* owner) override;
void Clear();
void StoreItem(uint8 slot, Item* pItem, bool update);
void RemoveItem(uint8 slot, bool update);
@@ -58,6 +57,8 @@ public:
void BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const override;
std::string GetDebugInfo() const override;
protected:
// Bag Storage space
Item* m_bagslot[MAX_BAG_SIZE];
+11 -1
View File
@@ -1097,7 +1097,7 @@ Item* Item::CreateItem(uint32 item, uint32 count, Player const* player, bool clo
if (count > pProto->GetMaxStackSize())
count = pProto->GetMaxStackSize();
ASSERT(count != 0 && "pProto->Stackable == 0 but checked at loading already");
ASSERT_NODEBUGINFO(count != 0 && "pProto->Stackable == 0 but checked at loading already");
Item* pItem = NewItemOrBag(pProto);
if (pItem->Create(sObjectMgr->GetGenerator<HighGuid::Item>().Generate(), item, player))
@@ -1287,3 +1287,13 @@ bool Item::CheckSoulboundTradeExpire()
return false;
}
std::string Item::GetDebugInfo() const
{
std::stringstream sstr;
sstr << Object::GetDebugInfo() << "\n"
<< std::boolalpha
<< "Owner: " << GetOwnerGUID().ToString() << " Count: " << GetCount()
<< " BagSlot: " << std::to_string(GetBagSlot()) << " Slot: " << std::to_string(GetSlot()) << " Equipped: " << IsEquipped();
return sstr.str();
}
+2
View File
@@ -353,6 +353,8 @@ public:
void RemoveFromObjectUpdate() override;
[[nodiscard]] uint32 GetScriptId() const { return GetTemplate()->ScriptId; }
std::string GetDebugInfo() const override;
private:
std::string m_text;
uint8 m_slot;
@@ -1010,6 +1010,13 @@ bool Object::PrintIndexError(uint32 index, bool set) const
return false;
}
std::string Object::GetDebugInfo() const
{
std::stringstream sstr;
sstr << GetGUID().ToString() + " Entry " << GetEntry();
return sstr.str();
}
void MovementInfo::OutDebug()
{
LOG_INFO("movement", "MOVEMENT INFO");
@@ -2419,6 +2426,15 @@ Player* WorldObject::SelectNearestPlayer(float distance) const
return target;
}
std::string WorldObject::GetDebugInfo() const
{
std::stringstream sstr;
sstr << WorldLocation::GetDebugInfo() << "\n"
<< Object::GetDebugInfo() << "\n"
<< "Name: " << GetName();
return sstr.str();
}
void WorldObject::GetGameObjectListWithEntryInGrid(std::list<GameObject*>& gameobjectList, uint32 entry, float maxSearchRange) const
{
Acore::AllGameObjectsWithEntryInRange check(this, entry, maxSearchRange);
+4
View File
@@ -208,6 +208,8 @@ public:
DynamicObject* ToDynObject() { if (GetTypeId() == TYPEID_DYNAMICOBJECT) return reinterpret_cast<DynamicObject*>(this); else return nullptr; }
[[nodiscard]] DynamicObject const* ToDynObject() const { if (GetTypeId() == TYPEID_DYNAMICOBJECT) return reinterpret_cast<DynamicObject const*>(this); else return nullptr; }
virtual std::string GetDebugInfo() const;
DataMap CustomData;
protected:
@@ -613,6 +615,8 @@ public:
[[nodiscard]] bool HasAllowedLooter(ObjectGuid guid) const;
[[nodiscard]] GuidUnorderedSet const& GetAllowedLooters() const;
std::string GetDebugInfo() const override;
ElunaEventProcessor* elunaEvents;
protected:
@@ -208,3 +208,10 @@ ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZOStreamer const& st
buf << x << y << z << o;
return buf;
}
std::string WorldLocation::GetDebugInfo() const
{
std::stringstream sstr;
sstr << "MapID: " << m_mapId << " " << Position::ToString();
return sstr.str();
}
@@ -317,6 +317,8 @@ public:
}
uint32 m_mapId;
std::string GetDebugInfo() const;
};
ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYStreamer const& streamer);
+10
View File
@@ -2439,3 +2439,13 @@ std::string Pet::GenerateActionBarData() const
return oss.str();
}
std::string Pet::GetDebugInfo() const
{
std::stringstream sstr;
sstr << Guardian::GetDebugInfo() << "\n"
<< std::boolalpha
<< "PetType: " << std::to_string(getPetType()) << " "
<< "PetNumber: " << m_charmInfo->GetPetNumber();
return sstr.str();
}
+2
View File
@@ -143,6 +143,8 @@ public:
void SetLoading(bool load) { m_loading = load; }
[[nodiscard]] bool HasTempSpell() const { return m_tempspell != 0; }
std::string GetDebugInfo() const override;
protected:
Player* m_owner;
int32 m_happinessTimer;
+92 -63
View File
@@ -222,6 +222,7 @@ Player::Player(WorldSession* session): Unit(true), m_mover(this)
m_bHasDelayedTeleport = false;
teleportStore_options = 0;
m_canTeleport = false;
m_canKnockback = false;
m_trade = nullptr;
@@ -1644,10 +1645,8 @@ void Player::ProcessDelayedOperations()
{
if (m_entryPointData.HasTaxiPath())
{
for (size_t i = 0; i < m_entryPointData.taxiPath.size() - 1; ++i)
m_taxi.AddTaxiDestination(m_entryPointData.taxiPath[i]);
m_taxi.SetTaxiSegment(m_entryPointData.taxiPath[m_entryPointData.taxiPath.size() - 1]);
m_taxi.AddTaxiDestination(m_entryPointData.taxiPath[0]);
m_taxi.AddTaxiDestination(m_entryPointData.taxiPath[1]);
m_entryPointData.ClearTaxiPath();
ContinueTaxiFlight();
}
@@ -10004,26 +10003,6 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc
return false;
}
// check node starting pos data set case if provided
if (node->x != 0.0f || node->y != 0.0f || node->z != 0.0f)
{
if (node->map_id != GetMapId() ||
(node->x - GetPositionX()) * (node->x - GetPositionX()) +
(node->y - GetPositionY()) * (node->y - GetPositionY()) +
(node->z - GetPositionZ()) * (node->z - GetPositionZ()) >
(2 * INTERACTION_DISTANCE) * (2 * INTERACTION_DISTANCE) * (2 * INTERACTION_DISTANCE))
{
GetSession()->SendActivateTaxiReply(ERR_TAXITOOFARAWAY);
return false;
}
}
// node must have pos if taxi master case (npc != nullptr)
else if (npc)
{
GetSession()->SendActivateTaxiReply(ERR_TAXIUNSPECIFIEDSERVERERROR);
return false;
}
// Prepare to flight start now
// stop combat at start taxi flight if any
@@ -10045,6 +10024,7 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc
// fill destinations path tail
uint32 sourcepath = 0;
uint32 totalcost = 0;
uint32 firstcost = 0;
uint32 prevnode = sourcenode;
uint32 lastnode = 0;
@@ -10063,6 +10043,8 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc
}
totalcost += cost;
if (i == 1)
firstcost = cost;
if (prevnode == sourcenode)
sourcepath = path;
@@ -10091,7 +10073,16 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc
uint32 money = GetMoney();
if (npc)
totalcost = (uint32)ceil(totalcost * GetReputationPriceDiscount(npc));
{
float discount = GetReputationPriceDiscount(npc);
totalcost = uint32(ceil(totalcost * discount));
firstcost = uint32(ceil(firstcost * discount));
m_taxi.SetFlightMasterFactionTemplateId(npc->GetFaction());
}
else
{
m_taxi.SetFlightMasterFactionTemplateId(0);
}
if (money < totalcost)
{
@@ -10102,8 +10093,6 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc
//Checks and preparations done, DO FLIGHT
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN, 1);
ModifyMoney(-(int32)totalcost);
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING, totalcost);
// prevent stealth flight
//RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TALK);
@@ -10113,12 +10102,16 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc
{
TaxiNodesEntry const* lastPathNode = sTaxiNodesStore.LookupEntry(nodes[nodes.size() - 1]);
m_taxi.ClearTaxiDestinations();
ModifyMoney(-(int32)totalcost);
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING, totalcost);
TeleportTo(lastPathNode->map_id, lastPathNode->x, lastPathNode->y, lastPathNode->z, GetOrientation());
return false;
}
else
{
m_flightSpellActivated = spellid;
ModifyMoney(-(int32)firstcost);
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING, firstcost);
GetSession()->SendActivateTaxiReply(ERR_TAXIOK);
GetSession()->SendDoFlight(mount_display_id, sourcepath);
}
@@ -10214,6 +10207,39 @@ void Player::ContinueTaxiFlight()
GetSession()->SendDoFlight(mountDisplayId, path, startNode);
}
void Player::SendTaxiNodeStatusMultiple()
{
for (auto itr = m_clientGUIDs.begin(); itr != m_clientGUIDs.end(); ++itr)
{
if (!itr->IsCreature())
{
continue;
}
Creature* creature = ObjectAccessor::GetCreature(*this, *itr);
if (!creature || creature->IsHostileTo(this))
{
continue;
}
if (!creature->HasNpcFlag(UNIT_NPC_FLAG_FLIGHTMASTER))
{
continue;
}
uint32 nearestNode = sObjectMgr->GetNearestTaxiNode(creature->GetPositionX(), creature->GetPositionY(), creature->GetPositionZ(), creature->GetMapId(), GetTeamId());
if (!nearestNode)
{
continue;
}
WorldPacket data(SMSG_TAXINODE_STATUS, 9);
data << *itr;
data << uint8(m_taxi.IsTaximaskNodeKnown(nearestNode) ? 1 : 0);
SendDirectMessage(&data);
}
}
void Player::ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs)
{
PacketCooldowns cooldowns;
@@ -10984,11 +11010,8 @@ void Player::SetEntryPoint()
m_entryPointData.mountSpell = 0;
m_entryPointData.joinPos = WorldLocation(GetMapId(), GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
std::vector<uint32> const& taxi = m_taxi.GetPath();
for (std::vector<uint32>::const_iterator itr = taxi.begin(); itr != taxi.end(); ++itr)
m_entryPointData.taxiPath.push_back(*itr);
m_entryPointData.taxiPath.push_back(m_taxi.GetTaxiSegment());
m_entryPointData.taxiPath[0] = m_taxi.GetTaxiSource();
m_entryPointData.taxiPath[1] = m_taxi.GetTaxiDestination();
}
else
{
@@ -11353,6 +11376,7 @@ void Player::SendInitialPacketsAfterAddToMap()
SendEnchantmentDurations(); // must be after add to map
SendItemDurations(); // must be after add to map
SendQuestGiverStatusMultiple();
SendTaxiNodeStatusMultiple();
// raid downscaling - send difficulty to player
if (GetMap()->IsRaid())
@@ -12007,23 +12031,21 @@ bool Player::GetBGAccessByLevel(BattlegroundTypeId bgTypeId) const
float Player::GetReputationPriceDiscount(Creature const* creature) const
{
FactionTemplateEntry const* vendorFaction = creature->GetFactionTemplateEntry();
if (!vendorFaction)
return GetReputationPriceDiscount(creature->GetFactionTemplateEntry());
}
float Player::GetReputationPriceDiscount(FactionTemplateEntry const* factionTemplate) const
{
if (!factionTemplate || !factionTemplate->faction)
{
return 1.0f;
}
return GetReputationPriceDiscount(vendorFaction);
}
float Player::GetReputationPriceDiscount(FactionTemplateEntry const* vendorFaction) const
{
if (!vendorFaction->faction)
return 1.0f;
ReputationRank rank = GetReputationRank(vendorFaction->faction);
ReputationRank rank = GetReputationRank(factionTemplate->faction);
if (rank <= REP_NEUTRAL)
{
return 1.0f;
}
return 1.0f - 0.05f * (rank - REP_NEUTRAL);
}
@@ -13875,20 +13897,27 @@ void Player::ResummonPetTemporaryUnSummonedIfAny()
bool Player::CanResummonPet(uint32 spellid)
{
if (getClass() == CLASS_DEATH_KNIGHT)
switch (getClass())
{
if (CanSeeDKPet())
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:
return true;
else if (spellid == 52150)
return false;
break;
default:
break;
}
else if (getClass() == CLASS_HUNTER || getClass() == CLASS_MAGE || getClass() == CLASS_WARLOCK)
return true;
if (!HasSpell(spellid))
return false;
return true;
return HasSpell(spellid);
}
bool Player::CanSeeSpellClickOn(Creature const* c) const
@@ -14228,16 +14257,9 @@ void Player::_SaveEntryPoint(CharacterDatabaseTransaction trans)
stmt->SetData (3, m_entryPointData.joinPos.GetPositionZ());
stmt->SetData (4, m_entryPointData.joinPos.GetOrientation());
stmt->SetData(5, m_entryPointData.joinPos.GetMapId());
std::ostringstream ss("");
if (m_entryPointData.HasTaxiPath())
{
for (size_t i = 0; i < m_entryPointData.taxiPath.size(); ++i)
ss << m_entryPointData.taxiPath[i] << ' '; // xinef: segment is stored as last point
}
stmt->SetData(6, ss.str());
stmt->SetData(7, m_entryPointData.mountSpell);
stmt->SetData(6, m_entryPointData.taxiPath[0]);
stmt->SetData(7, m_entryPointData.taxiPath[1]);
stmt->SetData(8, m_entryPointData.mountSpell);
trans->Append(stmt);
}
@@ -15958,3 +15980,10 @@ void Player::ResetSpeakTimers()
m_speakTime = 0;
m_speakCount = 0;
}
std::string Player::GetDebugInfo() const
{
std::stringstream sstr;
sstr << Unit::GetDebugInfo();
return sstr.str();
}
+11 -5
View File
@@ -1035,11 +1035,11 @@ struct EntryPointData
}
uint32 mountSpell{0};
std::vector<uint32> taxiPath;
std::array<uint32, 2> taxiPath;
WorldLocation joinPos;
void ClearTaxiPath() { taxiPath.clear(); }
[[nodiscard]] bool HasTaxiPath() const { return !taxiPath.empty(); }
void ClearTaxiPath() { taxiPath.fill(0); }
[[nodiscard]] bool HasTaxiPath() const { return taxiPath[0] && taxiPath[1]; }
};
class Player : public Unit, public GridObject<Player>
@@ -1126,6 +1126,7 @@ public:
bool ActivateTaxiPathTo(uint32 taxi_path_id, uint32 spellid = 1);
void CleanupAfterTaxiFlight();
void ContinueTaxiFlight();
void SendTaxiNodeStatusMultiple();
// mount_id can be used in scripting calls
[[nodiscard]] bool IsDeveloper() const { return HasPlayerFlag(PLAYER_FLAGS_DEVELOPER); }
@@ -1336,8 +1337,8 @@ public:
bool BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uint32 item, uint8 count, uint8 bag, uint8 slot);
bool _StoreOrEquipNewItem(uint32 vendorslot, uint32 item, uint8 count, uint8 bag, uint8 slot, int32 price, ItemTemplate const* pProto, Creature* pVendor, VendorItem const* crItem, bool bStore);
float GetReputationPriceDiscount(Creature const* creature) const;
float GetReputationPriceDiscount(FactionTemplateEntry const* vendorFaction) const;
[[nodiscard]] float GetReputationPriceDiscount(Creature const* creature) const;
[[nodiscard]] float GetReputationPriceDiscount(FactionTemplateEntry const* factionTemplate) const;
[[nodiscard]] Player* GetTrader() const { return m_trade ? m_trade->GetTrader() : nullptr; }
[[nodiscard]] TradeData* GetTradeData() const { return m_trade; }
@@ -2429,6 +2430,8 @@ public:
bool CanTeleport() { return m_canTeleport; }
void SetCanTeleport(bool value) { m_canTeleport = value; }
bool CanKnockback() { return m_canKnockback; }
void SetCanKnockback(bool value) { m_canKnockback = value; }
bool isAllowedToLoot(Creature const* creature);
@@ -2557,6 +2560,8 @@ public:
void ResetSpeakTimers();
std::string GetDebugInfo() const override;
protected:
// Gamemaster whisper whitelist
WhisperListContainer WhisperList;
@@ -2884,6 +2889,7 @@ private:
bool m_bMustDelayTeleport;
bool m_bHasDelayedTeleport;
bool m_canTeleport;
bool m_canKnockback;
std::unique_ptr<PetStable> m_petStable;
@@ -4894,21 +4894,9 @@ void Player::_LoadEntryPointData(PreparedQueryResult result)
fields[2].Get<float>(), // Z
fields[3].Get<float>()); // Orientation
std::string_view taxi = fields[5].Get<std::string_view>();
if (!taxi.empty())
{
for (auto const& itr : Acore::Tokenize(taxi, ' ', false))
{
uint32 node = Acore::StringTo<uint32>(itr).value_or(0);
m_entryPointData.taxiPath.emplace_back(node);
}
// Check integrity
if (m_entryPointData.taxiPath.size() < 3)
m_entryPointData.ClearTaxiPath();
}
m_entryPointData.mountSpell = fields[6].Get<uint32>();
m_entryPointData.taxiPath[0] = fields[5].Get<uint32>();
m_entryPointData.taxiPath[1] = fields[6].Get<uint32>();
m_entryPointData.mountSpell = fields[7].Get<uint32>();
}
bool Player::LoadPositionFromDB(uint32& mapid, float& x, float& y, float& z, float& o, bool& in_flight, ObjectGuid::LowType guid)
@@ -5190,10 +5178,8 @@ bool Player::LoadFromDB(ObjectGuid playerGuid, CharacterDatabaseQueryHolder cons
// xinef: restore taxi flight from entry point data
if (m_entryPointData.HasTaxiPath())
{
for (size_t i = 0; i < m_entryPointData.taxiPath.size() - 1; ++i)
m_taxi.AddTaxiDestination(m_entryPointData.taxiPath[i]);
m_taxi.SetTaxiSegment(m_entryPointData.taxiPath[m_entryPointData.taxiPath.size() - 1]);
m_taxi.AddTaxiDestination(m_entryPointData.taxiPath[0]);
m_taxi.AddTaxiDestination(m_entryPointData.taxiPath[1]);
m_entryPointData.ClearTaxiPath();
}
}
+48 -17
View File
@@ -20,11 +20,6 @@
#include "Tokenize.h"
#include "StringConvert.h"
PlayerTaxi::PlayerTaxi() : _taxiSegment(0)
{
memset(m_taximask, 0, sizeof(m_taximask));
}
void PlayerTaxi::InitTaxiNodesForLevel(uint32 race, uint32 chrClass, uint8 level)
{
// class specific initial known nodes
@@ -136,9 +131,25 @@ bool PlayerTaxi::LoadTaxiDestinationsFromString(const std::string& values, TeamI
{
ClearTaxiDestinations();
for (auto const& itr : Acore::Tokenize(values, ' ', false))
std::vector<std::string_view> tokens = Acore::Tokenize(values, ' ', false);
auto itr = tokens.begin();
if (itr != tokens.end())
{
if (Optional<uint32> node = Acore::StringTo<uint32>(itr))
if (Optional<uint32> faction = Acore::StringTo<uint32>(*itr))
{
m_flightMasterFactionId = *faction;
}
else
{
return false;
}
}
else
return false;
while ((++itr) != tokens.end())
{
if (Optional<uint32> node = Acore::StringTo<uint32>(*itr))
{
AddTaxiDestination(*node);
}
@@ -148,26 +159,33 @@ bool PlayerTaxi::LoadTaxiDestinationsFromString(const std::string& values, TeamI
}
}
if (m_TaxiDestinations.empty())
{
return true;
}
// Check integrity
if (m_TaxiDestinations.size() < 3)
if (m_TaxiDestinations.size() < 2)
{
return false;
}
// xinef: current segment is saved as last destination in db
_taxiSegment = m_TaxiDestinations[m_TaxiDestinations.size() - 1];
m_TaxiDestinations.pop_back();
for (size_t i = 0; i < m_TaxiDestinations.size() - 1; ++i)
for (size_t i = 1; i < m_TaxiDestinations.size(); ++i)
{
uint32 cost;
uint32 path;
sObjectMgr->GetTaxiPath(m_TaxiDestinations[i], m_TaxiDestinations[i + 1], path, cost);
sObjectMgr->GetTaxiPath(m_TaxiDestinations[i - 1], m_TaxiDestinations[i], path, cost);
if (!path)
{
return false;
}
}
// can't load taxi path without mount set (quest taxi path?)
if (!sObjectMgr->GetTaxiMountDisplayId(GetTaxiSource(), teamId, true))
{
return false;
}
return true;
}
@@ -175,26 +193,34 @@ bool PlayerTaxi::LoadTaxiDestinationsFromString(const std::string& values, TeamI
std::string PlayerTaxi::SaveTaxiDestinationsToString()
{
if (m_TaxiDestinations.empty())
{
return "";
}
ASSERT(m_TaxiDestinations.size() >= 2);
std::ostringstream ss;
ss << m_flightMasterFactionId << ' ';
for (size_t i = 0; i < m_TaxiDestinations.size(); ++i)
{
ss << m_TaxiDestinations[i] << ' ';
}
ss << _taxiSegment << ' ';
return ss.str();
}
uint32 PlayerTaxi::GetCurrentTaxiPath() const
{
if (m_TaxiDestinations.size() < 2 || m_TaxiDestinations.size() <= _taxiSegment + 1)
if (m_TaxiDestinations.size() < 2)
{
return 0;
}
uint32 path;
uint32 cost;
sObjectMgr->GetTaxiPath(m_TaxiDestinations[_taxiSegment], m_TaxiDestinations[_taxiSegment + 1], path, cost);
sObjectMgr->GetTaxiPath(m_TaxiDestinations[0], m_TaxiDestinations[1], path, cost);
return path;
}
@@ -205,3 +231,8 @@ std::ostringstream& operator<< (std::ostringstream& ss, PlayerTaxi const& taxi)
ss << taxi.m_taximask[i] << ' ';
return ss;
}
FactionTemplateEntry const* PlayerTaxi::GetFlightMasterFactionTemplate() const
{
return sFactionTemplateStore.LookupEntry(m_flightMasterFactionId);
}
+11 -12
View File
@@ -26,7 +26,7 @@ class ByteBuffer;
class AC_GAME_API PlayerTaxi
{
public:
PlayerTaxi();
PlayerTaxi() : m_flightMasterFactionId(0) { m_taximask.fill(0); }
~PlayerTaxi() = default;
// Nodes
@@ -59,29 +59,28 @@ public:
bool LoadTaxiDestinationsFromString(std::string const& values, TeamId teamId);
std::string SaveTaxiDestinationsToString();
void ClearTaxiDestinations() { m_TaxiDestinations.clear(); _taxiSegment = 0; }
void ClearTaxiDestinations() { m_TaxiDestinations.clear(); }
void AddTaxiDestination(uint32 dest) { m_TaxiDestinations.push_back(dest); }
[[nodiscard]] uint32 GetTaxiSource() const { return m_TaxiDestinations.size() <= _taxiSegment + 1 ? 0 : m_TaxiDestinations[_taxiSegment]; }
[[nodiscard]] uint32 GetTaxiDestination() const { return m_TaxiDestinations.size() <= _taxiSegment + 1 ? 0 : m_TaxiDestinations[_taxiSegment + 1]; }
[[nodiscard]] uint32 GetTaxiSource() const { return m_TaxiDestinations.empty() ? 0 : m_TaxiDestinations.front(); }
[[nodiscard]] uint32 GetTaxiDestination() const { return m_TaxiDestinations.size() < 2 ? 0 : m_TaxiDestinations[1]; }
[[nodiscard]] uint32 GetCurrentTaxiPath() const;
uint32 NextTaxiDestination()
{
++_taxiSegment;
m_TaxiDestinations.pop_front();
return GetTaxiDestination();
}
// xinef:
void SetTaxiSegment(uint32 segment) { _taxiSegment = segment; }
[[nodiscard]] uint32 GetTaxiSegment() const { return _taxiSegment; }
[[nodiscard]] std::vector<uint32> const& GetPath() const { return m_TaxiDestinations; }
[[nodiscard]] std::deque<uint32> const& GetPath() const { return m_TaxiDestinations; }
[[nodiscard]] bool empty() const { return m_TaxiDestinations.empty(); }
[[nodiscard]] FactionTemplateEntry const* GetFlightMasterFactionTemplate() const;
void SetFlightMasterFactionTemplateId(uint32 factionTemplateId) { m_flightMasterFactionId = factionTemplateId; }
friend std::ostringstream& operator<< (std::ostringstream& ss, PlayerTaxi const& taxi);
private:
TaxiMask m_taximask;
std::vector<uint32> m_TaxiDestinations;
uint32 _taxiSegment;
std::deque<uint32> m_TaxiDestinations;
uint32 m_flightMasterFactionId;
};
#endif
+31 -29
View File
@@ -116,38 +116,40 @@ void Totem::UnSummon(uint32 msTime)
CombatStop();
RemoveAurasDueToSpell(GetSpell(), GetGUID());
Unit* owner = GetOwner();
// clear owner's totem slot
for (uint8 i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i)
if (Unit* owner = GetOwner())
{
if (owner->m_SummonSlot[i] == GetGUID())
// clear owner's totem slot
for (uint8 i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i)
{
owner->m_SummonSlot[i].Clear();
break;
}
}
owner->RemoveAurasDueToSpell(GetSpell(), GetGUID());
// Remove Sentry Totem Aura
if (GetEntry() == SENTRY_TOTEM_ENTRY)
owner->RemoveAurasDueToSpell(SENTRY_TOTEM_SPELLID);
//remove aura all party members too
if (Player* player = owner->ToPlayer())
{
player->SendAutoRepeatCancel(this);
if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(GetUInt32Value(UNIT_CREATED_BY_SPELL)))
player->SendCooldownEvent(spell, 0, nullptr, false);
if (Group* group = player->GetGroup())
{
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
if (owner->m_SummonSlot[i] == GetGUID())
{
Player* target = itr->GetSource();
if (target && target->IsInMap(player) && group->SameSubGroup(player, target))
target->RemoveAurasDueToSpell(GetSpell(), GetGUID());
owner->m_SummonSlot[i].Clear();
break;
}
}
owner->RemoveAurasDueToSpell(GetSpell(), GetGUID());
// Remove Sentry Totem Aura
if (GetEntry() == SENTRY_TOTEM_ENTRY)
owner->RemoveAurasDueToSpell(SENTRY_TOTEM_SPELLID);
//remove aura all party members too
if (Player* player = owner->ToPlayer())
{
player->SendAutoRepeatCancel(this);
if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(GetUInt32Value(UNIT_CREATED_BY_SPELL)))
player->SendCooldownEvent(spell, 0, nullptr, false);
if (Group* group = player->GetGroup())
{
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
{
Player* target = itr->GetSource();
if (target && target->IsInMap(player) && group->SameSubGroup(player, target))
target->RemoveAurasDueToSpell(GetSpell(), GetGUID());
}
}
}
}
@@ -1004,3 +1004,10 @@ void StaticTransport::RemovePassenger(WorldObject* passenger, bool withAll)
}
}
}
std::string MotionTransport::GetDebugInfo() const
{
std::stringstream sstr;
sstr << GameObject::GetDebugInfo();
return sstr.str();
}
@@ -78,6 +78,7 @@ public:
uint32 GetPeriod() const { return GetUInt32Value(GAMEOBJECT_LEVEL); }
void SetPeriod(uint32 period) { SetUInt32Value(GAMEOBJECT_LEVEL, period); }
std::string GetDebugInfo() const override;
private:
void MoveToNextWaypoint();
float CalculateSegmentPos(float perc);
+35 -14
View File
@@ -465,6 +465,7 @@ void Unit::Update(uint32 p_time)
// xinef: if attack time > 0, reduce by diff
// if on next update, attack time < 0 assume player didnt attack - set to 0
bool suspendAttackTimer = false;
bool suspendRangedAttackTimer = false;
if (IsPlayer() && HasUnitState(UNIT_STATE_CASTING))
{
for (Spell* spell : m_currentSpells)
@@ -473,6 +474,11 @@ void Unit::Update(uint32 p_time)
{
if (spell->GetSpellInfo()->HasAttribute(SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS))
{
if (spell->IsChannelActive())
{
suspendRangedAttackTimer = true;
}
suspendAttackTimer = true;
break;
}
@@ -493,9 +499,12 @@ void Unit::Update(uint32 p_time)
}
}
if (int32 ranged_attack = getAttackTimer(RANGED_ATTACK))
if (!suspendRangedAttackTimer)
{
setAttackTimer(RANGED_ATTACK, ranged_attack > 0 ? ranged_attack - (int32) p_time : 0);
if (int32 ranged_attack = getAttackTimer(RANGED_ATTACK))
{
setAttackTimer(RANGED_ATTACK, ranged_attack > 0 ? ranged_attack - (int32)p_time : 0);
}
}
// update abilities available only for fraction of time
@@ -1109,7 +1118,7 @@ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage
{
Player* he = duel_wasMounted ? victim->GetCharmer()->ToPlayer() : victim->ToPlayer();
ASSERT(he && he->duel);
ASSERT_NODEBUGINFO(he && he->duel);
if (duel_wasMounted) // In this case victim==mount
victim->SetHealth(1);
@@ -2415,7 +2424,7 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType /*= BASE_A
DealMeleeDamage(&damageInfo, true);
DamageInfo dmgInfo(damageInfo);
ProcDamageAndSpell(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage,
Unit::ProcDamageAndSpell(damageInfo.attacker, damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage,
damageInfo.attackType, nullptr, nullptr, -1, nullptr, &dmgInfo);
if (GetTypeId() == TYPEID_PLAYER)
@@ -5961,15 +5970,15 @@ void Unit::SendSpellNonMeleeDamageLog(Unit* target, SpellInfo const* spellInfo,
SendSpellNonMeleeDamageLog(&log);
}
void Unit::ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 amount, WeaponAttackType attType, SpellInfo const* procSpellInfo, SpellInfo const* procAura, int8 procAuraEffectIndex, Spell const* procSpell, DamageInfo* damageInfo, HealInfo* healInfo, uint32 procPhase)
void Unit::ProcDamageAndSpell(Unit* actor, Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 amount, WeaponAttackType attType, SpellInfo const* procSpellInfo, SpellInfo const* procAura, int8 procAuraEffectIndex, Spell const* procSpell, DamageInfo* damageInfo, HealInfo* healInfo, uint32 procPhase)
{
// Not much to do if no flags are set.
if (procAttacker)
ProcDamageAndSpellFor(false, victim, procAttacker, procExtra, attType, procSpellInfo, amount, procAura, procAuraEffectIndex, procSpell, damageInfo, healInfo, procPhase);
if (procAttacker && actor)
actor->ProcDamageAndSpellFor(false, victim, procAttacker, procExtra, attType, procSpellInfo, amount, procAura, procAuraEffectIndex, procSpell, damageInfo, healInfo, procPhase);
// Now go on with a victim's events'n'auras
// Not much to do if no flags are set or there is no victim
if (victim && victim->IsAlive() && procVictim)
victim->ProcDamageAndSpellFor(true, this, procVictim, procExtra, attType, procSpellInfo, amount, procAura, procAuraEffectIndex, procSpell, damageInfo, healInfo, procPhase);
victim->ProcDamageAndSpellFor(true, actor, procVictim, procExtra, attType, procSpellInfo, amount, procAura, procAuraEffectIndex, procSpell, damageInfo, healInfo, procPhase);
}
void Unit::SendPeriodicAuraLog(SpellPeriodicAuraLogInfo* pInfo)
@@ -6151,7 +6160,7 @@ void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 /*SwingType
}
//victim may be nullptr
bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown)
bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, Spell const* spellProc /*= nullptr*/)
{
SpellInfo const* dummySpell = triggeredByAura->GetSpellInfo();
uint32 effIndex = triggeredByAura->GetEffIndex();
@@ -7077,7 +7086,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
case 28719:
{
// mana back
basepoints0 = int32(CalculatePct(procSpell->ManaCost, 30));
basepoints0 = int32(CalculatePct(spellProc->GetPowerCost(), 30));
target = this;
triggered_spell_id = 28742;
break;
@@ -16009,7 +16018,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
case SPELL_AURA_DUMMY:
{
LOG_DEBUG("spells.aura", "ProcDamageAndSpell: casting spell id {} (triggered by {} dummy aura of spell {})", spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId());
if (HandleDummyAuraProc(target, damage, triggeredByAura, procSpellInfo, procFlag, procExtra, cooldown))
if (HandleDummyAuraProc(target, damage, triggeredByAura, procSpellInfo, procFlag, procExtra, cooldown, procSpell))
takeCharges = true;
break;
}
@@ -17406,15 +17415,15 @@ void Unit::Kill(Unit* killer, Unit* victim, bool durabilityLoss, WeaponAttackTyp
if (killer && (killer->IsPet() || killer->IsTotem()))
if (Unit* owner = killer->GetOwner())
{
owner->ProcDamageAndSpell(victim, PROC_FLAG_KILL, PROC_FLAG_NONE, PROC_EX_NONE, 0, attackType, spellProto, nullptr, -1, spell);
Unit::ProcDamageAndSpell(owner, victim, PROC_FLAG_KILL, PROC_FLAG_NONE, PROC_EX_NONE, 0, attackType, spellProto, nullptr, -1, spell);
sScriptMgr->OnCreatureKilledByPet( killer->GetCharmerOrOwnerPlayerOrPlayerItself(), victim->ToCreature());
}
if (killer != victim && !victim->IsCritter())
killer->ProcDamageAndSpell(victim, killer ? PROC_FLAG_KILL : 0, PROC_FLAG_KILLED, PROC_EX_NONE, 0, attackType, spellProto, nullptr, -1, spell);
Unit::ProcDamageAndSpell(killer, victim, killer ? PROC_FLAG_KILL : 0, PROC_FLAG_KILLED, PROC_EX_NONE, 0, attackType, spellProto, nullptr, -1, spell);
// Proc auras on death - must be before aura/combat remove
victim->ProcDamageAndSpell(nullptr, PROC_FLAG_DEATH, PROC_FLAG_NONE, PROC_EX_NONE, 0, attackType, spellProto, nullptr, -1, spell);
Unit::ProcDamageAndSpell(victim, nullptr, PROC_FLAG_DEATH, PROC_FLAG_NONE, PROC_EX_NONE, 0, attackType, spellProto, nullptr, -1, spell);
// update get killing blow achievements, must be done before setDeathState to be able to require auras on target
// and before Spirit of Redemption as it also removes auras
@@ -18750,6 +18759,7 @@ void Unit::KnockbackFrom(float x, float y, float speedXY, float speedZ)
player->SetCanFly(true, true);
sScriptMgr->AnticheatSetSkipOnePacketForASH(player, true);
player->SetCanKnockback(true);
}
}
@@ -20843,3 +20853,14 @@ bool Unit::IsInDisallowedMountForm() const
return false;
}
std::string Unit::GetDebugInfo() const
{
std::stringstream sstr;
sstr << WorldObject::GetDebugInfo() << "\n"
<< std::boolalpha
<< "AliveState: " << IsAlive()
<< " UnitMovementFlags: " << GetUnitMovementFlags() << " ExtraUnitMovementFlags: " << GetExtraUnitMovementFlags()
<< " Class: " << std::to_string(getClass());
return sstr.str();
}
+4 -2
View File
@@ -1525,7 +1525,7 @@ public:
static void Kill(Unit* killer, Unit* victim, bool durabilityLoss = true, WeaponAttackType attackType = BASE_ATTACK, SpellInfo const* spellProto = nullptr, Spell const* spell = nullptr);
static int32 DealHeal(Unit* healer, Unit* victim, uint32 addhealth);
void ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procEx, uint32 amount, WeaponAttackType attType = BASE_ATTACK, SpellInfo const* procSpellInfo = nullptr, SpellInfo const* procAura = nullptr, int8 procAuraEffectIndex = -1, Spell const* procSpell = nullptr, DamageInfo* damageInfo = nullptr, HealInfo* healInfo = nullptr, uint32 procPhase = 2 /*PROC_SPELL_PHASE_HIT*/);
static void ProcDamageAndSpell(Unit* actor, Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procEx, uint32 amount, WeaponAttackType attType = BASE_ATTACK, SpellInfo const* procSpellInfo = nullptr, SpellInfo const* procAura = nullptr, int8 procAuraEffectIndex = -1, Spell const* procSpell = nullptr, DamageInfo* damageInfo = nullptr, HealInfo* healInfo = nullptr, uint32 procPhase = 2 /*PROC_SPELL_PHASE_HIT*/);
void ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellInfo const* procSpellInfo, uint32 damage, SpellInfo const* procAura = nullptr, int8 procAuraEffectIndex = -1, Spell const* procSpell = nullptr, DamageInfo* damageInfo = nullptr, HealInfo* healInfo = nullptr, uint32 procPhase = 2 /*PROC_SPELL_PHASE_HIT*/);
void GetProcAurasTriggeredOnEvent(std::list<AuraApplication*>& aurasTriggeringProc, std::list<AuraApplication*>* procAuras, ProcEventInfo eventInfo);
@@ -2431,6 +2431,8 @@ public:
virtual bool SetCannotReachTarget(bool cannotReach, bool isChase = true);
[[nodiscard]] bool CanNotReachTarget() const { return m_cannotReachTarget; }
std::string GetDebugInfo() const override;
protected:
explicit Unit (bool isWorldObject);
@@ -2515,7 +2517,7 @@ protected:
private:
bool IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent, ProcEventInfo const& eventInfo);
bool HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
bool HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, Spell const* spellProc = nullptr);
bool HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, bool* handled);
bool HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, uint32 procPhase, ProcEventInfo& eventInfo);
bool HandleOverrideClassScriptAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 cooldown);