1
0

Fix leashing, leading, rubberbanding mobs. Work in progress for size mod.

Fix #18 Leashing, leading, rubberbanding issues with spawns resolved
Issue #17 Work in Progress, size mod stat support in the works, setting temporary_scale in info struct seems to modify size, the pos_size values in the position struct are not for KoS and older clients.
AddSpellBonus was translating values from float to sint32 early, now we take bonus values into player add bonus so that float values will be honored, as well as sint32.  This applies to uncontested parry, block, dodge, riposte and the size mod.
This commit is contained in:
Emagi 2025-05-30 21:51:53 -04:00
parent 97d1393627
commit b937444425
8 changed files with 65 additions and 24 deletions

View File

@ -1,6 +1,6 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
Copyright (C) 2005 - 2025 EQ2EMulator Development Team (http://www.eq2emu.com formerly http://www.eq2emulator.net)
This file is part of EQ2Emulator.
@ -290,6 +290,7 @@ void Entity::MapInfoStruct()
get_float_funcs["recovery_speed"] = l::bind(&InfoStruct::get_recovery_speed, &info_struct);
get_float_funcs["spell_reuse_speed"] = l::bind(&InfoStruct::get_spell_reuse_speed, &info_struct);
get_float_funcs["spell_multi_attack"] = l::bind(&InfoStruct::get_spell_multi_attack, &info_struct);
get_float_funcs["size_mod"] = l::bind(&InfoStruct::get_size_mod, &info_struct);
get_float_funcs["dps"] = l::bind(&InfoStruct::get_dps, &info_struct);
get_float_funcs["dps_multiplier"] = l::bind(&InfoStruct::get_dps_multiplier, &info_struct);
get_float_funcs["attackspeed"] = l::bind(&InfoStruct::get_attackspeed, &info_struct);
@ -498,6 +499,7 @@ void Entity::MapInfoStruct()
set_float_funcs["recovery_speed"] = l::bind(&InfoStruct::set_recovery_speed, &info_struct, l::_1);
set_float_funcs["spell_reuse_speed"] = l::bind(&InfoStruct::set_spell_reuse_speed, &info_struct, l::_1);
set_float_funcs["spell_multi_attack"] = l::bind(&InfoStruct::set_spell_multi_attack, &info_struct, l::_1);
set_float_funcs["size_mod"] = l::bind(&InfoStruct::set_size_mod, &info_struct, l::_1);
set_float_funcs["dps"] = l::bind(&InfoStruct::set_dps, &info_struct, l::_1);
set_float_funcs["dps_multiplier"] = l::bind(&InfoStruct::set_dps_multiplier, &info_struct, l::_1);
set_float_funcs["attackspeed"] = l::bind(&InfoStruct::set_attackspeed, &info_struct, l::_1);
@ -1458,6 +1460,9 @@ void Entity::CalculateBonuses(){
info->set_recovery_speed(0);
info->set_spell_reuse_speed(0);
info->set_spell_multi_attack(0);
float previous_size_mod = info->get_size_mod();
info->set_size_mod(0.0f);
info->set_dps(0);
info->set_dps_multiplier(0);
info->set_haste(0);
@ -1543,6 +1548,7 @@ void Entity::CalculateBonuses(){
info->add_recovery_speed(values->abilityrecoveryspeed);
info->add_spell_reuse_speed(values->spellreusespeed);
info->add_spell_multi_attack(values->spellmultiattackchance);
info->add_size_mod(values->size_mod);
info->add_dps(values->dps);
info->add_dps_multiplier(CalculateDPSMultiplier());
info->add_haste(values->attackspeed);
@ -1653,6 +1659,12 @@ void Entity::CalculateBonuses(){
UpdateWeapons();
if(previous_size_mod != info->get_size_mod()) {
info_changed = true;
changed = true;
size_changed = true;
AddChangedZoneSpawn();
}
safe_delete(values);
}

View File

@ -1,6 +1,6 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
Copyright (C) 2005 - 2025 EQ2EMulator Development Team (http://www.eq2emu.com formerly http://www.eq2emulator.net)
This file is part of EQ2Emulator.
@ -43,7 +43,7 @@ struct BonusValues{
int32 spell_id;
int8 tier;
int16 type;
sint32 value;
float value;
int64 class_req;
vector<int16> race_req;
vector<int16> faction_req;
@ -636,6 +636,7 @@ struct InfoStruct{
float get_recovery_speed() { std::lock_guard<std::mutex> lk(classMutex); return recovery_speed_; }
float get_spell_reuse_speed() { std::lock_guard<std::mutex> lk(classMutex); return spell_reuse_speed_; }
float get_spell_multi_attack() { std::lock_guard<std::mutex> lk(classMutex); return spell_multi_attack_; }
float get_size_mod() { std::lock_guard<std::mutex> lk(classMutex); return size_mod_; }
float get_dps() { std::lock_guard<std::mutex> lk(classMutex); return dps_; }
float get_dps_multiplier() { std::lock_guard<std::mutex> lk(classMutex); return dps_multiplier_; }
float get_attackspeed() { std::lock_guard<std::mutex> lk(classMutex); return attackspeed_; }
@ -915,6 +916,7 @@ struct InfoStruct{
void set_recovery_speed(float value) { std::lock_guard<std::mutex> lk(classMutex); recovery_speed_ = value; }
void set_spell_reuse_speed(float value) { std::lock_guard<std::mutex> lk(classMutex); spell_reuse_speed_ = value; }
void set_spell_multi_attack(float value) { std::lock_guard<std::mutex> lk(classMutex); spell_multi_attack_ = value; }
void set_size_mod(float value) { std::lock_guard<std::mutex> lk(classMutex); size_mod_ = value; }
void set_dps(float value) { std::lock_guard<std::mutex> lk(classMutex); dps_ = value; }
void set_dps_multiplier(float value) { std::lock_guard<std::mutex> lk(classMutex); dps_multiplier_ = value; }
void set_attackspeed(float value) { std::lock_guard<std::mutex> lk(classMutex); attackspeed_ = value; }
@ -946,6 +948,7 @@ struct InfoStruct{
void add_recovery_speed(float value) { std::lock_guard<std::mutex> lk(classMutex); recovery_speed_ += value; }
void add_spell_reuse_speed(float value) { std::lock_guard<std::mutex> lk(classMutex); spell_reuse_speed_ += value; }
void add_spell_multi_attack(float value) { std::lock_guard<std::mutex> lk(classMutex); spell_multi_attack_ += value; }
void add_size_mod(float value) { std::lock_guard<std::mutex> lk(classMutex); size_mod_ += value; }
void add_dps(float value) { std::lock_guard<std::mutex> lk(classMutex); if(dps_ + value < 0.0f) dps_ = 0.0f; else dps_ += value; }
void add_dps_multiplier(float value) { std::lock_guard<std::mutex> lk(classMutex); if(dps_multiplier_ + value < 0.0f) dps_multiplier_ = 0.0f; else dps_multiplier_ += value; }
void add_attackspeed(float value) { std::lock_guard<std::mutex> lk(classMutex); if(attackspeed_ + value < 0.0f) attackspeed_ = 0.0f; else attackspeed_ += value; }
@ -1187,6 +1190,7 @@ private:
float recovery_speed_;
float spell_reuse_speed_;
float spell_multi_attack_;
float size_mod_;
float dps_;
float dps_multiplier_;
float attackspeed_;

View File

@ -1,6 +1,6 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
Copyright (C) 2005 - 2025 EQ2EMulator Development Team (http://www.eq2emu.com formerly http://www.eq2emulator.net)
This file is part of EQ2Emulator.
@ -692,6 +692,7 @@ struct ItemStatsValues{
float uncontested_block;
float uncontested_dodge;
float uncontested_riposte;
float size_mod;
};

View File

@ -1,6 +1,6 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
Copyright (C) 2005 - 2025 EQ2EMulator Development Team (http://www.eq2emu.com formerly http://www.eq2emulator.net)
This file is part of EQ2Emulator.
@ -80,6 +80,7 @@ Spawn::Spawn(){
position_changed = false;
send_spawn_changes = true;
info_changed = false;
size_changed = false;
appearance.pos.Speed1 = 0;
last_attacker = 0;
faction_id = 0;
@ -2193,24 +2194,21 @@ void Spawn::InitializePosPacketData(Player* player, PacketStruct* packet, bool b
packet->setDataByName("pos_heading2", appearance.pos.Dir2);
}
if (size == 0)
size = 32;
if (version <= 910) {
packet->setDataByName("pos_collision_radius", appearance.pos.collision_radius > 0 ? appearance.pos.collision_radius : 32);
packet->setDataByName("pos_size", size > 0 ? size : 32);
packet->setDataByName("pos_size_multiplier", 32); //32 is normal
}
else {
if (size == 0)
size = 32;
packet->setDataByName("pos_collision_radius", appearance.pos.collision_radius > 0 ? appearance.pos.collision_radius : 32);
packet->setDataByName("pos_size", 1.0f);
if (!IsPlayer())
if(!IsPlayer())
packet->setDataByName("pos_size", size > 0 ? (((float)size) / 32.0f) : 1.0f); // float not an integer
else
packet->setDataByName("pos_size", 1.0f);
// please do not remove! This makes it so NPCs for example do not resize large/small when you are in combat with them!
packet->setDataByName("pos_size_ratio", 1.0f);
}
@ -2490,6 +2488,11 @@ void Spawn::InitializeInfoPacketData(Player* spawn, PacketStruct* packet) {
if (GetMerchantID() > 0)
packet->setDataByName("merchant", 1);
if(IsEntity() && ((Entity*)this)->GetInfoStruct()->get_size_mod() != 0.0f) {
float mod = ((Entity*)this)->GetInfoStruct()->get_size_mod(); // e.g., -0.25 or +0.25
//packet->setDataByName("temporary_scale", mod); //TODO: Understand what these mod values should be, anything we send makes the client shrink to nothing
}
packet->setDataByName("effective_level", IsEntity() && ((Entity*)this)->GetInfoStruct()->get_effective_level() != 0 ? (int8)((Entity*)this)->GetInfoStruct()->get_effective_level() : (int8)GetLevel());
packet->setDataByName("level", (int8)GetLevel());
packet->setDataByName("unknown4", (int8)GetLevel());
@ -3187,8 +3190,15 @@ void Spawn::ProcessMovement(bool isSpawnListLocked){
float distance = GetDistance(followTarget, loc->x, loc->y, loc->z);
if ( (!EngagedInCombat() && m_followDistance > 0 && distance > m_followDistance) ||
( EngagedInCombat() && distance > rule_manager.GetZoneRule(GetZoneID(), R_Combat, MaxCombatRange)->GetFloat())) {
MoveToLocation(followTarget, rule_manager.GetZoneRule(GetZoneID(), R_Combat, MaxCombatRange)->GetFloat(), true, loc->mapped);
CalculateRunningLocation();
float self_distance = GetDistance(this, loc->x, loc->y, loc->z);
if(dist < distance || dist < self_distance) {
ClearRunningLocations();
CalculateRunningLocation(true);
}
else {
MoveToLocation(followTarget, rule_manager.GetZoneRule(GetZoneID(), R_Combat, MaxCombatRange)->GetFloat(), true, loc->mapped);
CalculateRunningLocation();
}
}
}
else {

View File

@ -1192,6 +1192,7 @@ public:
std::atomic<bool> info_changed;
std::atomic<bool> vis_changed;
std::atomic<bool> is_running;
std::atomic<bool> size_changed;
int16 size;
int32 faction_id;
int8 oversized_packet; //0xff

View File

@ -1,6 +1,6 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
Copyright (C) 2005 - 2025 EQ2EMulator Development Team (http://www.eq2emu.com formerly http://www.eq2emulator.net)
This file is part of EQ2Emulator.
@ -2246,16 +2246,24 @@ bool World::RejoinGroup(Client* client, int32 group_id){
}
void World::AddBonuses(Item* item, ItemStatsValues* values, int16 type, sint32 value, Entity* entity){
void World::AddBonuses(Item* item, ItemStatsValues* values, int16 type, float value, Entity* entity){
if(values){
if(item && entity && entity->IsPlayer())
{
int32 effective_level = entity->GetInfoStructUInt("effective_level");
if(effective_level && effective_level < entity->GetLevel() && item->details.recommended_level > effective_level)
{
int32 diff = item->details.recommended_level - effective_level;
float tmpValue = (float)value;
value = (sint32)(float)(tmpValue / (1.0f + ((float)diff * .05f)));
switch(type) {
case ITEM_STAT_SIZEMOD:
case ITEM_STAT_CONCENTRATION:
break;
default: {
int32 effective_level = entity->GetInfoStructUInt("effective_level");
if(effective_level && effective_level < entity->GetLevel() && item->details.recommended_level > effective_level)
{
int32 diff = item->details.recommended_level - effective_level;
float tmpValue = (float)value;
value = (sint32)(float)(tmpValue / (1.0f + ((float)diff * .05f)));
}
break;
}
}
}
switch(type){
@ -2383,6 +2391,10 @@ void World::AddBonuses(Item* item, ItemStatsValues* values, int16 type, sint32 v
values->spellmultiattackchance += value;
break;
}
case ITEM_STAT_SIZEMOD:{
values->size_mod += value;
break;
}
case ITEM_STAT_DPS:{
values->dps += value;
break;

View File

@ -635,7 +635,7 @@ public:
bool RejoinGroup(Client* client, int32 group_id);
//bool MakeLeader(Client* leader, string new_leader);
void AddBonuses(Item* item, ItemStatsValues* values, int16 type, sint32 value, Entity* entity);
void AddBonuses(Item* item, ItemStatsValues* values, int16 type, float value, Entity* entity);
int32 CreateGuild(const char* guild_name, Client* leader = 0, int32 group_id = 0);
void SaveGuilds();
void PickRandomLottoDigits(int32* digits);

View File

@ -2317,6 +2317,7 @@ void ZoneServer::SendSpawnChanges(){
spawn->position_changed = false;
spawn->vis_changed = false;
spawn->info_changed = false;
spawn->size_changed = false;
}
MSpawnList.releasereadlock(__FUNCTION__, __LINE__);
}