mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-02-01 10:03:47 +00:00
Merge branch 'azerothcore:master' into Playerbot
This commit is contained in:
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user