Compare commits

..

23 Commits

Author SHA1 Message Date
Alex King d142e1ca81 [Hotfix] Fix Quest Ownership Edge Case (#4977)
* [Hotfix] Fix Quest Ownership Edge Case

* Push
2025-08-02 22:09:30 -05:00
Chris Miles d9f4d49ef4 [Release] 23.9.0 (#4976) 2025-08-02 20:11:29 -05:00
Alex King 0a1df5bbb6 [Quest API] Add GetTimers() and GetPausedTimers() to Perl/Lua (#4965)
* [Quest API] Add GetTimers() and GetPausedTimers() to Perl/Lua

* Push
2025-08-02 19:17:56 -05:00
dependabot[bot] 41f3d7ff31 Bump golang.org/x/oauth2 in /utils/scripts/build/should-release (#4967)
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.0.0-20180821212333-d2e6202438be to 0.27.0.
- [Commits](https://github.com/golang/oauth2/commits/v0.27.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-version: 0.27.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-02 19:16:57 -05:00
solar 0afef19d26 [Loginserver] Fix Legacy World When Using Local DB (#4970)
Co-authored-by: solar <solar@heliacal.net>
2025-08-02 19:16:35 -05:00
Alex King e9be2d76c3 [Commands] Add #show keyring Subcommand (#4973) 2025-08-02 19:15:44 -05:00
solar ffa813b92c [Build] Fix Linking with GCC (#4969)
Co-authored-by: solar <solar@heliacal.net>
2025-08-02 19:15:11 -05:00
solar 909de47acd fix player movement deltas (jumping, turning) (#4975)
Co-authored-by: solar <solar@heliacal.net>
2025-08-02 10:32:30 -04:00
regneq 73a5f11e17 [Bug Fix] [Bug Fix] Show player count on the server list status. (#4971) 2025-07-30 19:39:55 -04:00
Alex King 9544e100c3 [Bug Fix] Fix Hero's Forge Ingame and Character Select (#4966) 2025-07-30 19:39:29 -04:00
Chris Miles f3232cdc3a [Database] Add Indexes to NPC's Spawns Loot (#4972) 2025-07-30 09:37:23 -04:00
Bemvaras b8884d6572 [Quest API] Add GetMemberRole() to Perl/Lua (#4963)
* Add group member role retrieval

* Expose group member role to Lua

* Cleanup

* Cleanup

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2025-07-10 15:09:04 -04:00
Alex King 323a0c0b27 [Feature] Zone Scripting (#4908)
* [Feature] Add Zone Scripting Capabilities

* Push

* Update zone.cpp

* Fix crashes

* Lua

* Add other events, finish Lua

* Add EVENT_ENTER_ZONE

* Final

* Push

* Push

* [Feature] Add Zone Scripting Capabilities

* Push

* Update zone.cpp

* Fix crashes

* Add EVENT_ENTER_ZONE

* Remove duplicates

* Update embparser.cpp
2025-07-10 15:08:08 -04:00
regneq ab45d4358d [Bug Fix] Add a missing Froglok starting area for Titanium Startzone. (#4962)
* Add a missing Froglok starting area for Titanium Startzone.

* fix formatting.

* add a missing break.
2025-07-04 12:53:45 -04:00
nytmyr f7775c7a75 [Bots] Fix FinishBuffing rule (#4961) 2025-06-30 19:54:04 -05:00
Chris Miles 659a960401 [Performance] Clear Wearchange Deduplication Cache (#4960)
* [Performance] Clear Wearchange Deduplication Cache

* Move timers to process loops
2025-06-30 13:57:43 -05:00
Chris Miles 07d484597d [Build] More Build Speed Improvements (#4959) 2025-06-30 13:09:23 -05:00
nytmyr fc470d5f83 [Bots] Fix ^cast resurrects (#4958)
- Was failing stack checks and couldn't be casted. Added bypass.
2025-06-29 10:19:00 -04:00
Chris Miles 585ed3bd25 [Release] 23.8.1 2025-06-28 17:29:25 -05:00
Chris Miles 2eb291a461 [Databuckets] Revert Caching Changes of #4917 (#4957)
* [Databuckets] Revert Caching Changes of #4917

* Comment caching tests until addressed later
2025-06-28 17:28:19 -05:00
Alex King a1421af214 [Bug Fix] Fix Hero Forge on Character Select (#4954) 2025-06-26 19:35:28 -04:00
Alex King 13aad6229f [Crash Fix] Fix Possible Crashes with Raid Methods (#4955) 2025-06-26 19:35:20 -04:00
Alex King 76d46ceaf0 [Bug Fix] Fix FindCharacter Using content_db (#4956) 2025-06-26 19:35:11 -04:00
67 changed files with 2661 additions and 601 deletions
+64
View File
@@ -1,3 +1,67 @@
## [23.9.1] 8/2/2025
### Hotfix
* Fix Quest Ownership Edge Case ([#4977](https://github.com/EQEmu/Server/pull/4977)) @Kinglykrab 2025-08-02
## [23.9.0] 8/2/2025
### Bots
* Fix FinishBuffing rule ([#4961](https://github.com/EQEmu/Server/pull/4961)) @nytmyr 2025-07-01
* Fix ^cast resurrects ([#4958](https://github.com/EQEmu/Server/pull/4958)) @nytmyr 2025-06-29
### Build
* Fix Linking with GCC ([#4969](https://github.com/EQEmu/Server/pull/4969)) @solar984 2025-08-03
* More Build Speed Improvements ([#4959](https://github.com/EQEmu/Server/pull/4959)) @Akkadius 2025-06-30
### Commands
* Add #show keyring Subcommand ([#4973](https://github.com/EQEmu/Server/pull/4973)) @Kinglykrab 2025-08-03
### Database
* Add Indexes to NPC's Spawns Loot ([#4972](https://github.com/EQEmu/Server/pull/4972)) @Akkadius 2025-07-30
### Feature
* Zone Scripting ([#4908](https://github.com/EQEmu/Server/pull/4908)) @Kinglykrab 2025-07-10
### Fixes
* Add a missing Froglok starting area for Titanium Startzone. ([#4962](https://github.com/EQEmu/Server/pull/4962)) @regneq 2025-07-04
* Fix Hero's Forge Ingame and Character Select ([#4966](https://github.com/EQEmu/Server/pull/4966)) @Kinglykrab 2025-07-30
* Show player count on the server list status. ([#4971](https://github.com/EQEmu/Server/pull/4971)) @regneq 2025-07-30
### Loginserver
* Fix Legacy World When Using Local DB ([#4970](https://github.com/EQEmu/Server/pull/4970)) @solar984 2025-08-03
### Performance
* Clear Wearchange Deduplication Cache ([#4960](https://github.com/EQEmu/Server/pull/4960)) @Akkadius 2025-06-30
### Quest API
* Add GetMemberRole() to Perl/Lua ([#4963](https://github.com/EQEmu/Server/pull/4963)) @Barathos 2025-07-10
* Add GetTimers() and GetPausedTimers() to Perl/Lua ([#4965](https://github.com/EQEmu/Server/pull/4965)) @Kinglykrab 2025-08-03
## [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 ## [23.8.0] 6/25/2025
### API ### API
+2
View File
@@ -363,6 +363,8 @@ MESSAGE(STATUS "**************************************************")
#setup server libs and headers #setup server libs and headers
SET(SERVER_LIBS common ${DATABASE_LIBRARY_LIBS} ${ZLIB_LIBRARY_LIBS} ${Boost_LIBRARIES} uv_a fmt RecastNavigation::Detour) 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 "${DATABASE_LIBRARY_INCLUDE}")
INCLUDE_DIRECTORIES(SYSTEM "${ZLIB_LIBRARY_INCLUDE}") INCLUDE_DIRECTORIES(SYSTEM "${ZLIB_LIBRARY_INCLUDE}")
INCLUDE_DIRECTORIES(SYSTEM "${Boost_INCLUDE_DIRS}") INCLUDE_DIRECTORIES(SYSTEM "${Boost_INCLUDE_DIRS}")
+1 -1
View File
@@ -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) 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) ENDIF (UNIX)
IF (WIN32 AND EQEMU_BUILD_PCH) IF (EQEMU_BUILD_PCH)
TARGET_PRECOMPILE_HEADERS(common PRIVATE pch/std-pch.h) TARGET_PRECOMPILE_HEADERS(common PRIVATE pch/std-pch.h)
ENDIF () ENDIF ()
+6 -80
View File
@@ -19,37 +19,6 @@ extern WorldDatabase database;
#error "You must define either ZONE or WORLD" #error "You must define either ZONE or WORLD"
#endif #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) void DataBucket::SetData(const std::string &bucket_key, const std::string &bucket_value, std::string expires_time)
{ {
auto k = DataBucketKey{ auto k = DataBucketKey{
@@ -167,15 +136,6 @@ void DataBucket::SetData(const DataBucketKey &k_)
// Serialize JSON back to string // Serialize JSON back to string
b.value = json_value.dump(); b.value = json_value.dump();
b.key_ = top_key; // Use the top-level key 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) { if (bucket_id) {
@@ -291,27 +251,12 @@ DataBucketsRepository::DataBuckets DataBucket::GetData(const DataBucketKey &k_,
LogDataBuckets("Returning key [{}] value [{}] from cache", e.key_, e.value); LogDataBuckets("Returning key [{}] value [{}] from cache", e.key_, e.value);
if (is_nested_key && !k_.key.empty()) { if (is_nested_key && !k_.key.empty()) {
std::string nested_cache_key = MakeNestedCacheKey(k_, k.key); return ExtractNestedValue(e, 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 e; 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 // Fetch the value from the database
@@ -370,43 +315,24 @@ DataBucketsRepository::DataBuckets DataBucket::GetData(const DataBucketKey &k_,
} }
// Add the value to the cache if it doesn't exist // 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) { if (can_cache) {
bool found_in_cache = false; bool has_cache = false;
for (const auto &e : g_data_bucket_cache) { for (const auto &e : g_data_bucket_cache) {
if (CheckBucketMatch(e, k)) { if (e.id == bucket.id) {
found_in_cache = true; has_cache = true;
break; break;
} }
} }
if (!found_in_cache) { if (!has_cache) {
LogDataBuckets("Cache miss for key [{}] - skipping DB due to CanCache", k.key); g_data_bucket_cache.emplace_back(bucket);
return DataBucketsRepository::NewEntity();
} }
} }
// Handle nested key extraction // Handle nested key extraction
if (is_nested_key && !k_.key.empty()) { 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; return bucket;
} }
@@ -7136,6 +7136,31 @@ ADD COLUMN `entity_variables` TEXT DEFAULT NULL AFTER `rezzable`;
)", )",
.content_schema_update = false .content_schema_update = false
}, },
ManifestEntry{
.version = 9326,
.description = "2025_07_27_add_indexes_npc_spawns_loot.sql",
.check = "SHOW INDEX FROM npc_types",
.condition = "missing",
.match = "idx_npc_types_loottable_id",
.sql = R"(
ALTER TABLE npc_types
ADD INDEX idx_npc_types_loottable_id (loottable_id);
ALTER TABLE spawnentry
ADD INDEX idx_spawnentry_spawngroup_id (spawngroupID),
ADD INDEX idx_spawnentry_npc_id (npcID);
ALTER TABLE lootdrop_entries
ADD INDEX idx_lootdrop_entries_lootdrop_id (lootdrop_id),
ADD INDEX idx_lootdrop_entries_item_id (item_id);
ALTER TABLE loottable_entries
ADD INDEX idx_loottable_entries_lootdrop_id (lootdrop_id),
ADD INDEX idx_loottable_entries_loottable_id (loottable_id);
)",
.content_schema_update = true
},
// -- template; copy/paste this when you need to create a new entry // -- template; copy/paste this when you need to create a new entry
// ManifestEntry{ // ManifestEntry{
// .version = 9228, // .version = 9228,
+2 -1
View File
@@ -988,7 +988,8 @@ enum StartZoneIndex {
Felwithe, Felwithe,
Akanon, Akanon,
Cabilis, Cabilis,
SharVahl SharVahl,
RatheMtn
}; };
enum FVNoDropFlagRule enum FVNoDropFlagRule
+1 -1
View File
@@ -574,7 +574,7 @@ EQ::ItemInstance* EQ::ItemInstance::GetOrnamentationAugment() const
uint32 EQ::ItemInstance::GetOrnamentHeroModel(int32 material_slot) const uint32 EQ::ItemInstance::GetOrnamentHeroModel(int32 material_slot) const
{ {
// Not a Hero Forge item. // Not a Hero Forge item.
if (m_ornament_hero_model == 0 || material_slot < 0) { if (m_ornament_hero_model == 0) {
return 0; return 0;
} }
+7 -27
View File
@@ -1,34 +1,14 @@
// types #pragma once
#include <limits>
#include <string>
#include <cctype>
#include <sstream>
// containers // Lightweight, widely used
#include <iterator> #include <string>
#include <set> #include <vector>
#include <unordered_set>
#include <map> #include <map>
#include <unordered_map> #include <unordered_map>
#include <list>
#include <vector>
// utilities
#include <iostream>
#include <cassert>
#include <cmath>
#include <memory> #include <memory>
#include <functional> #include <limits>
#include <algorithm> #include <cstdint>
#include <utility> #include <cassert>
#include <tuple>
#include <fstream>
#include <cstdio>
// fmt // fmt
#include <fmt/format.h> #include <fmt/format.h>
// lua
#include "lua.hpp"
#include <luabind/luabind.hpp>
#include <luabind/object.hpp>
@@ -142,6 +142,7 @@ public:
{.parent_command = "show", .sub_command = "hatelist", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "hatelist"}, {.parent_command = "show", .sub_command = "hatelist", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "hatelist"},
{.parent_command = "show", .sub_command = "inventory", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "peekinv"}, {.parent_command = "show", .sub_command = "inventory", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "peekinv"},
{.parent_command = "show", .sub_command = "ip_lookup", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "iplookup"}, {.parent_command = "show", .sub_command = "ip_lookup", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "iplookup"},
{.parent_command = "show", .sub_command = "keyring", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "showkeyring"},
{.parent_command = "show", .sub_command = "line_of_sight", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "checklos"}, {.parent_command = "show", .sub_command = "line_of_sight", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "checklos"},
{.parent_command = "show", .sub_command = "network", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "network"}, {.parent_command = "show", .sub_command = "network", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "network"},
{.parent_command = "show", .sub_command = "network_stats", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "netstats"}, {.parent_command = "show", .sub_command = "network_stats", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "netstats"},
+1
View File
@@ -358,6 +358,7 @@ bool RequiresStackCheck(uint16 spell_type) {
case BotSpellTypes::CompleteHeal: case BotSpellTypes::CompleteHeal:
case BotSpellTypes::PetCompleteHeals: case BotSpellTypes::PetCompleteHeals:
case BotSpellTypes::GroupCompleteHeals: case BotSpellTypes::GroupCompleteHeals:
case BotSpellTypes::Resurrect:
return false; return false;
default: default:
return true; return true;
+2 -2
View File
@@ -25,7 +25,7 @@
// Build variables // Build variables
// these get injected during the build pipeline // 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.9.1-dev" // always append -dev to the current version for custom-builds
#define LOGIN_VERSION "0.8.0" #define LOGIN_VERSION "0.8.0"
#define COMPILE_DATE __DATE__ #define COMPILE_DATE __DATE__
#define COMPILE_TIME __TIME__ #define COMPILE_TIME __TIME__
@@ -42,7 +42,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 9325 #define CURRENT_BINARY_DATABASE_VERSION 9326
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9054 #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9054
#define CUSTOM_BINARY_DATABASE_VERSION 0 #define CUSTOM_BINARY_DATABASE_VERSION 0
+1 -1
View File
@@ -31,7 +31,7 @@ public:
inline void DefaultLoginServerName(const std::string &v) { m_default_loginserver_name = v; } inline void DefaultLoginServerName(const std::string &v) { m_default_loginserver_name = v; }
inline std::string GetDefaultLoginServerName() const { return m_default_loginserver_name; } inline std::string GetDefaultLoginServerName() const { return m_default_loginserver_name; }
inline bool IsShowPlayerCountEnabled() const { return m_show_player_count; } inline bool IsShowPlayerCountEnabled() const { return m_show_player_count; }
inline void SetShowPlayerCount(bool show_player_count) { show_player_count = show_player_count; } inline void SetShowPlayerCount(bool show_player_count) { m_show_player_count = show_player_count; }
inline bool IsWorldDevTestServersListBottom() const { return m_world_dev_list_bottom; } inline bool IsWorldDevTestServersListBottom() const { return m_world_dev_list_bottom; }
inline void SetWorldDevTestServersListBottom(bool list_bottom) { m_world_dev_list_bottom = list_bottom; } inline void SetWorldDevTestServersListBottom(bool list_bottom) { m_world_dev_list_bottom = list_bottom; }
inline bool IsWorldSpecialCharacterStartListBottom() const { return m_special_char_list_bottom; } inline bool IsWorldSpecialCharacterStartListBottom() const { return m_special_char_list_bottom; }
+5 -1
View File
@@ -155,7 +155,11 @@ void WorldServer::ProcessUserToWorldResponseLegacy(uint16_t opcode, const EQ::Ne
auto *res = (UsertoWorldResponseLegacy *) packet.Data(); auto *res = (UsertoWorldResponseLegacy *) packet.Data();
LogDebug("Trying to find client with user id of [{}]", res->lsaccountid); LogDebug("Trying to find client with user id of [{}]", res->lsaccountid);
Client *c = server.client_manager->GetClient(res->lsaccountid, "eqemu"); std::string db_loginserver = "local";
if (std::getenv("LSPX")) {
db_loginserver = "eqemu";
}
Client *c = server.client_manager->GetClient(res->lsaccountid, db_loginserver);
if (c) { if (c) {
LogDebug( LogDebug(
"Found client with user id of [{}] and account name of [{}]", "Found client with user id of [{}] and account name of [{}]",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "eqemu-server", "name": "eqemu-server",
"version": "23.8.0", "version": "23.9.1",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/EQEmu/Server.git" "url": "https://github.com/EQEmu/Server.git"
+3 -3
View File
@@ -14,15 +14,15 @@ perl utils/scripts/build/tag-version.pl
mkdir -p build && cd build && \ mkdir -p build && cd build && \
cmake -DEQEMU_BUILD_TESTS=ON \ cmake -DEQEMU_BUILD_TESTS=ON \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DEQEMU_BUILD_STATIC=ON \ -DEQEMU_BUILD_STATIC=ON \
-DEQEMU_BUILD_LOGIN=ON \ -DEQEMU_BUILD_LOGIN=ON \
-DEQEMU_BUILD_LUA=ON \ -DEQEMU_BUILD_LUA=ON \
-DEQEMU_BUILD_PERL=ON \ -DEQEMU_BUILD_PERL=ON \
-DCMAKE_CXX_FLAGS:STRING="-O1 -g -Wno-everything" \ -DCMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING="-g -Wno-everything" \
-DCMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING="-O1 -g -Wno-everything" \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-G 'Unix Makefiles' \ -G 'Unix Makefiles' \
.. && make -j$((`nproc`-12)) .. && make -j$((`nproc`-2))
curl https://raw.githubusercontent.com/Akkadius/eqemu-install-v2/master/eqemu_config.json --output eqemu_config.json curl https://raw.githubusercontent.com/Akkadius/eqemu-install-v2/master/eqemu_config.json --output eqemu_config.json
./bin/tests ./bin/tests
+1 -4
View File
@@ -6,13 +6,10 @@ toolchain go1.23.5
require ( require (
github.com/google/go-github/v41 v41.0.0 github.com/google/go-github/v41 v41.0.0
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be golang.org/x/oauth2 v0.27.0
) )
require ( require (
github.com/golang/protobuf v1.3.2 // indirect
github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-querystring v1.1.0 // indirect
golang.org/x/crypto v0.36.0 // indirect golang.org/x/crypto v0.36.0 // indirect
golang.org/x/net v0.38.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
) )
+4 -6
View File
@@ -1,9 +1,9 @@
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-github/v41 v41.0.0 h1:HseJrM2JFf2vfiZJ8anY2hqBjdfY1Vlj/K27ueww4gg= github.com/google/go-github/v41 v41.0.0 h1:HseJrM2JFf2vfiZJ8anY2hqBjdfY1Vlj/K27ueww4gg=
github.com/google/go-github/v41 v41.0.0/go.mod h1:XgmCA5H323A9rtgExdTcnDkcqp6S30AVACCBDOonIxg= github.com/google/go-github/v41 v41.0.0/go.mod h1:XgmCA5H323A9rtgExdTcnDkcqp6S30AVACCBDOonIxg=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
@@ -14,10 +14,9 @@ golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=
golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -27,5 +26,4 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+10
View File
@@ -732,6 +732,12 @@ void WorldDatabase::SetTitaniumDefaultStartZone(PlayerProfile_Struct* in_pp, Cha
in_pp->binds[0].zone_id = Zones::SHARVAHL; // sharvahl in_pp->binds[0].zone_id = Zones::SHARVAHL; // sharvahl
break; break;
} }
case StartZoneIndex::RatheMtn:
{
in_pp->zone_id = Zones::RATHEMTN; // rathemtn
in_pp->binds[0].zone_id = Zones::RATHEMTN; // rathemtn
break;
}
} }
} }
} }
@@ -895,9 +901,13 @@ bool WorldDatabase::GetCharSelInventory(
inst->SetCustomDataString(e.custom_data); inst->SetCustomDataString(e.custom_data);
} }
if (e.ornament_icon != 0 || e.ornament_idfile != 0 || e.ornament_hero_model != 0) {
inst->SetOrnamentIcon(e.ornament_icon); inst->SetOrnamentIcon(e.ornament_icon);
inst->SetOrnamentationIDFile(e.ornament_idfile); inst->SetOrnamentationIDFile(e.ornament_idfile);
inst->SetOrnamentHeroModel(e.ornament_hero_model); inst->SetOrnamentHeroModel(e.ornament_hero_model);
} else if (item->HerosForgeModel > 0) {
inst->SetOrnamentHeroModel(item->HerosForgeModel);
}
inv->PutItem(e.slot_id, *inst); inv->PutItem(e.slot_id, *inst);
+2 -1
View File
@@ -483,6 +483,7 @@ INSTALL(TARGETS zone RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
# precompiled headers # precompiled headers
IF (EQEMU_BUILD_PCH) IF (EQEMU_BUILD_PCH)
TARGET_PRECOMPILE_HEADERS(zone PRIVATE ../common/pch/app-pch.h) 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) TARGET_PRECOMPILE_HEADERS(zone PRIVATE ./pch/pch.h)
ENDIF() ENDIF()
@@ -501,7 +502,7 @@ if (EQEMU_BUILD_STATIC AND PERL_LIBRARY)
endif() endif()
# link zone against common libraries # link zone against common libraries
target_link_libraries(zone PRIVATE ${ZONE_LIBS} lua_zone perl_zone gm_commands_zone) target_link_libraries(zone PRIVATE lua_zone perl_zone gm_commands_zone ${ZONE_LIBS})
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
+19
View File
@@ -3039,6 +3039,25 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
DispatchZoneControllerEvent(EVENT_DEATH_ZONE, owner_or_self, export_string, 0, &args); DispatchZoneControllerEvent(EVENT_DEATH_ZONE, owner_or_self, export_string, 0, &args);
} }
if (parse->ZoneHasQuestSub(EVENT_DEATH_ZONE)) {
const auto& export_string = fmt::format(
"{} {} {} {} {} {} {} {} {}",
killer_mob ? killer_mob->GetID() : 0,
damage,
spell,
static_cast<int>(attack_skill),
entity_id,
m_combat_record.GetStartTime(),
m_combat_record.GetEndTime(),
m_combat_record.GetDamageReceived(),
m_combat_record.GetHealingReceived()
);
std::vector<std::any> args = { corpse, this, owner_or_self };
parse->EventZone(EVENT_DEATH_ZONE, zone, export_string, 0, &args);
}
return true; return true;
} }
+3 -8
View File
@@ -9610,14 +9610,9 @@ bool Bot::CastChecks(uint16 spell_id, Mob* tar, uint16 spell_type, bool precheck
return false; return false;
} }
if ( bool is_mana_exempt = RuleB(Bots, FinishBuffing) && !IsEngaged() && IsBotBuffSpellType(spell_type);
!BotHasEnoughMana(spell_id) &&
( if (!BotHasEnoughMana(spell_id) && !is_mana_exempt) {
!RuleB(Bots, FinishBuffing) ||
IsEngaged() ||
IsBotBuffSpellType(spell_type)
)
) {
LogBotSpellChecksDetail("{} says, 'Cancelling cast of {} due to !BotHasEnoughMana.'", GetCleanName(), GetSpellName(spell_id)); LogBotSpellChecksDetail("{} says, 'Cancelling cast of {} due to !BotHasEnoughMana.'", GetCleanName(), GetSpellName(spell_id));
return false; return false;
} }
+26 -26
View File
@@ -318,32 +318,32 @@ void ZoneCLI::TestDataBuckets(int argc, char** argv, argh::parser& cmd, std::str
); );
// Cold cache test — should return "" // Cold cache test — should return ""
std::string cold_value = client->GetBucket(scoped_key); // std::string cold_value = client->GetBucket(scoped_key);
RunTest("Cold Cache Scoped Key Returns Empty (Due to Skip DB)", "", cold_value); // RunTest("Cold Cache Scoped Key Returns Empty (Due to Skip DB)", "", cold_value);
//
// ✅ Reload cache // // ✅ Reload cache
client->LoadDataBucketsCache(); // client->LoadDataBucketsCache();
//
// Cache should now return the value // // Cache should now return the value
std::string hot_value = client->GetBucket(scoped_key); // std::string hot_value = client->GetBucket(scoped_key);
RunTest("Post-BulkLoad Scoped Key Returns Value", "cached_value", hot_value); // RunTest("Post-BulkLoad Scoped Key Returns Value", "cached_value", hot_value);
//
// Also test nested key after preload // // Also test nested key after preload
client->DeleteBucket("ac_nested.test"); // client->DeleteBucket("ac_nested.test");
client->SetBucket("ac_nested.test", "nested_val"); // client->SetBucket("ac_nested.test", "nested_val");
//
// Clear cache, then preload // // Clear cache, then preload
DataBucket::ClearCache(); // DataBucket::ClearCache();
client->LoadDataBucketsCache(); // client->LoadDataBucketsCache();
//
std::string nested_value = client->GetBucket("ac_nested.test"); // std::string nested_value = client->GetBucket("ac_nested.test");
RunTest("Post-BulkLoad Nested Scoped Key Returns Value", "nested_val", nested_value); // RunTest("Post-BulkLoad Nested Scoped Key Returns Value", "nested_val", nested_value);
//
// Remove and check that cache misses properly again // // Remove and check that cache misses properly again
client->DeleteBucket("ac_nested.test"); // client->DeleteBucket("ac_nested.test");
DataBucket::ClearCache(); // DataBucket::ClearCache();
std::string post_delete_check = client->GetBucket("ac_nested.test"); // std::string post_delete_check = client->GetBucket("ac_nested.test");
RunTest("Post-Delete Nested Scoped Key Returns Empty", "", post_delete_check); // RunTest("Post-Delete Nested Scoped Key Returns Empty", "", post_delete_check);
std::cout << "\n===========================================\n"; std::cout << "\n===========================================\n";
+15 -3
View File
@@ -4780,9 +4780,21 @@ bool Client::KeyRingClear()
); );
} }
void Client::KeyRingList() void Client::KeyRingList(Client* c)
{ {
Message(Chat::LightBlue, "Keys on Keyring:"); if (!c) {
return;
}
std::string message = "Keys on Keyring:";
if (c != this) {
message = fmt::format(
"Keys on Keyring for {}:",
GetCleanName()
);
}
c->Message(Chat::LightBlue, message.c_str());
const EQ::ItemData *item = nullptr; const EQ::ItemData *item = nullptr;
@@ -4795,7 +4807,7 @@ void Client::KeyRingList()
item->Name item->Name
); );
Message(Chat::LightBlue, item_string.c_str()); c->Message(Chat::LightBlue, item_string.c_str());
} }
} }
} }
+1 -1
View File
@@ -331,7 +331,7 @@ public:
bool KeyRingCheck(uint32 item_id); bool KeyRingCheck(uint32 item_id);
bool KeyRingClear(); bool KeyRingClear();
bool KeyRingRemove(uint32 item_id); bool KeyRingRemove(uint32 item_id);
void KeyRingList(); void KeyRingList(Client* c = nullptr);
bool IsNameChangeAllowed(); bool IsNameChangeAllowed();
void InvokeChangeNameWindow(bool immediate = true); void InvokeChangeNameWindow(bool immediate = true);
bool ClearNameChange(); bool ClearNameChange();
+30 -16
View File
@@ -795,6 +795,11 @@ void Client::CompleteConnect()
parse->EventPlayer(EVENT_ENTER_ZONE, this, "", 0); parse->EventPlayer(EVENT_ENTER_ZONE, this, "", 0);
} }
if (parse->ZoneHasQuestSub(EVENT_ENTER_ZONE)) {
std::vector<std::any> args = { this };
parse->EventZone(EVENT_ENTER_ZONE, zone, "", 0, &args);
}
DeleteEntityVariable(SEE_BUFFS_FLAG); DeleteEntityVariable(SEE_BUFFS_FLAG);
// the way that the client deals with positions during the initial spawn struct // the way that the client deals with positions during the initial spawn struct
@@ -4709,6 +4714,12 @@ void Client::Handle_OP_ClickDoor(const EQApplicationPacket *app)
quest_return = parse->EventPlayer(EVENT_CLICK_DOOR, this, std::to_string(cd->doorid), 0, &args); quest_return = parse->EventPlayer(EVENT_CLICK_DOOR, this, std::to_string(cd->doorid), 0, &args);
} }
if (parse->ZoneHasQuestSub(EVENT_CLICK_DOOR)) {
std::vector<std::any> args = { currentdoor, this };
quest_return = parse->EventZone(EVENT_CLICK_DOOR, zone, std::to_string(cd->doorid), 0, &args);
}
if (quest_return == 0) { if (quest_return == 0) {
currentdoor->HandleClick(this, 0); currentdoor->HandleClick(this, 0);
} }
@@ -4741,6 +4752,11 @@ void Client::Handle_OP_ClickObject(const EQApplicationPacket *app)
parse->EventPlayer(EVENT_CLICK_OBJECT, this, std::to_string(click_object->drop_id), GetID(), &args); parse->EventPlayer(EVENT_CLICK_OBJECT, this, std::to_string(click_object->drop_id), GetID(), &args);
} }
if (parse->ZoneHasQuestSub(EVENT_CLICK_OBJECT)) {
std::vector<std::any> args = { object, this };
parse->EventZone(EVENT_CLICK_OBJECT, zone, std::to_string(click_object->drop_id), GetID(), &args);
}
if (IsDevToolsEnabled()) { if (IsDevToolsEnabled()) {
SetObjectToolEntityId(entity->GetID()); SetObjectToolEntityId(entity->GetID());
ObjectManipulation::CommandHeader(this); ObjectManipulation::CommandHeader(this);
@@ -4967,9 +4983,6 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
m_Proximity = glm::vec3(cx, cy, cz); m_Proximity = glm::vec3(cx, cy, cz);
} }
/* Update internal state */
m_Delta = glm::vec4(ppu->delta_x, ppu->delta_y, ppu->delta_z, EQ10toFloat(ppu->delta_heading));
if (RuleB(Skills, TrackingAutoRefreshSkillUps) && IsTracking() && ((m_Position.x != cx) || (m_Position.y != cy))) { if (RuleB(Skills, TrackingAutoRefreshSkillUps) && IsTracking() && ((m_Position.x != cx) || (m_Position.y != cy))) {
if (zone->random.Real(0, 100) < 70)//should be good if (zone->random.Real(0, 100) < 70)//should be good
CheckIncreaseSkill(EQ::skills::SkillTracking, nullptr, -20); CheckIncreaseSkill(EQ::skills::SkillTracking, nullptr, -20);
@@ -5003,6 +5016,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
rewind_timer.Start(30000, true); rewind_timer.Start(30000, true);
} }
glm::vec4 prevDelta = m_Delta; // SetMoving clears m_Delta
SetMoving(!(cy == m_Position.y && cx == m_Position.x)); SetMoving(!(cy == m_Position.y && cx == m_Position.x));
if (RuleB(Character, EnableAutoAFK)) { if (RuleB(Character, EnableAutoAFK)) {
@@ -5017,12 +5031,13 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
CheckSendBulkNpcPositions(); CheckSendBulkNpcPositions();
int32 new_animation = ppu->animation;
/* Update internal server position from what the client has sent */ /* Update internal server position from what the client has sent */
m_Position.x = cx; glm::vec4 prevPosition = m_Position;
m_Position.y = cy; m_Position = glm::vec4(cx, cy, cz, new_heading);
m_Position.z = cz; m_Delta = glm::vec4(ppu->delta_x, ppu->delta_y, ppu->delta_z, EQ10toFloat(ppu->delta_heading));
int32 prevAnimation = ppu->animation;
animation = ppu->animation;
bool positionUpdated = m_Position != prevPosition || m_Delta != prevDelta || m_Delta != glm::vec4(0.0f) || prevAnimation != animation;
/* Visual Debugging */ /* Visual Debugging */
if (RuleB(Character, OPClientUpdateVisualDebug)) { if (RuleB(Character, OPClientUpdateVisualDebug)) {
@@ -5032,11 +5047,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
} }
/* Only feed real time updates when client is moving */ /* Only feed real time updates when client is moving */
if (IsMoving() || new_heading != m_Position.w || new_animation != animation) { if (positionUpdated) {
animation = ppu->animation;
m_Position.w = new_heading;
/* Broadcast update to other clients */ /* Broadcast update to other clients */
static EQApplicationPacket outapp(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); static EQApplicationPacket outapp(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
PlayerPositionUpdateServer_Struct *position_update = (PlayerPositionUpdateServer_Struct *) outapp.pBuffer; PlayerPositionUpdateServer_Struct *position_update = (PlayerPositionUpdateServer_Struct *) outapp.pBuffer;
@@ -5049,7 +5060,6 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
entity_list.QueueCloseClients(this, &outapp, true, RuleI(Range, ClientPositionUpdates), nullptr, true); entity_list.QueueCloseClients(this, &outapp, true, RuleI(Range, ClientPositionUpdates), nullptr, true);
} }
/* Always send position updates to group - send when beyond normal ClientPositionUpdate range */ /* Always send position updates to group - send when beyond normal ClientPositionUpdate range */
Group *group = GetGroup(); Group *group = GetGroup();
Raid *raid = GetRaid(); Raid *raid = GetRaid();
@@ -5075,7 +5085,6 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
} }
CheckVirtualZoneLines(); CheckVirtualZoneLines();
} }
void Client::Handle_OP_CombatAbility(const EQApplicationPacket *app) void Client::Handle_OP_CombatAbility(const EQApplicationPacket *app)
@@ -9773,7 +9782,7 @@ void Client::Handle_OP_Jump(const EQApplicationPacket *app)
void Client::Handle_OP_KeyRing(const EQApplicationPacket *app) void Client::Handle_OP_KeyRing(const EQApplicationPacket *app)
{ {
KeyRingList(); KeyRingList(this);
} }
void Client::Handle_OP_KickPlayers(const EQApplicationPacket *app) void Client::Handle_OP_KickPlayers(const EQApplicationPacket *app)
@@ -12042,6 +12051,11 @@ void Client::Handle_OP_PopupResponse(const EQApplicationPacket *app)
parse->EventPlayer(EVENT_POPUP_RESPONSE, this, std::to_string(popup_response->popupid), 0); parse->EventPlayer(EVENT_POPUP_RESPONSE, this, std::to_string(popup_response->popupid), 0);
} }
if (parse->ZoneHasQuestSub(EVENT_POPUP_RESPONSE)) {
std::vector<std::any> args = { this };
parse->EventZone(EVENT_POPUP_RESPONSE, zone, std::to_string(popup_response->popupid), 0, &args);
}
auto t = GetTarget(); auto t = GetTarget();
if (t) { if (t) {
parse->EventBotMercNPC(EVENT_POPUP_RESPONSE, t, this, [&]() { return std::to_string(popup_response->popupid); }); parse->EventBotMercNPC(EVENT_POPUP_RESPONSE, t, this, [&]() { return std::to_string(popup_response->popupid); });
+4
View File
@@ -561,6 +561,10 @@ bool Client::Process() {
{ {
ItemTimerCheck(); ItemTimerCheck();
} }
if (m_clear_wearchange_cache_timer.Check()) {
m_last_seen_wearchange.clear();
}
} }
} }
+15
View File
@@ -1586,6 +1586,21 @@ void Corpse::LootCorpseItem(Client *c, const EQApplicationPacket *app)
} }
} }
if (parse->ZoneHasQuestSub(EVENT_LOOT_ZONE)) {
const auto &export_string = fmt::format(
"{} {} {} {}",
inst->GetItem()->ID,
inst->GetCharges(),
EntityList::RemoveNumbers(corpse_name),
GetID()
);
std::vector<std::any> args = {inst, this, c};
if (parse->EventZone(EVENT_LOOT_ZONE, zone, export_string, 0, &args) != 0) {
prevent_loot = true;
}
}
if (inst && PlayerEventLogs::Instance()->IsEventEnabled(PlayerEvent::LOOT_ITEM) && !IsPlayerCorpse()) { if (inst && PlayerEventLogs::Instance()->IsEventEnabled(PlayerEvent::LOOT_ITEM) && !IsPlayerCorpse()) {
auto e = PlayerEvent::LootItemEvent{ auto e = PlayerEvent::LootItemEvent{
.item_id = inst->GetItem()->ID, .item_id = inst->GetItem()->ID,
+305 -200
View File
@@ -222,6 +222,8 @@ PerlembParser::PerlembParser() : perl(nullptr)
global_bot_quest_status_ = questUnloaded; global_bot_quest_status_ = questUnloaded;
merc_quest_status_ = questUnloaded; merc_quest_status_ = questUnloaded;
global_merc_quest_status_ = questUnloaded; global_merc_quest_status_ = questUnloaded;
zone_quest_status_ = questUnloaded;
global_zone_quest_status_ = questUnloaded;
} }
PerlembParser::~PerlembParser() PerlembParser::~PerlembParser()
@@ -265,6 +267,8 @@ void PerlembParser::ReloadQuests()
global_bot_quest_status_ = questUnloaded; global_bot_quest_status_ = questUnloaded;
merc_quest_status_ = questUnloaded; merc_quest_status_ = questUnloaded;
global_merc_quest_status_ = questUnloaded; global_merc_quest_status_ = questUnloaded;
zone_quest_status_ = questUnloaded;
global_zone_quest_status_ = questUnloaded;
item_quest_status_.clear(); item_quest_status_.clear();
spell_quest_status_.clear(); spell_quest_status_.clear();
@@ -278,6 +282,7 @@ int PerlembParser::EventCommon(
EQ::ItemInstance* inst, EQ::ItemInstance* inst,
const SPDat_Spell_Struct* spell, const SPDat_Spell_Struct* spell,
Mob* mob, Mob* mob,
Zone* zone,
uint32 extra_data, uint32 extra_data,
bool is_global, bool is_global,
std::vector<std::any>* extra_pointers std::vector<std::any>* extra_pointers
@@ -287,52 +292,22 @@ int PerlembParser::EventCommon(
return 0; return 0;
} }
bool is_player_quest = false; QuestType quest_type = GetQuestTypes(
bool is_global_player_quest = false;
bool is_global_npc_quest = false;
bool is_bot_quest = false;
bool is_global_bot_quest = false;
bool is_merc_quest = false;
bool is_global_merc_quest = false;
bool is_item_quest = false;
bool is_spell_quest = false;
std::string package_name;
GetQuestTypes(
is_player_quest,
is_global_player_quest,
is_bot_quest,
is_global_bot_quest,
is_merc_quest,
is_global_merc_quest,
is_global_npc_quest,
is_item_quest,
is_spell_quest,
event_id, event_id,
npc_mob, npc_mob,
inst, inst,
mob, mob,
zone,
is_global is_global
); );
GetQuestPackageName( std::string package_name = GetQuestPackageName(
is_player_quest, quest_type,
is_global_player_quest,
is_bot_quest,
is_global_bot_quest,
is_merc_quest,
is_global_merc_quest,
is_global_npc_quest,
is_item_quest,
is_spell_quest,
package_name,
event_id, event_id,
object_id, object_id,
data, data,
npc_mob, npc_mob,
inst, inst
is_global
); );
const std::string& sub_name = QuestEventSubroutines[event_id]; const std::string& sub_name = QuestEventSubroutines[event_id];
@@ -348,15 +323,7 @@ int PerlembParser::EventCommon(
/* Check for QGlobal export event enable */ /* Check for QGlobal export event enable */
if (parse->perl_event_export_settings[event_id].qglobals) { if (parse->perl_event_export_settings[event_id].qglobals) {
ExportQGlobals( ExportQGlobals(
is_player_quest, quest_type,
is_global_player_quest,
is_bot_quest,
is_global_bot_quest,
is_merc_quest,
is_global_merc_quest,
is_global_npc_quest,
is_item_quest,
is_spell_quest,
package_name, package_name,
npc_mob, npc_mob,
mob, mob,
@@ -367,15 +334,7 @@ int PerlembParser::EventCommon(
/* Check for Mob export event enable */ /* Check for Mob export event enable */
if (parse->perl_event_export_settings[event_id].mob) { if (parse->perl_event_export_settings[event_id].mob) {
ExportMobVariables( ExportMobVariables(
is_player_quest, quest_type,
is_global_player_quest,
is_bot_quest,
is_global_bot_quest,
is_merc_quest,
is_global_merc_quest,
is_global_npc_quest,
is_item_quest,
is_spell_quest,
package_name, package_name,
mob, mob,
npc_mob npc_mob
@@ -397,19 +356,24 @@ int PerlembParser::EventCommon(
ExportEventVariables(package_name, event_id, object_id, data, npc_mob, inst, mob, extra_data, extra_pointers); ExportEventVariables(package_name, event_id, object_id, data, npc_mob, inst, mob, extra_data, extra_pointers);
} }
if (is_player_quest || is_global_player_quest) { if (quest_type == QuestType::Player || quest_type == QuestType::PlayerGlobal) {
return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, mob, mob, nullptr, nullptr); return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, mob, mob, nullptr, nullptr, nullptr);
} else if (is_bot_quest || is_global_bot_quest || is_merc_quest || is_global_merc_quest) { } else if (
return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, npc_mob, mob, nullptr, nullptr); quest_type == QuestType::Bot ||
} else if (is_item_quest) { quest_type == QuestType::BotGlobal ||
return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, mob, mob, inst, nullptr); quest_type == QuestType::Merc ||
} else if (is_spell_quest) { quest_type == QuestType::MercGlobal
) {
return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, npc_mob, mob, nullptr, nullptr, nullptr);
} else if (quest_type == QuestType::Item || quest_type == QuestType::ItemGlobal) {
return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, mob, mob, inst, nullptr, nullptr);
} else if (quest_type == QuestType::Spell || quest_type == QuestType::SpellGlobal) {
if (mob) { if (mob) {
return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, mob, mob, nullptr, spell); return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, mob, mob, nullptr, spell, nullptr);
} else { } else {
return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, npc_mob, mob, nullptr, spell); return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, npc_mob, mob, nullptr, spell, nullptr);
} }
} else { } else if (quest_type == QuestType::NPC || quest_type == QuestType::NPCGlobal) {
return SendCommands( return SendCommands(
package_name.c_str(), package_name.c_str(),
QuestEventSubroutines[event_id], QuestEventSubroutines[event_id],
@@ -417,8 +381,20 @@ int PerlembParser::EventCommon(
npc_mob, npc_mob,
mob, mob,
nullptr, nullptr,
nullptr,
nullptr nullptr
); );
} else if (quest_type == QuestType::Zone || quest_type == QuestType::ZoneGlobal) {
return SendCommands(
package_name.c_str(),
QuestEventSubroutines[event_id],
0,
nullptr,
nullptr,
nullptr,
nullptr,
zone
);
} }
} }
@@ -439,6 +415,7 @@ int PerlembParser::EventNPC(
nullptr, nullptr,
nullptr, nullptr,
mob, mob,
nullptr,
extra_data, extra_data,
false, false,
extra_pointers extra_pointers
@@ -462,6 +439,7 @@ int PerlembParser::EventGlobalNPC(
nullptr, nullptr,
nullptr, nullptr,
mob, mob,
nullptr,
extra_data, extra_data,
true, true,
extra_pointers extra_pointers
@@ -484,6 +462,7 @@ int PerlembParser::EventPlayer(
nullptr, nullptr,
nullptr, nullptr,
client, client,
nullptr,
extra_data, extra_data,
false, false,
extra_pointers extra_pointers
@@ -506,6 +485,7 @@ int PerlembParser::EventGlobalPlayer(
nullptr, nullptr,
nullptr, nullptr,
client, client,
nullptr,
extra_data, extra_data,
true, true,
extra_pointers extra_pointers
@@ -534,6 +514,7 @@ int PerlembParser::EventItem(
inst, inst,
nullptr, nullptr,
client, client,
nullptr,
extra_data, extra_data,
false, false,
extra_pointers extra_pointers
@@ -558,6 +539,7 @@ int PerlembParser::EventSpell(
nullptr, nullptr,
&spells[spell_id], &spells[spell_id],
client, client,
nullptr,
extra_data, extra_data,
false, false,
extra_pointers extra_pointers
@@ -1006,7 +988,8 @@ int PerlembParser::SendCommands(
Mob* other, Mob* other,
Mob* mob, Mob* mob,
EQ::ItemInstance* inst, EQ::ItemInstance* inst,
const SPDat_Spell_Struct* spell const SPDat_Spell_Struct* spell,
Zone* zone
) )
{ {
if (!perl) { if (!perl) {
@@ -1014,12 +997,22 @@ int PerlembParser::SendCommands(
} }
int ret_value = 0; int ret_value = 0;
RunningQuest q;
q.owner = other;
q.questitem = inst;
q.questspell = spell;
if (mob && mob->IsClient()) { if (mob && mob->IsClient()) {
quest_manager.StartQuest(other, mob->CastToClient(), inst, spell); q.initiator = mob->CastToClient();
} else {
quest_manager.StartQuest(other);
} }
if (zone) {
q.zone = zone;
}
quest_manager.StartQuest(q);
try { try {
perl->eval(fmt::format("package {};", prefix).c_str()); perl->eval(fmt::format("package {};", prefix).c_str());
@@ -1033,7 +1026,8 @@ int PerlembParser::SendCommands(
"merc", "merc",
"npc", "npc",
"questitem", "questitem",
"spell" "spell",
"zone"
}; };
for (const auto& suffix : suffixes) { for (const auto& suffix : suffixes) {
@@ -1058,6 +1052,7 @@ int PerlembParser::SendCommands(
sv_setsv(client, _empty_sv); sv_setsv(client, _empty_sv);
} }
if (other) {
if (other->IsBot()) { if (other->IsBot()) {
Bot* b = quest_manager.GetBot(); Bot* b = quest_manager.GetBot();
buf = fmt::format("{}::bot", prefix); buf = fmt::format("{}::bot", prefix);
@@ -1074,6 +1069,7 @@ int PerlembParser::SendCommands(
SV* npc = get_sv(buf.c_str(), true); SV* npc = get_sv(buf.c_str(), true);
sv_setref_pv(npc, "NPC", n); sv_setref_pv(npc, "NPC", n);
} }
}
//only export QuestItem if it's an inst quest //only export QuestItem if it's an inst quest
if (inst) { if (inst) {
@@ -1110,7 +1106,8 @@ int PerlembParser::SendCommands(
"merc", "merc",
"npc", "npc",
"questitem", "questitem",
"spell" "spell",
"zone"
}; };
for (const auto& suffix : suffixes) { for (const auto& suffix : suffixes) {
@@ -1192,20 +1189,12 @@ void PerlembParser::MapFunctions()
#endif // EMBPERL_XS_CLASSES #endif // EMBPERL_XS_CLASSES
} }
void PerlembParser::GetQuestTypes( QuestType PerlembParser::GetQuestTypes(
bool& is_player_quest,
bool& is_global_player_quest,
bool& is_bot_quest,
bool& is_global_bot_quest,
bool& is_merc_quest,
bool& is_global_merc_quest,
bool& is_global_npc_quest,
bool& is_item_quest,
bool& is_spell_quest,
QuestEventID event_id, QuestEventID event_id,
Mob* npc_mob, Mob* npc_mob,
EQ::ItemInstance* inst, EQ::ItemInstance* inst,
Mob* mob, Mob* mob,
Zone* zone,
bool is_global bool is_global
) )
{ {
@@ -1219,100 +1208,74 @@ void PerlembParser::GetQuestTypes(
event_id == EVENT_SPELL_FADE || event_id == EVENT_SPELL_FADE ||
event_id == EVENT_SPELL_EFFECT_TRANSLOCATE_COMPLETE event_id == EVENT_SPELL_EFFECT_TRANSLOCATE_COMPLETE
) { ) {
is_spell_quest = true; return is_global ? QuestType::SpellGlobal : QuestType::Spell;
} else { } else {
if (npc_mob) { if (npc_mob) {
if (!inst) { if (!inst) {
if (is_global) {
if (npc_mob->IsBot()) { if (npc_mob->IsBot()) {
is_global_bot_quest = true; return is_global ? QuestType::BotGlobal : QuestType::Bot;
} else if (npc_mob->IsMerc()) { } else if (npc_mob->IsMerc()) {
is_global_merc_quest = true; return is_global ? QuestType::MercGlobal : QuestType::Merc;
} else if (npc_mob->IsNPC()) {
return is_global ? QuestType::NPCGlobal : QuestType::NPC;
} }
} else { } else {
if (npc_mob->IsBot()) { return is_global ? QuestType::ItemGlobal : QuestType::Item;
is_bot_quest = true;
} else if (npc_mob->IsMerc()) {
is_merc_quest = true;
}
}
} else {
is_item_quest = true;
} }
} else if (!npc_mob && mob) { } else if (!npc_mob && mob) {
if (!inst) { if (!inst) {
if (is_global) {
if (mob->IsClient()) { if (mob->IsClient()) {
is_global_player_quest = true; return is_global ? QuestType::PlayerGlobal : QuestType::Player;
} }
} else { } else {
if (mob->IsClient()) { return is_global ? QuestType::ItemGlobal : QuestType::Item;
is_player_quest = true;
}
}
} else {
is_item_quest = true;
} }
} else if (zone) {
return is_global ? QuestType::ZoneGlobal : QuestType::Zone;
} }
} }
} }
void PerlembParser::GetQuestPackageName( std::string PerlembParser::GetQuestPackageName(
bool& is_player_quest, QuestType quest_type,
bool& is_global_player_quest,
bool& is_bot_quest,
bool& is_global_bot_quest,
bool& is_merc_quest,
bool& is_global_merc_quest,
bool& is_global_npc_quest,
bool& is_item_quest,
bool& is_spell_quest,
std::string& package_name,
QuestEventID event_id, QuestEventID event_id,
uint32 object_id, uint32 object_id,
const char* data, const char* data,
Mob* npc_mob, Mob* npc_mob,
EQ::ItemInstance* inst, EQ::ItemInstance* inst
bool is_global
) )
{ {
if ( if (quest_type == QuestType::NPC) {
!is_player_quest && return fmt::format("qst_npc_{}", npc_mob->GetNPCTypeID());
!is_global_player_quest && } else if (quest_type == QuestType::NPCGlobal) {
!is_bot_quest && return "qst_global_npc";
!is_global_bot_quest && } else if (quest_type == QuestType::Item || quest_type == QuestType::ItemGlobal) {
!is_merc_quest &&
!is_global_merc_quest &&
!is_item_quest &&
!is_spell_quest
) {
if (is_global) {
is_global_npc_quest = true;
package_name = "qst_global_npc";
} else {
package_name = fmt::format("qst_npc_{}", npc_mob->GetNPCTypeID());
}
} else if (is_item_quest) {
if (!inst) { if (!inst) {
return; return "";
} }
package_name = fmt::format("qst_item_{}", inst->GetID()); return fmt::format("qst_item_{}", inst->GetID());
} else if (is_player_quest) { } else if (quest_type == QuestType::Player) {
package_name = "qst_player"; return "qst_player";
} else if (is_global_player_quest) { } else if (quest_type == QuestType::PlayerGlobal) {
package_name = "qst_global_player"; return "qst_global_player";
} else if (is_bot_quest) { } else if (quest_type == QuestType::Bot) {
package_name = "qst_bot"; return "qst_bot";
} else if (is_global_bot_quest) { } else if (quest_type == QuestType::BotGlobal) {
package_name = "qst_global_bot"; return "qst_global_bot";
} else if (is_merc_quest) { } else if (quest_type == QuestType::Merc) {
package_name = "qst_merc"; return "qst_merc";
} else if (is_global_merc_quest) { } else if (quest_type == QuestType::MercGlobal) {
package_name = "qst_global_merc"; return "qst_global_merc";
} else { } else if (quest_type == QuestType::Spell || quest_type == QuestType::SpellGlobal) {
package_name = fmt::format("qst_spell_{}", object_id); return fmt::format("qst_spell_{}", object_id);
} else if (quest_type == QuestType::Zone) {
return "qst_zone";
} else if (quest_type == QuestType::ZoneGlobal) {
return "qst_global_zone";
} }
return "";
} }
void PerlembParser::ExportCharID(const std::string& package_name, int& char_id, Mob* npc_mob, Mob* mob) void PerlembParser::ExportCharID(const std::string& package_name, int& char_id, Mob* npc_mob, Mob* mob)
@@ -1331,15 +1294,7 @@ void PerlembParser::ExportCharID(const std::string& package_name, int& char_id,
} }
void PerlembParser::ExportQGlobals( void PerlembParser::ExportQGlobals(
bool is_player_quest, QuestType quest_type,
bool is_global_player_quest,
bool is_bot_quest,
bool is_global_bot_quest,
bool is_merc_quest,
bool is_global_merc_quest,
bool is_global_npc_quest,
bool is_item_quest,
bool is_spell_quest,
std::string& package_name, std::string& package_name,
Mob* npc_mob, Mob* npc_mob,
Mob* mob, Mob* mob,
@@ -1347,16 +1302,7 @@ void PerlembParser::ExportQGlobals(
) )
{ {
//NPC quest //NPC quest
if ( if (quest_type == QuestType::NPC || quest_type == QuestType::NPCGlobal) {
!is_player_quest &&
!is_global_player_quest &&
!is_bot_quest &&
!is_global_bot_quest &&
!is_merc_quest &&
!is_global_merc_quest &&
!is_item_quest &&
!is_spell_quest
) {
//only export for npcs that are global enabled. //only export for npcs that are global enabled.
if (npc_mob && npc_mob->GetQglobal()) { if (npc_mob && npc_mob->GetQglobal()) {
std::map<std::string, std::string> globhash; std::map<std::string, std::string> globhash;
@@ -1485,15 +1431,7 @@ void PerlembParser::ExportQGlobals(
} }
void PerlembParser::ExportMobVariables( void PerlembParser::ExportMobVariables(
bool is_player_quest, QuestType quest_type,
bool is_global_player_quest,
bool is_bot_quest,
bool is_global_bot_quest,
bool is_merc_quest,
bool is_global_merc_quest,
bool is_global_npc_quest,
bool is_item_quest,
bool is_spell_quest,
std::string& package_name, std::string& package_name,
Mob* mob, Mob* mob,
Mob* npc_mob Mob* npc_mob
@@ -1511,15 +1449,7 @@ void PerlembParser::ExportMobVariables(
ExportVar(package_name.c_str(), "bot_owner_char_id", mob->CastToBot()->GetBotOwnerCharacterID()); ExportVar(package_name.c_str(), "bot_owner_char_id", mob->CastToBot()->GetBotOwnerCharacterID());
} }
if ( if (quest_type == QuestType::NPC || quest_type == QuestType::NPCGlobal) {
!is_player_quest &&
!is_global_player_quest &&
!is_bot_quest &&
!is_global_bot_quest &&
!is_merc_quest &&
!is_global_merc_quest &&
!is_item_quest
) {
if (mob && mob->IsClient() && npc_mob && npc_mob->IsNPC()) { if (mob && mob->IsClient() && npc_mob && npc_mob->IsNPC()) {
Client* c = mob->CastToClient(); Client* c = mob->CastToClient();
@@ -1543,16 +1473,7 @@ void PerlembParser::ExportMobVariables(
ExportVar(package_name.c_str(), "userid", mob->GetID()); ExportVar(package_name.c_str(), "userid", mob->GetID());
} }
if ( if (quest_type == QuestType::NPC || quest_type == QuestType::NPCGlobal) {
!is_player_quest &&
!is_global_player_quest &&
!is_bot_quest &&
!is_global_bot_quest &&
!is_merc_quest &&
!is_global_merc_quest &&
!is_item_quest &&
!is_spell_quest
) {
if (npc_mob->IsNPC()) { if (npc_mob->IsNPC()) {
ExportVar(package_name.c_str(), "mname", npc_mob->GetName()); ExportVar(package_name.c_str(), "mname", npc_mob->GetName());
ExportVar(package_name.c_str(), "mobid", npc_mob->GetID()); ExportVar(package_name.c_str(), "mobid", npc_mob->GetID());
@@ -1758,10 +1679,14 @@ void PerlembParser::ExportEventVariables(
ExportVar(package_name.c_str(), "doorid", data); ExportVar(package_name.c_str(), "doorid", data);
ExportVar(package_name.c_str(), "version", zone->GetInstanceVersion()); ExportVar(package_name.c_str(), "version", zone->GetInstanceVersion());
if (extra_pointers && extra_pointers->size() == 1) { if (extra_pointers && extra_pointers->size() >= 1) {
ExportVar(package_name.c_str(), "door", "Doors", std::any_cast<Doors*>(extra_pointers->at(0))); ExportVar(package_name.c_str(), "door", "Doors", std::any_cast<Doors*>(extra_pointers->at(0)));
} }
if (extra_pointers && extra_pointers->size() == 2) {
ExportVar(package_name.c_str(), "player", "Client", std::any_cast<Client*>(extra_pointers->at(1)));
}
break; break;
} }
@@ -1782,10 +1707,14 @@ void PerlembParser::ExportEventVariables(
); );
} }
if (extra_pointers && extra_pointers->size() == 2) { if (extra_pointers && extra_pointers->size() >= 2) {
ExportVar(package_name.c_str(), "corpse", "Corpse", std::any_cast<Corpse*>(extra_pointers->at(1))); ExportVar(package_name.c_str(), "corpse", "Corpse", std::any_cast<Corpse*>(extra_pointers->at(1)));
} }
if (extra_pointers && extra_pointers->size() == 3) {
ExportVar(package_name.c_str(), "player", "Client", std::any_cast<Client*>(extra_pointers->at(2)));
}
break; break;
} }
@@ -1852,7 +1781,7 @@ void PerlembParser::ExportEventVariables(
ExportVar(package_name.c_str(), "picked_up_id", data); ExportVar(package_name.c_str(), "picked_up_id", data);
ExportVar(package_name.c_str(), "picked_up_entity_id", extra_data); ExportVar(package_name.c_str(), "picked_up_entity_id", extra_data);
if (extra_pointers && extra_pointers->size() == 1) { if (extra_pointers && extra_pointers->size() >= 1) {
ExportVar( ExportVar(
package_name.c_str(), package_name.c_str(),
"item", "item",
@@ -1861,6 +1790,10 @@ void PerlembParser::ExportEventVariables(
); );
} }
if (extra_pointers && extra_pointers->size() == 2) {
ExportVar(package_name.c_str(), "player", "Client", std::any_cast<Client*>(extra_pointers->at(1)));
}
break; break;
} }
@@ -1873,6 +1806,11 @@ void PerlembParser::ExportEventVariables(
case EVENT_POPUP_RESPONSE: { case EVENT_POPUP_RESPONSE: {
ExportVar(package_name.c_str(), "popupid", data); ExportVar(package_name.c_str(), "popupid", data);
if (extra_pointers && extra_pointers->size() == 1) {
ExportVar(package_name.c_str(), "player", "Client", std::any_cast<Client*>(extra_pointers->at(0)));
}
break; break;
} }
@@ -2036,10 +1974,14 @@ void PerlembParser::ExportEventVariables(
ExportVar(package_name.c_str(), "objectid", data); ExportVar(package_name.c_str(), "objectid", data);
ExportVar(package_name.c_str(), "clicker_id", extra_data); ExportVar(package_name.c_str(), "clicker_id", extra_data);
if (extra_pointers && extra_pointers->size() == 1) { if (extra_pointers && extra_pointers->size() >= 1) {
ExportVar(package_name.c_str(), "object", "Object", std::any_cast<Object*>(extra_pointers->at(0))); ExportVar(package_name.c_str(), "object", "Object", std::any_cast<Object*>(extra_pointers->at(0)));
} }
if (extra_pointers && extra_pointers->size() == 2) {
ExportVar(package_name.c_str(), "player", "Client", std::any_cast<Client*>(extra_pointers->at(1)));
}
break; break;
} }
@@ -2115,6 +2057,13 @@ void PerlembParser::ExportEventVariables(
ExportVar(package_name.c_str(), "killed_npc_id", !killed->IsMerc() && killed->IsNPC() ? killed->GetNPCTypeID() : 0); ExportVar(package_name.c_str(), "killed_npc_id", !killed->IsMerc() && killed->IsNPC() ? killed->GetNPCTypeID() : 0);
} }
} }
if (extra_pointers && extra_pointers->size() == 3) {
Mob* killer = std::any_cast<Mob*>(extra_pointers->at(2));
if (killer) {
ExportVar(package_name.c_str(), "killer", "Mob", killer);
}
}
break; break;
} }
@@ -2142,10 +2091,21 @@ void PerlembParser::ExportEventVariables(
} }
case EVENT_SPAWN_ZONE: { case EVENT_SPAWN_ZONE: {
ExportVar(package_name.c_str(), "spawned_entity_id", mob->GetID()); if (mob) {
ExportVar(package_name.c_str(), "spawned_bot_id", mob->IsBot() ? mob->CastToBot()->GetBotID() : 0);
ExportVar(package_name.c_str(), "spawned_npc_id", mob->IsNPC() ? mob->GetNPCTypeID() : 0);
ExportVar(package_name.c_str(), "spawned", "Mob", mob); ExportVar(package_name.c_str(), "spawned", "Mob", mob);
ExportVar(package_name.c_str(), "spawned_bot_id", mob->IsBot() ? mob->CastToBot()->GetBotID() : 0);
ExportVar(package_name.c_str(), "spawned_entity_id", mob->GetID());
ExportVar(package_name.c_str(), "spawned_npc_id", mob->IsNPC() ? mob->GetNPCTypeID() : 0);
}
if (extra_pointers && extra_pointers->size() == 1) {
NPC* spawn_npc = std::any_cast<NPC*>(extra_pointers->at(0));
ExportVar(package_name.c_str(), "spawned", "NPC", spawn_npc);
ExportVar(package_name.c_str(), "spawned_bot_id", spawn_npc->IsBot() ? spawn_npc->CastToBot()->GetBotID() : 0);
ExportVar(package_name.c_str(), "spawned_entity_id", spawn_npc->GetID());
ExportVar(package_name.c_str(), "spawned_npc_id", spawn_npc->IsNPC() ? spawn_npc->GetNPCTypeID() : 0);
}
break; break;
} }
@@ -2386,6 +2346,7 @@ void PerlembParser::ExportEventVariables(
} }
case EVENT_DESPAWN: { case EVENT_DESPAWN: {
ExportVar(package_name.c_str(), "despawned", "Mob", npc_mob);
ExportVar(package_name.c_str(), "despawned_entity_id", npc_mob->GetID()); ExportVar(package_name.c_str(), "despawned_entity_id", npc_mob->GetID());
ExportVar(package_name.c_str(), "despawned_bot_id", npc_mob->IsBot() ? npc_mob->CastToBot()->GetBotID() : 0); ExportVar(package_name.c_str(), "despawned_bot_id", npc_mob->IsBot() ? npc_mob->CastToBot()->GetBotID() : 0);
ExportVar(package_name.c_str(), "despawned_merc_id", npc_mob->IsMerc() ? npc_mob->CastToMerc()->GetMercenaryID() : 0); ExportVar(package_name.c_str(), "despawned_merc_id", npc_mob->IsMerc() ? npc_mob->CastToMerc()->GetMercenaryID() : 0);
@@ -2394,9 +2355,21 @@ void PerlembParser::ExportEventVariables(
} }
case EVENT_DESPAWN_ZONE: { case EVENT_DESPAWN_ZONE: {
ExportVar(package_name.c_str(), "despawned_entity_id", mob->GetID()); if (mob) {
ExportVar(package_name.c_str(), "despawned", "Mob", mob);
ExportVar(package_name.c_str(), "despawned_bot_id", mob->IsBot() ? mob->CastToBot()->GetBotID() : 0); ExportVar(package_name.c_str(), "despawned_bot_id", mob->IsBot() ? mob->CastToBot()->GetBotID() : 0);
ExportVar(package_name.c_str(), "despawned_entity_id", mob->GetID());
ExportVar(package_name.c_str(), "despawned_npc_id", mob->IsNPC() ? mob->GetNPCTypeID() : 0); ExportVar(package_name.c_str(), "despawned_npc_id", mob->IsNPC() ? mob->GetNPCTypeID() : 0);
}
if (extra_pointers && extra_pointers->size() == 1) {
NPC* spawn_npc = std::any_cast<NPC*>(extra_pointers->at(0));
ExportVar(package_name.c_str(), "despawned", "NPC", spawn_npc);
ExportVar(package_name.c_str(), "despawned_bot_id", spawn_npc->IsBot() ? spawn_npc->CastToBot()->GetBotID() : 0);
ExportVar(package_name.c_str(), "despawned_entity_id", spawn_npc->GetID());
ExportVar(package_name.c_str(), "despawned_npc_id", spawn_npc->IsNPC() ? spawn_npc->GetNPCTypeID() : 0);
}
break; break;
} }
@@ -2551,6 +2524,14 @@ void PerlembParser::ExportEventVariables(
break; break;
} }
case EVENT_ENTER_ZONE: {
if (extra_pointers && extra_pointers->size() == 1) {
ExportVar(package_name.c_str(), "player", "Client", std::any_cast<Client*>(extra_pointers->at(0)));
}
break;
}
default: { default: {
break; break;
} }
@@ -2648,6 +2629,7 @@ int PerlembParser::EventBot(
nullptr, nullptr,
nullptr, nullptr,
mob, mob,
nullptr,
extra_data, extra_data,
false, false,
extra_pointers extra_pointers
@@ -2671,6 +2653,7 @@ int PerlembParser::EventGlobalBot(
nullptr, nullptr,
nullptr, nullptr,
mob, mob,
nullptr,
extra_data, extra_data,
true, true,
extra_pointers extra_pointers
@@ -2768,6 +2751,7 @@ int PerlembParser::EventMerc(
nullptr, nullptr,
nullptr, nullptr,
mob, mob,
nullptr,
extra_data, extra_data,
false, false,
extra_pointers extra_pointers
@@ -2791,6 +2775,127 @@ int PerlembParser::EventGlobalMerc(
nullptr, nullptr,
nullptr, nullptr,
mob, mob,
nullptr,
extra_data,
true,
extra_pointers
);
}
void PerlembParser::LoadZoneScript(std::string filename)
{
if (!perl || zone_quest_status_ != questUnloaded) {
return;
}
try {
perl->eval_file("qst_zone", filename.c_str());
} catch (std::string e) {
AddError(
fmt::format(
"Error Compiling Zone Quest File [{}] Error [{}]",
filename,
e
)
);
zone_quest_status_ = questFailedToLoad;
return;
}
zone_quest_status_ = questLoaded;
}
void PerlembParser::LoadGlobalZoneScript(std::string filename)
{
if (!perl || global_zone_quest_status_ != questUnloaded) {
return;
}
try {
perl->eval_file("qst_global_zone", filename.c_str());
} catch (std::string e) {
AddError(
fmt::format(
"Error Compiling Global Zone Quest File [{}] Error [{}]",
filename,
e
)
);
global_zone_quest_status_ = questFailedToLoad;
return;
}
global_zone_quest_status_ = questLoaded;
}
bool PerlembParser::ZoneHasQuestSub(QuestEventID event_id)
{
if (
!perl ||
zone_quest_status_ != questLoaded ||
event_id >= _LargestEventID
) {
return false;
}
return perl->SubExists("qst_zone", QuestEventSubroutines[event_id]);
}
bool PerlembParser::GlobalZoneHasQuestSub(QuestEventID event_id)
{
if (
!perl ||
global_zone_quest_status_ != questLoaded ||
event_id >= _LargestEventID
) {
return false;
}
return perl->SubExists("qst_global_zone", QuestEventSubroutines[event_id]);
}
int PerlembParser::EventZone(
QuestEventID event_id,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any>* extra_pointers
)
{
return EventCommon(
event_id,
0,
data.c_str(),
nullptr,
nullptr,
nullptr,
nullptr,
zone,
extra_data,
false,
extra_pointers
);
}
int PerlembParser::EventGlobalZone(
QuestEventID event_id,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any>* extra_pointers
)
{
return EventCommon(
event_id,
0,
data.c_str(),
nullptr,
nullptr,
nullptr,
nullptr,
zone,
extra_data, extra_data,
true, true,
extra_pointers extra_pointers
+49 -42
View File
@@ -41,6 +41,23 @@ typedef enum {
questFailedToLoad questFailedToLoad
} PerlQuestStatus; } PerlQuestStatus;
enum class QuestType {
Bot,
BotGlobal,
Item,
ItemGlobal,
Merc,
MercGlobal,
NPC,
NPCGlobal,
Player,
PlayerGlobal,
Spell,
SpellGlobal,
Zone,
ZoneGlobal
};
class PerlembParser : public QuestInterface { class PerlembParser : public QuestInterface {
public: public:
PerlembParser(); PerlembParser();
@@ -136,6 +153,22 @@ public:
std::vector<std::any>* extra_pointers std::vector<std::any>* extra_pointers
); );
virtual int EventZone(
QuestEventID event_id,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any>* extra_pointers
);
virtual int EventGlobalZone(
QuestEventID event_id,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any>* extra_pointers
);
virtual bool HasQuestSub(uint32 npc_id, QuestEventID event_id); virtual bool HasQuestSub(uint32 npc_id, QuestEventID event_id);
virtual bool HasGlobalQuestSub(QuestEventID event_id); virtual bool HasGlobalQuestSub(QuestEventID event_id);
virtual bool PlayerHasQuestSub(QuestEventID event_id); virtual bool PlayerHasQuestSub(QuestEventID event_id);
@@ -146,6 +179,8 @@ public:
virtual bool GlobalBotHasQuestSub(QuestEventID event_id); virtual bool GlobalBotHasQuestSub(QuestEventID event_id);
virtual bool MercHasQuestSub(QuestEventID event_id); virtual bool MercHasQuestSub(QuestEventID event_id);
virtual bool GlobalMercHasQuestSub(QuestEventID event_id); virtual bool GlobalMercHasQuestSub(QuestEventID event_id);
virtual bool ZoneHasQuestSub(QuestEventID event_id);
virtual bool GlobalZoneHasQuestSub(QuestEventID event_id);
virtual void LoadNPCScript(std::string filename, int npc_id); virtual void LoadNPCScript(std::string filename, int npc_id);
virtual void LoadGlobalNPCScript(std::string filename); virtual void LoadGlobalNPCScript(std::string filename);
@@ -157,6 +192,8 @@ public:
virtual void LoadGlobalBotScript(std::string filename); virtual void LoadGlobalBotScript(std::string filename);
virtual void LoadMercScript(std::string filename); virtual void LoadMercScript(std::string filename);
virtual void LoadGlobalMercScript(std::string filename); virtual void LoadGlobalMercScript(std::string filename);
virtual void LoadZoneScript(std::string filename);
virtual void LoadGlobalZoneScript(std::string filename);
virtual void AddVar(std::string name, std::string val); virtual void AddVar(std::string name, std::string val);
virtual std::string GetVar(std::string name); virtual std::string GetVar(std::string name);
@@ -182,6 +219,7 @@ private:
EQ::ItemInstance* inst, EQ::ItemInstance* inst,
const SPDat_Spell_Struct* spell, const SPDat_Spell_Struct* spell,
Mob* mob, Mob* mob,
Zone* zone,
uint32 extra_data, uint32 extra_data,
bool is_global, bool is_global,
std::vector<std::any>* extra_pointers std::vector<std::any>* extra_pointers
@@ -194,59 +232,34 @@ private:
Mob* other, Mob* other,
Mob* mob, Mob* mob,
EQ::ItemInstance* inst, EQ::ItemInstance* inst,
const SPDat_Spell_Struct* spell const SPDat_Spell_Struct* spell,
Zone* zone
); );
void MapFunctions(); void MapFunctions();
void GetQuestTypes( QuestType GetQuestTypes(
bool& is_player_quest,
bool& is_global_player_quest,
bool& is_bot_quest,
bool& is_global_bot_quest,
bool& is_merc_quest,
bool& is_global_merc_quest,
bool& is_global_npc_quest,
bool& is_item_quest,
bool& is_spell_quest,
QuestEventID event, QuestEventID event,
Mob* npc_mob, Mob* npc_mob,
EQ::ItemInstance* inst, EQ::ItemInstance* inst,
Mob* mob, Mob* mob,
Zone* zone,
bool is_global bool is_global
); );
void GetQuestPackageName( std::string GetQuestPackageName(
bool& is_player_quest, QuestType quest_type,
bool& is_global_player_quest,
bool& is_bot_quest,
bool& is_global_bot_quest,
bool& is_merc_quest,
bool& is_global_merc_quest,
bool& is_global_npc_quest,
bool& is_item_quest,
bool& is_spell_quest,
std::string& package_name,
QuestEventID event, QuestEventID event,
uint32 object_id, uint32 object_id,
const char* data, const char* data,
Mob* npc_mob, Mob* npc_mob,
EQ::ItemInstance* inst, EQ::ItemInstance* inst
bool is_global
); );
void ExportCharID(const std::string& package_name, int& char_id, Mob* npc_mob, Mob* mob); void ExportCharID(const std::string& package_name, int& char_id, Mob* npc_mob, Mob* mob);
void ExportQGlobals( void ExportQGlobals(
bool is_player_quest, QuestType quest_type,
bool is_global_player_quest,
bool is_bot_quest,
bool is_global_bot_quest,
bool is_merc_quest,
bool is_global_merc_quest,
bool is_global_npc_quest,
bool is_item_quest,
bool is_spell_quest,
std::string& package_name, std::string& package_name,
Mob* npc_mob, Mob* npc_mob,
Mob* mob, Mob* mob,
@@ -254,15 +267,7 @@ private:
); );
void ExportMobVariables( void ExportMobVariables(
bool is_player_quest, QuestType quest_type,
bool is_global_player_quest,
bool is_bot_quest,
bool is_global_bot_quest,
bool is_merc_quest,
bool is_global_merc_quest,
bool is_global_npc_quest,
bool is_item_quest,
bool is_spell_quest,
std::string& package_name, std::string& package_name,
Mob* mob, Mob* mob,
Mob* npc_mob Mob* npc_mob
@@ -295,6 +300,8 @@ private:
PerlQuestStatus global_bot_quest_status_; PerlQuestStatus global_bot_quest_status_;
PerlQuestStatus merc_quest_status_; PerlQuestStatus merc_quest_status_;
PerlQuestStatus global_merc_quest_status_; PerlQuestStatus global_merc_quest_status_;
PerlQuestStatus zone_quest_status_;
PerlQuestStatus global_zone_quest_status_;
SV* _empty_sv; SV* _empty_sv;
+36
View File
@@ -6005,6 +6005,40 @@ bool Perl__handin(perl::reference handin_ref)
return quest_manager.handin(handin_map); return quest_manager.handin(handin_map);
} }
perl::array Perl__get_paused_timers(Mob* m)
{
perl::array a;
const auto& l = quest_manager.GetPausedTimers(m);
if (!l.empty()) {
a.reserve(l.size());
for (const auto& v : l) {
a.push_back(v);
}
}
return a;
}
perl::array Perl__get_timers(Mob* m)
{
perl::array a;
const auto& l = quest_manager.GetTimers(m);
if (!l.empty()) {
a.reserve(l.size());
for (const auto& v: l) {
a.push_back(v);
}
}
return a;
}
void perl_register_quest() void perl_register_quest()
{ {
perl::interpreter perl(PERL_GET_THX); perl::interpreter perl(PERL_GET_THX);
@@ -6694,6 +6728,7 @@ void perl_register_quest()
package.add("getguildidbycharid", &Perl__getguildidbycharid); package.add("getguildidbycharid", &Perl__getguildidbycharid);
package.add("getgroupidbycharid", &Perl__getgroupidbycharid); package.add("getgroupidbycharid", &Perl__getgroupidbycharid);
package.add("getinventoryslotname", &Perl__getinventoryslotname); package.add("getinventoryslotname", &Perl__getinventoryslotname);
package.add("get_paused_timers", &Perl__get_paused_timers);
package.add("getraididbycharid", &Perl__getraididbycharid); package.add("getraididbycharid", &Perl__getraididbycharid);
package.add("get_race_bitmask", &Perl__get_race_bitmask); package.add("get_race_bitmask", &Perl__get_race_bitmask);
package.add("get_recipe_component_item_ids", &Perl__GetRecipeComponentItemIDs); package.add("get_recipe_component_item_ids", &Perl__GetRecipeComponentItemIDs);
@@ -6713,6 +6748,7 @@ void perl_register_quest()
package.add("getspellstat", (int(*)(uint32, std::string))&Perl__getspellstat); package.add("getspellstat", (int(*)(uint32, std::string))&Perl__getspellstat);
package.add("getspellstat", (int(*)(uint32, std::string, uint8))&Perl__getspellstat); package.add("getspellstat", (int(*)(uint32, std::string, uint8))&Perl__getspellstat);
package.add("getskillname", &Perl__getskillname); package.add("getskillname", &Perl__getskillname);
package.add("get_timers", &Perl__get_timers);
package.add("getlevel", &Perl__getlevel); package.add("getlevel", &Perl__getlevel);
package.add("getplayerburiedcorpsecount", &Perl__getplayerburiedcorpsecount); package.add("getplayerburiedcorpsecount", &Perl__getplayerburiedcorpsecount);
package.add("getplayercorpsecount", &Perl__getplayercorpsecount); package.add("getplayercorpsecount", &Perl__getplayercorpsecount);
+5
View File
@@ -743,6 +743,11 @@ void EntityList::AddNPC(NPC *npc, bool send_spawn_packet, bool dont_queue)
npc->DispatchZoneControllerEvent(EVENT_SPAWN_ZONE, npc, "", 0, nullptr); npc->DispatchZoneControllerEvent(EVENT_SPAWN_ZONE, npc, "", 0, nullptr);
} }
if (parse->ZoneHasQuestSub(EVENT_SPAWN_ZONE)) {
std::vector<std::any> args = { npc };
parse->EventZone(EVENT_SPAWN_ZONE, zone, "", 0, &args);
}
if (zone->HasMap() && zone->HasWaterMap()) { if (zone->HasMap() && zone->HasWaterMap()) {
npc->SetSpawnedInWater(false); npc->SetSpawnedInWater(false);
if (zone->watermap->InLiquid(npc->GetPosition())) { if (zone->watermap->InLiquid(npc->GetPosition())) {
+5 -5
View File
@@ -4,9 +4,9 @@
void FindCharacter(Client *c, const Seperator *sep) void FindCharacter(Client *c, const Seperator *sep)
{ {
if (sep->IsNumber(2)) { 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) { if (!e.id) {
c->Message( c->Message(
Chat::White, Chat::White,
@@ -31,10 +31,10 @@ void FindCharacter(Client *c, const Seperator *sep)
return; 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( const auto& l = CharacterDataRepository::GetWhere(
content_db, database,
fmt::format( fmt::format(
"LOWER(`name`) LIKE '%%{}%%' AND `name` NOT LIKE '%-deleted-%' ORDER BY `id` ASC LIMIT 50", "LOWER(`name`) LIKE '%%{}%%' AND `name` NOT LIKE '%-deleted-%' ORDER BY `id` ASC LIMIT 50",
search_criteria 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) { for (const auto& e : l) {
c->Message( c->Message(
+2
View File
@@ -15,6 +15,7 @@
#include "show/group_info.cpp" #include "show/group_info.cpp"
#include "show/hatelist.cpp" #include "show/hatelist.cpp"
#include "show/inventory.cpp" #include "show/inventory.cpp"
#include "show/keyring.cpp"
#include "show/ip_lookup.cpp" #include "show/ip_lookup.cpp"
#include "show/line_of_sight.cpp" #include "show/line_of_sight.cpp"
#include "show/network.cpp" #include "show/network.cpp"
@@ -78,6 +79,7 @@ void command_show(Client *c, const Seperator *sep)
Cmd{.cmd = "hatelist", .u = "hatelist", .fn = ShowHateList, .a = {"#hatelist"}}, Cmd{.cmd = "hatelist", .u = "hatelist", .fn = ShowHateList, .a = {"#hatelist"}},
Cmd{.cmd = "inventory", .u = "inventory", .fn = ShowInventory, .a = {"#peekinv"}}, Cmd{.cmd = "inventory", .u = "inventory", .fn = ShowInventory, .a = {"#peekinv"}},
Cmd{.cmd = "ip_lookup", .u = "ip_lookup", .fn = ShowIPLookup, .a = {"#iplookup"}}, Cmd{.cmd = "ip_lookup", .u = "ip_lookup", .fn = ShowIPLookup, .a = {"#iplookup"}},
Cmd{.cmd = "keyring", .u = "keyring", .fn = ShowKeyring, .a = {"#showkeyring"}},
Cmd{.cmd = "line_of_sight", .u = "line_of_sight", .fn = ShowLineOfSight, .a = {"#checklos"}}, Cmd{.cmd = "line_of_sight", .u = "line_of_sight", .fn = ShowLineOfSight, .a = {"#checklos"}},
Cmd{.cmd = "network", .u = "network", .fn = ShowNetwork, .a = {"#network"}}, Cmd{.cmd = "network", .u = "network", .fn = ShowNetwork, .a = {"#network"}},
Cmd{.cmd = "network_stats", .u = "network_stats", .fn = ShowNetworkStats, .a = {"#netstats"}}, Cmd{.cmd = "network_stats", .u = "network_stats", .fn = ShowNetworkStats, .a = {"#netstats"}},
+12
View File
@@ -0,0 +1,12 @@
#include "../../client.h"
#include "../../dialogue_window.h"
void ShowKeyring(Client *c, const Seperator *sep)
{
Client* t = c;
if (c->GetTarget() && c->GetTarget()->IsClient()) {
t = c->GetTarget()->CastToClient();
}
t->KeyRingList(c);
}
+48 -4
View File
@@ -2474,17 +2474,61 @@ bool Group::AmIPuller(const char *mob_name)
bool Group::HasRole(Mob* m, uint8 Role) bool Group::HasRole(Mob* m, uint8 Role)
{ {
if(!m) if (!m) {
return false; return false;
}
for(uint32 i = 0; i < MAX_GROUP_MEMBERS; ++i) for (uint32 i = 0; i < MAX_GROUP_MEMBERS; ++i) {
{ if (m == members[i] && MemberRoles[i] & Role) {
if((m == members[i]) && (MemberRoles[i] & Role))
return true; return true;
} }
}
return false; return false;
} }
uint8 Group::GetMemberRole(Mob* m)
{
if (!m) {
return 0;
}
for (uint32 i = 0; i < MAX_GROUP_MEMBERS; ++i) {
if (m == members[i]) {
uint8 role = MemberRoles[i];
if (m == leader) {
role |= RoleLeader;
}
return role;
}
}
return 0;
}
uint8 Group::GetMemberRole(const char* name)
{
if (!name) {
return 0;
}
for (uint32 i = 0; i < MAX_GROUP_MEMBERS; ++i) {
if (!strcasecmp(membername[i], name)) {
uint8 role = MemberRoles[i];
if (leader && !strcasecmp(leader->GetName(), name)) {
role |= RoleLeader;
}
return role;
}
}
return 0;
}
void Group::QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_required /*= true*/, bool ignore_sender /*= true*/, float distance /*= 0*/) { void Group::QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_required /*= true*/, bool ignore_sender /*= true*/, float distance /*= 0*/) {
if (sender && sender->IsClient()) { if (sender && sender->IsClient()) {
for (uint32 i = 0; i < MAX_GROUP_MEMBERS; i++) { for (uint32 i = 0; i < MAX_GROUP_MEMBERS; i++) {
+8 -1
View File
@@ -30,7 +30,12 @@ class Mob;
#define MAX_MARKED_NPCS 3 #define MAX_MARKED_NPCS 3
enum { RoleAssist = 1, RoleTank = 2, RolePuller = 4 }; enum {
RoleAssist = 1,
RoleTank = 2,
RolePuller = 4,
RoleLeader = 8
};
class GroupIDConsumer { class GroupIDConsumer {
public: public:
@@ -119,6 +124,8 @@ public:
void SetGroupTankTarget(Mob *m); void SetGroupTankTarget(Mob *m);
void SetGroupPullerTarget(Mob *m); void SetGroupPullerTarget(Mob *m);
bool HasRole(Mob *m, uint8 Role); bool HasRole(Mob *m, uint8 Role);
uint8 GetMemberRole(Mob* m);
uint8 GetMemberRole(const char* name);
void NotifyAssistTarget(Client *c); void NotifyAssistTarget(Client *c);
void NotifyTankTarget(Client *c); void NotifyTankTarget(Client *c);
void NotifyPullerTarget(Client *c); void NotifyPullerTarget(Client *c);
+8 -1
View File
@@ -3575,7 +3575,13 @@ bool Lua_Client::KeyRingClear()
void Lua_Client::KeyRingList() void Lua_Client::KeyRingList()
{ {
Lua_Safe_Call_Void(); Lua_Safe_Call_Void();
self->KeyRingList(); self->KeyRingList(self);
}
void Lua_Client::KeyRingList(Lua_Client c)
{
Lua_Safe_Call_Void();
self->KeyRingList(self);
} }
bool Lua_Client::KeyRingRemove(uint32 item_id) bool Lua_Client::KeyRingRemove(uint32 item_id)
@@ -3932,6 +3938,7 @@ luabind::scope lua_register_client() {
.def("KeyRingCheck", (bool(Lua_Client::*)(uint32))&Lua_Client::KeyRingCheck) .def("KeyRingCheck", (bool(Lua_Client::*)(uint32))&Lua_Client::KeyRingCheck)
.def("KeyRingClear", (bool(Lua_Client::*)(void))&Lua_Client::KeyRingClear) .def("KeyRingClear", (bool(Lua_Client::*)(void))&Lua_Client::KeyRingClear)
.def("KeyRingList", (void(Lua_Client::*)(void))&Lua_Client::KeyRingList) .def("KeyRingList", (void(Lua_Client::*)(void))&Lua_Client::KeyRingList)
.def("KeyRingList", (void(Lua_Client::*)(Lua_Client))&Lua_Client::KeyRingList)
.def("KeyRingRemove", (bool(Lua_Client::*)(uint32))&Lua_Client::KeyRingRemove) .def("KeyRingRemove", (bool(Lua_Client::*)(uint32))&Lua_Client::KeyRingRemove)
.def("Kick", (void(Lua_Client::*)(void))&Lua_Client::Kick) .def("Kick", (void(Lua_Client::*)(void))&Lua_Client::Kick)
.def("LearnDisciplines", (uint16(Lua_Client::*)(uint8,uint8))&Lua_Client::LearnDisciplines) .def("LearnDisciplines", (uint16(Lua_Client::*)(uint8,uint8))&Lua_Client::LearnDisciplines)
+1
View File
@@ -521,6 +521,7 @@ public:
bool KeyRingCheck(uint32 item_id); bool KeyRingCheck(uint32 item_id);
bool KeyRingClear(); bool KeyRingClear();
void KeyRingList(); void KeyRingList();
void KeyRingList(Lua_Client c);
bool KeyRingRemove(uint32 item_id); bool KeyRingRemove(uint32 item_id);
bool CompleteTask(int task_id); bool CompleteTask(int task_id);
bool UncompleteTask(int task_id); bool UncompleteTask(int task_id);
+28
View File
@@ -5675,6 +5675,32 @@ bool lua_handin(luabind::adl::object handin_table)
return quest_manager.handin(handin_map); return quest_manager.handin(handin_map);
} }
luabind::object lua_get_paused_timers(lua_State* L, Mob* m) {
auto t = luabind::newtable(L);
auto v = quest_manager.GetPausedTimers(m);
int i = 1;
for (const auto& e : v) {
t[i] = e;
i++;
}
return t;
}
luabind::object lua_get_timers(lua_State* L, Mob* m) {
auto t = luabind::newtable(L);
auto v = quest_manager.GetTimers(m);
int i = 1;
for (const auto& e : v) {
t[i] = e;
i++;
}
return t;
}
#define LuaCreateNPCParse(name, c_type, default_value) do { \ #define LuaCreateNPCParse(name, c_type, default_value) do { \
cur = table[#name]; \ cur = table[#name]; \
if(luabind::type(cur) != LUA_TNIL) { \ if(luabind::type(cur) != LUA_TNIL) { \
@@ -6486,6 +6512,8 @@ luabind::scope lua_register_general() {
luabind::def("spawn_grid", &lua_spawn_grid), luabind::def("spawn_grid", &lua_spawn_grid),
luabind::def("get_zone", &lua_get_zone), luabind::def("get_zone", &lua_get_zone),
luabind::def("handin", &lua_handin), luabind::def("handin", &lua_handin),
luabind::def("get_paused_timers", &lua_get_paused_timers),
luabind::def("get_timers", &lua_get_timers),
/* /*
Cross Zone Cross Zone
*/ */
+12
View File
@@ -122,6 +122,16 @@ Lua_Mob Lua_Group::GetMember(int member_index) {
return self->members[member_index]; return self->members[member_index];
} }
uint8 Lua_Group::GetMemberRole(Lua_Mob member) {
Lua_Safe_Call_Int();
return self->GetMemberRole(member);
}
uint8 Lua_Group::GetMemberRole(const char* name) {
Lua_Safe_Call_Int();
return self->GetMemberRole(name);
}
bool Lua_Group::DoesAnyMemberHaveExpeditionLockout(std::string expedition_name, std::string event_name) bool Lua_Group::DoesAnyMemberHaveExpeditionLockout(std::string expedition_name, std::string event_name)
{ {
Lua_Safe_Call_Bool(); Lua_Safe_Call_Bool();
@@ -155,6 +165,8 @@ luabind::scope lua_register_group() {
.def("GetLeaderName", (const char*(Lua_Group::*)(void))&Lua_Group::GetLeaderName) .def("GetLeaderName", (const char*(Lua_Group::*)(void))&Lua_Group::GetLeaderName)
.def("GetLowestLevel", (uint32(Lua_Group::*)(void))&Lua_Group::GetLowestLevel) .def("GetLowestLevel", (uint32(Lua_Group::*)(void))&Lua_Group::GetLowestLevel)
.def("GetMember", (Lua_Mob(Lua_Group::*)(int))&Lua_Group::GetMember) .def("GetMember", (Lua_Mob(Lua_Group::*)(int))&Lua_Group::GetMember)
.def("GetMemberRole", (uint8(Lua_Group::*)(Lua_Mob))&Lua_Group::GetMemberRole)
.def("GetMemberRole", (uint8(Lua_Group::*)(const char*))&Lua_Group::GetMemberRole)
.def("GetTotalGroupDamage", (uint32(Lua_Group::*)(Lua_Mob))&Lua_Group::GetTotalGroupDamage) .def("GetTotalGroupDamage", (uint32(Lua_Group::*)(Lua_Mob))&Lua_Group::GetTotalGroupDamage)
.def("GroupCount", (int(Lua_Group::*)(void))&Lua_Group::GroupCount) .def("GroupCount", (int(Lua_Group::*)(void))&Lua_Group::GroupCount)
.def("GroupMessage", (void(Lua_Group::*)(Lua_Mob,const char*))&Lua_Group::GroupMessage) .def("GroupMessage", (void(Lua_Group::*)(Lua_Mob,const char*))&Lua_Group::GroupMessage)
+2
View File
@@ -49,6 +49,8 @@ public:
void TeleportGroup(Lua_Mob sender, uint32 zone_id, uint32 instance_id, float x, float y, float z, float h); void TeleportGroup(Lua_Mob sender, uint32 zone_id, uint32 instance_id, float x, float y, float z, float h);
int GetID(); int GetID();
Lua_Mob GetMember(int member_index); Lua_Mob GetMember(int member_index);
uint8 GetMemberRole(Lua_Mob member);
uint8 GetMemberRole(const char* name);
bool DoesAnyMemberHaveExpeditionLockout(std::string expedition_name, std::string event_name); bool DoesAnyMemberHaveExpeditionLockout(std::string expedition_name, std::string event_name);
bool DoesAnyMemberHaveExpeditionLockout(std::string expedition_name, std::string event_name, int max_check_count); bool DoesAnyMemberHaveExpeditionLockout(std::string expedition_name, std::string event_name, int max_check_count);
}; };
+32
View File
@@ -3482,6 +3482,36 @@ void Lua_Mob::BuffFadeSongs()
self->BuffFadeSongs(); self->BuffFadeSongs();
} }
luabind::object Lua_Mob::GetPausedTimers(lua_State* L) {
auto t = luabind::newtable(L);
if (d_) {
auto self = reinterpret_cast<NativeType*>(d_);
auto l = quest_manager.GetPausedTimers(self);
int i = 1;
for (const auto& v : l) {
t[i] = v;
i++;
}
}
return t;
}
luabind::object Lua_Mob::GetTimers(lua_State* L) {
auto t = luabind::newtable(L);
if (d_) {
auto self = reinterpret_cast<NativeType*>(d_);
auto l = quest_manager.GetTimers(self);
int i = 1;
for (const auto& v : l) {
t[i] = v;
i++;
}
}
return t;
}
luabind::scope lua_register_mob() { luabind::scope lua_register_mob() {
return luabind::class_<Lua_Mob, Lua_Entity>("Mob") return luabind::class_<Lua_Mob, Lua_Entity>("Mob")
.def(luabind::constructor<>()) .def(luabind::constructor<>())
@@ -3822,6 +3852,7 @@ luabind::scope lua_register_mob() {
.def("GetOwner", &Lua_Mob::GetOwner) .def("GetOwner", &Lua_Mob::GetOwner)
.def("GetOwnerID", &Lua_Mob::GetOwnerID) .def("GetOwnerID", &Lua_Mob::GetOwnerID)
.def("GetPR", &Lua_Mob::GetPR) .def("GetPR", &Lua_Mob::GetPR)
.def("GetPausedTimers", &Lua_Mob::GetPausedTimers)
.def("GetPet", &Lua_Mob::GetPet) .def("GetPet", &Lua_Mob::GetPet)
.def("GetPetOrder", (int(Lua_Mob::*)(void))&Lua_Mob::GetPetOrder) .def("GetPetOrder", (int(Lua_Mob::*)(void))&Lua_Mob::GetPetOrder)
.def("GetPhR", &Lua_Mob::GetPhR) .def("GetPhR", &Lua_Mob::GetPhR)
@@ -3847,6 +3878,7 @@ luabind::scope lua_register_mob() {
.def("GetTarget", &Lua_Mob::GetTarget) .def("GetTarget", &Lua_Mob::GetTarget)
.def("GetTexture", &Lua_Mob::GetTexture) .def("GetTexture", &Lua_Mob::GetTexture)
.def("GetTimerDurationMS", &Lua_Mob::GetTimerDurationMS) .def("GetTimerDurationMS", &Lua_Mob::GetTimerDurationMS)
.def("GetTimers", &Lua_Mob::GetTimers)
.def("GetUltimateOwner", &Lua_Mob::GetUltimateOwner) .def("GetUltimateOwner", &Lua_Mob::GetUltimateOwner)
.def("GetWIS", &Lua_Mob::GetWIS) .def("GetWIS", &Lua_Mob::GetWIS)
.def("GetWalkspeed", &Lua_Mob::GetWalkspeed) .def("GetWalkspeed", &Lua_Mob::GetWalkspeed)
+2
View File
@@ -612,6 +612,8 @@ public:
void BuffFadeDetrimentalByCaster(Lua_Mob caster); void BuffFadeDetrimentalByCaster(Lua_Mob caster);
void BuffFadeNonPersistDeath(); void BuffFadeNonPersistDeath();
void BuffFadeSongs(); void BuffFadeSongs();
luabind::object GetPausedTimers(lua_State* L);
luabind::object GetTimers(lua_State* L);
}; };
#endif #endif
+256 -7
View File
@@ -219,6 +219,7 @@ LuaParser::LuaParser() {
SpellArgumentDispatch[i] = handle_spell_null; SpellArgumentDispatch[i] = handle_spell_null;
EncounterArgumentDispatch[i] = handle_encounter_null; EncounterArgumentDispatch[i] = handle_encounter_null;
BotArgumentDispatch[i] = handle_bot_null; BotArgumentDispatch[i] = handle_bot_null;
ZoneArgumentDispatch[i] = handle_zone_null;
} }
NPCArgumentDispatch[EVENT_SAY] = handle_npc_event_say; NPCArgumentDispatch[EVENT_SAY] = handle_npc_event_say;
@@ -409,6 +410,23 @@ LuaParser::LuaParser() {
BotArgumentDispatch[EVENT_ENTITY_VARIABLE_SET] = handle_bot_entity_variable; BotArgumentDispatch[EVENT_ENTITY_VARIABLE_SET] = handle_bot_entity_variable;
BotArgumentDispatch[EVENT_ENTITY_VARIABLE_UPDATE] = handle_bot_entity_variable; BotArgumentDispatch[EVENT_ENTITY_VARIABLE_UPDATE] = handle_bot_entity_variable;
BotArgumentDispatch[EVENT_SPELL_BLOCKED] = handle_bot_spell_blocked; BotArgumentDispatch[EVENT_SPELL_BLOCKED] = handle_bot_spell_blocked;
ZoneArgumentDispatch[EVENT_CLICK_DOOR] = handle_zone_click_door;
ZoneArgumentDispatch[EVENT_CLICK_OBJECT] = handle_zone_click_object;
ZoneArgumentDispatch[EVENT_DEATH_ZONE] = handle_zone_death;
ZoneArgumentDispatch[EVENT_DESPAWN_ZONE] = handle_zone_despawn;
ZoneArgumentDispatch[EVENT_ENTER_ZONE] = handle_zone_enter;
ZoneArgumentDispatch[EVENT_LOOT_ZONE] = handle_zone_loot;
ZoneArgumentDispatch[EVENT_PAYLOAD] = handle_zone_payload;
ZoneArgumentDispatch[EVENT_PLAYER_PICKUP] = handle_zone_pickup;
ZoneArgumentDispatch[EVENT_POPUP_RESPONSE] = handle_zone_popup;
ZoneArgumentDispatch[EVENT_SIGNAL] = handle_zone_signal;
ZoneArgumentDispatch[EVENT_SPAWN_ZONE] = handle_zone_spawn;
ZoneArgumentDispatch[EVENT_TIMER] = handle_zone_timer;
ZoneArgumentDispatch[EVENT_TIMER_PAUSE] = handle_zone_timer_pause_resume_start;
ZoneArgumentDispatch[EVENT_TIMER_RESUME] = handle_zone_timer_pause_resume_start;
ZoneArgumentDispatch[EVENT_TIMER_START] = handle_zone_timer_pause_resume_start;
ZoneArgumentDispatch[EVENT_TIMER_STOP] = handle_zone_timer_stop;
#endif #endif
L = nullptr; L = nullptr;
@@ -489,7 +507,13 @@ int LuaParser::_EventNPC(std::string package_name, QuestEventID evt, NPC* npc, M
arg_function(this, L, npc, init, data, extra_data, extra_pointers); arg_function(this, L, npc, init, data, extra_data, extra_pointers);
Client *c = (init && init->IsClient()) ? init->CastToClient() : nullptr; Client *c = (init && init->IsClient()) ? init->CastToClient() : nullptr;
quest_manager.StartQuest(npc, c); RunningQuest q;
q.owner = npc;
q.initiator = c;
quest_manager.StartQuest(q);
if(lua_pcall(L, 1, 1, start + 1)) { if(lua_pcall(L, 1, 1, start + 1)) {
std::string error = lua_tostring(L, -1); std::string error = lua_tostring(L, -1);
AddError(error); AddError(error);
@@ -582,7 +606,13 @@ int LuaParser::_EventPlayer(std::string package_name, QuestEventID evt, Client *
auto arg_function = PlayerArgumentDispatch[evt]; auto arg_function = PlayerArgumentDispatch[evt];
arg_function(this, L, client, data, extra_data, extra_pointers); arg_function(this, L, client, data, extra_data, extra_pointers);
quest_manager.StartQuest(client, client); RunningQuest q;
q.owner = client;
q.initiator = client;
quest_manager.StartQuest(q);
if(lua_pcall(L, 1, 1, start + 1)) { if(lua_pcall(L, 1, 1, start + 1)) {
std::string error = lua_tostring(L, -1); std::string error = lua_tostring(L, -1);
AddError(error); AddError(error);
@@ -666,7 +696,14 @@ int LuaParser::_EventItem(std::string package_name, QuestEventID evt, Client *cl
auto arg_function = ItemArgumentDispatch[evt]; auto arg_function = ItemArgumentDispatch[evt];
arg_function(this, L, client, item, mob, data, extra_data, extra_pointers); arg_function(this, L, client, item, mob, data, extra_data, extra_pointers);
quest_manager.StartQuest(client, client, item); RunningQuest q;
q.owner = client;
q.initiator = client;
q.questitem = item;
quest_manager.StartQuest(q);
if(lua_pcall(L, 1, 1, start + 1)) { if(lua_pcall(L, 1, 1, start + 1)) {
std::string error = lua_tostring(L, -1); std::string error = lua_tostring(L, -1);
AddError(error); AddError(error);
@@ -748,7 +785,14 @@ int LuaParser::_EventSpell(std::string package_name, QuestEventID evt, Mob* mob,
auto arg_function = SpellArgumentDispatch[evt]; auto arg_function = SpellArgumentDispatch[evt];
arg_function(this, L, mob, client, spell_id, data, extra_data, extra_pointers); arg_function(this, L, mob, client, spell_id, data, extra_data, extra_pointers);
quest_manager.StartQuest(mob, client, nullptr, const_cast<SPDat_Spell_Struct*>(&spells[spell_id])); RunningQuest q;
q.owner = client;
q.initiator = client;
q.questspell = const_cast<SPDat_Spell_Struct*>(&spells[spell_id]);
quest_manager.StartQuest(q);
if(lua_pcall(L, 1, 1, start + 1)) { if(lua_pcall(L, 1, 1, start + 1)) {
std::string error = lua_tostring(L, -1); std::string error = lua_tostring(L, -1);
AddError(error); AddError(error);
@@ -814,7 +858,13 @@ int LuaParser::_EventEncounter(std::string package_name, QuestEventID evt, std::
auto arg_function = EncounterArgumentDispatch[evt]; auto arg_function = EncounterArgumentDispatch[evt];
arg_function(this, L, enc, data, extra_data, extra_pointers); arg_function(this, L, enc, data, extra_data, extra_pointers);
quest_manager.StartQuest(enc, nullptr, nullptr, nullptr, encounter_name); RunningQuest q;
q.owner = enc;
q.encounter = encounter_name;
quest_manager.StartQuest(q);
if(lua_pcall(L, 1, 1, start + 1)) { if(lua_pcall(L, 1, 1, start + 1)) {
std::string error = lua_tostring(L, -1); std::string error = lua_tostring(L, -1);
AddError(error); AddError(error);
@@ -1757,7 +1807,13 @@ int LuaParser::_EventBot(
arg_function(this, L, bot, init, data, extra_data, extra_pointers); arg_function(this, L, bot, init, data, extra_data, extra_pointers);
auto* c = (init && init->IsClient()) ? init->CastToClient() : nullptr; auto* c = (init && init->IsClient()) ? init->CastToClient() : nullptr;
quest_manager.StartQuest(bot, c); RunningQuest q;
q.owner = bot;
q.initiator = c;
quest_manager.StartQuest(q);
if(lua_pcall(L, 1, 1, start + 1)) { if(lua_pcall(L, 1, 1, start + 1)) {
std::string error = lua_tostring(L, -1); std::string error = lua_tostring(L, -1);
AddError(error); AddError(error);
@@ -1936,7 +1992,13 @@ int LuaParser::_EventMerc(
arg_function(this, L, merc, init, data, extra_data, extra_pointers); arg_function(this, L, merc, init, data, extra_data, extra_pointers);
auto* c = (init && init->IsClient()) ? init->CastToClient() : nullptr; auto* c = (init && init->IsClient()) ? init->CastToClient() : nullptr;
quest_manager.StartQuest(merc, c); RunningQuest q;
q.owner = merc;
q.initiator = c;
quest_manager.StartQuest(q);
if(lua_pcall(L, 1, 1, start + 1)) { if(lua_pcall(L, 1, 1, start + 1)) {
std::string error = lua_tostring(L, -1); std::string error = lua_tostring(L, -1);
AddError(error); AddError(error);
@@ -2039,3 +2101,190 @@ void LuaParser::LoadMercScript(std::string filename) {
void LuaParser::LoadGlobalMercScript(std::string filename) { void LuaParser::LoadGlobalMercScript(std::string filename) {
LoadScript(filename, "global_merc"); LoadScript(filename, "global_merc");
} }
int LuaParser::EventZone(
QuestEventID evt,
Zone *zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
evt = ConvertLuaEvent(evt);
if (evt >= _LargestEventID) {
return 0;
}
if (!zone) {
return 0;
}
if (!ZoneHasQuestSub(evt)) {
return 0;
}
return _EventZone("zone", evt, zone, data, extra_data, extra_pointers);
}
int LuaParser::EventGlobalZone(
QuestEventID evt,
Zone *zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
evt = ConvertLuaEvent(evt);
if (evt >= _LargestEventID) {
return 0;
}
if (!zone) {
return 0;
}
if (!GlobalZoneHasQuestSub(evt)) {
return 0;
}
return _EventZone("global_zone", evt, zone, data, extra_data, extra_pointers);
}
int LuaParser::_EventZone(
std::string package_name,
QuestEventID evt,
Zone *zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers,
luabind::adl::object *l_func
) {
const char *sub_name = LuaEvents[evt];
int start = lua_gettop(L);
try {
int npop = 2;
PushErrorHandler(L);
if(l_func != nullptr) {
l_func->push(L);
} else {
lua_getfield(L, LUA_REGISTRYINDEX, package_name.c_str());
lua_getfield(L, -1, sub_name);
npop = 3;
}
lua_createtable(L, 0, 0);
//push self
Lua_Zone l_zone(zone);
luabind::adl::object l_zone_o = luabind::adl::object(L, l_zone);
l_zone_o.push(L);
lua_setfield(L, -2, "self");
auto arg_function = ZoneArgumentDispatch[evt];
arg_function(this, L, zone, data, extra_data, extra_pointers);
RunningQuest q;
q.zone = zone;
quest_manager.StartQuest(q);
if(lua_pcall(L, 1, 1, start + 1)) {
std::string error = lua_tostring(L, -1);
AddError(error);
quest_manager.EndQuest();
lua_pop(L, npop);
return 0;
}
quest_manager.EndQuest();
if(lua_isnumber(L, -1)) {
int ret = static_cast<int>(lua_tointeger(L, -1));
lua_pop(L, npop);
return ret;
}
lua_pop(L, npop);
} catch(std::exception &ex) {
AddError(
fmt::format(
"Lua Exception | [{}] for Zone [{}] in [{}]: {}",
sub_name,
zone->GetShortName(),
package_name,
ex.what()
)
);
//Restore our stack to the best of our ability
int end = lua_gettop(L);
int n = end - start;
if(n > 0) {
lua_pop(L, n);
}
}
return 0;
}
int LuaParser::DispatchEventZone(
QuestEventID evt,
Zone *zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
evt = ConvertLuaEvent(evt);
if (evt >= _LargestEventID) {
return 0;
}
std::string package_name = "zone";
auto iter = lua_encounter_events_registered.find(package_name);
if (iter == lua_encounter_events_registered.end()) {
return 0;
}
int ret = 0;
auto riter = iter->second.begin();
while (riter != iter->second.end()) {
if (riter->event_id == evt) {
package_name = fmt::format("encounter_{}", riter->encounter_name);
int i = _EventZone(package_name, evt, zone, data, extra_data, extra_pointers, &riter->lua_reference);
if (i != 0) {
ret = i;
}
}
++riter;
}
return ret;
}
bool LuaParser::ZoneHasQuestSub(QuestEventID evt) {
evt = ConvertLuaEvent(evt);
if (evt >= _LargestEventID) {
return false;
}
const char *subname = LuaEvents[evt];
return HasFunction(subname, "zone");
}
bool LuaParser::GlobalZoneHasQuestSub(QuestEventID evt) {
evt = ConvertLuaEvent(evt);
if (evt >= _LargestEventID) {
return false;
}
const char *subname = LuaEvents[evt];
return HasFunction(subname, "global_zone");
}
void LuaParser::LoadZoneScript(std::string filename) {
LoadScript(filename, "zone");
}
void LuaParser::LoadGlobalZoneScript(std::string filename) {
LoadScript(filename, "global_zone");
}
+35
View File
@@ -125,6 +125,20 @@ public:
uint32 extra_data, uint32 extra_data,
std::vector<std::any>* extra_pointers std::vector<std::any>* extra_pointers
); );
virtual int EventZone(
QuestEventID evt,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any>* extra_pointers
);
virtual int EventGlobalZone(
QuestEventID evt,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any>* extra_pointers
);
virtual bool HasQuestSub(uint32 npc_id, QuestEventID evt); virtual bool HasQuestSub(uint32 npc_id, QuestEventID evt);
virtual bool HasGlobalQuestSub(QuestEventID evt); virtual bool HasGlobalQuestSub(QuestEventID evt);
@@ -138,6 +152,8 @@ public:
virtual bool GlobalBotHasQuestSub(QuestEventID evt); virtual bool GlobalBotHasQuestSub(QuestEventID evt);
virtual bool MercHasQuestSub(QuestEventID evt); virtual bool MercHasQuestSub(QuestEventID evt);
virtual bool GlobalMercHasQuestSub(QuestEventID evt); virtual bool GlobalMercHasQuestSub(QuestEventID evt);
virtual bool ZoneHasQuestSub(QuestEventID evt);
virtual bool GlobalZoneHasQuestSub(QuestEventID evt);
virtual void LoadNPCScript(std::string filename, int npc_id); virtual void LoadNPCScript(std::string filename, int npc_id);
virtual void LoadGlobalNPCScript(std::string filename); virtual void LoadGlobalNPCScript(std::string filename);
@@ -150,6 +166,8 @@ public:
virtual void LoadGlobalBotScript(std::string filename); virtual void LoadGlobalBotScript(std::string filename);
virtual void LoadMercScript(std::string filename); virtual void LoadMercScript(std::string filename);
virtual void LoadGlobalMercScript(std::string filename); virtual void LoadGlobalMercScript(std::string filename);
virtual void LoadZoneScript(std::string filename);
virtual void LoadGlobalZoneScript(std::string filename);
virtual void AddVar(std::string name, std::string val); virtual void AddVar(std::string name, std::string val);
virtual std::string GetVar(std::string name); virtual std::string GetVar(std::string name);
@@ -207,6 +225,13 @@ public:
uint32 extra_data, uint32 extra_data,
std::vector<std::any>* extra_pointers std::vector<std::any>* extra_pointers
); );
virtual int DispatchEventZone(
QuestEventID evt,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any>* extra_pointers
);
static LuaParser* Instance() { static LuaParser* Instance() {
static LuaParser inst; static LuaParser inst;
@@ -307,6 +332,15 @@ private:
std::vector<std::any>* extra_pointers, std::vector<std::any>* extra_pointers,
luabind::adl::object* l_func = nullptr luabind::adl::object* l_func = nullptr
); );
int _EventZone(
std::string package_name,
QuestEventID evt,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any>* extra_pointers,
luabind::adl::object* l_func = nullptr
);
void LoadScript(std::string filename, std::string package_name); void LoadScript(std::string filename, std::string package_name);
void MapFunctions(lua_State *L); void MapFunctions(lua_State *L);
@@ -323,6 +357,7 @@ private:
SpellArgumentHandler SpellArgumentDispatch[_LargestEventID]; SpellArgumentHandler SpellArgumentDispatch[_LargestEventID];
EncounterArgumentHandler EncounterArgumentDispatch[_LargestEventID]; EncounterArgumentHandler EncounterArgumentDispatch[_LargestEventID];
BotArgumentHandler BotArgumentDispatch[_LargestEventID]; BotArgumentHandler BotArgumentDispatch[_LargestEventID];
ZoneArgumentHandler ZoneArgumentDispatch[_LargestEventID];
}; };
#endif #endif
+289
View File
@@ -2873,4 +2873,293 @@ void handle_bot_spell_blocked(
lua_setfield(L, -2, "cast_spell"); lua_setfield(L, -2, "cast_spell");
} }
// Zone
void handle_zone_null(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
}
void handle_zone_click_door(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
Lua_Door l_door(std::any_cast<Doors*>(extra_pointers->at(0)));
luabind::adl::object l_door_o = luabind::adl::object(L, l_door);
l_door_o.push(L);
lua_setfield(L, -2, "door");
Lua_Client l_client(std::any_cast<Client*>(extra_pointers->at(1)));
luabind::adl::object l_client_o = luabind::adl::object(L, l_client);
l_client_o.push(L);
lua_setfield(L, -2, "other");
}
void handle_zone_click_object(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
Lua_Object l_object(std::any_cast<Object*>(extra_pointers->at(0)));
luabind::adl::object l_object_o = luabind::adl::object(L, l_object);
l_object_o.push(L);
lua_setfield(L, -2, "object");
Lua_Client l_client(std::any_cast<Client*>(extra_pointers->at(1)));
luabind::adl::object l_client_o = luabind::adl::object(L, l_client);
l_client_o.push(L);
lua_setfield(L, -2, "other");
}
void handle_zone_death(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
Seperator sep(data.c_str());
Lua_Mob l_mob(std::any_cast<Mob*>(extra_pointers->at(2)));
luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob);
l_mob_o.push(L);
lua_setfield(L, -2, "other");
lua_pushinteger(L, Strings::ToInt(sep.arg[0]));
lua_setfield(L, -2, "killer_id");
lua_pushinteger(L, Strings::ToInt(sep.arg[1]));
lua_setfield(L, -2, "damage");
const uint32 spell_id = Strings::ToUnsignedInt(sep.arg[2]);
if (IsValidSpell(spell_id)) {
Lua_Spell l_spell(&spells[spell_id]);
luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell);
l_spell_o.push(L);
lua_setfield(L, -2, "spell");
} else {
Lua_Spell l_spell(nullptr);
luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell);
l_spell_o.push(L);
lua_setfield(L, -2, "spell");
}
lua_pushinteger(L, Strings::ToInt(sep.arg[3]));
lua_setfield(L, -2, "skill_id");
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[4]));
lua_setfield(L, -2, "killed_entity_id");
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[5]));
lua_setfield(L, -2, "combat_start_time");
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[6]));
lua_setfield(L, -2, "combat_end_time");
lua_pushinteger(L, Strings::ToBigInt(sep.arg[7]));
lua_setfield(L, -2, "damage_received");
lua_pushinteger(L, Strings::ToBigInt(sep.arg[8]));
lua_setfield(L, -2, "healing_received");
if (extra_pointers && extra_pointers->size() >= 1) {
Lua_Corpse l_corpse(std::any_cast<Corpse*>(extra_pointers->at(0)));
luabind::adl::object l_corpse_o = luabind::adl::object(L, l_corpse);
l_corpse_o.push(L);
lua_setfield(L, -2, "corpse");
}
if (extra_pointers && extra_pointers->size() >= 2) {
Lua_NPC l_npc(std::any_cast<NPC*>(extra_pointers->at(1)));
luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc);
l_npc_o.push(L);
lua_setfield(L, -2, "killed");
}
}
void handle_zone_despawn(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
Lua_NPC l_npc(std::any_cast<NPC*>(extra_pointers->at(0)));
luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc);
l_npc_o.push(L);
lua_setfield(L, -2, "other");
}
void handle_zone_enter(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
Lua_Client l_client(std::any_cast<Client*>(extra_pointers->at(0)));
luabind::adl::object l_client_o = luabind::adl::object(L, l_client);
l_client_o.push(L);
lua_setfield(L, -2, "other");
}
void handle_zone_loot(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
Lua_Client l_client(std::any_cast<Client*>(extra_pointers->at(2)));
luabind::adl::object l_client_o = luabind::adl::object(L, l_client);
l_client_o.push(L);
lua_setfield(L, -2, "other");
Lua_ItemInst l_item(std::any_cast<EQ::ItemInstance*>(extra_pointers->at(0)));
luabind::adl::object l_item_o = luabind::adl::object(L, l_item);
l_item_o.push(L);
lua_setfield(L, -2, "item");
Lua_Corpse l_corpse(std::any_cast<Corpse*>(extra_pointers->at(1)));
luabind::adl::object l_corpse_o = luabind::adl::object(L, l_corpse);
l_corpse_o.push(L);
lua_setfield(L, -2, "corpse");
}
void handle_zone_payload(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
Seperator sep(data.c_str());
lua_pushinteger(L, Strings::ToInt(sep.arg[0]));
lua_setfield(L, -2, "payload_id");
lua_pushstring(L, sep.argplus[1]);
lua_setfield(L, -2, "payload_value");
}
void handle_zone_pickup(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
Lua_ItemInst l_item(std::any_cast<EQ::ItemInstance*>(extra_pointers->at(0)));
luabind::adl::object l_item_o = luabind::adl::object(L, l_item);
l_item_o.push(L);
lua_setfield(L, -2, "item");
Lua_Client l_client(std::any_cast<Client*>(extra_pointers->at(1)));
luabind::adl::object l_client_o = luabind::adl::object(L, l_client);
l_client_o.push(L);
lua_setfield(L, -2, "other");
}
void handle_zone_popup(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
lua_pushinteger(L, Strings::ToInt(data));
lua_setfield(L, -2, "popup_id");
Lua_Client l_client(std::any_cast<Client*>(extra_pointers->at(0)));
luabind::adl::object l_client_o = luabind::adl::object(L, l_client);
l_client_o.push(L);
lua_setfield(L, -2, "other");
}
void handle_zone_signal(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
lua_pushinteger(L, Strings::ToInt(data));
lua_setfield(L, -2, "signal");
}
void handle_zone_spawn(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
Lua_NPC l_npc(std::any_cast<NPC*>(extra_pointers->at(0)));
luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc);
l_npc_o.push(L);
lua_setfield(L, -2, "other");
}
void handle_zone_timer(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
lua_pushstring(L, data.c_str());
lua_setfield(L, -2, "timer");
}
void handle_zone_timer_pause_resume_start(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
Seperator sep(data.c_str());
lua_pushstring(L, sep.arg[0]);
lua_setfield(L, -2, "timer");
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[1]));
lua_setfield(L, -2, "duration");
}
void handle_zone_timer_stop(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
lua_pushstring(L, data.c_str());
lua_setfield(L, -2, "timer");
}
#endif #endif
+137
View File
@@ -9,6 +9,7 @@ typedef void(*SpellArgumentHandler)(QuestInterface*, lua_State*, Mob*, Client*,
typedef void(*EncounterArgumentHandler)(QuestInterface*, lua_State*, Encounter* encounter, std::string, uint32, std::vector<std::any>*); typedef void(*EncounterArgumentHandler)(QuestInterface*, lua_State*, Encounter* encounter, std::string, uint32, std::vector<std::any>*);
typedef void(*BotArgumentHandler)(QuestInterface*, lua_State*, Bot*, Mob*, std::string, uint32, std::vector<std::any>*); typedef void(*BotArgumentHandler)(QuestInterface*, lua_State*, Bot*, Mob*, std::string, uint32, std::vector<std::any>*);
typedef void(*MercArgumentHandler)(QuestInterface*, lua_State*, Merc*, Mob*, std::string, uint32, std::vector<std::any>*); typedef void(*MercArgumentHandler)(QuestInterface*, lua_State*, Merc*, Mob*, std::string, uint32, std::vector<std::any>*);
typedef void(*ZoneArgumentHandler)(QuestInterface*, lua_State*, Zone*, std::string, uint32, std::vector<std::any>*);
// NPC // NPC
void handle_npc_event_say( void handle_npc_event_say(
@@ -1278,5 +1279,141 @@ void handle_bot_spell_blocked(
std::vector<std::any> *extra_pointers std::vector<std::any> *extra_pointers
); );
// Zone
void handle_zone_null(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
);
void handle_zone_click_door(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
);
void handle_zone_click_object(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
);
void handle_zone_death(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
);
void handle_zone_despawn(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
);
void handle_zone_enter(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
);
void handle_zone_loot(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
);
void handle_zone_payload(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
);
void handle_zone_pickup(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
);
void handle_zone_popup(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
);
void handle_zone_signal(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
);
void handle_zone_spawn(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
);
void handle_zone_timer(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
);
void handle_zone_timer_pause_resume_start(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
);
void handle_zone_timer_stop(
QuestInterface *parse,
lua_State* L,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
);
#endif #endif
#endif #endif
+109
View File
@@ -772,6 +772,102 @@ bool Lua_Zone::VariableExists(const std::string& variable_name)
return self->VariableExists(variable_name); return self->VariableExists(variable_name);
} }
uint32 Lua_Zone::GetTimerDuration(std::string name)
{
Lua_Safe_Call_Int();
return self->GetTimerDuration(name);
}
uint32 Lua_Zone::GetTimerRemainingTime(std::string name)
{
Lua_Safe_Call_Int();
return self->GetTimerRemainingTime(name);
}
bool Lua_Zone::HasTimer(std::string name)
{
Lua_Safe_Call_Bool();
return self->HasTimer(name);
}
bool Lua_Zone::IsPausedTimer(std::string name)
{
Lua_Safe_Call_Bool();
return self->IsPausedTimer(name);
}
void Lua_Zone::PauseTimer(std::string name)
{
Lua_Safe_Call_Void();
self->PauseTimer(name);
}
void Lua_Zone::ResumeTimer(std::string name)
{
Lua_Safe_Call_Void();
self->ResumeTimer(name);
}
void Lua_Zone::SetTimer(std::string name, uint32 duration)
{
Lua_Safe_Call_Void();
self->SetTimer(name, duration);
}
void Lua_Zone::StopTimer(std::string name)
{
Lua_Safe_Call_Void();
self->StopTimer(name);
}
void Lua_Zone::StopAllTimers()
{
Lua_Safe_Call_Void();
self->StopAllTimers();
}
void Lua_Zone::SendPayload(int payload_id, std::string payload_value)
{
Lua_Safe_Call_Void();
self->SendPayload(payload_id, payload_value);
}
void Lua_Zone::Signal(int signal_id)
{
Lua_Safe_Call_Void();
self->Signal(signal_id);
}
luabind::object Lua_Zone::GetPausedTimers(lua_State* L) {
auto t = luabind::newtable(L);
if (d_) {
auto self = reinterpret_cast<NativeType*>(d_);
auto l = self->GetPausedTimers();
int i = 1;
for (const auto& v : l) {
t[i] = v;
i++;
}
}
return t;
}
luabind::object Lua_Zone::GetTimers(lua_State* L) {
auto t = luabind::newtable(L);
if (d_) {
auto self = reinterpret_cast<NativeType*>(d_);
auto l = self->GetTimers();
int i = 1;
for (const auto& v : l) {
t[i] = v;
i++;
}
}
return t;
}
luabind::scope lua_register_zone() { luabind::scope lua_register_zone() {
return luabind::class_<Lua_Zone>("Zones") return luabind::class_<Lua_Zone>("Zones")
.def(luabind::constructor<>()) .def(luabind::constructor<>())
@@ -840,6 +936,7 @@ luabind::scope lua_register_zone() {
.def("GetMinimumStatus", &Lua_Zone::GetMinimumStatus) .def("GetMinimumStatus", &Lua_Zone::GetMinimumStatus)
.def("GetNote", &Lua_Zone::GetNote) .def("GetNote", &Lua_Zone::GetNote)
.def("GetNPCMaximumAggroDistance", &Lua_Zone::GetNPCMaximumAggroDistance) .def("GetNPCMaximumAggroDistance", &Lua_Zone::GetNPCMaximumAggroDistance)
.def("GetPausedTimers", &Lua_Zone::GetPausedTimers)
.def("GetPEQZone", &Lua_Zone::GetPEQZone) .def("GetPEQZone", &Lua_Zone::GetPEQZone)
.def("GetRainChance", (int(Lua_Zone::*)(void))&Lua_Zone::GetRainChance) .def("GetRainChance", (int(Lua_Zone::*)(void))&Lua_Zone::GetRainChance)
.def("GetRainChance", (int(Lua_Zone::*)(uint8))&Lua_Zone::GetRainChance) .def("GetRainChance", (int(Lua_Zone::*)(uint8))&Lua_Zone::GetRainChance)
@@ -861,6 +958,9 @@ luabind::scope lua_register_zone() {
.def("GetSnowDuration", (int(Lua_Zone::*)(uint8))&Lua_Zone::GetSnowDuration) .def("GetSnowDuration", (int(Lua_Zone::*)(uint8))&Lua_Zone::GetSnowDuration)
.def("GetTimeType", &Lua_Zone::GetTimeType) .def("GetTimeType", &Lua_Zone::GetTimeType)
.def("GetTimeZone", &Lua_Zone::GetTimeZone) .def("GetTimeZone", &Lua_Zone::GetTimeZone)
.def("GetTimerDuration", &Lua_Zone::GetTimerDuration)
.def("GetTimerRemainingTime", &Lua_Zone::GetTimerRemainingTime)
.def("GetTimers", &Lua_Zone::GetTimers)
.def("GetZoneDescription", &Lua_Zone::GetZoneDescription) .def("GetZoneDescription", &Lua_Zone::GetZoneDescription)
.def("GetZoneID", &Lua_Zone::GetZoneID) .def("GetZoneID", &Lua_Zone::GetZoneID)
.def("GetZoneType", &Lua_Zone::GetZoneType) .def("GetZoneType", &Lua_Zone::GetZoneType)
@@ -875,10 +975,12 @@ luabind::scope lua_register_zone() {
.def("HasMap", &Lua_Zone::HasMap) .def("HasMap", &Lua_Zone::HasMap)
.def("HasWaterMap", &Lua_Zone::HasWaterMap) .def("HasWaterMap", &Lua_Zone::HasWaterMap)
.def("HasWeather", &Lua_Zone::HasWeather) .def("HasWeather", &Lua_Zone::HasWeather)
.def("HasTimer", &Lua_Zone::HasTimer)
.def("IsCity", &Lua_Zone::IsCity) .def("IsCity", &Lua_Zone::IsCity)
.def("IsHotzone", &Lua_Zone::IsHotzone) .def("IsHotzone", &Lua_Zone::IsHotzone)
.def("IsInstancePersistent", &Lua_Zone::IsInstancePersistent) .def("IsInstancePersistent", &Lua_Zone::IsInstancePersistent)
.def("IsIdleWhenEmpty", &Lua_Zone::IsIdleWhenEmpty) .def("IsIdleWhenEmpty", &Lua_Zone::IsIdleWhenEmpty)
.def("IsPausedTimer", &Lua_Zone::IsPausedTimer)
.def("IsPVPZone", &Lua_Zone::IsPVPZone) .def("IsPVPZone", &Lua_Zone::IsPVPZone)
.def("IsRaining", &Lua_Zone::IsRaining) .def("IsRaining", &Lua_Zone::IsRaining)
.def("IsSnowing", &Lua_Zone::IsSnowing) .def("IsSnowing", &Lua_Zone::IsSnowing)
@@ -887,8 +989,11 @@ luabind::scope lua_register_zone() {
.def("IsStaticZone", &Lua_Zone::IsStaticZone) .def("IsStaticZone", &Lua_Zone::IsStaticZone)
.def("IsUCSServerAvailable", &Lua_Zone::IsUCSServerAvailable) .def("IsUCSServerAvailable", &Lua_Zone::IsUCSServerAvailable)
.def("IsWaterZone", &Lua_Zone::IsWaterZone) .def("IsWaterZone", &Lua_Zone::IsWaterZone)
.def("PauseTimer", &Lua_Zone::PauseTimer)
.def("Repop", (void(Lua_Zone::*)(void))&Lua_Zone::Repop) .def("Repop", (void(Lua_Zone::*)(void))&Lua_Zone::Repop)
.def("Repop", (void(Lua_Zone::*)(bool))&Lua_Zone::Repop) .def("Repop", (void(Lua_Zone::*)(bool))&Lua_Zone::Repop)
.def("ResumeTimer", &Lua_Zone::ResumeTimer)
.def("SendPayload", &Lua_Zone::SendPayload)
.def("SetAAEXPModifier", &Lua_Zone::SetAAEXPModifier) .def("SetAAEXPModifier", &Lua_Zone::SetAAEXPModifier)
.def("SetAAEXPModifierByCharacterID", &Lua_Zone::SetAAEXPModifierByCharacterID) .def("SetAAEXPModifierByCharacterID", &Lua_Zone::SetAAEXPModifierByCharacterID)
.def("SetBucket", (void(Lua_Zone::*)(const std::string&,const std::string&))&Lua_Zone::SetBucket) .def("SetBucket", (void(Lua_Zone::*)(const std::string&,const std::string&))&Lua_Zone::SetBucket)
@@ -898,8 +1003,12 @@ luabind::scope lua_register_zone() {
.def("SetInstanceTimer", &Lua_Zone::SetInstanceTimer) .def("SetInstanceTimer", &Lua_Zone::SetInstanceTimer)
.def("SetInstanceTimeRemaining", &Lua_Zone::SetInstanceTimeRemaining) .def("SetInstanceTimeRemaining", &Lua_Zone::SetInstanceTimeRemaining)
.def("SetIsHotzone", &Lua_Zone::SetIsHotzone) .def("SetIsHotzone", &Lua_Zone::SetIsHotzone)
.def("SetTimer", &Lua_Zone::SetTimer)
.def("SetVariable", &Lua_Zone::SetVariable) .def("SetVariable", &Lua_Zone::SetVariable)
.def("ShowZoneGlobalLoot", &Lua_Zone::ShowZoneGlobalLoot) .def("ShowZoneGlobalLoot", &Lua_Zone::ShowZoneGlobalLoot)
.def("Signal", &Lua_Zone::Signal)
.def("StopTimer", &Lua_Zone::StopTimer)
.def("StopAllTimers", &Lua_Zone::StopAllTimers)
.def("VariableExists", &Lua_Zone::VariableExists); .def("VariableExists", &Lua_Zone::VariableExists);
} }
+13
View File
@@ -147,6 +147,19 @@ public:
luabind::object GetVariables(lua_State* L); luabind::object GetVariables(lua_State* L);
void SetVariable(const std::string& variable_name, const std::string& variable_value); void SetVariable(const std::string& variable_name, const std::string& variable_value);
bool VariableExists(const std::string& variable_name); bool VariableExists(const std::string& variable_name);
uint32 GetTimerDuration(std::string name);
uint32 GetTimerRemainingTime(std::string name);
bool HasTimer(std::string name);
bool IsPausedTimer(std::string name);
void PauseTimer(std::string name);
void ResumeTimer(std::string name);
void SetTimer(std::string name, uint32 duration);
void StopTimer(std::string name);
void StopAllTimers();
void Signal(int signal_id);
void SendPayload(int payload_id, std::string payload_value);
luabind::object GetPausedTimers(lua_State* L);
luabind::object GetTimers(lua_State* L);
// data buckets // data buckets
void SetBucket(const std::string& bucket_name, const std::string& bucket_value); void SetBucket(const std::string& bucket_name, const std::string& bucket_value);
+1
View File
@@ -133,6 +133,7 @@ Mob::Mob(
m_see_close_mobs_timer(1000), m_see_close_mobs_timer(1000),
m_mob_check_moving_timer(1000), m_mob_check_moving_timer(1000),
bot_attack_flag_timer(10000), bot_attack_flag_timer(10000),
m_clear_wearchange_cache_timer(60 * 10 * 1000), // 10 minutes
m_destroying(false) m_destroying(false)
{ {
mMovementManager = &MobMovementManager::Get(); mMovementManager = &MobMovementManager::Get();
+1
View File
@@ -211,6 +211,7 @@ public:
uint16 m_last_wearchange_race_id = 0; uint16 m_last_wearchange_race_id = 0;
// client_id -> slot_id -> key // client_id -> slot_id -> key
std::unordered_map<uint32_t, std::unordered_map<uint8_t, uint64_t>> m_last_seen_wearchange; std::unordered_map<uint32_t, std::unordered_map<uint8_t, uint64_t>> m_last_seen_wearchange;
Timer m_clear_wearchange_cache_timer;
// Bot attack flag // Bot attack flag
Timer bot_attack_flag_timer; Timer bot_attack_flag_timer;
+2 -2
View File
@@ -286,8 +286,8 @@ uint32 Mob::GetHerosForgeModel(uint8 material_slot) const
if (augment) { if (augment) {
item = augment->GetItem(); item = augment->GetItem();
heros_forge_model = item->HerosForgeModel; heros_forge_model = item->HerosForgeModel;
} else if (inst->GetOrnamentHeroModel()) { } else if (inst->GetOrnamentHeroModel(material_slot)) {
heros_forge_model = inst->GetOrnamentHeroModel(); heros_forge_model = inst->GetOrnamentHeroModel(material_slot);
} }
} }
} }
+9
View File
@@ -632,6 +632,10 @@ bool NPC::Process()
} }
if (tic_timer.Check()) { if (tic_timer.Check()) {
if (m_clear_wearchange_cache_timer.Check()) {
m_last_seen_wearchange.clear();
}
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_TICK)) { if (parse->HasQuestSub(GetNPCTypeID(), EVENT_TICK)) {
parse->EventNPC(EVENT_TICK, this, nullptr, "", 0); parse->EventNPC(EVENT_TICK, this, nullptr, "", 0);
} }
@@ -860,6 +864,11 @@ void NPC::Depop(bool start_spawn_timer) {
DispatchZoneControllerEvent(EVENT_DESPAWN_ZONE, this, "", 0, nullptr); DispatchZoneControllerEvent(EVENT_DESPAWN_ZONE, this, "", 0, nullptr);
} }
if (parse->ZoneHasQuestSub(EVENT_DESPAWN_ZONE)) {
std::vector<std::any> args = { this };
parse->EventZone(EVENT_DESPAWN_ZONE, zone, "", 0, &args);
}
p_depop = true; p_depop = true;
if (respawn2) { if (respawn2) {
if (start_spawn_timer) { if (start_spawn_timer) {
+24
View File
@@ -657,6 +657,30 @@ bool Object::HandleClick(Client* sender, const ClickObject_Struct* click_object)
} }
} }
if (parse->ZoneHasQuestSub(EVENT_PLAYER_PICKUP)) {
std::vector<std::any> args = { m_inst, sender };
if (parse->EventZone(EVENT_PLAYER_PICKUP, zone, std::to_string(item->ID), GetID(), &args)) {
auto outapp = new EQApplicationPacket(OP_ClickObject, sizeof(ClickObject_Struct));
memcpy(outapp->pBuffer, click_object, sizeof(ClickObject_Struct));
auto co = (ClickObject_Struct*) outapp->pBuffer;
co->drop_id = 0;
entity_list.QueueClients(nullptr, outapp, false);
safe_delete(outapp);
sender->SetTradeskillObject(nullptr);
user = nullptr;
return true;
}
}
// Transfer item to client // Transfer item to client
sender->PutItemInInventory(EQ::invslot::slotCursor, *m_inst, false); sender->PutItemInInventory(EQ::invslot::slotCursor, *m_inst, false);
sender->SendItemPacket(EQ::invslot::slotCursor, m_inst, ItemPacketTrade); sender->SendItemPacket(EQ::invslot::slotCursor, m_inst, ItemPacketTrade);
+8 -2
View File
@@ -3328,7 +3328,12 @@ bool Perl_Client_KeyRingClear(Client* self)
void Perl_Client_KeyRingList(Client* self) void Perl_Client_KeyRingList(Client* self)
{ {
self->KeyRingList(); self->KeyRingList(self);
}
void Perl_Client_KeyRingList(Client* self, Client* c)
{
self->KeyRingList(c);
} }
bool Perl_Client_KeyRingRemove(Client* self, uint32 item_id) bool Perl_Client_KeyRingRemove(Client* self, uint32 item_id)
@@ -3675,7 +3680,8 @@ void perl_register_client()
package.add("KeyRingAdd", &Perl_Client_KeyRingAdd); package.add("KeyRingAdd", &Perl_Client_KeyRingAdd);
package.add("KeyRingCheck", &Perl_Client_KeyRingCheck); package.add("KeyRingCheck", &Perl_Client_KeyRingCheck);
package.add("KeyRingClear", &Perl_Client_KeyRingClear); package.add("KeyRingClear", &Perl_Client_KeyRingClear);
package.add("KeyRingList", &Perl_Client_KeyRingList); package.add("KeyRingList", (void(*)(Client*))&Perl_Client_KeyRingList);
package.add("KeyRingList", (void(*)(Client*, Client*))&Perl_Client_KeyRingList);
package.add("KeyRingRemove", &Perl_Client_KeyRingRemove); package.add("KeyRingRemove", &Perl_Client_KeyRingRemove);
package.add("Kick", &Perl_Client_Kick); package.add("Kick", &Perl_Client_Kick);
package.add("LearnDisciplines", &Perl_Client_LearnDisciplines); package.add("LearnDisciplines", &Perl_Client_LearnDisciplines);
+12
View File
@@ -127,6 +127,16 @@ Client* Perl_Group_GetMember(Group* self, int member_index) // @categories Accou
return member ? member->CastToClient() : nullptr; return member ? member->CastToClient() : nullptr;
} }
uint8_t Perl_Group_GetMemberRole(Group* self, Mob* member) // @categories Account and Character, Script Utility, Group
{
return self->GetMemberRole(member);
}
uint8_t Perl_Group_GetMemberRole(Group* self, const char* name) // @categories Account and Character, Script Utility, Group
{
return self->GetMemberRole(name);
}
bool Perl_Group_DoesAnyMemberHaveExpeditionLockout(Group* self, std::string expedition_name, std::string event_name) bool Perl_Group_DoesAnyMemberHaveExpeditionLockout(Group* self, std::string expedition_name, std::string event_name)
{ {
return self->AnyMemberHasDzLockout(expedition_name, event_name); return self->AnyMemberHasDzLockout(expedition_name, event_name);
@@ -163,6 +173,8 @@ void perl_register_group()
package.add("GetLeaderName", &Perl_Group_GetLeaderName); package.add("GetLeaderName", &Perl_Group_GetLeaderName);
package.add("GetLowestLevel", &Perl_Group_GetLowestLevel); package.add("GetLowestLevel", &Perl_Group_GetLowestLevel);
package.add("GetMember", &Perl_Group_GetMember); package.add("GetMember", &Perl_Group_GetMember);
package.add("GetMemberRole", (uint8_t(*)(Group*, Mob*))&Perl_Group_GetMemberRole);
package.add("GetMemberRole", (uint8_t(*)(Group*, const char*))&Perl_Group_GetMemberRole);
package.add("GetTotalGroupDamage", &Perl_Group_GetTotalGroupDamage); package.add("GetTotalGroupDamage", &Perl_Group_GetTotalGroupDamage);
package.add("GroupCount", &Perl_Group_GroupCount); package.add("GroupCount", &Perl_Group_GroupCount);
package.add("GroupMessage", (void(*)(Group*, Mob*, const char*))&Perl_Group_GroupMessage); package.add("GroupMessage", (void(*)(Group*, Mob*, const char*))&Perl_Group_GroupMessage);
+26
View File
@@ -3573,6 +3573,30 @@ void Perl_Mob_BuffFadeSongs(Mob* self)
self->BuffFadeSongs(); self->BuffFadeSongs();
} }
perl::array Perl_Mob_GetPausedTimers(Mob* self)
{
perl::array a;
const auto& l = quest_manager.GetPausedTimers(self);
for (const auto& v : l) {
a.push_back(v);
}
return a;
}
perl::array Perl_Mob_GetTimers(Mob* self)
{
perl::array a;
const auto& l = quest_manager.GetTimers(self);
for (const auto& v : l) {
a.push_back(v);
}
return a;
}
void perl_register_mob() void perl_register_mob()
{ {
perl::interpreter perl(PERL_GET_THX); perl::interpreter perl(PERL_GET_THX);
@@ -3897,6 +3921,7 @@ void perl_register_mob()
package.add("GetOwner", &Perl_Mob_GetOwner); package.add("GetOwner", &Perl_Mob_GetOwner);
package.add("GetOwnerID", &Perl_Mob_GetOwnerID); package.add("GetOwnerID", &Perl_Mob_GetOwnerID);
package.add("GetPR", &Perl_Mob_GetPR); package.add("GetPR", &Perl_Mob_GetPR);
package.add("GetPausedTimers", &Perl_Mob_GetPausedTimers);
package.add("GetPet", &Perl_Mob_GetPet); package.add("GetPet", &Perl_Mob_GetPet);
package.add("GetPetID", &Perl_Mob_GetPetID); package.add("GetPetID", &Perl_Mob_GetPetID);
package.add("GetPetOrder", &Perl_Mob_GetPetOrder); package.add("GetPetOrder", &Perl_Mob_GetPetOrder);
@@ -3927,6 +3952,7 @@ void perl_register_mob()
package.add("GetTarget", &Perl_Mob_GetTarget); package.add("GetTarget", &Perl_Mob_GetTarget);
package.add("GetTexture", &Perl_Mob_GetTexture); package.add("GetTexture", &Perl_Mob_GetTexture);
package.add("GetTimerDurationMS", &Perl_Mob_GetTimerDurationMS); package.add("GetTimerDurationMS", &Perl_Mob_GetTimerDurationMS);
package.add("GetTimers", &Perl_Mob_GetTimers);
package.add("GetUltimateOwner", &Perl_Mob_GetUltimateOwner); package.add("GetUltimateOwner", &Perl_Mob_GetUltimateOwner);
package.add("GetWIS", &Perl_Mob_GetWIS); package.add("GetWIS", &Perl_Mob_GetWIS);
package.add("GetWalkspeed", &Perl_Mob_GetWalkspeed); package.add("GetWalkspeed", &Perl_Mob_GetWalkspeed);
+102
View File
@@ -598,6 +598,95 @@ bool Perl_Zone_VariableExists(Zone* self, const std::string variable_name)
return self->VariableExists(variable_name); return self->VariableExists(variable_name);
} }
uint32 Perl_Zone_GetTimerDuration(Zone* self, std::string name)
{
return self->GetTimerDuration(name);
}
uint32 Perl_Zone_GetTimerRemainingTime(Zone* self, std::string name)
{
return self->GetTimerRemainingTime(name);
}
bool Perl_Zone_HasTimer(Zone* self, std::string name)
{
return self->HasTimer(name);
}
bool Perl_Zone_IsPausedTimer(Zone* self, std::string name)
{
return self->IsPausedTimer(name);
}
void Perl_Zone_PauseTimer(Zone* self, std::string name)
{
self->PauseTimer(name);
}
void Perl_Zone_ResumeTimer(Zone* self, std::string name)
{
self->ResumeTimer(name);
}
void Perl_Zone_SetTimer(Zone* self, std::string name, uint32 duration)
{
self->SetTimer(name, duration);
}
void Perl_Zone_StopTimer(Zone* self, std::string name)
{
self->StopTimer(name);
}
void Perl_Zone_StopAllTimers(Zone* self)
{
self->StopAllTimers();
}
void Perl_Zone_SendPayload(Zone* self, int payload_id, std::string payload_value)
{
self->SendPayload(payload_id, payload_value);
}
void Perl_Zone_Signal(Zone* self, int signal_id)
{
self->Signal(signal_id);
}
perl::array Perl_Zone_GetPausedTimers(Zone* self)
{
perl::array a;
const auto& l = self->GetPausedTimers();
if (!l.empty()) {
a.reserve(l.size());
for (const auto& v : l) {
a.push_back(v);
}
}
return a;
}
perl::array Perl_Zone_GetTimers(Zone* self)
{
perl::array a;
const auto& l = self->GetTimers();
if (!l.empty()) {
a.reserve(l.size());
for (const auto& v : l) {
a.push_back(v);
}
}
return a;
}
void perl_register_zone() void perl_register_zone()
{ {
perl::interpreter perl(PERL_GET_THX); perl::interpreter perl(PERL_GET_THX);
@@ -668,6 +757,7 @@ void perl_register_zone()
package.add("GetMinimumStatus", &Perl_Zone_GetMinimumStatus); package.add("GetMinimumStatus", &Perl_Zone_GetMinimumStatus);
package.add("GetNote", &Perl_Zone_GetNote); package.add("GetNote", &Perl_Zone_GetNote);
package.add("GetNPCMaximumAggroDistance", &Perl_Zone_GetNPCMaximumAggroDistance); package.add("GetNPCMaximumAggroDistance", &Perl_Zone_GetNPCMaximumAggroDistance);
package.add("GetPausedTimers", &Perl_Zone_GetPausedTimers);
package.add("GetPEQZone", &Perl_Zone_GetPEQZone); package.add("GetPEQZone", &Perl_Zone_GetPEQZone);
package.add("GetRainChance", (int(*)(Zone*))&Perl_Zone_GetRainChance); package.add("GetRainChance", (int(*)(Zone*))&Perl_Zone_GetRainChance);
package.add("GetRainChance", (int(*)(Zone*, uint8))&Perl_Zone_GetRainChance); package.add("GetRainChance", (int(*)(Zone*, uint8))&Perl_Zone_GetRainChance);
@@ -689,6 +779,9 @@ void perl_register_zone()
package.add("GetSnowDuration", (int(*)(Zone*, uint8))&Perl_Zone_GetSnowDuration); package.add("GetSnowDuration", (int(*)(Zone*, uint8))&Perl_Zone_GetSnowDuration);
package.add("GetTimeType", &Perl_Zone_GetTimeType); package.add("GetTimeType", &Perl_Zone_GetTimeType);
package.add("GetTimeZone", &Perl_Zone_GetTimeZone); package.add("GetTimeZone", &Perl_Zone_GetTimeZone);
package.add("GetTimerDuration", &Perl_Zone_GetTimerDuration);
package.add("GetTimerRemainingTime", &Perl_Zone_GetTimerRemainingTime);
package.add("GetTimers", &Perl_Zone_GetTimers);
package.add("GetZoneDescription", &Perl_Zone_GetZoneDescription); package.add("GetZoneDescription", &Perl_Zone_GetZoneDescription);
package.add("GetZoneID", &Perl_Zone_GetZoneID); package.add("GetZoneID", &Perl_Zone_GetZoneID);
package.add("GetZoneType", &Perl_Zone_GetZoneType); package.add("GetZoneType", &Perl_Zone_GetZoneType);
@@ -701,12 +794,14 @@ void perl_register_zone()
package.add("GetZoneTotalBlockedSpells", &Perl_Zone_GetZoneTotalBlockedSpells); package.add("GetZoneTotalBlockedSpells", &Perl_Zone_GetZoneTotalBlockedSpells);
package.add("HasGraveyard", &Perl_Zone_HasGraveyard); package.add("HasGraveyard", &Perl_Zone_HasGraveyard);
package.add("HasMap", &Perl_Zone_HasMap); package.add("HasMap", &Perl_Zone_HasMap);
package.add("HasTimer", &Perl_Zone_HasTimer);
package.add("HasWaterMap", &Perl_Zone_HasWaterMap); package.add("HasWaterMap", &Perl_Zone_HasWaterMap);
package.add("HasWeather", &Perl_Zone_HasWeather); package.add("HasWeather", &Perl_Zone_HasWeather);
package.add("IsCity", &Perl_Zone_IsCity); package.add("IsCity", &Perl_Zone_IsCity);
package.add("IsHotzone", &Perl_Zone_IsHotzone); package.add("IsHotzone", &Perl_Zone_IsHotzone);
package.add("IsInstancePersistent", &Perl_Zone_IsInstancePersistent); package.add("IsInstancePersistent", &Perl_Zone_IsInstancePersistent);
package.add("IsIdleWhenEmpty", &Perl_Zone_IsIdleWhenEmpty); package.add("IsIdleWhenEmpty", &Perl_Zone_IsIdleWhenEmpty);
package.add("IsPausedTimer", &Perl_Zone_IsPausedTimer);
package.add("IsPVPZone", &Perl_Zone_IsPVPZone); package.add("IsPVPZone", &Perl_Zone_IsPVPZone);
package.add("IsRaining", &Perl_Zone_IsRaining); package.add("IsRaining", &Perl_Zone_IsRaining);
package.add("IsSnowing", &Perl_Zone_IsSnowing); package.add("IsSnowing", &Perl_Zone_IsSnowing);
@@ -715,8 +810,11 @@ void perl_register_zone()
package.add("IsStaticZone", &Perl_Zone_IsStaticZone); package.add("IsStaticZone", &Perl_Zone_IsStaticZone);
package.add("IsUCSServerAvailable", &Perl_Zone_IsUCSServerAvailable); package.add("IsUCSServerAvailable", &Perl_Zone_IsUCSServerAvailable);
package.add("IsWaterZone", &Perl_Zone_IsWaterZone); package.add("IsWaterZone", &Perl_Zone_IsWaterZone);
package.add("PauseTimer", &Perl_Zone_PauseTimer);
package.add("Repop", (void(*)(Zone*))&Perl_Zone_Repop); package.add("Repop", (void(*)(Zone*))&Perl_Zone_Repop);
package.add("Repop", (void(*)(Zone*, bool))&Perl_Zone_Repop); package.add("Repop", (void(*)(Zone*, bool))&Perl_Zone_Repop);
package.add("ResumeTimer", &Perl_Zone_ResumeTimer);
package.add("SendPayload", &Perl_Zone_SendPayload);
package.add("SetAAEXPModifier", &Perl_Zone_SetAAEXPModifier); package.add("SetAAEXPModifier", &Perl_Zone_SetAAEXPModifier);
package.add("SetAAEXPModifierByCharacterID", &Perl_Zone_SetAAEXPModifierByCharacterID); package.add("SetAAEXPModifierByCharacterID", &Perl_Zone_SetAAEXPModifierByCharacterID);
package.add("SetBucket", (void(*)(Zone*, const std::string, const std::string))&Perl_Zone_SetBucket); package.add("SetBucket", (void(*)(Zone*, const std::string, const std::string))&Perl_Zone_SetBucket);
@@ -726,7 +824,11 @@ void perl_register_zone()
package.add("SetInstanceTimer", &Perl_Zone_SetInstanceTimer); package.add("SetInstanceTimer", &Perl_Zone_SetInstanceTimer);
package.add("SetInstanceTimeRemaining", &Perl_Zone_SetInstanceTimeRemaining); package.add("SetInstanceTimeRemaining", &Perl_Zone_SetInstanceTimeRemaining);
package.add("SetIsHotzone", &Perl_Zone_SetIsHotzone); package.add("SetIsHotzone", &Perl_Zone_SetIsHotzone);
package.add("SetTimer", &Perl_Zone_SetTimer);
package.add("SetVariable", &Perl_Zone_SetVariable); package.add("SetVariable", &Perl_Zone_SetVariable);
package.add("Signal", &Perl_Zone_Signal);
package.add("StopTimer", &Perl_Zone_StopTimer);
package.add("StopAllTimers", &Perl_Zone_StopAllTimers);
package.add("ShowZoneGlobalLoot", &Perl_Zone_ShowZoneGlobalLoot); package.add("ShowZoneGlobalLoot", &Perl_Zone_ShowZoneGlobalLoot);
package.add("VariableExists", &Perl_Zone_VariableExists); package.add("VariableExists", &Perl_Zone_VariableExists);
} }
+45
View File
@@ -163,6 +163,28 @@ public:
return 0; return 0;
} }
virtual int EventZone(
QuestEventID event_id,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any>* extra_pointers
)
{
return 0;
}
virtual int EventGlobalZone(
QuestEventID event_id,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any>* extra_pointers
)
{
return 0;
}
virtual bool HasQuestSub(uint32 npc_id, QuestEventID event_id) virtual bool HasQuestSub(uint32 npc_id, QuestEventID event_id)
{ {
return false; return false;
@@ -223,6 +245,16 @@ public:
return false; return false;
} }
virtual bool ZoneHasQuestSub(QuestEventID event_id)
{
return false;
}
virtual bool GlobalZoneHasQuestSub(QuestEventID event_id)
{
return false;
}
virtual void LoadNPCScript(std::string filename, int npc_id) { } virtual void LoadNPCScript(std::string filename, int npc_id) { }
virtual void LoadGlobalNPCScript(std::string filename) { } virtual void LoadGlobalNPCScript(std::string filename) { }
virtual void LoadPlayerScript(std::string filename) { } virtual void LoadPlayerScript(std::string filename) { }
@@ -234,6 +266,8 @@ public:
virtual void LoadGlobalBotScript(std::string filename) { } virtual void LoadGlobalBotScript(std::string filename) { }
virtual void LoadMercScript(std::string filename) { } virtual void LoadMercScript(std::string filename) { }
virtual void LoadGlobalMercScript(std::string filename) { } virtual void LoadGlobalMercScript(std::string filename) { }
virtual void LoadZoneScript(std::string filename) { }
virtual void LoadGlobalZoneScript(std::string filename) { }
virtual int DispatchEventNPC( virtual int DispatchEventNPC(
QuestEventID event_id, QuestEventID event_id,
@@ -308,6 +342,17 @@ public:
return 0; return 0;
} }
virtual int DispatchEventZone(
QuestEventID event_id,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any>* extra_pointers
)
{
return 0;
}
virtual void AddVar(std::string name, std::string val) { } virtual void AddVar(std::string name, std::string val) { }
virtual std::string GetVar(std::string name) virtual std::string GetVar(std::string name)
{ {
+225
View File
@@ -49,6 +49,8 @@ QuestParserCollection::QuestParserCollection()
_global_bot_quest_status = QuestUnloaded; _global_bot_quest_status = QuestUnloaded;
_merc_quest_status = QuestUnloaded; _merc_quest_status = QuestUnloaded;
_global_merc_quest_status = QuestUnloaded; _global_merc_quest_status = QuestUnloaded;
_zone_quest_status = QuestUnloaded;
_global_zone_quest_status = QuestUnloaded;
} }
QuestParserCollection::~QuestParserCollection() { } QuestParserCollection::~QuestParserCollection() { }
@@ -85,6 +87,7 @@ void QuestParserCollection::ReloadQuests(bool reset_timers)
{ {
if (reset_timers) { if (reset_timers) {
quest_manager.ClearAllTimers(); quest_manager.ClearAllTimers();
zone->StopAllTimers();
} }
MapOpcodes(); MapOpcodes();
@@ -98,6 +101,8 @@ void QuestParserCollection::ReloadQuests(bool reset_timers)
_global_bot_quest_status = QuestUnloaded; _global_bot_quest_status = QuestUnloaded;
_merc_quest_status = QuestUnloaded; _merc_quest_status = QuestUnloaded;
_global_merc_quest_status = QuestUnloaded; _global_merc_quest_status = QuestUnloaded;
_zone_quest_status = QuestUnloaded;
_global_zone_quest_status = QuestUnloaded;
_spell_quest_status.clear(); _spell_quest_status.clear();
_item_quest_status.clear(); _item_quest_status.clear();
@@ -426,6 +431,49 @@ bool QuestParserCollection::MercHasQuestSub(QuestEventID event_id)
return MercHasQuestSubLocal(event_id) || MercHasQuestSubGlobal(event_id); return MercHasQuestSubLocal(event_id) || MercHasQuestSubGlobal(event_id);
} }
bool QuestParserCollection::ZoneHasQuestSubLocal(QuestEventID event_id)
{
if (_zone_quest_status == QuestUnloaded) {
std::string filename;
auto qi = GetQIByZoneQuest(filename);
if (qi) {
_zone_quest_status = qi->GetIdentifier();
qi->LoadZoneScript(filename);
return qi->ZoneHasQuestSub(event_id);
}
} else if (_zone_quest_status != QuestFailedToLoad) {
auto iter = _interfaces.find(_zone_quest_status);
return iter->second->ZoneHasQuestSub(event_id);
}
return false;
}
bool QuestParserCollection::ZoneHasQuestSubGlobal(QuestEventID event_id)
{
if (_global_zone_quest_status == QuestUnloaded) {
std::string filename;
auto qi = GetQIByGlobalZoneQuest(filename);
if (qi) {
_global_zone_quest_status = qi->GetIdentifier();
qi->LoadGlobalZoneScript(filename);
return qi->GlobalZoneHasQuestSub(event_id);
}
} else if (_global_zone_quest_status != QuestFailedToLoad) {
auto iter = _interfaces.find(_global_zone_quest_status);
return iter->second->GlobalZoneHasQuestSub(event_id);
}
return false;
}
bool QuestParserCollection::ZoneHasQuestSub(QuestEventID event_id)
{
return ZoneHasQuestSubLocal(event_id) || ZoneHasQuestSubGlobal(event_id);
}
int QuestParserCollection::EventNPC( int QuestParserCollection::EventNPC(
QuestEventID event_id, QuestEventID event_id,
NPC* npc, NPC* npc,
@@ -924,6 +972,83 @@ int QuestParserCollection::EventMercGlobal(
return 0; return 0;
} }
int QuestParserCollection::EventZone(
QuestEventID event_id,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any>* extra_pointers
)
{
const int local_return = EventZoneLocal(event_id, zone, data, extra_data, extra_pointers);
const int global_return = EventZoneGlobal(event_id, zone, data, extra_data, extra_pointers);
const int default_return = DispatchEventZone(event_id, zone, data, extra_data, extra_pointers);
if (local_return != 0) {
return local_return;
} else if (global_return != 0) {
return global_return;
} else if (default_return != 0) {
return default_return;
}
return 0;
}
int QuestParserCollection::EventZoneLocal(
QuestEventID event_id,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any>* extra_pointers
)
{
if (_zone_quest_status == QuestUnloaded) {
std::string filename;
auto qi = GetQIByZoneQuest(filename);
if (qi) {
_zone_quest_status = qi->GetIdentifier();
qi->LoadZoneScript(filename);
return qi->EventZone(event_id, zone, data, extra_data, extra_pointers);
}
} else {
if (_zone_quest_status != QuestFailedToLoad) {
auto iter = _interfaces.find(_zone_quest_status);
return iter->second->EventZone(event_id, zone, data, extra_data, extra_pointers);
}
}
return 0;
}
int QuestParserCollection::EventZoneGlobal(
QuestEventID event_id,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any>* extra_pointers
)
{
if (_global_zone_quest_status == QuestUnloaded) {
std::string filename;
auto qi = GetQIByGlobalZoneQuest(filename);
if (qi) {
_global_zone_quest_status = qi->GetIdentifier();
qi->LoadGlobalZoneScript(filename);
return qi->EventGlobalZone(event_id, zone, data, extra_data, extra_pointers);
}
} else {
if (_global_zone_quest_status != QuestFailedToLoad) {
auto iter = _interfaces.find(_global_zone_quest_status);
return iter->second->EventGlobalZone(event_id, zone, data, extra_data, extra_pointers);
}
}
return 0;
}
QuestInterface* QuestParserCollection::GetQIByNPCQuest(uint32 npc_id, std::string& filename) QuestInterface* QuestParserCollection::GetQIByNPCQuest(uint32 npc_id, std::string& filename)
{ {
if (!zone) { if (!zone) {
@@ -1425,6 +1550,86 @@ QuestInterface* QuestParserCollection::GetQIByGlobalMercQuest(std::string& filen
return nullptr; return nullptr;
} }
QuestInterface* QuestParserCollection::GetQIByZoneQuest(std::string& filename)
{
if (!zone || !zone->IsLoaded()) {
return nullptr;
}
std::string file_name;
for (auto& dir: PathManager::Instance()->GetQuestPaths()) {
const std::string& global_path = fmt::format(
"{}/{}",
dir,
QUEST_GLOBAL_DIRECTORY
);
const std::string& zone_path = fmt::format(
"{}/{}",
dir,
zone->GetShortName()
);
const std::string& zone_versioned_path = fmt::format(
"{}/{}/v{}",
dir,
zone->GetShortName(),
zone->GetInstanceVersion()
);
std::vector<std::string> file_names = {
fmt::format("{}/zone", zone_versioned_path), // Local versioned by Instance Version ./quests/zone/v0/zone.ext
fmt::format("{}/zone_v{}", zone_path, zone->GetInstanceVersion()), // Local by Instance Version
fmt::format("{}/zone", zone_path), // Local
fmt::format("{}/zone", global_path) // Global
};
for (auto& file: file_names) {
for (auto* e: _load_precedence) {
file_name = fmt::format(
"{}.{}",
file,
_extensions.find(e->GetIdentifier())->second
);
if (File::Exists(file_name)) {
filename = file_name;
return e;
}
}
}
}
return nullptr;
}
QuestInterface* QuestParserCollection::GetQIByGlobalZoneQuest(std::string& filename)
{
if (!zone) {
return nullptr;
}
std::string file_name;
for (auto& dir: PathManager::Instance()->GetQuestPaths()) {
for (auto* e: _load_precedence) {
file_name = fmt::format(
"{}/{}/global_zone.{}",
dir,
QUEST_GLOBAL_DIRECTORY,
_extensions.find(e->GetIdentifier())->second
);
if (File::Exists(file_name)) {
filename = file_name;
return e;
}
}
}
return nullptr;
}
void QuestParserCollection::GetErrors(std::list<std::string>& quest_errors) void QuestParserCollection::GetErrors(std::list<std::string>& quest_errors)
{ {
quest_errors.clear(); quest_errors.clear();
@@ -1561,6 +1766,26 @@ int QuestParserCollection::DispatchEventMerc(
return ret; return ret;
} }
int QuestParserCollection::DispatchEventZone(
QuestEventID event_id,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any>* extra_pointers
)
{
int ret = 0;
for (const auto& e: _load_precedence) {
int i = e->DispatchEventZone(event_id, zone, data, extra_data, extra_pointers);
if (i != 0) {
ret = i;
}
}
return ret;
}
void QuestParserCollection::LoadPerlEventExportSettings(PerlEventExportSettings* s) void QuestParserCollection::LoadPerlEventExportSettings(PerlEventExportSettings* s)
{ {
for (int i = 0; i < _LargestEventID; i++) { for (int i = 0; i < _LargestEventID; i++) {
+39
View File
@@ -72,6 +72,7 @@ public:
bool ItemHasQuestSub(EQ::ItemInstance* inst, QuestEventID event_id); bool ItemHasQuestSub(EQ::ItemInstance* inst, QuestEventID event_id);
bool BotHasQuestSub(QuestEventID event_id); bool BotHasQuestSub(QuestEventID event_id);
bool MercHasQuestSub(QuestEventID event_id); bool MercHasQuestSub(QuestEventID event_id);
bool ZoneHasQuestSub(QuestEventID event_id);
int EventNPC( int EventNPC(
QuestEventID event_id, QuestEventID event_id,
@@ -172,6 +173,14 @@ public:
std::vector<std::any>* extra_pointers = nullptr std::vector<std::any>* extra_pointers = nullptr
); );
int EventZone(
QuestEventID event_id,
Zone* zone,
std::string data,
uint32 extra_data = 0,
std::vector<std::any>* extra_pointers = nullptr
);
void GetErrors(std::list<std::string> &quest_errors); void GetErrors(std::list<std::string> &quest_errors);
/* /*
@@ -209,6 +218,8 @@ private:
bool BotHasQuestSubGlobal(QuestEventID event_id); bool BotHasQuestSubGlobal(QuestEventID event_id);
bool MercHasQuestSubLocal(QuestEventID event_id); bool MercHasQuestSubLocal(QuestEventID event_id);
bool MercHasQuestSubGlobal(QuestEventID event_id); bool MercHasQuestSubGlobal(QuestEventID event_id);
bool ZoneHasQuestSubLocal(QuestEventID event_id);
bool ZoneHasQuestSubGlobal(QuestEventID event_id);
int EventNPCLocal( int EventNPCLocal(
QuestEventID event_id, QuestEventID event_id,
@@ -280,6 +291,22 @@ private:
std::vector<std::any>* extra_pointers std::vector<std::any>* extra_pointers
); );
int EventZoneLocal(
QuestEventID event_id,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any>* extra_pointers
);
int EventZoneGlobal(
QuestEventID event_id,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any>* extra_pointers
);
QuestInterface* GetQIByNPCQuest(uint32 npc_id, std::string& filename); QuestInterface* GetQIByNPCQuest(uint32 npc_id, std::string& filename);
QuestInterface* GetQIByGlobalNPCQuest(std::string& filename); QuestInterface* GetQIByGlobalNPCQuest(std::string& filename);
QuestInterface* GetQIByPlayerQuest(std::string& filename); QuestInterface* GetQIByPlayerQuest(std::string& filename);
@@ -291,6 +318,8 @@ private:
QuestInterface* GetQIByGlobalBotQuest(std::string& filename); QuestInterface* GetQIByGlobalBotQuest(std::string& filename);
QuestInterface* GetQIByMercQuest(std::string& filename); QuestInterface* GetQIByMercQuest(std::string& filename);
QuestInterface* GetQIByGlobalMercQuest(std::string& filename); QuestInterface* GetQIByGlobalMercQuest(std::string& filename);
QuestInterface* GetQIByZoneQuest(std::string& filename);
QuestInterface* GetQIByGlobalZoneQuest(std::string& filename);
int DispatchEventNPC( int DispatchEventNPC(
QuestEventID event_id, QuestEventID event_id,
@@ -347,6 +376,14 @@ private:
std::vector<std::any>* extra_pointers std::vector<std::any>* extra_pointers
); );
int DispatchEventZone(
QuestEventID event_id,
Zone* zone,
std::string data,
uint32 extra_data,
std::vector<std::any>* extra_pointers
);
std::map<uint32, QuestInterface*> _interfaces; std::map<uint32, QuestInterface*> _interfaces;
std::map<uint32, std::string> _extensions; std::map<uint32, std::string> _extensions;
std::list<QuestInterface*> _load_precedence; std::list<QuestInterface*> _load_precedence;
@@ -359,6 +396,8 @@ private:
uint32 _global_bot_quest_status; uint32 _global_bot_quest_status;
uint32 _merc_quest_status; uint32 _merc_quest_status;
uint32 _global_merc_quest_status; uint32 _global_merc_quest_status;
uint32 _zone_quest_status;
uint32 _global_zone_quest_status;
std::map<uint32, uint32> _spell_quest_status; std::map<uint32, uint32> _spell_quest_status;
std::map<uint32, uint32> _item_quest_status; std::map<uint32, uint32> _item_quest_status;
std::map<std::string, uint32> _encounter_quest_status; std::map<std::string, uint32> _encounter_quest_status;
+89 -53
View File
@@ -64,10 +64,10 @@ QuestManager quest_manager;
EQ::ItemInstance* questitem = nullptr; \ EQ::ItemInstance* questitem = nullptr; \
const SPDat_Spell_Struct* questspell = nullptr; \ const SPDat_Spell_Struct* questspell = nullptr; \
bool depop_npc = false; \ bool depop_npc = false; \
std::string encounter; \ std::string encounter = ""; \
do { \ do { \
if(!quests_running_.empty()) { \ if(!m_running_quests.empty()) { \
running_quest e = quests_running_.top(); \ RunningQuest e = m_running_quests.top(); \
owner = e.owner; \ owner = e.owner; \
initiator = e.initiator; \ initiator = e.initiator; \
questitem = e.questitem; \ questitem = e.questitem; \
@@ -124,33 +124,30 @@ void QuestManager::Process() {
} }
} }
void QuestManager::StartQuest(Mob *_owner, Client *_initiator, EQ::ItemInstance* _questitem, const SPDat_Spell_Struct* _questspell, std::string encounter) { void QuestManager::StartQuest(const RunningQuest& q)
running_quest run; {
run.owner = _owner; m_running_quests.push(q);
run.initiator = _initiator;
run.questitem = _questitem;
run.questspell = _questspell;
run.depop_npc = false;
run.encounter = encounter;
quests_running_.push(run);
} }
void QuestManager::EndQuest() { void QuestManager::EndQuest() {
running_quest run = quests_running_.top(); RunningQuest run = m_running_quests.top();
if (run.depop_npc && run.owner->IsNPC()) { if (run.depop_npc && run.owner->IsNPC()) {
//clear out any timers for them... //clear out any timers for them...
std::list<QuestTimer>::iterator cur = QTimerList.begin(), end; std::list<QuestTimer>::iterator cur = QTimerList.begin(), end;
end = QTimerList.end(); end = QTimerList.end();
while (cur != end) { while (cur != end) {
if (cur->mob == run.owner) if (cur->mob == run.owner) {
cur = QTimerList.erase(cur); cur = QTimerList.erase(cur);
else } else {
++cur; ++cur;
} }
}
run.owner->Depop(); run.owner->Depop();
} }
quests_running_.pop();
m_running_quests.pop();
} }
void QuestManager::ClearAllTimers() { void QuestManager::ClearAllTimers() {
@@ -1098,18 +1095,18 @@ void QuestManager::depop(int npc_type) {
tmp->CastToNPC()->Depop(); tmp->CastToNPC()->Depop();
} }
else { else {
running_quest e = quests_running_.top(); RunningQuest e = m_running_quests.top();
e.depop_npc = true; e.depop_npc = true;
quests_running_.pop(); m_running_quests.pop();
quests_running_.push(e); m_running_quests.push(e);
} }
} }
} }
else { //depop self else { //depop self
running_quest e = quests_running_.top(); RunningQuest e = m_running_quests.top();
e.depop_npc = true; e.depop_npc = true;
quests_running_.pop(); m_running_quests.pop();
quests_running_.push(e); m_running_quests.push(e);
} }
} }
} }
@@ -1606,7 +1603,7 @@ void QuestManager::save() {
void QuestManager::faction(int faction_id, int faction_value, int temp) { void QuestManager::faction(int faction_id, int faction_value, int temp) {
QuestManagerCurrentQuestVars(); QuestManagerCurrentQuestVars();
running_quest run = quests_running_.top(); RunningQuest run = m_running_quests.top();
if(run.owner->IsCharmed() == false && initiator) { if(run.owner->IsCharmed() == false && initiator) {
if(faction_id != 0 && faction_value != 0) { if(faction_id != 0 && faction_value != 0) {
initiator->SetFactionLevel2( initiator->SetFactionLevel2(
@@ -2077,10 +2074,10 @@ void QuestManager::respawn(int npcTypeID, int grid) {
if (!owner || !owner->IsNPC()) if (!owner || !owner->IsNPC())
return; return;
running_quest e = quests_running_.top(); RunningQuest e = m_running_quests.top();
e.depop_npc = true; e.depop_npc = true;
quests_running_.pop(); m_running_quests.pop();
quests_running_.push(e); m_running_quests.push(e);
const NPCType* npcType = nullptr; const NPCType* npcType = nullptr;
if ((npcType = content_db.LoadNPCTypesData(npcTypeID))) if ((npcType = content_db.LoadNPCTypesData(npcTypeID)))
@@ -3980,81 +3977,90 @@ void QuestManager::ReloadZoneStaticData()
} }
} }
Client *QuestManager::GetInitiator() const { Client* QuestManager::GetInitiator() const
if(!quests_running_.empty()) { {
running_quest e = quests_running_.top(); if (!m_running_quests.empty()) {
RunningQuest e = m_running_quests.top();
return e.initiator; return e.initiator;
} }
return nullptr; return nullptr;
} }
NPC *QuestManager::GetNPC() const { NPC* QuestManager::GetNPC() const
if(!quests_running_.empty()) { {
running_quest e = quests_running_.top(); if (!m_running_quests.empty()) {
RunningQuest e = m_running_quests.top();
return (e.owner && e.owner->IsNPC()) ? e.owner->CastToNPC() : nullptr; return (e.owner && e.owner->IsNPC()) ? e.owner->CastToNPC() : nullptr;
} }
return nullptr; return nullptr;
} }
Bot *QuestManager::GetBot() const { Bot* QuestManager::GetBot() const
if (!quests_running_.empty()) { {
running_quest e = quests_running_.top(); if (!m_running_quests.empty()) {
RunningQuest e = m_running_quests.top();
return (e.owner && e.owner->IsBot()) ? e.owner->CastToBot() : nullptr; return (e.owner && e.owner->IsBot()) ? e.owner->CastToBot() : nullptr;
} }
return nullptr; return nullptr;
} }
Merc *QuestManager::GetMerc() const { Merc* QuestManager::GetMerc() const
if (!quests_running_.empty()) { {
running_quest e = quests_running_.top(); if (!m_running_quests.empty()) {
RunningQuest e = m_running_quests.top();
return (e.owner && e.owner->IsMerc()) ? e.owner->CastToMerc() : nullptr; return (e.owner && e.owner->IsMerc()) ? e.owner->CastToMerc() : nullptr;
} }
return nullptr; return nullptr;
} }
Mob *QuestManager::GetOwner() const { Mob* QuestManager::GetOwner() const
if(!quests_running_.empty()) { {
running_quest e = quests_running_.top(); if (!m_running_quests.empty()) {
RunningQuest e = m_running_quests.top();
return e.owner; return e.owner;
} }
return nullptr; return nullptr;
} }
EQ::InventoryProfile *QuestManager::GetInventory() const { EQ::InventoryProfile* QuestManager::GetInventory() const
if(!quests_running_.empty()) { {
running_quest e = quests_running_.top(); if (!m_running_quests.empty()) {
RunningQuest e = m_running_quests.top();
return &e.initiator->GetInv(); return &e.initiator->GetInv();
} }
return nullptr; return nullptr;
} }
EQ::ItemInstance *QuestManager::GetQuestItem() const { EQ::ItemInstance* QuestManager::GetQuestItem() const
if(!quests_running_.empty()) { {
running_quest e = quests_running_.top(); if (!m_running_quests.empty()) {
RunningQuest e = m_running_quests.top();
return e.questitem; return e.questitem;
} }
return nullptr; return nullptr;
} }
const SPDat_Spell_Struct *QuestManager::GetQuestSpell() { const SPDat_Spell_Struct* QuestManager::GetQuestSpell()
if(!quests_running_.empty()) { {
running_quest e = quests_running_.top(); if (!m_running_quests.empty()) {
RunningQuest e = m_running_quests.top();
return e.questspell; return e.questspell;
} }
return nullptr; return nullptr;
} }
std::string QuestManager::GetEncounter() const { std::string QuestManager::GetEncounter() const
if(!quests_running_.empty()) { {
running_quest e = quests_running_.top(); if (!m_running_quests.empty()) {
RunningQuest e = m_running_quests.top();
return e.encounter; return e.encounter;
} }
@@ -4661,3 +4667,33 @@ bool QuestManager::handin(std::map<std::string, uint32> required) {
return owner->CastToNPC()->CheckHandin(initiator, {}, required, {}); return owner->CastToNPC()->CheckHandin(initiator, {}, required, {});
} }
std::vector<std::string> QuestManager::GetPausedTimers(Mob* m)
{
std::vector<std::string> v;
if (m && !PTimerList.empty()) {
for (auto e = PTimerList.begin(); e != PTimerList.end(); e++) {
if (e->owner == m) {
v.emplace_back(e->name);
}
}
}
return v;
}
std::vector<std::string> QuestManager::GetTimers(Mob* m)
{
std::vector<std::string> v;
if (m && !QTimerList.empty()) {
for (auto e = QTimerList.begin(); e != QTimerList.end(); e++) {
if (e->mob == m) {
v.emplace_back(e->name);
}
}
}
return v;
}
+16 -11
View File
@@ -33,28 +33,31 @@ namespace EQ
class ItemInstance; class ItemInstance;
} }
class QuestManager { struct RunningQuest {
struct running_quest { Mob* owner = nullptr;
Mob *owner; Client* initiator = nullptr;
Client *initiator; EQ::ItemInstance* questitem = nullptr;
EQ::ItemInstance* questitem; const SPDat_Spell_Struct* questspell = nullptr;
const SPDat_Spell_Struct* questspell; bool depop_npc = false;
bool depop_npc; std::string encounter = "";
std::string encounter; Zone* zone = nullptr;
}; };
class QuestManager {
struct PausedTimer { struct PausedTimer {
Mob* owner; Mob* owner;
std::string name; std::string name;
uint32 time; uint32 time;
}; };
public: public:
QuestManager(); QuestManager();
virtual ~QuestManager(); virtual ~QuestManager();
void StartQuest(Mob *_owner, Client *_initiator = nullptr, EQ::ItemInstance* _questitem = nullptr, const SPDat_Spell_Struct* _questspell = nullptr, std::string encounter = ""); void StartQuest(const RunningQuest& q);
void EndQuest(); void EndQuest();
bool QuestsRunning() { return !quests_running_.empty(); } bool QuestsRunning() { return !m_running_quests.empty(); }
void Process(); void Process();
@@ -361,6 +364,8 @@ public:
bool SetAutoLoginCharacterNameByAccountID(uint32 account_id, const std::string& character_name); bool SetAutoLoginCharacterNameByAccountID(uint32 account_id, const std::string& character_name);
void SpawnCircle(uint32 npc_id, glm::vec4 position, float radius, uint32 points); void SpawnCircle(uint32 npc_id, glm::vec4 position, float radius, uint32 points);
void SpawnGrid(uint32 npc_id, glm::vec4 position, float spacing, uint32 spawn_count); void SpawnGrid(uint32 npc_id, glm::vec4 position, float spacing, uint32 spawn_count);
std::vector<std::string> GetPausedTimers(Mob* m);
std::vector<std::string> GetTimers(Mob* m);
Bot *GetBot() const; Bot *GetBot() const;
Client *GetInitiator() const; Client *GetInitiator() const;
@@ -381,7 +386,7 @@ public:
bool handin(std::map<std::string, uint32> required); bool handin(std::map<std::string, uint32> required);
private: private:
std::stack<running_quest> quests_running_; std::stack<RunningQuest> m_running_quests;
bool HaveProximitySays; bool HaveProximitySays;
+59 -49
View File
@@ -717,7 +717,7 @@ uint32 Raid::GetTotalRaidDamage(Mob* other)
return total; 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) { if (!caster) {
return; return;
@@ -728,26 +728,30 @@ void Raid::HealGroup(uint32 heal_amt, Mob* caster, uint32 gid, float range)
} }
float distance; float distance;
float range2 = range*range; float range_squared = range * range;
int member_count = 0;
int numMem = 0;
for (const auto& m : members) { 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()); distance = DistanceSquared(caster->GetPosition(), m.member->GetPosition());
if (distance <= range2) { if (distance <= range_squared) {
numMem += 1; member_count += 1;
} }
} }
} }
heal_amt /= numMem; if (member_count > 0) {
heal_amount /= member_count;
}
for (const auto& m : members) { 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()); distance = DistanceSquared(caster->GetPosition(), m.member->GetPosition());
if (distance <= range2) { if (distance <= range_squared) {
m.member->SetHP(m.member->GetHP() + heal_amt); m.member->SetHP(m.member->GetHP() + heal_amount);
m.member->SendHPUpdate(); 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) { if (!caster) {
return; return;
@@ -765,44 +769,48 @@ void Raid::BalanceHP(int32 penalty, uint32 gid, float range, Mob* caster, int32
range = 200; 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 distance;
float range2 = range*range; float range_squared = range * range;
for (const auto& m : members) { 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()); distance = DistanceSquared(caster->GetPosition(), m.member->GetPosition());
if (distance <= range2) { if (distance <= range_squared) {
dmgtaken_tmp = m.member->GetMaxHP() - m.member->GetHP(); damage_taken_temporary = m.member->GetMaxHP() - m.member->GetHP();
if (limit && (dmgtaken_tmp > limit)) { if (limit && (damage_taken_temporary > limit)) {
dmgtaken_tmp = limit; damage_taken_temporary = limit;
} }
dmgtaken += dmgtaken_tmp; damage_taken += damage_taken_temporary;
numMem += 1; member_count += 1;
} }
} }
} }
dmgtaken += dmgtaken * penalty / 100; damage_taken += damage_taken * penalty / 100;
dmgtaken /= numMem;
if (member_count > 0) {
damage_taken /= member_count;
}
for (const auto& m : members) { 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()); distance = DistanceSquared(caster->GetPosition(), m.member->GetPosition());
//this way the ability will never kill someone //this way the ability will never kill someone
//but it will come darn close //but it will come darn close
if (distance <= range2) { if (distance <= range_squared) {
if ((m.member->GetMaxHP() - dmgtaken) < 1) { if ((m.member->GetMaxHP() - damage_taken) < 1) {
m.member->SetHP(1); m.member->SetHP(1);
m.member->SendHPUpdate(); m.member->SendHPUpdate();
} } else {
m.member->SetHP(m.member->GetMaxHP() - damage_taken);
else {
m.member->SetHP(m.member->GetMaxHP() - dmgtaken);
m.member->SendHPUpdate(); 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) { if (!caster) {
return; return;
@@ -821,54 +829,56 @@ void Raid::BalanceMana(int32 penalty, uint32 gid, float range, Mob* caster, int3
} }
float distance; float distance;
float range2 = range*range; float range_squared = range * range;
int manataken = 0; int mana_taken = 0;
int numMem = 0; int mana_taken_temporary = 0;
int manataken_tmp = 0; int member_count = 0;
for (const auto& m : members) { for (const auto& m : members) {
if (m.is_bot) { if (m.is_bot) {
continue; 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()); distance = DistanceSquared(caster->GetPosition(), m.member->GetPosition());
if (distance <= range2) { if (distance <= range_squared) {
manataken_tmp = m.member->GetMaxMana() - m.member->GetMana(); mana_taken_temporary = m.member->GetMaxMana() - m.member->GetMana();
if (limit && (manataken_tmp > limit)) { if (limit && (mana_taken_temporary > limit)) {
manataken_tmp = limit; mana_taken_temporary = limit;
} }
manataken += manataken_tmp; mana_taken += mana_taken_temporary;
numMem += 1; member_count += 1;
} }
} }
} }
manataken += manataken * penalty / 100; mana_taken += mana_taken * penalty / 100;
manataken /= numMem;
if (member_count > 0) {
mana_taken /= member_count;
}
for (const auto& m : members) { for (const auto& m : members) {
if (m.is_bot) { if (m.is_bot) {
continue; continue;
} }
if (m.member && m.group_number == gid) { if (m.member && m.group_number == group_id) {
distance = DistanceSquared(caster->GetPosition(), m.member->GetPosition()); distance = DistanceSquared(caster->GetPosition(), m.member->GetPosition());
if (distance <= range2) { if (distance <= range_squared) {
if ((m.member->GetMaxMana() - manataken) < 1) { if ((m.member->GetMaxMana() - mana_taken) < 1) {
m.member->SetMana(1); m.member->SetMana(1);
if (m.member->IsClient()) { if (m.member->IsClient()) {
m.member->CastToClient()->SendManaUpdate(); m.member->CastToClient()->SendManaUpdate();
} }
} } else {
else { m.member->SetMana(m.member->GetMaxMana() - mana_taken);
m.member->SetMana(m.member->GetMaxMana() - manataken);
if (m.member->IsClient()) { if (m.member->IsClient()) {
m.member->CastToClient()->SendManaUpdate(); m.member->CastToClient()->SendManaUpdate();
+3 -3
View File
@@ -167,9 +167,9 @@ public:
void CastGroupSpell(Mob* caster,uint16 spellid, uint32 gid); void CastGroupSpell(Mob* caster,uint16 spellid, uint32 gid);
void SplitExp(ExpSource exp_source, const uint64 exp, Mob* other); void SplitExp(ExpSource exp_source, const uint64 exp, Mob* other);
uint32 GetTotalRaidDamage(Mob* other); uint32 GetTotalRaidDamage(Mob* other);
void BalanceHP(int32 penalty, uint32 gid, float range = 0, Mob* caster = nullptr, int32 limit = 0); void BalanceHP(int32 penalty, uint32 group_id, 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 BalanceMana(int32 penalty, uint32 group_id, float range = 0, Mob* caster = nullptr, int32 limit = 0);
void HealGroup(uint32 heal_amt, Mob* caster, uint32 gid, float range = 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 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); void TeleportGroup(Mob* sender, uint32 zoneID, uint16 instance_id, float x, float y, float z, float heading, uint32 gid);
+284
View File
@@ -1693,6 +1693,25 @@ bool Zone::Process() {
} }
} }
const bool has_timer_event = parse->ZoneHasQuestSub(EVENT_TIMER);
for (auto e : zone_timers) {
if (e.timer_.Enabled() && e.timer_.Check()) {
if (has_timer_event) {
parse->EventZone(EVENT_TIMER, this, e.name);
}
}
}
if (!m_zone_signals.empty()) {
int signal_id = m_zone_signals.front();
m_zone_signals.pop_front();
if (parse->ZoneHasQuestSub(EVENT_SIGNAL)) {
parse->EventZone(EVENT_SIGNAL, this, std::to_string(signal_id), 0);
}
}
mMovementManager->Process(); mMovementManager->Process();
return true; return true;
@@ -1935,6 +1954,8 @@ void Zone::Repop(bool is_forced)
quest_manager.ClearAllTimers(); quest_manager.ClearAllTimers();
StopAllTimers();
LogInfo("Loading spawn groups"); LogInfo("Loading spawn groups");
if (!content_db.LoadSpawnGroups(short_name, GetInstanceVersion(), &spawn_group_list)) { if (!content_db.LoadSpawnGroups(short_name, GetInstanceVersion(), &spawn_group_list)) {
LogError("Loading spawn groups failed"); LogError("Loading spawn groups failed");
@@ -3301,4 +3322,267 @@ void Zone::ReloadMaps()
pathing = IPathfinder::Load(map_name); pathing = IPathfinder::Load(map_name);
} }
uint32 Zone::GetTimerDuration(std::string name)
{
if (!IsLoaded() || zone_timers.empty()) {
return 0;
}
const auto& e = std::find_if(
zone_timers.begin(),
zone_timers.end(),
[&name](ZoneTimer e) {
return e.name == name;
}
);
return e != zone_timers.end() ? e->timer_.GetDuration() : 0;
}
uint32 Zone::GetTimerRemainingTime(std::string name)
{
if (!IsLoaded() || zone_timers.empty()) {
return 0;
}
const auto& e = std::find_if(
zone_timers.begin(),
zone_timers.end(),
[&name](ZoneTimer e) {
return e.name == name;
}
);
return e != zone_timers.end() ? e->timer_.GetRemainingTime() : 0;
}
bool Zone::HasTimer(std::string name)
{
if (!IsLoaded() || zone_timers.empty()) {
return false;
}
const auto& e = std::find_if(
zone_timers.begin(),
zone_timers.end(),
[&name](ZoneTimer e) {
return e.name == name;
}
);
return e != zone_timers.end();
}
bool Zone::IsPausedTimer(std::string name)
{
if (!IsLoaded() || paused_zone_timers.empty()) {
return false;
}
const auto& e = std::find_if(
paused_zone_timers.begin(),
paused_zone_timers.end(),
[&name](PausedZoneTimer e) {
return e.name == name;
}
);
return e != paused_zone_timers.end();
}
void Zone::PauseTimer(std::string name)
{
if (
!IsLoaded() ||
zone_timers.empty() ||
!HasTimer(name) ||
IsPausedTimer(name)
) {
return;
}
uint32 remaining_time = 0;
const bool has_pause_event = parse->ZoneHasQuestSub(EVENT_TIMER_PAUSE);
if (!zone_timers.empty()) {
for (auto e = zone_timers.begin(); e != zone_timers.end(); e++) {
if (e->name == name) {
remaining_time = e->timer_.GetRemainingTime();
zone_timers.erase(e);
const std::string& export_string = fmt::format(
"{} {}",
name,
remaining_time
);
LogQuests(
"Pausing timer [{}] with [{}] ms remaining",
name,
remaining_time
);
paused_zone_timers.emplace_back(
PausedZoneTimer{
.name = name,
.remaining_time = remaining_time
}
);
if (has_pause_event) {
parse->EventZone(EVENT_TIMER_PAUSE, this, export_string);
}
break;
}
}
}
}
void Zone::ResumeTimer(std::string name)
{
if (
!IsLoaded() ||
paused_zone_timers.empty() ||
!IsPausedTimer(name)
) {
return;
}
uint32 remaining_time = 0;
if (!paused_zone_timers.empty()) {
for (auto e = paused_zone_timers.begin(); e != paused_zone_timers.end(); e++) {
if (e->name == name) {
remaining_time = e->remaining_time;
paused_zone_timers.erase(e);
if (!remaining_time) {
LogQuests("Paused timer [{}] not found or has expired.", name);
return;
}
const std::string& export_string = fmt::format(
"{} {}",
name,
remaining_time
);
LogQuests(
"Creating a new timer and resuming [{}] with [{}] ms remaining",
name,
remaining_time
);
zone_timers.emplace_back(ZoneTimer(name, remaining_time));
if (parse->ZoneHasQuestSub(EVENT_TIMER_RESUME)) {
parse->EventZone(EVENT_TIMER_RESUME, this, export_string);
}
break;
}
}
}
}
void Zone::SetTimer(std::string name, uint32 duration)
{
if (!IsLoaded() || HasTimer(name)) {
return;
}
zone_timers.emplace_back(ZoneTimer(name, duration));
if (parse->ZoneHasQuestSub(EVENT_TIMER_START)) {
const std::string& export_string = fmt::format("{} {}", name, duration);
parse->EventZone(EVENT_TIMER_START, this, export_string);
}
}
void Zone::StopTimer(std::string name)
{
if (
!IsLoaded() ||
zone_timers.empty() ||
!HasTimer(name) ||
IsPausedTimer(name)
) {
return;
}
const bool has_stop_event = parse->ZoneHasQuestSub(EVENT_TIMER_STOP);
for (auto e = zone_timers.begin(); e != zone_timers.end(); e++) {
if (e->name == name) {
if (has_stop_event) {
parse->EventZone(EVENT_TIMER_STOP, this, name);
}
zone_timers.erase(e);
break;
}
}
}
void Zone::StopAllTimers()
{
if (!IsLoaded() || zone_timers.empty()) {
return;
}
const bool has_stop_event = parse->ZoneHasQuestSub(EVENT_TIMER_STOP);
for (auto e = zone_timers.begin(); e != zone_timers.end();) {
if (has_stop_event) {
parse->EventZone(EVENT_TIMER_STOP, this, e->name);
}
e = zone_timers.erase(e);
}
}
void Zone::Signal(int signal_id)
{
m_zone_signals.push_back(signal_id);
}
void Zone::SendPayload(int payload_id, std::string payload_value)
{
if (parse->ZoneHasQuestSub(EVENT_PAYLOAD)) {
const auto& export_string = fmt::format("{} {}", payload_id, payload_value);
parse->EventZone(EVENT_PAYLOAD, this, export_string, 0);
}
}
std::vector<std::string> Zone::GetPausedTimers()
{
std::vector<std::string> v;
if (!paused_zone_timers.empty()) {
for (auto e = paused_zone_timers.begin(); e != paused_zone_timers.end(); e++) {
v.emplace_back(e->name);
}
}
return v;
}
std::vector<std::string> Zone::GetTimers()
{
std::vector<std::string> v;
if (!zone_timers.empty()) {
for (auto e = zone_timers.begin(); e != zone_timers.end(); e++) {
v.emplace_back(e->name);
}
}
return v;
}
#include "zone_loot.cpp" #include "zone_loot.cpp"
+32
View File
@@ -486,6 +486,26 @@ public:
static void ClearZoneState(uint32 zone_id, uint32 instance_id); static void ClearZoneState(uint32 zone_id, uint32 instance_id);
void ReloadMaps(); void ReloadMaps();
void Signal(int signal_id);
void SendPayload(int payload_id, std::string payload_value);
struct PausedZoneTimer {
std::string name;
uint32 remaining_time;
};
uint32 GetTimerDuration(std::string name);
uint32 GetTimerRemainingTime(std::string name);
bool HasTimer(std::string name);
bool IsPausedTimer(std::string name);
void PauseTimer(std::string name);
void ResumeTimer(std::string name);
void SetTimer(std::string name, uint32 duration);
void StopTimer(std::string name);
void StopAllTimers();
std::vector<std::string> GetPausedTimers();
std::vector<std::string> GetTimers();
private: private:
bool allow_mercs; bool allow_mercs;
bool can_bind; bool can_bind;
@@ -552,6 +572,18 @@ private:
std::vector<BaseDataRepository::BaseData> m_base_data = { }; std::vector<BaseDataRepository::BaseData> m_base_data = { };
uint32_t m_zone_server_id = 0; uint32_t m_zone_server_id = 0;
class ZoneTimer {
public:
inline ZoneTimer(std::string _name, uint32 duration)
: name(_name), timer_(duration) { timer_.Start(duration, false); }
std::string name;
Timer timer_;
};
std::vector<ZoneTimer> zone_timers;
std::vector<PausedZoneTimer> paused_zone_timers;
std::deque<int> m_zone_signals;
}; };
#endif #endif