Merge branch 'azerothcore:master' into Playerbot

This commit is contained in:
ZhengPeiRu21
2022-04-16 21:41:45 -06:00
committed by GitHub
240 changed files with 14385 additions and 4083 deletions

View File

@@ -202,7 +202,7 @@ bool ForcedDespawnDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
}
Creature::Creature(bool isWorldObject): Unit(isWorldObject), MovableMapObject(), m_groupLootTimer(0), lootingGroupLowGUID(0), m_PlayerDamageReq(0), m_lootRecipientGroup(0),
m_corpseRemoveTime(0), m_respawnTime(0), m_respawnDelay(300), m_corpseDelay(60), m_wanderDistance(0.0f),
m_corpseRemoveTime(0), m_respawnTime(0), m_respawnDelay(300), m_corpseDelay(60), m_wanderDistance(0.0f), m_boundaryCheckTime(2500),
m_transportCheckTimer(1000), lootPickPocketRestoreTime(0), m_reactState(REACT_AGGRESSIVE), m_defaultMovementType(IDLE_MOTION_TYPE),
m_spawnId(0), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false),
m_AlreadySearchedAssistance(false), m_regenHealth(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), m_moveInLineOfSightDisabled(false), m_moveInLineOfSightStrictlyDisabled(false),
@@ -689,6 +689,17 @@ void Creature::Update(uint32 diff)
SelectVictim();
}
// periodic check to see if the creature has passed an evade boundary
if (IsAIEnabled && !IsInEvadeMode() && IsInCombat())
{
if (diff >= m_boundaryCheckTime)
{
AI()->CheckInRoom();
m_boundaryCheckTime = 2500;
} else
m_boundaryCheckTime -= diff;
}
Unit* owner = GetCharmerOrOwner();
if (IsCharmed() && !IsWithinDistInMap(owner, GetMap()->GetVisibilityRange(), true, false))
{

View File

@@ -285,6 +285,8 @@ public:
[[nodiscard]] float GetWanderDistance() const { return m_wanderDistance; }
void SetWanderDistance(float dist) { m_wanderDistance = dist; }
void DoImmediateBoundaryCheck() { m_boundaryCheckTime = 0; }
uint32 m_groupLootTimer; // (msecs)timer used for group loot
uint32 lootingGroupLowGUID; // used to find group which is looting corpse
@@ -401,6 +403,7 @@ protected:
uint32 m_respawnDelay; // (secs) delay between corpse disappearance and respawning
uint32 m_corpseDelay; // (secs) delay between death and corpse disappearance
float m_wanderDistance;
uint32 m_boundaryCheckTime; // (msecs) remaining time for next evade boundary check
uint16 m_transportCheckTimer;
uint32 lootPickPocketRestoreTime;

View File

@@ -15,8 +15,8 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Define.h"
#include "Item.h"
#include "Define.h"
#include "SmartEnum.h"
#include <stdexcept>

View File

@@ -2304,7 +2304,7 @@ TempSummon* WorldObject::SummonCreature(uint32 entry, const Position& pos, TempS
return nullptr;
}
GameObject* WorldObject::SummonGameObject(uint32 entry, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime, bool checkTransport)
GameObject* WorldObject::SummonGameObject(uint32 entry, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime, bool checkTransport, GOSummonType summonType)
{
if (!IsInWorld())
return nullptr;
@@ -2330,7 +2330,7 @@ GameObject* WorldObject::SummonGameObject(uint32 entry, float x, float y, float
if (respawnTime)
go->SetSpellId(1);
if (GetTypeId() == TYPEID_PLAYER || GetTypeId() == TYPEID_UNIT) //not sure how to handle this
if (GetTypeId() == TYPEID_PLAYER || (GetTypeId() == TYPEID_UNIT && summonType == GO_SUMMON_TIMED_OR_CORPSE_DESPAWN)) //not sure how to handle this
ToUnit()->AddGameObject(go);
else
go->SetSpawnedByDefault(false);

View File

@@ -65,6 +65,12 @@ enum NotifyFlags
NOTIFY_ALL = 0xFF
};
enum GOSummonType
{
GO_SUMMON_TIMED_OR_CORPSE_DESPAWN = 0, // despawns after a specified time OR when the summoner dies
GO_SUMMON_TIMED_DESPAWN = 1 // despawns after a specified time
};
class WorldPacket;
class UpdateData;
class ByteBuffer;
@@ -516,7 +522,7 @@ public:
TempSummon* SummonCreature(uint32 id, const Position& pos, TempSummonType spwtype = TEMPSUMMON_MANUAL_DESPAWN, uint32 despwtime = 0, uint32 vehId = 0, SummonPropertiesEntry const* properties = nullptr) const;
TempSummon* SummonCreature(uint32 id, float x, float y, float z, float ang = 0, TempSummonType spwtype = TEMPSUMMON_MANUAL_DESPAWN, uint32 despwtime = 0, SummonPropertiesEntry const* properties = nullptr);
GameObject* SummonGameObject(uint32 entry, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime, bool checkTransport = true);
GameObject* SummonGameObject(uint32 entry, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime, bool checkTransport = true, GOSummonType summonType = GO_SUMMON_TIMED_OR_CORPSE_DESPAWN);
Creature* SummonTrigger(float x, float y, float z, float ang, uint32 dur, bool setLevel = false, CreatureAI * (*GetAI)(Creature*) = nullptr);
void SummonCreatureGroup(uint8 group, std::list<TempSummon*>* list = nullptr);

View File

@@ -36,7 +36,9 @@
#include "PlayerSettings.h"
#include "PlayerTaxi.h"
#include "QuestDef.h"
#include "SpellAuras.h"
#include "SpellMgr.h"
#include "SpellInfo.h"
#include "TradeData.h"
#include "Unit.h"
#include "WorldSession.h"
@@ -2923,32 +2925,28 @@ template <class T> T Player::ApplySpellMod(uint32 spellId, SpellModOp op, T& bas
{
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
if (!spellInfo)
{
return 0;
}
float totalmul = 1.0f;
int32 totalflat = 0;
// Drop charges for triggering spells instead of triggered ones
if (m_spellModTakingSpell)
spell = m_spellModTakingSpell;
for (auto mod : m_spellMods[op])
auto calculateSpellMod = [&](SpellModifier* mod)
{
// Charges can be set only for mods with auras
if (!mod->ownerAura)
ASSERT(mod->charges == 0);
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
continue;
// xinef: temporary pets cannot use charged mods of owner, needed for mirror image QQ they should use their own auras
if (temporaryPet && mod->charges != 0)
continue;
{
return;
}
if (mod->type == SPELLMOD_FLAT)
{
// xinef: do not allow to consume more than one 100% crit increasing spell
if (mod->op == SPELLMOD_CRITICAL_CHANCE && totalflat >= 100)
continue;
{
return;
}
totalflat += mod->value;
}
@@ -2956,32 +2954,88 @@ template <class T> T Player::ApplySpellMod(uint32 spellId, SpellModOp op, T& bas
{
// skip percent mods for null basevalue (most important for spell mods with charges)
if (basevalue == T(0) || totalmul == 0.0f)
continue;
{
return;
}
// special case (skip > 10sec spell casts for instant cast setting)
if (mod->op == SPELLMOD_CASTING_TIME && basevalue >= T(10000) && mod->value <= -100)
continue;
{
return;
}
// xinef: special exception for surge of light, dont affect crit chance if previous mods were not applied
else if (mod->op == SPELLMOD_CRITICAL_CHANCE && spell && !HasSpellMod(mod, spell))
continue;
{
return;
}
// xinef: special case for backdraft gcd reduce with backlast time reduction, dont affect gcd if cast time was not applied
else if (mod->op == SPELLMOD_GLOBAL_COOLDOWN && spell && !HasSpellMod(mod, spell))
continue;
{
return;
}
// xinef: those two mods should be multiplicative (Glyph of Renew)
if (mod->op == SPELLMOD_DAMAGE || mod->op == SPELLMOD_DOT)
{
totalmul *= CalculatePct(1.0f, 100.0f + mod->value);
}
else
{
totalmul += CalculatePct(1.0f, mod->value);
}
}
DropModCharge(mod, spell);
};
// Drop charges for triggering spells instead of triggered ones
if (m_spellModTakingSpell)
{
spell = m_spellModTakingSpell;
}
SpellModifier* chargedMod = nullptr;
for (auto mod : m_spellMods[op])
{
// Charges can be set only for mods with auras
if (!mod->ownerAura)
{
ASSERT(!mod->charges);
}
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
{
continue;
}
if (mod->ownerAura->IsUsingCharges())
{
if (!chargedMod || (chargedMod->ownerAura->GetSpellInfo()->SpellPriority < mod->ownerAura->GetSpellInfo()->SpellPriority))
{
chargedMod = mod;
}
continue;
}
calculateSpellMod(mod);
}
if (chargedMod)
{
calculateSpellMod(chargedMod);
}
float diff = 0.0f;
if (op == SPELLMOD_CASTING_TIME || op == SPELLMOD_DURATION)
{
diff = ((float)basevalue + totalflat) * (totalmul - 1.0f) + (float)totalflat;
}
else
{
diff = (float)basevalue * (totalmul - 1.0f) + (float)totalflat;
}
basevalue = T((float)basevalue + diff);
return T(diff);
}

View File

@@ -1616,24 +1616,24 @@ QuestGiverStatus Player::GetQuestDialogStatus(Object* questgiver)
continue;
QuestStatus status = GetQuestStatus(questId);
if ((status == QUEST_STATUS_COMPLETE && !GetQuestRewardStatus(questId)) || (quest->IsAutoComplete() && CanTakeQuest(quest, false)))
if (status == QUEST_STATUS_COMPLETE && !GetQuestRewardStatus(questId))
{
if (quest->IsRepeatable() || quest->IsDailyOrWeekly())
{
result2 = DIALOG_STATUS_REWARD_REP;
}
else
{
result2 = DIALOG_STATUS_REWARD;
}
result2 = DIALOG_STATUS_REWARD;
}
else if (status == QUEST_STATUS_INCOMPLETE)
{
result2 = DIALOG_STATUS_INCOMPLETE;
}
if (quest->IsAutoComplete() && CanTakeQuest(quest, false) && quest->IsRepeatable() && !quest->IsDailyOrWeekly())
{
result2 = DIALOG_STATUS_REWARD_REP;
}
if (result2 > result)
{
result = result2;
}
}
for (QuestRelations::const_iterator i = qr.first; i != qr.second; ++i)

View File

@@ -14056,7 +14056,7 @@ void Unit::TauntFadeOut(Unit* taunter)
if (m_ThreatMgr.isThreatListEmpty())
{
if (creature->IsAIEnabled)
creature->AI()->EnterEvadeMode();
creature->AI()->EnterEvadeMode(CreatureAI::EVADE_REASON_NO_HOSTILES);
return;
}
@@ -14094,7 +14094,7 @@ Unit* Creature::SelectVictim()
if (CanHaveThreatList())
{
if (!target && !m_ThreatMgr.isThreatListEmpty())
target = m_ThreatMgr.getHostilTarget();
target = m_ThreatMgr.getHostileTarget();
}
else if (!HasReactState(REACT_PASSIVE))
{
@@ -14142,7 +14142,7 @@ Unit* Creature::SelectVictim()
for (Unit::AuraEffectList::const_iterator itr = iAuras.begin(); itr != iAuras.end(); ++itr)
if ((*itr)->GetBase()->IsPermanent())
{
AI()->EnterEvadeMode();
AI()->EnterEvadeMode(CreatureAI::EVADE_REASON_NO_HOSTILES);
break;
}
return nullptr;
@@ -17916,6 +17916,8 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au
// Set charmed
charmer->SetCharm(this, true);
StopAttackingInvalidTarget();
if (GetTypeId() == TYPEID_UNIT)
{
if (MovementGenerator* movementGenerator = GetMotionMaster()->GetMotionSlot(MOTION_SLOT_IDLE))
@@ -18080,6 +18082,8 @@ void Unit::RemoveCharmedBy(Unit* charmer)
charmer->SetCharm(this, false);
StopAttackingInvalidTarget();
Player* playerCharmer = charmer->ToPlayer();
if (playerCharmer)
{
@@ -19623,6 +19627,37 @@ void Unit::StopAttackFaction(uint32 faction_id)
(*itr)->StopAttackFaction(faction_id);
}
void Unit::StopAttackingInvalidTarget()
{
AttackerSet const& attackers = getAttackers();
for (AttackerSet::const_iterator itr = attackers.begin(); itr != attackers.end();)
{
Unit* attacker = (*itr);
if (!attacker->IsValidAttackTarget(this))
{
attacker->AttackStop();
if (attacker->GetTypeId() == TYPEID_PLAYER)
{
attacker->ToPlayer()->SendAttackSwingCancelAttack();
}
for (Unit* controled : attacker->m_Controlled)
{
if (controled->GetVictim() == this && !controled->IsValidAttackTarget(this))
{
controled->AttackStop();
}
}
itr = attackers.begin();
}
else
{
++itr;
}
}
}
void Unit::OutDebugInfo() const
{
LOG_ERROR("entities.unit", "Unit::OutDebugInfo");

View File

@@ -1360,6 +1360,7 @@ public:
void CombatStop(bool includingCast = false);
void CombatStopWithPets(bool includingCast = false);
void StopAttackFaction(uint32 faction_id);
void StopAttackingInvalidTarget();
Unit* SelectNearbyTarget(Unit* exclude = nullptr, float dist = NOMINAL_MELEE_RANGE) const;
Unit* SelectNearbyNoTotemTarget(Unit* exclude = nullptr, float dist = NOMINAL_MELEE_RANGE) const;
void SendMeleeAttackStop(Unit* victim = nullptr);

View File

@@ -15,9 +15,9 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Unit.h"
#include "Define.h"
#include "SmartEnum.h"
#include "Unit.h"
#include <stdexcept>
namespace Acore::Impl::EnumUtilsImpl