diff --git a/source/WorldServer/Entity.cpp b/source/WorldServer/Entity.cpp index 2211a8f..6cde2f0 100644 --- a/source/WorldServer/Entity.cpp +++ b/source/WorldServer/Entity.cpp @@ -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); } diff --git a/source/WorldServer/Entity.h b/source/WorldServer/Entity.h index 8a993cf..d66552c 100644 --- a/source/WorldServer/Entity.h +++ b/source/WorldServer/Entity.h @@ -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 race_req; vector faction_req; @@ -636,6 +636,7 @@ struct InfoStruct{ float get_recovery_speed() { std::lock_guard lk(classMutex); return recovery_speed_; } float get_spell_reuse_speed() { std::lock_guard lk(classMutex); return spell_reuse_speed_; } float get_spell_multi_attack() { std::lock_guard lk(classMutex); return spell_multi_attack_; } + float get_size_mod() { std::lock_guard lk(classMutex); return size_mod_; } float get_dps() { std::lock_guard lk(classMutex); return dps_; } float get_dps_multiplier() { std::lock_guard lk(classMutex); return dps_multiplier_; } float get_attackspeed() { std::lock_guard lk(classMutex); return attackspeed_; } @@ -915,6 +916,7 @@ struct InfoStruct{ void set_recovery_speed(float value) { std::lock_guard lk(classMutex); recovery_speed_ = value; } void set_spell_reuse_speed(float value) { std::lock_guard lk(classMutex); spell_reuse_speed_ = value; } void set_spell_multi_attack(float value) { std::lock_guard lk(classMutex); spell_multi_attack_ = value; } + void set_size_mod(float value) { std::lock_guard lk(classMutex); size_mod_ = value; } void set_dps(float value) { std::lock_guard lk(classMutex); dps_ = value; } void set_dps_multiplier(float value) { std::lock_guard lk(classMutex); dps_multiplier_ = value; } void set_attackspeed(float value) { std::lock_guard lk(classMutex); attackspeed_ = value; } @@ -946,6 +948,7 @@ struct InfoStruct{ void add_recovery_speed(float value) { std::lock_guard lk(classMutex); recovery_speed_ += value; } void add_spell_reuse_speed(float value) { std::lock_guard lk(classMutex); spell_reuse_speed_ += value; } void add_spell_multi_attack(float value) { std::lock_guard lk(classMutex); spell_multi_attack_ += value; } + void add_size_mod(float value) { std::lock_guard lk(classMutex); size_mod_ += value; } void add_dps(float value) { std::lock_guard lk(classMutex); if(dps_ + value < 0.0f) dps_ = 0.0f; else dps_ += value; } void add_dps_multiplier(float value) { std::lock_guard lk(classMutex); if(dps_multiplier_ + value < 0.0f) dps_multiplier_ = 0.0f; else dps_multiplier_ += value; } void add_attackspeed(float value) { std::lock_guard 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_; diff --git a/source/WorldServer/Items/Items.h b/source/WorldServer/Items/Items.h index 38c0e8d..25c021c 100644 --- a/source/WorldServer/Items/Items.h +++ b/source/WorldServer/Items/Items.h @@ -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; }; diff --git a/source/WorldServer/Spawn.cpp b/source/WorldServer/Spawn.cpp index de6a0e1..8556681 100644 --- a/source/WorldServer/Spawn.cpp +++ b/source/WorldServer/Spawn.cpp @@ -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 { diff --git a/source/WorldServer/Spawn.h b/source/WorldServer/Spawn.h index bb4b526..e3e6a6a 100644 --- a/source/WorldServer/Spawn.h +++ b/source/WorldServer/Spawn.h @@ -1192,6 +1192,7 @@ public: std::atomic info_changed; std::atomic vis_changed; std::atomic is_running; + std::atomic size_changed; int16 size; int32 faction_id; int8 oversized_packet; //0xff diff --git a/source/WorldServer/World.cpp b/source/WorldServer/World.cpp index f295777..63e7c92 100644 --- a/source/WorldServer/World.cpp +++ b/source/WorldServer/World.cpp @@ -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; diff --git a/source/WorldServer/World.h b/source/WorldServer/World.h index 039c83d..400431a 100644 --- a/source/WorldServer/World.h +++ b/source/WorldServer/World.h @@ -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); diff --git a/source/WorldServer/zoneserver.cpp b/source/WorldServer/zoneserver.cpp index a846120..50f2604 100644 --- a/source/WorldServer/zoneserver.cpp +++ b/source/WorldServer/zoneserver.cpp @@ -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__); }