mirror of
https://github.com/EQEmu/Server.git
synced 2026-04-16 01:22:25 +00:00
Merge branch 'master' of github.com:EQEmu/Server
This commit is contained in:
commit
1110b284d8
@ -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).
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
2
utils/sql/git/required/2017_06_24_rule_values_expand.sql
Normal file
2
utils/sql/git/required/2017_06_24_rule_values_expand.sql
Normal 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`;
|
||||||
@ -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;
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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);
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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();
|
||||||
|
|||||||
@ -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);
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user