Merge branch 'master' of github.com:EQEmu/Server

This commit is contained in:
KimLS 2017-06-29 14:14:24 -07:00
commit 1110b284d8
20 changed files with 156 additions and 178 deletions

View File

@ -1,5 +1,16 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50) EQEMu Changelog (Started on Sept 24, 2003 15:50)
------------------------------------------------------- -------------------------------------------------------
== 6/28/2017 ==
Akkadius: Fixed issues with Z correctness when NPCs are pathing on normal grids
Akkadius: Fixed issues with Z correctness when NPCs are engaged with players following
Akkadius: NPC corpses should fall into the ground far less
== 6/25/2017 ==
Akkadius: New rules made by developers are now automatically created when world boots up, this keeps
from having to issue schema SQL updates every time rules are added.
- Whenever a rule isn't present in the database, it will be automatically created
Akkadius: Sped up saylink retrieval x1000 helpful for dialogues, plugins with many saylinks
== 4/16/2017 == == 4/16/2017 ==
KLS: Merge eqstream branch KLS: Merge eqstream branch
- UDP client stack completely rewritten should both have better throughput and recover better (peq has had far fewer reports of desyncs). - UDP client stack completely rewritten should both have better throughput and recover better (peq has had far fewer reports of desyncs).

View File

@ -221,7 +221,7 @@ namespace EQ
resend_delay_ms = 150; resend_delay_ms = 150;
resend_delay_factor = 1.5; resend_delay_factor = 1.5;
resend_delay_min = 150; resend_delay_min = 150;
resend_delay_max = 4000; resend_delay_max = 1000;
connect_delay_ms = 500; connect_delay_ms = 500;
stale_connection_ms = 90000; stale_connection_ms = 90000;
connect_stale_ms = 5000; connect_stale_ms = 5000;

View File

@ -274,6 +274,7 @@ RULE_BOOL(Map, FixPathingZWhenLoading, true) //increases zone boot times a bit
RULE_BOOL(Map, FixPathingZAtWaypoints, false) //alternative to `WhenLoading`, accomplishes the same thing but does it at each waypoint instead of once at boot time. RULE_BOOL(Map, FixPathingZAtWaypoints, false) //alternative to `WhenLoading`, accomplishes the same thing but does it at each waypoint instead of once at boot time.
RULE_BOOL(Map, FixPathingZWhenMoving, false) //very CPU intensive, but helps hopping with widely spaced waypoints. RULE_BOOL(Map, FixPathingZWhenMoving, false) //very CPU intensive, but helps hopping with widely spaced waypoints.
RULE_BOOL(Map, FixPathingZOnSendTo, false) //try to repair Z coords in the SendTo routine as well. RULE_BOOL(Map, FixPathingZOnSendTo, false) //try to repair Z coords in the SendTo routine as well.
RULE_BOOL(Map, FixZWhenMoving, true) // Automatically fix NPC Z coordinates when moving/pathing/engaged (Far less CPU intensive than its predecessor)
RULE_REAL(Map, FixPathingZMaxDeltaMoving, 20) //at runtime while pathing: max change in Z to allow the BestZ code to apply. RULE_REAL(Map, FixPathingZMaxDeltaMoving, 20) //at runtime while pathing: max change in Z to allow the BestZ code to apply.
RULE_REAL(Map, FixPathingZMaxDeltaWaypoint, 20) //at runtime at each waypoint: max change in Z to allow the BestZ code to apply. RULE_REAL(Map, FixPathingZMaxDeltaWaypoint, 20) //at runtime at each waypoint: max change in Z to allow the BestZ code to apply.
RULE_REAL(Map, FixPathingZMaxDeltaSendTo, 20) //at runtime in SendTo: max change in Z to allow the BestZ code to apply. RULE_REAL(Map, FixPathingZMaxDeltaSendTo, 20) //at runtime in SendTo: max change in Z to allow the BestZ code to apply.
@ -397,6 +398,7 @@ RULE_BOOL(Spells, FlatItemExtraSpellAmt, false) // allow SpellDmg stat to affect
RULE_BOOL(Spells, IgnoreSpellDmgLvlRestriction, false) // ignore the 5 level spread on applying SpellDmg RULE_BOOL(Spells, IgnoreSpellDmgLvlRestriction, false) // ignore the 5 level spread on applying SpellDmg
RULE_BOOL(Spells, AllowItemTGB, false) // TGB doesn't work with items on live, custom servers want it though RULE_BOOL(Spells, AllowItemTGB, false) // TGB doesn't work with items on live, custom servers want it though
RULE_BOOL(Spells, NPCInnateProcOverride, true) // NPC innate procs override the target type to single target. RULE_BOOL(Spells, NPCInnateProcOverride, true) // NPC innate procs override the target type to single target.
RULE_BOOL(Spells, OldRainTargets, false) // use old incorrectly implemented max targets for rains
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY(Combat) RULE_CATEGORY(Combat)

View File

@ -30,7 +30,7 @@
Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/ */
#define CURRENT_BINARY_DATABASE_VERSION 9111 #define CURRENT_BINARY_DATABASE_VERSION 9112
#ifdef BOTS #ifdef BOTS
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9017 #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9017
#else #else

View File

@ -42,6 +42,7 @@ WeaponSkillFalloff = RuleR.Get(Rule.WeaponSkillFalloff);
ArcheryHitPenalty = RuleR.Get(Rule.ArcheryHitPenalty); ArcheryHitPenalty = RuleR.Get(Rule.ArcheryHitPenalty);
UseOldDamageIntervalRules = RuleB.Get(Rule.UseOldDamageIntervalRules); UseOldDamageIntervalRules = RuleB.Get(Rule.UseOldDamageIntervalRules);
CriticalMessageRange = RuleI.Get(Rule.CriticalDamage);
function MeleeMitigation(e) function MeleeMitigation(e)
e.IgnoreDefault = true; e.IgnoreDefault = true;
@ -238,9 +239,9 @@ function TryCriticalHit(e)
e.hit.damage_done = (e.hit.damage_done * SlayDmgBonus * 2.25) / 100; e.hit.damage_done = (e.hit.damage_done * SlayDmgBonus * 2.25) / 100;
if (self:GetGender() == 1) then if (self:GetGender() == 1) then
entity_list:FilteredMessageClose(self, false, 200, MT.CritMelee, Filter.MeleeCrits, string.format('%s\'s holy blade cleanses her target! (%d)', self:GetCleanName(), e.hit.damage_done)); entity_list:FilteredMessageClose(self, false, CriticalMessageRange, MT.CritMelee, Filter.MeleeCrits, string.format('%s\'s holy blade cleanses her target! (%d)', self:GetCleanName(), e.hit.damage_done));
else else
entity_list:FilteredMessageClose(self, false, 200, MT.CritMelee, Filter.MeleeCrits, string.format('%s\'s holy blade cleanses his target! (%d)', self:GetCleanName(), e.hit.damage_done)); entity_list:FilteredMessageClose(self, false, CriticalMessageRange, MT.CritMelee, Filter.MeleeCrits, string.format('%s\'s holy blade cleanses his target! (%d)', self:GetCleanName(), e.hit.damage_done));
end end
return e; return e;
@ -326,15 +327,15 @@ function TryCriticalHit(e)
end end
if (crip_success) then if (crip_success) then
entity_list:FilteredMessageClose(self, false, 200, MT.CritMelee, Filter.MeleeCrits, string.format('%s lands a Crippling Blow! (%d)', self:GetCleanName(), e.hit.damage_done)); entity_list:FilteredMessageClose(self, false, CriticalMessageRange, MT.CritMelee, Filter.MeleeCrits, string.format('%s lands a Crippling Blow! (%d)', self:GetCleanName(), e.hit.damage_done));
if (defender:GetLevel() <= 55 and not defender:GetSpecialAbility(SpecialAbility.unstunable)) then if (defender:GetLevel() <= 55 and not defender:GetSpecialAbility(SpecialAbility.unstunable)) then
defender:Emote("staggers."); defender:Emote("staggers.");
defender:Stun(0); defender:Stun(0);
end end
elseif (deadlySuccess) then elseif (deadlySuccess) then
entity_list:FilteredMessageClose(self, false, 200, MT.CritMelee, Filter.MeleeCrits, string.format('%s scores a Deadly Strike! (%d)', self:GetCleanName(), e.hit.damage_done)); entity_list:FilteredMessageClose(self, false, CriticalMessageRange, MT.CritMelee, Filter.MeleeCrits, string.format('%s scores a Deadly Strike! (%d)', self:GetCleanName(), e.hit.damage_done));
else else
entity_list:FilteredMessageClose(self, false, 200, MT.CritMelee, Filter.MeleeCrits, string.format('%s scores a critical hit! (%d)', self:GetCleanName(), e.hit.damage_done)); entity_list:FilteredMessageClose(self, false, CriticalMessageRange, MT.CritMelee, Filter.MeleeCrits, string.format('%s scores a critical hit! (%d)', self:GetCleanName(), e.hit.damage_done));
end end
end end
end end
@ -379,9 +380,9 @@ function TryPetCriticalHit(self, defender, hit)
local entity_list = eq.get_entity_list(); local entity_list = eq.get_entity_list();
critMod = critMod + GetCritDmgMod(self, hit.skill) * 2; critMod = critMod + GetCritDmgMod(self, hit.skill) * 2;
hit.damage_done = (hit.damage_done * critMod) / 100; hit.damage_done = (hit.damage_done * critMod) / 100;
entity_list:FilteredMessageClose(this, false, 200, entity_list:FilteredMessageClose(this, false, CriticalMessageRange,
MT.CritMelee, Filter.MeleeCrits, string.format('%s scores a critical hit! (%d)', MT.CritMelee, Filter.MeleeCrits, string.format('%s scores a critical hit! (%d)',
self:GetCleanName(), hit.damage_done)); self:GetCleanName(), e.hit.damage_done));
end end
end end

View File

@ -365,6 +365,7 @@
9109|2017_04_08_doors_disable_timer.sql|SHOW COLUMNS FROM `doors` LIKE 'disable_timer'|empty| 9109|2017_04_08_doors_disable_timer.sql|SHOW COLUMNS FROM `doors` LIKE 'disable_timer'|empty|
9110|2017_04_10_graveyard.sql|show index from graveyard WHERE key_name = 'zone_id_nonunique'|empty| 9110|2017_04_10_graveyard.sql|show index from graveyard WHERE key_name = 'zone_id_nonunique'|empty|
9111|2017_06_24_saylink_index.sql|SHOW INDEX FROM `saylink` WHERE `key_name` = 'phrase_index'|empty| 9111|2017_06_24_saylink_index.sql|SHOW INDEX FROM `saylink` WHERE `key_name` = 'phrase_index'|empty|
9112|2017_06_24_rule_values_expand.sql|SHOW COLUMNS FROM rule_values WHERE Field = 'rule_value' and Type = 'varchar(30)'|empty|
# Upgrade conditions: # Upgrade conditions:
# This won't be needed after this system is implemented, but it is used database that are not # This won't be needed after this system is implemented, but it is used database that are not

View File

@ -0,0 +1,2 @@
ALTER TABLE `rule_values`
MODIFY COLUMN `rule_value` varchar(30) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT '' AFTER `rule_name`;

View File

@ -332,6 +332,8 @@ int main(int argc, char** argv) {
database.ClearMerchantTemp(); database.ClearMerchantTemp();
} }
RuleManager::Instance()->SaveRules(&database);
Log(Logs::General, Logs::World_Server, "Loading EQ time of day.."); Log(Logs::General, Logs::World_Server, "Loading EQ time of day..");
TimeOfDay_Struct eqTime; TimeOfDay_Struct eqTime;
time_t realtime; time_t realtime;

View File

@ -53,9 +53,8 @@ extern WorldServer worldserver;
extern EntityList entity_list; extern EntityList entity_list;
extern Zone* zone; extern Zone* zone;
EQEmu::skills::SkillType Mob::AttackAnimation(int Hand, const EQEmu::ItemInstance* weapon) EQEmu::skills::SkillType Mob::AttackAnimation(int Hand, const EQEmu::ItemInstance* weapon, EQEmu::skills::SkillType skillinuse)
{ {
EQEmu::skills::SkillType skillinuse = EQEmu::skills::Skill1HBlunt;
// Determine animation // Determine animation
int type = 0; int type = 0;
if (weapon && weapon->IsClassCommon()) { if (weapon && weapon->IsClassCommon()) {
@ -1924,7 +1923,7 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
//do attack animation regardless of whether or not we can hit below //do attack animation regardless of whether or not we can hit below
int16 charges = 0; int16 charges = 0;
EQEmu::ItemInstance weapon_inst(weapon, charges); EQEmu::ItemInstance weapon_inst(weapon, charges);
my_hit.skill = AttackAnimation(Hand, &weapon_inst); my_hit.skill = AttackAnimation(Hand, &weapon_inst, my_hit.skill);
//basically "if not immune" then do the attack //basically "if not immune" then do the attack
if (weapon_damage > 0) { if (weapon_damage > 0) {
@ -2388,6 +2387,13 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, EQEmu::skills::Skil
entity_list.UnMarkNPC(GetID()); entity_list.UnMarkNPC(GetID());
entity_list.RemoveNPC(GetID()); entity_list.RemoveNPC(GetID());
/* Fix Z on Corpse Creation */
glm::vec3 dest(m_Position.x, m_Position.y, m_Position.z);
float new_z = zone->zonemap->FindBestZ(dest, nullptr);
corpse->SetFlyMode(1);
corpse->GMMove(m_Position.x, m_Position.y, new_z + 5, m_Position.w);
this->SetID(0); this->SetID(0);
if (killer != 0 && emoteid != 0) if (killer != 0 && emoteid != 0)

View File

@ -68,6 +68,7 @@ Beacon::Beacon(Mob *at_mob, int lifetime)
resist_adjust = 0; resist_adjust = 0;
spell_iterations = 0; spell_iterations = 0;
caster_id = 0; caster_id = 0;
max_targets = 4; // default
if(lifetime) if(lifetime)
remove_timer.Start(); remove_timer.Start();
@ -93,10 +94,10 @@ bool Beacon::Process()
) )
{ {
Mob *caster = entity_list.GetMob(caster_id); Mob *caster = entity_list.GetMob(caster_id);
if(caster && spell_iterations--) if(caster && spell_iterations-- && max_targets)
{ {
bool affect_caster = (!caster->IsNPC() && !caster->IsAIControlled()); //NPC AE spells do not affect the NPC caster bool affect_caster = (!caster->IsNPC() && !caster->IsAIControlled()); //NPC AE spells do not affect the NPC caster
entity_list.AESpell(caster, this, spell_id, affect_caster, resist_adjust); entity_list.AESpell(caster, this, spell_id, affect_caster, resist_adjust, &max_targets);
} }
else else
{ {
@ -126,6 +127,8 @@ void Beacon::AELocationSpell(Mob *caster, uint16 cast_spell_id, int16 resist_adj
this->resist_adjust = resist_adjust; this->resist_adjust = resist_adjust;
spell_iterations = spells[spell_id].AEDuration / 2500; spell_iterations = spells[spell_id].AEDuration / 2500;
spell_iterations = spell_iterations < 1 ? 1 : spell_iterations; // at least 1 spell_iterations = spell_iterations < 1 ? 1 : spell_iterations; // at least 1
if (spells[spell_id].aemaxtargets)
max_targets = spells[spell_id].aemaxtargets;
spell_timer.Start(2500); spell_timer.Start(2500);
spell_timer.Trigger(); spell_timer.Trigger();
} }

View File

@ -56,6 +56,7 @@ protected:
int16 resist_adjust; int16 resist_adjust;
int spell_iterations; int spell_iterations;
Timer spell_timer; Timer spell_timer;
int max_targets;
uint16 caster_id; uint16 caster_id;
private: private:

View File

@ -694,7 +694,7 @@ void EntityList::AETaunt(Client* taunter, float range, int32 bonus_hate)
// causes caster to hit every mob within dist range of center with // causes caster to hit every mob within dist range of center with
// spell_id. // spell_id.
// NPC spells will only affect other NPCs with compatible faction // NPC spells will only affect other NPCs with compatible faction
void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster, int16 resist_adjust) void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster, int16 resist_adjust, int *max_targets)
{ {
Mob *curmob = nullptr; Mob *curmob = nullptr;
@ -703,12 +703,25 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_
float min_range2 = spells[spell_id].min_range * spells[spell_id].min_range; float min_range2 = spells[spell_id].min_range * spells[spell_id].min_range;
float dist_targ = 0; float dist_targ = 0;
const auto &position = spells[spell_id].targettype == ST_Ring ? caster->GetTargetRingLocation() : static_cast<glm::vec3>(center->GetPosition());
glm::vec2 min = { position.x - dist, position.y - dist };
glm::vec2 max = { position.x + dist, position.y + dist };
bool bad = IsDetrimentalSpell(spell_id); bool bad = IsDetrimentalSpell(spell_id);
bool isnpc = caster->IsNPC(); bool isnpc = caster->IsNPC();
int MAX_TARGETS_ALLOWED = 4;
if (spells[spell_id].aemaxtargets) if (RuleB(Spells, OldRainTargets))
MAX_TARGETS_ALLOWED = spells[spell_id].aemaxtargets; max_targets = nullptr; // ignore it!
// if we have a passed in value, use it, otherwise default to data
// detrimental Target AEs have a default value of 4 for PCs and unlimited for NPCs
int max_targets_allowed = 0; // unlimited
if (max_targets) // rains pass this in since they need to preserve the count through waves
max_targets_allowed = *max_targets;
else if (spells[spell_id].aemaxtargets)
max_targets_allowed = spells[spell_id].aemaxtargets;
else if (IsTargetableAESpell(spell_id) && bad && !isnpc)
max_targets_allowed = 4;
int iCounter = 0; int iCounter = 0;
@ -732,13 +745,10 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_
continue; continue;
if (spells[spell_id].pcnpc_only_flag == 2 && (curmob->IsClient() || curmob->IsMerc())) if (spells[spell_id].pcnpc_only_flag == 2 && (curmob->IsClient() || curmob->IsMerc()))
continue; continue;
if (!IsWithinAxisAlignedBox(static_cast<glm::vec2>(curmob->GetPosition()), min, max))
continue;
if (spells[spell_id].targettype == ST_Ring) { dist_targ = DistanceSquared(curmob->GetPosition(), position);
dist_targ = DistanceSquared(static_cast<glm::vec3>(curmob->GetPosition()), caster->GetTargetRingLocation());
}
else if (center) {
dist_targ = DistanceSquared(curmob->GetPosition(), center->GetPosition());
}
if (dist_targ > dist2) //make sure they are in range if (dist_targ > dist2) //make sure they are in range
continue; continue;
@ -776,24 +786,19 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_
} }
curmob->CalcSpellPowerDistanceMod(spell_id, dist_targ); curmob->CalcSpellPowerDistanceMod(spell_id, dist_targ);
caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust);
//if we get here... cast the spell. if (max_targets_allowed) { // if we have a limit, increment count
if (IsTargetableAESpell(spell_id) && bad) {
if (iCounter < MAX_TARGETS_ALLOWED) {
caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust);
}
} else {
if (spells[spell_id].aemaxtargets && iCounter < spells[spell_id].aemaxtargets)
caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust);
if (!spells[spell_id].aemaxtargets)
caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust);
}
if (!isnpc || spells[spell_id].aemaxtargets) //npcs are not target limited (unless casting a spell with a target limit)...
iCounter++; iCounter++;
if (iCounter >= max_targets_allowed) // we done
break;
} }
} }
if (max_targets && max_targets_allowed)
*max_targets = *max_targets - iCounter;
}
void EntityList::MassGroupBuff(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster) void EntityList::MassGroupBuff(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster)
{ {
Mob *curmob = nullptr; Mob *curmob = nullptr;

View File

@ -357,7 +357,7 @@ public:
void AEAttack(Mob *attacker, float dist, int Hand = EQEmu::inventory::slotPrimary, int count = 0, bool IsFromSpell = false); void AEAttack(Mob *attacker, float dist, int Hand = EQEmu::inventory::slotPrimary, int count = 0, bool IsFromSpell = false);
void AETaunt(Client *caster, float range=0, int32 bonus_hate=0); void AETaunt(Client *caster, float range=0, int32 bonus_hate=0);
void AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster = true, int16 resist_adjust = 0); void AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster = true, int16 resist_adjust = 0, int *max_targets = nullptr);
void MassGroupBuff(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster = true); void MassGroupBuff(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster = true);
void AEBardPulse(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster = true); void AEBardPulse(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster = true);

View File

@ -112,7 +112,9 @@ Mob::Mob(const char* in_name,
m_Position(position), m_Position(position),
tmHidden(-1), tmHidden(-1),
mitigation_ac(0), mitigation_ac(0),
m_specialattacks(eSpecialAttacks::None) m_specialattacks(eSpecialAttacks::None),
fix_z_timer(1000),
fix_z_timer_engaged(100)
{ {
targeted = 0; targeted = 0;
tar_ndx=0; tar_ndx=0;

View File

@ -233,7 +233,7 @@ public:
inline bool SeeImprovedHide() const { return see_improved_hide; } inline bool SeeImprovedHide() const { return see_improved_hide; }
bool IsInvisible(Mob* other = 0) const; bool IsInvisible(Mob* other = 0) const;
void SetInvisible(uint8 state); void SetInvisible(uint8 state);
EQEmu::skills::SkillType AttackAnimation(int Hand, const EQEmu::ItemInstance* weapon); EQEmu::skills::SkillType AttackAnimation(int Hand, const EQEmu::ItemInstance* weapon, EQEmu::skills::SkillType skillinuse = EQEmu::skills::Skill1HBlunt);
//Song //Song
bool UseBardSpellLogic(uint16 spell_id = 0xffff, int slot = -1); bool UseBardSpellLogic(uint16 spell_id = 0xffff, int slot = -1);
@ -913,6 +913,7 @@ public:
float GetGroundZ(float new_x, float new_y, float z_offset=0.0); float GetGroundZ(float new_x, float new_y, float z_offset=0.0);
void SendTo(float new_x, float new_y, float new_z); void SendTo(float new_x, float new_y, float new_z);
void SendToFixZ(float new_x, float new_y, float new_z); void SendToFixZ(float new_x, float new_y, float new_z);
void FixZ();
void NPCSpecialAttacks(const char* parse, int permtag, bool reset = true, bool remove = false); void NPCSpecialAttacks(const char* parse, int permtag, bool reset = true, bool remove = false);
inline uint32 DontHealMeBefore() const { return pDontHealMeBefore; } inline uint32 DontHealMeBefore() const { return pDontHealMeBefore; }
inline uint32 DontBuffMeBefore() const { return pDontBuffMeBefore; } inline uint32 DontBuffMeBefore() const { return pDontBuffMeBefore; }
@ -1373,6 +1374,8 @@ protected:
bool flee_mode; bool flee_mode;
Timer flee_timer; Timer flee_timer;
Timer fix_z_timer;
Timer fix_z_timer_engaged;
bool pAIControlled; bool pAIControlled;
bool roamer; bool roamer;

View File

@ -743,6 +743,10 @@ void Client::AI_Process()
if(RuleB(Combat, EnableFearPathing)){ if(RuleB(Combat, EnableFearPathing)){
if(currently_fleeing) { if(currently_fleeing) {
if (fix_z_timer_engaged.Check())
this->FixZ();
if(IsRooted()) { if(IsRooted()) {
//make sure everybody knows were not moving, for appearance sake //make sure everybody knows were not moving, for appearance sake
if(IsMoving()) if(IsMoving())
@ -782,6 +786,7 @@ void Client::AI_Process()
} }
return; return;
} }
} }
} }
@ -991,6 +996,12 @@ void Mob::AI_Process() {
if (engaged) { if (engaged) {
/* Fix Z when following during pull, not when engaged and stationary */
if (moving && fix_z_timer_engaged.Check())
if(this->GetTarget())
if(DistanceNoZ(this->GetPosition(), this->GetTarget()->GetPosition()) > 50)
this->FixZ();
if (!(m_PlayerState & static_cast<uint32>(PlayerState::Aggressive))) if (!(m_PlayerState & static_cast<uint32>(PlayerState::Aggressive)))
SendAddPlayerState(PlayerState::Aggressive); SendAddPlayerState(PlayerState::Aggressive);
// we are prevented from getting here if we are blind and don't have a target in range // we are prevented from getting here if we are blind and don't have a target in range

View File

@ -541,6 +541,9 @@ int main(int argc, char** argv) {
if (previous_loaded && !current_loaded) { if (previous_loaded && !current_loaded) {
process_timer.Stop(); process_timer.Stop();
process_timer.Start(1000, true); process_timer.Start(1000, true);
uint32 shutdown_timer = database.getZoneShutDownDelay(zone->GetZoneID(), zone->GetInstanceVersion());
zone->StartShutdownTimer(shutdown_timer);
} }
else if (!previous_loaded && current_loaded) { else if (!previous_loaded && current_loaded) {
process_timer.Stop(); process_timer.Stop();

View File

@ -2237,21 +2237,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, ui
// special ae duration spell // special ae duration spell
ae_center->CastToBeacon()->AELocationSpell(this, spell_id, resist_adjust); ae_center->CastToBeacon()->AELocationSpell(this, spell_id, resist_adjust);
} else { } else {
// regular PB AE or targeted AE spell - spell_target is null if PB // unsure if we actually need this? Need to find some spell examples
if(spell_target) // this must be an AETarget spell
{
bool cast_on_target = true;
if (spells[spell_id].targettype == ST_TargetAENoPlayersPets && spell_target->IsPetOwnerClient())
cast_on_target = false;
if (spells[spell_id].targettype == ST_AreaClientOnly && !spell_target->IsClient())
cast_on_target = false;
if (spells[spell_id].targettype == ST_AreaNPCOnly && !spell_target->IsNPC())
cast_on_target = false;
// affect the target too
if (cast_on_target)
SpellOnTarget(spell_id, spell_target, false, true, resist_adjust);
}
if(ae_center && ae_center == this && IsBeneficialSpell(spell_id)) if(ae_center && ae_center == this && IsBeneficialSpell(spell_id))
SpellOnTarget(spell_id, this); SpellOnTarget(spell_id, this);

View File

@ -513,39 +513,8 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo
m_Position.y = new_y; m_Position.y = new_y;
m_Position.z = new_z; m_Position.z = new_z;
uint8 NPCFlyMode = 0; if(fix_z_timer.Check())
this->FixZ();
if (IsNPC()) {
if (CastToNPC()->GetFlyMode() == 1 || CastToNPC()->GetFlyMode() == 2)
NPCFlyMode = 1;
}
//fix up pathing Z
if (!NPCFlyMode && checkZ && zone->HasMap() && RuleB(Map, FixPathingZWhenMoving))
{
if (!RuleB(Watermap, CheckForWaterWhenMoving) || !zone->HasWaterMap() ||
(zone->HasWaterMap() && !zone->watermap->InWater(glm::vec3(m_Position))))
{
glm::vec3 dest(m_Position.x, m_Position.y, m_Position.z);
float newz = zone->zonemap->FindBestZ(dest, nullptr) + 2.0f;
if ((newz > -2000) &&
std::abs(newz - dest.z) < RuleR(Map, FixPathingZMaxDeltaMoving)) // Sanity check.
{
if ((std::abs(x - m_Position.x) < 0.5) &&
(std::abs(y - m_Position.y) < 0.5)) {
if (std::abs(z - m_Position.z) <=
RuleR(Map, FixPathingZMaxDeltaMoving))
m_Position.z = z;
else
m_Position.z = newz + 1;
}
else
m_Position.z = newz + 1;
}
}
}
tar_ndx++; tar_ndx++;
return true; return true;
@ -651,37 +620,8 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo
m_Position.w = CalculateHeadingToTarget(x, y); m_Position.w = CalculateHeadingToTarget(x, y);
} }
uint8 NPCFlyMode = 0; if (fix_z_timer.Check())
this->FixZ();
if (IsNPC()) {
if (CastToNPC()->GetFlyMode() == 1 || CastToNPC()->GetFlyMode() == 2)
NPCFlyMode = 1;
}
//fix up pathing Z
if (!NPCFlyMode && checkZ && zone->HasMap() && RuleB(Map, FixPathingZWhenMoving)) {
if (!RuleB(Watermap, CheckForWaterWhenMoving) || !zone->HasWaterMap() ||
(zone->HasWaterMap() && !zone->watermap->InWater(glm::vec3(m_Position))))
{
glm::vec3 dest(m_Position.x, m_Position.y, m_Position.z);
float newz = zone->zonemap->FindBestZ(dest, nullptr);
if ((newz > -2000) &&
std::abs(newz - dest.z) < RuleR(Map, FixPathingZMaxDeltaMoving)) // Sanity check.
{
if (std::abs(x - m_Position.x) < 0.5 && std::abs(y - m_Position.y) < 0.5) {
if (std::abs(z - m_Position.z) <= RuleR(Map, FixPathingZMaxDeltaMoving))
m_Position.z = z;
else
m_Position.z = newz + 1;
}
else
m_Position.z = newz + 1;
}
}
}
SetMoving(true); SetMoving(true);
moved = true; moved = true;
@ -769,39 +709,8 @@ bool Mob::CalculateNewPosition(float x, float y, float z, int speed, bool checkZ
Log(Logs::Detail, Logs::AI, "Next position (%.3f, %.3f, %.3f)", m_Position.x, m_Position.y, m_Position.z); Log(Logs::Detail, Logs::AI, "Next position (%.3f, %.3f, %.3f)", m_Position.x, m_Position.y, m_Position.z);
} }
uint8 NPCFlyMode = 0; if (fix_z_timer.Check())
this->FixZ();
if (IsNPC()) {
if (CastToNPC()->GetFlyMode() == 1 || CastToNPC()->GetFlyMode() == 2)
NPCFlyMode = 1;
}
//fix up pathing Z
if (!NPCFlyMode && checkZ && zone->HasMap() && RuleB(Map, FixPathingZWhenMoving))
{
if (!RuleB(Watermap, CheckForWaterWhenMoving) || !zone->HasWaterMap() ||
(zone->HasWaterMap() && !zone->watermap->InWater(glm::vec3(m_Position))))
{
glm::vec3 dest(m_Position.x, m_Position.y, m_Position.z);
float newz = zone->zonemap->FindBestZ(dest, nullptr) + 2.0f;
Log(Logs::Detail, Logs::AI, "BestZ returned %4.3f at %4.3f, %4.3f, %4.3f", newz, m_Position.x, m_Position.y, m_Position.z);
if ((newz > -2000) &&
std::abs(newz - dest.z) < RuleR(Map, FixPathingZMaxDeltaMoving)) // Sanity check.
{
if (std::abs(x - m_Position.x) < 0.5 && std::abs(y - m_Position.y) < 0.5) {
if (std::abs(z - m_Position.z) <= RuleR(Map, FixPathingZMaxDeltaMoving))
m_Position.z = z;
else
m_Position.z = newz + 1;
}
else
m_Position.z = newz + 1;
}
}
}
//OP_MobUpdate //OP_MobUpdate
if ((old_test_vector != test_vector) || tar_ndx>20) { //send update if ((old_test_vector != test_vector) || tar_ndx>20) { //send update
@ -943,9 +852,6 @@ void Mob::SendToFixZ(float new_x, float new_y, float new_z) {
m_Position.y = new_y; m_Position.y = new_y;
m_Position.z = new_z + 0.1; m_Position.z = new_z + 0.1;
//fix up pathing Z, this shouldent be needed IF our waypoints
//are corrected instead
if (zone->HasMap() && RuleB(Map, FixPathingZOnSendTo)) if (zone->HasMap() && RuleB(Map, FixPathingZOnSendTo))
{ {
if (!RuleB(Watermap, CheckForWaterOnSendTo) || !zone->HasWaterMap() || if (!RuleB(Watermap, CheckForWaterOnSendTo) || !zone->HasWaterMap() ||
@ -955,7 +861,7 @@ void Mob::SendToFixZ(float new_x, float new_y, float new_z) {
float newz = zone->zonemap->FindBestZ(dest, nullptr); float newz = zone->zonemap->FindBestZ(dest, nullptr);
Log(Logs::Detail, Logs::AI, "BestZ returned %4.3f at %4.3f, %4.3f, %4.3f", newz, m_Position.x, m_Position.y, m_Position.z); Log(Logs::Moderate, Logs::Pathing, "BestZ returned %4.3f at %4.3f, %4.3f, %4.3f", newz, m_Position.x, m_Position.y, m_Position.z);
if ((newz > -2000) && std::abs(newz - dest.z) < RuleR(Map, FixPathingZMaxDeltaSendTo)) // Sanity check. if ((newz > -2000) && std::abs(newz - dest.z) < RuleR(Map, FixPathingZMaxDeltaSendTo)) // Sanity check.
m_Position.z = newz + 1; m_Position.z = newz + 1;
@ -963,6 +869,39 @@ void Mob::SendToFixZ(float new_x, float new_y, float new_z) {
} }
} }
void Mob::FixZ() {
BenchTimer timer;
timer.reset();
if (zone->HasMap() && RuleB(Map, FixZWhenMoving) && (flymode != 1 && flymode != 2))
{
if (!RuleB(Watermap, CheckForWaterWhenMoving) || !zone->HasWaterMap() ||
(zone->HasWaterMap() && !zone->watermap->InWater(glm::vec3(m_Position))))
{
glm::vec3 dest(m_Position.x, m_Position.y, m_Position.z);
float new_z = zone->zonemap->FindBestZ(dest, nullptr);
auto duration = timer.elapsed();
Log(
Logs::Moderate,
Logs::Pathing,
"Mob::FixZ() (%s) returned %4.3f at %4.3f, %4.3f, %4.3f - Took %lf",
this->GetCleanName(),
new_z,
m_Position.x,
m_Position.y,
m_Position.z,
duration
);
if ((new_z > -2000) && std::abs(new_z - dest.z) < RuleR(Map, FixPathingZMaxDeltaMoving))
m_Position.z = new_z + 1;
}
}
}
int ZoneDatabase::GetHighestGrid(uint32 zoneid) { int ZoneDatabase::GetHighestGrid(uint32 zoneid) {
std::string query = StringFormat("SELECT COALESCE(MAX(id), 0) FROM grid WHERE zoneid = %i", zoneid); std::string query = StringFormat("SELECT COALESCE(MAX(id), 0) FROM grid WHERE zoneid = %i", zoneid);

View File

@ -1414,11 +1414,11 @@ bool Zone::HasWeather()
void Zone::StartShutdownTimer(uint32 set_time) { void Zone::StartShutdownTimer(uint32 set_time) {
if (set_time > autoshutdown_timer.GetRemainingTime()) { if (set_time > autoshutdown_timer.GetRemainingTime()) {
if (set_time == (RuleI(Zone, AutoShutdownDelay))) if (set_time == (RuleI(Zone, AutoShutdownDelay))) {
{
set_time = database.getZoneShutDownDelay(GetZoneID(), GetInstanceVersion()); set_time = database.getZoneShutDownDelay(GetZoneID(), GetInstanceVersion());
} }
autoshutdown_timer.Start(set_time, false); autoshutdown_timer.SetTimer(set_time);
Log(Logs::General, Logs::Zone_Server, "Zone::StartShutdownTimer set to %u", set_time);
} }
} }