Core/Creatures: Various fixes for creatures, regarding combat conditions, despawning, and few others

Port From (https://github.com/TrinityCore/TrinityCore/commit/fe63cd3dbb66f4fda743858db4284a24bc2bd400)
This commit is contained in:
hondacrx
2019-08-17 10:47:55 -04:00
parent bdfea4ecad
commit d3cbe70f56
10 changed files with 155 additions and 158 deletions
+1 -1
View File
@@ -175,8 +175,8 @@ namespace Framework.Constants
public const int MaxCreatureModelIds = 4;
public const int MaxTrainerspellAbilityReqs = 3;
public const int CreatureRegenInterval = 2 * Time.InMilliseconds;
public const int CreatureNoPathEvadeTime = 5 * Time.InMilliseconds;
public const int PetFocusRegenInterval = 4 * Time.InMilliseconds;
public const int CreatureNoPathEvadeTime = 5 * Time.InMilliseconds;
public const int BoundaryVisualizeCreature = 15425;
public const float BoundaryVisualizeCreatureScale = 0.25f;
public const int BoundaryVisualizeStepSize = 1;
@@ -33,6 +33,7 @@ namespace Game.Entities
ObjectGuid m_suppressedTarget; // Stores the creature's "real" target while casting
float m_suppressedOrientation; // Stores the creature's "real" orientation while casting
long _lastDamagedTime; // Part of Evade mechanics
MultiMap<byte, byte> m_textRepeat = new MultiMap<byte, byte>();
public ulong m_PlayerDamageReq;
+143 -130
View File
@@ -101,10 +101,7 @@ namespace Game.Entities
public void DisappearAndDie()
{
DestroyForNearbyPlayers();
if (IsAlive())
setDeathState(DeathState.JustDied);
RemoveCorpse(false);
ForcedDespawn(0);
}
public void SearchFormation()
@@ -121,7 +118,7 @@ namespace Game.Entities
FormationMgr.AddCreatureToGroup(frmdata.leaderGUID, this);
}
public void RemoveCorpse(bool setSpawnTime = true)
public void RemoveCorpse(bool setSpawnTime = true, bool destroyForNearbyPlayers = true)
{
if (getDeathState() != DeathState.Corpse)
return;
@@ -135,6 +132,9 @@ namespace Game.Entities
if (IsAIEnabled)
GetAI().CorpseRemoved(respawnDelay);
if (destroyForNearbyPlayers)
DestroyForNearbyPlayers();
// Should get removed later, just keep "compatibility" with scripts
if (setSpawnTime)
m_respawnTime = Math.Max(Time.UnixTime + respawnDelay, m_respawnTime);
@@ -145,6 +145,21 @@ namespace Game.Entities
float x, y, z, o;
GetRespawnPosition(out x, out y, out z, out o);
// We were spawned on transport, calculate real position
if (IsSpawnedOnTransport())
{
Position pos = m_movementInfo.transport.pos;
pos.posX = x;
pos.posY = y;
pos.posZ = z;
pos.SetOrientation(o);
ITransport transport = GetDirectTransport();
if (transport != null)
transport.CalculatePassengerPosition(ref x, ref y, ref z, ref o);
}
SetHomePosition(x, y, z, o);
GetMap().CreatureRelocation(this, x, y, z, o);
}
@@ -275,6 +290,11 @@ namespace Game.Entities
SetNpcFlags((NPCFlags)(npcFlags & 0xFFFFFFFF));
SetNpcFlags2((NPCFlags2)(npcFlags >> 32));
// if unit is in combat, keep this flag
unitFlags &= ~(uint)UnitFlags.InCombat;
if (IsInCombat())
unitFlags |= (uint)UnitFlags.InCombat;
SetUnitFlags((UnitFlags)unitFlags);
SetUnitFlags2((UnitFlags2)unitFlags2);
SetUnitFlags3((UnitFlags3)unitFlags3);
@@ -283,8 +303,6 @@ namespace Game.Entities
SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.StateAnimID), (uint)CliDB.AnimationDataStorage.Count);
RemoveUnitFlag(UnitFlags.InCombat);
SetBaseAttackTime(WeaponAttackType.BaseAttack, cInfo.BaseAttackTime);
SetBaseAttackTime(WeaponAttackType.OffAttack, cInfo.BaseAttackTime);
SetBaseAttackTime(WeaponAttackType.RangedAttack, cInfo.RangeAttackTime);
@@ -518,13 +536,11 @@ namespace Game.Entities
if (!IsInEvadeMode() && (!bInCombat || IsPolymorphed() || CanNotReachTarget())) // regenerate health if not in combat or if polymorphed
RegenerateHealth();
if (HasUnitFlag2(UnitFlags2.RegeneratePower))
{
if (GetPowerType() == PowerType.Energy)
Regenerate(PowerType.Energy);
else
RegenerateMana();
}
if (GetPowerType() == PowerType.Energy)
Regenerate(PowerType.Energy);
else
Regenerate(PowerType.Mana);
m_regenTimer = SharedConst.CreatureRegenInterval;
}
@@ -541,66 +557,14 @@ namespace Game.Entities
}
void RegenerateMana()
{
int curValue = GetPower(PowerType.Mana);
int maxValue = GetMaxPower(PowerType.Mana);
if (curValue >= maxValue)
return;
int addvalue = 0;
// Combat and any controlled creature
if (IsInCombat() || !GetCharmerOrOwnerGUID().IsEmpty())
{
float ManaIncreaseRate = WorldConfig.GetFloatValue(WorldCfg.RatePowerMana);
addvalue = (int)((27.0f / 5.0f + 17.0f) * ManaIncreaseRate);
}
else
addvalue = maxValue / 3;
// Apply modifiers (if any).
addvalue *= (int)GetTotalAuraMultiplierByMiscValue(AuraType.ModPowerRegenPercent, (int)PowerType.Mana);
addvalue += GetTotalAuraModifierByMiscValue(AuraType.ModPowerRegen, (int)PowerType.Mana) * SharedConst.CreatureRegenInterval / (5 * Time.InMilliseconds);
ModifyPower(PowerType.Mana, addvalue);
}
void RegenerateHealth()
{
if (!isRegeneratingHealth())
return;
ulong curValue = GetHealth();
ulong maxValue = GetMaxHealth();
if (curValue >= maxValue)
return;
long addvalue = 0;
// Not only pet, but any controlled creature
if (!GetCharmerOrOwnerGUID().IsEmpty())
{
float HealthIncreaseRate = WorldConfig.GetFloatValue(WorldCfg.RateHealth);
addvalue = (uint)(0.015f * GetMaxHealth() * HealthIncreaseRate);
}
else
addvalue = (long)maxValue / 3;
// Apply modifiers (if any).
addvalue *= (int)GetTotalAuraMultiplier(AuraType.ModHealthRegenPercent);
addvalue += GetTotalAuraModifier(AuraType.ModRegen) * SharedConst.CreatureRegenInterval / (5 * Time.InMilliseconds);
ModifyHealth(addvalue);
}
public void Regenerate(PowerType power)
{
int curValue = GetPower(power);
int maxValue = GetMaxPower(power);
if (!HasUnitFlag2(UnitFlags2.RegeneratePower))
return;
if (curValue >= maxValue)
return;
@@ -620,6 +584,19 @@ namespace Game.Entities
addvalue = 20;
break;
}
case PowerType.Mana:
{
// Combat and any controlled creature
if (IsInCombat() || GetCharmerOrOwnerGUID().IsEmpty())
{
float ManaIncreaseRate = WorldConfig.GetFloatValue(WorldCfg.RatePowerMana);
addvalue = (27.0f / 5.0f + 17.0f) * ManaIncreaseRate;
}
else
addvalue = maxValue / 3;
break;
}
default:
return;
}
@@ -631,6 +608,35 @@ namespace Game.Entities
ModifyPower(power, (int)addvalue);
}
void RegenerateHealth()
{
if (!isRegeneratingHealth())
return;
ulong curValue = GetHealth();
ulong maxValue = GetMaxHealth();
if (curValue >= maxValue)
return;
long addvalue = 0;
// Not only pet, but any controlled creature (and not polymorphed)
if (!GetCharmerOrOwnerGUID().IsEmpty() && !IsPolymorphed())
{
float HealthIncreaseRate = WorldConfig.GetFloatValue(WorldCfg.RateHealth);
addvalue = (uint)(0.015f * GetMaxHealth() * HealthIncreaseRate);
}
else
addvalue = (long)maxValue / 3;
// Apply modifiers (if any).
addvalue *= (int)GetTotalAuraMultiplier(AuraType.ModHealthRegenPercent);
addvalue += GetTotalAuraModifier(AuraType.ModRegen) * SharedConst.CreatureRegenInterval / (5 * Time.InMilliseconds);
ModifyHealth(addvalue);
}
public void DoFleeToGetAssistance()
{
if (!GetVictim())
@@ -770,6 +776,10 @@ namespace Game.Entities
return false;
}
// Allow players to see those units while dead, do it here (mayby altered by addon auras)
if (cinfo.TypeFlags.HasAnyFlag(CreatureTypeFlags.GhostVisible))
m_serverSideVisibility.SetValue(ServerSideVisibilityType.Ghost, GhostVisibilityType.Alive | GhostVisibilityType.Ghost);
if (!CreateFromProto(guidlow, entry, data, vehId))
return false;
@@ -1615,7 +1625,7 @@ namespace Game.Entities
setDeathState(DeathState.Corpse);
}
RemoveCorpse(false);
RemoveCorpse(false, false);
if (getDeathState() == DeathState.Dead)
{
@@ -1672,33 +1682,21 @@ namespace Game.Entities
return;
}
// do it before killing creature
DestroyForNearbyPlayers();
if (IsAlive())
setDeathState(DeathState.JustDied);
bool overrideRespawnTime = true;
if (forceRespawnTimer > TimeSpan.Zero)
{
if (IsAlive())
{
uint respawnDelay = m_respawnDelay;
uint corpseDelay = m_corpseDelay;
m_respawnDelay = (uint)forceRespawnTimer.TotalSeconds;
m_corpseDelay = 0;
setDeathState(DeathState.JustDied);
m_respawnDelay = respawnDelay;
m_corpseDelay = corpseDelay;
}
else
{
m_corpseRemoveTime = Time.UnixTime;
m_respawnTime = Time.UnixTime + (long)forceRespawnTimer.TotalMilliseconds;
}
}
else
{
if (IsAlive())
setDeathState(DeathState.JustDied);
SetRespawnTime((uint)forceRespawnTimer.TotalSeconds);
overrideRespawnTime = false;
}
RemoveCorpse(false);
// Skip corpse decay time
RemoveCorpse(overrideRespawnTime, false);
}
public void DespawnOrUnsummon(TimeSpan time, TimeSpan forceRespawnTimer = default(TimeSpan)) { DespawnOrUnsummon((uint)time.TotalMilliseconds, forceRespawnTimer); }
@@ -1979,6 +1977,14 @@ namespace Game.Entities
if (!IsAlive())
return false;
// we cannot assist in evade mode
if (IsInEvadeMode())
return false;
// or if enemy is in evade mode
if (enemy.GetTypeId() == TypeId.Unit && enemy.ToCreature().IsInEvadeMode())
return false;
// we don't need help from non-combatant ;)
if (IsCivilian())
return false;
@@ -2066,22 +2072,41 @@ namespace Game.Entities
if (IsAIEnabled && !GetAI().CanAIAttack(victim))
return false;
if (GetMap().IsDungeon())
return true;
// we cannot attack in evade mode
if (IsInEvadeMode())
return false;
// if the mob is actively being damaged, do not reset due to distance unless it's a world boss
if (!isWorldBoss())
if (Time.UnixTime - GetLastDamagedTime() <= SharedConst.MaxAggroResetTime)
// or if enemy is in evade mode
if (victim.GetTypeId() == TypeId.Unit && victim.ToCreature().IsInEvadeMode())
return false;
if (!GetCharmerOrOwnerGUID().IsPlayer())
{
if (GetMap().IsDungeon())
return true;
//Use AttackDistance in distance check if threat radius is lower. This prevents creature bounce in and out of combat every update tick.
float dist = Math.Max(GetAttackDistance(victim), (WorldConfig.GetFloatValue(WorldCfg.ThreatRadius) + m_CombatDistance));
// don't check distance to home position if recently damaged, this should include taunt auras
if (!isWorldBoss() && (GetLastDamagedTime() > Global.WorldMgr.GetGameTime() || HasAuraType(AuraType.ModTaunt)))
return true;
}
// Map visibility range, but no more than 2*cell size
float dist = Math.Min(GetMap().GetVisibilityRange(), MapConst.SizeofCells * 2);
Unit unit = GetCharmerOrOwner();
if (unit != null)
return victim.IsWithinDist(unit, dist);
else
return victim.IsInDist(m_homePosition, dist);
{
// include sizes for huge npcs
dist += GetObjectSize() + victim.GetObjectSize();
// to prevent creatures in air ignore attacks because distance is already too high...
if (GetCreatureTemplate().InhabitType.HasAnyFlag(InhabitType.Air))
return victim.IsInDist2d(m_homePosition, dist);
else
return victim.IsInDist(m_homePosition, dist);
}
}
CreatureAddon GetCreatureAddon()
@@ -2242,40 +2267,17 @@ namespace Game.Entities
public void GetRespawnPosition(out float x, out float y, out float z)
{
if (m_spawnId != 0)
{
CreatureData data = Global.ObjectMgr.GetCreatureData(GetSpawnId());
if (data != null)
{
x = data.posX;
y = data.posY;
z = data.posZ;
return;
}
}
GetPosition(out x, out y, out z);
float notUsed;
GetRespawnPosition(out x, out y, out z, out notUsed, out notUsed);
}
public void GetRespawnPosition(out float x, out float y, out float z, out float ori)
{
if (m_spawnId != 0)
{
CreatureData data = Global.ObjectMgr.GetCreatureData(GetSpawnId());
if (data != null)
{
x = data.posX;
y = data.posY;
z = data.posZ;
ori = data.orientation;
return;
}
}
GetPosition(out x, out y, out z, out ori);
float notUsed;
GetRespawnPosition(out x, out y, out z, out ori, out notUsed);
}
public void GetRespawnPosition(out float x, out float y, out float z, out float ori, out float dist)
{
// for npcs on transport, this will return transport offset
if (m_spawnId != 0)
{
CreatureData data = Global.ObjectMgr.GetCreatureData(GetSpawnId());
@@ -2291,10 +2293,17 @@ namespace Game.Entities
}
}
GetPosition(out x, out y, out z, out ori);
// changed this from current position to home position, fixes world summons with infinite duration (wg npcs for example)
Position homePos = GetHomePosition();
x = homePos.GetPositionX();
y = homePos.GetPositionY();
z = homePos.GetPositionZ();
ori = homePos.GetOrientation();
dist = 0;
}
bool IsSpawnedOnTransport() { return m_creatureData != null && m_creatureData.mapid != GetMapId(); }
public void AllLootRemovedFromCorpse()
{
if (loot.loot_type != LootType.Skinning && !IsPet() && GetCreatureTemplate().SkinLootId != 0 && hasLootRecipient())
@@ -3056,6 +3065,10 @@ namespace Game.Entities
public bool IsReputationGainDisabled() { return DisableReputationGain; }
public bool IsDamageEnoughForLootingAndReward() { return m_creatureInfo.FlagsExtra.HasAnyFlag(CreatureFlagsExtra.NoPlayerDamageReq) || m_PlayerDamageReq == 0; }
// Part of Evade mechanics
long GetLastDamagedTime() { return _lastDamagedTime; }
public void SetLastDamagedTime(long val) { _lastDamagedTime = val; }
public void ResetPlayerDamageReq() { m_PlayerDamageReq = (uint)(GetHealth() / 2); }
public uint GetOriginalEntry()
+4 -7
View File
@@ -1047,13 +1047,14 @@ namespace Game.Entities
victim.ModifyHealth(-(int)damage);
if (damagetype == DamageEffectType.Direct || damagetype == DamageEffectType.SpellDirect)
{
victim.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.DirectDamage, spellProto != null ? spellProto.Id : 0);
victim.UpdateLastDamagedTime(spellProto);
}
if (!victim.IsTypeId(TypeId.Player))
{
// Part of Evade mechanics. DoT's and Thorns / Retribution Aura do not contribute to this
if (damagetype != DamageEffectType.DOT && damage > 0 && !victim.GetOwnerGUID().IsPlayer() && (spellProto == null || !spellProto.HasAura(GetMap().GetDifficultyID(), AuraType.DamageShield)))
victim.ToCreature().SetLastDamagedTime(Global.WorldMgr.GetGameTime() + SharedConst.MaxAggroResetTime);
victim.AddThreat(this, damage, damageSchoolMask, spellProto);
}
else // victim is a player
@@ -3206,9 +3207,5 @@ namespace Game.Entities
}
return true;
}
// Part of Evade mechanics
public long GetLastDamagedTime() { return _lastDamagedTime; }
public void SetLastDamagedTime(long val) { _lastDamagedTime = val; }
}
}
-1
View File
@@ -65,7 +65,6 @@ namespace Game.Entities
public float m_modMeleeHitChance { get; set; }
public float m_modRangedHitChance { get; set; }
public float m_modSpellHitChance { get; set; }
long _lastDamagedTime;
bool m_canDualWield;
public int m_baseSpellCritChance { get; set; }
public uint m_regenTimer { get; set; }
-11
View File
@@ -4262,17 +4262,6 @@ namespace Game.Entities
return val;
}
void UpdateLastDamagedTime(SpellInfo spellProto)
{
if (!IsTypeId(TypeId.Unit) || IsPet())
return;
if (spellProto != null && spellProto.HasAura(Difficulty.None, AuraType.DamageShield))
return;
SetLastDamagedTime(Time.UnixTime);
}
public bool IsHighestExclusiveAura(Aura aura, bool removeOtherAuraApplications = false)
{
foreach (AuraEffect aurEff in aura.GetAuraEffects())
+3 -2
View File
@@ -143,8 +143,9 @@ namespace Game
GetPlayer().RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Talk);
if (unit.IsArmorer() || unit.IsCivilian() || unit.IsQuestGiver() || unit.IsServiceProvider() || unit.IsGuard())
unit.StopMoving();
// and if he has pure gossip or is banker and moves or is tabard designer?
//if (unit->IsArmorer() || unit->IsCivilian() || unit->IsQuestGiver() || unit->IsServiceProvider() || unit->IsGuard())
unit.StopMoving();
// If spiritguide, no need for gossip menu, just put player into resurrect queue
if (unit.IsSpiritGuide())
+1 -1
View File
@@ -438,7 +438,7 @@ namespace Game.PvP
{
// Don't save respawn time
creature.SetRespawnTime(0);
creature.RemoveCorpse();
creature.DespawnOrUnsummon();
creature.AddObjectToRemoveList();
}
+1 -1
View File
@@ -2587,7 +2587,7 @@ namespace Game.Spells
{
target.Kill(caster);
if (caster.IsTypeId(TypeId.Unit))
caster.ToCreature().RemoveCorpse();
caster.ToCreature().DespawnOrUnsummon();
}
if (!mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmount))
+1 -4
View File
@@ -2956,10 +2956,7 @@ namespace Game.Spells
caster.RewardPlayerAndGroupAtEvent(18388, unitTarget);
Creature target = unitTarget.ToCreature();
if (target != null)
{
target.setDeathState(DeathState.Corpse);
target.RemoveCorpse();
}
target.DespawnOrUnsummon();
}
break;
// Mug Transformation