mirror of
https://github.com/mangosfour/server.git
synced 2025-12-13 22:37:03 +00:00
Lots of cmangos commirs applied
This commit is contained in:
parent
8431568536
commit
18dd18780d
44 changed files with 677 additions and 323 deletions
|
|
@ -130,7 +130,6 @@ class BattleGroundQueue
|
|||
bool AddGroup(GroupQueueInfo* ginfo, uint32 desiredCount);
|
||||
bool KickGroup(uint32 size);
|
||||
uint32 GetPlayerCount() const {return PlayerCount;}
|
||||
public:
|
||||
GroupsQueueType SelectedGroups;
|
||||
private:
|
||||
uint32 PlayerCount;
|
||||
|
|
|
|||
|
|
@ -235,8 +235,6 @@ bool ChatHandler::HandleTriggerCommand(char* args)
|
|||
|
||||
float dist2 = MAP_SIZE * MAP_SIZE;
|
||||
|
||||
Player* pl = m_session->GetPlayer();
|
||||
|
||||
// Search triggers
|
||||
for (uint32 id = 0; id < sAreaTriggerStore.GetNumRows(); ++id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -734,17 +734,17 @@ dtStatus PathFinder::findSmoothPath(const float* startPos, const float* endPos,
|
|||
npolys -= npos;
|
||||
|
||||
// Handle the connection.
|
||||
float startPos[VERTEX_SIZE], endPos[VERTEX_SIZE];
|
||||
dtResult = m_navMesh->getOffMeshConnectionPolyEndPoints(prevRef, polyRef, startPos, endPos);
|
||||
float newStartPos[VERTEX_SIZE], newEndPos[VERTEX_SIZE];
|
||||
dtResult = m_navMesh->getOffMeshConnectionPolyEndPoints(prevRef, polyRef, newStartPos, newEndPos);
|
||||
if (dtStatusSucceed(dtResult))
|
||||
{
|
||||
if (nsmoothPath < maxSmoothPathSize)
|
||||
{
|
||||
dtVcopy(&smoothPath[nsmoothPath * VERTEX_SIZE], startPos);
|
||||
dtVcopy(&smoothPath[nsmoothPath * VERTEX_SIZE], newStartPos);
|
||||
++nsmoothPath;
|
||||
}
|
||||
// Move position at the other side of the off-mesh link.
|
||||
dtVcopy(iterPos, endPos);
|
||||
dtVcopy(iterPos, newEndPos);
|
||||
|
||||
m_navMeshQuery->getPolyHeight(polys[0], iterPos, &iterPos[1]);
|
||||
iterPos[1] += 0.5f;
|
||||
|
|
|
|||
|
|
@ -419,6 +419,7 @@ void FlightPathMovementGenerator::Reset(Player& player)
|
|||
player.getHostileRefManager().setOnlineOfflineState(false);
|
||||
player.addUnitState(UNIT_STAT_TAXI_FLIGHT);
|
||||
player.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
|
||||
player.SetClientControl(&player, 0);
|
||||
|
||||
Movement::MoveSplineInit init(player);
|
||||
uint32 end = GetPathAtMapEnd();
|
||||
|
|
|
|||
|
|
@ -411,7 +411,14 @@ bool Creature::UpdateEntry(uint32 Entry, Team team, const CreatureData* data /*=
|
|||
// creatures always have melee weapon ready if any
|
||||
SetSheath(SHEATH_STATE_MELEE);
|
||||
|
||||
SelectLevel(GetCreatureInfo(), preserveHPAndPower ? GetHealthPercent() : 100.0f);
|
||||
if (preserveHPAndPower)
|
||||
{
|
||||
uint32 healthPercent = GetHealthPercent();
|
||||
SelectLevel();
|
||||
SetHealthPercent(healthPercent);
|
||||
}
|
||||
else
|
||||
SelectLevel();
|
||||
|
||||
if (team == HORDE)
|
||||
setFaction(GetCreatureInfo()->FactionHorde);
|
||||
|
|
@ -830,6 +837,9 @@ bool Creature::AIM_Initialize()
|
|||
i_motionMaster.Initialize();
|
||||
i_AI = FactorySelector::selectAI(this);
|
||||
delete oldAI;
|
||||
|
||||
// Handle Spawned Events, also calls Reset()
|
||||
i_AI->JustRespawned();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1241,6 +1251,126 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
|
|||
WorldDatabase.CommitTransaction();
|
||||
}
|
||||
|
||||
void Creature::SelectLevel(uint32 forcedLevel /*= USE_DEFAULT_DATABASE_LEVEL*/)
|
||||
{
|
||||
CreatureInfo const* cinfo = GetCreatureInfo();
|
||||
if (!cinfo)
|
||||
return;
|
||||
|
||||
uint32 rank = IsPet() ? 0 : cinfo->Rank; // TODO :: IsPet probably not needed here
|
||||
|
||||
// level
|
||||
uint32 level = forcedLevel;
|
||||
uint32 const minlevel = cinfo->MinLevel;
|
||||
uint32 const maxlevel = cinfo->MaxLevel;
|
||||
|
||||
if (level == USE_DEFAULT_DATABASE_LEVEL)
|
||||
level = minlevel == maxlevel ? minlevel : urand(minlevel, maxlevel);
|
||||
|
||||
SetLevel(level);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Calculate level dependent stats
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint32 health;
|
||||
uint32 mana;
|
||||
|
||||
if (CreatureClassLvlStats const* cCLS = sObjectMgr.GetCreatureClassLvlStats(level, cinfo->UnitClass, cinfo->Expansion))
|
||||
{
|
||||
// Use Creature Stats to calculate stat values
|
||||
|
||||
// health
|
||||
health = cCLS->BaseHealth * cinfo->HealthMultiplier;
|
||||
|
||||
// mana
|
||||
mana = cCLS->BaseMana * cinfo->PowerMultiplier;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (forcedLevel == USE_DEFAULT_DATABASE_LEVEL || (forcedLevel >= minlevel && forcedLevel <= maxlevel))
|
||||
{
|
||||
// Use old style to calculate stat values
|
||||
float rellevel = maxlevel == minlevel ? 0 : (float(level - minlevel)) / (maxlevel - minlevel);
|
||||
|
||||
// health
|
||||
uint32 minhealth = std::min(cinfo->MaxLevelHealth, cinfo->MinLevelHealth);
|
||||
uint32 maxhealth = std::max(cinfo->MaxLevelHealth, cinfo->MinLevelHealth);
|
||||
health = uint32(minhealth + uint32(rellevel * (maxhealth - minhealth)));
|
||||
|
||||
// mana
|
||||
uint32 minmana = std::min(cinfo->MaxLevelMana, cinfo->MinLevelMana);
|
||||
uint32 maxmana = std::max(cinfo->MaxLevelMana, cinfo->MinLevelMana);
|
||||
mana = minmana + uint32(rellevel * (maxmana - minmana));
|
||||
}
|
||||
else
|
||||
{
|
||||
sLog.outError("Creature::SelectLevel> Error trying to set level(%u) for creature %s without enough data to do it!", level, GetGuidStr().c_str());
|
||||
// probably wrong
|
||||
health = (cinfo->MaxLevelHealth / cinfo->MaxLevel) * level;
|
||||
mana = (cinfo->MaxLevelMana / cinfo->MaxLevel) * level;
|
||||
}
|
||||
}
|
||||
|
||||
health *= _GetHealthMod(rank); // Apply custom config settting
|
||||
if (health < 1)
|
||||
health = 1;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Set values
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// health
|
||||
SetCreateHealth(health);
|
||||
SetMaxHealth(health);
|
||||
SetHealth(health);
|
||||
|
||||
SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, float(health));
|
||||
|
||||
// all power types
|
||||
for (int i = POWER_MANA; i <= POWER_RUNIC_POWER; ++i)
|
||||
{
|
||||
uint32 maxValue = 0;
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case POWER_MANA: maxValue = mana; break;
|
||||
case POWER_RAGE: maxValue = 0; break;
|
||||
case POWER_FOCUS: maxValue = POWER_FOCUS_DEFAULT; break;
|
||||
case POWER_ENERGY: maxValue = POWER_ENERGY_DEFAULT * cinfo->PowerMultiplier; break;
|
||||
case POWER_RUNE: maxValue = 0; break;
|
||||
case POWER_RUNIC_POWER: maxValue = 0; break;
|
||||
}
|
||||
|
||||
uint32 value = maxValue;
|
||||
|
||||
// For non regenerating powers set 0
|
||||
if ((i == POWER_ENERGY || i == POWER_MANA) && !IsRegeneratingPower())
|
||||
value = 0;
|
||||
|
||||
// Mana requires an extra field to be set
|
||||
if (i == POWER_MANA)
|
||||
SetCreateMana(value);
|
||||
|
||||
SetMaxPower(Powers(i), maxValue);
|
||||
SetPower(Powers(i), value);
|
||||
SetModifierValue(UnitMods(UNIT_MOD_POWER_START + i), BASE_VALUE, float(value));
|
||||
}
|
||||
|
||||
// damage
|
||||
float damagemod = _GetDamageMod(rank);
|
||||
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, cinfo->MinMeleeDmg * damagemod);
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, cinfo->MaxMeleeDmg * damagemod);
|
||||
|
||||
SetBaseWeaponDamage(OFF_ATTACK, MINDAMAGE, cinfo->MinMeleeDmg * damagemod);
|
||||
SetBaseWeaponDamage(OFF_ATTACK, MAXDAMAGE, cinfo->MaxMeleeDmg * damagemod);
|
||||
|
||||
SetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, cinfo->MinRangedDmg * damagemod);
|
||||
SetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, cinfo->MaxRangedDmg * damagemod);
|
||||
|
||||
SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, cinfo->MeleeAttackPower * damagemod);
|
||||
}
|
||||
|
||||
void Creature::SelectLevel(const CreatureInfo* cinfo, float percentHealth /*= 100.0f*/)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ enum CreatureFlagsExtra
|
|||
|
||||
#define MAX_KILL_CREDIT 2
|
||||
#define MAX_CREATURE_MODEL 4
|
||||
|
||||
#define USE_DEFAULT_DATABASE_LEVEL 0 // just used to show we don't want to force the new creature level and use the level stored in db
|
||||
|
||||
// from `creature_template` table
|
||||
struct CreatureInfo
|
||||
|
|
@ -522,6 +522,7 @@ class Creature : public Unit
|
|||
bool Create(uint32 guidlow, CreatureCreatePos& cPos, CreatureInfo const* cinfo, Team team = TEAM_NONE, const CreatureData* data = NULL, GameEventCreatureData const* eventData = NULL);
|
||||
bool LoadCreatureAddon(bool reload);
|
||||
void SelectLevel(const CreatureInfo* cinfo, float percentHealth = 100.0f);
|
||||
void SelectLevel(uint32 forcedLevel = USE_DEFAULT_DATABASE_LEVEL);
|
||||
void LoadEquipment(uint32 equip_entry, bool force = false);
|
||||
|
||||
bool HasStaticDBSpawnData() const; // listed in `creature` table and have fixed in DB guid
|
||||
|
|
|
|||
|
|
@ -59,9 +59,12 @@ namespace FactorySelector
|
|||
// select by NPC flags _first_ - otherwise EventAI might be choosen for pets/totems
|
||||
// excplicit check for isControlled() and owner type to allow guardian, mini-pets and pets controlled by NPCs to be scripted by EventAI
|
||||
Unit* owner = NULL;
|
||||
if ((creature->IsPet() && ((Pet*)creature)->isControlled() &&
|
||||
((owner = creature->GetOwner()) && owner->GetTypeId() == TYPEID_PLAYER)) || creature->IsCharmed())
|
||||
ai_factory = ai_registry.GetRegistryItem("PetAI");
|
||||
if (creature->IsPet() && ((Pet*)creature)->isControlled())
|
||||
{
|
||||
Unit* controler = creature->GetOwner() ? creature->GetOwner() : creature->GetCharmer();
|
||||
if (controler && controler->GetTypeId() == TYPEID_PLAYER && controler->IsAlive())
|
||||
ai_factory = ai_registry.GetRegistryItem("PetAI");
|
||||
}
|
||||
else if (creature->IsTotem())
|
||||
ai_factory = ai_registry.GetRegistryItem("TotemAI");
|
||||
|
||||
|
|
|
|||
|
|
@ -156,9 +156,6 @@ CreatureEventAI::CreatureEventAI(Creature* c) : CreatureAI(c),
|
|||
}
|
||||
else
|
||||
sLog.outErrorEventAI("EventMap for Creature %u is empty but creature is using CreatureEventAI.", m_creature->GetEntry());
|
||||
|
||||
// Handle Spawned Events, also calls Reset()
|
||||
JustRespawned();
|
||||
}
|
||||
|
||||
#define LOG_PROCESS_EVENT \
|
||||
|
|
|
|||
|
|
@ -214,6 +214,7 @@ bool DynamicObject::isVisibleForInState(Player const* u, WorldObject const* view
|
|||
return IsWithinDistInMap(viewPoint, GetMap()->GetVisibilityDistance() + (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false);
|
||||
}
|
||||
|
||||
|
||||
bool DynamicObject::IsHostileTo(Unit const* unit) const
|
||||
{
|
||||
if (Unit* owner = GetCaster())
|
||||
|
|
|
|||
|
|
@ -764,6 +764,76 @@ void GameObject::SaveRespawnTime()
|
|||
{ GetMap()->GetPersistentState()->SaveGORespawnTime(GetGUIDLow(), m_respawnTime); }
|
||||
}
|
||||
|
||||
bool GameObject::isVisibleForInState(Player const* u, WorldObject const* viewPoint, bool inVisibleList) const
|
||||
{
|
||||
// Not in world
|
||||
if (!IsInWorld() || !u->IsInWorld())
|
||||
return false;
|
||||
|
||||
// invisible at client always
|
||||
if (!GetGOInfo()->displayId)
|
||||
return false;
|
||||
|
||||
// Transport always visible at this step implementation
|
||||
if (IsTransport() && IsInMap(u))
|
||||
return true;
|
||||
|
||||
// quick check visibility false cases for non-GM-mode
|
||||
if (!u->isGameMaster())
|
||||
{
|
||||
// despawned and then not visible for non-GM in GM-mode
|
||||
if (!isSpawned())
|
||||
return false;
|
||||
|
||||
// special invisibility cases
|
||||
if (GetGOInfo()->type == GAMEOBJECT_TYPE_TRAP && GetGOInfo()->trap.stealthed)
|
||||
{
|
||||
bool trapNotVisible = false;
|
||||
|
||||
// handle summoned traps, usually by players
|
||||
if (Unit* owner = GetOwner())
|
||||
{
|
||||
if (owner->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
Player* ownerPlayer = (Player*)owner;
|
||||
if ((GetMap()->IsBattleGroundOrArena() && ownerPlayer->GetBGTeam() != u->GetBGTeam()) ||
|
||||
(ownerPlayer->IsInDuelWith(u)) ||
|
||||
(ownerPlayer->GetTeam() != u->GetTeam()))
|
||||
trapNotVisible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (u->IsFriendlyTo(owner))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// handle environment traps (spawned by DB)
|
||||
else
|
||||
{
|
||||
if (this->IsFriendlyTo(u))
|
||||
return true;
|
||||
else
|
||||
trapNotVisible = true;
|
||||
}
|
||||
|
||||
// only rogue have skill for traps detection
|
||||
if (Aura* aura = ((Player*)u)->GetAura(2836, EFFECT_INDEX_0))
|
||||
{
|
||||
if (roll_chance_i(aura->GetModifier()->m_amount) && u->isInFront(this, 15.0f))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (trapNotVisible)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// check distance
|
||||
return IsWithinDistInMap(viewPoint, GetMap()->GetVisibilityDistance() +
|
||||
(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false);
|
||||
}
|
||||
|
||||
/*
|
||||
bool GameObject::isVisibleForInState(Player const* u, WorldObject const* viewPoint, bool inVisibleList) const
|
||||
{
|
||||
// Not in world
|
||||
|
|
@ -784,6 +854,7 @@ bool GameObject::isVisibleForInState(Player const* u, WorldObject const* viewPoi
|
|||
// despawned and then not visible for non-GM in GM-mode
|
||||
if (!isSpawned())
|
||||
{ return false; }
|
||||
*/
|
||||
|
||||
// special invisibility cases
|
||||
/* TODO: implement trap stealth, take look at spell 2836
|
||||
|
|
@ -792,12 +863,14 @@ bool GameObject::isVisibleForInState(Player const* u, WorldObject const* viewPoi
|
|||
if(check stuff here)
|
||||
return false;
|
||||
}*/
|
||||
/*
|
||||
}
|
||||
|
||||
// check distance
|
||||
|
||||
return IsWithinDistInMap(viewPoint, GetMap()->GetVisibilityDistance() +
|
||||
(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false);
|
||||
}
|
||||
*/
|
||||
|
||||
void GameObject::Respawn()
|
||||
{
|
||||
|
|
@ -1669,7 +1742,7 @@ void GameObject::Use(Unit* user)
|
|||
SpellCastTargets targets;
|
||||
targets.setUnitTarget(user);
|
||||
|
||||
spell->prepare(&targets);
|
||||
spell->SpellStart(&targets);
|
||||
}
|
||||
|
||||
// overwrite WorldObject function for proper name localization
|
||||
|
|
|
|||
|
|
@ -259,16 +259,19 @@ bool LootStoreItem::Roll(bool rate) const
|
|||
if (mincountOrRef < 0) // reference case
|
||||
return roll_chance_f(chance * (rate ? sWorld.getConfig(CONFIG_FLOAT_RATE_DROP_ITEM_REFERENCED) : 1.0f));
|
||||
|
||||
if (type == LOOT_ITEM_TYPE_ITEM)
|
||||
if (type == LOOTITEM_TYPE_CURRENCY)
|
||||
return roll_chance_f(chance * (rate ? sWorld.getConfig(CONFIG_FLOAT_RATE_DROP_CURRENCY) : 1.0f));
|
||||
else
|
||||
{
|
||||
if (needs_quest)
|
||||
return roll_chance_f(chance * (rate ? sWorld.getConfig(CONFIG_FLOAT_RATE_DROP_ITEM_QUEST) : 1.0f));
|
||||
|
||||
ItemPrototype const* pProto = ObjectMgr::GetItemPrototype(itemid);
|
||||
|
||||
float qualityModifier = pProto && rate ? sWorld.getConfig(qualityToRate[pProto->Quality]) : 1.0f;
|
||||
|
||||
return roll_chance_f(chance * qualityModifier);
|
||||
}
|
||||
else if (type == LOOT_ITEM_TYPE_CURRENCY)
|
||||
return roll_chance_f(chance * (rate ? sWorld.getConfig(CONFIG_FLOAT_RATE_DROP_CURRENCY) : 1.0f));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,8 +53,10 @@ enum PermissionTypes
|
|||
|
||||
enum LootItemType
|
||||
{
|
||||
LOOT_ITEM_TYPE_ITEM = 0,
|
||||
LOOT_ITEM_TYPE_CURRENCY = 1,
|
||||
LOOT_ITEM_TYPE_ITEM = 0,
|
||||
LOOT_ITEM_TYPE_CURRENCY = 1,
|
||||
LOOTITEM_TYPE_CONDITIONNAL = 3,
|
||||
LOOTITEM_TYPE_CURRENCY = 4,
|
||||
};
|
||||
|
||||
enum LootType
|
||||
|
|
|
|||
|
|
@ -133,63 +133,37 @@ void Object::SendForcedObjectUpdate()
|
|||
void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const
|
||||
{
|
||||
if (!target)
|
||||
{ return; }
|
||||
return;
|
||||
|
||||
uint8 updatetype = UPDATETYPE_CREATE_OBJECT;
|
||||
uint16 updateFlags = m_updateFlag;
|
||||
|
||||
/** lower flag1 **/
|
||||
if (target == this) // building packet for yourself
|
||||
{ updateFlags |= UPDATEFLAG_SELF; }
|
||||
updateFlags |= UPDATEFLAG_SELF;
|
||||
|
||||
switch (GetObjectGuid().GetHigh())
|
||||
if (m_itsNewObject)
|
||||
{
|
||||
case HIGHGUID_PLAYER:
|
||||
case HIGHGUID_PET:
|
||||
case HIGHGUID_CORPSE:
|
||||
case HIGHGUID_DYNAMICOBJECT:
|
||||
updatetype = UPDATETYPE_CREATE_OBJECT2;
|
||||
break;
|
||||
case HIGHGUID_UNIT:
|
||||
switch (GetObjectGuid().GetHigh())
|
||||
{
|
||||
Creature* creature = (Creature*)this;
|
||||
if (creature->IsTemporarySummon() && ((TemporarySummon*)this)->GetSummonerGuid().IsPlayer())
|
||||
case HighGuid::HIGHGUID_DYNAMICOBJECT:
|
||||
case HighGuid::HIGHGUID_CORPSE:
|
||||
case HighGuid::HIGHGUID_PLAYER:
|
||||
case HighGuid::HIGHGUID_UNIT:
|
||||
case HighGuid::HIGHGUID_VEHICLE:
|
||||
case HighGuid::HIGHGUID_GAMEOBJECT:
|
||||
updatetype = UPDATETYPE_CREATE_OBJECT2;
|
||||
break;
|
||||
}
|
||||
case HIGHGUID_GAMEOBJECT:
|
||||
{
|
||||
if (((GameObject*)this)->GetOwnerGuid().IsPlayer())
|
||||
updatetype = UPDATETYPE_CREATE_OBJECT2;
|
||||
break;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (updateFlags & UPDATEFLAG_HAS_POSITION)
|
||||
{
|
||||
// UPDATETYPE_CREATE_OBJECT2 for some gameobject types...
|
||||
if (isType(TYPEMASK_GAMEOBJECT))
|
||||
{
|
||||
switch (((GameObject*)this)->GetGoType())
|
||||
{
|
||||
case GAMEOBJECT_TYPE_TRAP:
|
||||
case GAMEOBJECT_TYPE_DUEL_ARBITER:
|
||||
case GAMEOBJECT_CreatureTypeFlagsTAND:
|
||||
case GAMEOBJECT_TYPE_FLAGDROP:
|
||||
updatetype = UPDATETYPE_CREATE_OBJECT2;
|
||||
break;
|
||||
case GAMEOBJECT_TYPE_TRANSPORT:
|
||||
updateFlags |= UPDATEFLAG_TRANSPORT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isType(TYPEMASK_UNIT))
|
||||
{
|
||||
if (((Unit*)this)->getVictim())
|
||||
updateFlags |= UPDATEFLAG_HAS_ATTACKING_TARGET;
|
||||
}
|
||||
if (isType(TYPEMASK_UNIT))
|
||||
{
|
||||
if (((Unit*)this)->getVictim())
|
||||
updateFlags |= UPDATEFLAG_HAS_ATTACKING_TARGET;
|
||||
}
|
||||
|
||||
// DEBUG_LOG("BuildCreateUpdate: update-type: %u, object-type: %u got updateFlags: %X", updatetype, m_objectTypeId, updateFlags);
|
||||
|
|
|
|||
|
|
@ -400,6 +400,7 @@ class Object
|
|||
|
||||
virtual bool HasQuest(uint32 /* quest_id */) const { return false; }
|
||||
virtual bool HasInvolvedQuest(uint32 /* quest_id */) const { return false; }
|
||||
void SetItsNewObject(bool enable) { m_itsNewObject = enable; }
|
||||
|
||||
protected:
|
||||
Object();
|
||||
|
|
@ -435,6 +436,7 @@ class Object
|
|||
|
||||
private:
|
||||
bool m_inWorld;
|
||||
bool m_itsNewObject;
|
||||
|
||||
PackedGuid m_PackGUID;
|
||||
|
||||
|
|
@ -567,7 +569,7 @@ class WorldObject : public Object
|
|||
float GetDistanceZ(const WorldObject* obj) const;
|
||||
bool IsInMap(const WorldObject* obj) const
|
||||
{
|
||||
return IsInWorld() && obj->IsInWorld() && (GetMap() == obj->GetMap()) && InSamePhase(obj);
|
||||
return obj && IsInWorld() && obj->IsInWorld() && (GetMap() == obj->GetMap()) && InSamePhase(obj);
|
||||
}
|
||||
bool IsWithinDist3d(float x, float y, float z, float dist2compare) const;
|
||||
bool IsWithinDist2d(float x, float y, float dist2compare) const;
|
||||
|
|
|
|||
|
|
@ -8227,9 +8227,9 @@ bool PlayerCondition::Meets(Player const* player, Map const* map, WorldObject co
|
|||
case CONDITION_TEAM:
|
||||
{
|
||||
if (conditionSourceType == CONDITION_FROM_REFERING_LOOT && sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
|
||||
{ return true; }
|
||||
return true;
|
||||
else
|
||||
{ return uint32(player->GetTeam()) == m_value1; }
|
||||
return uint32(player->GetTeam()) == m_value1;
|
||||
}
|
||||
case CONDITION_SKILL:
|
||||
return player->HasSkill(m_value1) && player->GetBaseSkillValue(m_value1) >= m_value2;
|
||||
|
|
|
|||
|
|
@ -197,6 +197,9 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petentry, uint32 petnumber, bool c
|
|||
SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
|
||||
SetName(fields[8].GetString());
|
||||
|
||||
SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SUPPORTABLE | UNIT_BYTE2_FLAG_AURAS);
|
||||
SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
|
||||
|
||||
switch (getPetType())
|
||||
{
|
||||
case SUMMON_PET:
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ typedef std::vector<uint32> AutoSpellList;
|
|||
#define ACTIVE_SPELLS_MAX 4
|
||||
|
||||
#define PET_FOLLOW_DIST 1.0f
|
||||
#define PET_FOLLOW_ANGLE (M_PI_F/2.0f)
|
||||
#define PET_FOLLOW_ANGLE (M_PI_F / 4.00f) * 3.50f
|
||||
|
||||
class Player;
|
||||
|
||||
|
|
|
|||
|
|
@ -48,28 +48,24 @@ PetAI::PetAI(Creature* c) : CreatureAI(c), i_tracker(TIME_INTERVAL_LOOK), inComb
|
|||
UpdateAllies();
|
||||
}
|
||||
|
||||
void PetAI::MoveInLineOfSight(Unit* u)
|
||||
void PetAI::MoveInLineOfSight(Unit* pWho)
|
||||
{
|
||||
if (m_creature->getVictim())
|
||||
return;
|
||||
|
||||
if (m_creature->IsPet() && ((Pet*)m_creature)->GetModeFlags() & PET_MODE_DISABLE_ACTIONS)
|
||||
return;
|
||||
|
||||
if (!m_creature->GetCharmInfo() || !m_creature->GetCharmInfo()->HasReactState(REACT_AGGRESSIVE))
|
||||
return;
|
||||
|
||||
if (u->IsTargetableForAttack() && m_creature->IsHostileTo(u) &&
|
||||
u->isInAccessablePlaceFor(m_creature))
|
||||
if (m_creature->CanInitiateAttack() && pWho->IsTargetableForAttack() &&
|
||||
m_creature->IsHostileTo(pWho) && pWho->isInAccessablePlaceFor(m_creature))
|
||||
{
|
||||
float attackRadius = m_creature->GetAttackDistance(u);
|
||||
if (m_creature->IsWithinDistInMap(u, attackRadius) && m_creature->GetDistanceZ(u) <= CREATURE_Z_ATTACK_RANGE)
|
||||
if (!m_creature->CanFly() && m_creature->GetDistanceZ(pWho) > CREATURE_Z_ATTACK_RANGE)
|
||||
return;
|
||||
|
||||
if (m_creature->IsWithinDistInMap(pWho, m_creature->GetAttackDistance(pWho)) && m_creature->IsWithinLOSInMap(pWho))
|
||||
{
|
||||
if (m_creature->IsWithinLOSInMap(u))
|
||||
{
|
||||
AttackStart(u);
|
||||
u->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
|
||||
}
|
||||
pWho->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
|
||||
AttackStart(pWho);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -298,7 +294,7 @@ void PetAI::UpdateAI(const uint32 diff)
|
|||
|
||||
m_creature->AddCreatureSpellCooldown(spell->m_spellInfo->Id);
|
||||
|
||||
spell->prepare(&targets);
|
||||
spell->SpellStart(&targets);
|
||||
}
|
||||
|
||||
// deleted cached Spell objects
|
||||
|
|
|
|||
|
|
@ -3629,17 +3629,18 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool learn_low_rank, bo
|
|||
PlayerSpellMap::iterator prev_itr = m_spells.find(prev_id);
|
||||
if (prev_itr != m_spells.end())
|
||||
{
|
||||
if (prev_itr->second.dependent != cur_dependent)
|
||||
PlayerSpell& spell = prev_itr->second;
|
||||
if (spell.dependent != cur_dependent)
|
||||
{
|
||||
prev_itr->second.dependent = cur_dependent;
|
||||
if (prev_itr->second.state != PLAYERSPELL_NEW)
|
||||
prev_itr->second.state = PLAYERSPELL_CHANGED;
|
||||
spell.dependent = cur_dependent;
|
||||
if (spell.state != PLAYERSPELL_NEW)
|
||||
spell.state = PLAYERSPELL_CHANGED;
|
||||
}
|
||||
|
||||
// now re-learn if need re-activate
|
||||
if (cur_active && !prev_itr->second.active && learn_low_rank)
|
||||
if (cur_active && !spell.active && learn_low_rank)
|
||||
{
|
||||
if (addSpell(prev_id, true, false, prev_itr->second.dependent, prev_itr->second.disabled))
|
||||
if (addSpell(prev_id, true, false, spell.dependent, spell.disabled))
|
||||
{
|
||||
// downgrade spell ranks in spellbook and action bar
|
||||
WorldPacket data(SMSG_SUPERCEDED_SPELL, 4 + 4);
|
||||
|
|
@ -6306,7 +6307,12 @@ void Player::CheckAreaExploreAndOutdoor()
|
|||
SpellEntry const* spellInfo = sSpellStore.LookupEntry(itr->first);
|
||||
if (!spellInfo || !IsNeedCastSpellAtOutdoor(spellInfo) || HasAura(itr->first))
|
||||
continue;
|
||||
CastSpell(this, itr->first, true, NULL);
|
||||
|
||||
SpellShapeshiftEntry const* shapeShift = spellInfo->GetSpellShapeshift();
|
||||
|
||||
if (!shapeShift || (shapeShift->Stances || shapeShift->StancesNot) && !IsNeedCastSpellAtFormApply(spellInfo, GetShapeshiftForm()))
|
||||
continue;
|
||||
CastSpell(this, itr->first, true, nullptr);
|
||||
}
|
||||
}
|
||||
else if (sWorld.getConfig(CONFIG_BOOL_VMAP_INDOOR_CHECK) && !isGameMaster())
|
||||
|
|
@ -6980,13 +6986,13 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea)
|
|||
|
||||
if (zone->flags & AREA_FLAG_SANCTUARY) // in sanctuary
|
||||
{
|
||||
SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SUPPORTABLE);
|
||||
SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY);
|
||||
if (sWorld.IsFFAPvPRealm())
|
||||
SetFFAPvP(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SUPPORTABLE);
|
||||
RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY);
|
||||
}
|
||||
|
||||
if (zone->flags & AREA_FLAG_CAPITAL) // in capital city
|
||||
|
|
@ -7812,7 +7818,7 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8
|
|||
spell->m_CastItem = item;
|
||||
spell->m_cast_count = cast_count; // set count of casts
|
||||
spell->m_currentBasePoints[EFFECT_INDEX_0] = learning_spell_id;
|
||||
spell->prepare(&targets);
|
||||
spell->SpellStart(&targets);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -7843,7 +7849,7 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8
|
|||
spell->m_CastItem = item;
|
||||
spell->m_cast_count = cast_count; // set count of casts
|
||||
spell->m_glyphIndex = glyphIndex; // glyph index
|
||||
spell->prepare(&targets);
|
||||
spell->SpellStart(&targets);
|
||||
|
||||
++count;
|
||||
}
|
||||
|
|
@ -7875,7 +7881,7 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8
|
|||
spell->m_CastItem = item;
|
||||
spell->m_cast_count = cast_count; // set count of casts
|
||||
spell->m_glyphIndex = glyphIndex; // glyph index
|
||||
spell->prepare(&targets);
|
||||
spell->SpellStart(&targets);
|
||||
|
||||
++count;
|
||||
}
|
||||
|
|
@ -18354,6 +18360,10 @@ void Player::Whisper(const std::string& text, uint32 language, ObjectGuid receiv
|
|||
ChatHandler::BuildChatPacket(data, CHAT_MSG_WHISPER, text.c_str(), Language(language), GetChatTag(), GetObjectGuid(), GetName());
|
||||
rPlayer->GetSession()->SendPacket(&data);
|
||||
|
||||
// do not send confirmations, afk, dnd or system notifications for addon messages
|
||||
if (language == LANG_ADDON)
|
||||
return;
|
||||
|
||||
data.clear();
|
||||
ChatHandler::BuildChatPacket(data, CHAT_MSG_WHISPER_INFORM, text.c_str(), Language(language), CHAT_TAG_NONE, rPlayer->GetObjectGuid());
|
||||
GetSession()->SendPacket(&data);
|
||||
|
|
@ -18365,10 +18375,13 @@ void Player::Whisper(const std::string& text, uint32 language, ObjectGuid receiv
|
|||
}
|
||||
|
||||
// announce afk or dnd message
|
||||
if (rPlayer->isAFK())
|
||||
ChatHandler(this).PSendSysMessage(LANG_PLAYER_AFK, rPlayer->GetName(), rPlayer->autoReplyMsg.c_str());
|
||||
else if (rPlayer->isDND())
|
||||
ChatHandler(this).PSendSysMessage(LANG_PLAYER_DND, rPlayer->GetName(), rPlayer->autoReplyMsg.c_str());
|
||||
if (rPlayer->isAFK() || rPlayer->isDND())
|
||||
{
|
||||
const ChatMsg msgtype = rPlayer->isAFK() ? CHAT_MSG_AFK : CHAT_MSG_DND;
|
||||
data.clear();
|
||||
ChatHandler::BuildChatPacket(data, msgtype, rPlayer->autoReplyMsg.c_str(), LANG_UNIVERSAL, CHAT_TAG_NONE, rPlayer->GetObjectGuid());
|
||||
GetSession()->SendPacket(&data);
|
||||
}
|
||||
}
|
||||
|
||||
void Player::PetSpellInitialize()
|
||||
|
|
@ -20780,8 +20793,8 @@ bool Player::IsSpellFitByClassAndRace(uint32 spell_id, uint32* pReqlevel /*= NUL
|
|||
if (abilityEntry->classmask && (abilityEntry->classmask & classmask) == 0)
|
||||
continue;
|
||||
|
||||
SkillRaceClassInfoMapBounds bounds = sSpellMgr.GetSkillRaceClassInfoMapBounds(abilityEntry->skillId);
|
||||
for (SkillRaceClassInfoMap::const_iterator itr = bounds.first; itr != bounds.second; ++itr)
|
||||
SkillRaceClassInfoMapBounds raceBounds = sSpellMgr.GetSkillRaceClassInfoMapBounds(abilityEntry->skillId);
|
||||
for (SkillRaceClassInfoMap::const_iterator itr = raceBounds.first; itr != raceBounds.second; ++itr)
|
||||
{
|
||||
SkillRaceClassInfoEntry const* skillRCEntry = itr->second;
|
||||
if ((skillRCEntry->raceMask & racemask) && (skillRCEntry->classMask & classmask))
|
||||
|
|
|
|||
|
|
@ -452,7 +452,7 @@ enum PlayerFlags
|
|||
PLAYER_FLAGS_GM = 0x00000008,
|
||||
PLAYER_FLAGS_GHOST = 0x00000010,
|
||||
PLAYER_FLAGS_RESTING = 0x00000020,
|
||||
PLAYER_FLAGS_UNK7 = 0x00000040, // admin?
|
||||
PLAYER_FLAGS_SANCTUARY = 0x00000040,
|
||||
PLAYER_FLAGS_UNK8 = 0x00000080, // pre-3.0.3 PLAYER_FLAGS_FFA_PVP flag for FFA PVP state
|
||||
PLAYER_FLAGS_CONTESTED_PVP = 0x00000100, // Player has been involved in a PvP combat and will be attacked by contested guards
|
||||
PLAYER_FLAGS_IN_PVP = 0x00000200,
|
||||
|
|
@ -2574,6 +2574,10 @@ class Player : public Unit
|
|||
void SetTitle(CharTitlesEntry const* title, bool lost = false);
|
||||
|
||||
bool canSeeSpellClickOn(Creature const* creature) const;
|
||||
|
||||
// function used for raise ally spell
|
||||
bool IsGhouled() const { return m_isGhouled; }
|
||||
void SetGhouled(bool enable) { m_isGhouled = enable; }
|
||||
protected:
|
||||
|
||||
uint32 m_contestedPvPTimer;
|
||||
|
|
@ -2899,6 +2903,8 @@ class Player : public Unit
|
|||
uint32 m_timeSyncServer;
|
||||
|
||||
uint32 m_cachedGS;
|
||||
|
||||
bool m_isGhouled;
|
||||
};
|
||||
|
||||
void AddItemsSetItem(Player* player, Item* item);
|
||||
|
|
|
|||
|
|
@ -809,7 +809,9 @@ bool IsPositiveEffect(SpellEntry const* spellproto, SpellEffectIndex effIndex)
|
|||
switch (spellproto->Id)
|
||||
{
|
||||
case 13139: // net-o-matic special effect
|
||||
case 23182: // Mark of Frost
|
||||
case 23445: // evil twin
|
||||
case 25040: // Mark of Nature
|
||||
case 35679: // Protectorate Demolitionist
|
||||
case 37695: // Stanky
|
||||
case 38637: // Nether Exhaustion (red)
|
||||
|
|
@ -931,6 +933,7 @@ bool IsPositiveEffect(SpellEntry const* spellproto, SpellEffectIndex effIndex)
|
|||
{
|
||||
case 36897: // Transporter Malfunction (race mutation to horde)
|
||||
case 36899: // Transporter Malfunction (race mutation to alliance)
|
||||
case 37097: // Crate Disguise
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
|
@ -940,6 +943,7 @@ bool IsPositiveEffect(SpellEntry const* spellproto, SpellEffectIndex effIndex)
|
|||
{
|
||||
case 802: // Mutate Bug, wrongly negative by target modes
|
||||
case 38449: // Blessing of the Tides
|
||||
case 50312: // Unholy Frenzy
|
||||
return true;
|
||||
case 36900: // Soul Split: Evil!
|
||||
case 36901: // Soul Split: Good
|
||||
|
|
@ -1058,16 +1062,6 @@ bool IsSingleTargetSpell(SpellEntry const* spellInfo)
|
|||
{
|
||||
// all other single target spells have if it has AttributesEx5
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR_EX5_SINGLE_TARGET_SPELL))
|
||||
return true;
|
||||
|
||||
// TODO - need found Judgements rule
|
||||
switch (GetSpellSpecific(spellInfo->Id))
|
||||
{
|
||||
case SPELL_JUDGEMENT:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// single target triggered spell.
|
||||
// Not real client side single target spell, but it' not triggered until prev. aura expired.
|
||||
|
|
@ -1086,12 +1080,10 @@ bool IsSingleTargetSpells(SpellEntry const* spellInfo1, SpellEntry const* spellI
|
|||
spellInfo1->SpellIconID == spellInfo2->SpellIconID )
|
||||
return true;
|
||||
|
||||
// TODO - need found Judgements rule
|
||||
SpellSpecific spec1 = GetSpellSpecific(spellInfo1->Id);
|
||||
// spell with single target specific types
|
||||
switch (spec1)
|
||||
{
|
||||
case SPELL_JUDGEMENT:
|
||||
case SPELL_MAGE_POLYMORPH:
|
||||
if (GetSpellSpecific(spellInfo2->Id) == spec1)
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -669,9 +669,13 @@ void Unit::Update(uint32 update_diff, uint32 p_time)
|
|||
// update abilities available only for fraction of time
|
||||
UpdateReactives(update_diff);
|
||||
|
||||
ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, GetHealth() < GetMaxHealth() * 0.20f);
|
||||
ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, GetHealth() < GetMaxHealth() * 0.35f);
|
||||
ModifyAuraState(AURA_STATE_HEALTH_ABOVE_75_PERCENT, GetHealth() > GetMaxHealth() * 0.75f);
|
||||
if (IsAlive())
|
||||
{
|
||||
ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, GetHealth() < GetMaxHealth() * 0.20f);
|
||||
ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, GetHealth() < GetMaxHealth() * 0.35f);
|
||||
ModifyAuraState(AURA_STATE_HEALTH_ABOVE_75_PERCENT, GetHealth() > GetMaxHealth() * 0.75f);
|
||||
}
|
||||
|
||||
UpdateSplineMovement(p_time);
|
||||
i_motionMaster.UpdateMotion(p_time);
|
||||
}
|
||||
|
|
@ -734,7 +738,7 @@ bool Unit::UpdateMeleeAttackingState()
|
|||
player->SwingErrorMsg(swingError);
|
||||
}
|
||||
|
||||
return swingError == 0;
|
||||
return swingError;
|
||||
}
|
||||
|
||||
bool Unit::haveOffhandWeapon() const
|
||||
|
|
@ -1089,6 +1093,8 @@ uint32 Unit::DealDamage(Unit* pVictim, uint32 damage, CleanDamage const* cleanDa
|
|||
|
||||
player_tap->SendDirectMessage(&data);
|
||||
}
|
||||
else if (GetTypeId() == TYPEID_UNIT && this != pVictim)
|
||||
ProcDamageAndSpell(pVictim, PROC_FLAG_KILL, PROC_FLAG_KILLED, PROC_EX_NONE, 0);
|
||||
|
||||
// Reward player, his pets, and group/raid members
|
||||
if (player_tap != pVictim)
|
||||
|
|
@ -1538,7 +1544,7 @@ void Unit::CastSpell(Unit* Victim, SpellEntry const* spellInfo, bool triggered,
|
|||
targets.setSource(caster->GetPositionX(), caster->GetPositionY(), caster->GetPositionZ());
|
||||
|
||||
spell->m_CastItem = castItem;
|
||||
spell->prepare(&targets, triggeredByAura);
|
||||
spell->SpellStart(&targets, triggeredByAura);
|
||||
}
|
||||
|
||||
void Unit::CastCustomSpell(Unit* Victim, uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item* castItem, Aura* triggeredByAura, ObjectGuid originalCaster, SpellEntry const* triggeredBy)
|
||||
|
|
@ -1600,7 +1606,7 @@ void Unit::CastCustomSpell(Unit* Victim, SpellEntry const* spellInfo, int32 cons
|
|||
if (WorldObject* caster = spell->GetCastingObject())
|
||||
{ targets.setSource(caster->GetPositionX(), caster->GetPositionY(), caster->GetPositionZ()); }
|
||||
|
||||
spell->prepare(&targets, triggeredByAura);
|
||||
spell->SpellStart(&targets, triggeredByAura);
|
||||
}
|
||||
|
||||
// used for scripting
|
||||
|
|
@ -1657,7 +1663,7 @@ void Unit::CastSpell(float x, float y, float z, SpellEntry const* spellInfo, boo
|
|||
{ targets.setDestination(x, y, z); }
|
||||
|
||||
spell->m_CastItem = castItem;
|
||||
spell->prepare(&targets, triggeredByAura);
|
||||
spell->SpellStart(&targets, triggeredByAura);
|
||||
}
|
||||
|
||||
// Obsolete func need remove, here only for comotability vs another patches
|
||||
|
|
@ -1897,6 +1903,11 @@ void Unit::CalculateMeleeDamage(Unit* pVictim, CalcDamageInfo* damageInfo, Weapo
|
|||
damageInfo->procEx |= PROC_EX_CRITICAL_HIT;
|
||||
// Crit bonus calc
|
||||
damageInfo->damage += damageInfo->damage;
|
||||
|
||||
// Apply SPELL_AURA_MOD_CRIT_DAMAGE_BONUS modifier first
|
||||
const int32 bonus = GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, SPELL_SCHOOL_MASK_NORMAL);
|
||||
damageInfo->damage += int32((damageInfo->damage) * float(bonus / 100.0f));
|
||||
|
||||
int32 mod = 0;
|
||||
// Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
|
||||
if (damageInfo->attackType == RANGED_ATTACK)
|
||||
|
|
@ -1904,8 +1915,6 @@ void Unit::CalculateMeleeDamage(Unit* pVictim, CalcDamageInfo* damageInfo, Weapo
|
|||
else
|
||||
mod += damageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE);
|
||||
|
||||
mod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, SPELL_SCHOOL_MASK_NORMAL);
|
||||
|
||||
if (mod != 0)
|
||||
damageInfo->damage = int32((damageInfo->damage) * float((100.0f + mod) / 100.0f));
|
||||
|
||||
|
|
@ -2917,6 +2926,8 @@ void Unit::AttackerStateUpdate(Unit* pVictim, WeaponAttackType attType, bool ext
|
|||
return;
|
||||
}
|
||||
|
||||
RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MELEE_ATTACK);
|
||||
|
||||
// attack can be redirected to another target
|
||||
pVictim = SelectMagnetTarget(pVictim);
|
||||
|
||||
|
|
@ -2934,6 +2945,22 @@ void Unit::AttackerStateUpdate(Unit* pVictim, WeaponAttackType attType, bool ext
|
|||
else
|
||||
DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
|
||||
GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist);
|
||||
|
||||
if (Unit* owner = GetOwner())
|
||||
if (owner->GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
owner->SetInCombatWith(pVictim);
|
||||
owner->AddThreat(pVictim);
|
||||
pVictim->SetInCombatWith(owner);
|
||||
}
|
||||
|
||||
for (GuidSet::const_iterator itr = m_guardianPets.begin(); itr != m_guardianPets.end(); ++itr)
|
||||
if (Unit* pet = (Unit*)GetMap()->GetPet(*itr))
|
||||
{
|
||||
pet->SetInCombatWith(pVictim);
|
||||
pet->AddThreat(pVictim);
|
||||
pVictim->SetInCombatWith(pet);
|
||||
}
|
||||
|
||||
// if damage pVictim call AI reaction
|
||||
pVictim->AttackedBy(this);
|
||||
|
|
@ -3101,25 +3128,19 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit* pVictim, WeaponAttackT
|
|||
}
|
||||
|
||||
// mobs can score crushing blows if they're 4 or more levels above victim
|
||||
if (GetLevelForTarget(pVictim) >= pVictim->GetLevelForTarget(this) + 4 &&
|
||||
// can be from by creature (if can) or from controlled player that considered as creature
|
||||
((GetTypeId() != TYPEID_PLAYER && !((Creature*)this)->IsPet() &&
|
||||
!(((Creature*)this)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_CRUSH)) ||
|
||||
GetTypeId() == TYPEID_PLAYER && GetCharmerOrOwnerGuid()))
|
||||
// having defense above your maximum (from items, talents etc.) has no effect
|
||||
// mob's level * 5 - player's current defense skill - add 2% chance per lacking skill point, min. is 20%
|
||||
if ((getLevel() - 4) >= pVictim->getLevel() && !IsNonMeleeSpellCasted(false) /* It should have been !spellCasted but wrath doesn't have that? */
|
||||
&& roll < (tmp = (((attackerMaxSkillValueForLevel - tmp) * 200) - 2000)))
|
||||
{
|
||||
// when their weapon skill is 15 or more above victim's defense skill
|
||||
tmp = victimMaxSkillValueForLevel;
|
||||
// tmp = mob's level * 5 - player's current defense skill
|
||||
tmp = attackerMaxSkillValueForLevel - tmp;
|
||||
if (tmp >= 15)
|
||||
uint32 typeId = GetTypeId();
|
||||
/* It should have been !(((Creature*)this)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_CRUSH) but wrath doesn't have that? */
|
||||
if ((typeId == TYPEID_UNIT && !(GetOwnerGuid() && GetOwner()->GetTypeId() == TYPEID_PLAYER)
|
||||
&& !(static_cast<Creature const*>(this)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_CRUSH))
|
||||
|| (typeId == TYPEID_PLAYER && GetCharmerGuid() && GetCharmer()->GetTypeId() == TYPEID_UNIT))
|
||||
{
|
||||
// add 2% chance per lacking skill point, min. is 15%
|
||||
tmp = tmp * 200 - 1500;
|
||||
if (roll < (sum += tmp))
|
||||
{
|
||||
DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum - tmp, sum);
|
||||
return MELEE_HIT_CRUSHING;
|
||||
}
|
||||
DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: CRUSHING %d)", tmp);
|
||||
return MELEE_HIT_CRUSHING;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3848,7 +3869,7 @@ void Unit::_UpdateAutoRepeatSpell()
|
|||
|
||||
// we want to shoot
|
||||
Spell* spell = new Spell(this, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo, true);
|
||||
spell->prepare(&(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets));
|
||||
spell->SpellStart(&(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets));
|
||||
|
||||
// all went good, reset attack
|
||||
resetAttackTimer(RANGED_ATTACK);
|
||||
|
|
@ -4557,31 +4578,9 @@ bool Unit::RemoveNoStackAurasDueToAuraHolder(SpellAuraHolder* holder)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (i_spellId == spellId) continue;
|
||||
|
||||
bool is_triggered_by_spell = false;
|
||||
// prevent triggering aura of removing aura that triggered it
|
||||
for(int j = 0; j < MAX_EFFECT_INDEX; ++j)
|
||||
{
|
||||
SpellEffectEntry const* iSpellEffect = i_spellProto->GetSpellEffect(SpellEffectIndex(j));
|
||||
if(!iSpellEffect)
|
||||
continue;
|
||||
|
||||
if (iSpellEffect->EffectTriggerSpell == spellId)
|
||||
is_triggered_by_spell = true;
|
||||
}
|
||||
|
||||
// prevent triggered aura of removing aura that triggering it (triggered effect early some aura of parent spell
|
||||
for(int j = 0; j < MAX_EFFECT_INDEX; ++j)
|
||||
{
|
||||
SpellEffectEntry const* spellEffect = i_spellProto->GetSpellEffect(SpellEffectIndex(j));
|
||||
if(!spellEffect)
|
||||
continue;
|
||||
if (spellEffect->EffectTriggerSpell == i_spellId)
|
||||
is_triggered_by_spell = true;
|
||||
}
|
||||
|
||||
if (is_triggered_by_spell)
|
||||
if (((*i).second->GetTriggeredBy() && (*i).second->GetTriggeredBy()->Id == spellId)
|
||||
|| (holder->GetTriggeredBy() && holder->GetTriggeredBy()->Id == i_spellId))
|
||||
continue;
|
||||
|
||||
SpellSpecific i_spellId_spec = GetSpellSpecific(i_spellId);
|
||||
|
|
@ -4982,6 +4981,46 @@ void Unit::RemoveAurasWithAttribute(uint32 flags)
|
|||
}
|
||||
}
|
||||
|
||||
void Unit::RemoveAurasOnCast(SpellEntry const* castedSpellEntry)
|
||||
{
|
||||
for (SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end();)
|
||||
{
|
||||
SpellAuraHolder* holder = iter->second;
|
||||
SpellEntry const* spellEntry = holder->GetSpellProto();
|
||||
bool removeThisHolder = false;
|
||||
|
||||
if (spellEntry->GetAuraInterruptFlags() & AURA_INTERRUPT_FLAG_UNK2)
|
||||
{
|
||||
if (castedSpellEntry->HasAttribute(SPELL_ATTR_EX_NOT_BREAK_STEALTH))
|
||||
{
|
||||
bool foundStealth = false;
|
||||
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
|
||||
{
|
||||
if (Aura* aura = holder->m_auras[i])
|
||||
{
|
||||
if (aura->GetModifier()->m_auraname == SPELL_AURA_MOD_STEALTH)
|
||||
{
|
||||
foundStealth = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
removeThisHolder = !foundStealth;
|
||||
}
|
||||
else
|
||||
removeThisHolder = true;
|
||||
}
|
||||
|
||||
if (removeThisHolder)
|
||||
{
|
||||
RemoveSpellAuraHolder(iter->second);
|
||||
iter = m_spellAuraHolders.begin();
|
||||
}
|
||||
else
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::RemoveNotOwnTrackedTargetAuras(uint32 newPhase)
|
||||
{
|
||||
// tracked aura targets from other casters are removed if the phase does no more fit
|
||||
|
|
@ -5882,7 +5921,7 @@ bool Unit::IsHostileTo(Unit const* unit) const
|
|||
return false;
|
||||
|
||||
// Sanctuary
|
||||
if (pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SUPPORTABLE) && pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SUPPORTABLE))
|
||||
if (pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY) && pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY))
|
||||
return false;
|
||||
|
||||
// PvP FFA state
|
||||
|
|
@ -5994,7 +6033,7 @@ bool Unit::IsFriendlyTo(Unit const* unit) const
|
|||
return true;
|
||||
|
||||
// Sanctuary
|
||||
if (pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SUPPORTABLE) && pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SUPPORTABLE))
|
||||
if (pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY) && pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY))
|
||||
return true;
|
||||
|
||||
// PvP FFA state
|
||||
|
|
@ -6115,10 +6154,13 @@ bool Unit::Attack(Unit* victim, bool meleeAttack)
|
|||
if (m_attacking == victim)
|
||||
{
|
||||
// switch to melee attack from ranged/magic
|
||||
if (meleeAttack && !hasUnitState(UNIT_STAT_MELEE_ATTACKING))
|
||||
if (meleeAttack)
|
||||
{
|
||||
addUnitState(UNIT_STAT_MELEE_ATTACKING);
|
||||
SendMeleeAttackStart(victim);
|
||||
if (!hasUnitState(UNIT_STAT_MELEE_ATTACKING))
|
||||
{
|
||||
addUnitState(UNIT_STAT_MELEE_ATTACKING);
|
||||
SendMeleeAttackStart(victim);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -7237,6 +7279,14 @@ bool Unit::IsSpellCrit(Unit* pVictim, SpellEntry const* spellProto, SpellSchoolM
|
|||
if (spellProto->HasAttribute(SPELL_ATTR_EX2_CANT_CRIT))
|
||||
return false;
|
||||
|
||||
// Creatures do not crit with their spells or abilities, unless it is owned by a player (pet, totem, etc)
|
||||
if (GetTypeId() != TYPEID_PLAYER)
|
||||
{
|
||||
Unit* owner = GetOwner();
|
||||
if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
|
||||
return false;
|
||||
}
|
||||
|
||||
float crit_chance = 0.0f;
|
||||
switch(spellProto->GetDmgClass())
|
||||
{
|
||||
|
|
@ -7420,6 +7470,10 @@ uint32 Unit::SpellCriticalDamageBonus(SpellEntry const* spellProto, uint32 damag
|
|||
break;
|
||||
}
|
||||
|
||||
// Apply SPELL_AURA_MOD_CRIT_DAMAGE_BONUS modifier first
|
||||
const int32 pctBonus = GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, GetSpellSchoolMask(spellProto));
|
||||
crit_bonus += int32((damage + crit_bonus) * float(pctBonus / 100.0f));
|
||||
|
||||
// adds additional damage to crit_bonus (from talents)
|
||||
if (Player* modOwner = GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
|
||||
|
|
@ -7438,8 +7492,6 @@ uint32 Unit::SpellCriticalDamageBonus(SpellEntry const* spellProto, uint32 damag
|
|||
else
|
||||
critPctDamageMod += pVictim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_DAMAGE, GetSpellSchoolMask(spellProto));
|
||||
|
||||
critPctDamageMod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, GetSpellSchoolMask(spellProto));
|
||||
|
||||
if (critPctDamageMod != 0)
|
||||
crit_bonus = int32(crit_bonus * float((100.0f + critPctDamageMod) / 100.0f));
|
||||
|
||||
|
|
@ -7535,9 +7587,9 @@ uint32 Unit::SpellHealingBonusDone(Unit* pVictim, SpellEntry const* spellProto,
|
|||
int ownHotCount = 0; // counted HoT types amount, not stacks
|
||||
|
||||
Unit::AuraList const& RejorRegr = pVictim->GetAurasByType(SPELL_AURA_PERIODIC_HEAL);
|
||||
for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
|
||||
if ((*i)->GetSpellProto()->GetSpellFamilyName() == SPELLFAMILY_DRUID &&
|
||||
(*i)->GetCasterGuid() == GetObjectGuid())
|
||||
for (Unit::AuraList::const_iterator itr = RejorRegr.begin(); itr != RejorRegr.end(); ++itr)
|
||||
if ((*itr)->GetSpellProto()->GetSpellFamilyName() == SPELLFAMILY_DRUID &&
|
||||
(*itr)->GetCasterGuid() == GetObjectGuid())
|
||||
++ownHotCount;
|
||||
|
||||
if (ownHotCount)
|
||||
|
|
@ -8274,13 +8326,11 @@ void Unit::Mount(uint32 mount, uint32 spellId)
|
|||
// Normal case (Unsummon only permanent pet)
|
||||
else if (Pet* pet = GetPet())
|
||||
{
|
||||
if (pet->IsPermanentPetFor((Player*)this) && !((Player*)this)->InArena() &&
|
||||
sWorld.getConfig(CONFIG_BOOL_PET_UNSUMMON_AT_MOUNT))
|
||||
{
|
||||
if (pet->isControlled() && (!(pet->isTemporarySummoned() || ((Player*)this)->InArena())
|
||||
|| sWorld.getConfig(CONFIG_BOOL_PET_UNSUMMON_AT_MOUNT)))
|
||||
((Player*)this)->UnsummonPetTemporaryIfAny();
|
||||
}
|
||||
else
|
||||
pet->ApplyModeFlags(PET_MODE_DISABLE_ACTIONS, true);
|
||||
pet->SetModeFlags(PET_MODE_DISABLE_ACTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -79,9 +79,9 @@ enum SpellAuraInterruptFlags
|
|||
AURA_INTERRUPT_FLAG_NOT_ABOVEWATER = 0x00000080, // 7 removed by entering water
|
||||
AURA_INTERRUPT_FLAG_NOT_UNDERWATER = 0x00000100, // 8 removed by leaving water
|
||||
AURA_INTERRUPT_FLAG_NOT_SHEATHED = 0x00000200, // 9 removed by unsheathing
|
||||
AURA_INTERRUPT_FLAG_UNK10 = 0x00000400, // 10
|
||||
AURA_INTERRUPT_FLAG_UNK11 = 0x00000800, // 11
|
||||
AURA_INTERRUPT_FLAG_UNK12 = 0x00001000, // 12 removed by attack?
|
||||
AURA_INTERRUPT_FLAG_TALK = 0x00000400, // 10 talk to npc / loot? action on creature
|
||||
AURA_INTERRUPT_FLAG_USE = 0x00000800, // 11 mine/use/open action on gameobject
|
||||
AURA_INTERRUPT_FLAG_MELEE_ATTACK = 0x00001000, // 12 removed by attack
|
||||
AURA_INTERRUPT_FLAG_UNK13 = 0x00002000, // 13
|
||||
AURA_INTERRUPT_FLAG_UNK14 = 0x00004000, // 14
|
||||
AURA_INTERRUPT_FLAG_UNK15 = 0x00008000, // 15 removed by casting a spell?
|
||||
|
|
@ -3140,6 +3140,9 @@ class Unit : public WorldObject
|
|||
* \todo Are linked and flying auras really not removed on evade?
|
||||
*/
|
||||
void RemoveAllAurasOnEvade();
|
||||
|
||||
// remove specific aura on cast
|
||||
void RemoveAurasOnCast(SpellEntry const* castedSpellEntry);
|
||||
|
||||
// removing specific aura FROM stack by diff reasons and selections
|
||||
void RemoveAuraHolderFromStack(uint32 spellId, uint32 stackAmount = 1, ObjectGuid casterGuid = ObjectGuid(), AuraRemoveMode mode = AURA_REMOVE_BY_DEFAULT);
|
||||
|
|
|
|||
|
|
@ -321,6 +321,9 @@ void VehicleInfo::UnBoard(Unit* passenger, bool changeVehicle)
|
|||
|
||||
UnBoardPassenger(passenger); // Use TransportBase to remove the passenger from storage list
|
||||
|
||||
// Remove passenger modifications
|
||||
RemoveSeatMods(passenger, seatEntry->m_flags);
|
||||
|
||||
if (!changeVehicle) // Send expected unboarding packages
|
||||
{
|
||||
// Update movementInfo
|
||||
|
|
@ -354,9 +357,6 @@ void VehicleInfo::UnBoard(Unit* passenger, bool changeVehicle)
|
|||
}
|
||||
}
|
||||
|
||||
// Remove passenger modifications
|
||||
RemoveSeatMods(passenger, seatEntry->m_flags);
|
||||
|
||||
// Some creature vehicles get despawned after passenger unboarding
|
||||
if (m_owner->GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -136,8 +136,8 @@ void OutdoorPvPMgr::HandlePlayerEnterZone(Player* player, uint32 zoneId)
|
|||
{
|
||||
if (OutdoorPvP* script = GetScript(zoneId))
|
||||
script->HandlePlayerEnterZone(player, true);
|
||||
else if (OutdoorPvP* script = GetScriptOfAffectedZone(zoneId))
|
||||
script->HandlePlayerEnterZone(player, false);
|
||||
else if (OutdoorPvP* affectedScript = GetScriptOfAffectedZone(zoneId))
|
||||
affectedScript->HandlePlayerEnterZone(player, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -151,8 +151,8 @@ void OutdoorPvPMgr::HandlePlayerLeaveZone(Player* player, uint32 zoneId)
|
|||
// teleport: called once from Player::CleanupsBeforeDelete, once from Player::UpdateZone
|
||||
if (OutdoorPvP* script = GetScript(zoneId))
|
||||
script->HandlePlayerLeaveZone(player, true);
|
||||
else if (OutdoorPvP* script = GetScriptOfAffectedZone(zoneId))
|
||||
script->HandlePlayerLeaveZone(player, false);
|
||||
else if (OutdoorPvP* affectedScript = GetScriptOfAffectedZone(zoneId))
|
||||
affectedScript->HandlePlayerLeaveZone(player, false);
|
||||
}
|
||||
|
||||
void OutdoorPvPMgr::Update(uint32 diff)
|
||||
|
|
|
|||
|
|
@ -107,6 +107,9 @@ void HostileReference::fireStatusChanged(ThreatRefStatusChangeEvent& pThreatRefS
|
|||
|
||||
void HostileReference::addThreat(float pMod)
|
||||
{
|
||||
if (pMod + iThreat < 0)
|
||||
pMod = -iThreat;
|
||||
|
||||
iThreat += pMod;
|
||||
// the threat is changed. Source and target unit have to be availabe
|
||||
// if the link was cut before relink it again
|
||||
|
|
@ -495,12 +498,16 @@ Unit* ThreatManager::getHostileTarget()
|
|||
|
||||
float ThreatManager::getThreat(Unit* pVictim, bool pAlsoSearchOfflineList)
|
||||
{
|
||||
if (!pVictim)
|
||||
return 0.0f;
|
||||
|
||||
float threat = 0.0f;
|
||||
HostileReference* ref = iThreatContainer.getReferenceByTarget(pVictim);
|
||||
if (!ref && pAlsoSearchOfflineList)
|
||||
ref = iThreatOfflineContainer.getReferenceByTarget(pVictim);
|
||||
if (ref)
|
||||
|
||||
if (HostileReference* ref = iThreatContainer.getReferenceByTarget(pVictim))
|
||||
threat = ref->getThreat();
|
||||
else if (pAlsoSearchOfflineList)
|
||||
threat = iThreatOfflineContainer.getReferenceByTarget(pVictim)->getThreat();
|
||||
|
||||
return threat;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -531,7 +531,7 @@ enum SpellCastTargetFlags
|
|||
TARGET_FLAG_OBJECT = 0x00000800, // pguid, 2 spells
|
||||
TARGET_FLAG_TRADE_ITEM = 0x00001000, // pguid, 0 spells
|
||||
TARGET_FLAG_STRING = 0x00002000, // string, 0 spells
|
||||
TARGET_FLAG_UNK1 = 0x00004000, // 199 spells, opening object/lock
|
||||
TARGET_FLAG_GAMEOBJECT_ITEM = 0x00004000, // 199 spells, opening object/lock
|
||||
TARGET_FLAG_CORPSE = 0x00008000, // pguid, resurrection spells
|
||||
TARGET_FLAG_UNK2 = 0x00010000, // pguid, not used in any spells as of 3.0.3 (can be set dynamically)
|
||||
TARGET_FLAG_GLYPH = 0x00020000, // used in glyph spells
|
||||
|
|
|
|||
|
|
@ -279,7 +279,7 @@ enum SpellAttributes
|
|||
SPELL_ATTR_TRADESPELL = 0x00000020,// 5 trade spells, will be added by client to a sublist of profession spell
|
||||
SPELL_ATTR_PASSIVE = 0x00000040,// 6 Passive spell
|
||||
SPELL_ATTR_UNK7 = 0x00000080,// 7 can't be linked in chat?
|
||||
SPELL_ATTR_UNK8 = 0x00000100,// 8 hide created item in tooltip (for effect=24)
|
||||
SPELL_ATTR_UNK8 = 0x00000100,// 8
|
||||
SPELL_ATTR_UNK9 = 0x00000200,// 9
|
||||
SPELL_ATTR_ON_NEXT_SWING_2 = 0x00000400,// 10 on next swing 2
|
||||
SPELL_ATTR_UNK11 = 0x00000800,// 11
|
||||
|
|
@ -422,7 +422,7 @@ enum SpellAttributesEx4
|
|||
SPELL_ATTR_EX4_UNK4 = 0x00000010,// 4 This will no longer cause guards to attack on use??
|
||||
SPELL_ATTR_EX4_UNK5 = 0x00000020,// 5
|
||||
SPELL_ATTR_EX4_NOT_STEALABLE = 0x00000040,// 6 although such auras might be dispellable, they cannot be stolen
|
||||
SPELL_ATTR_EX4_UNK7 = 0x00000080,// 7
|
||||
SPELL_ATTR_EX4_CAN_CAST_WHILE_CASTING = 0x00000080,// 7 In theory, can use this spell while another is channeled/cast/autocast
|
||||
SPELL_ATTR_EX4_STACK_DOT_MODIFIER = 0x00000100,// 8 no effect on non DoTs?
|
||||
SPELL_ATTR_EX4_UNK9 = 0x00000200,// 9
|
||||
SPELL_ATTR_EX4_SPELL_VS_EXTEND_COST = 0x00000400,// 10 Rogue Shiv have this flag
|
||||
|
|
@ -495,7 +495,7 @@ enum SpellAttributesEx6
|
|||
SPELL_ATTR_EX6_UNK5 = 0x00000020,// 5
|
||||
SPELL_ATTR_EX6_UNK6 = 0x00000040,// 6
|
||||
SPELL_ATTR_EX6_UNK7 = 0x00000080,// 7
|
||||
SPELL_ATTR_EX6_UNK8 = 0x00000100,// 8
|
||||
SPELL_ATTR_EX6_IGNORE_CC_TARGETS = 0x00000100,// 8 ignores target with cc effects
|
||||
SPELL_ATTR_EX6_UNK9 = 0x00000200,// 9
|
||||
SPELL_ATTR_EX6_UNK10 = 0x00000400,// 10
|
||||
SPELL_ATTR_EX6_NOT_IN_RAID_INSTANCE = 0x00000800,// 11 not usable in raid instance
|
||||
|
|
|
|||
|
|
@ -1016,8 +1016,8 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
|
|||
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT:
|
||||
{
|
||||
uint32 counter = 0;
|
||||
for (QuestStatusMap::const_iterator itr = GetPlayer()->getQuestStatusMap().begin(); itr != GetPlayer()->getQuestStatusMap().end(); ++itr)
|
||||
if (itr->second.m_rewarded)
|
||||
for (QuestStatusMap::const_iterator questItr = GetPlayer()->getQuestStatusMap().begin(); questItr != GetPlayer()->getQuestStatusMap().end(); ++questItr)
|
||||
if (questItr->second.m_rewarded)
|
||||
++counter;
|
||||
change = counter;
|
||||
progressType = PROGRESS_HIGHEST;
|
||||
|
|
@ -1030,10 +1030,10 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
|
|||
continue;
|
||||
|
||||
uint32 counter = 0;
|
||||
for (QuestStatusMap::const_iterator itr = GetPlayer()->getQuestStatusMap().begin(); itr != GetPlayer()->getQuestStatusMap().end(); ++itr)
|
||||
for (QuestStatusMap::const_iterator questItr = GetPlayer()->getQuestStatusMap().begin(); questItr != GetPlayer()->getQuestStatusMap().end(); ++questItr)
|
||||
{
|
||||
Quest const* quest = sObjectMgr.GetQuestTemplate(itr->first);
|
||||
if (itr->second.m_rewarded && quest->GetZoneOrSort() >= 0 && uint32(quest->GetZoneOrSort()) == achievementCriteria->complete_quests_in_zone.zoneID)
|
||||
Quest const* quest = sObjectMgr.GetQuestTemplate(questItr->first);
|
||||
if (questItr->second.m_rewarded && quest->GetZoneOrSort() >= 0 && uint32(quest->GetZoneOrSort()) == achievementCriteria->complete_quests_in_zone.zoneID)
|
||||
++counter;
|
||||
}
|
||||
change = counter;
|
||||
|
|
|
|||
|
|
@ -682,7 +682,7 @@ class ChatHandler
|
|||
std::string ExtractPlayerNameFromLink(char** text);
|
||||
bool ExtractPlayerTarget(char** args, Player** player, ObjectGuid* player_guid = NULL, std::string* player_name = NULL);
|
||||
// select by arg (name/link) or in-game selection online/offline player
|
||||
|
||||
|
||||
std::string petLink(std::string const& name) const { return m_session ? "|cffffffff|Hpet:" + name + "|h[" + name + "]|h|r" : name; }
|
||||
std::string playerLink(std::string const& name) const { return m_session ? "|cffffffff|Hplayer:" + name + "|h[" + name + "]|h|r" : name; }
|
||||
std::string GetNameLink(Player* chr) const;
|
||||
|
|
|
|||
|
|
@ -362,7 +362,9 @@ Map::Add(T* obj)
|
|||
DEBUG_LOG("%s enters grid[%u,%u]", obj->GetGuidStr().c_str(), cell.GridX(), cell.GridY());
|
||||
|
||||
obj->GetViewPoint().Event_AddedToWorld(&(*grid)(cell.CellX(), cell.CellY()));
|
||||
obj->SetItsNewObject(true);
|
||||
UpdateObjectVisibility(obj, cell, p);
|
||||
obj->SetItsNewObject(false);
|
||||
}
|
||||
|
||||
void Map::MessageBroadcast(Player const* player, WorldPacket* msg, bool to_self)
|
||||
|
|
|
|||
|
|
@ -263,7 +263,7 @@ void WorldSession::HandlePetAction(WorldPacket& recv_data)
|
|||
}
|
||||
}
|
||||
|
||||
spell->prepare(&(spell->m_targets));
|
||||
spell->SpellStart(&(spell->m_targets));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -704,7 +704,7 @@ void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket)
|
|||
pet->SendPetAIReaction();
|
||||
}
|
||||
|
||||
spell->prepare(&(spell->m_targets), triggeredByAura);
|
||||
spell->SpellStart(&(spell->m_targets), triggeredByAura);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -243,8 +243,8 @@ void SpellCastTargets::read(ByteBuffer& data, Unit* caster)
|
|||
// TARGET_FLAG_UNK2 is used for non-combat pets, maybe other?
|
||||
if (m_targetMask & (TARGET_FLAG_UNIT | TARGET_FLAG_UNK2))
|
||||
data >> m_unitTargetGUID.ReadAsPacked();
|
||||
|
||||
if (m_targetMask & (TARGET_FLAG_OBJECT))
|
||||
|
||||
if (m_targetMask & (TARGET_FLAG_OBJECT | TARGET_FLAG_GAMEOBJECT_ITEM))
|
||||
data >> m_GOTargetGUID.ReadAsPacked();
|
||||
|
||||
if ((m_targetMask & (TARGET_FLAG_ITEM | TARGET_FLAG_TRADE_ITEM)) && caster->GetTypeId() == TYPEID_PLAYER)
|
||||
|
|
@ -416,7 +416,7 @@ Spell::Spell(Unit* caster, SpellEntry const* info, bool triggered, ObjectGuid or
|
|||
for (int i = 0; i < MAX_EFFECT_INDEX; ++i)
|
||||
m_currentBasePoints[i] = m_spellInfo->CalculateSimpleValue(SpellEffectIndex(i));
|
||||
|
||||
m_spellState = SPELL_STATE_PREPARING;
|
||||
m_spellState = SPELL_STATE_CREATED;
|
||||
|
||||
m_castPositionX = m_castPositionY = m_castPositionZ = 0;
|
||||
m_TriggerSpells.clear();
|
||||
|
|
@ -1854,6 +1854,13 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList&
|
|||
++next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!prev->IsWithinLOSInMap(*next)
|
||||
|| (m_spellInfo->HasAttribute(SPELL_ATTR_EX6_IGNORE_CC_TARGETS) && !(*next)->CanFreeMove()))
|
||||
{
|
||||
++next;
|
||||
continue;
|
||||
}
|
||||
prev = *next;
|
||||
targetUnitMap.push_back(prev);
|
||||
tempTargetUnitMap.erase(next);
|
||||
|
|
@ -2986,8 +2993,13 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList&
|
|||
}
|
||||
|
||||
// remove caster from the list if required by attribute
|
||||
if (targetMode != TARGET_SELF && targetMode != TARGET_SELF2 && m_spellInfo->HasAttribute(SPELL_ATTR_EX_CANT_TARGET_SELF))
|
||||
targetUnitMap.remove(m_caster);
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR_EX_CANT_TARGET_SELF))
|
||||
{
|
||||
const SpellEffectEntry* spellEffect = m_spellInfo->GetSpellEffect(effIndex);
|
||||
|
||||
if (targetMode != TARGET_SELF && targetMode != TARGET_SELF2 && (spellEffect && spellEffect->Effect != SPELL_EFFECT_SUMMON))
|
||||
targetUnitMap.remove(m_caster);
|
||||
}
|
||||
|
||||
if (unMaxTargets && targetUnitMap.size() > unMaxTargets)
|
||||
{
|
||||
|
|
@ -3064,34 +3076,11 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList&
|
|||
}
|
||||
}
|
||||
|
||||
void Spell::prepare(SpellCastTargets const* targets, Aura* triggeredByAura)
|
||||
SpellCastResult Spell::PreCastCheck(Aura* triggeredByAura /*= nullptr*/)
|
||||
{
|
||||
m_targets = *targets;
|
||||
|
||||
m_spellState = SPELL_STATE_PREPARING;
|
||||
|
||||
m_castPositionX = m_caster->GetPositionX();
|
||||
m_castPositionY = m_caster->GetPositionY();
|
||||
m_castPositionZ = m_caster->GetPositionZ();
|
||||
m_castOrientation = m_caster->GetOrientation();
|
||||
|
||||
if (triggeredByAura)
|
||||
m_triggeredByAuraSpell = triggeredByAura->GetSpellProto();
|
||||
|
||||
// create and add update event for this spell
|
||||
SpellEvent* Event = new SpellEvent(this);
|
||||
m_caster->m_Events.AddEvent(Event, m_caster->m_Events.CalculateTime(1));
|
||||
|
||||
// Prevent casting at cast another spell (ServerSide check)
|
||||
if (m_caster->IsNonMeleeSpellCasted(false, true, true) && m_cast_count)
|
||||
{
|
||||
SendCastResult(SPELL_FAILED_SPELL_IN_PROGRESS);
|
||||
finish(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fill cost data
|
||||
m_powerCost = CalculatePowerCost(m_spellInfo, m_caster, this, m_CastItem);
|
||||
if (m_caster->IsNonMeleeSpellCasted(false, true, true) && m_cast_count && !m_spellInfo->HasAttribute(SPELL_ATTR_EX4_CAN_CAST_WHILE_CASTING))
|
||||
return SPELL_FAILED_SPELL_IN_PROGRESS;
|
||||
|
||||
SpellCastResult result = CheckCast(true);
|
||||
if (result != SPELL_CAST_OK && !IsAutoRepeat()) // always cast autorepeat dummy for triggering
|
||||
|
|
@ -3101,10 +3090,49 @@ void Spell::prepare(SpellCastTargets const* targets, Aura* triggeredByAura)
|
|||
SendChannelUpdate(0);
|
||||
triggeredByAura->GetHolder()->SetAuraDuration(0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return SPELL_CAST_OK;
|
||||
}
|
||||
|
||||
void Spell::SpellStart(SpellCastTargets const* targets, Aura* triggeredByAura)
|
||||
{
|
||||
m_spellState = SPELL_STATE_STARTING;
|
||||
m_targets = *targets;
|
||||
|
||||
if (m_CastItem)
|
||||
m_CastItemGuid = m_CastItem->GetObjectGuid();
|
||||
|
||||
m_castPositionX = m_caster->GetPositionX();
|
||||
m_castPositionY = m_caster->GetPositionY();
|
||||
m_castPositionZ = m_caster->GetPositionZ();
|
||||
m_castOrientation = m_caster->GetOrientation();
|
||||
|
||||
if (triggeredByAura)
|
||||
m_triggeredByAuraSpell = triggeredByAura->GetSpellProto();
|
||||
|
||||
// create and add update event for this spell
|
||||
SpellEvent* Event = new SpellEvent(this);
|
||||
m_caster->m_Events.AddEvent(Event, m_caster->m_Events.CalculateTime(1));
|
||||
|
||||
// Fill cost data
|
||||
m_powerCost = m_IsTriggeredSpell ? 0 : CalculatePowerCost(m_spellInfo, m_caster, this, m_CastItem);
|
||||
|
||||
SpellCastResult result = PreCastCheck();
|
||||
if (result != SPELL_CAST_OK)
|
||||
{
|
||||
SendCastResult(result);
|
||||
finish(false);
|
||||
return;
|
||||
}
|
||||
else
|
||||
Prepare();
|
||||
}
|
||||
|
||||
void Spell::Prepare()
|
||||
{
|
||||
m_spellState = SPELL_STATE_PREPARING;
|
||||
|
||||
// Prepare data for triggers
|
||||
prepareDataForTriggerSystem();
|
||||
|
|
@ -3116,13 +3144,8 @@ void Spell::prepare(SpellCastTargets const* targets, Aura* triggeredByAura)
|
|||
// set timer base at cast time
|
||||
ReSetTimer();
|
||||
|
||||
// stealth must be removed at cast starting (at show channel bar)
|
||||
// skip triggered spell (item equip spell casting and other not explicit character casts/item uses)
|
||||
if (!m_IsTriggeredSpell && isSpellBreakStealth(m_spellInfo))
|
||||
{
|
||||
m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
|
||||
m_caster->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
|
||||
}
|
||||
if (!m_IsTriggeredSpell)
|
||||
m_caster->RemoveAurasOnCast(m_spellInfo);
|
||||
|
||||
// add non-triggered (with cast time and without)
|
||||
if (!m_IsTriggeredSpell)
|
||||
|
|
@ -3134,6 +3157,10 @@ void Spell::prepare(SpellCastTargets const* targets, Aura* triggeredByAura)
|
|||
SendSpellStart();
|
||||
|
||||
TriggerGlobalCooldown();
|
||||
|
||||
// Execute instant spells immediate
|
||||
if (m_timer == 0 && !IsNextMeleeSwingSpell() && !IsAutoRepeat() && !IsChanneledSpell(m_spellInfo))
|
||||
cast();
|
||||
}
|
||||
// execute triggered without cast time explicitly in call point
|
||||
else if (m_timer == 0)
|
||||
|
|
@ -5087,7 +5114,7 @@ void Spell::CastTriggerSpells()
|
|||
for (SpellInfoList::const_iterator si = m_TriggerSpells.begin(); si != m_TriggerSpells.end(); ++si)
|
||||
{
|
||||
Spell* spell = new Spell(m_caster, (*si), true, m_originalCasterGUID);
|
||||
spell->prepare(&m_targets); // use original spell original targets
|
||||
spell->SpellStart(&m_targets); // use original spell original targets
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -6072,23 +6099,43 @@ SpellCastResult Spell::CheckCast(bool strict)
|
|||
}
|
||||
case SPELL_EFFECT_SUMMON_PET:
|
||||
{
|
||||
if (m_caster->GetPetGuid()) // let warlock do a replacement summon
|
||||
if (m_caster->GetCharmGuid())
|
||||
return SPELL_FAILED_ALREADY_HAVE_CHARM;
|
||||
|
||||
uint32 plClass = m_caster->getClass();
|
||||
if (plClass == CLASS_HUNTER)
|
||||
{
|
||||
|
||||
Pet* pet = ((Player*)m_caster)->GetPet();
|
||||
|
||||
if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->getClass() == CLASS_WARLOCK)
|
||||
if (Creature* pet = m_caster->GetPet())
|
||||
{
|
||||
if (strict) // Summoning Disorientation, trigger pet stun (cast by pet so it doesn't attack player)
|
||||
pet->CastSpell(pet, 32752, true, NULL, NULL, pet->GetObjectGuid());
|
||||
if (!pet->IsAlive() || pet->IsDead()) // this one will not play along; tried and retried countless times....
|
||||
return SPELL_FAILED_TARGETS_DEAD;
|
||||
else
|
||||
return SPELL_FAILED_ALREADY_HAVE_SUMMON;
|
||||
}
|
||||
else
|
||||
{
|
||||
Pet* dbPet = new Pet;
|
||||
if (dbPet->LoadPetFromDB((Player*)m_caster, 0))
|
||||
return SPELL_CAST_OK; // still returns an error to the player, so this error must come from somewhere else...
|
||||
else
|
||||
{
|
||||
delete dbPet;
|
||||
return SPELL_FAILED_NO_PET;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_caster->GetPetGuid())
|
||||
{
|
||||
if (plClass == CLASS_WARLOCK) // let warlock do a replacement summon
|
||||
{
|
||||
if (strict) // Summoning Disorientation, trigger pet stun (cast by pet so it doesn't attack player)
|
||||
if (Pet* pet = ((Player*)m_caster)->GetPet())
|
||||
pet->CastSpell(pet, 32752, true, nullptr, nullptr, pet->GetObjectGuid());
|
||||
}
|
||||
else
|
||||
return SPELL_FAILED_ALREADY_HAVE_SUMMON;
|
||||
}
|
||||
|
||||
if (m_caster->GetCharmGuid())
|
||||
return SPELL_FAILED_ALREADY_HAVE_CHARM;
|
||||
|
||||
break;
|
||||
}
|
||||
case SPELL_EFFECT_SUMMON_PLAYER:
|
||||
|
|
@ -6438,16 +6485,21 @@ SpellCastResult Spell::CheckPetCast(Unit* target)
|
|||
if (!m_caster->IsAlive())
|
||||
return SPELL_FAILED_CASTER_DEAD;
|
||||
|
||||
if (m_caster->IsNonMeleeSpellCasted(false)) // prevent spellcast interruption by another spellcast
|
||||
if (m_caster->IsNonMeleeSpellCasted(false) && !m_spellInfo->HasAttribute(SPELL_ATTR_EX4_CAN_CAST_WHILE_CASTING)) // prevent spellcast interruption by another spellcast
|
||||
return SPELL_FAILED_SPELL_IN_PROGRESS;
|
||||
if (m_caster->IsInCombat() && IsNonCombatSpell(m_spellInfo))
|
||||
return SPELL_FAILED_AFFECTING_COMBAT;
|
||||
|
||||
if (m_caster->GetTypeId() == TYPEID_UNIT && (((Creature*)m_caster)->IsPet() || m_caster->IsCharmed()))
|
||||
{
|
||||
// dead owner (pets still alive when owners ressed?)
|
||||
if (m_caster->GetCharmerOrOwner() && !m_caster->GetCharmerOrOwner()->IsAlive())
|
||||
return SPELL_FAILED_CASTER_DEAD;
|
||||
// dead owner (currently only ghouled players can have alive pet casting)
|
||||
Unit* charmer = m_caster->GetCharmerOrOwner();
|
||||
if (charmer)
|
||||
{
|
||||
Player* pCharmer = charmer->GetTypeId() == TYPEID_PLAYER ? static_cast<Player*>(charmer) : nullptr;
|
||||
if (!charmer->IsAlive() && (!pCharmer || !pCharmer->IsGhouled()))
|
||||
return SPELL_FAILED_CASTER_DEAD;
|
||||
}
|
||||
|
||||
if (!target && m_targets.getUnitTarget())
|
||||
target = m_targets.getUnitTarget();
|
||||
|
|
|
|||
|
|
@ -390,7 +390,7 @@ class Spell
|
|||
Spell(Unit* caster, SpellEntry const* info, bool triggered, ObjectGuid originalCasterGUID = ObjectGuid(), SpellEntry const* triggeredBy = NULL);
|
||||
~Spell();
|
||||
|
||||
void prepare(SpellCastTargets const* targets, Aura* triggeredByAura = NULL);
|
||||
void SpellStart(SpellCastTargets const* targets, Aura* triggeredByAura = nullptr);
|
||||
|
||||
void cancel();
|
||||
|
||||
|
|
@ -537,6 +537,9 @@ class Spell
|
|||
bool IgnoreItemRequirements() const; // some item use spells have unexpected reagent data
|
||||
void UpdateOriginalCasterPointer();
|
||||
|
||||
SpellCastResult PreCastCheck(Aura* triggeredByAura = nullptr);
|
||||
void Prepare();
|
||||
|
||||
Unit* m_caster;
|
||||
|
||||
ObjectGuid m_originalCasterGUID; // real source of cast (aura caster/etc), used for spell targets selection
|
||||
|
|
|
|||
|
|
@ -611,9 +611,9 @@ Aura* CreateAura(SpellEntry const* spellproto, SpellEffectIndex eff, int32* curr
|
|||
return new Aura(spellproto, eff, currentBasePoints, holder, target, caster, castItem);
|
||||
}
|
||||
|
||||
SpellAuraHolder* CreateSpellAuraHolder(SpellEntry const* spellproto, Unit* target, WorldObject* caster, Item* castItem)
|
||||
SpellAuraHolder* CreateSpellAuraHolder(SpellEntry const* spellproto, Unit* target, WorldObject* caster, Item* castItem /*= nullptr*/, SpellEntry const* triggeredBy /*= nullptr*/)
|
||||
{
|
||||
return new SpellAuraHolder(spellproto, target, caster, castItem);
|
||||
return new SpellAuraHolder(spellproto, target, caster, castItem, triggeredBy);
|
||||
}
|
||||
|
||||
void Aura::SetModifier(AuraType t, int32 a, uint32 pt, int32 miscValue)
|
||||
|
|
@ -4670,15 +4670,15 @@ void Aura::HandleAuraModStun(bool apply, bool Real)
|
|||
target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
|
||||
target->CastStop(target->GetObjectGuid() == GetCasterGuid() ? GetId() : 0);
|
||||
|
||||
// Creature specific
|
||||
if (target->GetTypeId() != TYPEID_PLAYER)
|
||||
{ target->StopMoving(); }
|
||||
else
|
||||
Unit* charmer = target->GetCharmer();
|
||||
if (target->GetTypeId() == TYPEID_PLAYER || (charmer && charmer->GetTypeId() == TYPEID_PLAYER))
|
||||
{
|
||||
((Player*)target)->m_movementInfo.SetMovementFlags(MOVEFLAG_NONE);
|
||||
target->m_movementInfo.SetMovementFlags(MOVEFLAG_NONE);
|
||||
target->SetStandState(UNIT_STAND_STATE_STAND);// in 1.5 client
|
||||
target->SetRoot(true);
|
||||
}
|
||||
else
|
||||
target->StopMoving();
|
||||
|
||||
// Summon the Naj'entus Spine GameObject on target if spell is Impaling Spine
|
||||
if (GetId() == 39837)
|
||||
|
|
@ -7592,9 +7592,12 @@ void Aura::PeriodicTick()
|
|||
if (Spell* spell = pCaster->GetCurrentSpell(CurrentSpellTypes(i)))
|
||||
if (spell->m_spellInfo->Id == GetId())
|
||||
{ spell->cancel(); }
|
||||
|
||||
|
||||
if (Player* modOwner = pCaster->GetSpellModOwner())
|
||||
{ modOwner->ApplySpellMod(GetId(), SPELLMOD_MULTIPLE_VALUE, multiplier); }
|
||||
{
|
||||
modOwner->ApplySpellMod(GetId(), SPELLMOD_ALL_EFFECTS, new_damage);
|
||||
modOwner->ApplySpellMod(GetId(), SPELLMOD_MULTIPLE_VALUE, multiplier);
|
||||
}
|
||||
|
||||
int32 heal = pCaster->SpellHealingBonusTaken(pCaster, spellProto, int32(new_damage * multiplier), DOT, GetStackAmount());
|
||||
|
||||
|
|
@ -7602,6 +7605,9 @@ void Aura::PeriodicTick()
|
|||
pCaster->CalculateHealAbsorb(heal, &absorbHeal);
|
||||
|
||||
int32 gain = pCaster->DealHeal(pCaster, heal - absorbHeal, spellProto, false, absorbHeal);
|
||||
// Health Leech effects do not generate healing aggro
|
||||
if (m_modifier.m_auraname == SPELL_AURA_PERIODIC_LEECH)
|
||||
break;
|
||||
pCaster->getHostileRefManager().threatAssist(pCaster, gain * 0.5f * sSpellMgr.GetSpellThreatMultiplier(spellProto), spellProto);
|
||||
break;
|
||||
}
|
||||
|
|
@ -7802,9 +7808,9 @@ void Aura::PeriodicTick()
|
|||
pdamage = target->GetMaxPower(POWER_MANA) * 5 / 100;
|
||||
drain_amount = target->GetPower(POWER_MANA) > pdamage ? pdamage : target->GetPower(POWER_MANA);
|
||||
target->ModifyPower(POWER_MANA, -drain_amount);
|
||||
|
||||
SpellPeriodicAuraLogInfo pInfo(this, drain_amount, 0, 0, 0, 0.0f);
|
||||
target->SendPeriodicAuraLog(&pInfo);
|
||||
|
||||
SpellPeriodicAuraLogInfo info(this, drain_amount, 0, 0, 0, 0.0f);
|
||||
target->SendPeriodicAuraLog(&info);
|
||||
}
|
||||
// no break here
|
||||
}
|
||||
|
|
@ -9119,8 +9125,8 @@ bool Aura::HasMechanic(uint32 mechanic) const
|
|||
return m_spellEffect->EffectMechanic == mechanic;
|
||||
}
|
||||
|
||||
SpellAuraHolder::SpellAuraHolder(SpellEntry const* spellproto, Unit* target, WorldObject* caster, Item* castItem) :
|
||||
m_spellProto(spellproto),
|
||||
SpellAuraHolder::SpellAuraHolder(SpellEntry const* spellproto, Unit* target, WorldObject* caster, Item* castItem, SpellEntry const* triggeredBy) :
|
||||
m_spellProto(spellproto), m_triggeredBy(triggeredBy),
|
||||
m_target(target), m_castItemGuid(castItem ? castItem->GetObjectGuid() : ObjectGuid()),
|
||||
m_auraSlot(MAX_AURAS), m_auraFlags(AFLAG_NONE), m_auraLevel(1),
|
||||
m_procCharges(0), m_stackAmount(1),
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ struct ReapplyAffectedPassiveAurasHelper;
|
|||
class SpellAuraHolder
|
||||
{
|
||||
public:
|
||||
SpellAuraHolder(SpellEntry const* spellproto, Unit* target, WorldObject* caster, Item* castItem);
|
||||
SpellAuraHolder(SpellEntry const* spellproto, Unit* target, WorldObject* caster, Item* castItem, SpellEntry const* triggeredBy);
|
||||
Aura* m_auras[MAX_EFFECT_INDEX];
|
||||
|
||||
void AddAura(Aura* aura, SpellEffectIndex index);
|
||||
|
|
@ -104,6 +104,7 @@ class SpellAuraHolder
|
|||
bool ModStackAmount(int32 num); // return true if last charge dropped
|
||||
|
||||
Aura* GetAuraByEffectIndex(SpellEffectIndex index) const { return m_auras[index]; }
|
||||
SpellEntry const* GetTriggeredBy() const { return m_triggeredBy; }
|
||||
|
||||
uint32 GetId() const { return m_spellProto->Id; }
|
||||
SpellEntry const* GetSpellProto() const { return m_spellProto; }
|
||||
|
|
@ -206,6 +207,7 @@ class SpellAuraHolder
|
|||
ObjectGuid m_casterGuid;
|
||||
ObjectGuid m_castItemGuid; // it is NOT safe to keep a pointer to the item because it may get deleted
|
||||
time_t m_applyTime;
|
||||
SpellEntry const* m_triggeredBy; // Spell responsible for this holder
|
||||
|
||||
uint8 m_auraSlot; // Aura slot on unit (for show in client)
|
||||
uint8 m_auraFlags; // Aura info flag (for send data to client)
|
||||
|
|
@ -578,5 +580,5 @@ class SingleEnemyTargetAura : public Aura
|
|||
};
|
||||
|
||||
Aura* CreateAura(SpellEntry const* spellproto, SpellEffectIndex eff, int32* currentBasePoints, SpellAuraHolder* holder, Unit* target, Unit* caster = NULL, Item* castItem = NULL);
|
||||
SpellAuraHolder* CreateSpellAuraHolder(SpellEntry const* spellproto, Unit* target, WorldObject* caster, Item* castItem = NULL);
|
||||
SpellAuraHolder* CreateSpellAuraHolder(SpellEntry const* spellproto, Unit* target, WorldObject* caster, Item* castItem = nullptr, SpellEntry const* triggeredBy = nullptr);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -306,8 +306,8 @@ void Spell::EffectInstaKill(SpellEffectEntry const* /*effect*/)
|
|||
data << unitTarget->GetObjectGuid(); // Victim GUID
|
||||
data << uint32(m_spellInfo->Id);
|
||||
m_caster->SendMessageToSet(&data, true);
|
||||
|
||||
m_caster->DealDamage(unitTarget, unitTarget->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
|
||||
|
||||
m_caster->DealDamage(unitTarget, unitTarget->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, m_spellInfo, false);
|
||||
}
|
||||
|
||||
void Spell::EffectEnvironmentalDMG(SpellEffectEntry const* effect)
|
||||
|
|
@ -1384,6 +1384,13 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
|
|||
|
||||
return;
|
||||
}
|
||||
case 32027: // Expedition Flare
|
||||
{
|
||||
// 32029 = Expedition Preserver | 32030 = Expedition Scout
|
||||
m_caster->CastSpell(m_caster, (urand(0, 1) ? 32029 : 32030), true);
|
||||
|
||||
return;
|
||||
}
|
||||
case 32146: // Liquid Fire
|
||||
{
|
||||
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->GetTypeId() != TYPEID_PLAYER)
|
||||
|
|
@ -1609,7 +1616,7 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
|
|||
unitTarget->CastSpell(m_caster, 42486, true);
|
||||
|
||||
// There is no known spell to kill the target
|
||||
unitTarget->DealDamage(unitTarget, unitTarget->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false);
|
||||
m_caster->DealDamage(unitTarget, unitTarget->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false);
|
||||
return;
|
||||
}
|
||||
case 42489: // Cast Ooze Zap When Energized
|
||||
|
|
@ -5372,6 +5379,10 @@ void Spell::EffectApplyAreaAura(SpellEffectEntry const* effect)
|
|||
|
||||
void Spell::EffectSummonType(SpellEffectEntry const* effect)
|
||||
{
|
||||
// if this spell already have an aura applied cancel the summon
|
||||
if (m_caster->HasAura(m_spellInfo->Id))
|
||||
return;
|
||||
|
||||
uint32 prop_id = effect->EffectMiscValueB;
|
||||
SummonPropertiesEntry const *summon_prop = sSummonPropertiesStore.LookupEntry(prop_id);
|
||||
if(!summon_prop)
|
||||
|
|
@ -5563,8 +5574,8 @@ void Spell::EffectSummonType(SpellEffectEntry const* effect)
|
|||
|
||||
if (!summonResult)
|
||||
return; // No further handling required
|
||||
|
||||
for (CreatureSummonPositions::iterator itr = summonPositions.begin(); itr != summonPositions.end(); ++itr)
|
||||
|
||||
for (itr = summonPositions.begin(); itr != summonPositions.end(); ++itr)
|
||||
{
|
||||
MANGOS_ASSERT(itr->creature || itr != summonPositions.begin());
|
||||
if (!itr->creature)
|
||||
|
|
@ -5930,21 +5941,27 @@ bool Spell::DoSummonPet(SpellEffectEntry const* effect)
|
|||
return false;
|
||||
}
|
||||
|
||||
uint32 level = m_caster->getLevel(); // TODO Engineering Pets have also caster-level? (if they exist)
|
||||
Pet* spawnCreature = new Pet(SUMMON_PET);
|
||||
Pet* spawnCreature = new Pet();
|
||||
|
||||
if (m_caster->GetTypeId() == TYPEID_PLAYER && spawnCreature->LoadPetFromDB((Player*)m_caster, pet_entry))
|
||||
// set timer for unsummon
|
||||
if (m_duration > 0)
|
||||
spawnCreature->SetDuration(m_duration);
|
||||
|
||||
if (m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
// Summon in dest location
|
||||
if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
|
||||
spawnCreature->Relocate(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, -m_caster->GetOrientation());
|
||||
if (spawnCreature->LoadPetFromDB((Player*)m_caster, pet_entry))
|
||||
{
|
||||
// Summon in dest location
|
||||
if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
|
||||
spawnCreature->Relocate(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, -m_caster->GetOrientation());
|
||||
|
||||
// set timer for unsummon
|
||||
if (m_duration > 0)
|
||||
spawnCreature->SetDuration(m_duration);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
spawnCreature->setPetType(SUMMON_PET);
|
||||
}
|
||||
else
|
||||
spawnCreature->setPetType(GUARDIAN_PET);
|
||||
|
||||
// Summon in dest location
|
||||
CreatureCreatePos pos(m_caster->GetMap(), m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, -m_caster->GetOrientation(), m_caster->GetPhaseMask());
|
||||
|
|
@ -5961,35 +5978,27 @@ bool Spell::DoSummonPet(SpellEffectEntry const* effect)
|
|||
return false;
|
||||
}
|
||||
|
||||
uint32 level = std::max(m_caster->getLevel() + effect->EffectMultipleValue, 1.0f);
|
||||
|
||||
spawnCreature->SetRespawnCoord(pos);
|
||||
|
||||
// set timer for unsummon
|
||||
if (m_duration > 0)
|
||||
spawnCreature->SetDuration(m_duration);
|
||||
|
||||
spawnCreature->SetOwnerGuid(m_caster->GetObjectGuid());
|
||||
spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
|
||||
spawnCreature->SetPowerType(POWER_MANA);
|
||||
spawnCreature->setFaction(m_caster->getFaction());
|
||||
spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0);
|
||||
spawnCreature->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
|
||||
spawnCreature->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
|
||||
spawnCreature->SetCreatorGuid(m_caster->GetObjectGuid());
|
||||
spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
|
||||
|
||||
spawnCreature->InitStatsForLevel(level, m_caster);
|
||||
spawnCreature->InitStatsForLevel(level);
|
||||
|
||||
spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
|
||||
|
||||
spawnCreature->AIM_Initialize();
|
||||
spawnCreature->InitPetCreateSpells();
|
||||
spawnCreature->InitLevelupSpellsForLevel();
|
||||
spawnCreature->SetHealth(spawnCreature->GetMaxHealth());
|
||||
spawnCreature->SetPower(POWER_MANA, spawnCreature->GetMaxPower(POWER_MANA));
|
||||
|
||||
// spawnCreature->SetName(""); // generated by client
|
||||
|
||||
map->Add((Creature*)spawnCreature);
|
||||
spawnCreature->AIM_Initialize();
|
||||
|
||||
m_caster->SetPet(spawnCreature);
|
||||
|
||||
|
|
@ -5999,13 +6008,25 @@ bool Spell::DoSummonPet(SpellEffectEntry const* effect)
|
|||
spawnCreature->SavePetToDB(PET_SAVE_AS_CURRENT);
|
||||
((Player*)m_caster)->PetSpellInitialize();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Notify Summoner
|
||||
if (m_originalCaster && (m_originalCaster != m_caster)
|
||||
&& (m_originalCaster->GetTypeId() == TYPEID_UNIT) && ((Creature*)m_originalCaster)->AI())
|
||||
{
|
||||
((Creature*)m_originalCaster)->AI()->JustSummoned(spawnCreature);
|
||||
if (m_originalCaster->IsInCombat() && !(spawnCreature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE)))
|
||||
((Creature*)spawnCreature)->AI()->AttackStart(m_originalCaster->getAttackerForHelper());
|
||||
}
|
||||
else if ((m_caster->GetTypeId() == TYPEID_UNIT) && ((Creature*)m_caster)->AI())
|
||||
{
|
||||
((Creature*)m_caster)->AI()->JustSummoned(spawnCreature);
|
||||
if (m_caster->IsInCombat() && !(spawnCreature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE)))
|
||||
((Creature*)spawnCreature)->AI()->AttackStart(m_caster->getAttackerForHelper());
|
||||
}
|
||||
}
|
||||
|
||||
if (m_caster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_caster)->AI())
|
||||
((Creature*)m_caster)->AI()->JustSummoned((Creature*)spawnCreature);
|
||||
if (m_originalCaster && m_originalCaster != m_caster && m_originalCaster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_originalCaster)->AI())
|
||||
((Creature*)m_originalCaster)->AI()->JustSummoned((Creature*)spawnCreature);
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Spell::DoSummonVehicle(CreatureSummonPositions& list, SummonPropertiesEntry const* prop, SpellEffectEntry const * effect, uint32 /*level*/)
|
||||
|
|
@ -6496,7 +6517,7 @@ void Spell::EffectEnchantItemTmp(SpellEffectEntry const* effect)
|
|||
Spell* spell = new Spell(m_caster, spellInfo, true);
|
||||
SpellCastTargets targets;
|
||||
targets.setItemTarget(itemTarget);
|
||||
spell->prepare(&targets);
|
||||
spell->SpellStart(&targets);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -11232,6 +11253,18 @@ void Spell::EffectTransmitted(SpellEffectEntry const* effect)
|
|||
{
|
||||
uint32 name_id = effect->EffectMiscValue;
|
||||
|
||||
switch (m_spellInfo->Id)
|
||||
{
|
||||
case 29886: // Create Soulwell
|
||||
if (m_caster->HasAura(18692))
|
||||
name_id = 183510;
|
||||
else if (m_caster->HasAura(18693))
|
||||
name_id = 183511;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
GameObjectInfo const* goinfo = ObjectMgr::GetGameObjectInfo(name_id);
|
||||
|
||||
if (!goinfo)
|
||||
|
|
|
|||
|
|
@ -433,7 +433,7 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
|
|||
Spell* spell = new Spell(mover, spellInfo, triggeredByAura ? true : false, mover->GetObjectGuid(), triggeredByAura ? triggeredByAura->GetSpellProto() : NULL);
|
||||
spell->m_cast_count = cast_count; // set count of casts
|
||||
spell->m_glyphIndex = glyphIndex;
|
||||
spell->prepare(&targets, triggeredByAura);
|
||||
spell->SpellStart(&targets, triggeredByAura);
|
||||
}
|
||||
|
||||
void WorldSession::HandleCancelCastOpcode(WorldPacket& recvPacket)
|
||||
|
|
|
|||
|
|
@ -521,10 +521,10 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& recvPacket)
|
|||
trader->ModifyMoney(my_trade->GetMoney());
|
||||
|
||||
if (my_spell)
|
||||
my_spell->prepare(&my_targets);
|
||||
my_spell->SpellStart(&my_targets);
|
||||
|
||||
if (his_spell)
|
||||
his_spell->prepare(&his_targets);
|
||||
his_spell->SpellStart(&his_targets);
|
||||
|
||||
// cleanup
|
||||
clearAcceptTradeMode(my_trade, his_trade);
|
||||
|
|
|
|||
|
|
@ -358,7 +358,7 @@ bool Transport::GenerateWaypoints(uint32 pathid, std::set<uint32>& mapids)
|
|||
newY = keyFrames[i].node->y + (keyFrames[i + 1].node->y - keyFrames[i].node->y) * d / keyFrames[i + 1].distFromPrev;
|
||||
newZ = keyFrames[i].node->z + (keyFrames[i + 1].node->z - keyFrames[i].node->z) * d / keyFrames[i + 1].distFromPrev;
|
||||
|
||||
bool teleport = false;
|
||||
teleport = false;
|
||||
if (keyFrames[i].node->mapid != cM)
|
||||
{
|
||||
teleport = true;
|
||||
|
|
@ -366,7 +366,7 @@ bool Transport::GenerateWaypoints(uint32 pathid, std::set<uint32>& mapids)
|
|||
}
|
||||
|
||||
// sLog.outString("T: %d, D: %f, x: %f, y: %f, z: %f", t, d, newX, newY, newZ);
|
||||
WayPoint pos(keyFrames[i].node->mapid, newX, newY, newZ, teleport);
|
||||
pos = WayPoint(keyFrames[i].node->mapid, newX, newY, newZ, teleport);
|
||||
if (teleport)
|
||||
m_WayPoints[t] = pos;
|
||||
}
|
||||
|
|
@ -412,7 +412,7 @@ bool Transport::GenerateWaypoints(uint32 pathid, std::set<uint32>& mapids)
|
|||
cM = keyFrames[i + 1].node->mapid;
|
||||
}
|
||||
|
||||
WayPoint pos(keyFrames[i + 1].node->mapid, keyFrames[i + 1].node->x, keyFrames[i + 1].node->y, keyFrames[i + 1].node->z, teleport,
|
||||
pos = WayPoint(keyFrames[i + 1].node->mapid, keyFrames[i + 1].node->x, keyFrames[i + 1].node->y, keyFrames[i + 1].node->z, teleport,
|
||||
keyFrames[i + 1].node->arrivalEventID, keyFrames[i + 1].node->departureEventID);
|
||||
|
||||
// sLog.outString("T: %d, x: %f, y: %f, z: %f, t:%d", t, pos.x, pos.y, pos.z, teleport);
|
||||
|
|
|
|||
|
|
@ -3109,10 +3109,10 @@ SpellAuraProcResult Unit::HandleProcTriggerSpellAuraProc(Unit* pVictim, uint32 d
|
|||
}
|
||||
case 69023: // Mirrored Soul
|
||||
{
|
||||
int32 basepoints = (int32)(damage * 0.45f);
|
||||
int32 basepoints2 = (int32)(damage * 0.45f);
|
||||
if (Unit* caster = triggeredByAura->GetCaster())
|
||||
// Actually this spell should be sent with SMSG_SPELL_START
|
||||
CastCustomSpell(caster, 69034, &basepoints, nullptr, nullptr, true, nullptr, triggeredByAura, GetObjectGuid());
|
||||
CastCustomSpell(caster, 69034, &basepoints2, nullptr, nullptr, true, nullptr, triggeredByAura, GetObjectGuid());
|
||||
|
||||
return SPELL_AURA_PROC_OK;
|
||||
}
|
||||
|
|
@ -3212,8 +3212,8 @@ SpellAuraProcResult Unit::HandleProcTriggerSpellAuraProc(Unit* pVictim, uint32 d
|
|||
if ((*i)->GetSpellProto()->GetSpellFamilyName() == SPELLFAMILY_WARLOCK && (*i)->GetSpellProto()->SpellIconID == 113)
|
||||
{
|
||||
// basepoints of trigger spell stored in dummyeffect of spellProto
|
||||
int32 basepoints = GetMaxPower(POWER_MANA) * (*i)->GetSpellProto()->CalculateSimpleValue(EFFECT_INDEX_2) / 100;
|
||||
CastCustomSpell(this, 18371, &basepoints, nullptr, nullptr, true, castItem, triggeredByAura);
|
||||
int32 basepoints2 = GetMaxPower(POWER_MANA) * (*i)->GetSpellProto()->CalculateSimpleValue(EFFECT_INDEX_2) / 100;
|
||||
CastCustomSpell(this, 18371, &basepoints2, nullptr, nullptr, true, castItem, triggeredByAura);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -252,8 +252,6 @@ World::AddSession_(WorldSession* s)
|
|||
// prevent decrease sessions count if session queued
|
||||
if (RemoveQueuedSession(old->second))
|
||||
{ decrease_session = false; }
|
||||
// not remove replaced session form queue if listed
|
||||
delete old->second;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -468,6 +466,7 @@ void World::LoadConfigSettings(bool reload)
|
|||
setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_LEGENDARY, "Rate.Drop.Item.Legendary", 1.0f);
|
||||
setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_ARTIFACT, "Rate.Drop.Item.Artifact", 1.0f);
|
||||
setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_REFERENCED, "Rate.Drop.Item.Referenced", 1.0f);
|
||||
setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_QUEST, "Rate.Drop.Item.Quest", 1.0f);
|
||||
setConfigPos(CONFIG_FLOAT_RATE_DROP_MONEY, "Rate.Drop.Money", 1.0f);
|
||||
setConfigPos(CONFIG_FLOAT_RATE_DROP_CURRENCY, "Rate.Drop.Currency", 1.0f);
|
||||
setConfigPos(CONFIG_FLOAT_RATE_DROP_CURRENCY_AMOUNT, "Rate.Drop.Currency.Amount", 1.0f);
|
||||
|
|
|
|||
|
|
@ -263,6 +263,7 @@ enum eConfigFloatValues
|
|||
CONFIG_FLOAT_RATE_DROP_ITEM_LEGENDARY,
|
||||
CONFIG_FLOAT_RATE_DROP_ITEM_ARTIFACT,
|
||||
CONFIG_FLOAT_RATE_DROP_ITEM_REFERENCED,
|
||||
CONFIG_FLOAT_RATE_DROP_ITEM_QUEST,
|
||||
CONFIG_FLOAT_RATE_DROP_MONEY,
|
||||
CONFIG_FLOAT_RATE_DROP_CURRENCY,
|
||||
CONFIG_FLOAT_RATE_DROP_CURRENCY_AMOUNT,
|
||||
|
|
|
|||
|
|
@ -1272,6 +1272,7 @@ Visibility.AIRelocationNotifyDelay = 1000
|
|||
# Rate.Drop.Item.Legendary
|
||||
# Rate.Drop.Item.Artifact
|
||||
# Rate.Drop.Item.Referenced
|
||||
# Rate.Drop.Item.Quest
|
||||
# Rate.Drop.Money
|
||||
# Rate.Drop.Currency
|
||||
# Drop rates (items by quality, money and currency drop chance)
|
||||
|
|
@ -1423,6 +1424,7 @@ Rate.Drop.Item.Epic = 1
|
|||
Rate.Drop.Item.Legendary = 1
|
||||
Rate.Drop.Item.Artifact = 1
|
||||
Rate.Drop.Item.Referenced = 1
|
||||
Rate.Drop.Item.Quest = 1
|
||||
Rate.Drop.Money = 1
|
||||
Rate.Drop.Currency = 1
|
||||
Rate.Drop.Currency.Amount = 1
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue