mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-24 10:02:28 +00:00
Compare commits
10 Commits
v23.8.0
...
build-analyze
| Author | SHA1 | Date | |
|---|---|---|---|
| 588de15382 | |||
| aeb13e8fd3 | |||
| 98f824b0f5 | |||
| 605e23e8d0 | |||
| fc470d5f83 | |||
| 585ed3bd25 | |||
| 2eb291a461 | |||
| a1421af214 | |||
| 13aad6229f | |||
| 76d46ceaf0 |
+33
-1
@@ -30,6 +30,11 @@ steps:
|
||||
- name: cache
|
||||
path: /home/eqemu/.ccache/
|
||||
|
||||
trigger:
|
||||
branch:
|
||||
exclude:
|
||||
- build-analyze
|
||||
|
||||
---
|
||||
|
||||
kind: pipeline
|
||||
@@ -57,6 +62,11 @@ steps:
|
||||
commands:
|
||||
- .\utils\scripts\build\windows-build.ps1
|
||||
|
||||
trigger:
|
||||
branch:
|
||||
exclude:
|
||||
- build-analyze
|
||||
|
||||
---
|
||||
|
||||
kind: pipeline
|
||||
@@ -87,7 +97,10 @@ steps:
|
||||
|
||||
trigger:
|
||||
branch:
|
||||
- master
|
||||
include:
|
||||
- master
|
||||
exclude:
|
||||
- build-analyze
|
||||
event:
|
||||
- push
|
||||
|
||||
@@ -95,4 +108,23 @@ depends_on:
|
||||
- Build Windows
|
||||
- Build Linux
|
||||
|
||||
---
|
||||
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: Build Analyze
|
||||
|
||||
steps:
|
||||
- name: Build Linux X64
|
||||
image: akkadius/eqemu-server:v16
|
||||
environment:
|
||||
GITHUB_TOKEN:
|
||||
from_secret: GH_RELEASE_GITHUB_API_TOKEN
|
||||
commands:
|
||||
- ./utils/scripts/build/linux-build-analyze.sh
|
||||
|
||||
trigger:
|
||||
branch:
|
||||
- build-analyze
|
||||
event:
|
||||
- push
|
||||
@@ -1,3 +1,18 @@
|
||||
## [23.8.1] 6/28/2025
|
||||
|
||||
### Crash Fix
|
||||
|
||||
* Fix Possible Crashes with Raid Methods ([#4955](https://github.com/EQEmu/Server/pull/4955)) @Kinglykrab 2025-06-26
|
||||
|
||||
### Databuckets
|
||||
|
||||
* Revert Caching Changes of #4917 ([#4957](https://github.com/EQEmu/Server/pull/4957)) @Akkadius 2025-06-28
|
||||
|
||||
### Fixes
|
||||
|
||||
* Fix FindCharacter Using content_db ([#4956](https://github.com/EQEmu/Server/pull/4956)) @Kinglykrab 2025-06-26
|
||||
* Fix Hero Forge on Character Select ([#4954](https://github.com/EQEmu/Server/pull/4954)) @Kinglykrab 2025-06-26
|
||||
|
||||
## [23.8.0] 6/25/2025
|
||||
|
||||
### API
|
||||
|
||||
@@ -363,6 +363,8 @@ MESSAGE(STATUS "**************************************************")
|
||||
#setup server libs and headers
|
||||
SET(SERVER_LIBS common ${DATABASE_LIBRARY_LIBS} ${ZLIB_LIBRARY_LIBS} ${Boost_LIBRARIES} uv_a fmt RecastNavigation::Detour)
|
||||
|
||||
set(FMT_HEADER_ONLY OFF)
|
||||
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${DATABASE_LIBRARY_INCLUDE}")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${ZLIB_LIBRARY_INCLUDE}")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${Boost_INCLUDE_DIRS}")
|
||||
|
||||
@@ -841,7 +841,7 @@ IF (UNIX)
|
||||
SET_SOURCE_FILES_PROPERTIES("patches/sod.cpp" "patches/sof.cpp" "patches/rof.cpp" "patches/rof2.cpp" "patches/uf.cpp" PROPERTIES COMPILE_FLAGS -O0)
|
||||
ENDIF (UNIX)
|
||||
|
||||
IF (WIN32 AND EQEMU_BUILD_PCH)
|
||||
IF (EQEMU_BUILD_PCH)
|
||||
TARGET_PRECOMPILE_HEADERS(common PRIVATE pch/std-pch.h)
|
||||
ENDIF ()
|
||||
|
||||
|
||||
+8
-82
@@ -19,37 +19,6 @@ extern WorldDatabase database;
|
||||
#error "You must define either ZONE or WORLD"
|
||||
#endif
|
||||
|
||||
// Key: compound cache key (e.g., account_id|character_id|zone_id|instance_id|top_key|full_key)
|
||||
// Value: resolved DataBuckets with extracted nested value
|
||||
static std::unordered_map<std::string, DataBucketsRepository::DataBuckets> g_nested_bucket_cache;
|
||||
|
||||
static std::string MakeNestedCacheKey(const DataBucketKey &k, const std::string &full_key) {
|
||||
return fmt::format(
|
||||
"account_id:{}|character_id:{}|npc_id:{}|bot_id:{}|zone_id:{}|instance_id:{}|top_key:{}|full_key:{}",
|
||||
k.account_id, k.character_id, k.npc_id, k.bot_id, k.zone_id, k.instance_id,
|
||||
Strings::Split(full_key, NESTED_KEY_DELIMITER).front(),
|
||||
full_key
|
||||
);
|
||||
}
|
||||
|
||||
static std::string MakeNestedCacheKeyPrefix(const DataBucketKey &k, const std::string &top_key) {
|
||||
return fmt::format(
|
||||
"account_id:{}|character_id:{}|npc_id:{}|bot_id:{}|zone_id:{}|instance_id:{}|top_key:{}|",
|
||||
k.account_id, k.character_id, k.npc_id, k.bot_id, k.zone_id, k.instance_id, top_key
|
||||
);
|
||||
}
|
||||
|
||||
static void InvalidateNestedCacheForKey(const DataBucketKey &k, const std::string &top_key) {
|
||||
std::string prefix = MakeNestedCacheKeyPrefix(k, top_key);
|
||||
for (auto it = g_nested_bucket_cache.begin(); it != g_nested_bucket_cache.end(); ) {
|
||||
if (it->first.find(prefix) == 0) {
|
||||
it = g_nested_bucket_cache.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DataBucket::SetData(const std::string &bucket_key, const std::string &bucket_value, std::string expires_time)
|
||||
{
|
||||
auto k = DataBucketKey{
|
||||
@@ -167,15 +136,6 @@ void DataBucket::SetData(const DataBucketKey &k_)
|
||||
// Serialize JSON back to string
|
||||
b.value = json_value.dump();
|
||||
b.key_ = top_key; // Use the top-level key
|
||||
|
||||
if (CanCache(k_)) {
|
||||
InvalidateNestedCacheForKey(k_, top_key);
|
||||
std::string nested_cache_key = MakeNestedCacheKey(k_, k_.key);
|
||||
auto extracted = ExtractNestedValue(b, k_.key);
|
||||
if (extracted.id > 0) {
|
||||
g_nested_bucket_cache[nested_cache_key] = extracted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bucket_id) {
|
||||
@@ -291,27 +251,12 @@ DataBucketsRepository::DataBuckets DataBucket::GetData(const DataBucketKey &k_,
|
||||
LogDataBuckets("Returning key [{}] value [{}] from cache", e.key_, e.value);
|
||||
|
||||
if (is_nested_key && !k_.key.empty()) {
|
||||
std::string nested_cache_key = MakeNestedCacheKey(k_, k.key);
|
||||
|
||||
auto it = g_nested_bucket_cache.find(nested_cache_key);
|
||||
if (it != g_nested_bucket_cache.end()) {
|
||||
LogDataBucketsDetail("Nested cache hit for key [{}]", nested_cache_key);
|
||||
return it->second;
|
||||
}
|
||||
|
||||
auto extracted = ExtractNestedValue(e, k_.key);
|
||||
if (extracted.id > 0) {
|
||||
g_nested_bucket_cache[nested_cache_key] = extracted;
|
||||
}
|
||||
return extracted;
|
||||
return ExtractNestedValue(e, k_.key);
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
// if we can cache its assumed we didn't load this into the cache so we should not return a miss
|
||||
return DataBucketsRepository::NewEntity(); // Not found in cache
|
||||
}
|
||||
|
||||
// Fetch the value from the database
|
||||
@@ -370,42 +315,23 @@ DataBucketsRepository::DataBuckets DataBucket::GetData(const DataBucketKey &k_,
|
||||
}
|
||||
|
||||
// Add the value to the cache if it doesn't exist
|
||||
// If cacheable and not found in cache, short-circuit and assume it doesn't exist
|
||||
if (can_cache) {
|
||||
bool found_in_cache = false;
|
||||
bool has_cache = false;
|
||||
for (const auto &e : g_data_bucket_cache) {
|
||||
if (CheckBucketMatch(e, k)) {
|
||||
found_in_cache = true;
|
||||
if (e.id == bucket.id) {
|
||||
has_cache = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_in_cache) {
|
||||
LogDataBuckets("Cache miss for key [{}] - skipping DB due to CanCache", k.key);
|
||||
return DataBucketsRepository::NewEntity();
|
||||
if (!has_cache) {
|
||||
g_data_bucket_cache.emplace_back(bucket);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle nested key extraction
|
||||
if (is_nested_key && !k_.key.empty()) {
|
||||
if (CanCache(k_)) {
|
||||
std::string nested_cache_key = MakeNestedCacheKey(k_, k.key);
|
||||
|
||||
auto it = g_nested_bucket_cache.find(nested_cache_key);
|
||||
if (it != g_nested_bucket_cache.end()) {
|
||||
LogDataBucketsDetail("Nested cache hit for key [{}]", nested_cache_key);
|
||||
return it->second;
|
||||
}
|
||||
|
||||
auto extracted = ExtractNestedValue(bucket, k_.key);
|
||||
if (extracted.id > 0) {
|
||||
g_nested_bucket_cache[nested_cache_key] = extracted;
|
||||
}
|
||||
return extracted;
|
||||
} else {
|
||||
// Not cacheable, just extract and return
|
||||
return ExtractNestedValue(bucket, k_.key);
|
||||
}
|
||||
return ExtractNestedValue(bucket, k_.key);
|
||||
}
|
||||
|
||||
return bucket;
|
||||
@@ -917,4 +843,4 @@ bool DataBucket::CanCache(const DataBucketKey &key)
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -574,7 +574,7 @@ EQ::ItemInstance* EQ::ItemInstance::GetOrnamentationAugment() const
|
||||
uint32 EQ::ItemInstance::GetOrnamentHeroModel(int32 material_slot) const
|
||||
{
|
||||
// Not a Hero Forge item.
|
||||
if (m_ornament_hero_model == 0 || material_slot < 0) {
|
||||
if (m_ornament_hero_model == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+7
-27
@@ -1,34 +1,14 @@
|
||||
// types
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <cctype>
|
||||
#include <sstream>
|
||||
#pragma once
|
||||
|
||||
// containers
|
||||
#include <iterator>
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
// Lightweight, widely used
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
// utilities
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <tuple>
|
||||
#include <fstream>
|
||||
#include <cstdio>
|
||||
#include <limits>
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
|
||||
// fmt
|
||||
#include <fmt/format.h>
|
||||
|
||||
// lua
|
||||
#include "lua.hpp"
|
||||
#include <luabind/luabind.hpp>
|
||||
#include <luabind/object.hpp>
|
||||
|
||||
@@ -358,6 +358,7 @@ bool RequiresStackCheck(uint16 spell_type) {
|
||||
case BotSpellTypes::CompleteHeal:
|
||||
case BotSpellTypes::PetCompleteHeals:
|
||||
case BotSpellTypes::GroupCompleteHeals:
|
||||
case BotSpellTypes::Resurrect:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
// Build variables
|
||||
// these get injected during the build pipeline
|
||||
#define CURRENT_VERSION "23.8.0-dev" // always append -dev to the current version for custom-builds
|
||||
#define CURRENT_VERSION "23.8.1-dev" // always append -dev to the current version for custom-builds
|
||||
#define LOGIN_VERSION "0.8.0"
|
||||
#define COMPILE_DATE __DATE__
|
||||
#define COMPILE_TIME __TIME__
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "eqemu-server",
|
||||
"version": "23.8.0",
|
||||
"version": "23.8.1",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/EQEmu/Server.git"
|
||||
|
||||
Executable
+44
@@ -0,0 +1,44 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -ex
|
||||
|
||||
sudo chown eqemu:eqemu /drone/src/ * -R
|
||||
|
||||
# Install ClangBuildAnalyzer if missing
|
||||
if ! command -v clang-build-analyzer &> /dev/null; then
|
||||
echo "Installing latest Clang Build Analyzer..."
|
||||
LATEST_VERSION=$(curl -s https://api.github.com/repos/aras-p/ClangBuildAnalyzer/releases/latest \
|
||||
| grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
|
||||
sudo curl -sSL "https://github.com/aras-p/ClangBuildAnalyzer/releases/download/v${LATEST_VERSION}/ClangBuildAnalyzer-linux" \
|
||||
-o /usr/local/bin/clang-build-analyzer
|
||||
sudo chmod +x /usr/local/bin/clang-build-analyzer
|
||||
fi
|
||||
|
||||
git submodule init && git submodule update
|
||||
perl utils/scripts/build/tag-version.pl
|
||||
|
||||
mkdir -p build
|
||||
|
||||
clang-build-analyzer --start build/
|
||||
|
||||
cd build && \
|
||||
cmake -DEQEMU_BUILD_TESTS=ON \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DEQEMU_BUILD_LUA=ON \
|
||||
-DEQEMU_BUILD_PERL=ON \
|
||||
-DEQEMU_BUILD_LOGIN=ON \
|
||||
-DEQEMU_BUILD_STATIC=ON \
|
||||
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
||||
-DCMAKE_CXX_FLAGS:STRING="-O0 -g -Wno-everything -ftime-trace" \
|
||||
-G 'Unix Makefiles' \
|
||||
.. && \
|
||||
make -j"$(nproc)"
|
||||
|
||||
# 🧠 Generate ClangBuildAnalyzer report
|
||||
clang-build-analyzer --stop ./ /tmp/eqemu.capture
|
||||
clang-build-analyzer --analyze /tmp/eqemu.capture > report.txt
|
||||
cat report.txt
|
||||
|
||||
ldd ./bin/zone
|
||||
|
||||
cd /drone/src/
|
||||
@@ -76,7 +76,7 @@ ADD_EXECUTABLE(world ${world_sources} ${world_headers})
|
||||
|
||||
INSTALL(TARGETS world RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
|
||||
IF (WIN32 AND EQEMU_BUILD_PCH)
|
||||
IF (EQEMU_BUILD_PCH)
|
||||
TARGET_PRECOMPILE_HEADERS(world PRIVATE ../common/pch/std-pch.h)
|
||||
ENDIF ()
|
||||
|
||||
|
||||
@@ -483,6 +483,7 @@ INSTALL(TARGETS zone RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
# precompiled headers
|
||||
IF (EQEMU_BUILD_PCH)
|
||||
TARGET_PRECOMPILE_HEADERS(zone PRIVATE ../common/pch/app-pch.h)
|
||||
TARGET_PRECOMPILE_HEADERS(zone PRIVATE ../common/pch/std-pch.h)
|
||||
TARGET_PRECOMPILE_HEADERS(zone PRIVATE ./pch/pch.h)
|
||||
ENDIF()
|
||||
|
||||
|
||||
@@ -318,32 +318,32 @@ void ZoneCLI::TestDataBuckets(int argc, char** argv, argh::parser& cmd, std::str
|
||||
);
|
||||
|
||||
// Cold cache test — should return ""
|
||||
std::string cold_value = client->GetBucket(scoped_key);
|
||||
RunTest("Cold Cache Scoped Key Returns Empty (Due to Skip DB)", "", cold_value);
|
||||
|
||||
// ✅ Reload cache
|
||||
client->LoadDataBucketsCache();
|
||||
|
||||
// Cache should now return the value
|
||||
std::string hot_value = client->GetBucket(scoped_key);
|
||||
RunTest("Post-BulkLoad Scoped Key Returns Value", "cached_value", hot_value);
|
||||
|
||||
// Also test nested key after preload
|
||||
client->DeleteBucket("ac_nested.test");
|
||||
client->SetBucket("ac_nested.test", "nested_val");
|
||||
|
||||
// Clear cache, then preload
|
||||
DataBucket::ClearCache();
|
||||
client->LoadDataBucketsCache();
|
||||
|
||||
std::string nested_value = client->GetBucket("ac_nested.test");
|
||||
RunTest("Post-BulkLoad Nested Scoped Key Returns Value", "nested_val", nested_value);
|
||||
|
||||
// Remove and check that cache misses properly again
|
||||
client->DeleteBucket("ac_nested.test");
|
||||
DataBucket::ClearCache();
|
||||
std::string post_delete_check = client->GetBucket("ac_nested.test");
|
||||
RunTest("Post-Delete Nested Scoped Key Returns Empty", "", post_delete_check);
|
||||
// std::string cold_value = client->GetBucket(scoped_key);
|
||||
// RunTest("Cold Cache Scoped Key Returns Empty (Due to Skip DB)", "", cold_value);
|
||||
//
|
||||
// // ✅ Reload cache
|
||||
// client->LoadDataBucketsCache();
|
||||
//
|
||||
// // Cache should now return the value
|
||||
// std::string hot_value = client->GetBucket(scoped_key);
|
||||
// RunTest("Post-BulkLoad Scoped Key Returns Value", "cached_value", hot_value);
|
||||
//
|
||||
// // Also test nested key after preload
|
||||
// client->DeleteBucket("ac_nested.test");
|
||||
// client->SetBucket("ac_nested.test", "nested_val");
|
||||
//
|
||||
// // Clear cache, then preload
|
||||
// DataBucket::ClearCache();
|
||||
// client->LoadDataBucketsCache();
|
||||
//
|
||||
// std::string nested_value = client->GetBucket("ac_nested.test");
|
||||
// RunTest("Post-BulkLoad Nested Scoped Key Returns Value", "nested_val", nested_value);
|
||||
//
|
||||
// // Remove and check that cache misses properly again
|
||||
// client->DeleteBucket("ac_nested.test");
|
||||
// DataBucket::ClearCache();
|
||||
// std::string post_delete_check = client->GetBucket("ac_nested.test");
|
||||
// RunTest("Post-Delete Nested Scoped Key Returns Empty", "", post_delete_check);
|
||||
|
||||
|
||||
std::cout << "\n===========================================\n";
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
void FindCharacter(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (sep->IsNumber(2)) {
|
||||
const auto character_id = Strings::ToUnsignedInt(sep->arg[2]);
|
||||
const uint32 character_id = Strings::ToUnsignedInt(sep->arg[2]);
|
||||
|
||||
const auto& e = CharacterDataRepository::FindOne(content_db, character_id);
|
||||
const auto& e = CharacterDataRepository::FindOne(database, character_id);
|
||||
if (!e.id) {
|
||||
c->Message(
|
||||
Chat::White,
|
||||
@@ -31,10 +31,10 @@ void FindCharacter(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
const auto search_criteria = Strings::ToLower(sep->argplus[2]);
|
||||
const std::string& search_criteria = Strings::ToLower(sep->argplus[2]);
|
||||
|
||||
const auto& l = CharacterDataRepository::GetWhere(
|
||||
content_db,
|
||||
database,
|
||||
fmt::format(
|
||||
"LOWER(`name`) LIKE '%%{}%%' AND `name` NOT LIKE '%-deleted-%' ORDER BY `id` ASC LIMIT 50",
|
||||
search_criteria
|
||||
@@ -51,7 +51,7 @@ void FindCharacter(Client *c, const Seperator *sep)
|
||||
);
|
||||
}
|
||||
|
||||
auto found_count = 0;
|
||||
uint32 found_count = 0;
|
||||
|
||||
for (const auto& e : l) {
|
||||
c->Message(
|
||||
|
||||
+59
-49
@@ -717,7 +717,7 @@ uint32 Raid::GetTotalRaidDamage(Mob* other)
|
||||
return total;
|
||||
}
|
||||
|
||||
void Raid::HealGroup(uint32 heal_amt, Mob* caster, uint32 gid, float range)
|
||||
void Raid::HealGroup(uint32 heal_amount, Mob* caster, uint32 group_id, float range)
|
||||
{
|
||||
if (!caster) {
|
||||
return;
|
||||
@@ -728,26 +728,30 @@ void Raid::HealGroup(uint32 heal_amt, Mob* caster, uint32 gid, float range)
|
||||
}
|
||||
|
||||
float distance;
|
||||
float range2 = range*range;
|
||||
float range_squared = range * range;
|
||||
|
||||
int member_count = 0;
|
||||
|
||||
int numMem = 0;
|
||||
for (const auto& m : members) {
|
||||
if (m.member && m.group_number == gid) {
|
||||
if (m.member && m.group_number == group_id) {
|
||||
distance = DistanceSquared(caster->GetPosition(), m.member->GetPosition());
|
||||
|
||||
if (distance <= range2) {
|
||||
numMem += 1;
|
||||
if (distance <= range_squared) {
|
||||
member_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
heal_amt /= numMem;
|
||||
if (member_count > 0) {
|
||||
heal_amount /= member_count;
|
||||
}
|
||||
|
||||
for (const auto& m : members) {
|
||||
if (m.member && m.group_number == gid) {
|
||||
if (m.member && m.group_number == group_id) {
|
||||
distance = DistanceSquared(caster->GetPosition(), m.member->GetPosition());
|
||||
|
||||
if (distance <= range2) {
|
||||
m.member->SetHP(m.member->GetHP() + heal_amt);
|
||||
if (distance <= range_squared) {
|
||||
m.member->SetHP(m.member->GetHP() + heal_amount);
|
||||
m.member->SendHPUpdate();
|
||||
}
|
||||
}
|
||||
@@ -755,7 +759,7 @@ void Raid::HealGroup(uint32 heal_amt, Mob* caster, uint32 gid, float range)
|
||||
}
|
||||
|
||||
|
||||
void Raid::BalanceHP(int32 penalty, uint32 gid, float range, Mob* caster, int32 limit)
|
||||
void Raid::BalanceHP(int32 penalty, uint32 group_id, float range, Mob* caster, int32 limit)
|
||||
{
|
||||
if (!caster) {
|
||||
return;
|
||||
@@ -765,44 +769,48 @@ void Raid::BalanceHP(int32 penalty, uint32 gid, float range, Mob* caster, int32
|
||||
range = 200;
|
||||
}
|
||||
|
||||
int dmgtaken = 0, numMem = 0, dmgtaken_tmp = 0;
|
||||
int damage_taken = 0;
|
||||
int damage_taken_temporary = 0;
|
||||
int member_count = 0;
|
||||
|
||||
float distance;
|
||||
float range2 = range*range;
|
||||
float range_squared = range * range;
|
||||
|
||||
for (const auto& m : members) {
|
||||
if (m.member && m.group_number == gid) {
|
||||
if (m.member && m.group_number == group_id) {
|
||||
distance = DistanceSquared(caster->GetPosition(), m.member->GetPosition());
|
||||
|
||||
if (distance <= range2) {
|
||||
dmgtaken_tmp = m.member->GetMaxHP() - m.member->GetHP();
|
||||
if (distance <= range_squared) {
|
||||
damage_taken_temporary = m.member->GetMaxHP() - m.member->GetHP();
|
||||
|
||||
if (limit && (dmgtaken_tmp > limit)) {
|
||||
dmgtaken_tmp = limit;
|
||||
if (limit && (damage_taken_temporary > limit)) {
|
||||
damage_taken_temporary = limit;
|
||||
}
|
||||
|
||||
dmgtaken += dmgtaken_tmp;
|
||||
numMem += 1;
|
||||
damage_taken += damage_taken_temporary;
|
||||
member_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dmgtaken += dmgtaken * penalty / 100;
|
||||
dmgtaken /= numMem;
|
||||
damage_taken += damage_taken * penalty / 100;
|
||||
|
||||
if (member_count > 0) {
|
||||
damage_taken /= member_count;
|
||||
}
|
||||
|
||||
for (const auto& m : members) {
|
||||
if (m.member && m.group_number == gid) {
|
||||
if (m.member && m.group_number == group_id) {
|
||||
distance = DistanceSquared(caster->GetPosition(), m.member->GetPosition());
|
||||
|
||||
//this way the ability will never kill someone
|
||||
//but it will come darn close
|
||||
if (distance <= range2) {
|
||||
if ((m.member->GetMaxHP() - dmgtaken) < 1) {
|
||||
if (distance <= range_squared) {
|
||||
if ((m.member->GetMaxHP() - damage_taken) < 1) {
|
||||
m.member->SetHP(1);
|
||||
m.member->SendHPUpdate();
|
||||
}
|
||||
|
||||
else {
|
||||
m.member->SetHP(m.member->GetMaxHP() - dmgtaken);
|
||||
} else {
|
||||
m.member->SetHP(m.member->GetMaxHP() - damage_taken);
|
||||
m.member->SendHPUpdate();
|
||||
}
|
||||
}
|
||||
@@ -810,7 +818,7 @@ void Raid::BalanceHP(int32 penalty, uint32 gid, float range, Mob* caster, int32
|
||||
}
|
||||
}
|
||||
|
||||
void Raid::BalanceMana(int32 penalty, uint32 gid, float range, Mob* caster, int32 limit)
|
||||
void Raid::BalanceMana(int32 penalty, uint32 group_id, float range, Mob* caster, int32 limit)
|
||||
{
|
||||
if (!caster) {
|
||||
return;
|
||||
@@ -821,54 +829,56 @@ void Raid::BalanceMana(int32 penalty, uint32 gid, float range, Mob* caster, int3
|
||||
}
|
||||
|
||||
float distance;
|
||||
float range2 = range*range;
|
||||
float range_squared = range * range;
|
||||
|
||||
int manataken = 0;
|
||||
int numMem = 0;
|
||||
int manataken_tmp = 0;
|
||||
int mana_taken = 0;
|
||||
int mana_taken_temporary = 0;
|
||||
int member_count = 0;
|
||||
|
||||
for (const auto& m : members) {
|
||||
if (m.is_bot) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m.member && m.group_number == gid && m.member->GetMaxMana() > 0) {
|
||||
if (m.member && m.group_number == group_id && m.member->GetMaxMana() > 0) {
|
||||
distance = DistanceSquared(caster->GetPosition(), m.member->GetPosition());
|
||||
|
||||
if (distance <= range2) {
|
||||
manataken_tmp = m.member->GetMaxMana() - m.member->GetMana();
|
||||
if (distance <= range_squared) {
|
||||
mana_taken_temporary = m.member->GetMaxMana() - m.member->GetMana();
|
||||
|
||||
if (limit && (manataken_tmp > limit)) {
|
||||
manataken_tmp = limit;
|
||||
if (limit && (mana_taken_temporary > limit)) {
|
||||
mana_taken_temporary = limit;
|
||||
}
|
||||
|
||||
manataken += manataken_tmp;
|
||||
numMem += 1;
|
||||
mana_taken += mana_taken_temporary;
|
||||
member_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
manataken += manataken * penalty / 100;
|
||||
manataken /= numMem;
|
||||
mana_taken += mana_taken * penalty / 100;
|
||||
|
||||
if (member_count > 0) {
|
||||
mana_taken /= member_count;
|
||||
}
|
||||
|
||||
for (const auto& m : members) {
|
||||
if (m.is_bot) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m.member && m.group_number == gid) {
|
||||
if (m.member && m.group_number == group_id) {
|
||||
distance = DistanceSquared(caster->GetPosition(), m.member->GetPosition());
|
||||
|
||||
if (distance <= range2) {
|
||||
if ((m.member->GetMaxMana() - manataken) < 1) {
|
||||
if (distance <= range_squared) {
|
||||
if ((m.member->GetMaxMana() - mana_taken) < 1) {
|
||||
m.member->SetMana(1);
|
||||
|
||||
if (m.member->IsClient()) {
|
||||
m.member->CastToClient()->SendManaUpdate();
|
||||
}
|
||||
}
|
||||
else {
|
||||
m.member->SetMana(m.member->GetMaxMana() - manataken);
|
||||
} else {
|
||||
m.member->SetMana(m.member->GetMaxMana() - mana_taken);
|
||||
|
||||
if (m.member->IsClient()) {
|
||||
m.member->CastToClient()->SendManaUpdate();
|
||||
|
||||
+3
-3
@@ -167,9 +167,9 @@ public:
|
||||
void CastGroupSpell(Mob* caster,uint16 spellid, uint32 gid);
|
||||
void SplitExp(ExpSource exp_source, const uint64 exp, Mob* other);
|
||||
uint32 GetTotalRaidDamage(Mob* other);
|
||||
void BalanceHP(int32 penalty, uint32 gid, float range = 0, Mob* caster = nullptr, int32 limit = 0);
|
||||
void BalanceMana(int32 penalty, uint32 gid, float range = 0, Mob* caster = nullptr, int32 limit = 0);
|
||||
void HealGroup(uint32 heal_amt, Mob* caster, uint32 gid, float range = 0);
|
||||
void BalanceHP(int32 penalty, uint32 group_id, float range = 0, Mob* caster = nullptr, int32 limit = 0);
|
||||
void BalanceMana(int32 penalty, uint32 group_id, float range = 0, Mob* caster = nullptr, int32 limit = 0);
|
||||
void HealGroup(uint32 heal_amount, Mob* caster, uint32 group_id, float range = 0);
|
||||
void SplitMoney(uint32 gid, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Client *splitter = nullptr);
|
||||
|
||||
void TeleportGroup(Mob* sender, uint32 zoneID, uint16 instance_id, float x, float y, float z, float heading, uint32 gid);
|
||||
|
||||
Reference in New Issue
Block a user