mirror of
https://github.com/EQEmu/Server.git
synced 2026-06-13 02:38:45 +00:00
Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d41725e325 | |||
| 88580b69b6 | |||
| f7a6fe595a | |||
| 07d14c2681 | |||
| eac7a73fb6 | |||
| c5715f1f14 | |||
| 3902230fa1 | |||
| 212969f5cd | |||
| de4226fdc9 | |||
| 8b13434197 | |||
| 27274397ec | |||
| 2b79a36014 | |||
| 8cf52294e9 | |||
| 0ef79903f8 | |||
| ab14458f9e | |||
| 5b94e736b3 | |||
| c3b8cc9744 | |||
| 89e3b2c72e | |||
| 23c4aa241b | |||
| acb7584e26 | |||
| a885bd9322 | |||
| 20fe1926e0 | |||
| eb7118754b | |||
| 3611b49f68 | |||
| 511d8a8bb3 | |||
| 1598d2e17b | |||
| 805757ba87 | |||
| eb6ac25540 | |||
| cb634cf57d | |||
| 2f7ca2cdc8 | |||
| 425d24c1f4 | |||
| 875df8e64a | |||
| 7a2d2a0c51 | |||
| 5296202e56 | |||
| e2db8ffea8 | |||
| fa2ab11676 |
@@ -1,3 +1,81 @@
|
|||||||
|
## [23.2.0] 3/3/2025
|
||||||
|
|
||||||
|
### Crash
|
||||||
|
|
||||||
|
* Database SetMutex crash fix ([#4741](https://github.com/EQEmu/Server/pull/4741)) @Akkadius 2025-03-03
|
||||||
|
* Fix Aura process crash with bots ([#4743](https://github.com/EQEmu/Server/pull/4743)) @Akkadius 2025-03-03
|
||||||
|
* Fix crash in add loot code path ([#4745](https://github.com/EQEmu/Server/pull/4745)) @Akkadius 2025-03-03
|
||||||
|
* Fix world repop crash ([#4742](https://github.com/EQEmu/Server/pull/4742)) @Akkadius 2025-03-03
|
||||||
|
* Potential crash fix in scan close mobs ([#4744](https://github.com/EQEmu/Server/pull/4744)) @Akkadius 2025-03-03
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
* Cleanup zone buckets on instance purge. ([#4739](https://github.com/EQEmu/Server/pull/4739)) @zimp-wow 2025-03-02
|
||||||
|
* Fix an error causing Endurance Regen to not be applied by items. ([#4738](https://github.com/EQEmu/Server/pull/4738)) @catapultam-habeo 2025-03-02
|
||||||
|
|
||||||
|
### World
|
||||||
|
|
||||||
|
* Check if port in use to avoid double booting mistakes ([#4740](https://github.com/EQEmu/Server/pull/4740)) @Akkadius 2025-03-03
|
||||||
|
|
||||||
|
## [23.1.0] 3/1/2025
|
||||||
|
|
||||||
|
### Bots
|
||||||
|
|
||||||
|
* Fix unresponsive bots in groups upon group wipe ([#4712](https://github.com/EQEmu/Server/pull/4712)) @nytmyr 2025-02-28
|
||||||
|
|
||||||
|
### Code
|
||||||
|
|
||||||
|
* More login <-> world code cleanup ([#4724](https://github.com/EQEmu/Server/pull/4724)) @Akkadius 2025-02-28
|
||||||
|
|
||||||
|
### Crash
|
||||||
|
|
||||||
|
* Check for directory existence before traversing in CheckForCompatibleQuestPlugins ([#4730](https://github.com/EQEmu/Server/pull/4730)) @Akkadius 2025-03-02
|
||||||
|
* Fix filesystem crash / exception in DatabaseDumpService::RemoveCredentialsFile() ([#4731](https://github.com/EQEmu/Server/pull/4731)) @Akkadius 2025-03-01
|
||||||
|
* Fix large file size crash in File::GetContents for windows ([#4735](https://github.com/EQEmu/Server/pull/4735)) @Akkadius 2025-03-02
|
||||||
|
* Fix reload concurrency crash when ran from Spire ([#4733](https://github.com/EQEmu/Server/pull/4733)) @Akkadius 2025-03-02
|
||||||
|
* Validate item in SE_SummonItemIntoBag ([#4734](https://github.com/EQEmu/Server/pull/4734)) @Akkadius 2025-03-02
|
||||||
|
* World CLI validation ([#4728](https://github.com/EQEmu/Server/pull/4728)) @Akkadius 2025-03-01
|
||||||
|
|
||||||
|
### Database
|
||||||
|
|
||||||
|
* Remove force_interactive from big bag updates ([#4727](https://github.com/EQEmu/Server/pull/4727)) @Akkadius 2025-03-01
|
||||||
|
|
||||||
|
### Feature
|
||||||
|
|
||||||
|
* Add a rule for spells to bypass stacking rules ([#4716](https://github.com/EQEmu/Server/pull/4716)) @catapultam-habeo 2025-02-28
|
||||||
|
* Evolving items Additions ([#4725](https://github.com/EQEmu/Server/pull/4725)) @neckkola 2025-03-01
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
* Add character_pet_name to player tables schema @Akkadius 2025-03-02
|
||||||
|
* Add client packets to questmanager:setguild ([#4732](https://github.com/EQEmu/Server/pull/4732)) @neckkola 2025-03-01
|
||||||
|
* Clear m_completed_shared_tasks before reloading @Akkadius 2025-02-24
|
||||||
|
* Fix AA Reset Error Message ([#4720](https://github.com/EQEmu/Server/pull/4720)) @Kinglykrab 2025-02-28
|
||||||
|
* Fix Issue with Suffixes/Prefixes ([#4723](https://github.com/EQEmu/Server/pull/4723)) @Kinglykrab 2025-02-28
|
||||||
|
* Fix Trading Items to Bot Pets ([#4721](https://github.com/EQEmu/Server/pull/4721)) @MortimerGreenwald 2025-02-28
|
||||||
|
* Refactor ApplyItemBonuses to fix double-counting of ATK and recommended levels not correctly applying ([#4713](https://github.com/EQEmu/Server/pull/4713)) @catapultam-habeo 2025-03-01
|
||||||
|
|
||||||
|
### Loginserver
|
||||||
|
|
||||||
|
* Minor cleanup ([#4729](https://github.com/EQEmu/Server/pull/4729)) @Akkadius 2025-03-01
|
||||||
|
|
||||||
|
### Quest API
|
||||||
|
|
||||||
|
* Add Key Ring Methods to Perl and Lua ([#4719](https://github.com/EQEmu/Server/pull/4719)) @Kinglykrab 2025-02-28
|
||||||
|
* Implement eq.handin() and quest::handin() ([#4718](https://github.com/EQEmu/Server/pull/4718)) @Akkadius 2025-02-28
|
||||||
|
|
||||||
|
### Tasks
|
||||||
|
|
||||||
|
* Extend IsTaskCompleted to also be aware of shared task completion ([#4714](https://github.com/EQEmu/Server/pull/4714)) @Akkadius 2025-02-24
|
||||||
|
|
||||||
|
### Zone
|
||||||
|
|
||||||
|
* Implement Zone State Saving on Shutdown ([#4715](https://github.com/EQEmu/Server/pull/4715)) @Akkadius 2025-02-28
|
||||||
|
|
||||||
|
### Zone State
|
||||||
|
|
||||||
|
* Wrap all serialization/deserialization in try/catch ([#4726](https://github.com/EQEmu/Server/pull/4726)) @Akkadius 2025-03-01
|
||||||
|
|
||||||
## [23.0.2] 2/21/2025
|
## [23.0.2] 2/21/2025
|
||||||
|
|
||||||
### Bots
|
### Bots
|
||||||
|
|||||||
+1
-1
@@ -245,7 +245,7 @@ uint32 Database::CreateAccount(
|
|||||||
e.password = password;
|
e.password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
LogInfo("Account Attempting to be created: [{}:{}] status: {}", loginserver, name, status);
|
LogInfo("Account attempting to be created loginserver [{}] name [{}] status [{}]", loginserver, name, status);
|
||||||
|
|
||||||
e = AccountRepository::InsertOne(*this, e);
|
e = AccountRepository::InsertOne(*this, e);
|
||||||
|
|
||||||
|
|||||||
@@ -596,8 +596,13 @@ void DatabaseDumpService::BuildCredentialsFile()
|
|||||||
void DatabaseDumpService::RemoveCredentialsFile()
|
void DatabaseDumpService::RemoveCredentialsFile()
|
||||||
{
|
{
|
||||||
if (File::Exists(CREDENTIALS_FILE)) {
|
if (File::Exists(CREDENTIALS_FILE)) {
|
||||||
|
try {
|
||||||
std::filesystem::remove(CREDENTIALS_FILE);
|
std::filesystem::remove(CREDENTIALS_FILE);
|
||||||
}
|
}
|
||||||
|
catch (std::exception &e) {
|
||||||
|
LogError("std::filesystem::remove err [{}]", e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DatabaseDumpService::IsDumpStaticInstanceData()
|
bool DatabaseDumpService::IsDumpStaticInstanceData()
|
||||||
|
|||||||
@@ -6417,7 +6417,7 @@ ADD COLUMN `guid` bigint(20) UNSIGNED NOT NULL DEFAULT 0 AFTER `ornament_hero_mo
|
|||||||
ADD PRIMARY KEY (`account_id`, `slot_id`);
|
ADD PRIMARY KEY (`account_id`, `slot_id`);
|
||||||
)",
|
)",
|
||||||
.content_schema_update = false,
|
.content_schema_update = false,
|
||||||
.force_interactive = true
|
.force_interactive = false
|
||||||
},
|
},
|
||||||
ManifestEntry{
|
ManifestEntry{
|
||||||
.version = 9298,
|
.version = 9298,
|
||||||
@@ -6481,7 +6481,7 @@ UPDATE `sharedbank` SET `slot_id` = ((`slot_id` - 2531) + 11010) WHERE `slot_id`
|
|||||||
UPDATE `sharedbank` SET `slot_id` = ((`slot_id` - 2541) + 11210) WHERE `slot_id` BETWEEN 2541 AND 2550; -- Shared Bank Bag 2
|
UPDATE `sharedbank` SET `slot_id` = ((`slot_id` - 2541) + 11210) WHERE `slot_id` BETWEEN 2541 AND 2550; -- Shared Bank Bag 2
|
||||||
)",
|
)",
|
||||||
.content_schema_update = false,
|
.content_schema_update = false,
|
||||||
.force_interactive = true
|
.force_interactive = false
|
||||||
},
|
},
|
||||||
ManifestEntry{
|
ManifestEntry{
|
||||||
.version = 9299,
|
.version = 9299,
|
||||||
@@ -6871,6 +6871,73 @@ CREATE INDEX idx_instance_id ON data_buckets (instance_id);
|
|||||||
)",
|
)",
|
||||||
.content_schema_update = false
|
.content_schema_update = false
|
||||||
},
|
},
|
||||||
|
ManifestEntry{
|
||||||
|
.version = 9307,
|
||||||
|
.description = "2025_02_17_zone_state_spawns.sql",
|
||||||
|
.check = "SHOW TABLES LIKE 'zone_state_spawns'",
|
||||||
|
.condition = "empty",
|
||||||
|
.match = "",
|
||||||
|
.sql = R"(
|
||||||
|
CREATE TABLE `zone_state_spawns` (
|
||||||
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`zone_id` int(11) unsigned DEFAULT NULL,
|
||||||
|
`instance_id` int(11) unsigned DEFAULT NULL,
|
||||||
|
`is_corpse` tinyint(11) DEFAULT 0,
|
||||||
|
`decay_in_seconds` int(11) DEFAULT 0,
|
||||||
|
`npc_id` int(10) unsigned DEFAULT NULL,
|
||||||
|
`spawn2_id` int(10) unsigned NOT NULL,
|
||||||
|
`spawngroup_id` int(10) unsigned NOT NULL,
|
||||||
|
`x` float NOT NULL,
|
||||||
|
`y` float NOT NULL,
|
||||||
|
`z` float NOT NULL,
|
||||||
|
`heading` float NOT NULL,
|
||||||
|
`respawn_time` int(10) unsigned NOT NULL,
|
||||||
|
`variance` int(10) unsigned NOT NULL,
|
||||||
|
`grid` int(10) unsigned DEFAULT 0,
|
||||||
|
`current_waypoint` int(11) DEFAULT 0,
|
||||||
|
`path_when_zone_idle` smallint(6) DEFAULT 0,
|
||||||
|
`condition_id` smallint(5) unsigned DEFAULT 0,
|
||||||
|
`condition_min_value` smallint(6) DEFAULT 0,
|
||||||
|
`enabled` smallint(6) DEFAULT 1,
|
||||||
|
`anim` smallint(5) unsigned DEFAULT 0,
|
||||||
|
`loot_data` text DEFAULT NULL,
|
||||||
|
`entity_variables` text DEFAULT NULL,
|
||||||
|
`buffs` text DEFAULT NULL,
|
||||||
|
`hp` bigint(20) DEFAULT 0,
|
||||||
|
`mana` bigint(20) DEFAULT 0,
|
||||||
|
`endurance` bigint(20) DEFAULT 0,
|
||||||
|
`created_at` datetime DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4
|
||||||
|
)",
|
||||||
|
.content_schema_update = false
|
||||||
|
},
|
||||||
|
ManifestEntry{
|
||||||
|
.version = 9308,
|
||||||
|
.description = "2025_add_multivalue_support_to_evolving_subtype.sql",
|
||||||
|
.check = "SHOW COLUMNS FROM `items_evolving_details` LIKE 'sub_type'",
|
||||||
|
.condition = "missing",
|
||||||
|
.match = "varchar(200)",
|
||||||
|
.sql = R"(
|
||||||
|
ALTER TABLE `items_evolving_details`
|
||||||
|
CHANGE COLUMN `sub_type` `sub_type` VARCHAR(200) NULL DEFAULT '0' AFTER `type`;
|
||||||
|
)",
|
||||||
|
.content_schema_update = true
|
||||||
|
},
|
||||||
|
// this one got missed being added to PEQ dumps so adding it again so it gets added when folks take a new release
|
||||||
|
ManifestEntry{
|
||||||
|
.version = 9309,
|
||||||
|
.description = "2025_03_1_create_pet_names_table_if_not_exist.sql",
|
||||||
|
.check = "SHOW TABLES LIKE 'character_pet_name'",
|
||||||
|
.condition = "empty",
|
||||||
|
.match = "",
|
||||||
|
.sql = R"(
|
||||||
|
CREATE TABLE `character_pet_name` (
|
||||||
|
`character_id` INT(11) NOT NULL PRIMARY KEY,
|
||||||
|
`name` VARCHAR(64) NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
)",
|
||||||
|
},
|
||||||
// -- 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,
|
||||||
|
|||||||
@@ -562,6 +562,7 @@ void Database::PurgeExpiredInstances()
|
|||||||
DynamicZoneMembersRepository::DeleteByManyInstances(*this, imploded_instance_ids);
|
DynamicZoneMembersRepository::DeleteByManyInstances(*this, imploded_instance_ids);
|
||||||
DynamicZonesRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", imploded_instance_ids));
|
DynamicZonesRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", imploded_instance_ids));
|
||||||
Spawn2DisabledRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", imploded_instance_ids));
|
Spawn2DisabledRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", imploded_instance_ids));
|
||||||
|
DataBucketsRepository::DeleteWhere(*this, fmt::format("instance_id != 0 and instance_id IN ({})", imploded_instance_ids));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration)
|
void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration)
|
||||||
|
|||||||
@@ -139,6 +139,7 @@ namespace DatabaseSchema {
|
|||||||
"character_pet_buffs",
|
"character_pet_buffs",
|
||||||
"character_pet_info",
|
"character_pet_info",
|
||||||
"character_pet_inventory",
|
"character_pet_inventory",
|
||||||
|
"character_pet_name",
|
||||||
"character_peqzone_flags",
|
"character_peqzone_flags",
|
||||||
"character_potionbelt",
|
"character_potionbelt",
|
||||||
"character_skills",
|
"character_skills",
|
||||||
@@ -350,6 +351,7 @@ namespace DatabaseSchema {
|
|||||||
"shared_task_dynamic_zones",
|
"shared_task_dynamic_zones",
|
||||||
"shared_task_members",
|
"shared_task_members",
|
||||||
"shared_tasks",
|
"shared_tasks",
|
||||||
|
"zone_state_spawns",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -302,7 +302,9 @@ std::string DBcore::Escape(const std::string& s)
|
|||||||
|
|
||||||
void DBcore::SetMutex(Mutex *mutex)
|
void DBcore::SetMutex(Mutex *mutex)
|
||||||
{
|
{
|
||||||
|
if (m_mutex && m_mutex != mutex) {
|
||||||
safe_delete(m_mutex);
|
safe_delete(m_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
DBcore::m_mutex = mutex;
|
DBcore::m_mutex = mutex;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ static const uint32 ADVANCED_LORE_LENGTH = 8192;
|
|||||||
*/
|
*/
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
|
|
||||||
struct LoginInfo_Struct {
|
struct LoginInfo {
|
||||||
/*000*/ char login_info[64];
|
/*000*/ char login_info[64];
|
||||||
/*064*/ uint8 unknown064[124];
|
/*064*/ uint8 unknown064[124];
|
||||||
/*188*/ uint8 zoning; // 01 if zoning, 00 if not
|
/*188*/ uint8 zoning; // 01 if zoning, 00 if not
|
||||||
|
|||||||
@@ -149,6 +149,7 @@ namespace Logs {
|
|||||||
BotSpellChecks,
|
BotSpellChecks,
|
||||||
BotSpellTypeChecks,
|
BotSpellTypeChecks,
|
||||||
NpcHandin,
|
NpcHandin,
|
||||||
|
ZoneState,
|
||||||
MaxCategoryID /* Don't Remove this */
|
MaxCategoryID /* Don't Remove this */
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -256,7 +257,8 @@ namespace Logs {
|
|||||||
"Bot Settings",
|
"Bot Settings",
|
||||||
"Bot Spell Checks",
|
"Bot Spell Checks",
|
||||||
"Bot Spell Type Checks",
|
"Bot Spell Type Checks",
|
||||||
"NpcHandin"
|
"NpcHandin",
|
||||||
|
"ZoneState"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -914,6 +914,16 @@
|
|||||||
OutF(LogSys, Logs::Detail, Logs::NpcHandin, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
OutF(LogSys, Logs::Detail, Logs::NpcHandin, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define LogZoneState(message, ...) do {\
|
||||||
|
if (LogSys.IsLogEnabled(Logs::General, Logs::ZoneState))\
|
||||||
|
OutF(LogSys, Logs::General, Logs::ZoneState, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define LogZoneStateDetail(message, ...) do {\
|
||||||
|
if (LogSys.IsLogEnabled(Logs::Detail, Logs::ZoneState))\
|
||||||
|
OutF(LogSys, Logs::Detail, Logs::ZoneState, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define Log(debug_level, log_category, message, ...) do {\
|
#define Log(debug_level, log_category, message, ...) do {\
|
||||||
if (LogSys.IsLogEnabled(debug_level, log_category))\
|
if (LogSys.IsLogEnabled(debug_level, log_category))\
|
||||||
LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||||
|
|||||||
+12
-13
@@ -39,6 +39,7 @@
|
|||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
@@ -90,23 +91,21 @@ std::string File::GetCwd()
|
|||||||
|
|
||||||
FileContentsResult File::GetContents(const std::string &file_name)
|
FileContentsResult File::GetContents(const std::string &file_name)
|
||||||
{
|
{
|
||||||
std::string error;
|
std::ifstream f(file_name, std::ios::in | std::ios::binary);
|
||||||
std::ifstream f;
|
if (!f) {
|
||||||
f.open(file_name);
|
return { .error = fmt::format("Couldn't open file [{}]", file_name) };
|
||||||
std::string line;
|
}
|
||||||
|
|
||||||
|
constexpr size_t CHUNK_SIZE = 4096; // Read 4KB chunks
|
||||||
std::string lines;
|
std::string lines;
|
||||||
if (f.is_open()) {
|
std::vector<char> buffer(CHUNK_SIZE);
|
||||||
while (f) {
|
|
||||||
std::getline(f, line);
|
while (f.read(buffer.data(), CHUNK_SIZE) || f.gcount() > 0) {
|
||||||
lines += line + "\n";
|
lines.append(buffer.data(), f.gcount());
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
error = fmt::format("Couldn't open file [{}]", file_name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return FileContentsResult{
|
return FileContentsResult{
|
||||||
.contents = lines,
|
.contents = lines,
|
||||||
.error = error,
|
.error = {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -259,3 +259,76 @@ bool IpUtil::IsIPAddress(const std::string &ip_address)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <winsock2.h>
|
||||||
|
#pragma comment(lib, "ws2_32.lib") // Link against Winsock library
|
||||||
|
#else
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h> // For inet_pton
|
||||||
|
#pragma comment(lib, "ws2_32.lib") // Link against Winsock library
|
||||||
|
#else
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h> // For inet_pton
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool IpUtil::IsPortInUse(const std::string& ip, int port) {
|
||||||
|
bool in_use = false;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
WSADATA wsaData;
|
||||||
|
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
|
||||||
|
std::cerr << "WSAStartup failed\n";
|
||||||
|
return true; // Assume in use on failure
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (sock < 0) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
WSACleanup();
|
||||||
|
#endif
|
||||||
|
return true; // Assume in use on failure
|
||||||
|
}
|
||||||
|
|
||||||
|
sockaddr_in addr{};
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = htons(port);
|
||||||
|
|
||||||
|
// Convert IP address from string to binary format
|
||||||
|
if (inet_pton(AF_INET, ip.c_str(), &addr.sin_addr) <= 0) {
|
||||||
|
std::cerr << "Invalid IP address format: " << ip << std::endl;
|
||||||
|
#ifdef _WIN32
|
||||||
|
closesocket(sock);
|
||||||
|
WSACleanup();
|
||||||
|
#else
|
||||||
|
close(sock);
|
||||||
|
#endif
|
||||||
|
return true; // Assume in use on failure
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||||
|
in_use = true; // Bind failed, port is in use
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
closesocket(sock);
|
||||||
|
WSACleanup();
|
||||||
|
#else
|
||||||
|
close(sock);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return in_use;
|
||||||
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ public:
|
|||||||
int port
|
int port
|
||||||
);
|
);
|
||||||
static bool IsIPAddress(const std::string &ip_address);
|
static bool IsIPAddress(const std::string &ip_address);
|
||||||
|
static bool IsPortInUse(const std::string& ip, int port);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ struct LootItem {
|
|||||||
uint16 trivial_max_level;
|
uint16 trivial_max_level;
|
||||||
uint16 npc_min_level;
|
uint16 npc_min_level;
|
||||||
uint16 npc_max_level;
|
uint16 npc_max_level;
|
||||||
|
uint32 lootdrop_id; // required for zone state referencing
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::list<LootItem*> LootItems;
|
typedef std::list<LootItem*> LootItems;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ void EQ::Net::ServertalkServerConnection::Send(uint16_t opcode, EQ::Net::Packet
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (opcode == ServerOP_UsertoWorldReq) {
|
if (opcode == ServerOP_UsertoWorldReq) {
|
||||||
auto req_in = (UsertoWorldRequest_Struct*)p.Data();
|
auto req_in = (UsertoWorldRequest*)p.Data();
|
||||||
|
|
||||||
EQ::Net::DynamicPacket req;
|
EQ::Net::DynamicPacket req;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
@@ -45,7 +45,7 @@ void EQ::Net::ServertalkServerConnection::Send(uint16_t opcode, EQ::Net::Packet
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (opcode == ServerOP_LSClientAuth) {
|
if (opcode == ServerOP_LSClientAuth) {
|
||||||
auto req_in = (ClientAuth_Struct*)p.Data();
|
auto req_in = (ClientAuth*)p.Data();
|
||||||
|
|
||||||
EQ::Net::DynamicPacket req;
|
EQ::Net::DynamicPacket req;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
@@ -54,7 +54,7 @@ void EQ::Net::ServertalkServerConnection::Send(uint16_t opcode, EQ::Net::Packet
|
|||||||
req.PutData(i, req_in->key, 30); i += 30;
|
req.PutData(i, req_in->key, 30); i += 30;
|
||||||
req.PutUInt8(i, req_in->lsadmin); i += 1;
|
req.PutUInt8(i, req_in->lsadmin); i += 1;
|
||||||
req.PutUInt16(i, req_in->is_world_admin); i += 2;
|
req.PutUInt16(i, req_in->is_world_admin); i += 2;
|
||||||
req.PutUInt32(i, req_in->ip); i += 4;
|
req.PutUInt32(i, req_in->ip_address); i += 4;
|
||||||
req.PutUInt8(i, req_in->is_client_from_local_network); i += 1;
|
req.PutUInt8(i, req_in->is_client_from_local_network); i += 1;
|
||||||
|
|
||||||
EQ::Net::DynamicPacket out;
|
EQ::Net::DynamicPacket out;
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ void PathManager::LoadPaths()
|
|||||||
constexpr int path_width = 0;
|
constexpr int path_width = 0;
|
||||||
constexpr int break_length = 70;
|
constexpr int break_length = 70;
|
||||||
|
|
||||||
std::cout << std::endl;
|
LogInfo("Loading server paths");
|
||||||
LogInfo("{}", Strings::Repeat("-", break_length));
|
LogInfo("{}", Strings::Repeat("-", break_length));
|
||||||
for (const auto& [name, in_path] : paths) {
|
for (const auto& [name, in_path] : paths) {
|
||||||
if (!in_path.empty()) {
|
if (!in_path.empty()) {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public:
|
|||||||
uint32_t item_evolve_level;
|
uint32_t item_evolve_level;
|
||||||
uint32_t item_id;
|
uint32_t item_id;
|
||||||
uint32_t type;
|
uint32_t type;
|
||||||
uint32_t sub_type;
|
std::string sub_type;
|
||||||
int64_t required_amount;
|
int64_t required_amount;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ public:
|
|||||||
e.item_evolve_level = 0;
|
e.item_evolve_level = 0;
|
||||||
e.item_id = 0;
|
e.item_id = 0;
|
||||||
e.type = 0;
|
e.type = 0;
|
||||||
e.sub_type = 0;
|
e.sub_type = "0";
|
||||||
e.required_amount = 0;
|
e.required_amount = 0;
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
@@ -144,7 +144,7 @@ public:
|
|||||||
e.item_evolve_level = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
e.item_evolve_level = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||||
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||||
e.type = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
e.type = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||||
e.sub_type = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
e.sub_type = row[5] ? row[5] : "0";
|
||||||
e.required_amount = row[6] ? strtoll(row[6], nullptr, 10) : 0;
|
e.required_amount = row[6] ? strtoll(row[6], nullptr, 10) : 0;
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
@@ -183,7 +183,7 @@ public:
|
|||||||
v.push_back(columns[2] + " = " + std::to_string(e.item_evolve_level));
|
v.push_back(columns[2] + " = " + std::to_string(e.item_evolve_level));
|
||||||
v.push_back(columns[3] + " = " + std::to_string(e.item_id));
|
v.push_back(columns[3] + " = " + std::to_string(e.item_id));
|
||||||
v.push_back(columns[4] + " = " + std::to_string(e.type));
|
v.push_back(columns[4] + " = " + std::to_string(e.type));
|
||||||
v.push_back(columns[5] + " = " + std::to_string(e.sub_type));
|
v.push_back(columns[5] + " = '" + Strings::Escape(e.sub_type) + "'");
|
||||||
v.push_back(columns[6] + " = " + std::to_string(e.required_amount));
|
v.push_back(columns[6] + " = " + std::to_string(e.required_amount));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
@@ -211,7 +211,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.item_evolve_level));
|
v.push_back(std::to_string(e.item_evolve_level));
|
||||||
v.push_back(std::to_string(e.item_id));
|
v.push_back(std::to_string(e.item_id));
|
||||||
v.push_back(std::to_string(e.type));
|
v.push_back(std::to_string(e.type));
|
||||||
v.push_back(std::to_string(e.sub_type));
|
v.push_back("'" + Strings::Escape(e.sub_type) + "'");
|
||||||
v.push_back(std::to_string(e.required_amount));
|
v.push_back(std::to_string(e.required_amount));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
@@ -247,7 +247,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.item_evolve_level));
|
v.push_back(std::to_string(e.item_evolve_level));
|
||||||
v.push_back(std::to_string(e.item_id));
|
v.push_back(std::to_string(e.item_id));
|
||||||
v.push_back(std::to_string(e.type));
|
v.push_back(std::to_string(e.type));
|
||||||
v.push_back(std::to_string(e.sub_type));
|
v.push_back("'" + Strings::Escape(e.sub_type) + "'");
|
||||||
v.push_back(std::to_string(e.required_amount));
|
v.push_back(std::to_string(e.required_amount));
|
||||||
|
|
||||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
@@ -287,7 +287,7 @@ public:
|
|||||||
e.item_evolve_level = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
e.item_evolve_level = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||||
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||||
e.type = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
e.type = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||||
e.sub_type = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
e.sub_type = row[5] ? row[5] : "0";
|
||||||
e.required_amount = row[6] ? strtoll(row[6], nullptr, 10) : 0;
|
e.required_amount = row[6] ? strtoll(row[6], nullptr, 10) : 0;
|
||||||
|
|
||||||
all_entries.push_back(e);
|
all_entries.push_back(e);
|
||||||
@@ -318,7 +318,7 @@ public:
|
|||||||
e.item_evolve_level = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
e.item_evolve_level = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||||
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||||
e.type = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
e.type = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||||
e.sub_type = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
e.sub_type = row[5] ? row[5] : "0";
|
||||||
e.required_amount = row[6] ? strtoll(row[6], nullptr, 10) : 0;
|
e.required_amount = row[6] ? strtoll(row[6], nullptr, 10) : 0;
|
||||||
|
|
||||||
all_entries.push_back(e);
|
all_entries.push_back(e);
|
||||||
@@ -399,7 +399,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.item_evolve_level));
|
v.push_back(std::to_string(e.item_evolve_level));
|
||||||
v.push_back(std::to_string(e.item_id));
|
v.push_back(std::to_string(e.item_id));
|
||||||
v.push_back(std::to_string(e.type));
|
v.push_back(std::to_string(e.type));
|
||||||
v.push_back(std::to_string(e.sub_type));
|
v.push_back("'" + Strings::Escape(e.sub_type) + "'");
|
||||||
v.push_back(std::to_string(e.required_amount));
|
v.push_back(std::to_string(e.required_amount));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
@@ -428,7 +428,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.item_evolve_level));
|
v.push_back(std::to_string(e.item_evolve_level));
|
||||||
v.push_back(std::to_string(e.item_id));
|
v.push_back(std::to_string(e.item_id));
|
||||||
v.push_back(std::to_string(e.type));
|
v.push_back(std::to_string(e.type));
|
||||||
v.push_back(std::to_string(e.sub_type));
|
v.push_back("'" + Strings::Escape(e.sub_type) + "'");
|
||||||
v.push_back(std::to_string(e.required_amount));
|
v.push_back(std::to_string(e.required_amount));
|
||||||
|
|
||||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
|
|||||||
@@ -0,0 +1,703 @@
|
|||||||
|
/**
|
||||||
|
* DO NOT MODIFY THIS FILE
|
||||||
|
*
|
||||||
|
* This repository was automatically generated and is NOT to be modified directly.
|
||||||
|
* Any repository modifications are meant to be made to the repository extending the base.
|
||||||
|
* Any modifications to base repositories are to be made by the generator only
|
||||||
|
*
|
||||||
|
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||||
|
* @docs https://docs.eqemu.io/developer/repositories
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EQEMU_BASE_ZONE_STATE_SPAWNS_REPOSITORY_H
|
||||||
|
#define EQEMU_BASE_ZONE_STATE_SPAWNS_REPOSITORY_H
|
||||||
|
|
||||||
|
#include "../../database.h"
|
||||||
|
#include "../../strings.h"
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
class BaseZoneStateSpawnsRepository {
|
||||||
|
public:
|
||||||
|
struct ZoneStateSpawns {
|
||||||
|
int64_t id;
|
||||||
|
uint32_t zone_id;
|
||||||
|
uint32_t instance_id;
|
||||||
|
int8_t is_corpse;
|
||||||
|
int32_t decay_in_seconds;
|
||||||
|
uint32_t npc_id;
|
||||||
|
uint32_t spawn2_id;
|
||||||
|
uint32_t spawngroup_id;
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
float z;
|
||||||
|
float heading;
|
||||||
|
uint32_t respawn_time;
|
||||||
|
uint32_t variance;
|
||||||
|
uint32_t grid;
|
||||||
|
int32_t current_waypoint;
|
||||||
|
int16_t path_when_zone_idle;
|
||||||
|
uint16_t condition_id;
|
||||||
|
int16_t condition_min_value;
|
||||||
|
int16_t enabled;
|
||||||
|
uint16_t anim;
|
||||||
|
std::string loot_data;
|
||||||
|
std::string entity_variables;
|
||||||
|
std::string buffs;
|
||||||
|
int64_t hp;
|
||||||
|
int64_t mana;
|
||||||
|
int64_t endurance;
|
||||||
|
time_t created_at;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::string PrimaryKey()
|
||||||
|
{
|
||||||
|
return std::string("id");
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::string> Columns()
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
"id",
|
||||||
|
"zone_id",
|
||||||
|
"instance_id",
|
||||||
|
"is_corpse",
|
||||||
|
"decay_in_seconds",
|
||||||
|
"npc_id",
|
||||||
|
"spawn2_id",
|
||||||
|
"spawngroup_id",
|
||||||
|
"x",
|
||||||
|
"y",
|
||||||
|
"z",
|
||||||
|
"heading",
|
||||||
|
"respawn_time",
|
||||||
|
"variance",
|
||||||
|
"grid",
|
||||||
|
"current_waypoint",
|
||||||
|
"path_when_zone_idle",
|
||||||
|
"condition_id",
|
||||||
|
"condition_min_value",
|
||||||
|
"enabled",
|
||||||
|
"anim",
|
||||||
|
"loot_data",
|
||||||
|
"entity_variables",
|
||||||
|
"buffs",
|
||||||
|
"hp",
|
||||||
|
"mana",
|
||||||
|
"endurance",
|
||||||
|
"created_at",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::string> SelectColumns()
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
"id",
|
||||||
|
"zone_id",
|
||||||
|
"instance_id",
|
||||||
|
"is_corpse",
|
||||||
|
"decay_in_seconds",
|
||||||
|
"npc_id",
|
||||||
|
"spawn2_id",
|
||||||
|
"spawngroup_id",
|
||||||
|
"x",
|
||||||
|
"y",
|
||||||
|
"z",
|
||||||
|
"heading",
|
||||||
|
"respawn_time",
|
||||||
|
"variance",
|
||||||
|
"grid",
|
||||||
|
"current_waypoint",
|
||||||
|
"path_when_zone_idle",
|
||||||
|
"condition_id",
|
||||||
|
"condition_min_value",
|
||||||
|
"enabled",
|
||||||
|
"anim",
|
||||||
|
"loot_data",
|
||||||
|
"entity_variables",
|
||||||
|
"buffs",
|
||||||
|
"hp",
|
||||||
|
"mana",
|
||||||
|
"endurance",
|
||||||
|
"UNIX_TIMESTAMP(created_at)",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string ColumnsRaw()
|
||||||
|
{
|
||||||
|
return std::string(Strings::Implode(", ", Columns()));
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string SelectColumnsRaw()
|
||||||
|
{
|
||||||
|
return std::string(Strings::Implode(", ", SelectColumns()));
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string TableName()
|
||||||
|
{
|
||||||
|
return std::string("zone_state_spawns");
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string BaseSelect()
|
||||||
|
{
|
||||||
|
return fmt::format(
|
||||||
|
"SELECT {} FROM {}",
|
||||||
|
SelectColumnsRaw(),
|
||||||
|
TableName()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string BaseInsert()
|
||||||
|
{
|
||||||
|
return fmt::format(
|
||||||
|
"INSERT INTO {} ({}) ",
|
||||||
|
TableName(),
|
||||||
|
ColumnsRaw()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ZoneStateSpawns NewEntity()
|
||||||
|
{
|
||||||
|
ZoneStateSpawns e{};
|
||||||
|
|
||||||
|
e.id = 0;
|
||||||
|
e.zone_id = 0;
|
||||||
|
e.instance_id = 0;
|
||||||
|
e.is_corpse = 0;
|
||||||
|
e.decay_in_seconds = 0;
|
||||||
|
e.npc_id = 0;
|
||||||
|
e.spawn2_id = 0;
|
||||||
|
e.spawngroup_id = 0;
|
||||||
|
e.x = 0;
|
||||||
|
e.y = 0;
|
||||||
|
e.z = 0;
|
||||||
|
e.heading = 0;
|
||||||
|
e.respawn_time = 0;
|
||||||
|
e.variance = 0;
|
||||||
|
e.grid = 0;
|
||||||
|
e.current_waypoint = 0;
|
||||||
|
e.path_when_zone_idle = 0;
|
||||||
|
e.condition_id = 0;
|
||||||
|
e.condition_min_value = 0;
|
||||||
|
e.enabled = 1;
|
||||||
|
e.anim = 0;
|
||||||
|
e.loot_data = "";
|
||||||
|
e.entity_variables = "";
|
||||||
|
e.buffs = "";
|
||||||
|
e.hp = 0;
|
||||||
|
e.mana = 0;
|
||||||
|
e.endurance = 0;
|
||||||
|
e.created_at = 0;
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ZoneStateSpawns GetZoneStateSpawns(
|
||||||
|
const std::vector<ZoneStateSpawns> &zone_state_spawnss,
|
||||||
|
int zone_state_spawns_id
|
||||||
|
)
|
||||||
|
{
|
||||||
|
for (auto &zone_state_spawns : zone_state_spawnss) {
|
||||||
|
if (zone_state_spawns.id == zone_state_spawns_id) {
|
||||||
|
return zone_state_spawns;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
static ZoneStateSpawns FindOne(
|
||||||
|
Database& db,
|
||||||
|
int zone_state_spawns_id
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{} WHERE {} = {} LIMIT 1",
|
||||||
|
BaseSelect(),
|
||||||
|
PrimaryKey(),
|
||||||
|
zone_state_spawns_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
auto row = results.begin();
|
||||||
|
if (results.RowCount() == 1) {
|
||||||
|
ZoneStateSpawns e{};
|
||||||
|
|
||||||
|
e.id = row[0] ? strtoll(row[0], nullptr, 10) : 0;
|
||||||
|
e.zone_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||||
|
e.instance_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||||
|
e.is_corpse = row[3] ? static_cast<int8_t>(atoi(row[3])) : 0;
|
||||||
|
e.decay_in_seconds = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
|
||||||
|
e.npc_id = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||||
|
e.spawn2_id = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
|
||||||
|
e.spawngroup_id = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
|
||||||
|
e.x = row[8] ? strtof(row[8], nullptr) : 0;
|
||||||
|
e.y = row[9] ? strtof(row[9], nullptr) : 0;
|
||||||
|
e.z = row[10] ? strtof(row[10], nullptr) : 0;
|
||||||
|
e.heading = row[11] ? strtof(row[11], nullptr) : 0;
|
||||||
|
e.respawn_time = row[12] ? static_cast<uint32_t>(strtoul(row[12], nullptr, 10)) : 0;
|
||||||
|
e.variance = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
||||||
|
e.grid = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||||
|
e.current_waypoint = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
|
||||||
|
e.path_when_zone_idle = row[16] ? static_cast<int16_t>(atoi(row[16])) : 0;
|
||||||
|
e.condition_id = row[17] ? static_cast<uint16_t>(strtoul(row[17], nullptr, 10)) : 0;
|
||||||
|
e.condition_min_value = row[18] ? static_cast<int16_t>(atoi(row[18])) : 0;
|
||||||
|
e.enabled = row[19] ? static_cast<int16_t>(atoi(row[19])) : 1;
|
||||||
|
e.anim = row[20] ? static_cast<uint16_t>(strtoul(row[20], nullptr, 10)) : 0;
|
||||||
|
e.loot_data = row[21] ? row[21] : "";
|
||||||
|
e.entity_variables = row[22] ? row[22] : "";
|
||||||
|
e.buffs = row[23] ? row[23] : "";
|
||||||
|
e.hp = row[24] ? strtoll(row[24], nullptr, 10) : 0;
|
||||||
|
e.mana = row[25] ? strtoll(row[25], nullptr, 10) : 0;
|
||||||
|
e.endurance = row[26] ? strtoll(row[26], nullptr, 10) : 0;
|
||||||
|
e.created_at = strtoll(row[27] ? row[27] : "-1", nullptr, 10);
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int DeleteOne(
|
||||||
|
Database& db,
|
||||||
|
int zone_state_spawns_id
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"DELETE FROM {} WHERE {} = {}",
|
||||||
|
TableName(),
|
||||||
|
PrimaryKey(),
|
||||||
|
zone_state_spawns_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int UpdateOne(
|
||||||
|
Database& db,
|
||||||
|
const ZoneStateSpawns &e
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
auto columns = Columns();
|
||||||
|
|
||||||
|
v.push_back(columns[1] + " = " + std::to_string(e.zone_id));
|
||||||
|
v.push_back(columns[2] + " = " + std::to_string(e.instance_id));
|
||||||
|
v.push_back(columns[3] + " = " + std::to_string(e.is_corpse));
|
||||||
|
v.push_back(columns[4] + " = " + std::to_string(e.decay_in_seconds));
|
||||||
|
v.push_back(columns[5] + " = " + std::to_string(e.npc_id));
|
||||||
|
v.push_back(columns[6] + " = " + std::to_string(e.spawn2_id));
|
||||||
|
v.push_back(columns[7] + " = " + std::to_string(e.spawngroup_id));
|
||||||
|
v.push_back(columns[8] + " = " + std::to_string(e.x));
|
||||||
|
v.push_back(columns[9] + " = " + std::to_string(e.y));
|
||||||
|
v.push_back(columns[10] + " = " + std::to_string(e.z));
|
||||||
|
v.push_back(columns[11] + " = " + std::to_string(e.heading));
|
||||||
|
v.push_back(columns[12] + " = " + std::to_string(e.respawn_time));
|
||||||
|
v.push_back(columns[13] + " = " + std::to_string(e.variance));
|
||||||
|
v.push_back(columns[14] + " = " + std::to_string(e.grid));
|
||||||
|
v.push_back(columns[15] + " = " + std::to_string(e.current_waypoint));
|
||||||
|
v.push_back(columns[16] + " = " + std::to_string(e.path_when_zone_idle));
|
||||||
|
v.push_back(columns[17] + " = " + std::to_string(e.condition_id));
|
||||||
|
v.push_back(columns[18] + " = " + std::to_string(e.condition_min_value));
|
||||||
|
v.push_back(columns[19] + " = " + std::to_string(e.enabled));
|
||||||
|
v.push_back(columns[20] + " = " + std::to_string(e.anim));
|
||||||
|
v.push_back(columns[21] + " = '" + Strings::Escape(e.loot_data) + "'");
|
||||||
|
v.push_back(columns[22] + " = '" + Strings::Escape(e.entity_variables) + "'");
|
||||||
|
v.push_back(columns[23] + " = '" + Strings::Escape(e.buffs) + "'");
|
||||||
|
v.push_back(columns[24] + " = " + std::to_string(e.hp));
|
||||||
|
v.push_back(columns[25] + " = " + std::to_string(e.mana));
|
||||||
|
v.push_back(columns[26] + " = " + std::to_string(e.endurance));
|
||||||
|
v.push_back(columns[27] + " = FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"UPDATE {} SET {} WHERE {} = {}",
|
||||||
|
TableName(),
|
||||||
|
Strings::Implode(", ", v),
|
||||||
|
PrimaryKey(),
|
||||||
|
e.id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ZoneStateSpawns InsertOne(
|
||||||
|
Database& db,
|
||||||
|
ZoneStateSpawns e
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
v.push_back(std::to_string(e.id));
|
||||||
|
v.push_back(std::to_string(e.zone_id));
|
||||||
|
v.push_back(std::to_string(e.instance_id));
|
||||||
|
v.push_back(std::to_string(e.is_corpse));
|
||||||
|
v.push_back(std::to_string(e.decay_in_seconds));
|
||||||
|
v.push_back(std::to_string(e.npc_id));
|
||||||
|
v.push_back(std::to_string(e.spawn2_id));
|
||||||
|
v.push_back(std::to_string(e.spawngroup_id));
|
||||||
|
v.push_back(std::to_string(e.x));
|
||||||
|
v.push_back(std::to_string(e.y));
|
||||||
|
v.push_back(std::to_string(e.z));
|
||||||
|
v.push_back(std::to_string(e.heading));
|
||||||
|
v.push_back(std::to_string(e.respawn_time));
|
||||||
|
v.push_back(std::to_string(e.variance));
|
||||||
|
v.push_back(std::to_string(e.grid));
|
||||||
|
v.push_back(std::to_string(e.current_waypoint));
|
||||||
|
v.push_back(std::to_string(e.path_when_zone_idle));
|
||||||
|
v.push_back(std::to_string(e.condition_id));
|
||||||
|
v.push_back(std::to_string(e.condition_min_value));
|
||||||
|
v.push_back(std::to_string(e.enabled));
|
||||||
|
v.push_back(std::to_string(e.anim));
|
||||||
|
v.push_back("'" + Strings::Escape(e.loot_data) + "'");
|
||||||
|
v.push_back("'" + Strings::Escape(e.entity_variables) + "'");
|
||||||
|
v.push_back("'" + Strings::Escape(e.buffs) + "'");
|
||||||
|
v.push_back(std::to_string(e.hp));
|
||||||
|
v.push_back(std::to_string(e.mana));
|
||||||
|
v.push_back(std::to_string(e.endurance));
|
||||||
|
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{} VALUES ({})",
|
||||||
|
BaseInsert(),
|
||||||
|
Strings::Implode(",", v)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (results.Success()) {
|
||||||
|
e.id = results.LastInsertedID();
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
e = NewEntity();
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int InsertMany(
|
||||||
|
Database& db,
|
||||||
|
const std::vector<ZoneStateSpawns> &entries
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::vector<std::string> insert_chunks;
|
||||||
|
|
||||||
|
for (auto &e: entries) {
|
||||||
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
v.push_back(std::to_string(e.id));
|
||||||
|
v.push_back(std::to_string(e.zone_id));
|
||||||
|
v.push_back(std::to_string(e.instance_id));
|
||||||
|
v.push_back(std::to_string(e.is_corpse));
|
||||||
|
v.push_back(std::to_string(e.decay_in_seconds));
|
||||||
|
v.push_back(std::to_string(e.npc_id));
|
||||||
|
v.push_back(std::to_string(e.spawn2_id));
|
||||||
|
v.push_back(std::to_string(e.spawngroup_id));
|
||||||
|
v.push_back(std::to_string(e.x));
|
||||||
|
v.push_back(std::to_string(e.y));
|
||||||
|
v.push_back(std::to_string(e.z));
|
||||||
|
v.push_back(std::to_string(e.heading));
|
||||||
|
v.push_back(std::to_string(e.respawn_time));
|
||||||
|
v.push_back(std::to_string(e.variance));
|
||||||
|
v.push_back(std::to_string(e.grid));
|
||||||
|
v.push_back(std::to_string(e.current_waypoint));
|
||||||
|
v.push_back(std::to_string(e.path_when_zone_idle));
|
||||||
|
v.push_back(std::to_string(e.condition_id));
|
||||||
|
v.push_back(std::to_string(e.condition_min_value));
|
||||||
|
v.push_back(std::to_string(e.enabled));
|
||||||
|
v.push_back(std::to_string(e.anim));
|
||||||
|
v.push_back("'" + Strings::Escape(e.loot_data) + "'");
|
||||||
|
v.push_back("'" + Strings::Escape(e.entity_variables) + "'");
|
||||||
|
v.push_back("'" + Strings::Escape(e.buffs) + "'");
|
||||||
|
v.push_back(std::to_string(e.hp));
|
||||||
|
v.push_back(std::to_string(e.mana));
|
||||||
|
v.push_back(std::to_string(e.endurance));
|
||||||
|
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
|
||||||
|
|
||||||
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{} VALUES {}",
|
||||||
|
BaseInsert(),
|
||||||
|
Strings::Implode(",", insert_chunks)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<ZoneStateSpawns> All(Database& db)
|
||||||
|
{
|
||||||
|
std::vector<ZoneStateSpawns> all_entries;
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{}",
|
||||||
|
BaseSelect()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
all_entries.reserve(results.RowCount());
|
||||||
|
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
ZoneStateSpawns e{};
|
||||||
|
|
||||||
|
e.id = row[0] ? strtoll(row[0], nullptr, 10) : 0;
|
||||||
|
e.zone_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||||
|
e.instance_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||||
|
e.is_corpse = row[3] ? static_cast<int8_t>(atoi(row[3])) : 0;
|
||||||
|
e.decay_in_seconds = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
|
||||||
|
e.npc_id = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||||
|
e.spawn2_id = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
|
||||||
|
e.spawngroup_id = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
|
||||||
|
e.x = row[8] ? strtof(row[8], nullptr) : 0;
|
||||||
|
e.y = row[9] ? strtof(row[9], nullptr) : 0;
|
||||||
|
e.z = row[10] ? strtof(row[10], nullptr) : 0;
|
||||||
|
e.heading = row[11] ? strtof(row[11], nullptr) : 0;
|
||||||
|
e.respawn_time = row[12] ? static_cast<uint32_t>(strtoul(row[12], nullptr, 10)) : 0;
|
||||||
|
e.variance = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
||||||
|
e.grid = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||||
|
e.current_waypoint = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
|
||||||
|
e.path_when_zone_idle = row[16] ? static_cast<int16_t>(atoi(row[16])) : 0;
|
||||||
|
e.condition_id = row[17] ? static_cast<uint16_t>(strtoul(row[17], nullptr, 10)) : 0;
|
||||||
|
e.condition_min_value = row[18] ? static_cast<int16_t>(atoi(row[18])) : 0;
|
||||||
|
e.enabled = row[19] ? static_cast<int16_t>(atoi(row[19])) : 1;
|
||||||
|
e.anim = row[20] ? static_cast<uint16_t>(strtoul(row[20], nullptr, 10)) : 0;
|
||||||
|
e.loot_data = row[21] ? row[21] : "";
|
||||||
|
e.entity_variables = row[22] ? row[22] : "";
|
||||||
|
e.buffs = row[23] ? row[23] : "";
|
||||||
|
e.hp = row[24] ? strtoll(row[24], nullptr, 10) : 0;
|
||||||
|
e.mana = row[25] ? strtoll(row[25], nullptr, 10) : 0;
|
||||||
|
e.endurance = row[26] ? strtoll(row[26], nullptr, 10) : 0;
|
||||||
|
e.created_at = strtoll(row[27] ? row[27] : "-1", nullptr, 10);
|
||||||
|
|
||||||
|
all_entries.push_back(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return all_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<ZoneStateSpawns> GetWhere(Database& db, const std::string &where_filter)
|
||||||
|
{
|
||||||
|
std::vector<ZoneStateSpawns> all_entries;
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{} WHERE {}",
|
||||||
|
BaseSelect(),
|
||||||
|
where_filter
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
all_entries.reserve(results.RowCount());
|
||||||
|
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
ZoneStateSpawns e{};
|
||||||
|
|
||||||
|
e.id = row[0] ? strtoll(row[0], nullptr, 10) : 0;
|
||||||
|
e.zone_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||||
|
e.instance_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||||
|
e.is_corpse = row[3] ? static_cast<int8_t>(atoi(row[3])) : 0;
|
||||||
|
e.decay_in_seconds = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
|
||||||
|
e.npc_id = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||||
|
e.spawn2_id = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
|
||||||
|
e.spawngroup_id = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
|
||||||
|
e.x = row[8] ? strtof(row[8], nullptr) : 0;
|
||||||
|
e.y = row[9] ? strtof(row[9], nullptr) : 0;
|
||||||
|
e.z = row[10] ? strtof(row[10], nullptr) : 0;
|
||||||
|
e.heading = row[11] ? strtof(row[11], nullptr) : 0;
|
||||||
|
e.respawn_time = row[12] ? static_cast<uint32_t>(strtoul(row[12], nullptr, 10)) : 0;
|
||||||
|
e.variance = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
||||||
|
e.grid = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||||
|
e.current_waypoint = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
|
||||||
|
e.path_when_zone_idle = row[16] ? static_cast<int16_t>(atoi(row[16])) : 0;
|
||||||
|
e.condition_id = row[17] ? static_cast<uint16_t>(strtoul(row[17], nullptr, 10)) : 0;
|
||||||
|
e.condition_min_value = row[18] ? static_cast<int16_t>(atoi(row[18])) : 0;
|
||||||
|
e.enabled = row[19] ? static_cast<int16_t>(atoi(row[19])) : 1;
|
||||||
|
e.anim = row[20] ? static_cast<uint16_t>(strtoul(row[20], nullptr, 10)) : 0;
|
||||||
|
e.loot_data = row[21] ? row[21] : "";
|
||||||
|
e.entity_variables = row[22] ? row[22] : "";
|
||||||
|
e.buffs = row[23] ? row[23] : "";
|
||||||
|
e.hp = row[24] ? strtoll(row[24], nullptr, 10) : 0;
|
||||||
|
e.mana = row[25] ? strtoll(row[25], nullptr, 10) : 0;
|
||||||
|
e.endurance = row[26] ? strtoll(row[26], nullptr, 10) : 0;
|
||||||
|
e.created_at = strtoll(row[27] ? row[27] : "-1", nullptr, 10);
|
||||||
|
|
||||||
|
all_entries.push_back(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return all_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int DeleteWhere(Database& db, const std::string &where_filter)
|
||||||
|
{
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"DELETE FROM {} WHERE {}",
|
||||||
|
TableName(),
|
||||||
|
where_filter
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int Truncate(Database& db)
|
||||||
|
{
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"TRUNCATE TABLE {}",
|
||||||
|
TableName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int64 GetMaxId(Database& db)
|
||||||
|
{
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"SELECT COALESCE(MAX({}), 0) FROM {}",
|
||||||
|
PrimaryKey(),
|
||||||
|
TableName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int64 Count(Database& db, const std::string &where_filter = "")
|
||||||
|
{
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"SELECT COUNT(*) FROM {} {}",
|
||||||
|
TableName(),
|
||||||
|
(where_filter.empty() ? "" : "WHERE " + where_filter)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string BaseReplace()
|
||||||
|
{
|
||||||
|
return fmt::format(
|
||||||
|
"REPLACE INTO {} ({}) ",
|
||||||
|
TableName(),
|
||||||
|
ColumnsRaw()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ReplaceOne(
|
||||||
|
Database& db,
|
||||||
|
const ZoneStateSpawns &e
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
v.push_back(std::to_string(e.id));
|
||||||
|
v.push_back(std::to_string(e.zone_id));
|
||||||
|
v.push_back(std::to_string(e.instance_id));
|
||||||
|
v.push_back(std::to_string(e.is_corpse));
|
||||||
|
v.push_back(std::to_string(e.decay_in_seconds));
|
||||||
|
v.push_back(std::to_string(e.npc_id));
|
||||||
|
v.push_back(std::to_string(e.spawn2_id));
|
||||||
|
v.push_back(std::to_string(e.spawngroup_id));
|
||||||
|
v.push_back(std::to_string(e.x));
|
||||||
|
v.push_back(std::to_string(e.y));
|
||||||
|
v.push_back(std::to_string(e.z));
|
||||||
|
v.push_back(std::to_string(e.heading));
|
||||||
|
v.push_back(std::to_string(e.respawn_time));
|
||||||
|
v.push_back(std::to_string(e.variance));
|
||||||
|
v.push_back(std::to_string(e.grid));
|
||||||
|
v.push_back(std::to_string(e.current_waypoint));
|
||||||
|
v.push_back(std::to_string(e.path_when_zone_idle));
|
||||||
|
v.push_back(std::to_string(e.condition_id));
|
||||||
|
v.push_back(std::to_string(e.condition_min_value));
|
||||||
|
v.push_back(std::to_string(e.enabled));
|
||||||
|
v.push_back(std::to_string(e.anim));
|
||||||
|
v.push_back("'" + Strings::Escape(e.loot_data) + "'");
|
||||||
|
v.push_back("'" + Strings::Escape(e.entity_variables) + "'");
|
||||||
|
v.push_back("'" + Strings::Escape(e.buffs) + "'");
|
||||||
|
v.push_back(std::to_string(e.hp));
|
||||||
|
v.push_back(std::to_string(e.mana));
|
||||||
|
v.push_back(std::to_string(e.endurance));
|
||||||
|
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{} VALUES ({})",
|
||||||
|
BaseReplace(),
|
||||||
|
Strings::Implode(",", v)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ReplaceMany(
|
||||||
|
Database& db,
|
||||||
|
const std::vector<ZoneStateSpawns> &entries
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::vector<std::string> insert_chunks;
|
||||||
|
|
||||||
|
for (auto &e: entries) {
|
||||||
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
v.push_back(std::to_string(e.id));
|
||||||
|
v.push_back(std::to_string(e.zone_id));
|
||||||
|
v.push_back(std::to_string(e.instance_id));
|
||||||
|
v.push_back(std::to_string(e.is_corpse));
|
||||||
|
v.push_back(std::to_string(e.decay_in_seconds));
|
||||||
|
v.push_back(std::to_string(e.npc_id));
|
||||||
|
v.push_back(std::to_string(e.spawn2_id));
|
||||||
|
v.push_back(std::to_string(e.spawngroup_id));
|
||||||
|
v.push_back(std::to_string(e.x));
|
||||||
|
v.push_back(std::to_string(e.y));
|
||||||
|
v.push_back(std::to_string(e.z));
|
||||||
|
v.push_back(std::to_string(e.heading));
|
||||||
|
v.push_back(std::to_string(e.respawn_time));
|
||||||
|
v.push_back(std::to_string(e.variance));
|
||||||
|
v.push_back(std::to_string(e.grid));
|
||||||
|
v.push_back(std::to_string(e.current_waypoint));
|
||||||
|
v.push_back(std::to_string(e.path_when_zone_idle));
|
||||||
|
v.push_back(std::to_string(e.condition_id));
|
||||||
|
v.push_back(std::to_string(e.condition_min_value));
|
||||||
|
v.push_back(std::to_string(e.enabled));
|
||||||
|
v.push_back(std::to_string(e.anim));
|
||||||
|
v.push_back("'" + Strings::Escape(e.loot_data) + "'");
|
||||||
|
v.push_back("'" + Strings::Escape(e.entity_variables) + "'");
|
||||||
|
v.push_back("'" + Strings::Escape(e.buffs) + "'");
|
||||||
|
v.push_back(std::to_string(e.hp));
|
||||||
|
v.push_back(std::to_string(e.mana));
|
||||||
|
v.push_back(std::to_string(e.endurance));
|
||||||
|
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
|
||||||
|
|
||||||
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{} VALUES {}",
|
||||||
|
BaseReplace(),
|
||||||
|
Strings::Implode(",", insert_chunks)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //EQEMU_BASE_ZONE_STATE_SPAWNS_REPOSITORY_H
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#ifndef EQEMU_ZONE_STATE_SPAWNS_REPOSITORY_H
|
||||||
|
#define EQEMU_ZONE_STATE_SPAWNS_REPOSITORY_H
|
||||||
|
|
||||||
|
#include "../database.h"
|
||||||
|
#include "../strings.h"
|
||||||
|
#include "base/base_zone_state_spawns_repository.h"
|
||||||
|
|
||||||
|
class ZoneStateSpawnsRepository: public BaseZoneStateSpawnsRepository {
|
||||||
|
public:
|
||||||
|
// Custom extended repository methods here
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //EQEMU_ZONE_STATE_SPAWNS_REPOSITORY_H
|
||||||
@@ -374,6 +374,7 @@ RULE_BOOL(Zone, AllowCrossZoneSpellsOnBots, false, "Set to true to allow cross z
|
|||||||
RULE_BOOL(Zone, AllowCrossZoneSpellsOnMercs, false, "Set to true to allow cross zone spells (cast/remove) to affect mercenaries")
|
RULE_BOOL(Zone, AllowCrossZoneSpellsOnMercs, false, "Set to true to allow cross zone spells (cast/remove) to affect mercenaries")
|
||||||
RULE_BOOL(Zone, AllowCrossZoneSpellsOnPets, false, "Set to true to allow cross zone spells (cast/remove) to affect pets")
|
RULE_BOOL(Zone, AllowCrossZoneSpellsOnPets, false, "Set to true to allow cross zone spells (cast/remove) to affect pets")
|
||||||
RULE_BOOL(Zone, ZoneShardQuestMenuOnly, false, "Set to true if you only want quests to show the zone shard menu")
|
RULE_BOOL(Zone, ZoneShardQuestMenuOnly, false, "Set to true if you only want quests to show the zone shard menu")
|
||||||
|
RULE_BOOL(Zone, StateSavingOnShutdown, true, "Set to true if you want zones to save state on shutdown (npcs, corpses, loot, entity variables, buffs etc.)")
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Map)
|
RULE_CATEGORY(Map)
|
||||||
@@ -528,6 +529,7 @@ RULE_INT(Spells, TargetedAOEMaxTargets, 4, "Max number of targets a Targeted AOE
|
|||||||
RULE_INT(Spells, PointBlankAOEMaxTargets, 0, "Max number of targets a Point-Blank AOE spell can cast on. Set to 0 for no limit.")
|
RULE_INT(Spells, PointBlankAOEMaxTargets, 0, "Max number of targets a Point-Blank AOE spell can cast on. Set to 0 for no limit.")
|
||||||
RULE_INT(Spells, DefaultAOEMaxTargets, 0, "Max number of targets that an AOE spell which does not meet other descriptions can cast on. Set to 0 for no limit.")
|
RULE_INT(Spells, DefaultAOEMaxTargets, 0, "Max number of targets that an AOE spell which does not meet other descriptions can cast on. Set to 0 for no limit.")
|
||||||
RULE_BOOL(Spells, AllowFocusOnSkillDamageSpells, false, "Allow focus effects 185, 459, and 482 to enhance SkillAttack spell effect 193")
|
RULE_BOOL(Spells, AllowFocusOnSkillDamageSpells, false, "Allow focus effects 185, 459, and 482 to enhance SkillAttack spell effect 193")
|
||||||
|
RULE_STRING(Spells, AlwaysStackSpells, "", "Comma-Seperated list of spell IDs to always stack with every other spell, except themselves.")
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Combat)
|
RULE_CATEGORY(Combat)
|
||||||
@@ -1145,6 +1147,7 @@ RULE_BOOL(Items, DisableSpellFocusEffects, false, "Enable this to disable Spell
|
|||||||
RULE_BOOL(Items, SummonItemAllowInvisibleAugments, false, "Enable this to allow augments to be put in invisible augment slots of items in Client::SummonItem")
|
RULE_BOOL(Items, SummonItemAllowInvisibleAugments, false, "Enable this to allow augments to be put in invisible augment slots of items in Client::SummonItem")
|
||||||
RULE_BOOL(Items, AugmentItemAllowInvisibleAugments, false, "Enable this to allow augments to be put in invisible augment slots by players")
|
RULE_BOOL(Items, AugmentItemAllowInvisibleAugments, false, "Enable this to allow augments to be put in invisible augment slots by players")
|
||||||
RULE_BOOL(Items, AlwaysReturnHandins, true, "Enable this to always return handins to the player")
|
RULE_BOOL(Items, AlwaysReturnHandins, true, "Enable this to always return handins to the player")
|
||||||
|
RULE_BOOL(Items, NPCUseRecommendedLevels, false, "Enable to have NPCs scale item stats by recommended levels")
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Parcel)
|
RULE_CATEGORY(Parcel)
|
||||||
|
|||||||
+33
-16
@@ -677,36 +677,53 @@ struct ServerLSPlayerZoneChange_Struct {
|
|||||||
uint32 to; // 0 = world
|
uint32 to; // 0 = world
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ClientAuth_Struct {
|
struct ClientAuth {
|
||||||
uint32 loginserver_account_id; // ID# in login server's db
|
uint32 loginserver_account_id; // ID# in login server's db
|
||||||
char loginserver_name[64];
|
char loginserver_name[64];
|
||||||
char account_name[30]; // username in login server's db
|
char account_name[30]; // username in login server's db
|
||||||
char key[30]; // the Key the client will present
|
char key[30]; // the key the client will present
|
||||||
uint8 lsadmin; // login server admin level
|
uint8 lsadmin; // login server admin level
|
||||||
int16 is_world_admin; // login's suggested worldadmin level setting for this user, up to the world if they want to obey it
|
int16 is_world_admin; // login's suggested worldadmin level setting for this user, up to the world if they want to obey it
|
||||||
uint32 ip;
|
uint32 ip_address;
|
||||||
uint8 is_client_from_local_network; // 1 if the client is from the local network
|
uint8 is_client_from_local_network; // 1 if the client is from the local network
|
||||||
|
|
||||||
template<class Archive>
|
template<class Archive>
|
||||||
void serialize(Archive &ar)
|
void serialize(Archive &ar)
|
||||||
{
|
{
|
||||||
ar(loginserver_account_id, loginserver_name, account_name, key, lsadmin, is_world_admin, ip, is_client_from_local_network);
|
ar(
|
||||||
|
loginserver_account_id,
|
||||||
|
loginserver_name,
|
||||||
|
account_name,
|
||||||
|
key,
|
||||||
|
lsadmin,
|
||||||
|
is_world_admin,
|
||||||
|
ip_address,
|
||||||
|
is_client_from_local_network
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ClientAuthLegacy_Struct {
|
struct ClientAuthLegacy {
|
||||||
uint32 loginserver_account_id; // ID# in login server's db
|
uint32 loginserver_account_id; // ID# in login server's db
|
||||||
char loginserver_account_name[30]; // username in login server's db
|
char loginserver_account_name[30]; // username in login server's db
|
||||||
char key[30]; // the Key the client will present
|
char key[30]; // the key the client will present
|
||||||
uint8 loginserver_admin_level; // login server admin level
|
uint8 loginserver_admin_level; // login server admin level
|
||||||
int16 is_world_admin; // login's suggested worldadmin level setting for this user, up to the world if they want to obey it
|
int16 is_world_admin; // login's suggested worldadmin level setting for this user, up to the world if they want to obey it
|
||||||
uint32 ip;
|
uint32 ip_address;
|
||||||
uint8 is_client_from_local_network; // 1 if the client is from the local network
|
uint8 is_client_from_local_network; // 1 if the client is from the local network
|
||||||
|
|
||||||
template<class Archive>
|
template<class Archive>
|
||||||
void serialize(Archive &ar)
|
void serialize(Archive &ar)
|
||||||
{
|
{
|
||||||
ar(loginserver_account_id, loginserver_account_name, key, loginserver_admin_level, is_world_admin, ip, is_client_from_local_network);
|
ar(
|
||||||
|
loginserver_account_id,
|
||||||
|
loginserver_account_name,
|
||||||
|
key,
|
||||||
|
loginserver_admin_level,
|
||||||
|
is_world_admin,
|
||||||
|
ip_address,
|
||||||
|
is_client_from_local_network
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -834,7 +851,7 @@ struct ServerSyncWorldList_Struct {
|
|||||||
bool placeholder;
|
bool placeholder;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UsertoWorldRequestLegacy_Struct {
|
struct UsertoWorldRequestLegacy {
|
||||||
uint32 lsaccountid;
|
uint32 lsaccountid;
|
||||||
uint32 worldid;
|
uint32 worldid;
|
||||||
uint32 FromID;
|
uint32 FromID;
|
||||||
@@ -842,16 +859,16 @@ struct UsertoWorldRequestLegacy_Struct {
|
|||||||
char IPAddr[64];
|
char IPAddr[64];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UsertoWorldRequest_Struct {
|
struct UsertoWorldRequest {
|
||||||
uint32 lsaccountid;
|
uint32 lsaccountid;
|
||||||
uint32 worldid;
|
uint32 worldid;
|
||||||
uint32 FromID;
|
uint32 FromID; // appears to be unused today
|
||||||
uint32 ToID;
|
uint32 ToID; // appears to be unused today
|
||||||
char IPAddr[64];
|
char IPAddr[64];
|
||||||
char login[64];
|
char login[64];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UsertoWorldResponseLegacy_Struct {
|
struct UsertoWorldResponseLegacy {
|
||||||
uint32 lsaccountid;
|
uint32 lsaccountid;
|
||||||
uint32 worldid;
|
uint32 worldid;
|
||||||
int8 response; // -3) World Full, -2) Banned, -1) Suspended, 0) Denied, 1) Allowed
|
int8 response; // -3) World Full, -2) Banned, -1) Suspended, 0) Denied, 1) Allowed
|
||||||
@@ -859,12 +876,12 @@ struct UsertoWorldResponseLegacy_Struct {
|
|||||||
uint32 ToID;
|
uint32 ToID;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UsertoWorldResponse_Struct {
|
struct UsertoWorldResponse {
|
||||||
uint32 lsaccountid;
|
uint32 lsaccountid;
|
||||||
uint32 worldid;
|
uint32 worldid;
|
||||||
int8 response; // -3) World Full, -2) Banned, -1) Suspended, 0) Denied, 1) Allowed
|
int8 response; // -3) World Full, -2) Banned, -1) Suspended, 0) Denied, 1) Allowed
|
||||||
uint32 FromID;
|
uint32 FromID; // appears to be unused today
|
||||||
uint32 ToID;
|
uint32 ToID; // appears to be unused today
|
||||||
char login[64];
|
char login[64];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -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.0.2-dev" // always append -dev to the current version for custom-builds
|
#define CURRENT_VERSION "23.2.0-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 9306
|
#define CURRENT_BINARY_DATABASE_VERSION 9309
|
||||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9054
|
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9054
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ void WorldServer::ProcessUserToWorldResponseLegacy(uint16_t opcode, const EQ::Ne
|
|||||||
packet.ToString()
|
packet.ToString()
|
||||||
);
|
);
|
||||||
|
|
||||||
if (packet.Length() < sizeof(UsertoWorldResponseLegacy_Struct)) {
|
if (packet.Length() < sizeof(UsertoWorldResponseLegacy)) {
|
||||||
LogError(
|
LogError(
|
||||||
"Received application packet from server that had opcode ServerOP_UsertoWorldResp, "
|
"Received application packet from server that had opcode ServerOP_UsertoWorldResp, "
|
||||||
"but was too small. Discarded to avoid buffer overrun"
|
"but was too small. Discarded to avoid buffer overrun"
|
||||||
@@ -152,7 +152,7 @@ void WorldServer::ProcessUserToWorldResponseLegacy(uint16_t opcode, const EQ::Ne
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *res = (UsertoWorldResponseLegacy_Struct *) 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");
|
Client *c = server.client_manager->GetClient(res->lsaccountid, "eqemu");
|
||||||
@@ -229,7 +229,7 @@ void WorldServer::ProcessUserToWorldResponse(uint16_t opcode, const EQ::Net::Pac
|
|||||||
packet.ToString()
|
packet.ToString()
|
||||||
);
|
);
|
||||||
|
|
||||||
if (packet.Length() < sizeof(UsertoWorldResponse_Struct)) {
|
if (packet.Length() < sizeof(UsertoWorldResponse)) {
|
||||||
LogError(
|
LogError(
|
||||||
"Received application packet from server that had opcode ServerOP_UsertoWorldResp, "
|
"Received application packet from server that had opcode ServerOP_UsertoWorldResp, "
|
||||||
"but was too small. Discarded to avoid buffer overrun"
|
"but was too small. Discarded to avoid buffer overrun"
|
||||||
@@ -238,7 +238,7 @@ void WorldServer::ProcessUserToWorldResponse(uint16_t opcode, const EQ::Net::Pac
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto res = (UsertoWorldResponse_Struct *) packet.Data();
|
auto res = (UsertoWorldResponse *) 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(
|
Client *c = server.client_manager->GetClient(
|
||||||
@@ -358,14 +358,12 @@ void WorldServer::ProcessLSAccountUpdate(uint16_t opcode, const EQ::Net::Packet
|
|||||||
void WorldServer::HandleNewWorldserver(LoginserverNewWorldRequest *req)
|
void WorldServer::HandleNewWorldserver(LoginserverNewWorldRequest *req)
|
||||||
{
|
{
|
||||||
if (m_is_server_logged_in) {
|
if (m_is_server_logged_in) {
|
||||||
LogError(
|
LogInfo("Login server was already marked as logged in, returning");
|
||||||
"Login server was already marked as logged in, aborting"
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!HandleNewWorldserverValidation(req)) {
|
if (!HandleNewWorldserverValidation(req)) {
|
||||||
LogError("WorldServer::HandleNewWorldserver failed validation rules");
|
LogError("failed validation rules");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,7 +492,7 @@ void WorldServer::HandleWorldserverStatusUpdate(LoginserverWorldStatusUpdate *u)
|
|||||||
void WorldServer::SendClientAuthToWorld(Client *c)
|
void WorldServer::SendClientAuthToWorld(Client *c)
|
||||||
{
|
{
|
||||||
EQ::Net::DynamicPacket outapp;
|
EQ::Net::DynamicPacket outapp;
|
||||||
ClientAuth_Struct a{};
|
ClientAuth a{};
|
||||||
|
|
||||||
a.loginserver_account_id = c->GetAccountID();
|
a.loginserver_account_id = c->GetAccountID();
|
||||||
|
|
||||||
@@ -503,7 +501,7 @@ void WorldServer::SendClientAuthToWorld(Client *c)
|
|||||||
|
|
||||||
a.lsadmin = 0;
|
a.lsadmin = 0;
|
||||||
a.is_world_admin = 0;
|
a.is_world_admin = 0;
|
||||||
a.ip = inet_addr(c->GetConnection()->GetRemoteAddr().c_str());
|
a.ip_address = inet_addr(c->GetConnection()->GetRemoteAddr().c_str());
|
||||||
strncpy(a.loginserver_name, &c->GetLoginServerName()[0], 64);
|
strncpy(a.loginserver_name, &c->GetLoginServerName()[0], 64);
|
||||||
|
|
||||||
const std::string &client_address(c->GetConnection()->GetRemoteAddr());
|
const std::string &client_address(c->GetConnection()->GetRemoteAddr());
|
||||||
@@ -521,7 +519,7 @@ void WorldServer::SendClientAuthToWorld(Client *c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct in_addr ip_addr{};
|
struct in_addr ip_addr{};
|
||||||
ip_addr.s_addr = a.ip;
|
ip_addr.s_addr = a.ip_address;
|
||||||
|
|
||||||
LogInfo(
|
LogInfo(
|
||||||
"Client authentication response: world_address [{}] client_address [{}]",
|
"Client authentication response: world_address [{}] client_address [{}]",
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ private:
|
|||||||
std::string m_server_version;
|
std::string m_server_version;
|
||||||
bool m_is_server_authorized_to_list;
|
bool m_is_server_authorized_to_list;
|
||||||
bool m_is_server_logged_in;
|
bool m_is_server_logged_in;
|
||||||
bool m_is_server_trusted;
|
bool m_is_server_trusted; // this is primarily for worldserver being able to push updates to the loginserver
|
||||||
|
|
||||||
static void FormatWorldServerName(char *name, int8 server_list_type);
|
static void FormatWorldServerName(char *name, int8 server_list_type);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -154,9 +154,9 @@ void WorldServerManager::SendUserLoginToWorldRequest(
|
|||||||
|
|
||||||
if (iter != m_world_servers.end()) {
|
if (iter != m_world_servers.end()) {
|
||||||
EQ::Net::DynamicPacket outapp;
|
EQ::Net::DynamicPacket outapp;
|
||||||
outapp.Resize(sizeof(UsertoWorldRequest_Struct));
|
outapp.Resize(sizeof(UsertoWorldRequest));
|
||||||
|
|
||||||
auto *r = reinterpret_cast<UsertoWorldRequest_Struct *>(outapp.Data());
|
auto *r = reinterpret_cast<UsertoWorldRequest *>(outapp.Data());
|
||||||
r->worldid = server_id;
|
r->worldid = server_id;
|
||||||
r->lsaccountid = client_account_id;
|
r->lsaccountid = client_account_id;
|
||||||
strncpy(r->login, client_loginserver.c_str(), 64);
|
strncpy(r->login, client_loginserver.c_str(), 64);
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "eqemu-server",
|
"name": "eqemu-server",
|
||||||
"version": "23.0.2",
|
"version": "23.2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/EQEmu/Server.git"
|
"url": "https://github.com/EQEmu/Server.git"
|
||||||
|
|||||||
+13
-13
@@ -447,30 +447,30 @@ void Client::SendPostEnterWorld() {
|
|||||||
|
|
||||||
bool Client::HandleSendLoginInfoPacket(const EQApplicationPacket *app)
|
bool Client::HandleSendLoginInfoPacket(const EQApplicationPacket *app)
|
||||||
{
|
{
|
||||||
if (app->size != sizeof(LoginInfo_Struct)) {
|
if (app->size != sizeof(LoginInfo)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *login_info = (LoginInfo_Struct *) app->pBuffer;
|
auto *r = (LoginInfo *) app->pBuffer;
|
||||||
|
|
||||||
// Quagmire - max len for name is 18, pass 15
|
// Quagmire - max len for name is 18, pass 15
|
||||||
char name[19] = {0};
|
char name[19] = {0};
|
||||||
char password[16] = {0};
|
char password[16] = {0};
|
||||||
strn0cpy(name, (char *) login_info->login_info, 18);
|
strn0cpy(name, (char *) r->login_info, 18);
|
||||||
strn0cpy(password, (char *) &(login_info->login_info[strlen(name) + 1]), 15);
|
strn0cpy(password, (char *) &(r->login_info[strlen(name) + 1]), 15);
|
||||||
|
|
||||||
LogDebug("Receiving Login Info Packet from Client | name [{0}] password [{1}]", name, password);
|
LogDebug("Receiving login info packet from client | name [{}] password [{}]", name, password);
|
||||||
|
|
||||||
if (strlen(password) <= 1) {
|
if (strlen(password) <= 1) {
|
||||||
LogInfo("Login without a password");
|
LogInfo("Login without a password");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
is_player_zoning = (login_info->zoning == 1);
|
is_player_zoning = (r->zoning == 1);
|
||||||
|
|
||||||
uint32 id = Strings::ToInt(name);
|
uint32 id = Strings::ToInt(name);
|
||||||
if (id == 0) {
|
if (id == 0) {
|
||||||
LogWarning("Receiving Login Info Packet from Client | account_id is 0 - disconnecting");
|
LogWarning("Receiving login info packet from client | account_id is 0 - disconnecting");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,15 +480,15 @@ bool Client::HandleSendLoginInfoPacket(const EQApplicationPacket *app)
|
|||||||
LogClientLogin("Checking authentication id [{}] passed", id);
|
LogClientLogin("Checking authentication id [{}] passed", id);
|
||||||
if (!is_player_zoning) {
|
if (!is_player_zoning) {
|
||||||
// Track who is in and who is out of the game
|
// Track who is in and who is out of the game
|
||||||
char *inout= (char *) "";
|
std::string in_out;
|
||||||
|
|
||||||
if (cle->GetOnline() == CLE_Status::Never) {
|
if (cle->GetOnline() == CLE_Status::Never) {
|
||||||
// Desktop -> Char Select
|
// Desktop -> Char Select
|
||||||
inout = (char *) "In";
|
in_out = "in";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Game -> Char Select
|
// Game -> Char Select
|
||||||
inout=(char *) "Out";
|
in_out = "out";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always at Char select at this point.
|
// Always at Char select at this point.
|
||||||
@@ -497,7 +497,7 @@ bool Client::HandleSendLoginInfoPacket(const EQApplicationPacket *app)
|
|||||||
// Could use a Logging Out Completely message somewhere.
|
// Could use a Logging Out Completely message somewhere.
|
||||||
cle->SetOnline(CLE_Status::CharSelect);
|
cle->SetOnline(CLE_Status::CharSelect);
|
||||||
|
|
||||||
LogInfo("Account ({}) Logging({}) to character select :: LSID [{}] ", cle->AccountName(), inout, cle->LSID());
|
LogInfo("Account ({}) Logging ({}) to character select :: LSID [{}] ", cle->AccountName(), in_out, cle->LSID());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
cle->SetOnline();
|
cle->SetOnline();
|
||||||
@@ -545,7 +545,7 @@ bool Client::HandleSendLoginInfoPacket(const EQApplicationPacket *app)
|
|||||||
if (!skip_char_info && !custom_files_key.empty() && cle->Admin() < RuleI(World, CustomFilesAdminLevel)) {
|
if (!skip_char_info && !custom_files_key.empty() && cle->Admin() < RuleI(World, CustomFilesAdminLevel)) {
|
||||||
// Modified clients can utilize this unused block in login_info to send custom payloads on login
|
// Modified clients can utilize this unused block in login_info to send custom payloads on login
|
||||||
// which indicates they are using custom client files with the correct version, based on key payload.
|
// which indicates they are using custom client files with the correct version, based on key payload.
|
||||||
const auto client_key = std::string(reinterpret_cast<char*>(login_info->unknown064));
|
const auto client_key = std::string(reinterpret_cast<char*>(r->unknown064));
|
||||||
if (custom_files_key != client_key) {
|
if (custom_files_key != client_key) {
|
||||||
std::string message = fmt::format("Missing Files [{}]", RuleS(World, CustomFilesUrl) );
|
std::string message = fmt::format("Missing Files [{}]", RuleS(World, CustomFilesUrl) );
|
||||||
SendUnsupportedClientPacket(message);
|
SendUnsupportedClientPacket(message);
|
||||||
@@ -1434,7 +1434,7 @@ void Client::EnterWorld(bool TryBootup) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (TryBootup) {
|
if (TryBootup) {
|
||||||
LogInfo("Attempting autobootup of [{}] ([{}]:[{}])", zone_name, zone_id, instance_id);
|
LogInfo("Attempting autobootup of [{}] [{}] [{}]", zone_name, zone_id, instance_id);
|
||||||
autobootup_timeout.Start();
|
autobootup_timeout.Start();
|
||||||
zone_waiting_for_bootup = zoneserver_list.TriggerBootup(zone_id, instance_id);
|
zone_waiting_for_bootup = zoneserver_list.TriggerBootup(zone_id, instance_id);
|
||||||
if (zone_waiting_for_bootup == 0) {
|
if (zone_waiting_for_bootup == 0) {
|
||||||
|
|||||||
+155
-178
@@ -1,20 +1,3 @@
|
|||||||
/* EQEMu: Everquest Server Emulator
|
|
||||||
Copyright (C) 2001-2005 EQEMu Development Team (http://eqemulator.net)
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
||||||
are required to give you total support for your newly bought product;
|
|
||||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
#include "../common/global_define.h"
|
#include "../common/global_define.h"
|
||||||
#include "cliententry.h"
|
#include "cliententry.h"
|
||||||
#include "clientlist.h"
|
#include "clientlist.h"
|
||||||
@@ -24,8 +7,6 @@
|
|||||||
#include "worlddb.h"
|
#include "worlddb.h"
|
||||||
#include "zoneserver.h"
|
#include "zoneserver.h"
|
||||||
#include "world_config.h"
|
#include "world_config.h"
|
||||||
#include "../common/guilds.h"
|
|
||||||
#include "../common/strings.h"
|
|
||||||
|
|
||||||
extern uint32 numplayers;
|
extern uint32 numplayers;
|
||||||
extern LoginServerList loginserverlist;
|
extern LoginServerList loginserverlist;
|
||||||
@@ -33,84 +14,79 @@ extern ClientList client_list;
|
|||||||
extern volatile bool RunLoops;
|
extern volatile bool RunLoops;
|
||||||
extern SharedTaskManager shared_task_manager;
|
extern SharedTaskManager shared_task_manager;
|
||||||
|
|
||||||
/**
|
|
||||||
* @param in_id
|
|
||||||
* @param in_loginserver_id
|
|
||||||
* @param in_loginserver_name
|
|
||||||
* @param in_login_name
|
|
||||||
* @param in_login_key
|
|
||||||
* @param in_is_world_admin
|
|
||||||
* @param ip
|
|
||||||
* @param local
|
|
||||||
*/
|
|
||||||
ClientListEntry::ClientListEntry(
|
ClientListEntry::ClientListEntry(
|
||||||
uint32 in_id,
|
uint32 id,
|
||||||
uint32 in_loginserver_id,
|
uint32 login_server_id,
|
||||||
const char *in_loginserver_name,
|
const char *login_server_name,
|
||||||
const char *in_login_name,
|
const char *account_name,
|
||||||
const char *in_login_key,
|
const char *login_key,
|
||||||
int16 in_is_world_admin,
|
int16 is_world_admin,
|
||||||
uint32 ip,
|
uint32 ip_address,
|
||||||
uint8 local
|
uint8 local
|
||||||
)
|
)
|
||||||
: id(in_id)
|
: m_id(id)
|
||||||
{
|
{
|
||||||
ClearVars(true);
|
ClearVars(true);
|
||||||
|
|
||||||
LogDebug(
|
LogDebug(
|
||||||
"in_id [{0}] in_loginserver_id [{1}] in_loginserver_name [{2}] in_login_name [{3}] in_login_key [{4}] "
|
"id [{}] loginserver_id [{}] loginserver_name [{}] login_name [{}] login_key [{}] is_world_admin [{}] ip [{}] local [{}]",
|
||||||
" in_is_world_admin [{5}] ip [{6}] local [{7}]",
|
id,
|
||||||
in_id,
|
login_server_id,
|
||||||
in_loginserver_id,
|
login_server_name,
|
||||||
in_loginserver_name,
|
account_name,
|
||||||
in_login_name,
|
login_key,
|
||||||
in_login_key,
|
is_world_admin,
|
||||||
in_is_world_admin,
|
ip_address,
|
||||||
ip,
|
|
||||||
local
|
local
|
||||||
);
|
);
|
||||||
|
|
||||||
pIP = ip;
|
m_ip_address = ip_address;
|
||||||
pLSID = in_loginserver_id;
|
m_login_server_id = login_server_id;
|
||||||
if (in_loginserver_id > 0) {
|
if (login_server_id > 0) {
|
||||||
paccountid = database.GetAccountIDFromLSID(in_loginserver_name, in_loginserver_id, paccountname, &padmin);
|
m_account_id = database.GetAccountIDFromLSID(
|
||||||
|
login_server_name,
|
||||||
|
login_server_id,
|
||||||
|
m_account_name,
|
||||||
|
&m_admin
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
strn0cpy(loginserver_account_name, in_login_name, sizeof(loginserver_account_name));
|
strn0cpy(m_login_account_name, account_name, sizeof(m_login_account_name));
|
||||||
strn0cpy(plskey, in_login_key, sizeof(plskey));
|
strn0cpy(m_key, login_key, sizeof(m_key));
|
||||||
strn0cpy(source_loginserver, in_loginserver_name, sizeof(source_loginserver));
|
strn0cpy(m_source_loginserver, login_server_name, sizeof(m_source_loginserver));
|
||||||
pworldadmin = in_is_world_admin;
|
|
||||||
plocal = (local == 1);
|
|
||||||
|
|
||||||
memset(pLFGComments, 0, 64);
|
m_world_admin = is_world_admin;
|
||||||
|
m_is_local = (local == 1);
|
||||||
|
|
||||||
|
memset(m_lfg_comments, 0, 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientListEntry::ClientListEntry(uint32 in_id, ZoneServer *iZS, ServerClientList_Struct *scl, CLE_Status iOnline)
|
ClientListEntry::ClientListEntry(uint32 in_id, ZoneServer *z, ServerClientList_Struct *scl, CLE_Status online)
|
||||||
: id(in_id)
|
: m_id(in_id)
|
||||||
{
|
{
|
||||||
ClearVars(true);
|
ClearVars(true);
|
||||||
|
|
||||||
pIP = 0;
|
m_ip_address = 0;
|
||||||
pLSID = scl->LSAccountID;
|
m_login_server_id = scl->LSAccountID;
|
||||||
strn0cpy(loginserver_account_name, scl->name, sizeof(loginserver_account_name));
|
strn0cpy(m_login_account_name, scl->name, sizeof(m_login_account_name));
|
||||||
strn0cpy(plskey, scl->lskey, sizeof(plskey));
|
strn0cpy(m_key, scl->lskey, sizeof(m_key));
|
||||||
pworldadmin = 0;
|
m_world_admin = 0;
|
||||||
|
|
||||||
paccountid = scl->AccountID;
|
m_account_id = scl->AccountID;
|
||||||
strn0cpy(paccountname, scl->AccountName, sizeof(paccountname));
|
strn0cpy(m_account_name, scl->AccountName, sizeof(m_account_name));
|
||||||
padmin = scl->Admin;
|
m_admin = scl->Admin;
|
||||||
|
|
||||||
pinstance = 0;
|
m_instance = 0;
|
||||||
pLFGFromLevel = 0;
|
m_lfg_from_level = 0;
|
||||||
pLFGToLevel = 0;
|
m_lfg_to_level = 0;
|
||||||
pLFGMatchFilter = false;
|
m_lfg_match_filter = false;
|
||||||
memset(pLFGComments, 0, 64);
|
memset(m_lfg_comments, 0, 64);
|
||||||
|
|
||||||
if (iOnline >= CLE_Status::Zoning) {
|
if (online >= CLE_Status::Zoning) {
|
||||||
Update(iZS, scl, iOnline);
|
Update(z, scl, online);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
SetOnline(iOnline);
|
SetOnline(online);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,16 +96,16 @@ ClientListEntry::~ClientListEntry()
|
|||||||
Camp(); // updates zoneserver's numplayers
|
Camp(); // updates zoneserver's numplayers
|
||||||
client_list.RemoveCLEReferances(this);
|
client_list.RemoveCLEReferances(this);
|
||||||
}
|
}
|
||||||
for (auto& elem : tell_queue) {
|
for (auto &elem: m_tell_queue) {
|
||||||
safe_delete_array(elem);
|
safe_delete_array(elem);
|
||||||
}
|
}
|
||||||
tell_queue.clear();
|
m_tell_queue.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientListEntry::SetChar(uint32 iCharID, const char *iCharName)
|
void ClientListEntry::SetChar(uint32 iCharID, const char *iCharName)
|
||||||
{
|
{
|
||||||
pcharid = iCharID;
|
m_char_id = iCharID;
|
||||||
strn0cpy(pname, iCharName, sizeof(pname));
|
strn0cpy(m_char_name, iCharName, sizeof(m_char_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientListEntry::SetOnline(CLE_Status iOnline)
|
void ClientListEntry::SetOnline(CLE_Status iOnline)
|
||||||
@@ -142,20 +118,20 @@ void ClientListEntry::SetOnline(CLE_Status iOnline)
|
|||||||
static_cast<int>(iOnline)
|
static_cast<int>(iOnline)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (iOnline >= CLE_Status::Online && pOnline < CLE_Status::Online) {
|
if (iOnline >= CLE_Status::Online && m_online < CLE_Status::Online) {
|
||||||
numplayers++;
|
numplayers++;
|
||||||
}
|
}
|
||||||
else if (iOnline < CLE_Status::Online && pOnline >= CLE_Status::Online) {
|
else if (iOnline < CLE_Status::Online && m_online >= CLE_Status::Online) {
|
||||||
numplayers--;
|
numplayers--;
|
||||||
}
|
}
|
||||||
if (iOnline != CLE_Status::Online || pOnline < CLE_Status::Online) {
|
if (iOnline != CLE_Status::Online || m_online < CLE_Status::Online) {
|
||||||
pOnline = iOnline;
|
m_online = iOnline;
|
||||||
}
|
}
|
||||||
if (iOnline < CLE_Status::Zoning) {
|
if (iOnline < CLE_Status::Zoning) {
|
||||||
Camp();
|
Camp();
|
||||||
}
|
}
|
||||||
if (pOnline >= CLE_Status::Online) {
|
if (m_online >= CLE_Status::Online) {
|
||||||
stale = 0;
|
m_stale = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,49 +169,49 @@ void ClientListEntry::LSZoneChange(ZoneToZone_Struct *ztz)
|
|||||||
|
|
||||||
void ClientListEntry::Update(ZoneServer *iZS, ServerClientList_Struct *scl, CLE_Status iOnline)
|
void ClientListEntry::Update(ZoneServer *iZS, ServerClientList_Struct *scl, CLE_Status iOnline)
|
||||||
{
|
{
|
||||||
if (pzoneserver != iZS) {
|
if (m_zone_server != iZS) {
|
||||||
if (pzoneserver) {
|
if (m_zone_server) {
|
||||||
pzoneserver->RemovePlayer();
|
m_zone_server->RemovePlayer();
|
||||||
LSUpdate(pzoneserver);
|
LSUpdate(m_zone_server);
|
||||||
}
|
}
|
||||||
if (iZS) {
|
if (iZS) {
|
||||||
iZS->AddPlayer();
|
iZS->AddPlayer();
|
||||||
LSUpdate(iZS);
|
LSUpdate(iZS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pzoneserver = iZS;
|
m_zone_server = iZS;
|
||||||
pzone = scl->zone;
|
m_zone = scl->zone;
|
||||||
pinstance = scl->instance_id;
|
m_instance = scl->instance_id;
|
||||||
pcharid = scl->charid;
|
m_char_id = scl->charid;
|
||||||
|
|
||||||
strcpy(pname, scl->name);
|
strcpy(m_char_name, scl->name);
|
||||||
if (paccountid == 0) {
|
if (m_account_id == 0) {
|
||||||
paccountid = scl->AccountID;
|
m_account_id = scl->AccountID;
|
||||||
strcpy(paccountname, scl->AccountName);
|
strcpy(m_account_name, scl->AccountName);
|
||||||
strcpy(loginserver_account_name, scl->AccountName);
|
strcpy(m_login_account_name, scl->AccountName);
|
||||||
pIP = scl->IP;
|
m_ip_address = scl->IP;
|
||||||
pLSID = scl->LSAccountID;
|
m_login_server_id = scl->LSAccountID;
|
||||||
strn0cpy(plskey, scl->lskey, sizeof(plskey));
|
strn0cpy(m_key, scl->lskey, sizeof(m_key));
|
||||||
}
|
}
|
||||||
padmin = scl->Admin;
|
m_admin = scl->Admin;
|
||||||
plevel = scl->level;
|
m_level = scl->level;
|
||||||
pclass_ = scl->class_;
|
m_class_ = scl->class_;
|
||||||
prace = scl->race;
|
m_race = scl->race;
|
||||||
panon = scl->anon;
|
m_anon = scl->anon;
|
||||||
ptellsoff = scl->tellsoff;
|
m_tells_off = scl->tellsoff;
|
||||||
pguild_id = scl->guild_id;
|
m_guild_id = scl->guild_id;
|
||||||
pguild_rank = scl->guild_rank;
|
m_guild_rank = scl->guild_rank;
|
||||||
pguild_tribute_opt_in = scl->guild_tribute_opt_in;
|
m_guild_tribute_opt_in = scl->guild_tribute_opt_in;
|
||||||
pLFG = scl->LFG;
|
m_lfg = scl->LFG;
|
||||||
gm = scl->gm;
|
m_gm = scl->gm;
|
||||||
pClientVersion = scl->ClientVersion;
|
m_client_version = scl->ClientVersion;
|
||||||
|
|
||||||
// Fields from the LFG Window
|
// Fields from the LFG Window
|
||||||
if ((scl->LFGFromLevel != 0) && (scl->LFGToLevel != 0)) {
|
if ((scl->LFGFromLevel != 0) && (scl->LFGToLevel != 0)) {
|
||||||
pLFGFromLevel = scl->LFGFromLevel;
|
m_lfg_from_level = scl->LFGFromLevel;
|
||||||
pLFGToLevel = scl->LFGToLevel;
|
m_lfg_to_level = scl->LFGToLevel;
|
||||||
pLFGMatchFilter = scl->LFGMatchFilter;
|
m_lfg_match_filter = scl->LFGMatchFilter;
|
||||||
memcpy(pLFGComments, scl->LFGComments, sizeof(pLFGComments));
|
memcpy(m_lfg_comments, scl->LFGComments, sizeof(m_lfg_comments));
|
||||||
}
|
}
|
||||||
|
|
||||||
SetOnline(iOnline);
|
SetOnline(iOnline);
|
||||||
@@ -243,76 +219,76 @@ void ClientListEntry::Update(ZoneServer *iZS, ServerClientList_Struct *scl, CLE_
|
|||||||
|
|
||||||
void ClientListEntry::LeavingZone(ZoneServer *iZS, CLE_Status iOnline)
|
void ClientListEntry::LeavingZone(ZoneServer *iZS, CLE_Status iOnline)
|
||||||
{
|
{
|
||||||
if (iZS != 0 && iZS != pzoneserver) {
|
if (iZS != 0 && iZS != m_zone_server) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SetOnline(iOnline);
|
SetOnline(iOnline);
|
||||||
|
|
||||||
shared_task_manager.RemoveActiveInvitationByCharacterID(CharID());
|
shared_task_manager.RemoveActiveInvitationByCharacterID(CharID());
|
||||||
|
|
||||||
if (pzoneserver) {
|
if (m_zone_server) {
|
||||||
pzoneserver->RemovePlayer();
|
m_zone_server->RemovePlayer();
|
||||||
LSUpdate(pzoneserver);
|
LSUpdate(m_zone_server);
|
||||||
}
|
}
|
||||||
pzoneserver = 0;
|
m_zone_server = 0;
|
||||||
pzone = 0;
|
m_zone = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientListEntry::ClearVars(bool iAll)
|
void ClientListEntry::ClearVars(bool iAll)
|
||||||
{
|
{
|
||||||
if (iAll) {
|
if (iAll) {
|
||||||
pOnline = CLE_Status::Never;
|
m_online = CLE_Status::Never;
|
||||||
stale = 0;
|
m_stale = 0;
|
||||||
|
|
||||||
pLSID = 0;
|
m_login_server_id = 0;
|
||||||
memset(loginserver_account_name, 0, sizeof(loginserver_account_name));
|
memset(m_login_account_name, 0, sizeof(m_login_account_name));
|
||||||
memset(plskey, 0, sizeof(plskey));
|
memset(m_key, 0, sizeof(m_key));
|
||||||
pworldadmin = 0;
|
m_world_admin = 0;
|
||||||
|
|
||||||
paccountid = 0;
|
m_account_id = 0;
|
||||||
memset(paccountname, 0, sizeof(paccountname));
|
memset(m_account_name, 0, sizeof(m_account_name));
|
||||||
padmin = AccountStatus::Player;
|
m_admin = AccountStatus::Player;
|
||||||
}
|
}
|
||||||
pzoneserver = 0;
|
m_zone_server = 0;
|
||||||
pzone = 0;
|
m_zone = 0;
|
||||||
pcharid = 0;
|
m_char_id = 0;
|
||||||
memset(pname, 0, sizeof(pname));
|
memset(m_char_name, 0, sizeof(m_char_name));
|
||||||
plevel = 0;
|
m_level = 0;
|
||||||
pclass_ = 0;
|
m_class_ = 0;
|
||||||
prace = 0;
|
m_race = 0;
|
||||||
panon = 0;
|
m_anon = 0;
|
||||||
ptellsoff = 0;
|
m_tells_off = 0;
|
||||||
pguild_id = GUILD_NONE;
|
m_guild_id = GUILD_NONE;
|
||||||
pguild_rank = 0;
|
m_guild_rank = 0;
|
||||||
pLFG = 0;
|
m_lfg = 0;
|
||||||
gm = 0;
|
m_gm = 0;
|
||||||
pClientVersion = 0;
|
m_client_version = 0;
|
||||||
for (auto& elem : tell_queue) {
|
for (auto &elem: m_tell_queue) {
|
||||||
safe_delete_array(elem);
|
safe_delete_array(elem);
|
||||||
}
|
}
|
||||||
tell_queue.clear();
|
m_tell_queue.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientListEntry::Camp(ZoneServer *iZS)
|
void ClientListEntry::Camp(ZoneServer *iZS)
|
||||||
{
|
{
|
||||||
if (iZS != 0 && iZS != pzoneserver) {
|
if (iZS != 0 && iZS != m_zone_server) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (pzoneserver) {
|
if (m_zone_server) {
|
||||||
pzoneserver->RemovePlayer();
|
m_zone_server->RemovePlayer();
|
||||||
LSUpdate(pzoneserver);
|
LSUpdate(m_zone_server);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClearVars();
|
ClearVars();
|
||||||
|
|
||||||
stale = 0;
|
m_stale = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ClientListEntry::CheckStale()
|
bool ClientListEntry::CheckStale()
|
||||||
{
|
{
|
||||||
stale++;
|
m_stale++;
|
||||||
if (stale > 20) {
|
if (m_stale > 20) {
|
||||||
if (pOnline > CLE_Status::Offline) {
|
if (m_online > CLE_Status::Offline) {
|
||||||
SetOnline(CLE_Status::Offline);
|
SetOnline(CLE_Status::Offline);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,48 +300,50 @@ bool ClientListEntry::CheckStale()
|
|||||||
bool ClientListEntry::CheckAuth(uint32 loginserver_account_id, const char *key_password)
|
bool ClientListEntry::CheckAuth(uint32 loginserver_account_id, const char *key_password)
|
||||||
{
|
{
|
||||||
LogDebug(
|
LogDebug(
|
||||||
"ls_account_id [{0}] key_password [{1}] plskey [{2}]",
|
"ls_account_id [{}] key_password [{}] key [{}]",
|
||||||
loginserver_account_id,
|
loginserver_account_id,
|
||||||
key_password,
|
key_password,
|
||||||
plskey
|
m_key
|
||||||
);
|
);
|
||||||
if (pLSID == loginserver_account_id && strncmp(plskey, key_password, 10) == 0) {
|
|
||||||
|
|
||||||
|
if (m_login_server_id == loginserver_account_id && strncmp(m_key, key_password, 10) == 0) {
|
||||||
LogDebug(
|
LogDebug(
|
||||||
"ls_account_id [{0}] key_password [{1}] plskey [{2}] lsid [{3}] paccountid [{4}]",
|
"ls_account_id [{}] key_password [{}] m_key [{}] lsid [{}] m_account_id [{}]",
|
||||||
loginserver_account_id,
|
loginserver_account_id,
|
||||||
key_password,
|
key_password,
|
||||||
plskey,
|
m_key,
|
||||||
LSID(),
|
LSID(),
|
||||||
paccountid
|
m_account_id
|
||||||
);
|
);
|
||||||
|
|
||||||
if (paccountid == 0 && LSID() > 0) {
|
// create account if it doesn't exist
|
||||||
|
if (m_account_id == 0 && LSID() > 0) {
|
||||||
int16 default_account_status = WorldConfig::get()->DefaultStatus;
|
int16 default_account_status = WorldConfig::get()->DefaultStatus;
|
||||||
|
|
||||||
paccountid = database.CreateAccount(
|
m_account_id = database.CreateAccount(
|
||||||
loginserver_account_name,
|
m_login_account_name,
|
||||||
std::string(),
|
std::string(),
|
||||||
default_account_status,
|
default_account_status,
|
||||||
source_loginserver,
|
m_source_loginserver,
|
||||||
LSID()
|
LSID()
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!paccountid) {
|
if (!m_account_id) {
|
||||||
LogInfo(
|
LogError(
|
||||||
"Error adding local account for LS login: [{0}:{1}], duplicate name",
|
"Error adding local account for LS login [{}] [{}], duplicate name",
|
||||||
source_loginserver,
|
m_source_loginserver,
|
||||||
loginserver_account_name
|
m_login_account_name
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
strn0cpy(paccountname, loginserver_account_name, sizeof(paccountname));
|
strn0cpy(m_account_name, m_login_account_name, sizeof(m_account_name));
|
||||||
padmin = default_account_status;
|
m_admin = default_account_status;
|
||||||
}
|
}
|
||||||
std::string lsworldadmin;
|
std::string lsworldadmin;
|
||||||
if (database.GetVariable("honorlsworldadmin", lsworldadmin)) {
|
if (database.GetVariable("honorlsworldadmin", lsworldadmin)) {
|
||||||
if (Strings::ToInt(lsworldadmin) == 1 && pworldadmin != 0 && (padmin < pworldadmin || padmin == AccountStatus::Player)) {
|
if (Strings::ToInt(lsworldadmin) == 1 && m_world_admin != 0 &&
|
||||||
padmin = pworldadmin;
|
(m_admin < m_world_admin || m_admin == AccountStatus::Player)) {
|
||||||
|
m_admin = m_world_admin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -380,8 +358,8 @@ void ClientListEntry::ProcessTellQueue()
|
|||||||
}
|
}
|
||||||
|
|
||||||
ServerPacket *pack;
|
ServerPacket *pack;
|
||||||
auto it = tell_queue.begin();
|
auto it = m_tell_queue.begin();
|
||||||
while (it != tell_queue.end()) {
|
while (it != m_tell_queue.end()) {
|
||||||
pack = new ServerPacket(
|
pack = new ServerPacket(
|
||||||
ServerOP_ChannelMessage,
|
ServerOP_ChannelMessage,
|
||||||
sizeof(ServerChannelMessage_Struct) + strlen((*it)->message) + 1
|
sizeof(ServerChannelMessage_Struct) + strlen((*it)->message) + 1
|
||||||
@@ -390,8 +368,7 @@ void ClientListEntry::ProcessTellQueue()
|
|||||||
Server()->SendPacket(pack);
|
Server()->SendPacket(pack);
|
||||||
safe_delete(pack);
|
safe_delete(pack);
|
||||||
safe_delete_array(*it);
|
safe_delete_array(*it);
|
||||||
it = tell_queue.erase(it);
|
it = m_tell_queue.erase(it);
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+88
-106
@@ -8,8 +8,7 @@
|
|||||||
#include "../common/rulesys.h"
|
#include "../common/rulesys.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
typedef enum
|
typedef enum {
|
||||||
{
|
|
||||||
Never,
|
Never,
|
||||||
Offline,
|
Offline,
|
||||||
Online,
|
Online,
|
||||||
@@ -33,35 +32,18 @@ struct ServerClientList_Struct;
|
|||||||
class ClientListEntry {
|
class ClientListEntry {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
|
||||||
* @param id
|
|
||||||
* @param in_loginserver_id
|
|
||||||
* @param in_loginserver_name
|
|
||||||
* @param in_login_name
|
|
||||||
* @param in_login_key
|
|
||||||
* @param in_is_world_admin
|
|
||||||
* @param ip
|
|
||||||
* @param local
|
|
||||||
*/
|
|
||||||
ClientListEntry(
|
ClientListEntry(
|
||||||
uint32 id,
|
uint32 id,
|
||||||
uint32 in_loginserver_id,
|
uint32 login_server_id,
|
||||||
const char *in_loginserver_name,
|
const char *login_server_name,
|
||||||
const char *in_login_name,
|
const char *account_name,
|
||||||
const char *in_login_key,
|
const char *login_key,
|
||||||
int16 in_is_world_admin = 0,
|
int16 is_world_admin = 0,
|
||||||
uint32 ip = 0,
|
uint32 ip_address = 0,
|
||||||
uint8 local = 0
|
uint8 local = 0
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
ClientListEntry(uint32 id, ZoneServer *z, ServerClientList_Struct *scl, CLE_Status online);
|
||||||
* @param id
|
|
||||||
* @param iZS
|
|
||||||
* @param scl
|
|
||||||
* @param iOnline
|
|
||||||
*/
|
|
||||||
ClientListEntry(uint32 id, uint32 iAccID, const char* iAccName, MD5& iMD5Pass, int16 iAdmin = AccountStatus::Player);
|
|
||||||
ClientListEntry(uint32 id, ZoneServer* iZS, ServerClientList_Struct* scl, CLE_Status iOnline);
|
|
||||||
~ClientListEntry();
|
~ClientListEntry();
|
||||||
bool CheckStale();
|
bool CheckStale();
|
||||||
void Update(ZoneServer *zoneserver, ServerClientList_Struct *scl, CLE_Status iOnline = CLE_Status::InZone);
|
void Update(ZoneServer *zoneserver, ServerClientList_Struct *scl, CLE_Status iOnline = CLE_Status::InZone);
|
||||||
@@ -70,61 +52,61 @@ public:
|
|||||||
bool CheckAuth(uint32 loginserver_account_id, const char *key_password);
|
bool CheckAuth(uint32 loginserver_account_id, const char *key_password);
|
||||||
void SetOnline(CLE_Status iOnline = CLE_Status::Online);
|
void SetOnline(CLE_Status iOnline = CLE_Status::Online);
|
||||||
void SetChar(uint32 iCharID, const char *iCharName);
|
void SetChar(uint32 iCharID, const char *iCharName);
|
||||||
inline CLE_Status Online() { return pOnline; }
|
inline CLE_Status Online() { return m_online; }
|
||||||
inline const uint32 GetID() const { return id; }
|
inline const uint32 GetID() const { return m_id; }
|
||||||
inline const uint32 GetIP() const { return pIP; }
|
inline const uint32 GetIP() const { return m_ip_address; }
|
||||||
inline void SetIP(const uint32& iIP) { pIP = iIP; }
|
inline void SetIP(const uint32 &iIP) { m_ip_address = iIP; }
|
||||||
inline void KeepAlive() { stale = 0; }
|
inline void KeepAlive() { m_stale = 0; }
|
||||||
inline uint8 GetStaleCounter() const { return stale; }
|
inline uint8 GetStaleCounter() const { return m_stale; }
|
||||||
void LeavingZone(ZoneServer *iZS = 0, CLE_Status iOnline = CLE_Status::Offline);
|
void LeavingZone(ZoneServer *iZS = 0, CLE_Status iOnline = CLE_Status::Offline);
|
||||||
void Camp(ZoneServer *iZS = 0);
|
void Camp(ZoneServer *iZS = 0);
|
||||||
|
|
||||||
// Login Server stuff
|
// Login Server stuff
|
||||||
inline const char* LoginServer() const { return source_loginserver; }
|
inline const char *LoginServer() const { return m_source_loginserver; }
|
||||||
inline uint32 LSID() const { return pLSID; }
|
inline uint32 LSID() const { return m_login_server_id; }
|
||||||
inline uint32 LSAccountID() const { return pLSID; }
|
inline uint32 LSAccountID() const { return m_login_server_id; }
|
||||||
inline const char* LSName() const { return loginserver_account_name; }
|
inline const char *LSName() const { return m_login_account_name; }
|
||||||
inline int16 WorldAdmin() const { return pworldadmin; }
|
inline int16 WorldAdmin() const { return m_world_admin; }
|
||||||
inline const char* GetLSKey() const { return plskey; }
|
inline const char *GetLSKey() const { return m_key; }
|
||||||
inline const CLE_Status GetOnline() const { return pOnline; }
|
inline const CLE_Status GetOnline() const { return m_online; }
|
||||||
|
|
||||||
// Account stuff
|
// Account stuff
|
||||||
inline uint32 AccountID() const { return paccountid; }
|
inline uint32 AccountID() const { return m_account_id; }
|
||||||
inline const char* AccountName() const { return paccountname; }
|
inline const char *AccountName() const { return m_account_name; }
|
||||||
inline int16 Admin() const { return padmin; }
|
inline int16 Admin() const { return m_admin; }
|
||||||
inline void SetAdmin(uint16 iAdmin) { padmin = iAdmin; }
|
inline void SetAdmin(uint16 iAdmin) { m_admin = iAdmin; }
|
||||||
|
|
||||||
// Character info
|
// Character info
|
||||||
inline ZoneServer *Server() const { return pzoneserver; }
|
inline ZoneServer *Server() const { return m_zone_server; }
|
||||||
inline void ClearServer() { pzoneserver = 0; }
|
inline void ClearServer() { m_zone_server = 0; }
|
||||||
inline uint32 CharID() const { return pcharid; }
|
inline uint32 CharID() const { return m_char_id; }
|
||||||
inline const char *name() const { return pname; }
|
inline const char *name() const { return m_char_name; }
|
||||||
inline uint32 zone() const { return pzone; }
|
inline uint32 zone() const { return m_zone; }
|
||||||
inline uint16 instance() const { return pinstance; }
|
inline uint16 instance() const { return m_instance; }
|
||||||
inline uint8 level() const { return plevel; }
|
inline uint8 level() const { return m_level; }
|
||||||
inline uint8 class_() const { return pclass_; }
|
inline uint8 class_() const { return m_class_; }
|
||||||
inline uint16 race() const { return prace; }
|
inline uint16 race() const { return m_race; }
|
||||||
inline uint8 Anon() { return panon; }
|
inline uint8 Anon() { return m_anon; }
|
||||||
inline uint8 TellsOff() const { return ptellsoff; }
|
inline uint8 TellsOff() const { return m_tells_off; }
|
||||||
inline uint32 GuildID() const { return pguild_id; }
|
inline uint32 GuildID() const { return m_guild_id; }
|
||||||
inline uint32 GuildRank() const { return pguild_rank; }
|
inline uint32 GuildRank() const { return m_guild_rank; }
|
||||||
inline bool GuildTributeOptIn() const { return pguild_tribute_opt_in; }
|
inline bool GuildTributeOptIn() const { return m_guild_tribute_opt_in; }
|
||||||
inline void SetGuild(uint32 guild_id) { pguild_id = guild_id; }
|
inline void SetGuild(uint32 guild_id) { m_guild_id = guild_id; }
|
||||||
inline void SetGuildTributeOptIn(bool opt) { pguild_tribute_opt_in = opt; }
|
inline void SetGuildTributeOptIn(bool opt) { m_guild_tribute_opt_in = opt; }
|
||||||
inline bool LFG() const { return pLFG; }
|
inline bool LFG() const { return m_lfg; }
|
||||||
inline uint8 GetGM() const { return gm; }
|
inline uint8 GetGM() const { return m_gm; }
|
||||||
inline void SetGM(uint8 igm) { gm = igm; }
|
inline void SetGM(uint8 igm) { m_gm = igm; }
|
||||||
inline void SetZone(uint32 zone) { pzone = zone; }
|
inline void SetZone(uint32 zone) { m_zone = zone; }
|
||||||
inline bool IsLocalClient() const { return plocal; }
|
inline bool IsLocalClient() const { return m_is_local; }
|
||||||
inline uint8 GetLFGFromLevel() const { return pLFGFromLevel; }
|
inline uint8 GetLFGFromLevel() const { return m_lfg_from_level; }
|
||||||
inline uint8 GetLFGToLevel() const { return pLFGToLevel; }
|
inline uint8 GetLFGToLevel() const { return m_lfg_to_level; }
|
||||||
inline bool GetLFGMatchFilter() const { return pLFGMatchFilter; }
|
inline bool GetLFGMatchFilter() const { return m_lfg_match_filter; }
|
||||||
inline const char *GetLFGComments() const { return pLFGComments; }
|
inline const char *GetLFGComments() const { return m_lfg_comments; }
|
||||||
inline uint8 GetClientVersion() { return pClientVersion; }
|
inline uint8 GetClientVersion() { return m_client_version; }
|
||||||
|
|
||||||
inline bool TellQueueFull() const { return tell_queue.size() >= RuleI(World, TellQueueSize); }
|
inline bool TellQueueFull() const { return m_tell_queue.size() >= RuleI(World, TellQueueSize); }
|
||||||
inline bool TellQueueEmpty() const { return tell_queue.empty(); }
|
inline bool TellQueueEmpty() const { return m_tell_queue.empty(); }
|
||||||
inline void PushToTellQueue(ServerChannelMessage_Struct *scm) { tell_queue.push_back(scm); }
|
inline void PushToTellQueue(ServerChannelMessage_Struct *scm) { m_tell_queue.push_back(scm); }
|
||||||
void ProcessTellQueue();
|
void ProcessTellQueue();
|
||||||
|
|
||||||
void SetPendingDzInvite(ServerPacket *pack) { m_dz_invite.reset(pack->Copy()); };
|
void SetPendingDzInvite(ServerPacket *pack) { m_dz_invite.reset(pack->Copy()); };
|
||||||
@@ -133,48 +115,48 @@ public:
|
|||||||
private:
|
private:
|
||||||
void ClearVars(bool iAll = false);
|
void ClearVars(bool iAll = false);
|
||||||
|
|
||||||
const uint32 id;
|
const uint32 m_id;
|
||||||
uint32 pIP;
|
uint32 m_ip_address;
|
||||||
CLE_Status pOnline;
|
CLE_Status m_online;
|
||||||
uint8 stale;
|
uint8 m_stale;
|
||||||
|
|
||||||
// Login Server stuff
|
// Login Server stuff
|
||||||
char source_loginserver[64]{}; //Loginserver we came from.
|
char m_source_loginserver[64]{}; //Loginserver we came from.
|
||||||
uint32 pLSID;
|
uint32 m_login_server_id;
|
||||||
char loginserver_account_name[32]{};
|
char m_login_account_name[32]{};
|
||||||
char plskey[16]{};
|
char m_key[16]{};
|
||||||
int16 pworldadmin; // Login server's suggested admin status setting
|
int16 m_world_admin; // Login server's suggested admin status setting
|
||||||
bool plocal;
|
bool m_is_local;
|
||||||
|
|
||||||
// Account stuff
|
// Account stuff
|
||||||
uint32 paccountid;
|
uint32 m_account_id;
|
||||||
char paccountname[32]{};
|
char m_account_name[32]{};
|
||||||
int16 padmin{};
|
int16 m_admin{};
|
||||||
|
|
||||||
// Character info
|
// Character info
|
||||||
ZoneServer* pzoneserver{};
|
ZoneServer *m_zone_server{};
|
||||||
uint32 pzone{};
|
uint32 m_zone{};
|
||||||
uint16 pinstance{};
|
uint16 m_instance{};
|
||||||
uint32 pcharid{};
|
uint32 m_char_id{};
|
||||||
char pname[64]{};
|
char m_char_name[64]{};
|
||||||
uint8 plevel{};
|
uint8 m_level{};
|
||||||
uint8 pclass_{};
|
uint8 m_class_{};
|
||||||
uint16 prace{};
|
uint16 m_race{};
|
||||||
uint8 panon{};
|
uint8 m_anon{};
|
||||||
uint8 ptellsoff{};
|
uint8 m_tells_off{};
|
||||||
uint32 pguild_id{};
|
uint32 m_guild_id{};
|
||||||
uint32 pguild_rank;
|
uint32 m_guild_rank;
|
||||||
bool pguild_tribute_opt_in{};
|
bool m_guild_tribute_opt_in{};
|
||||||
bool pLFG{};
|
bool m_lfg{};
|
||||||
uint8 gm{};
|
uint8 m_gm{};
|
||||||
uint8 pClientVersion{};
|
uint8 m_client_version{};
|
||||||
uint8 pLFGFromLevel{};
|
uint8 m_lfg_from_level{};
|
||||||
uint8 pLFGToLevel{};
|
uint8 m_lfg_to_level{};
|
||||||
bool pLFGMatchFilter{};
|
bool m_lfg_match_filter{};
|
||||||
char pLFGComments[64]{};
|
char m_lfg_comments[64]{};
|
||||||
|
|
||||||
// Tell Queue -- really a vector :D
|
// Tell Queue -- really a vector :D
|
||||||
std::vector<ServerChannelMessage_Struct *> tell_queue;
|
std::vector<ServerChannelMessage_Struct *> m_tell_queue;
|
||||||
|
|
||||||
std::unique_ptr<ServerPacket> m_dz_invite;
|
std::unique_ptr<ServerPacket> m_dz_invite;
|
||||||
};
|
};
|
||||||
|
|||||||
+23
-5
@@ -331,8 +331,26 @@ void ClientList::SendCLEList(const int16& admin, const char* to, WorldTCPConnect
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ClientList::CLEAdd(uint32 iLSID, const char *iLoginServerName, const char* iLoginName, const char* iLoginKey, int16 iWorldAdmin, uint32 ip, uint8 local) {
|
void ClientList::CLEAdd(
|
||||||
auto tmp = new ClientListEntry(GetNextCLEID(), iLSID, iLoginServerName, iLoginName, iLoginKey, iWorldAdmin, ip, local);
|
uint32 login_server_id,
|
||||||
|
const char *login_server_name,
|
||||||
|
const char *login_name,
|
||||||
|
const char *login_key,
|
||||||
|
int16 world_admin,
|
||||||
|
uint32 ip_address,
|
||||||
|
uint8 is_local
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto tmp = new ClientListEntry(
|
||||||
|
GetNextCLEID(),
|
||||||
|
login_server_id,
|
||||||
|
login_server_name,
|
||||||
|
login_name,
|
||||||
|
login_key,
|
||||||
|
world_admin,
|
||||||
|
ip_address,
|
||||||
|
is_local
|
||||||
|
);
|
||||||
|
|
||||||
clientlist.Append(tmp);
|
clientlist.Append(tmp);
|
||||||
}
|
}
|
||||||
@@ -457,19 +475,19 @@ void ClientList::CLEKeepAlive(uint32 numupdates, uint32* wid) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientListEntry *ClientList::CheckAuth(uint32 iLSID, const char *iKey)
|
ClientListEntry *ClientList::CheckAuth(uint32 loginserver_account_id, const char *key)
|
||||||
{
|
{
|
||||||
LinkedListIterator<ClientListEntry *> iterator(clientlist);
|
LinkedListIterator<ClientListEntry *> iterator(clientlist);
|
||||||
|
|
||||||
iterator.Reset();
|
iterator.Reset();
|
||||||
while (iterator.MoreElements()) {
|
while (iterator.MoreElements()) {
|
||||||
if (iterator.GetData()->CheckAuth(iLSID, iKey)) {
|
if (iterator.GetData()->CheckAuth(loginserver_account_id, key)) {
|
||||||
return iterator.GetData();
|
return iterator.GetData();
|
||||||
}
|
}
|
||||||
iterator.Advance();
|
iterator.Advance();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientList::SendOnlineGuildMembers(uint32 FromID, uint32 GuildID)
|
void ClientList::SendOnlineGuildMembers(uint32 FromID, uint32 GuildID)
|
||||||
|
|||||||
+2
-2
@@ -51,7 +51,7 @@ public:
|
|||||||
|
|
||||||
void ClientUpdate(ZoneServer* zoneserver, ServerClientList_Struct* scl);
|
void ClientUpdate(ZoneServer* zoneserver, ServerClientList_Struct* scl);
|
||||||
void CLERemoveZSRef(ZoneServer* iZS);
|
void CLERemoveZSRef(ZoneServer* iZS);
|
||||||
ClientListEntry* CheckAuth(uint32 iLSID, const char* iKey);
|
ClientListEntry* CheckAuth(uint32 loginserver_account_id, const char* key);
|
||||||
ClientListEntry* FindCharacter(const char* name);
|
ClientListEntry* FindCharacter(const char* name);
|
||||||
ClientListEntry* FindCLEByAccountID(uint32 iAccID);
|
ClientListEntry* FindCLEByAccountID(uint32 iAccID);
|
||||||
ClientListEntry* FindCLEByCharacterID(uint32 iCharID);
|
ClientListEntry* FindCLEByCharacterID(uint32 iCharID);
|
||||||
@@ -59,7 +59,7 @@ public:
|
|||||||
void DisconnectByIP(uint32 in_ip);
|
void DisconnectByIP(uint32 in_ip);
|
||||||
void CLCheckStale();
|
void CLCheckStale();
|
||||||
void CLEKeepAlive(uint32 numupdates, uint32* wid);
|
void CLEKeepAlive(uint32 numupdates, uint32* wid);
|
||||||
void CLEAdd(uint32 iLSID, const char* iLoginServerName, const char* iLoginName, const char* iLoginKey, int16 iWorldAdmin = AccountStatus::Player, uint32 ip = 0, uint8 local=0);
|
void CLEAdd(uint32 login_server_id, const char* login_server_name, const char* login_name, const char* login_key, int16 world_admin = AccountStatus::Player, uint32 ip_address = 0, uint8 is_local=0);
|
||||||
void UpdateClientGuild(uint32 char_id, uint32 guild_id);
|
void UpdateClientGuild(uint32 char_id, uint32 guild_id);
|
||||||
bool IsAccountInGame(uint32 iLSID);
|
bool IsAccountInGame(uint32 iLSID);
|
||||||
|
|
||||||
|
|||||||
+38
-38
@@ -46,7 +46,7 @@ void LoginServer::ProcessUsertoWorldReqLeg(uint16_t opcode, EQ::Net::Packet &p)
|
|||||||
const WorldConfig *Config = WorldConfig::get();
|
const WorldConfig *Config = WorldConfig::get();
|
||||||
LogNetcode("Received ServerPacket from LS OpCode {:#04x}", opcode);
|
LogNetcode("Received ServerPacket from LS OpCode {:#04x}", opcode);
|
||||||
|
|
||||||
UsertoWorldRequestLegacy_Struct *utwr = (UsertoWorldRequestLegacy_Struct *) p.Data();
|
UsertoWorldRequestLegacy *utwr = (UsertoWorldRequestLegacy *) p.Data();
|
||||||
uint32 id = database.GetAccountIDFromLSID("eqemu", utwr->lsaccountid);
|
uint32 id = database.GetAccountIDFromLSID("eqemu", utwr->lsaccountid);
|
||||||
int16 status = database.GetAccountStatus(id);
|
int16 status = database.GetAccountStatus(id);
|
||||||
|
|
||||||
@@ -63,11 +63,11 @@ void LoginServer::ProcessUsertoWorldReqLeg(uint16_t opcode, EQ::Net::Packet &p)
|
|||||||
|
|
||||||
ServerPacket outpack;
|
ServerPacket outpack;
|
||||||
outpack.opcode = ServerOP_UsertoWorldRespLeg;
|
outpack.opcode = ServerOP_UsertoWorldRespLeg;
|
||||||
outpack.size = sizeof(UsertoWorldResponseLegacy_Struct);
|
outpack.size = sizeof(UsertoWorldResponseLegacy);
|
||||||
outpack.pBuffer = new uchar[outpack.size];
|
outpack.pBuffer = new uchar[outpack.size];
|
||||||
memset(outpack.pBuffer, 0, outpack.size);
|
memset(outpack.pBuffer, 0, outpack.size);
|
||||||
|
|
||||||
UsertoWorldResponseLegacy_Struct *utwrs = (UsertoWorldResponseLegacy_Struct *) outpack.pBuffer;
|
UsertoWorldResponseLegacy *utwrs = (UsertoWorldResponseLegacy *) outpack.pBuffer;
|
||||||
utwrs->lsaccountid = utwr->lsaccountid;
|
utwrs->lsaccountid = utwr->lsaccountid;
|
||||||
utwrs->ToID = utwr->FromID;
|
utwrs->ToID = utwr->FromID;
|
||||||
utwrs->worldid = utwr->worldid;
|
utwrs->worldid = utwr->worldid;
|
||||||
@@ -126,7 +126,7 @@ void LoginServer::ProcessUsertoWorldReq(uint16_t opcode, EQ::Net::Packet &p)
|
|||||||
const WorldConfig *Config = WorldConfig::get();
|
const WorldConfig *Config = WorldConfig::get();
|
||||||
LogNetcode("Received ServerPacket from LS OpCode {:#04x}", opcode);
|
LogNetcode("Received ServerPacket from LS OpCode {:#04x}", opcode);
|
||||||
|
|
||||||
UsertoWorldRequest_Struct *utwr = (UsertoWorldRequest_Struct *) p.Data();
|
UsertoWorldRequest *utwr = (UsertoWorldRequest *) p.Data();
|
||||||
uint32 id = database.GetAccountIDFromLSID(utwr->login, utwr->lsaccountid);
|
uint32 id = database.GetAccountIDFromLSID(utwr->login, utwr->lsaccountid);
|
||||||
int16 status = database.GetAccountStatus(id);
|
int16 status = database.GetAccountStatus(id);
|
||||||
|
|
||||||
@@ -143,11 +143,11 @@ void LoginServer::ProcessUsertoWorldReq(uint16_t opcode, EQ::Net::Packet &p)
|
|||||||
|
|
||||||
ServerPacket outpack;
|
ServerPacket outpack;
|
||||||
outpack.opcode = ServerOP_UsertoWorldResp;
|
outpack.opcode = ServerOP_UsertoWorldResp;
|
||||||
outpack.size = sizeof(UsertoWorldResponse_Struct);
|
outpack.size = sizeof(UsertoWorldResponse);
|
||||||
outpack.pBuffer = new uchar[outpack.size];
|
outpack.pBuffer = new uchar[outpack.size];
|
||||||
memset(outpack.pBuffer, 0, outpack.size);
|
memset(outpack.pBuffer, 0, outpack.size);
|
||||||
|
|
||||||
UsertoWorldResponse_Struct *utwrs = (UsertoWorldResponse_Struct *) outpack.pBuffer;
|
UsertoWorldResponse *utwrs = (UsertoWorldResponse *) outpack.pBuffer;
|
||||||
utwrs->lsaccountid = utwr->lsaccountid;
|
utwrs->lsaccountid = utwr->lsaccountid;
|
||||||
utwrs->ToID = utwr->FromID;
|
utwrs->ToID = utwr->FromID;
|
||||||
strn0cpy(utwrs->login, utwr->login, 64);
|
strn0cpy(utwrs->login, utwr->login, 64);
|
||||||
@@ -208,27 +208,27 @@ void LoginServer::ProcessLSClientAuthLegacy(uint16_t opcode, EQ::Net::Packet &p)
|
|||||||
LogNetcode("Received ServerPacket from LS OpCode {:#04x}", opcode);
|
LogNetcode("Received ServerPacket from LS OpCode {:#04x}", opcode);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto client_authentication_request = p.GetSerialize<ClientAuthLegacy_Struct>(0);
|
auto r = p.GetSerialize<ClientAuthLegacy>(0);
|
||||||
|
|
||||||
LogDebug(
|
LogDebug(
|
||||||
"Processing Loginserver Auth Legacy | account_id [{0}] account_name [{1}] key [{2}] admin [{3}] ip [{4}] "
|
"Processing Loginserver Auth Legacy | account_id [{}] account_name [{}] key [{}] admin [{}] ip [{}] "
|
||||||
"local_network [{5}]",
|
"local_network [{}]",
|
||||||
client_authentication_request.loginserver_account_id,
|
r.loginserver_account_id,
|
||||||
client_authentication_request.loginserver_account_name,
|
r.loginserver_account_name,
|
||||||
client_authentication_request.key,
|
r.key,
|
||||||
client_authentication_request.is_world_admin,
|
r.is_world_admin,
|
||||||
client_authentication_request.ip,
|
r.ip_address,
|
||||||
client_authentication_request.is_client_from_local_network
|
r.is_client_from_local_network
|
||||||
);
|
);
|
||||||
|
|
||||||
client_list.CLEAdd(
|
client_list.CLEAdd(
|
||||||
client_authentication_request.loginserver_account_id,
|
r.loginserver_account_id,
|
||||||
"eqemu",
|
"eqemu",
|
||||||
client_authentication_request.loginserver_account_name,
|
r.loginserver_account_name,
|
||||||
client_authentication_request.key,
|
r.key,
|
||||||
client_authentication_request.is_world_admin,
|
r.is_world_admin,
|
||||||
client_authentication_request.ip,
|
r.ip_address,
|
||||||
client_authentication_request.is_client_from_local_network
|
r.is_client_from_local_network
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
catch (std::exception &ex) {
|
catch (std::exception &ex) {
|
||||||
@@ -242,28 +242,28 @@ void LoginServer::ProcessLSClientAuth(uint16_t opcode, EQ::Net::Packet &p)
|
|||||||
LogNetcode("Received ServerPacket from LS OpCode {:#04x}", opcode);
|
LogNetcode("Received ServerPacket from LS OpCode {:#04x}", opcode);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto client_authentication_request = p.GetSerialize<ClientAuth_Struct>(0);
|
auto r = p.GetSerialize<ClientAuth>(0);
|
||||||
|
|
||||||
LogDebug(
|
LogDebug(
|
||||||
"Processing Loginserver Auth | account_id [{0}] account_name [{1}] loginserver_name [{2}] key [{3}] "
|
"Processing Loginserver Auth | account_id [{}] account_name [{}] loginserver_name [{}] key [{}] "
|
||||||
"admin [{4}] ip [{5}] local_network [{6}]",
|
"admin [{}] ip [{}] local_network [{}]",
|
||||||
client_authentication_request.loginserver_account_id,
|
r.loginserver_account_id,
|
||||||
client_authentication_request.account_name,
|
r.account_name,
|
||||||
client_authentication_request.loginserver_name,
|
r.loginserver_name,
|
||||||
client_authentication_request.key,
|
r.key,
|
||||||
client_authentication_request.is_world_admin,
|
r.is_world_admin,
|
||||||
client_authentication_request.ip,
|
r.ip_address,
|
||||||
client_authentication_request.is_client_from_local_network
|
r.is_client_from_local_network
|
||||||
);
|
);
|
||||||
|
|
||||||
client_list.CLEAdd(
|
client_list.CLEAdd(
|
||||||
client_authentication_request.loginserver_account_id,
|
r.loginserver_account_id,
|
||||||
client_authentication_request.loginserver_name,
|
r.loginserver_name,
|
||||||
client_authentication_request.account_name,
|
r.account_name,
|
||||||
client_authentication_request.key,
|
r.key,
|
||||||
client_authentication_request.is_world_admin,
|
r.is_world_admin,
|
||||||
client_authentication_request.ip,
|
r.ip_address,
|
||||||
client_authentication_request.is_client_from_local_network
|
r.is_client_from_local_network
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
catch (std::exception &ex) {
|
catch (std::exception &ex) {
|
||||||
|
|||||||
@@ -89,6 +89,7 @@
|
|||||||
#include "../common/events/player_event_logs.h"
|
#include "../common/events/player_event_logs.h"
|
||||||
#include "../common/skill_caps.h"
|
#include "../common/skill_caps.h"
|
||||||
#include "../common/repositories/character_parcels_repository.h"
|
#include "../common/repositories/character_parcels_repository.h"
|
||||||
|
#include "../common/ip_util.h"
|
||||||
|
|
||||||
SkillCaps skill_caps;
|
SkillCaps skill_caps;
|
||||||
ZoneStore zone_store;
|
ZoneStore zone_store;
|
||||||
@@ -188,6 +189,11 @@ int main(int argc, char **argv)
|
|||||||
launcher_list.LoadList();
|
launcher_list.LoadList();
|
||||||
zoneserver_list.Init();
|
zoneserver_list.Init();
|
||||||
|
|
||||||
|
if (IpUtil::IsPortInUse(Config->WorldIP, Config->WorldTCPPort)) {
|
||||||
|
LogError("World port [{}] already in use", Config->WorldTCPPort);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<EQ::Net::ConsoleServer> console;
|
std::unique_ptr<EQ::Net::ConsoleServer> console;
|
||||||
if (Config->TelnetEnabled) {
|
if (Config->TelnetEnabled) {
|
||||||
LogInfo("Console (TCP) listener started on [{}:{}]", Config->TelnetIP, Config->TelnetTCPPort);
|
LogInfo("Console (TCP) listener started on [{}:{}]", Config->TelnetIP, Config->TelnetTCPPort);
|
||||||
|
|||||||
@@ -101,6 +101,13 @@ bool WorldBoot::HandleCommandInput(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if we ran a valid command, this whole CLI handler needs to be improved at a later time
|
||||||
|
std::string arg1 = argc >= 2 ? argv[1] : "";
|
||||||
|
if (argc >= 2 && !Strings::Contains(arg1, ":")) {
|
||||||
|
std::cout << "Invalid command, use --help to see available commands" << std::endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,12 +35,6 @@ WorldDatabase content_db;
|
|||||||
extern std::vector<RaceClassAllocation> character_create_allocations;
|
extern std::vector<RaceClassAllocation> character_create_allocations;
|
||||||
extern std::vector<RaceClassCombos> character_create_race_class_combos;
|
extern std::vector<RaceClassCombos> character_create_race_class_combos;
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param account_id
|
|
||||||
* @param out_app
|
|
||||||
* @param client_version_bit
|
|
||||||
*/
|
|
||||||
void WorldDatabase::GetCharSelectInfo(uint32 account_id, EQApplicationPacket **out_app, uint32 client_version_bit)
|
void WorldDatabase::GetCharSelectInfo(uint32 account_id, EQApplicationPacket **out_app, uint32 client_version_bit)
|
||||||
{
|
{
|
||||||
EQ::versions::ClientVersion
|
EQ::versions::ClientVersion
|
||||||
|
|||||||
+2
-1
@@ -894,7 +894,8 @@ void ZSList::SendServerReload(ServerReload::Type type, uchar *packet)
|
|||||||
ServerReload::Type::Commands,
|
ServerReload::Type::Commands,
|
||||||
ServerReload::Type::PerlExportSettings,
|
ServerReload::Type::PerlExportSettings,
|
||||||
ServerReload::Type::DataBucketsCache,
|
ServerReload::Type::DataBucketsCache,
|
||||||
ServerReload::Type::WorldRepop
|
ServerReload::Type::WorldRepop,
|
||||||
|
ServerReload::Type::WorldWithRespawn
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set requires_zone_booted flag before executing reload logic
|
// Set requires_zone_booted flag before executing reload logic
|
||||||
|
|||||||
@@ -2789,6 +2789,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
|||||||
const uint16 entity_id = GetID();
|
const uint16 entity_id = GetID();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
(
|
||||||
!HasOwner() &&
|
!HasOwner() &&
|
||||||
!IsMerc() &&
|
!IsMerc() &&
|
||||||
!GetSwarmInfo() &&
|
!GetSwarmInfo() &&
|
||||||
@@ -2814,6 +2815,8 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
|||||||
killer_mob && is_ldon_treasure
|
killer_mob && is_ldon_treasure
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|| IsQueuedForCorpse()
|
||||||
) {
|
) {
|
||||||
if (killer) {
|
if (killer) {
|
||||||
if (killer->GetOwner() != 0 && killer->GetOwner()->IsClient()) {
|
if (killer->GetOwner() != 0 && killer->GetOwner()->IsClient()) {
|
||||||
|
|||||||
+89
-299
@@ -281,285 +281,103 @@ void Mob::AddItemBonuses(const EQ::ItemInstance* inst, StatBonuses* b, bool is_a
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_ammo_item) {
|
if (is_ammo_item) {
|
||||||
const auto recommended_level = is_augment ? recommended_level_override : inst->GetItemRecommendedLevel(true);
|
return;
|
||||||
|
|
||||||
if (IsNPC() || current_level >= recommended_level) {
|
|
||||||
b->HP += item->HP;
|
|
||||||
b->Mana += item->Mana;
|
|
||||||
b->Endurance += item->Endur;
|
|
||||||
|
|
||||||
b->AC += item->AC;
|
|
||||||
b->ATK += item->Attack;
|
|
||||||
|
|
||||||
b->STR += (item->AStr + item->HeroicStr);
|
|
||||||
b->STA += (item->ASta + item->HeroicSta);
|
|
||||||
b->DEX += (item->ADex + item->HeroicDex);
|
|
||||||
b->AGI += (item->AAgi + item->HeroicAgi);
|
|
||||||
b->INT += (item->AInt + item->HeroicInt);
|
|
||||||
b->WIS += (item->AWis + item->HeroicWis);
|
|
||||||
b->CHA += (item->ACha + item->HeroicCha);
|
|
||||||
|
|
||||||
b->MR += (item->MR + item->HeroicMR);
|
|
||||||
b->FR += (item->FR + item->HeroicFR);
|
|
||||||
b->CR += (item->CR + item->HeroicCR);
|
|
||||||
b->PR += (item->PR + item->HeroicPR);
|
|
||||||
b->DR += (item->DR + item->HeroicDR);
|
|
||||||
b->Corrup += (item->SVCorruption + item->HeroicSVCorrup);
|
|
||||||
|
|
||||||
b->STRCapMod += item->HeroicStr;
|
|
||||||
b->STACapMod += item->HeroicSta;
|
|
||||||
b->DEXCapMod += item->HeroicDex;
|
|
||||||
b->AGICapMod += item->HeroicAgi;
|
|
||||||
b->INTCapMod += item->HeroicInt;
|
|
||||||
b->WISCapMod += item->HeroicWis;
|
|
||||||
b->CHACapMod += item->HeroicCha;
|
|
||||||
|
|
||||||
b->MRCapMod += item->HeroicMR;
|
|
||||||
b->CRCapMod += item->HeroicFR;
|
|
||||||
b->FRCapMod += item->HeroicCR;
|
|
||||||
b->PRCapMod += item->HeroicPR;
|
|
||||||
b->DRCapMod += item->HeroicDR;
|
|
||||||
b->CorrupCapMod += item->HeroicSVCorrup;
|
|
||||||
|
|
||||||
b->HeroicSTR += item->HeroicStr;
|
|
||||||
b->HeroicSTA += item->HeroicSta;
|
|
||||||
b->HeroicDEX += item->HeroicDex;
|
|
||||||
b->HeroicAGI += item->HeroicAgi;
|
|
||||||
b->HeroicINT += item->HeroicInt;
|
|
||||||
b->HeroicWIS += item->HeroicWis;
|
|
||||||
b->HeroicCHA += item->HeroicCha;
|
|
||||||
|
|
||||||
b->HeroicMR += item->HeroicMR;
|
|
||||||
b->HeroicFR += item->HeroicFR;
|
|
||||||
b->HeroicCR += item->HeroicCR;
|
|
||||||
b->HeroicPR += item->HeroicPR;
|
|
||||||
b->HeroicDR += item->HeroicDR;
|
|
||||||
b->HeroicCorrup += item->HeroicSVCorrup;
|
|
||||||
} else {
|
|
||||||
b->HP += CalcRecommendedLevelBonus(current_level, recommended_level, item->HP);
|
|
||||||
b->Mana += CalcRecommendedLevelBonus(current_level, recommended_level, item->Mana);
|
|
||||||
b->Endurance += CalcRecommendedLevelBonus(current_level, recommended_level, item->Endur);
|
|
||||||
|
|
||||||
b->AC += CalcRecommendedLevelBonus(current_level, recommended_level, item->AC);
|
|
||||||
b->ATK += CalcRecommendedLevelBonus(current_level, recommended_level, item->Attack);
|
|
||||||
|
|
||||||
b->STR += CalcRecommendedLevelBonus(current_level, recommended_level, (item->AStr + item->HeroicStr));
|
|
||||||
b->STA += CalcRecommendedLevelBonus(current_level, recommended_level, (item->ASta + item->HeroicSta));
|
|
||||||
b->DEX += CalcRecommendedLevelBonus(current_level, recommended_level, (item->ADex + item->HeroicDex));
|
|
||||||
b->AGI += CalcRecommendedLevelBonus(current_level, recommended_level, (item->AAgi + item->HeroicAgi));
|
|
||||||
b->INT += CalcRecommendedLevelBonus(current_level, recommended_level, (item->AInt + item->HeroicInt));
|
|
||||||
b->WIS += CalcRecommendedLevelBonus(current_level, recommended_level, (item->AWis + item->HeroicWis));
|
|
||||||
b->CHA += CalcRecommendedLevelBonus(current_level, recommended_level, (item->ACha + item->HeroicCha));
|
|
||||||
|
|
||||||
b->MR += CalcRecommendedLevelBonus(current_level, recommended_level, (item->MR + item->HeroicMR));
|
|
||||||
b->FR += CalcRecommendedLevelBonus(current_level, recommended_level, (item->FR + item->HeroicFR));
|
|
||||||
b->CR += CalcRecommendedLevelBonus(current_level, recommended_level, (item->CR + item->HeroicCR));
|
|
||||||
b->PR += CalcRecommendedLevelBonus(current_level, recommended_level, (item->PR + item->HeroicPR));
|
|
||||||
b->DR += CalcRecommendedLevelBonus(current_level, recommended_level, (item->DR + item->HeroicDR));
|
|
||||||
b->Corrup += CalcRecommendedLevelBonus(current_level, recommended_level, (item->SVCorruption + item->HeroicSVCorrup));
|
|
||||||
|
|
||||||
b->STRCapMod += CalcRecommendedLevelBonus(current_level, recommended_level, item->HeroicStr);
|
|
||||||
b->STACapMod += CalcRecommendedLevelBonus(current_level, recommended_level, item->HeroicSta);
|
|
||||||
b->DEXCapMod += CalcRecommendedLevelBonus(current_level, recommended_level, item->HeroicDex);
|
|
||||||
b->AGICapMod += CalcRecommendedLevelBonus(current_level, recommended_level, item->HeroicAgi);
|
|
||||||
b->INTCapMod += CalcRecommendedLevelBonus(current_level, recommended_level, item->HeroicInt);
|
|
||||||
b->WISCapMod += CalcRecommendedLevelBonus(current_level, recommended_level, item->HeroicWis);
|
|
||||||
b->CHACapMod += CalcRecommendedLevelBonus(current_level, recommended_level, item->HeroicCha);
|
|
||||||
|
|
||||||
b->MRCapMod += CalcRecommendedLevelBonus(current_level, recommended_level, item->HeroicMR);
|
|
||||||
b->CRCapMod += CalcRecommendedLevelBonus(current_level, recommended_level, item->HeroicFR);
|
|
||||||
b->FRCapMod += CalcRecommendedLevelBonus(current_level, recommended_level, item->HeroicCR);
|
|
||||||
b->PRCapMod += CalcRecommendedLevelBonus(current_level, recommended_level, item->HeroicPR);
|
|
||||||
b->DRCapMod += CalcRecommendedLevelBonus(current_level, recommended_level, item->HeroicDR);
|
|
||||||
b->CorrupCapMod += CalcRecommendedLevelBonus(current_level, recommended_level, item->HeroicSVCorrup);
|
|
||||||
|
|
||||||
b->HeroicSTR += CalcRecommendedLevelBonus(current_level, recommended_level, item->HeroicStr);
|
|
||||||
b->HeroicSTA += CalcRecommendedLevelBonus(current_level, recommended_level, item->HeroicSta);
|
|
||||||
b->HeroicDEX += CalcRecommendedLevelBonus(current_level, recommended_level, item->HeroicDex);
|
|
||||||
b->HeroicAGI += CalcRecommendedLevelBonus(current_level, recommended_level, item->HeroicAgi);
|
|
||||||
b->HeroicINT += CalcRecommendedLevelBonus(current_level, recommended_level, item->HeroicInt);
|
|
||||||
b->HeroicWIS += CalcRecommendedLevelBonus(current_level, recommended_level, item->HeroicWis);
|
|
||||||
b->HeroicCHA += CalcRecommendedLevelBonus(current_level, recommended_level, item->HeroicCha);
|
|
||||||
|
|
||||||
b->HeroicMR += CalcRecommendedLevelBonus(current_level, recommended_level, item->HeroicMR);
|
|
||||||
b->HeroicFR += CalcRecommendedLevelBonus(current_level, recommended_level, item->HeroicFR);
|
|
||||||
b->HeroicCR += CalcRecommendedLevelBonus(current_level, recommended_level, item->HeroicCR);
|
|
||||||
b->HeroicPR += CalcRecommendedLevelBonus(current_level, recommended_level, item->HeroicPR);
|
|
||||||
b->HeroicDR += CalcRecommendedLevelBonus(current_level, recommended_level, item->HeroicDR);
|
|
||||||
b->HeroicCorrup += CalcRecommendedLevelBonus(current_level, recommended_level, item->HeroicSVCorrup);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto recommended_level = is_augment ? recommended_level_override : inst->GetItemRecommendedLevel(true);
|
||||||
|
const bool meets_recommended = (IsNPC() && !RuleB(Items, NPCUseRecommendedLevels)) || current_level >= recommended_level;
|
||||||
|
|
||||||
|
auto CalcItemBonus = [&](int statValue) -> int {
|
||||||
|
return meets_recommended ? statValue : CalcRecommendedLevelBonus(current_level, recommended_level, statValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto CalcCappedItemBonus = [&](int currentStat, int bonus, int cap) -> int {
|
||||||
|
int calc_stat = currentStat + CalcItemBonus(bonus);
|
||||||
|
return IsOfClientBotMerc() ? std::min(cap, calc_stat) : calc_stat;
|
||||||
|
};
|
||||||
|
|
||||||
|
b->HP += CalcItemBonus(item->HP);
|
||||||
|
b->Mana += CalcItemBonus(item->Mana);
|
||||||
|
b->Endurance += CalcItemBonus(item->Endur);
|
||||||
|
b->AC += CalcItemBonus(item->AC);
|
||||||
|
|
||||||
|
b->STR += CalcItemBonus(item->AStr + item->HeroicStr);
|
||||||
|
b->STA += CalcItemBonus(item->ASta + item->HeroicSta);
|
||||||
|
b->DEX += CalcItemBonus(item->ADex + item->HeroicDex);
|
||||||
|
b->AGI += CalcItemBonus(item->AAgi + item->HeroicAgi);
|
||||||
|
b->INT += CalcItemBonus(item->AInt + item->HeroicInt);
|
||||||
|
b->WIS += CalcItemBonus(item->AWis + item->HeroicWis);
|
||||||
|
b->CHA += CalcItemBonus(item->ACha + item->HeroicCha);
|
||||||
|
|
||||||
|
b->HeroicSTR += CalcItemBonus(item->HeroicStr);
|
||||||
|
b->HeroicSTA += CalcItemBonus(item->HeroicSta);
|
||||||
|
b->HeroicDEX += CalcItemBonus(item->HeroicDex);
|
||||||
|
b->HeroicAGI += CalcItemBonus(item->HeroicAgi);
|
||||||
|
b->HeroicINT += CalcItemBonus(item->HeroicInt);
|
||||||
|
b->HeroicWIS += CalcItemBonus(item->HeroicWis);
|
||||||
|
b->HeroicCHA += CalcItemBonus(item->HeroicCha);
|
||||||
|
|
||||||
|
b->STRCapMod += b->HeroicSTR;
|
||||||
|
b->STACapMod += b->HeroicSTA;
|
||||||
|
b->DEXCapMod += b->HeroicDEX;
|
||||||
|
b->AGICapMod += b->HeroicAGI;
|
||||||
|
b->INTCapMod += b->HeroicINT;
|
||||||
|
b->WISCapMod += b->HeroicWIS;
|
||||||
|
b->CHACapMod += b->HeroicCHA;
|
||||||
|
|
||||||
|
b->MR += CalcItemBonus(item->MR + item->HeroicMR);
|
||||||
|
b->FR += CalcItemBonus(item->FR + item->HeroicFR);
|
||||||
|
b->CR += CalcItemBonus(item->CR + item->HeroicCR);
|
||||||
|
b->PR += CalcItemBonus(item->PR + item->HeroicPR);
|
||||||
|
b->DR += CalcItemBonus(item->DR + item->HeroicDR);
|
||||||
|
b->Corrup += CalcItemBonus(item->SVCorruption + item->HeroicSVCorrup);
|
||||||
|
|
||||||
|
b->HeroicMR += CalcItemBonus(item->HeroicMR);
|
||||||
|
b->HeroicFR += CalcItemBonus(item->HeroicFR);
|
||||||
|
b->HeroicCR += CalcItemBonus(item->HeroicCR);
|
||||||
|
b->HeroicPR += CalcItemBonus(item->HeroicPR);
|
||||||
|
b->HeroicDR += CalcItemBonus(item->HeroicDR);
|
||||||
|
b->HeroicCorrup += CalcItemBonus(item->HeroicSVCorrup);
|
||||||
|
|
||||||
|
b->MRCapMod += b->HeroicMR;
|
||||||
|
b->FRCapMod += b->HeroicFR;
|
||||||
|
b->CRCapMod += b->HeroicCR;
|
||||||
|
b->PRCapMod += b->HeroicPR;
|
||||||
|
b->DRCapMod += b->HeroicDR;
|
||||||
|
b->CorrupCapMod += b->HeroicCorrup;
|
||||||
|
|
||||||
|
b->HPRegen += CalcItemBonus(item->Regen);
|
||||||
|
b->ManaRegen += CalcItemBonus(item->ManaRegen);
|
||||||
|
b->EnduranceRegen += CalcItemBonus(item->EnduranceRegen);
|
||||||
|
|
||||||
|
// These have rule-configured caps.
|
||||||
|
b->ATK = CalcCappedItemBonus(b->ATK, item->Attack, RuleI(Character, ItemATKCap) + itembonuses.ItemATKCap + spellbonuses.ItemATKCap + aabonuses.ItemATKCap);
|
||||||
|
b->DamageShield = CalcCappedItemBonus(b->DamageShield, item->DamageShield, RuleI(Character, ItemDamageShieldCap));
|
||||||
|
b->SpellShield = CalcCappedItemBonus(b->SpellShield, item->SpellShield, RuleI(Character, ItemSpellShieldingCap));
|
||||||
|
b->MeleeMitigation = CalcCappedItemBonus(b->MeleeMitigation, item->Shielding, RuleI(Character, ItemShieldingCap));
|
||||||
|
b->StunResist = CalcCappedItemBonus(b->StunResist, item->StunResist, RuleI(Character, ItemStunResistCap));
|
||||||
|
b->StrikeThrough = CalcCappedItemBonus(b->StrikeThrough, item->StrikeThrough, RuleI(Character, ItemStrikethroughCap));
|
||||||
|
b->AvoidMeleeChance = CalcCappedItemBonus(b->AvoidMeleeChance, item->Avoidance, RuleI(Character, ItemAvoidanceCap));
|
||||||
|
b->HitChance = CalcCappedItemBonus(b->HitChance, item->Accuracy, RuleI(Character, ItemAccuracyCap));
|
||||||
|
b->ProcChance = CalcCappedItemBonus(b->ProcChance, item->CombatEffects, RuleI(Character, ItemCombatEffectsCap));
|
||||||
|
b->DoTShielding = CalcCappedItemBonus(b->DoTShielding, item->DotShielding, RuleI(Character, ItemDoTShieldingCap));
|
||||||
|
b->HealAmt = CalcCappedItemBonus(b->HealAmt, item->HealAmt, RuleI(Character, ItemHealAmtCap));
|
||||||
|
b->SpellDmg = CalcCappedItemBonus(b->SpellDmg, item->SpellDmg, RuleI(Character, ItemSpellDmgCap));
|
||||||
|
b->Clairvoyance = CalcCappedItemBonus(b->Clairvoyance, item->Clairvoyance, RuleI(Character, ItemClairvoyanceCap));
|
||||||
|
b->DSMitigation = CalcCappedItemBonus(b->DSMitigation, item->DSMitigation, RuleI(Character, ItemDSMitigationCap));
|
||||||
|
|
||||||
if (b->haste < item->Haste) {
|
if (b->haste < item->Haste) {
|
||||||
b->haste = item->Haste;
|
b->haste = item->Haste;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item->Regen != 0) {
|
if (item->ExtraDmgAmt != 0 && item->ExtraDmgSkill <= EQ::skills::HIGHEST_SKILL) {
|
||||||
b->HPRegen += item->Regen;
|
if (item->ExtraDmgSkill == ALL_SKILLS) {
|
||||||
|
for (const auto &skill_id: EQ::skills::GetExtraDamageSkills()) {
|
||||||
|
b->SkillDamageAmount[skill_id] = CalcCappedItemBonus(b->SkillDamageAmount[skill_id], item->ExtraDmgAmt, RuleI(Character, ItemExtraDmgCap));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item->ManaRegen != 0) {
|
|
||||||
b->ManaRegen += item->ManaRegen;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item->EnduranceRegen != 0) {
|
|
||||||
b->EnduranceRegen += item->EnduranceRegen;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item->Attack != 0) {
|
|
||||||
unsigned int cap = RuleI(Character, ItemATKCap);
|
|
||||||
cap += itembonuses.ItemATKCap + spellbonuses.ItemATKCap + aabonuses.ItemATKCap;
|
|
||||||
|
|
||||||
if (
|
|
||||||
IsOfClientBotMerc() &&
|
|
||||||
(b->ATK + item->Attack) > cap
|
|
||||||
) {
|
|
||||||
b->ATK = RuleI(Character, ItemATKCap);
|
|
||||||
} else {
|
} else {
|
||||||
b->ATK += item->Attack;
|
b->SkillDamageAmount[item->ExtraDmgSkill] = CalcCappedItemBonus(b->SkillDamageAmount[item->ExtraDmgSkill], item->ExtraDmgAmt, RuleI(Character, ItemExtraDmgCap));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item->DamageShield != 0) {
|
|
||||||
if (
|
|
||||||
IsOfClientBotMerc() &&
|
|
||||||
(b->DamageShield + item->DamageShield) > RuleI(Character, ItemDamageShieldCap)
|
|
||||||
) {
|
|
||||||
b->DamageShield = RuleI(Character, ItemDamageShieldCap);
|
|
||||||
} else {
|
|
||||||
b->DamageShield += item->DamageShield;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item->SpellShield != 0) {
|
|
||||||
if (
|
|
||||||
IsOfClientBotMerc() &&
|
|
||||||
(b->SpellShield + item->SpellShield) > RuleI(Character, ItemSpellShieldingCap)
|
|
||||||
) {
|
|
||||||
b->SpellShield = RuleI(Character, ItemSpellShieldingCap);
|
|
||||||
} else {
|
|
||||||
b->SpellShield += item->SpellShield;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item->Shielding != 0) {
|
|
||||||
if (
|
|
||||||
IsOfClientBotMerc() &&
|
|
||||||
(b->MeleeMitigation + item->Shielding) > RuleI(Character, ItemShieldingCap)
|
|
||||||
) {
|
|
||||||
b->MeleeMitigation = RuleI(Character, ItemShieldingCap);
|
|
||||||
} else {
|
|
||||||
b->MeleeMitigation += item->Shielding;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item->StunResist != 0) {
|
|
||||||
if (
|
|
||||||
IsOfClientBotMerc() &&
|
|
||||||
(b->StunResist + item->StunResist) > RuleI(Character, ItemStunResistCap)
|
|
||||||
) {
|
|
||||||
b->StunResist = RuleI(Character, ItemStunResistCap);
|
|
||||||
} else {
|
|
||||||
b->StunResist += item->StunResist;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item->StrikeThrough != 0) {
|
|
||||||
if (
|
|
||||||
IsOfClientBotMerc() &&
|
|
||||||
(b->StrikeThrough + item->StrikeThrough) > RuleI(Character, ItemStrikethroughCap)
|
|
||||||
) {
|
|
||||||
b->StrikeThrough = RuleI(Character, ItemStrikethroughCap);
|
|
||||||
} else {
|
|
||||||
b->StrikeThrough += item->StrikeThrough;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item->Avoidance != 0) {
|
|
||||||
if (
|
|
||||||
IsOfClientBotMerc() &&
|
|
||||||
(b->AvoidMeleeChance + item->Avoidance) > RuleI(Character, ItemAvoidanceCap)
|
|
||||||
) {
|
|
||||||
b->AvoidMeleeChance = RuleI(Character, ItemAvoidanceCap);
|
|
||||||
} else {
|
|
||||||
b->AvoidMeleeChance += item->Avoidance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item->Accuracy != 0) {
|
|
||||||
if (
|
|
||||||
IsOfClientBotMerc() &&
|
|
||||||
(b->HitChance + item->Accuracy) > RuleI(Character, ItemAccuracyCap)
|
|
||||||
) {
|
|
||||||
b->HitChance = RuleI(Character, ItemAccuracyCap);
|
|
||||||
} else {
|
|
||||||
b->HitChance += item->Accuracy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item->CombatEffects != 0) {
|
|
||||||
if (
|
|
||||||
IsOfClientBotMerc() &&
|
|
||||||
(b->ProcChance + item->CombatEffects) > RuleI(Character, ItemCombatEffectsCap)
|
|
||||||
) {
|
|
||||||
b->ProcChance = RuleI(Character, ItemCombatEffectsCap);
|
|
||||||
} else {
|
|
||||||
b->ProcChance += item->CombatEffects;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item->DotShielding != 0) {
|
|
||||||
if (
|
|
||||||
IsOfClientBotMerc() &&
|
|
||||||
(b->DoTShielding + item->DotShielding) > RuleI(Character, ItemDoTShieldingCap)
|
|
||||||
) {
|
|
||||||
b->DoTShielding = RuleI(Character, ItemDoTShieldingCap);
|
|
||||||
} else {
|
|
||||||
b->DoTShielding += item->DotShielding;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item->HealAmt != 0) {
|
|
||||||
if (
|
|
||||||
IsOfClientBotMerc() &&
|
|
||||||
(b->HealAmt + item->HealAmt) > RuleI(Character, ItemHealAmtCap)
|
|
||||||
) {
|
|
||||||
b->HealAmt = RuleI(Character, ItemHealAmtCap);
|
|
||||||
} else {
|
|
||||||
b->HealAmt += item->HealAmt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item->SpellDmg != 0) {
|
|
||||||
if (
|
|
||||||
IsOfClientBotMerc() &&
|
|
||||||
(b->SpellDmg + item->SpellDmg) > RuleI(Character, ItemSpellDmgCap)
|
|
||||||
) {
|
|
||||||
b->SpellDmg = RuleI(Character, ItemSpellDmgCap);
|
|
||||||
} else {
|
|
||||||
b->SpellDmg += item->SpellDmg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item->Clairvoyance != 0) {
|
|
||||||
if (
|
|
||||||
IsOfClientBotMerc() &&
|
|
||||||
(b->Clairvoyance + item->Clairvoyance) > RuleI(Character, ItemClairvoyanceCap)
|
|
||||||
) {
|
|
||||||
b->Clairvoyance = RuleI(Character, ItemClairvoyanceCap);
|
|
||||||
} else {
|
|
||||||
b->Clairvoyance += item->Clairvoyance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item->DSMitigation != 0) {
|
|
||||||
if (
|
|
||||||
IsOfClientBotMerc() &&
|
|
||||||
(b->DSMitigation + item->DSMitigation) > RuleI(Character, ItemDSMitigationCap)
|
|
||||||
) {
|
|
||||||
b->DSMitigation = RuleI(Character, ItemDSMitigationCap);
|
|
||||||
} else {
|
|
||||||
b->DSMitigation += item->DSMitigation;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -678,32 +496,6 @@ void Mob::AddItemBonuses(const EQ::ItemInstance* inst, StatBonuses* b, bool is_a
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item->ExtraDmgAmt != 0 && item->ExtraDmgSkill <= EQ::skills::HIGHEST_SKILL) {
|
|
||||||
if (item->ExtraDmgSkill == ALL_SKILLS) {
|
|
||||||
for (const auto& skill_id : EQ::skills::GetExtraDamageSkills()) {
|
|
||||||
if (
|
|
||||||
!IsNPC() &&
|
|
||||||
RuleI(Character, ItemExtraDmgCap) >= 0 &&
|
|
||||||
(b->SkillDamageAmount[skill_id] + item->ExtraDmgAmt) > RuleI(Character, ItemExtraDmgCap)
|
|
||||||
) {
|
|
||||||
b->SkillDamageAmount[skill_id] = RuleI(Character, ItemExtraDmgCap);
|
|
||||||
} else {
|
|
||||||
b->SkillDamageAmount[skill_id] += item->ExtraDmgAmt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (
|
|
||||||
!IsNPC() &&
|
|
||||||
RuleI(Character, ItemExtraDmgCap) >= 0 &&
|
|
||||||
(b->SkillDamageAmount[item->ExtraDmgSkill] + item->ExtraDmgAmt) > RuleI(Character, ItemExtraDmgCap)
|
|
||||||
) {
|
|
||||||
b->SkillDamageAmount[item->ExtraDmgSkill] = RuleI(Character, ItemExtraDmgCap);
|
|
||||||
} else {
|
|
||||||
b->SkillDamageAmount[item->ExtraDmgSkill] += item->ExtraDmgAmt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_augment) {
|
if (!is_augment) {
|
||||||
for (int i = EQ::invaug::SOCKET_BEGIN; i <= EQ::invaug::SOCKET_END; i++) {
|
for (int i = EQ::invaug::SOCKET_BEGIN; i <= EQ::invaug::SOCKET_END; i++) {
|
||||||
const auto* augment = inst->GetAugment(i);
|
const auto* augment = inst->GetAugment(i);
|
||||||
@@ -715,8 +507,6 @@ void Mob::AddItemBonuses(const EQ::ItemInstance* inst, StatBonuses* b, bool is_a
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Mob::AdditiveWornBonuses(const EQ::ItemInstance* inst, StatBonuses* b, bool is_augment) {
|
void Mob::AdditiveWornBonuses(const EQ::ItemInstance* inst, StatBonuses* b, bool is_augment) {
|
||||||
/*
|
/*
|
||||||
|
|||||||
+2
-2
@@ -3728,7 +3728,7 @@ bool Bot::Spawn(Client* botCharacterOwner) {
|
|||||||
SetVerifiedRaid(true);
|
SetVerifiedRaid(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (auto group = entity_list.GetGroupByMob(this)) {
|
else if (auto group = entity_list.GetGroupByMobName(GetName())) {
|
||||||
// Safety Check to confirm we have a valid group
|
// Safety Check to confirm we have a valid group
|
||||||
auto owner = GetBotOwner();
|
auto owner = GetBotOwner();
|
||||||
if (owner && !group->IsGroupMember(owner->GetCleanName())) {
|
if (owner && !group->IsGroupMember(owner->GetCleanName())) {
|
||||||
@@ -3744,7 +3744,7 @@ bool Bot::Spawn(Client* botCharacterOwner) {
|
|||||||
|
|
||||||
if (RuleB(Bots, RunSpellTypeChecksOnSpawn)) {
|
if (RuleB(Bots, RunSpellTypeChecksOnSpawn)) {
|
||||||
OwnerMessage("Running SpellType checks. There may be some spells that are mislabeled as incorrect. Use this as a loose guideline.");
|
OwnerMessage("Running SpellType checks. There may be some spells that are mislabeled as incorrect. Use this as a loose guideline.");
|
||||||
CheckBotSpells(); //This runs through a serious of checks and outputs any spells that are set to the wrong spell type in the database
|
CheckBotSpells(); //This runs through a series of checks and outputs any spells that are set to the wrong spell type in the database
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsBotRanged()) {
|
if (IsBotRanged()) {
|
||||||
|
|||||||
+52
-19
@@ -708,6 +708,9 @@ Client::Client(EQStreamInterface *ieqs) : Mob(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Client::~Client() {
|
Client::~Client() {
|
||||||
|
entity_list.RemoveMobFromCloseLists(this);
|
||||||
|
m_close_mobs.clear();
|
||||||
|
|
||||||
if (ClientVersion() == EQ::versions::ClientVersion::RoF2 && RuleB (Parcel, EnableParcelMerchants)) {
|
if (ClientVersion() == EQ::versions::ClientVersion::RoF2 && RuleB (Parcel, EnableParcelMerchants)) {
|
||||||
DoParcelCancel();
|
DoParcelCancel();
|
||||||
}
|
}
|
||||||
@@ -965,6 +968,10 @@ bool Client::SaveAA()
|
|||||||
|
|
||||||
m_pp.aapoints_spent = aa_points_spent + m_epp.expended_aa;
|
m_pp.aapoints_spent = aa_points_spent + m_epp.expended_aa;
|
||||||
|
|
||||||
|
if (v.empty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return CharacterAlternateAbilitiesRepository::ReplaceMany(database, v);
|
return CharacterAlternateAbilitiesRepository::ReplaceMany(database, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4622,7 +4629,7 @@ void Client::KeyRingLoad()
|
|||||||
const auto &l = KeyringRepository::GetWhere(
|
const auto &l = KeyringRepository::GetWhere(
|
||||||
database,
|
database,
|
||||||
fmt::format(
|
fmt::format(
|
||||||
"`char_id` = {} ORDER BY `item_id`",
|
"`char_id` = {} ORDER BY `item_id` ASC",
|
||||||
character_id
|
character_id
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -4631,21 +4638,15 @@ void Client::KeyRingLoad()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (const auto& e : l) {
|
for (const auto& e : l) {
|
||||||
keyring.emplace_back(e.item_id);
|
keyring.emplace_back(e.item_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::KeyRingAdd(uint32 item_id)
|
bool Client::KeyRingAdd(uint32 item_id)
|
||||||
{
|
{
|
||||||
if (!item_id) {
|
if (!item_id || KeyRingCheck(item_id)) {
|
||||||
return;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
const bool found = KeyRingCheck(item_id);
|
|
||||||
if (found) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto e = KeyringRepository::NewEntity();
|
auto e = KeyringRepository::NewEntity();
|
||||||
@@ -4656,14 +4657,14 @@ void Client::KeyRingAdd(uint32 item_id)
|
|||||||
e = KeyringRepository::InsertOne(database, e);
|
e = KeyringRepository::InsertOne(database, e);
|
||||||
|
|
||||||
if (!e.id) {
|
if (!e.id) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
keyring.emplace_back(item_id);
|
keyring.emplace_back(item_id);
|
||||||
|
|
||||||
if (!RuleB(World, UseItemLinksForKeyRing)) {
|
if (!RuleB(World, UseItemLinksForKeyRing)) {
|
||||||
Message(Chat::LightBlue, "Added to keyring.");
|
Message(Chat::LightBlue, "Added to keyring.");
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string &item_link = database.CreateItemLink(item_id);
|
const std::string &item_link = database.CreateItemLink(item_id);
|
||||||
@@ -4675,17 +4676,25 @@ void Client::KeyRingAdd(uint32 item_id)
|
|||||||
item_link
|
item_link
|
||||||
).c_str()
|
).c_str()
|
||||||
);
|
);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Client::KeyRingCheck(uint32 item_id)
|
bool Client::KeyRingCheck(uint32 item_id)
|
||||||
{
|
{
|
||||||
for (const auto &e : keyring) {
|
return std::find(keyring.begin(), keyring.end(), item_id) != keyring.end();
|
||||||
if (e == item_id) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
bool Client::KeyRingClear()
|
||||||
|
{
|
||||||
|
keyring.clear();
|
||||||
|
|
||||||
|
return KeyringRepository::DeleteWhere(
|
||||||
|
database,
|
||||||
|
fmt::format(
|
||||||
|
"`char_id` = {}",
|
||||||
|
CharacterID()
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::KeyRingList()
|
void Client::KeyRingList()
|
||||||
@@ -4694,16 +4703,40 @@ void Client::KeyRingList()
|
|||||||
|
|
||||||
const EQ::ItemData *item = nullptr;
|
const EQ::ItemData *item = nullptr;
|
||||||
|
|
||||||
for (const auto &e : keyring) {
|
for (const uint32& e : keyring) {
|
||||||
item = database.GetItem(e);
|
item = database.GetItem(e);
|
||||||
if (item) {
|
if (item) {
|
||||||
const std::string &item_string = RuleB(World, UseItemLinksForKeyRing) ? database.CreateItemLink(e) : item->Name;
|
const std::string& item_string = (
|
||||||
|
RuleB(World, UseItemLinksForKeyRing) ?
|
||||||
|
database.CreateItemLink(e) :
|
||||||
|
item->Name
|
||||||
|
);
|
||||||
|
|
||||||
Message(Chat::LightBlue, item_string.c_str());
|
Message(Chat::LightBlue, item_string.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Client::KeyRingRemove(uint32 item_id)
|
||||||
|
{
|
||||||
|
keyring.erase(
|
||||||
|
std::remove(
|
||||||
|
keyring.begin(),
|
||||||
|
keyring.end(),
|
||||||
|
item_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return KeyringRepository::DeleteWhere(
|
||||||
|
database,
|
||||||
|
fmt::format(
|
||||||
|
"`char_id` = {} AND `item_id` = {}",
|
||||||
|
CharacterID(),
|
||||||
|
item_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
bool Client::IsPetNameChangeAllowed() {
|
bool Client::IsPetNameChangeAllowed() {
|
||||||
if (RuleB(Pets, AlwaysAllowPetRename)) {
|
if (RuleB(Pets, AlwaysAllowPetRename)) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
+33
-3
@@ -327,8 +327,10 @@ public:
|
|||||||
// void TraderPriceUpdate(const EQApplicationPacket *app);
|
// void TraderPriceUpdate(const EQApplicationPacket *app);
|
||||||
uint8 WithCustomer(uint16 NewCustomer);
|
uint8 WithCustomer(uint16 NewCustomer);
|
||||||
void KeyRingLoad();
|
void KeyRingLoad();
|
||||||
void KeyRingAdd(uint32 item_id);
|
bool KeyRingAdd(uint32 item_id);
|
||||||
bool KeyRingCheck(uint32 item_id);
|
bool KeyRingCheck(uint32 item_id);
|
||||||
|
bool KeyRingClear();
|
||||||
|
bool KeyRingRemove(uint32 item_id);
|
||||||
void KeyRingList();
|
void KeyRingList();
|
||||||
bool IsPetNameChangeAllowed();
|
bool IsPetNameChangeAllowed();
|
||||||
void GrantPetNameChange();
|
void GrantPetNameChange();
|
||||||
@@ -1289,6 +1291,29 @@ public:
|
|||||||
void SendSpellTypePrompts(bool commanded_types = false, bool client_only_types = false);
|
void SendSpellTypePrompts(bool commanded_types = false, bool client_only_types = false);
|
||||||
|
|
||||||
// Task System Methods
|
// Task System Methods
|
||||||
|
inline void LoadClientSharedCompletedTasks()
|
||||||
|
{
|
||||||
|
std::string query = fmt::format(R"(
|
||||||
|
SELECT
|
||||||
|
cst.task_id
|
||||||
|
FROM completed_shared_task_members cstm
|
||||||
|
JOIN completed_shared_tasks cst ON cstm.shared_task_id = cst.id
|
||||||
|
WHERE cstm.character_id = {}
|
||||||
|
GROUP BY cst.task_id;
|
||||||
|
)", CharacterID());
|
||||||
|
|
||||||
|
auto results = database.QueryDatabase(query);
|
||||||
|
if (!results.Success()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_completed_shared_tasks.clear();
|
||||||
|
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
m_completed_shared_tasks.push_back(std::stoi(row[0]));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
inline std::vector<uint32_t> GetCompletedSharedTasks() const { return m_completed_shared_tasks; };
|
||||||
void LoadClientTaskState();
|
void LoadClientTaskState();
|
||||||
void RemoveClientTaskState();
|
void RemoveClientTaskState();
|
||||||
void SendTaskActivityComplete(int task_id, int activity_id, int task_index, TaskType task_type, int task_incomplete=1);
|
void SendTaskActivityComplete(int task_id, int activity_id, int task_index, TaskType task_type, int task_incomplete=1);
|
||||||
@@ -1459,7 +1484,10 @@ public:
|
|||||||
{
|
{
|
||||||
return (task_state ? task_state->EnabledTaskCount(task_set_id) : -1);
|
return (task_state ? task_state->EnabledTaskCount(task_set_id) : -1);
|
||||||
}
|
}
|
||||||
inline bool IsTaskCompleted(int task_id) { return (task_state ? task_state->IsTaskCompleted(task_id) : false); }
|
inline bool IsTaskCompleted(int task_id)
|
||||||
|
{
|
||||||
|
return (task_state ? task_state->IsTaskCompleted(task_id, this) : false);
|
||||||
|
}
|
||||||
inline bool AreTasksCompleted(std::vector<int> task_ids)
|
inline bool AreTasksCompleted(std::vector<int> task_ids)
|
||||||
{
|
{
|
||||||
return (task_state ? task_state->AreTasksCompleted(task_ids) : false);
|
return (task_state ? task_state->AreTasksCompleted(task_ids) : false);
|
||||||
@@ -2012,7 +2040,7 @@ private:
|
|||||||
bool GuildBanker;
|
bool GuildBanker;
|
||||||
uint16 duel_target;
|
uint16 duel_target;
|
||||||
bool duelaccepted;
|
bool duelaccepted;
|
||||||
std::list<uint32> keyring;
|
std::vector<uint32> keyring;
|
||||||
bool tellsoff; // GM /toggle
|
bool tellsoff; // GM /toggle
|
||||||
bool gm_hide_me;
|
bool gm_hide_me;
|
||||||
bool LFG;
|
bool LFG;
|
||||||
@@ -2290,6 +2318,8 @@ private:
|
|||||||
bool m_has_quest_compass = false;
|
bool m_has_quest_compass = false;
|
||||||
std::vector<uint32_t> m_dynamic_zone_ids;
|
std::vector<uint32_t> m_dynamic_zone_ids;
|
||||||
|
|
||||||
|
std::vector<uint32_t> m_completed_shared_tasks;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum BotOwnerOption : size_t {
|
enum BotOwnerOption : size_t {
|
||||||
booDeathMarquee,
|
booDeathMarquee,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
extern WorldServer worldserver;
|
extern WorldServer worldserver;
|
||||||
extern QueryServ* QServ;
|
extern QueryServ* QServ;
|
||||||
|
const std::string SUB_TYPE_DELIMITER = ".";
|
||||||
|
|
||||||
void Client::DoEvolveItemToggle(const EQApplicationPacket *app)
|
void Client::DoEvolveItemToggle(const EQApplicationPacket *app)
|
||||||
{
|
{
|
||||||
@@ -77,11 +78,12 @@ void Client::ProcessEvolvingItem(const uint64 exp, const Mob *mob)
|
|||||||
"CharacterID <green>[{}] found equipped item ID <yellow>[{}]", CharacterID(), inst->GetID());
|
"CharacterID <green>[{}] found equipped item ID <yellow>[{}]", CharacterID(), inst->GetID());
|
||||||
if (!inst->IsEvolving() || !inst->GetEvolveActivated()) {
|
if (!inst->IsEvolving() || !inst->GetEvolveActivated()) {
|
||||||
LogEvolveItemDetail(
|
LogEvolveItemDetail(
|
||||||
"CharacterID <green>[{}], item ID <yellow>[{}] not an evolving item.", CharacterID(), inst->GetID());
|
"CharacterID <green>[{}], item ID <yellow>[{}] not an evolving item.", CharacterID(), inst->GetID()
|
||||||
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst->GetTimers().contains("evolve") && !inst->GetTimers().at("evolve").Check()) {
|
if (inst->GetTimers().contains("evolve") && !inst->GetTimers().at("evolve").Check(false)) {
|
||||||
LogEvolveItemDetail(
|
LogEvolveItemDetail(
|
||||||
"CharacterID <green>[{}], item ID <yellow>[{}] timer not yet expired. <red>[{}] secs remaining.",
|
"CharacterID <green>[{}], item ID <yellow>[{}] timer not yet expired. <red>[{}] secs remaining.",
|
||||||
CharacterID(),
|
CharacterID(),
|
||||||
@@ -98,32 +100,39 @@ void Client::ProcessEvolvingItem(const uint64 exp, const Mob *mob)
|
|||||||
CharacterID(),
|
CharacterID(),
|
||||||
inst->GetID(),
|
inst->GetID(),
|
||||||
type,
|
type,
|
||||||
sub_type);
|
sub_type
|
||||||
|
);
|
||||||
|
|
||||||
|
auto sub_types = Strings::Split(sub_type, SUB_TYPE_DELIMITER);
|
||||||
|
auto has_sub_type = [&](uint32_t type) {
|
||||||
|
return Strings::Contains(sub_types, std::to_string(type));
|
||||||
|
};
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case EvolvingItems::Types::AMOUNT_OF_EXP: {
|
case EvolvingItems::Types::AMOUNT_OF_EXP: {
|
||||||
LogEvolveItemDetail("Type <green>[{}] Processing sub_type", type);
|
LogEvolveItemDetail("Type <green>[{}] Processing sub_type", type);
|
||||||
if (sub_type == EvolvingItems::SubTypes::ALL_EXP ||
|
|
||||||
(sub_type == EvolvingItems::SubTypes::GROUP_EXP && IsGrouped())) {
|
// Determine the evolve amount based on sub_type conditions
|
||||||
LogEvolveItemDetail("Sub_Type <green>[{}] Processing Item", sub_type);
|
int evolve_amount = 0;
|
||||||
inst->SetEvolveAddToCurrentAmount(exp * RuleR(EvolvingItems, PercentOfGroupExperience) / 100);
|
|
||||||
|
if (has_sub_type(EvolvingItems::SubTypes::ALL_EXP) ||
|
||||||
|
(has_sub_type(EvolvingItems::SubTypes::GROUP_EXP) && IsGrouped())) {
|
||||||
|
evolve_amount = exp * RuleR(EvolvingItems, PercentOfGroupExperience) / 100;
|
||||||
}
|
}
|
||||||
else if (
|
else if (has_sub_type(EvolvingItems::SubTypes::ALL_EXP) ||
|
||||||
sub_type == EvolvingItems::SubTypes::ALL_EXP ||
|
(has_sub_type(EvolvingItems::SubTypes::RAID_EXP) && IsRaidGrouped())) {
|
||||||
(sub_type == EvolvingItems::SubTypes::RAID_EXP && IsRaidGrouped())) {
|
evolve_amount = exp * RuleR(EvolvingItems, PercentOfRaidExperience) / 100;
|
||||||
LogEvolveItemDetail("Sub_Type <green>[{}] Processing Item", sub_type);
|
|
||||||
inst->SetEvolveAddToCurrentAmount(exp * RuleR(EvolvingItems, PercentOfRaidExperience) / 100);
|
|
||||||
}
|
}
|
||||||
else if (
|
else if (has_sub_type(EvolvingItems::SubTypes::ALL_EXP) ||
|
||||||
sub_type == EvolvingItems::SubTypes::ALL_EXP || sub_type == EvolvingItems::SubTypes::SOLO_EXP) {
|
has_sub_type(EvolvingItems::SubTypes::SOLO_EXP)) {
|
||||||
LogEvolveItemDetail("Sub_Type <green>[{}] Processing Item", sub_type);
|
evolve_amount = exp * RuleR(EvolvingItems, PercentOfSoloExperience) / 100;
|
||||||
inst->SetEvolveAddToCurrentAmount(exp * RuleR(EvolvingItems, PercentOfSoloExperience) / 100);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inst->CalculateEvolveProgression();
|
inst->CalculateEvolveProgression();
|
||||||
|
|
||||||
auto e = CharacterEvolvingItemsRepository::SetCurrentAmountAndProgression(
|
auto e = CharacterEvolvingItemsRepository::SetCurrentAmountAndProgression(
|
||||||
database, inst->GetEvolveUniqueID(), inst->GetEvolveCurrentAmount(), inst->GetEvolveProgression());
|
database, inst->GetEvolveUniqueID(), inst->GetEvolveCurrentAmount(), inst->GetEvolveProgression()
|
||||||
|
);
|
||||||
if (!e.id) {
|
if (!e.id) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -146,7 +155,7 @@ void Client::ProcessEvolvingItem(const uint64 exp, const Mob *mob)
|
|||||||
}
|
}
|
||||||
case EvolvingItems::Types::SPECIFIC_MOB_RACE: {
|
case EvolvingItems::Types::SPECIFIC_MOB_RACE: {
|
||||||
LogEvolveItemDetail("Type <green>[{}] Processing sub type", type);
|
LogEvolveItemDetail("Type <green>[{}] Processing sub type", type);
|
||||||
if (mob && mob->GetRace() == sub_type) {
|
if (mob && has_sub_type(mob->GetRace())) {
|
||||||
LogEvolveItemDetail("Sub_Type <green>[{}] Processing Item", sub_type);
|
LogEvolveItemDetail("Sub_Type <green>[{}] Processing Item", sub_type);
|
||||||
inst->SetEvolveAddToCurrentAmount(1);
|
inst->SetEvolveAddToCurrentAmount(1);
|
||||||
inst->CalculateEvolveProgression();
|
inst->CalculateEvolveProgression();
|
||||||
@@ -155,7 +164,8 @@ void Client::ProcessEvolvingItem(const uint64 exp, const Mob *mob)
|
|||||||
database,
|
database,
|
||||||
inst->GetEvolveUniqueID(),
|
inst->GetEvolveUniqueID(),
|
||||||
inst->GetEvolveCurrentAmount(),
|
inst->GetEvolveCurrentAmount(),
|
||||||
inst->GetEvolveProgression());
|
inst->GetEvolveProgression()
|
||||||
|
);
|
||||||
if (!e.id) {
|
if (!e.id) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -163,7 +173,8 @@ void Client::ProcessEvolvingItem(const uint64 exp, const Mob *mob)
|
|||||||
SendEvolvingPacket(EvolvingItems::Actions::UPDATE_ITEMS, e);
|
SendEvolvingPacket(EvolvingItems::Actions::UPDATE_ITEMS, e);
|
||||||
|
|
||||||
LogEvolveItem(
|
LogEvolveItem(
|
||||||
"Processing Complete for item id <green>[{1}] Type 3 Specific Mob Race - SubType <yellow>[{0}] "
|
"Processing Complete for item id <green>[{1}] Type 3 Specific Mob Race - SubType "
|
||||||
|
"<yellow>[{0}] "
|
||||||
"- Increased count by 1 for <green>[{1}]",
|
"- Increased count by 1 for <green>[{1}]",
|
||||||
sub_type,
|
sub_type,
|
||||||
inst->GetID()
|
inst->GetID()
|
||||||
@@ -178,7 +189,7 @@ void Client::ProcessEvolvingItem(const uint64 exp, const Mob *mob)
|
|||||||
}
|
}
|
||||||
case EvolvingItems::Types::SPECIFIC_ZONE_ID: {
|
case EvolvingItems::Types::SPECIFIC_ZONE_ID: {
|
||||||
LogEvolveItemDetail("Type <green>[{}] Processing sub type", type);
|
LogEvolveItemDetail("Type <green>[{}] Processing sub type", type);
|
||||||
if (mob && mob->GetZoneID() == sub_type) {
|
if (mob && has_sub_type(mob->GetZoneID())) {
|
||||||
LogEvolveItemDetail("Sub_Type <green>[{}] Processing Item", sub_type);
|
LogEvolveItemDetail("Sub_Type <green>[{}] Processing Item", sub_type);
|
||||||
inst->SetEvolveAddToCurrentAmount(1);
|
inst->SetEvolveAddToCurrentAmount(1);
|
||||||
inst->CalculateEvolveProgression();
|
inst->CalculateEvolveProgression();
|
||||||
@@ -187,7 +198,8 @@ void Client::ProcessEvolvingItem(const uint64 exp, const Mob *mob)
|
|||||||
database,
|
database,
|
||||||
inst->GetEvolveUniqueID(),
|
inst->GetEvolveUniqueID(),
|
||||||
inst->GetEvolveCurrentAmount(),
|
inst->GetEvolveCurrentAmount(),
|
||||||
inst->GetEvolveProgression());
|
inst->GetEvolveProgression()
|
||||||
|
);
|
||||||
if (!e.id) {
|
if (!e.id) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -195,7 +207,8 @@ void Client::ProcessEvolvingItem(const uint64 exp, const Mob *mob)
|
|||||||
SendEvolvingPacket(EvolvingItems::Actions::UPDATE_ITEMS, e);
|
SendEvolvingPacket(EvolvingItems::Actions::UPDATE_ITEMS, e);
|
||||||
|
|
||||||
LogEvolveItem(
|
LogEvolveItem(
|
||||||
"Processing Complete for item id <green>[{1}] Type 4 Specific Zone ID - SubType <yellow>[{0}] "
|
"Processing Complete for item id <green>[{1}] Type 4 Specific Zone ID - SubType "
|
||||||
|
"<yellow>[{0}] "
|
||||||
"- Increased count by 1 for <green>[{1}]",
|
"- Increased count by 1 for <green>[{1}]",
|
||||||
sub_type,
|
sub_type,
|
||||||
inst->GetID()
|
inst->GetID()
|
||||||
@@ -208,6 +221,44 @@ void Client::ProcessEvolvingItem(const uint64 exp, const Mob *mob)
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case EvolvingItems::Types::NUMBER_OF_KILLS: {
|
||||||
|
LogEvolveItemDetail("Type <green>[{}] Processing sub type", type);
|
||||||
|
if (mob) {
|
||||||
|
if (mob->GetLevel() >= Strings::ToUnsignedInt(sub_types.front()) ||
|
||||||
|
Strings::ToUnsignedInt(sub_types.front()) == 0
|
||||||
|
) {
|
||||||
|
LogEvolveItemDetail("Sub_Type <green>[{}] Processing Item", sub_type);
|
||||||
|
inst->SetEvolveAddToCurrentAmount(1);
|
||||||
|
inst->CalculateEvolveProgression();
|
||||||
|
|
||||||
|
auto e = CharacterEvolvingItemsRepository::SetCurrentAmountAndProgression(
|
||||||
|
database,
|
||||||
|
inst->GetEvolveUniqueID(),
|
||||||
|
inst->GetEvolveCurrentAmount(),
|
||||||
|
inst->GetEvolveProgression()
|
||||||
|
);
|
||||||
|
if (!e.id) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
SendEvolvingPacket(EvolvingItems::Actions::UPDATE_ITEMS, e);
|
||||||
|
|
||||||
|
LogEvolveItem(
|
||||||
|
"Processing Complete for item id <green>[{1}] Type 4 Specific Zone ID - SubType "
|
||||||
|
"<yellow>[{0}] "
|
||||||
|
"- Increased count by 1 for <green>[{1}]",
|
||||||
|
sub_type,
|
||||||
|
inst->GetID()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inst->GetEvolveProgression() >= 100) {
|
||||||
|
queue.push_back(inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
#include "../common/types.h"
|
#include "../common/types.h"
|
||||||
#include "../common/spdat.h"
|
#include "../common/spdat.h"
|
||||||
|
|
||||||
|
#include <cereal/cereal.hpp>
|
||||||
|
|
||||||
#define HIGHEST_RESIST 9 //Max resist type value
|
#define HIGHEST_RESIST 9 //Max resist type value
|
||||||
#define MAX_SPELL_PROJECTILE 10 //Max amount of spell projectiles that can be active by a single mob.
|
#define MAX_SPELL_PROJECTILE 10 //Max amount of spell projectiles that can be active by a single mob.
|
||||||
|
|
||||||
@@ -272,6 +274,46 @@ struct Buffs_Struct {
|
|||||||
bool persistant_buff;
|
bool persistant_buff;
|
||||||
bool client; //True if the caster is a client
|
bool client; //True if the caster is a client
|
||||||
bool UpdateClient;
|
bool UpdateClient;
|
||||||
|
|
||||||
|
// cereal
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive &ar)
|
||||||
|
{
|
||||||
|
|
||||||
|
std::string caster_name_str(caster_name);
|
||||||
|
if (Archive::is_saving::value) {
|
||||||
|
caster_name_str = std::string(caster_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
ar(
|
||||||
|
CEREAL_NVP(spellid),
|
||||||
|
CEREAL_NVP(casterlevel),
|
||||||
|
CEREAL_NVP(casterid),
|
||||||
|
CEREAL_NVP(caster_name_str),
|
||||||
|
CEREAL_NVP(ticsremaining),
|
||||||
|
CEREAL_NVP(counters),
|
||||||
|
CEREAL_NVP(hit_number),
|
||||||
|
CEREAL_NVP(melee_rune),
|
||||||
|
CEREAL_NVP(magic_rune),
|
||||||
|
CEREAL_NVP(dot_rune),
|
||||||
|
CEREAL_NVP(caston_x),
|
||||||
|
CEREAL_NVP(caston_y),
|
||||||
|
CEREAL_NVP(caston_z),
|
||||||
|
CEREAL_NVP(ExtraDIChance),
|
||||||
|
CEREAL_NVP(RootBreakChance),
|
||||||
|
CEREAL_NVP(instrument_mod),
|
||||||
|
CEREAL_NVP(virus_spread_time),
|
||||||
|
CEREAL_NVP(persistant_buff),
|
||||||
|
CEREAL_NVP(client),
|
||||||
|
CEREAL_NVP(UpdateClient)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Copy back into caster_name after deserialization
|
||||||
|
if (Archive::is_loading::value) {
|
||||||
|
strncpy(caster_name, caster_name_str.c_str(), sizeof(caster_name));
|
||||||
|
caster_name[sizeof(caster_name) - 1] = '\0'; // Ensure null termination
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StatBonuses {
|
struct StatBonuses {
|
||||||
|
|||||||
@@ -200,6 +200,7 @@ public:
|
|||||||
uint32 GetItemIDBySlot(uint16 loot_slot);
|
uint32 GetItemIDBySlot(uint16 loot_slot);
|
||||||
uint16 GetFirstLootSlotByItemID(uint32 item_id);
|
uint16 GetFirstLootSlotByItemID(uint32 item_id);
|
||||||
std::vector<int> GetLootList();
|
std::vector<int> GetLootList();
|
||||||
|
inline const LootItems &GetLootItems() { return m_item_list; }
|
||||||
void LootCorpseItem(Client *c, const EQApplicationPacket *app);
|
void LootCorpseItem(Client *c, const EQApplicationPacket *app);
|
||||||
void EndLoot(Client *c, const EQApplicationPacket *app);
|
void EndLoot(Client *c, const EQApplicationPacket *app);
|
||||||
void MakeLootRequestPackets(Client *c, const EQApplicationPacket *app);
|
void MakeLootRequestPackets(Client *c, const EQApplicationPacket *app);
|
||||||
|
|||||||
+24
-1
@@ -754,7 +754,7 @@ void Perl__setsky(uint8 new_sky)
|
|||||||
|
|
||||||
void Perl__setguild(uint32_t guild_id, uint8_t guild_rank_id)
|
void Perl__setguild(uint32_t guild_id, uint8_t guild_rank_id)
|
||||||
{
|
{
|
||||||
quest_manager.setguild(guild_id, guild_rank_id);
|
quest_manager.SetGuild(guild_id, guild_rank_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Perl__createguild(const char* guild_name, const char* leader_name)
|
void Perl__createguild(const char* guild_name, const char* leader_name)
|
||||||
@@ -5973,6 +5973,28 @@ void Perl__SpawnGrid(uint32 npc_id, float x, float y, float z, float heading, fl
|
|||||||
quest_manager.SpawnGrid(npc_id, glm::vec4(x, y, z, heading), spacing, spawn_count);
|
quest_manager.SpawnGrid(npc_id, glm::vec4(x, y, z, heading), spacing, spawn_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Perl__handin(perl::reference handin_ref)
|
||||||
|
{
|
||||||
|
perl::hash handin = handin_ref;
|
||||||
|
|
||||||
|
std::map<std::string, uint32> handin_map;
|
||||||
|
|
||||||
|
for (auto e: handin) {
|
||||||
|
if (!e.first) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Strings::EqualFold(e.first, "0")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32 count = static_cast<uint32>(handin.at(e.first));
|
||||||
|
handin_map[e.first] = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
return quest_manager.handin(handin_map);
|
||||||
|
}
|
||||||
|
|
||||||
void perl_register_quest()
|
void perl_register_quest()
|
||||||
{
|
{
|
||||||
perl::interpreter perl(PERL_GET_THX);
|
perl::interpreter perl(PERL_GET_THX);
|
||||||
@@ -6698,6 +6720,7 @@ void perl_register_quest()
|
|||||||
package.add("gmsay", (void(*)(const char*, int, bool))&Perl__gmsay);
|
package.add("gmsay", (void(*)(const char*, int, bool))&Perl__gmsay);
|
||||||
package.add("gmsay", (void(*)(const char*, int, bool, int))&Perl__gmsay);
|
package.add("gmsay", (void(*)(const char*, int, bool, int))&Perl__gmsay);
|
||||||
package.add("gmsay", (void(*)(const char*, int, bool, int, int))&Perl__gmsay);
|
package.add("gmsay", (void(*)(const char*, int, bool, int, int))&Perl__gmsay);
|
||||||
|
package.add("handin", &Perl__handin);
|
||||||
package.add("has_zone_flag", &Perl__has_zone_flag);
|
package.add("has_zone_flag", &Perl__has_zone_flag);
|
||||||
package.add("hasrecipelearned", &Perl__hasrecipelearned);
|
package.add("hasrecipelearned", &Perl__hasrecipelearned);
|
||||||
package.add("hastimer", &Perl__hastimer);
|
package.add("hastimer", &Perl__hastimer);
|
||||||
|
|||||||
+1
-1
@@ -2933,7 +2933,7 @@ void EntityList::ScanCloseMobs(Mob *scanning_mob)
|
|||||||
for (auto &e : mob_list) {
|
for (auto &e : mob_list) {
|
||||||
auto mob = e.second;
|
auto mob = e.second;
|
||||||
|
|
||||||
if (mob->GetID() <= 0) {
|
if (mob && mob->GetID() <= 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -91,6 +91,8 @@ void command_guild(Client* c, const Seperator* sep)
|
|||||||
else {
|
else {
|
||||||
auto guild_name = sep->argplus[3];
|
auto guild_name = sep->argplus[3];
|
||||||
auto guild_id = guild_mgr.CreateGuild(sep->argplus[3], leader_id);
|
auto guild_id = guild_mgr.CreateGuild(sep->argplus[3], leader_id);
|
||||||
|
auto leader = entity_list.GetClientByCharID(leader_id);
|
||||||
|
|
||||||
|
|
||||||
LogGuilds(
|
LogGuilds(
|
||||||
"[{}]: Creating guild [{}] with leader [{}] with GM command. It was given id [{}]",
|
"[{}]: Creating guild [{}] with leader [{}] with GM command. It was given id [{}]",
|
||||||
@@ -115,7 +117,7 @@ void command_guild(Client* c, const Seperator* sep)
|
|||||||
).c_str()
|
).c_str()
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!guild_mgr.SetGuild(leader_id, guild_id, GUILD_LEADER)) {
|
if (!guild_mgr.SetGuild(leader, guild_id, GUILD_LEADER)) {
|
||||||
c->Message(
|
c->Message(
|
||||||
Chat::White,
|
Chat::White,
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@@ -268,6 +270,7 @@ void command_guild(Client* c, const Seperator* sep)
|
|||||||
database.GetCharacterID(sep->arg[2])
|
database.GetCharacterID(sep->arg[2])
|
||||||
);
|
);
|
||||||
auto character_name = database.GetCharNameByID(character_id);
|
auto character_name = database.GetCharNameByID(character_id);
|
||||||
|
auto client = entity_list.GetClientByCharID(character_id);
|
||||||
if (!character_id || character_name.empty()) {
|
if (!character_id || character_name.empty()) {
|
||||||
c->Message(
|
c->Message(
|
||||||
Chat::White,
|
Chat::White,
|
||||||
@@ -305,14 +308,14 @@ void command_guild(Client* c, const Seperator* sep)
|
|||||||
"{} ({}) has {} put into {} ({}).",
|
"{} ({}) has {} put into {} ({}).",
|
||||||
character_name,
|
character_name,
|
||||||
character_id,
|
character_id,
|
||||||
guild_mgr.SetGuild(character_id, guild_id, GUILD_MEMBER) ? "been" : "failed to be",
|
guild_mgr.SetGuild(client, guild_id, GUILD_MEMBER) ? "been" : "failed to be",
|
||||||
guild_mgr.GetGuildNameByID(guild_id),
|
guild_mgr.GetGuildNameByID(guild_id),
|
||||||
guild_id
|
guild_id
|
||||||
).c_str()
|
).c_str()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
guild_mgr.SetGuild(character_id, GUILD_NONE, 0);
|
guild_mgr.SetGuild(client, GUILD_NONE, 0);
|
||||||
c->Message(
|
c->Message(
|
||||||
Chat::White,
|
Chat::White,
|
||||||
fmt::format(
|
fmt::format(
|
||||||
|
|||||||
+35
-36
@@ -1317,42 +1317,6 @@ bool GuildBankManager::SplitStack(uint32 guild_id, uint16 slot_id, uint32 quanti
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// void GuildBankManager::UpdateItemQuantity(uint32 guildID, uint16 area, uint16 slotID, uint32 quantity)
|
|
||||||
// {
|
|
||||||
// // Helper method for MergeStacks. Assuming all passed parameters are valid.
|
|
||||||
// //
|
|
||||||
// std::string query = StringFormat("UPDATE `guild_bank` SET `qty` = %i "
|
|
||||||
// "WHERE `guildid` = %i AND `area` = %i "
|
|
||||||
// "AND `slot` = %i LIMIT 1",
|
|
||||||
// quantity, guildID, area, slotID);
|
|
||||||
// auto results = database.QueryDatabase(query);
|
|
||||||
// if(!results.Success()) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
|
|
||||||
// bool GuildBankManager::AllowedToWithdraw(uint32 guild_id, uint16 area, uint16 slot_id, const char *name)
|
|
||||||
// {
|
|
||||||
// auto guild_bank = GetGuildBank(guild_id);
|
|
||||||
// if (!guild_bank) {
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (area != GuildBankMainArea) {
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// auto item = &guild_bank->items.main_area[slot_id];
|
|
||||||
// uint8 permissions = item->permissions;
|
|
||||||
//
|
|
||||||
// if (permissions == GuildBankBankerOnly) {
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
|
|
||||||
int32 GuildBankManager::NextFreeBankSlot(uint32 guild_id, uint32 area)
|
int32 GuildBankManager::NextFreeBankSlot(uint32 guild_id, uint32 area)
|
||||||
{
|
{
|
||||||
auto guild_bank = GetGuildBank(guild_id);
|
auto guild_bank = GetGuildBank(guild_id);
|
||||||
@@ -1760,3 +1724,38 @@ void GuildBankManager::SendGuildBankItemUpdate(uint32 guild_id, int32 slot_id, u
|
|||||||
|
|
||||||
entity_list.QueueClientsGuildBankItemUpdate(&gbius, guild_id);
|
entity_list.QueueClientsGuildBankItemUpdate(&gbius, guild_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ZoneGuildManager::SetGuild(Client *client, uint32 guild_id, uint8 rank)
|
||||||
|
{
|
||||||
|
if (!client || rank > GUILD_MAX_RANK || !GetGuildByGuildID(guild_id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rank <= GUILD_RANK_NONE) {
|
||||||
|
rank = GUILD_RECRUIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32 current_guild_id = client->GuildID();
|
||||||
|
if (current_guild_id == guild_id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_guild_id != guild_id && current_guild_id != GUILD_NONE) {
|
||||||
|
guild_mgr.RemoveMember(client->GuildID(), client->CharacterID(), std::string(client->GetCleanName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
client->SetGuildID(guild_id);
|
||||||
|
client->SetGuildRank(rank);
|
||||||
|
MemberAdd(
|
||||||
|
guild_id,
|
||||||
|
client->CharacterID(),
|
||||||
|
client->GetLevel(),
|
||||||
|
client->GetClass(),
|
||||||
|
rank,
|
||||||
|
client->GetZoneID(),
|
||||||
|
client->GetName()
|
||||||
|
);
|
||||||
|
|
||||||
|
client->SendGuildSpawnAppearance();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ public:
|
|||||||
void ListGuilds(Client *c, uint32 guild_id = 0) const;
|
void ListGuilds(Client *c, uint32 guild_id = 0) const;
|
||||||
void DescribeGuild(Client *c, uint32 guild_id) const;
|
void DescribeGuild(Client *c, uint32 guild_id) const;
|
||||||
bool IsActionABankAction(GuildAction action);
|
bool IsActionABankAction(GuildAction action);
|
||||||
|
bool SetGuild(Client *client, uint32 guild_id, uint8 rank);
|
||||||
|
|
||||||
uint8 *MakeGuildMembers(uint32 guild_id, const char* prefix_name, uint32& length);
|
uint8 *MakeGuildMembers(uint32 guild_id, const char* prefix_name, uint32& length);
|
||||||
void SendToWorldMemberLevelUpdate(uint32 guild_id, uint32 level, std::string player_name);
|
void SendToWorldMemberLevelUpdate(uint32 guild_id, uint32 level, std::string player_name);
|
||||||
|
|||||||
+14
-1
@@ -276,6 +276,11 @@ void NPC::AddLootDrop(
|
|||||||
uint32 augment_six
|
uint32 augment_six
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
if (m_resumed_from_zone_suspend) {
|
||||||
|
LogZoneState("NPC [{}] is resuming from zone suspend, skipping AddItem", GetCleanName());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!item2) {
|
if (!item2) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -370,6 +375,10 @@ void NPC::AddLootDrop(
|
|||||||
if (item2->Slots & slots) {
|
if (item2->Slots & slots) {
|
||||||
if (equipment[i]) {
|
if (equipment[i]) {
|
||||||
compitem = database.GetItem(equipment[i]);
|
compitem = database.GetItem(equipment[i]);
|
||||||
|
if (!compitem) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (item2->AC > compitem->AC || (item2->AC == compitem->AC && item2->HP > compitem->HP)) {
|
if (item2->AC > compitem->AC || (item2->AC == compitem->AC && item2->HP > compitem->HP)) {
|
||||||
// item would be an upgrade
|
// item would be an upgrade
|
||||||
// check if we're multi-slot, if yes then we have to keep
|
// check if we're multi-slot, if yes then we have to keep
|
||||||
@@ -380,6 +389,9 @@ void NPC::AddLootDrop(
|
|||||||
else {
|
else {
|
||||||
// Unequip old item
|
// Unequip old item
|
||||||
auto *old_item = GetItem(i);
|
auto *old_item = GetItem(i);
|
||||||
|
if (!old_item) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
old_item->equip_slot = EQ::invslot::SLOT_INVALID;
|
old_item->equip_slot = EQ::invslot::SLOT_INVALID;
|
||||||
|
|
||||||
@@ -500,6 +512,7 @@ void NPC::AddLootDrop(
|
|||||||
parse->EventNPC(EVENT_LOOT_ADDED, this, nullptr, "", 0, &args);
|
parse->EventNPC(EVENT_LOOT_ADDED, this, nullptr, "", 0, &args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
item->lootdrop_id = loot_drop.lootdrop_id;
|
||||||
m_loot_items.push_back(item);
|
m_loot_items.push_back(item);
|
||||||
|
|
||||||
if (found) {
|
if (found) {
|
||||||
@@ -671,7 +684,7 @@ LootItem *NPC::GetItem(int slot_id)
|
|||||||
end = m_loot_items.end();
|
end = m_loot_items.end();
|
||||||
for (; cur != end; ++cur) {
|
for (; cur != end; ++cur) {
|
||||||
LootItem *item = *cur;
|
LootItem *item = *cur;
|
||||||
if (item->equip_slot == slot_id) {
|
if (item && item->equip_slot == slot_id) {
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+32
-11
@@ -1199,16 +1199,6 @@ void Lua_Client::SetStartZone(int zone_id, float x, float y, float z) {
|
|||||||
self->SetStartZone(zone_id, x, y, z);
|
self->SetStartZone(zone_id, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Lua_Client::KeyRingAdd(uint32 item) {
|
|
||||||
Lua_Safe_Call_Void();
|
|
||||||
self->KeyRingAdd(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Lua_Client::KeyRingCheck(uint32 item) {
|
|
||||||
Lua_Safe_Call_Bool();
|
|
||||||
return self->KeyRingCheck(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Lua_Client::AddPVPPoints(uint32 points) {
|
void Lua_Client::AddPVPPoints(uint32 points) {
|
||||||
Lua_Safe_Call_Void();
|
Lua_Safe_Call_Void();
|
||||||
self->AddPVPPoints(points);
|
self->AddPVPPoints(points);
|
||||||
@@ -3548,6 +3538,34 @@ std::string Lua_Client::GetPotionBeltItemName(uint8 slot_id)
|
|||||||
return self->GetPotionBeltItemName(slot_id);
|
return self->GetPotionBeltItemName(slot_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Lua_Client::KeyRingAdd(uint32 item) {
|
||||||
|
Lua_Safe_Call_Bool();
|
||||||
|
return self->KeyRingAdd(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Lua_Client::KeyRingCheck(uint32 item) {
|
||||||
|
Lua_Safe_Call_Bool();
|
||||||
|
return self->KeyRingCheck(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Lua_Client::KeyRingClear()
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Bool();
|
||||||
|
return self->KeyRingClear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lua_Client::KeyRingList()
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Void();
|
||||||
|
self->KeyRingList();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Lua_Client::KeyRingRemove(uint32 item_id)
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Bool();
|
||||||
|
return self->KeyRingRemove(item_id);
|
||||||
|
}
|
||||||
|
|
||||||
luabind::scope lua_register_client() {
|
luabind::scope lua_register_client() {
|
||||||
return luabind::class_<Lua_Client, Lua_Mob>("Client")
|
return luabind::class_<Lua_Client, Lua_Mob>("Client")
|
||||||
.def(luabind::constructor<>())
|
.def(luabind::constructor<>())
|
||||||
@@ -3869,8 +3887,11 @@ luabind::scope lua_register_client() {
|
|||||||
.def("IsTaskActive", (bool(Lua_Client::*)(int))&Lua_Client::IsTaskActive)
|
.def("IsTaskActive", (bool(Lua_Client::*)(int))&Lua_Client::IsTaskActive)
|
||||||
.def("IsTaskActivityActive", (bool(Lua_Client::*)(int,int))&Lua_Client::IsTaskActivityActive)
|
.def("IsTaskActivityActive", (bool(Lua_Client::*)(int,int))&Lua_Client::IsTaskActivityActive)
|
||||||
.def("IsTaskCompleted", (bool(Lua_Client::*)(int))&Lua_Client::IsTaskCompleted)
|
.def("IsTaskCompleted", (bool(Lua_Client::*)(int))&Lua_Client::IsTaskCompleted)
|
||||||
.def("KeyRingAdd", (void(Lua_Client::*)(uint32))&Lua_Client::KeyRingAdd)
|
.def("KeyRingAdd", (bool(Lua_Client::*)(uint32))&Lua_Client::KeyRingAdd)
|
||||||
.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("KeyRingList", (void(Lua_Client::*)(void))&Lua_Client::KeyRingList)
|
||||||
|
.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)
|
||||||
.def("LearnRecipe", (void(Lua_Client::*)(uint32))&Lua_Client::LearnRecipe)
|
.def("LearnRecipe", (void(Lua_Client::*)(uint32))&Lua_Client::LearnRecipe)
|
||||||
|
|||||||
+5
-2
@@ -313,8 +313,6 @@ public:
|
|||||||
void SetStartZone(int zone_id, float x, float y);
|
void SetStartZone(int zone_id, float x, float y);
|
||||||
void SetStartZone(int zone_id, float x, float y, float z);
|
void SetStartZone(int zone_id, float x, float y, float z);
|
||||||
void SetStartZone(int zone_id, float x, float y, float z, float heading);
|
void SetStartZone(int zone_id, float x, float y, float z, float heading);
|
||||||
void KeyRingAdd(uint32 item);
|
|
||||||
bool KeyRingCheck(uint32 item);
|
|
||||||
void AddPVPPoints(uint32 points);
|
void AddPVPPoints(uint32 points);
|
||||||
void AddCrystals(uint32 radiant_count, uint32 ebon_count);
|
void AddCrystals(uint32 radiant_count, uint32 ebon_count);
|
||||||
void SetEbonCrystals(uint32 value);
|
void SetEbonCrystals(uint32 value);
|
||||||
@@ -518,6 +516,11 @@ public:
|
|||||||
uint32 GetPotionBeltItemIcon(uint8 slot_id);
|
uint32 GetPotionBeltItemIcon(uint8 slot_id);
|
||||||
uint32 GetPotionBeltItemID(uint8 slot_id);
|
uint32 GetPotionBeltItemID(uint8 slot_id);
|
||||||
std::string GetPotionBeltItemName(uint8 slot_id);
|
std::string GetPotionBeltItemName(uint8 slot_id);
|
||||||
|
bool KeyRingAdd(uint32 item_id);
|
||||||
|
bool KeyRingCheck(uint32 item_id);
|
||||||
|
bool KeyRingClear();
|
||||||
|
void KeyRingList();
|
||||||
|
bool KeyRingRemove(uint32 item_id);
|
||||||
|
|
||||||
// account data buckets
|
// account data buckets
|
||||||
void SetAccountBucket(std::string bucket_name, std::string bucket_value);
|
void SetAccountBucket(std::string bucket_name, std::string bucket_value);
|
||||||
|
|||||||
+27
-1
@@ -468,7 +468,7 @@ void lua_set_sky(int sky) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void lua_set_guild(int guild_id, int rank) {
|
void lua_set_guild(int guild_id, int rank) {
|
||||||
quest_manager.setguild(guild_id, rank);
|
quest_manager.SetGuild(guild_id, rank);
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua_create_guild(const char *name, const char *leader) {
|
void lua_create_guild(const char *name, const char *leader) {
|
||||||
@@ -5642,6 +5642,31 @@ Lua_Zone lua_get_zone()
|
|||||||
return Lua_Zone(zone);
|
return Lua_Zone(zone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool lua_handin(luabind::adl::object handin_table)
|
||||||
|
{
|
||||||
|
std::map<std::string, uint32> handin_map;
|
||||||
|
|
||||||
|
for (luabind::iterator i(handin_table), end; i != end; i++) {
|
||||||
|
std::string key;
|
||||||
|
if (luabind::type(i.key()) == LUA_TSTRING) {
|
||||||
|
key = luabind::object_cast<std::string>(i.key());
|
||||||
|
}
|
||||||
|
else if (luabind::type(i.key()) == LUA_TNUMBER) {
|
||||||
|
key = fmt::format("{}", luabind::object_cast<int>(i.key()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LogError("Handin key type [{}] not supported", luabind::type(i.key()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!key.empty()) {
|
||||||
|
handin_map[key] = luabind::object_cast<uint32>(handin_table[i.key()]);
|
||||||
|
LogNpcHandinDetail("Handin key [{}] value [{}]", key, handin_map[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return quest_manager.handin(handin_map);
|
||||||
|
}
|
||||||
|
|
||||||
#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) { \
|
||||||
@@ -6450,6 +6475,7 @@ luabind::scope lua_register_general() {
|
|||||||
luabind::def("spawn_circle", &lua_spawn_circle),
|
luabind::def("spawn_circle", &lua_spawn_circle),
|
||||||
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),
|
||||||
/*
|
/*
|
||||||
Cross Zone
|
Cross Zone
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -939,6 +939,12 @@ Lua_Spawn Lua_NPC::GetSpawn(lua_State* L)
|
|||||||
return Lua_Spawn(self->GetSpawn());
|
return Lua_Spawn(self->GetSpawn());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Lua_NPC::IsResumedFromZoneSuspend()
|
||||||
|
{
|
||||||
|
Lua_Safe_Call_Bool();
|
||||||
|
return self->IsResumedFromZoneSuspend();
|
||||||
|
}
|
||||||
|
|
||||||
luabind::scope lua_register_npc() {
|
luabind::scope lua_register_npc() {
|
||||||
return luabind::class_<Lua_NPC, Lua_Mob>("NPC")
|
return luabind::class_<Lua_NPC, Lua_Mob>("NPC")
|
||||||
.def(luabind::constructor<>())
|
.def(luabind::constructor<>())
|
||||||
@@ -1040,6 +1046,7 @@ luabind::scope lua_register_npc() {
|
|||||||
.def("IsOnHatelist", (bool(Lua_NPC::*)(Lua_Mob))&Lua_NPC::IsOnHatelist)
|
.def("IsOnHatelist", (bool(Lua_NPC::*)(Lua_Mob))&Lua_NPC::IsOnHatelist)
|
||||||
.def("IsRaidTarget", (bool(Lua_NPC::*)(void))&Lua_NPC::IsRaidTarget)
|
.def("IsRaidTarget", (bool(Lua_NPC::*)(void))&Lua_NPC::IsRaidTarget)
|
||||||
.def("IsRareSpawn", (bool(Lua_NPC::*)(void))&Lua_NPC::IsRareSpawn)
|
.def("IsRareSpawn", (bool(Lua_NPC::*)(void))&Lua_NPC::IsRareSpawn)
|
||||||
|
.def("IsResumedFromZoneSuspend",(bool(Lua_NPC::*)(void))&Lua_NPC::IsResumedFromZoneSuspend)
|
||||||
.def("IsTaunting", (bool(Lua_NPC::*)(void))&Lua_NPC::IsTaunting)
|
.def("IsTaunting", (bool(Lua_NPC::*)(void))&Lua_NPC::IsTaunting)
|
||||||
.def("IsUnderwaterOnly", (bool(Lua_NPC::*)(void))&Lua_NPC::IsUnderwaterOnly)
|
.def("IsUnderwaterOnly", (bool(Lua_NPC::*)(void))&Lua_NPC::IsUnderwaterOnly)
|
||||||
.def("MerchantCloseShop", (void(Lua_NPC::*)(void))&Lua_NPC::MerchantCloseShop)
|
.def("MerchantCloseShop", (void(Lua_NPC::*)(void))&Lua_NPC::MerchantCloseShop)
|
||||||
|
|||||||
@@ -198,6 +198,7 @@ public:
|
|||||||
);
|
);
|
||||||
void ReturnHandinItems(Lua_Client c);
|
void ReturnHandinItems(Lua_Client c);
|
||||||
Lua_Spawn GetSpawn(lua_State* L);
|
Lua_Spawn GetSpawn(lua_State* L);
|
||||||
|
bool IsResumedFromZoneSuspend();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+27
-19
@@ -631,7 +631,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
if (zone) {
|
if (zone) {
|
||||||
if (!zone->Process()) {
|
if (!zone->Process()) {
|
||||||
Zone::Shutdown();
|
zone->Shutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -668,7 +668,7 @@ int main(int argc, char **argv)
|
|||||||
safe_delete(Config);
|
safe_delete(Config);
|
||||||
|
|
||||||
if (zone != 0) {
|
if (zone != 0) {
|
||||||
Zone::Shutdown(true);
|
zone->Shutdown(true);
|
||||||
}
|
}
|
||||||
//Fix for Linux world server problem.
|
//Fix for Linux world server problem.
|
||||||
safe_delete(task_manager);
|
safe_delete(task_manager);
|
||||||
@@ -687,7 +687,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
void Shutdown()
|
void Shutdown()
|
||||||
{
|
{
|
||||||
Zone::Shutdown(true);
|
zone->Shutdown(true);
|
||||||
LogInfo("Shutting down...");
|
LogInfo("Shutting down...");
|
||||||
LogSys.CloseFileLogs();
|
LogSys.CloseFileLogs();
|
||||||
EQ::EventLoop::Get().Shutdown();
|
EQ::EventLoop::Get().Shutdown();
|
||||||
@@ -731,37 +731,45 @@ void UpdateWindowTitle(char *iNewTitle)
|
|||||||
|
|
||||||
bool CheckForCompatibleQuestPlugins()
|
bool CheckForCompatibleQuestPlugins()
|
||||||
{
|
{
|
||||||
const std::vector<std::string>& directories = { "lua_modules", "plugins" };
|
const std::vector<std::pair<std::string, bool *>> directories = {
|
||||||
|
{"lua_modules", nullptr},
|
||||||
|
{"plugins", nullptr}
|
||||||
|
};
|
||||||
|
|
||||||
bool lua_found = false;
|
bool lua_found = false;
|
||||||
bool perl_found = false;
|
bool perl_found = false;
|
||||||
|
|
||||||
for (const auto& directory : directories) {
|
try {
|
||||||
for (const auto& file : fs::directory_iterator(path.GetServerPath() + "/" + directory)) {
|
for (const auto &[directory, flag]: directories) {
|
||||||
if (file.is_regular_file()) {
|
std::string dir_path = path.GetServerPath() + "/" + directory;
|
||||||
auto f = file.path().string();
|
if (!File::Exists(dir_path)) { continue; }
|
||||||
if (File::Exists(f)) {
|
|
||||||
auto r = File::GetContents(std::filesystem::path{ f }.string());
|
for (const auto &file: fs::directory_iterator(dir_path)) {
|
||||||
if (Strings::Contains(r.contents, "CheckHandin")) {
|
if (!file.is_regular_file()) { continue; }
|
||||||
if (Strings::EqualFold(directory, "lua_modules")) {
|
|
||||||
|
std::string file_path = file.path().string();
|
||||||
|
if (!File::Exists(file_path)) { continue; }
|
||||||
|
|
||||||
|
auto r = File::GetContents(file_path);
|
||||||
|
if (!Strings::Contains(r.contents, "CheckHandin")) { continue; }
|
||||||
|
|
||||||
|
if (directory == "lua_modules") {
|
||||||
lua_found = true;
|
lua_found = true;
|
||||||
} else if (Strings::EqualFold(directory, "plugins")) {
|
}
|
||||||
|
else {
|
||||||
perl_found = true;
|
perl_found = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lua_found && perl_found) {
|
if (lua_found && perl_found) { return true; }
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (const fs::filesystem_error &ex) {
|
||||||
|
LogError("Failed to check for compatible quest plugins: {}", ex.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lua_found) {
|
if (!lua_found) {
|
||||||
LogError("Failed to find CheckHandin in lua_modules");
|
LogError("Failed to find CheckHandin in lua_modules");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!perl_found) {
|
if (!perl_found) {
|
||||||
LogError("Failed to find CheckHandin in plugins");
|
LogError("Failed to find CheckHandin in plugins");
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -531,6 +531,9 @@ Mob::Mob(
|
|||||||
|
|
||||||
Mob::~Mob()
|
Mob::~Mob()
|
||||||
{
|
{
|
||||||
|
entity_list.RemoveMobFromCloseLists(this);
|
||||||
|
m_close_mobs.clear();
|
||||||
|
|
||||||
quest_manager.stopalltimers(this);
|
quest_manager.stopalltimers(this);
|
||||||
|
|
||||||
mMovementManager->RemoveMob(this);
|
mMovementManager->RemoveMob(this);
|
||||||
@@ -570,11 +573,8 @@ Mob::~Mob()
|
|||||||
entity_list.UnMarkNPC(GetID());
|
entity_list.UnMarkNPC(GetID());
|
||||||
UninitializeBuffSlots();
|
UninitializeBuffSlots();
|
||||||
|
|
||||||
entity_list.RemoveMobFromCloseLists(this);
|
|
||||||
entity_list.RemoveAuraFromMobs(this);
|
entity_list.RemoveAuraFromMobs(this);
|
||||||
|
|
||||||
m_close_mobs.clear();
|
|
||||||
|
|
||||||
ClearDataBucketCache();
|
ClearDataBucketCache();
|
||||||
|
|
||||||
LeaveHealRotationTargetPool();
|
LeaveHealRotationTargetPool();
|
||||||
|
|||||||
+57
-3
@@ -62,6 +62,7 @@
|
|||||||
#else
|
#else
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern Zone* zone;
|
extern Zone* zone;
|
||||||
@@ -131,6 +132,9 @@ NPC::NPC(const NPCType *npc_type_data, Spawn2 *in_respawn, const glm::vec4 &posi
|
|||||||
),
|
),
|
||||||
attacked_timer(CombatEventTimer_expire),
|
attacked_timer(CombatEventTimer_expire),
|
||||||
swarm_timer(100),
|
swarm_timer(100),
|
||||||
|
m_corpse_queue_timer(1000),
|
||||||
|
m_corpse_queue_shutoff_timer(30000),
|
||||||
|
m_resumed_from_zone_suspend_shutoff_timer(30000),
|
||||||
classattack_timer(1000),
|
classattack_timer(1000),
|
||||||
monkattack_timer(1000),
|
monkattack_timer(1000),
|
||||||
knightattack_timer(1000),
|
knightattack_timer(1000),
|
||||||
@@ -618,7 +622,49 @@ bool NPC::Process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// zone state corpse creation timer
|
||||||
|
if (RuleB(Zone, StateSavingOnShutdown)) {
|
||||||
|
// creates a corpse if the NPC is queued for corpse creation
|
||||||
|
if (m_corpse_queue_timer.Check()) {
|
||||||
|
if (IsQueuedForCorpse()) {
|
||||||
|
auto decay_timer = m_corpse_decay_time;
|
||||||
|
uint16 corpse_id = GetID();
|
||||||
|
Death(this, GetHP() + 1, SPELL_UNKNOWN, EQ::skills::SkillHandtoHand);
|
||||||
|
auto c = entity_list.GetCorpseByID(corpse_id);
|
||||||
|
if (c) {
|
||||||
|
c->UnLock();
|
||||||
|
c->SetDecayTimer(decay_timer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_corpse_queue_timer.Disable();
|
||||||
|
m_corpse_queue_shutoff_timer.Disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
// shuts off the corpse queue timer if it is still running
|
||||||
|
if (m_corpse_queue_shutoff_timer.Check()) {
|
||||||
|
m_corpse_queue_timer.Disable();
|
||||||
|
m_corpse_queue_shutoff_timer.Disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
// shuts off the temporary spawn protected state of the NPC
|
||||||
|
if (m_resumed_from_zone_suspend_shutoff_timer.Check()) {
|
||||||
|
m_resumed_from_zone_suspend_shutoff_timer.Disable();
|
||||||
|
SetResumedFromZoneSuspend(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (tic_timer.Check()) {
|
if (tic_timer.Check()) {
|
||||||
|
if (RuleB(Zone, StateSavingOnShutdown) && IsQueuedForCorpse()) {
|
||||||
|
auto decay_timer = m_corpse_decay_time;
|
||||||
|
uint16 corpse_id = GetID();
|
||||||
|
Death(this, GetHP() + 1, SPELL_UNKNOWN, EQ::skills::SkillHandtoHand);
|
||||||
|
auto c = entity_list.GetCorpseByID(corpse_id);
|
||||||
|
if (c) {
|
||||||
|
c->UnLock();
|
||||||
|
c->SetDecayTimer(decay_timer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
@@ -4269,7 +4315,7 @@ bool NPC::CanPetTakeItem(const EQ::ItemInstance *inst)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsPetOwnerClient() && !IsCharmedPet()) {
|
if (!IsPetOwnerOfClientBot() && !IsCharmedPet()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4351,6 +4397,10 @@ bool NPC::CheckHandin(
|
|||||||
h = m_hand_in;
|
h = m_hand_in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsMultiQuestEnabled()) {
|
||||||
|
LogNpcHandin("{} Multi-Quest hand-in enabled", log_handin_prefix);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::pair<const std::map<std::string, uint32>&, Handin&>> datasets = {};
|
std::vector<std::pair<const std::map<std::string, uint32>&, Handin&>> datasets = {};
|
||||||
|
|
||||||
// if we've already started the hand-in process, we don't want to re-process the hand-in data
|
// if we've already started the hand-in process, we don't want to re-process the hand-in data
|
||||||
@@ -4432,7 +4482,7 @@ bool NPC::CheckHandin(
|
|||||||
|
|
||||||
// multi-quest
|
// multi-quest
|
||||||
if (IsMultiQuestEnabled()) {
|
if (IsMultiQuestEnabled()) {
|
||||||
for (auto &h_item: h.items) {
|
for (auto &h_item: m_hand_in.items) {
|
||||||
for (const auto &r_item: r.items) {
|
for (const auto &r_item: r.items) {
|
||||||
if (h_item.item_id == r_item.item_id && h_item.count == r_item.count) {
|
if (h_item.item_id == r_item.item_id && h_item.count == r_item.count) {
|
||||||
h_item.is_multiquest_item = true;
|
h_item.is_multiquest_item = true;
|
||||||
@@ -4777,7 +4827,11 @@ NPC::Handin NPC::ReturnHandinItems(Client *c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
c->PushItemOnCursor(*i.item, true);
|
c->PushItemOnCursor(*i.item, true);
|
||||||
LogNpcHandin("Hand-in failed, returning item [{}]", i.item->GetItem()->Name);
|
LogNpcHandin(
|
||||||
|
"Hand-in failed, returning item [{}] i.is_multiquest_item [{}]",
|
||||||
|
i.item->GetItem()->Name,
|
||||||
|
i.is_multiquest_item
|
||||||
|
);
|
||||||
|
|
||||||
returned_handin = true;
|
returned_handin = true;
|
||||||
return true; // Mark this item for removal
|
return true; // Mark this item for removal
|
||||||
|
|||||||
+19
@@ -601,6 +601,13 @@ public:
|
|||||||
bool HasProcessedHandinReturn() { return m_has_processed_handin_return; }
|
bool HasProcessedHandinReturn() { return m_has_processed_handin_return; }
|
||||||
bool HandinStarted() { return m_handin_started; }
|
bool HandinStarted() { return m_handin_started; }
|
||||||
|
|
||||||
|
// zone state save
|
||||||
|
inline void SetQueuedToCorpse() { m_queued_for_corpse = true; }
|
||||||
|
inline bool IsQueuedForCorpse() { return m_queued_for_corpse; }
|
||||||
|
inline uint32_t SetCorpseDecayTime(uint32_t decay_time) { return m_corpse_decay_time = decay_time; }
|
||||||
|
inline void SetResumedFromZoneSuspend(bool state = true) { m_resumed_from_zone_suspend = state; }
|
||||||
|
inline bool IsResumedFromZoneSuspend() { return m_resumed_from_zone_suspend; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void HandleRoambox();
|
void HandleRoambox();
|
||||||
@@ -622,6 +629,18 @@ protected:
|
|||||||
uint32 m_loot_platinum;
|
uint32 m_loot_platinum;
|
||||||
LootItems m_loot_items;
|
LootItems m_loot_items;
|
||||||
|
|
||||||
|
// zone state
|
||||||
|
bool m_resumed_from_zone_suspend = false;
|
||||||
|
bool m_queued_for_corpse = false; // this is to check for corpse creation on zone state restore
|
||||||
|
uint32_t m_corpse_decay_time = 0; // decay time set on zone state restore
|
||||||
|
Timer m_corpse_queue_timer = {}; // this is to check for corpse creation on zone state restore
|
||||||
|
Timer m_corpse_queue_shutoff_timer = {};
|
||||||
|
|
||||||
|
// this is a 30-second timer that protects a NPC from having double assignment of loot
|
||||||
|
// this is to prevent a player from killing a NPC and then zoning out and back in to get loot again
|
||||||
|
// if loot was to be assigned via script again, this protects double assignment for 30 seconds
|
||||||
|
Timer m_resumed_from_zone_suspend_shutoff_timer = {};
|
||||||
|
|
||||||
std::list<NpcFactionEntriesRepository::NpcFactionEntries> faction_list;
|
std::list<NpcFactionEntriesRepository::NpcFactionEntries> faction_list;
|
||||||
|
|
||||||
int32 npc_faction_id;
|
int32 npc_faction_id;
|
||||||
|
|||||||
+28
-10
@@ -1142,16 +1142,6 @@ void Perl_Client_SetStartZone(Client* self, uint32 zone_id, float x, float y, fl
|
|||||||
self->SetStartZone(zone_id, x, y, z, heading);
|
self->SetStartZone(zone_id, x, y, z, heading);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Perl_Client_KeyRingAdd(Client* self, uint32 item_id) // @categories Account and Character, Inventory and Items
|
|
||||||
{
|
|
||||||
self->KeyRingAdd(item_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Perl_Client_KeyRingCheck(Client* self, uint32 item_id) // @categories Account and Character, Inventory and Items
|
|
||||||
{
|
|
||||||
return self->KeyRingCheck(item_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Perl_Client_AddPVPPoints(Client* self, uint32 points) // @categories Currency and Points
|
void Perl_Client_AddPVPPoints(Client* self, uint32 points) // @categories Currency and Points
|
||||||
{
|
{
|
||||||
self->AddPVPPoints(points);
|
self->AddPVPPoints(points);
|
||||||
@@ -3306,6 +3296,31 @@ std::string Perl_Client_GetPotionBeltItemName(Client* self, uint8 slot_id)
|
|||||||
return self->GetPotionBeltItemName(slot_id);
|
return self->GetPotionBeltItemName(slot_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Perl_Client_KeyRingAdd(Client* self, uint32 item_id) // @categories Account and Character, Inventory and Items
|
||||||
|
{
|
||||||
|
return self->KeyRingAdd(item_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Perl_Client_KeyRingCheck(Client* self, uint32 item_id) // @categories Account and Character, Inventory and Items
|
||||||
|
{
|
||||||
|
return self->KeyRingCheck(item_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Perl_Client_KeyRingClear(Client* self)
|
||||||
|
{
|
||||||
|
return self->KeyRingClear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Perl_Client_KeyRingList(Client* self)
|
||||||
|
{
|
||||||
|
self->KeyRingList();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Perl_Client_KeyRingRemove(Client* self, uint32 item_id)
|
||||||
|
{
|
||||||
|
return self->KeyRingRemove(item_id);
|
||||||
|
}
|
||||||
|
|
||||||
void perl_register_client()
|
void perl_register_client()
|
||||||
{
|
{
|
||||||
perl::interpreter perl(PERL_GET_THX);
|
perl::interpreter perl(PERL_GET_THX);
|
||||||
@@ -3630,6 +3645,9 @@ void perl_register_client()
|
|||||||
package.add("IsTaskCompleted", &Perl_Client_IsTaskCompleted);
|
package.add("IsTaskCompleted", &Perl_Client_IsTaskCompleted);
|
||||||
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("KeyRingList", &Perl_Client_KeyRingList);
|
||||||
|
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);
|
||||||
package.add("LearnRecipe", &Perl_Client_LearnRecipe);
|
package.add("LearnRecipe", &Perl_Client_LearnRecipe);
|
||||||
|
|||||||
@@ -806,6 +806,11 @@ void Perl_NPC_MultiQuestEnable(NPC* self)
|
|||||||
self->MultiQuestEnable();
|
self->MultiQuestEnable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Perl_NPC_IsResumedFromZoneSuspend(NPC* self)
|
||||||
|
{
|
||||||
|
return self->IsResumedFromZoneSuspend();
|
||||||
|
}
|
||||||
|
|
||||||
bool Perl_NPC_CheckHandin(
|
bool Perl_NPC_CheckHandin(
|
||||||
NPC* self,
|
NPC* self,
|
||||||
Client* c,
|
Client* c,
|
||||||
@@ -983,6 +988,7 @@ void perl_register_npc()
|
|||||||
package.add("IsOnHatelist", &Perl_NPC_IsOnHatelist);
|
package.add("IsOnHatelist", &Perl_NPC_IsOnHatelist);
|
||||||
package.add("IsRaidTarget", &Perl_NPC_IsRaidTarget);
|
package.add("IsRaidTarget", &Perl_NPC_IsRaidTarget);
|
||||||
package.add("IsRareSpawn", &Perl_NPC_IsRareSpawn);
|
package.add("IsRareSpawn", &Perl_NPC_IsRareSpawn);
|
||||||
|
package.add("IsResumedFromZoneSuspend", &Perl_NPC_IsResumedFromZoneSuspend);
|
||||||
package.add("IsTaunting", &Perl_NPC_IsTaunting);
|
package.add("IsTaunting", &Perl_NPC_IsTaunting);
|
||||||
package.add("IsUnderwaterOnly", (bool(*)(NPC*))&Perl_NPC_IsUnderwaterOnly);
|
package.add("IsUnderwaterOnly", (bool(*)(NPC*))&Perl_NPC_IsUnderwaterOnly);
|
||||||
package.add("MerchantCloseShop", &Perl_NPC_MerchantCloseShop);
|
package.add("MerchantCloseShop", &Perl_NPC_MerchantCloseShop);
|
||||||
|
|||||||
+18
-3
@@ -1623,10 +1623,10 @@ void QuestManager::setsky(uint8 new_sky) {
|
|||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QuestManager::setguild(uint32 new_guild_id, uint8 new_rank) {
|
void QuestManager::SetGuild(uint32 new_guild_id, uint8 new_rank) {
|
||||||
QuestManagerCurrentQuestVars();
|
QuestManagerCurrentQuestVars();
|
||||||
if (initiator) {
|
if (initiator) {
|
||||||
guild_mgr.SetGuild(initiator->CharacterID(), new_guild_id, new_rank);
|
guild_mgr.SetGuild(initiator, new_guild_id, new_rank);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1681,7 +1681,7 @@ void QuestManager::CreateGuild(const char *guild_name, const char *leader) {
|
|||||||
gid
|
gid
|
||||||
).c_str()
|
).c_str()
|
||||||
);
|
);
|
||||||
if (!guild_mgr.SetGuild(character_id, gid, GUILD_LEADER)) {
|
if (!guild_mgr.SetGuild(initiator, gid, GUILD_LEADER)) {
|
||||||
worldserver.SendEmoteMessage(
|
worldserver.SendEmoteMessage(
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@@ -4606,3 +4606,18 @@ void QuestManager::SpawnGrid(uint32 npc_id, glm::vec4 position, float spacing, u
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QuestManager::handin(std::map<std::string, uint32> required) {
|
||||||
|
QuestManagerCurrentQuestVars();
|
||||||
|
if (!owner || !initiator) {
|
||||||
|
LogQuests("QuestManager::handin called with nullptr owner. Probably syntax error in quest file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (owner && !owner->IsNPC()) {
|
||||||
|
LogQuests("QuestManager::handin called with non-NPC owner. Probably syntax error in quest file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return owner->CastToNPC()->CheckHandin(initiator, {}, required, {});
|
||||||
|
}
|
||||||
|
|||||||
+2
-1
@@ -152,7 +152,7 @@ public:
|
|||||||
void faction(int faction_id, int faction_value, int temp);
|
void faction(int faction_id, int faction_value, int temp);
|
||||||
void rewardfaction(int faction_id, int faction_value);
|
void rewardfaction(int faction_id, int faction_value);
|
||||||
void setsky(uint8 new_sky);
|
void setsky(uint8 new_sky);
|
||||||
void setguild(uint32 new_guild_id, uint8 new_rank);
|
void SetGuild(uint32 new_guild_id, uint8 new_rank);
|
||||||
void CreateGuild(const char *guild_name, const char *leader);
|
void CreateGuild(const char *guild_name, const char *leader);
|
||||||
void settime(uint8 new_hour, uint8 new_min, bool update_world = true);
|
void settime(uint8 new_hour, uint8 new_min, bool update_world = true);
|
||||||
void itemlink(int item_id);
|
void itemlink(int item_id);
|
||||||
@@ -376,6 +376,7 @@ public:
|
|||||||
bool botquest();
|
bool botquest();
|
||||||
bool createBot(const char *name, const char *lastname, uint8 level, uint16 race, uint8 botclass, uint8 gender);
|
bool createBot(const char *name, const char *lastname, uint8 level, uint16 race, uint8 botclass, uint8 gender);
|
||||||
|
|
||||||
|
bool handin(std::map<std::string, uint32> required);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::stack<running_quest> quests_running_;
|
std::stack<running_quest> quests_running_;
|
||||||
|
|||||||
+16
-5
@@ -16,6 +16,7 @@
|
|||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <cereal/archives/json.hpp>
|
||||||
#include "../common/global_define.h"
|
#include "../common/global_define.h"
|
||||||
#include "../common/strings.h"
|
#include "../common/strings.h"
|
||||||
|
|
||||||
@@ -33,6 +34,7 @@
|
|||||||
#include "../common/repositories/spawn2_repository.h"
|
#include "../common/repositories/spawn2_repository.h"
|
||||||
#include "../common/repositories/spawn2_disabled_repository.h"
|
#include "../common/repositories/spawn2_disabled_repository.h"
|
||||||
#include "../common/repositories/respawn_times_repository.h"
|
#include "../common/repositories/respawn_times_repository.h"
|
||||||
|
#include "../common/repositories/zone_state_spawns_repository.h"
|
||||||
|
|
||||||
extern EntityList entity_list;
|
extern EntityList entity_list;
|
||||||
extern Zone* zone;
|
extern Zone* zone;
|
||||||
@@ -86,7 +88,7 @@ Spawn2::Spawn2(uint32 in_spawn2_id, uint32 spawngroup_id,
|
|||||||
y = in_y;
|
y = in_y;
|
||||||
z = in_z;
|
z = in_z;
|
||||||
heading = in_heading;
|
heading = in_heading;
|
||||||
respawn_ = respawn;
|
m_respawn_time = respawn;
|
||||||
variance_ = variance;
|
variance_ = variance;
|
||||||
grid_ = grid;
|
grid_ = grid;
|
||||||
path_when_zone_idle = in_path_when_zone_idle;
|
path_when_zone_idle = in_path_when_zone_idle;
|
||||||
@@ -95,6 +97,7 @@ Spawn2::Spawn2(uint32 in_spawn2_id, uint32 spawngroup_id,
|
|||||||
npcthis = nullptr;
|
npcthis = nullptr;
|
||||||
enabled = in_enabled;
|
enabled = in_enabled;
|
||||||
this->anim = anim;
|
this->anim = anim;
|
||||||
|
currentnpcid = 0;
|
||||||
|
|
||||||
if(timeleft == 0xFFFFFFFF) {
|
if(timeleft == 0xFFFFFFFF) {
|
||||||
//special disable timeleft
|
//special disable timeleft
|
||||||
@@ -115,7 +118,7 @@ Spawn2::~Spawn2()
|
|||||||
|
|
||||||
uint32 Spawn2::resetTimer()
|
uint32 Spawn2::resetTimer()
|
||||||
{
|
{
|
||||||
uint32 rspawn = respawn_ * 1000;
|
uint32 rspawn = m_respawn_time * 1000;
|
||||||
|
|
||||||
if (variance_ != 0) {
|
if (variance_ != 0) {
|
||||||
int var_over_2 = (variance_ * 1000) / 2;
|
int var_over_2 = (variance_ * 1000) / 2;
|
||||||
@@ -150,12 +153,12 @@ uint32 Spawn2::despawnTimer(uint32 despawn_timer)
|
|||||||
bool Spawn2::Process() {
|
bool Spawn2::Process() {
|
||||||
IsDespawned = false;
|
IsDespawned = false;
|
||||||
|
|
||||||
if (!Enabled())
|
if (!Enabled()) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
//grab our spawn group
|
//grab our spawn group
|
||||||
SpawnGroup *spawn_group = zone->spawn_group_list.GetSpawnGroup(spawngroup_id_);
|
SpawnGroup *spawn_group = zone->spawn_group_list.GetSpawnGroup(spawngroup_id_);
|
||||||
|
|
||||||
if (NPCPointerValid() && (spawn_group && spawn_group->despawn == 0 || condition_id != 0)) {
|
if (NPCPointerValid() && (spawn_group && spawn_group->despawn == 0 || condition_id != 0)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -195,7 +198,7 @@ bool Spawn2::Process() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//have the spawn group pick an NPC for us
|
//have the spawn group pick an NPC for us
|
||||||
uint32 npcid = spawn_group->GetNPCType(condition_value);
|
uint32 npcid = currentnpcid && currentnpcid > 0 ? currentnpcid : spawn_group->GetNPCType(condition_value);
|
||||||
if (npcid == 0) {
|
if (npcid == 0) {
|
||||||
LogSpawns("Spawn2 [{}]: Spawn group [{}] did not yeild an NPC! not spawning", spawn2_id, spawngroup_id_);
|
LogSpawns("Spawn2 [{}]: Spawn group [{}] did not yeild an NPC! not spawning", spawn2_id, spawngroup_id_);
|
||||||
|
|
||||||
@@ -267,10 +270,12 @@ bool Spawn2::Process() {
|
|||||||
NPC *npc = new NPC(tmp, this, glm::vec4(x, y, z, heading), GravityBehavior::Water);
|
NPC *npc = new NPC(tmp, this, glm::vec4(x, y, z, heading), GravityBehavior::Water);
|
||||||
|
|
||||||
npcthis = npc;
|
npcthis = npc;
|
||||||
|
|
||||||
npc->AddLootTable();
|
npc->AddLootTable();
|
||||||
if (npc->DropsGlobalLoot()) {
|
if (npc->DropsGlobalLoot()) {
|
||||||
npc->CheckGlobalLootTables();
|
npc->CheckGlobalLootTables();
|
||||||
}
|
}
|
||||||
|
|
||||||
npc->SetSpawnGroupId(spawngroup_id_);
|
npc->SetSpawnGroupId(spawngroup_id_);
|
||||||
npc->SaveGuardPointAnim(anim);
|
npc->SaveGuardPointAnim(anim);
|
||||||
npc->SetAppearance((EmuAppearance) anim);
|
npc->SetAppearance((EmuAppearance) anim);
|
||||||
@@ -500,6 +505,12 @@ bool ZoneDatabase::PopulateZoneSpawnList(uint32 zoneid, LinkedList<Spawn2*> &spa
|
|||||||
|
|
||||||
NPC::SpawnZoneController();
|
NPC::SpawnZoneController();
|
||||||
|
|
||||||
|
if (RuleB(Zone, StateSavingOnShutdown) && zone->LoadZoneState(spawn_times, disabled_spawns)) {
|
||||||
|
LogZoneState("Loaded zone state for zone [{}] instance_id [{}]", zone_name, zone->GetInstanceID());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// normal spawn2 loading
|
||||||
for (auto &s: spawns) {
|
for (auto &s: spawns) {
|
||||||
uint32 spawn_time_left = 0;
|
uint32 spawn_time_left = 0;
|
||||||
if (spawn_times.count(s.id) != 0) {
|
if (spawn_times.count(s.id) != 0) {
|
||||||
|
|||||||
+9
-3
@@ -55,10 +55,10 @@ public:
|
|||||||
float GetZ() { return z; }
|
float GetZ() { return z; }
|
||||||
float GetHeading() { return heading; }
|
float GetHeading() { return heading; }
|
||||||
bool PathWhenZoneIdle() { return path_when_zone_idle; }
|
bool PathWhenZoneIdle() { return path_when_zone_idle; }
|
||||||
void SetRespawnTimer(uint32 newrespawntime) { respawn_ = newrespawntime; };
|
void SetRespawnTimer(uint32 newrespawntime) { m_respawn_time = newrespawntime; };
|
||||||
void SetVariance(uint32 newvariance) { variance_ = newvariance; }
|
void SetVariance(uint32 newvariance) { variance_ = newvariance; }
|
||||||
const uint32 GetVariance() const { return variance_; }
|
const uint32 GetVariance() const { return variance_; }
|
||||||
uint32 RespawnTimer() { return respawn_; }
|
uint32 RespawnTimer() { return m_respawn_time; }
|
||||||
uint32 SpawnGroupID() { return spawngroup_id_; }
|
uint32 SpawnGroupID() { return spawngroup_id_; }
|
||||||
uint32 CurrentNPCID() { return currentnpcid; }
|
uint32 CurrentNPCID() { return currentnpcid; }
|
||||||
void SetCurrentNPCID(uint32 nid) { currentnpcid = nid; }
|
void SetCurrentNPCID(uint32 nid) { currentnpcid = nid; }
|
||||||
@@ -70,12 +70,18 @@ public:
|
|||||||
Timer GetTimer() { return timer; }
|
Timer GetTimer() { return timer; }
|
||||||
void SetTimer(uint32 duration) { timer.Start(duration); }
|
void SetTimer(uint32 duration) { timer.Start(duration); }
|
||||||
uint32 GetKillCount() { return killcount; }
|
uint32 GetKillCount() { return killcount; }
|
||||||
|
uint32 GetGrid() const { return grid_; }
|
||||||
|
bool GetPathWhenZoneIdle() const { return path_when_zone_idle; }
|
||||||
|
int16 GetConditionMinValue() const { return condition_min_value; }
|
||||||
|
int16 GetAnimation () { return anim; }
|
||||||
|
inline NPC *GetNPC() const { return npcthis; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class Zone;
|
friend class Zone;
|
||||||
Timer timer;
|
Timer timer;
|
||||||
private:
|
private:
|
||||||
uint32 spawn2_id;
|
uint32 spawn2_id;
|
||||||
uint32 respawn_;
|
uint32 m_respawn_time;
|
||||||
uint32 resetTimer();
|
uint32 resetTimer();
|
||||||
uint32 despawnTimer(uint32 despawn_timer);
|
uint32 despawnTimer(uint32 despawn_timer);
|
||||||
|
|
||||||
|
|||||||
@@ -1243,6 +1243,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
case SE_SummonItemIntoBag:
|
case SE_SummonItemIntoBag:
|
||||||
{
|
{
|
||||||
const EQ::ItemData *item = database.GetItem(spell.base_value[i]);
|
const EQ::ItemData *item = database.GetItem(spell.base_value[i]);
|
||||||
|
if (!item) {
|
||||||
|
Message(Chat::Red, "Unable to summon item %d. Item not found.", spell.base_value[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef SPELL_EFFECT_SPAM
|
#ifdef SPELL_EFFECT_SPAM
|
||||||
const char *itemname = item ? item->Name : "*Unknown Item*";
|
const char *itemname = item ? item->Name : "*Unknown Item*";
|
||||||
snprintf(effect_desc, _EDLEN, "Summon Item In Bag: %s (id %d)", itemname, spell.base_value[i]);
|
snprintf(effect_desc, _EDLEN, "Summon Item In Bag: %s (id %d)", itemname, spell.base_value[i]);
|
||||||
|
|||||||
@@ -3135,6 +3135,17 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string& always_stack_spells = RuleS(Spells, AlwaysStackSpells);
|
||||||
|
if (spellid1 != spellid2 && !always_stack_spells.empty()) {
|
||||||
|
const auto& v = Strings::Split(always_stack_spells, ",");
|
||||||
|
if (Strings::Contains(v, std::to_string(spellid1))) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (Strings::Contains(v, std::to_string(spellid2))) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
One of these is a bard song and one isn't and they're both beneficial so they should stack.
|
One of these is a bard song and one isn't and they're both beneficial so they should stack.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -952,6 +952,8 @@ int ClientTaskState::IncrementDoneCount(
|
|||||||
|
|
||||||
client->CancelTask(task_index, task_data->type);
|
client->CancelTask(task_index, task_data->type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client->LoadClientSharedCompletedTasks();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -1561,7 +1563,7 @@ int ClientTaskState::TaskTimeLeft(int task_id)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ClientTaskState::IsTaskCompleted(int task_id)
|
bool ClientTaskState::IsTaskCompleted(int task_id, Client *c)
|
||||||
{
|
{
|
||||||
if (!RuleB(TaskSystem, RecordCompletedTasks)) {
|
if (!RuleB(TaskSystem, RecordCompletedTasks)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -1574,6 +1576,14 @@ bool ClientTaskState::IsTaskCompleted(int task_id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (c) {
|
||||||
|
for (auto &e: c->GetCompletedSharedTasks()) {
|
||||||
|
if (e == task_id) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ public:
|
|||||||
void AcceptNewTask(Client *client, int task_id, int npc_type_id, time_t accept_time, bool enforce_level_requirement = false);
|
void AcceptNewTask(Client *client, int task_id, int npc_type_id, time_t accept_time, bool enforce_level_requirement = false);
|
||||||
void FailTask(Client *client, int task_id);
|
void FailTask(Client *client, int task_id);
|
||||||
int TaskTimeLeft(int task_id);
|
int TaskTimeLeft(int task_id);
|
||||||
bool IsTaskCompleted(int task_id);
|
bool IsTaskCompleted(int task_id, Client *c = nullptr);
|
||||||
bool AreTasksCompleted(const std::vector<int>& task_ids);
|
bool AreTasksCompleted(const std::vector<int>& task_ids);
|
||||||
bool IsTaskActive(int task_id);
|
bool IsTaskActive(int task_id);
|
||||||
bool IsTaskActivityActive(int task_id, int activity_id);
|
bool IsTaskActivityActive(int task_id, int activity_id);
|
||||||
|
|||||||
+2
-1
@@ -15,8 +15,9 @@ extern QueryServ *QServ;
|
|||||||
void Client::LoadClientTaskState()
|
void Client::LoadClientTaskState()
|
||||||
{
|
{
|
||||||
if (RuleB(TaskSystem, EnableTaskSystem) && task_manager) {
|
if (RuleB(TaskSystem, EnableTaskSystem) && task_manager) {
|
||||||
safe_delete(task_state);
|
LoadClientSharedCompletedTasks();
|
||||||
|
|
||||||
|
safe_delete(task_state);
|
||||||
task_state = new ClientTaskState();
|
task_state = new ClientTaskState();
|
||||||
if (!task_manager->LoadClientState(this, task_state)) {
|
if (!task_manager->LoadClientState(this, task_state)) {
|
||||||
safe_delete(task_state);
|
safe_delete(task_state);
|
||||||
|
|||||||
+8
-8
@@ -57,34 +57,34 @@ EQApplicationPacket* TitleManager::MakeTitlesPacket(Client* c)
|
|||||||
return outapp;
|
return outapp;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string TitleManager::GetPrefix(int title_set)
|
std::string TitleManager::GetPrefix(int title_id)
|
||||||
{
|
{
|
||||||
if (!title_set) {
|
if (!title_id) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
auto e = std::find_if(
|
auto e = std::find_if(
|
||||||
titles.begin(),
|
titles.begin(),
|
||||||
titles.end(),
|
titles.end(),
|
||||||
[title_set](const auto& t) {
|
[title_id](const auto& t) {
|
||||||
return t.title_set == title_set;
|
return t.id == title_id;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return e != titles.end() ? e->prefix : "";
|
return e != titles.end() ? e->prefix : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string TitleManager::GetSuffix(int title_set)
|
std::string TitleManager::GetSuffix(int title_id)
|
||||||
{
|
{
|
||||||
if (!title_set) {
|
if (!title_id) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
auto e = std::find_if(
|
auto e = std::find_if(
|
||||||
titles.begin(),
|
titles.begin(),
|
||||||
titles.end(),
|
titles.end(),
|
||||||
[title_set](const auto& t) {
|
[title_id](const auto& t) {
|
||||||
return t.title_set == title_set;
|
return t.id == title_id;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -15,8 +15,8 @@ public:
|
|||||||
bool LoadTitles();
|
bool LoadTitles();
|
||||||
|
|
||||||
EQApplicationPacket* MakeTitlesPacket(Client* c);
|
EQApplicationPacket* MakeTitlesPacket(Client* c);
|
||||||
std::string GetPrefix(int title_set);
|
std::string GetPrefix(int title_id);
|
||||||
std::string GetSuffix(int title_set);
|
std::string GetSuffix(int title_id);
|
||||||
std::vector<TitlesRepository::Titles> GetEligibleTitles(Client* c);
|
std::vector<TitlesRepository::Titles> GetEligibleTitles(Client* c);
|
||||||
bool IsNewAATitleAvailable(int aa_points, int class_id);
|
bool IsNewAATitleAvailable(int aa_points, int class_id);
|
||||||
bool IsNewTradeSkillTitleAvailable(int t, int skill_value);
|
bool IsNewTradeSkillTitleAvailable(int t, int skill_value);
|
||||||
|
|||||||
+23
-3
@@ -551,7 +551,7 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
|
|||||||
|
|
||||||
auto with = tradingWith->CastToNPC();
|
auto with = tradingWith->CastToNPC();
|
||||||
const EQ::ItemData *item = inst->GetItem();
|
const EQ::ItemData *item = inst->GetItem();
|
||||||
const bool is_pet = with->IsPetOwnerClient() || with->IsCharmedPet();
|
const bool is_pet = with->IsPetOwnerOfClientBot() || with->IsCharmedPet();
|
||||||
if (is_pet && with->CanPetTakeItem(inst)) {
|
if (is_pet && with->CanPetTakeItem(inst)) {
|
||||||
// pets need to look inside bags and try to equip items found there
|
// pets need to look inside bags and try to equip items found there
|
||||||
if (item->IsClassBag() && item->BagSlots > 0) {
|
if (item->IsClassBag() && item->BagSlots > 0) {
|
||||||
@@ -618,16 +618,36 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
|
|||||||
item_list.emplace_back(inst);
|
item_list.emplace_back(inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto handin_npc = tradingWith->CastToNPC();
|
||||||
|
|
||||||
m_external_handin_money_returned = {};
|
m_external_handin_money_returned = {};
|
||||||
m_external_handin_items_returned = {};
|
m_external_handin_items_returned = {};
|
||||||
bool has_aggro = tradingWith->CheckAggro(this);
|
bool has_aggro = tradingWith->CheckAggro(this);
|
||||||
if (parse->HasQuestSub(tradingWith->GetNPCTypeID(), EVENT_TRADE) && !has_aggro) {
|
if (parse->HasQuestSub(tradingWith->GetNPCTypeID(), EVENT_TRADE) && !has_aggro) {
|
||||||
|
// This CheckHandin call enables eq.handin and quest::handin to recognize the hand-in context.
|
||||||
|
// It initializes the first hand-in bucket, which is then reused for the EVENT_TRADE subroutine.
|
||||||
|
std::map<std::string, uint32> handin = {
|
||||||
|
{"copper", trade->cp},
|
||||||
|
{"silver", trade->sp},
|
||||||
|
{"gold", trade->gp},
|
||||||
|
{"platinum", trade->pp}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (EQ::ItemInstance *inst: items) {
|
||||||
|
if (!inst || !inst->GetItem()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string item_id = fmt::format("{}", inst->GetItem()->ID);
|
||||||
|
handin[item_id] += inst->GetCharges();
|
||||||
|
}
|
||||||
|
|
||||||
|
handin_npc->CheckHandin(this, handin, {}, items);
|
||||||
|
|
||||||
parse->EventNPC(EVENT_TRADE, tradingWith->CastToNPC(), this, "", 0, &item_list);
|
parse->EventNPC(EVENT_TRADE, tradingWith->CastToNPC(), this, "", 0, &item_list);
|
||||||
LogNpcHandinDetail("EVENT_TRADE triggered for NPC [{}]", tradingWith->GetNPCTypeID());
|
LogNpcHandinDetail("EVENT_TRADE triggered for NPC [{}]", tradingWith->GetNPCTypeID());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto handin_npc = tradingWith->CastToNPC();
|
|
||||||
|
|
||||||
// this is a catch-all return for items that weren't consumed by the EVENT_TRADE subroutine
|
// this is a catch-all return for items that weren't consumed by the EVENT_TRADE subroutine
|
||||||
// it's possible we have a quest NPC that doesn't have an EVENT_TRADE subroutine
|
// it's possible we have a quest NPC that doesn't have an EVENT_TRADE subroutine
|
||||||
// we can't double fire the ReturnHandinItems() event, so we need to check if it's already been processed from EVENT_TRADE
|
// we can't double fire the ReturnHandinItems() event, so we need to check if it's already been processed from EVENT_TRADE
|
||||||
|
|||||||
+7
-10
@@ -591,7 +591,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
|||||||
|
|
||||||
auto *s = (ServerZoneStateChange_Struct *) pack->pBuffer;
|
auto *s = (ServerZoneStateChange_Struct *) pack->pBuffer;
|
||||||
LogInfo("Zone shutdown by {}.", s->admin_name);
|
LogInfo("Zone shutdown by {}.", s->admin_name);
|
||||||
Zone::Shutdown();
|
zone->Shutdown();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -4500,13 +4500,6 @@ void WorldServer::QueueReload(ServerReload::Request r)
|
|||||||
m_reload_mutex.lock();
|
m_reload_mutex.lock();
|
||||||
int64_t reload_at = r.reload_at_unix - std::time(nullptr);
|
int64_t reload_at = r.reload_at_unix - std::time(nullptr);
|
||||||
|
|
||||||
// If the reload is set to happen now, process it immediately versus queuing it
|
|
||||||
if (reload_at <= 0) {
|
|
||||||
ProcessReload(r);
|
|
||||||
m_reload_mutex.unlock();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LogInfo(
|
LogInfo(
|
||||||
"Queuing reload for [{}] ({}) to reload in [{}]",
|
"Queuing reload for [{}] ({}) to reload in [{}]",
|
||||||
ServerReload::GetName(r.type),
|
ServerReload::GetName(r.type),
|
||||||
@@ -4668,16 +4661,20 @@ void WorldServer::ProcessReload(const ServerReload::Request& request)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ServerReload::Type::WorldRepop:
|
case ServerReload::Type::WorldRepop:
|
||||||
entity_list.ClearAreas();
|
|
||||||
parse->ReloadQuests();
|
parse->ReloadQuests();
|
||||||
|
if (zone && zone->IsLoaded()) {
|
||||||
|
entity_list.ClearAreas();
|
||||||
zone->Repop();
|
zone->Repop();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ServerReload::Type::WorldWithRespawn:
|
case ServerReload::Type::WorldWithRespawn:
|
||||||
entity_list.ClearAreas();
|
|
||||||
parse->ReloadQuests();
|
parse->ReloadQuests();
|
||||||
|
if (zone && zone->IsLoaded()) {
|
||||||
|
entity_list.ClearAreas();
|
||||||
zone->Repop();
|
zone->Repop();
|
||||||
zone->ClearSpawnTimers();
|
zone->ClearSpawnTimers();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ServerReload::Type::ZonePoints:
|
case ServerReload::Type::ZonePoints:
|
||||||
|
|||||||
+38
-21
@@ -64,6 +64,7 @@
|
|||||||
#include "../common/repositories/ldon_trap_templates_repository.h"
|
#include "../common/repositories/ldon_trap_templates_repository.h"
|
||||||
#include "../common/repositories/respawn_times_repository.h"
|
#include "../common/repositories/respawn_times_repository.h"
|
||||||
#include "../common/repositories/npc_emotes_repository.h"
|
#include "../common/repositories/npc_emotes_repository.h"
|
||||||
|
#include "../common/repositories/zone_state_spawns_repository.h"
|
||||||
#include "../common/serverinfo.h"
|
#include "../common/serverinfo.h"
|
||||||
#include "../common/repositories/merc_stance_entries_repository.h"
|
#include "../common/repositories/merc_stance_entries_repository.h"
|
||||||
#include "../common/repositories/alternate_currency_repository.h"
|
#include "../common/repositories/alternate_currency_repository.h"
|
||||||
@@ -880,57 +881,66 @@ void Zone::Shutdown(bool quiet)
|
|||||||
}
|
}
|
||||||
|
|
||||||
DataBucket::DeleteCachedBuckets(DataBucketLoadType::Zone, zone->GetZoneID(), zone->GetInstanceID());
|
DataBucket::DeleteCachedBuckets(DataBucketLoadType::Zone, zone->GetZoneID(), zone->GetInstanceID());
|
||||||
|
// save and kick all clients
|
||||||
|
for (auto c : entity_list.GetClientList()) {
|
||||||
|
c.second->Save();
|
||||||
|
c.second->WorldKick();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RuleB(Zone, StateSavingOnShutdown)) {
|
||||||
|
SaveZoneState();
|
||||||
|
}
|
||||||
|
|
||||||
entity_list.StopMobAI();
|
entity_list.StopMobAI();
|
||||||
|
|
||||||
std::map<uint32, NPCType *>::iterator itr;
|
std::map<uint32, NPCType *>::iterator itr;
|
||||||
while (!zone->npctable.empty()) {
|
while (!npctable.empty()) {
|
||||||
itr = zone->npctable.begin();
|
itr = npctable.begin();
|
||||||
delete itr->second;
|
delete itr->second;
|
||||||
itr->second = nullptr;
|
itr->second = nullptr;
|
||||||
zone->npctable.erase(itr);
|
npctable.erase(itr);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!zone->merctable.empty()) {
|
while (!merctable.empty()) {
|
||||||
itr = zone->merctable.begin();
|
itr = merctable.begin();
|
||||||
delete itr->second;
|
delete itr->second;
|
||||||
itr->second = nullptr;
|
itr->second = nullptr;
|
||||||
zone->merctable.erase(itr);
|
merctable.erase(itr);
|
||||||
}
|
}
|
||||||
|
|
||||||
zone->adventure_entry_list_flavor.clear();
|
adventure_entry_list_flavor.clear();
|
||||||
|
|
||||||
std::map<uint32, LDoNTrapTemplate *>::iterator itr4;
|
std::map<uint32, LDoNTrapTemplate *>::iterator itr4;
|
||||||
while (!zone->ldon_trap_list.empty()) {
|
while (!ldon_trap_list.empty()) {
|
||||||
itr4 = zone->ldon_trap_list.begin();
|
itr4 = ldon_trap_list.begin();
|
||||||
delete itr4->second;
|
delete itr4->second;
|
||||||
itr4->second = nullptr;
|
itr4->second = nullptr;
|
||||||
zone->ldon_trap_list.erase(itr4);
|
ldon_trap_list.erase(itr4);
|
||||||
}
|
}
|
||||||
zone->ldon_trap_entry_list.clear();
|
ldon_trap_entry_list.clear();
|
||||||
|
|
||||||
LogInfo(
|
LogInfo(
|
||||||
"Zone [{}] zone_id [{}] version [{}] instance_id [{}]",
|
"Zone [{}] zone_id [{}] version [{}] instance_id [{}]",
|
||||||
zone->GetShortName(),
|
GetShortName(),
|
||||||
zone->GetZoneID(),
|
GetZoneID(),
|
||||||
zone->GetInstanceVersion(),
|
GetInstanceVersion(),
|
||||||
zone->GetInstanceID()
|
GetInstanceID()
|
||||||
);
|
);
|
||||||
petition_list.ClearPetitions();
|
petition_list.ClearPetitions();
|
||||||
zone->SetZoneHasCurrentTime(false);
|
SetZoneHasCurrentTime(false);
|
||||||
if (!quiet) {
|
if (!quiet) {
|
||||||
LogInfo(
|
LogInfo(
|
||||||
"Zone [{}] zone_id [{}] version [{}] instance_id [{}] Going to sleep",
|
"Zone [{}] zone_id [{}] version [{}] instance_id [{}] Going to sleep",
|
||||||
zone->GetShortName(),
|
GetShortName(),
|
||||||
zone->GetZoneID(),
|
GetZoneID(),
|
||||||
zone->GetInstanceVersion(),
|
GetInstanceVersion(),
|
||||||
zone->GetInstanceID()
|
GetInstanceID()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
is_zone_loaded = false;
|
is_zone_loaded = false;
|
||||||
|
|
||||||
zone->ResetAuth();
|
ResetAuth();
|
||||||
safe_delete(zone);
|
safe_delete(zone);
|
||||||
entity_list.ClearAreas();
|
entity_list.ClearAreas();
|
||||||
parse->ReloadQuests(true);
|
parse->ReloadQuests(true);
|
||||||
@@ -1099,6 +1109,8 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Zone::~Zone() {
|
Zone::~Zone() {
|
||||||
|
LogInfo("Zone destructor called for zone [{}]", short_name);
|
||||||
|
|
||||||
spawn2_list.Clear();
|
spawn2_list.Clear();
|
||||||
if (worldserver.Connected()) {
|
if (worldserver.Connected()) {
|
||||||
worldserver.SetZoneData(0);
|
worldserver.SetZoneData(0);
|
||||||
@@ -1926,6 +1938,10 @@ void Zone::Repop(bool is_forced)
|
|||||||
|
|
||||||
spawn_conditions.LoadSpawnConditions(short_name, instanceid);
|
spawn_conditions.LoadSpawnConditions(short_name, instanceid);
|
||||||
|
|
||||||
|
if (RuleB(Zone, StateSavingOnShutdown)) {
|
||||||
|
ClearZoneState(zoneid, instanceid);
|
||||||
|
}
|
||||||
|
|
||||||
if (!content_db.PopulateZoneSpawnList(zoneid, spawn2_list, GetInstanceVersion())) {
|
if (!content_db.PopulateZoneSpawnList(zoneid, spawn2_list, GetInstanceVersion())) {
|
||||||
LogDebug("Error in Zone::Repop: database.PopulateZoneSpawnList failed");
|
LogDebug("Error in Zone::Repop: database.PopulateZoneSpawnList failed");
|
||||||
}
|
}
|
||||||
@@ -3202,4 +3218,5 @@ void Zone::DisableRespawnTimers()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "zone_save_state.cpp"
|
||||||
#include "zone_loot.cpp"
|
#include "zone_loot.cpp"
|
||||||
|
|||||||
+12
-1
@@ -47,6 +47,8 @@
|
|||||||
#include "../common/repositories/lootdrop_entries_repository.h"
|
#include "../common/repositories/lootdrop_entries_repository.h"
|
||||||
#include "../common/repositories/base_data_repository.h"
|
#include "../common/repositories/base_data_repository.h"
|
||||||
#include "../common/repositories/skill_caps_repository.h"
|
#include "../common/repositories/skill_caps_repository.h"
|
||||||
|
#include "../common/repositories/zone_state_spawns_repository.h"
|
||||||
|
#include "../common/repositories/spawn2_disabled_repository.h"
|
||||||
|
|
||||||
struct EXPModifier
|
struct EXPModifier
|
||||||
{
|
{
|
||||||
@@ -104,7 +106,7 @@ class MobMovementManager;
|
|||||||
class Zone {
|
class Zone {
|
||||||
public:
|
public:
|
||||||
static bool Bootup(uint32 iZoneID, uint32 iInstanceID, bool is_static = false);
|
static bool Bootup(uint32 iZoneID, uint32 iInstanceID, bool is_static = false);
|
||||||
static void Shutdown(bool quiet = false);
|
void Shutdown(bool quiet = false);
|
||||||
|
|
||||||
Zone(uint32 in_zoneid, uint32 in_instanceid, const char *in_short_name);
|
Zone(uint32 in_zoneid, uint32 in_instanceid, const char *in_short_name);
|
||||||
~Zone();
|
~Zone();
|
||||||
@@ -438,6 +440,7 @@ public:
|
|||||||
// loot
|
// loot
|
||||||
void LoadLootTable(const uint32 loottable_id);
|
void LoadLootTable(const uint32 loottable_id);
|
||||||
void LoadLootTables(const std::vector<uint32> in_loottable_ids);
|
void LoadLootTables(const std::vector<uint32> in_loottable_ids);
|
||||||
|
void LoadLootDrops(const std::vector<uint32> in_lootdrop_ids);
|
||||||
void ClearLootTables();
|
void ClearLootTables();
|
||||||
void ReloadLootTables();
|
void ReloadLootTables();
|
||||||
LoottableRepository::Loottable *GetLootTable(const uint32 loottable_id);
|
LoottableRepository::Loottable *GetLootTable(const uint32 loottable_id);
|
||||||
@@ -460,6 +463,14 @@ public:
|
|||||||
inline void SetZoneServerId(uint32 id) { m_zone_server_id = id; }
|
inline void SetZoneServerId(uint32 id) { m_zone_server_id = id; }
|
||||||
inline uint32 GetZoneServerId() const { return m_zone_server_id; }
|
inline uint32 GetZoneServerId() const { return m_zone_server_id; }
|
||||||
|
|
||||||
|
// zone state
|
||||||
|
bool LoadZoneState(
|
||||||
|
std::unordered_map<uint32, uint32> spawn_times,
|
||||||
|
std::vector<Spawn2DisabledRepository::Spawn2Disabled> disabled_spawns
|
||||||
|
);
|
||||||
|
void SaveZoneState();
|
||||||
|
static void ClearZoneState(uint32 zone_id, uint32 instance_id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool allow_mercs;
|
bool allow_mercs;
|
||||||
bool can_bind;
|
bool can_bind;
|
||||||
|
|||||||
@@ -300,3 +300,92 @@ std::vector<LootdropEntriesRepository::LootdropEntries> Zone::GetLootdropEntries
|
|||||||
return entries;
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Zone::LoadLootDrops(const std::vector<uint32> in_lootdrop_ids)
|
||||||
|
{
|
||||||
|
BenchTimer timer;
|
||||||
|
|
||||||
|
// copy lootdrop_ids
|
||||||
|
std::vector<uint32> lootdrop_ids = in_lootdrop_ids;
|
||||||
|
|
||||||
|
// check if lootdrop is already loaded
|
||||||
|
std::vector<uint32> loaded_drops = {};
|
||||||
|
for (const auto &e: lootdrop_ids) {
|
||||||
|
for (const auto &f: m_lootdrops) {
|
||||||
|
if (e == f.id) {
|
||||||
|
LogLootDetail("Lootdrop [{}] already loaded", e);
|
||||||
|
loaded_drops.push_back(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove loaded drops from lootdrop_ids
|
||||||
|
for (const auto &e: loaded_drops) {
|
||||||
|
lootdrop_ids.erase(
|
||||||
|
std::remove(
|
||||||
|
lootdrop_ids.begin(),
|
||||||
|
lootdrop_ids.end(),
|
||||||
|
e
|
||||||
|
),
|
||||||
|
lootdrop_ids.end()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lootdrop_ids.empty()) {
|
||||||
|
LogLootDetail("No lootdrops to load");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lootdrops = LootdropRepository::GetWhere(
|
||||||
|
content_db,
|
||||||
|
fmt::format(
|
||||||
|
"id IN ({})",
|
||||||
|
Strings::Join(lootdrop_ids, ",")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
auto lootdrop_entries = LootdropEntriesRepository::GetWhere(
|
||||||
|
content_db,
|
||||||
|
fmt::format(
|
||||||
|
"lootdrop_id IN ({})",
|
||||||
|
Strings::Join(lootdrop_ids, ",")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// emplace back drops to m_lootdrops if not exists
|
||||||
|
for (const auto &e: lootdrops) {
|
||||||
|
bool has_drop = false;
|
||||||
|
|
||||||
|
for (const auto &l: m_lootdrops) {
|
||||||
|
if (e.id == l.id) {
|
||||||
|
has_drop = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_entry = false;
|
||||||
|
if (!has_drop) {
|
||||||
|
// add lootdrop
|
||||||
|
m_lootdrops.emplace_back(e);
|
||||||
|
|
||||||
|
// add lootdrop entries
|
||||||
|
for (const auto &f: lootdrop_entries) {
|
||||||
|
if (e.id == f.lootdrop_id) {
|
||||||
|
|
||||||
|
// check if lootdrop entry already exists in memory
|
||||||
|
has_entry = false;
|
||||||
|
for (const auto &g: m_lootdrop_entries) {
|
||||||
|
if (f.lootdrop_id == g.lootdrop_id && f.item_id == g.item_id && f.multiplier == g.multiplier) {
|
||||||
|
has_entry = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lootdrop_ids.empty()) {
|
||||||
|
LogInfo("Loaded [{}] lootdrops ({}s)", m_lootdrops.size(), std::to_string(timer.elapsed()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,587 @@
|
|||||||
|
#include <string>
|
||||||
|
#include <cereal/archives/json.hpp>
|
||||||
|
#include <cereal/types/map.hpp>
|
||||||
|
#include "npc.h"
|
||||||
|
#include "corpse.h"
|
||||||
|
#include "zone.h"
|
||||||
|
#include "../common/repositories/zone_state_spawns_repository.h"
|
||||||
|
#include "../common/repositories/spawn2_disabled_repository.h"
|
||||||
|
|
||||||
|
struct LootEntryStateData {
|
||||||
|
uint32 item_id;
|
||||||
|
uint32_t lootdrop_id;
|
||||||
|
uint16 charges = 0; // used in dynamically added loot (AddItem)
|
||||||
|
|
||||||
|
// cereal
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive &ar)
|
||||||
|
{
|
||||||
|
ar(
|
||||||
|
CEREAL_NVP(item_id),
|
||||||
|
CEREAL_NVP(lootdrop_id),
|
||||||
|
CEREAL_NVP(charges)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LootStateData {
|
||||||
|
uint32 copper = 0;
|
||||||
|
uint32 silver = 0;
|
||||||
|
uint32 gold = 0;
|
||||||
|
uint32 platinum = 0;
|
||||||
|
std::vector<LootEntryStateData> entries = {};
|
||||||
|
|
||||||
|
// cereal
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive &ar)
|
||||||
|
{
|
||||||
|
ar(
|
||||||
|
CEREAL_NVP(copper),
|
||||||
|
CEREAL_NVP(silver),
|
||||||
|
CEREAL_NVP(gold),
|
||||||
|
CEREAL_NVP(platinum),
|
||||||
|
CEREAL_NVP(entries)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool IsValidJson(const std::string& json) {
|
||||||
|
rapidjson::Document doc;
|
||||||
|
rapidjson::ParseResult result = doc.Parse(json.c_str());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void LoadLootStateData(Zone *zone, NPC *npc, const std::string &loot_data)
|
||||||
|
{
|
||||||
|
LootStateData l{};
|
||||||
|
|
||||||
|
if (!IsValidJson(loot_data)) {
|
||||||
|
LogZoneState("Invalid JSON data for NPC [{}]", npc->GetNPCTypeID());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
std::stringstream ss;
|
||||||
|
{
|
||||||
|
ss << loot_data;
|
||||||
|
cereal::JSONInputArchive ar(ss);
|
||||||
|
l.serialize(ar);
|
||||||
|
}
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
LogZoneState("Failed to load loot state data for NPC [{}] [{}]", npc->GetNPCTypeID(), e.what());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
npc->AddLootCash(l.copper, l.silver, l.gold, l.platinum);
|
||||||
|
|
||||||
|
for (auto &e: l.entries) {
|
||||||
|
const auto *db_item = database.GetItem(e.item_id);
|
||||||
|
if (!db_item) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dynamically added via AddItem
|
||||||
|
if (e.lootdrop_id == 0) {
|
||||||
|
npc->AddItem(e.item_id, e.charges);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto entries = zone->GetLootdropEntries(e.lootdrop_id);
|
||||||
|
if (entries.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LootdropEntriesRepository::LootdropEntries lootdrop_entry;
|
||||||
|
|
||||||
|
for (auto &le: entries) {
|
||||||
|
if (e.item_id == le.item_id) {
|
||||||
|
lootdrop_entry = le;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
npc->AddLootDrop(db_item, lootdrop_entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string GetLootSerialized(NPC *npc)
|
||||||
|
{
|
||||||
|
LootStateData ls = {};
|
||||||
|
auto loot_items = npc->GetLootItems(); // Assuming this returns a list of loot items
|
||||||
|
ls.copper = npc->GetCopper();
|
||||||
|
ls.silver = npc->GetSilver();
|
||||||
|
ls.gold = npc->GetGold();
|
||||||
|
ls.platinum = npc->GetPlatinum();
|
||||||
|
ls.entries.reserve(loot_items.size());
|
||||||
|
|
||||||
|
for (auto &l: loot_items) {
|
||||||
|
ls.entries.emplace_back(
|
||||||
|
LootEntryStateData{
|
||||||
|
.item_id = l->item_id,
|
||||||
|
.lootdrop_id = l->lootdrop_id,
|
||||||
|
.charges = l->charges,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
std::stringstream ss;
|
||||||
|
{
|
||||||
|
cereal::JSONOutputArchiveSingleLine ar(ss);
|
||||||
|
ls.serialize(ar);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ss.str();
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
LogZoneState("Failed to serialize loot data for NPC [{}] [{}]", npc->GetNPCTypeID(), e.what());
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string GetLootSerialized(Corpse *c)
|
||||||
|
{
|
||||||
|
LootStateData ls = {};
|
||||||
|
auto loot_items = c->GetLootItems(); // Assuming this returns a list of loot items
|
||||||
|
ls.copper = c->GetCopper();
|
||||||
|
ls.silver = c->GetSilver();
|
||||||
|
ls.gold = c->GetGold();
|
||||||
|
ls.platinum = c->GetPlatinum();
|
||||||
|
ls.entries.reserve(loot_items.size());
|
||||||
|
|
||||||
|
for (auto &l: loot_items) {
|
||||||
|
ls.entries.emplace_back(
|
||||||
|
LootEntryStateData{
|
||||||
|
.item_id = l->item_id,
|
||||||
|
.lootdrop_id = l->lootdrop_id,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
std::stringstream ss;
|
||||||
|
{
|
||||||
|
cereal::JSONOutputArchiveSingleLine ar(ss);
|
||||||
|
ls.serialize(ar);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ss.str();
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
LogZoneState("Failed to serialize loot data for Corpse [{}] [{}]", c->GetID(), e.what());
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void LoadNPCEntityVariables(NPC *n, const std::string &entity_variables)
|
||||||
|
{
|
||||||
|
if (!IsValidJson(entity_variables)) {
|
||||||
|
LogZoneState("Invalid JSON data for NPC [{}]", n->GetNPCTypeID());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::string, std::string> deserialized_map;
|
||||||
|
try {
|
||||||
|
std::istringstream is(entity_variables);
|
||||||
|
{
|
||||||
|
cereal::JSONInputArchive archive(is);
|
||||||
|
archive(deserialized_map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception &e) {
|
||||||
|
LogZoneState("Failed to load entity variables for NPC [{}] [{}]", n->GetNPCTypeID(), e.what());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &[key, value]: deserialized_map) {
|
||||||
|
n->SetEntityVariable(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void LoadNPCBuffs(NPC *n, const std::string &buffs)
|
||||||
|
{
|
||||||
|
if (!IsValidJson(buffs)) {
|
||||||
|
LogZoneState("Invalid JSON data for NPC [{}]", n->GetNPCTypeID());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Buffs_Struct> valid_buffs;
|
||||||
|
try {
|
||||||
|
std::istringstream is(buffs);
|
||||||
|
{
|
||||||
|
cereal::JSONInputArchive archive(is);
|
||||||
|
archive(cereal::make_nvp("buffs", valid_buffs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception &e) {
|
||||||
|
LogZoneState("Failed to load entity variables for NPC [{}] [{}]", n->GetNPCTypeID(), e.what());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &b: valid_buffs) {
|
||||||
|
// int AddBuff(Mob *caster, const uint16 spell_id, int duration = 0, int32 level_override = -1, bool disable_buff_overwrite = false);
|
||||||
|
n->AddBuff(n, b.spellid, b.ticsremaining, b.casterlevel, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::vector<uint32_t> GetLootdropIds(const std::vector<ZoneStateSpawnsRepository::ZoneStateSpawns> &spawn_states)
|
||||||
|
{
|
||||||
|
LogInfo("Loading lootdrop ids for zone state spawns");
|
||||||
|
|
||||||
|
std::vector<uint32_t> lootdrop_ids;
|
||||||
|
for (auto &s: spawn_states) {
|
||||||
|
if (s.loot_data.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LootStateData l{};
|
||||||
|
try {
|
||||||
|
std::stringstream ss;
|
||||||
|
{
|
||||||
|
ss << s.loot_data;
|
||||||
|
cereal::JSONInputArchive ar(ss);
|
||||||
|
l.serialize(ar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception &e) {
|
||||||
|
LogZoneState("Failed to load loot state data for spawn2 [{}] [{}]", s.id, e.what());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &e: l.entries) {
|
||||||
|
// make sure it isn't already in the list
|
||||||
|
if (std::find(lootdrop_ids.begin(), lootdrop_ids.end(), e.lootdrop_id) == lootdrop_ids.end()) {
|
||||||
|
lootdrop_ids.push_back(e.lootdrop_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LogInfo("Loaded [{}] lootdrop id(s)", lootdrop_ids.size());
|
||||||
|
|
||||||
|
return lootdrop_ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void LoadNPCState(Zone *zone, NPC *n, ZoneStateSpawnsRepository::ZoneStateSpawns &s)
|
||||||
|
{
|
||||||
|
n->SetHP(s.hp);
|
||||||
|
n->SetMana(s.mana);
|
||||||
|
n->SetEndurance(s.endurance);
|
||||||
|
|
||||||
|
if (s.grid) {
|
||||||
|
n->AssignWaypoints(s.grid, s.current_waypoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadLootStateData(zone, n, s.loot_data);
|
||||||
|
LoadNPCEntityVariables(n, s.entity_variables);
|
||||||
|
LoadNPCBuffs(n, s.buffs);
|
||||||
|
|
||||||
|
if (s.is_corpse) {
|
||||||
|
auto decay_time = s.decay_in_seconds * 1000;
|
||||||
|
if (decay_time > 0) {
|
||||||
|
n->SetQueuedToCorpse();
|
||||||
|
n->SetCorpseDecayTime(decay_time);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
n->Depop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
n->SetResumedFromZoneSuspend(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Zone::LoadZoneState(
|
||||||
|
std::unordered_map<uint32, uint32> spawn_times,
|
||||||
|
std::vector<Spawn2DisabledRepository::Spawn2Disabled> disabled_spawns
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto spawn_states = ZoneStateSpawnsRepository::GetWhere(
|
||||||
|
database,
|
||||||
|
fmt::format(
|
||||||
|
"zone_id = {} AND instance_id = {}",
|
||||||
|
zoneid,
|
||||||
|
zone->GetInstanceID()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
LogInfo("Loading zone state spawns for zone [{}] spawns [{}]", GetShortName(), spawn_states.size());
|
||||||
|
|
||||||
|
std::vector<uint32_t> lootdrop_ids = GetLootdropIds(spawn_states);
|
||||||
|
zone->LoadLootDrops(lootdrop_ids);
|
||||||
|
|
||||||
|
// we have to load grids first otherwise setting grid/wp will not work
|
||||||
|
zone->initgrids_timer.Trigger();
|
||||||
|
zone->Process();
|
||||||
|
|
||||||
|
for (auto &s: spawn_states) {
|
||||||
|
if (s.spawngroup_id == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s.is_corpse) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 spawn_time_left = 0;
|
||||||
|
if (spawn_times.count(s.spawn2_id) != 0) {
|
||||||
|
spawn_time_left = spawn_times[s.spawn2_id];
|
||||||
|
LogInfo("Spawn2 [{}] Respawn time left [{}]", s.spawn2_id, spawn_time_left);
|
||||||
|
}
|
||||||
|
|
||||||
|
// load from spawn2_disabled
|
||||||
|
bool spawn_enabled = true;
|
||||||
|
|
||||||
|
// check if spawn is disabled
|
||||||
|
for (auto &ds: disabled_spawns) {
|
||||||
|
if (ds.spawn2_id == s.spawn2_id) {
|
||||||
|
spawn_enabled = !ds.disabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto new_spawn = new Spawn2(
|
||||||
|
s.spawn2_id,
|
||||||
|
s.spawngroup_id,
|
||||||
|
s.x,
|
||||||
|
s.y,
|
||||||
|
s.z,
|
||||||
|
s.heading,
|
||||||
|
s.respawn_time,
|
||||||
|
s.variance,
|
||||||
|
spawn_time_left,
|
||||||
|
s.grid,
|
||||||
|
(bool) s.path_when_zone_idle,
|
||||||
|
s.condition_id,
|
||||||
|
s.condition_min_value,
|
||||||
|
spawn_enabled,
|
||||||
|
(EmuAppearance) s.anim
|
||||||
|
);
|
||||||
|
|
||||||
|
if (spawn_time_left == 0) {
|
||||||
|
new_spawn->SetCurrentNPCID(s.npc_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
spawn2_list.Insert(new_spawn);
|
||||||
|
new_spawn->Process();
|
||||||
|
auto n = new_spawn->GetNPC();
|
||||||
|
if (n) {
|
||||||
|
n->ClearLootItems();
|
||||||
|
if (s.grid > 0) {
|
||||||
|
n->AssignWaypoints(s.grid, s.current_waypoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// dynamic spawns, quest spawns, triggers etc.
|
||||||
|
for (auto &s: spawn_states) {
|
||||||
|
if (s.spawngroup_id > 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto npc_type = content_db.LoadNPCTypesData(s.npc_id);
|
||||||
|
if (!npc_type) {
|
||||||
|
LogZoneState("Failed to load NPC type data for npc_id [{}]", s.npc_id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto npc = new NPC(
|
||||||
|
npc_type,
|
||||||
|
nullptr,
|
||||||
|
glm::vec4(s.x, s.y, s.z, s.heading),
|
||||||
|
GravityBehavior::Water
|
||||||
|
);
|
||||||
|
|
||||||
|
entity_list.AddNPC(npc, true, true);
|
||||||
|
|
||||||
|
LoadNPCState(zone, npc, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// any NPC that is spawned by the spawn system
|
||||||
|
for (auto &e: entity_list.GetNPCList()) {
|
||||||
|
auto npc = e.second;
|
||||||
|
if (npc->GetSpawnGroupId() == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &s: spawn_states) {
|
||||||
|
bool is_same_npc =
|
||||||
|
s.npc_id == npc->GetNPCTypeID() &&
|
||||||
|
s.spawn2_id == npc->GetSpawnPointID() &&
|
||||||
|
s.spawngroup_id == npc->GetSpawnGroupId();
|
||||||
|
if (is_same_npc) {
|
||||||
|
LoadNPCState(zone, npc, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return !spawn_states.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SaveNPCState(NPC *n, ZoneStateSpawnsRepository::ZoneStateSpawns &s)
|
||||||
|
{
|
||||||
|
// entity variables
|
||||||
|
std::map<std::string, std::string> variables;
|
||||||
|
for (const auto &k: n->GetEntityVariables()) {
|
||||||
|
variables[k] = n->GetEntityVariable(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
std::ostringstream os;
|
||||||
|
{
|
||||||
|
cereal::JSONOutputArchiveSingleLine archive(os);
|
||||||
|
archive(variables);
|
||||||
|
}
|
||||||
|
s.entity_variables = os.str();
|
||||||
|
}
|
||||||
|
catch (const std::exception &e) {
|
||||||
|
LogZoneState("Failed to serialize entity variables for NPC [{}] [{}]", n->GetNPCTypeID(), e.what());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// buffs
|
||||||
|
auto buffs = n->GetBuffs();
|
||||||
|
if (!buffs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Buffs_Struct> valid_buffs;
|
||||||
|
|
||||||
|
for (int index = 0; index < n->GetMaxBuffSlots(); index++) {
|
||||||
|
if (buffs[index].spellid != 0 && buffs[index].spellid != 65535) {
|
||||||
|
valid_buffs.push_back(buffs[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
std::ostringstream os = std::ostringstream();
|
||||||
|
{
|
||||||
|
cereal::JSONOutputArchiveSingleLine archive(os);
|
||||||
|
archive(cereal::make_nvp("buffs", valid_buffs));
|
||||||
|
}
|
||||||
|
s.buffs = os.str();
|
||||||
|
}
|
||||||
|
catch (const std::exception &e) {
|
||||||
|
LogZoneState("Failed to serialize buffs for NPC [{}] [{}]", n->GetNPCTypeID(), e.what());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rest
|
||||||
|
s.npc_id = n->GetNPCTypeID();
|
||||||
|
s.loot_data = GetLootSerialized(n);
|
||||||
|
s.hp = n->GetHP();
|
||||||
|
s.mana = n->GetMana();
|
||||||
|
s.endurance = n->GetEndurance();
|
||||||
|
s.grid = n->GetGrid();
|
||||||
|
s.current_waypoint = n->GetGrid() > 0 ? n->GetCWP() : 0;
|
||||||
|
s.x = n->GetX();
|
||||||
|
s.y = n->GetY();
|
||||||
|
s.z = n->GetZ();
|
||||||
|
s.heading = n->GetHeading();
|
||||||
|
s.created_at = std::time(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Zone::SaveZoneState()
|
||||||
|
{
|
||||||
|
// spawns
|
||||||
|
std::vector<ZoneStateSpawnsRepository::ZoneStateSpawns> spawns = {};
|
||||||
|
LinkedListIterator<Spawn2 *> iterator(spawn2_list);
|
||||||
|
iterator.Reset();
|
||||||
|
while (iterator.MoreElements()) {
|
||||||
|
Spawn2 *sp = iterator.GetData();
|
||||||
|
auto s = ZoneStateSpawnsRepository::NewEntity();
|
||||||
|
s.zone_id = GetZoneID();
|
||||||
|
s.instance_id = GetInstanceID();
|
||||||
|
s.npc_id = sp->CurrentNPCID();
|
||||||
|
s.spawn2_id = sp->GetID();
|
||||||
|
s.spawngroup_id = sp->SpawnGroupID();
|
||||||
|
s.x = sp->GetX();
|
||||||
|
s.y = sp->GetY();
|
||||||
|
s.z = sp->GetZ();
|
||||||
|
s.heading = sp->GetHeading();
|
||||||
|
s.respawn_time = sp->RespawnTimer();
|
||||||
|
s.variance = sp->GetVariance();
|
||||||
|
s.grid = sp->GetGrid();
|
||||||
|
s.path_when_zone_idle = sp->GetPathWhenZoneIdle() ? 1 : 0;
|
||||||
|
s.condition_id = sp->GetSpawnCondition();
|
||||||
|
s.condition_min_value = sp->GetConditionMinValue();
|
||||||
|
s.enabled = sp->Enabled() ? 1 : 0;
|
||||||
|
s.anim = sp->GetAnimation();
|
||||||
|
s.created_at = std::time(nullptr);
|
||||||
|
|
||||||
|
auto n = sp->GetNPC();
|
||||||
|
if (n) {
|
||||||
|
SaveNPCState(n, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
spawns.emplace_back(s);
|
||||||
|
iterator.Advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
// npcs that are not in the spawn2 list
|
||||||
|
for (auto &n: entity_list.GetNPCList()) {
|
||||||
|
// everything below here is dynamically spawned
|
||||||
|
bool ignore_npcs =
|
||||||
|
n.second->GetSpawnGroupId() > 0 ||
|
||||||
|
n.second->GetNPCTypeID() < 100 ||
|
||||||
|
n.second->HasOwner();
|
||||||
|
if (ignore_npcs) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto s = ZoneStateSpawnsRepository::NewEntity();
|
||||||
|
s.zone_id = GetZoneID();
|
||||||
|
s.instance_id = GetInstanceID();
|
||||||
|
|
||||||
|
SaveNPCState(n.second, s);
|
||||||
|
|
||||||
|
spawns.emplace_back(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// corpses
|
||||||
|
for (auto &n: entity_list.GetCorpseList()) {
|
||||||
|
if (!n.second->IsNPCCorpse()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto s = ZoneStateSpawnsRepository::NewEntity();
|
||||||
|
s.zone_id = GetZoneID();
|
||||||
|
s.instance_id = GetInstanceID();
|
||||||
|
s.npc_id = n.second->GetNPCTypeID();
|
||||||
|
s.is_corpse = 1;
|
||||||
|
s.x = n.second->GetX();
|
||||||
|
s.y = n.second->GetY();
|
||||||
|
s.z = n.second->GetZ();
|
||||||
|
s.heading = n.second->GetHeading();
|
||||||
|
s.created_at = std::time(nullptr);
|
||||||
|
s.loot_data = GetLootSerialized(n.second);
|
||||||
|
s.decay_in_seconds = (int) (n.second->GetDecayTime() / 1000);
|
||||||
|
|
||||||
|
spawns.emplace_back(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZoneStateSpawnsRepository::DeleteWhere(
|
||||||
|
database,
|
||||||
|
fmt::format(
|
||||||
|
"`zone_id` = {} AND `instance_id` = {}",
|
||||||
|
GetZoneID(),
|
||||||
|
GetInstanceID()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
ZoneStateSpawnsRepository::InsertMany(database, spawns);
|
||||||
|
|
||||||
|
LogInfo("Saved [{}] zone state spawns", Strings::Commify(spawns.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Zone::ClearZoneState(uint32 zone_id, uint32 instance_id)
|
||||||
|
{
|
||||||
|
ZoneStateSpawnsRepository::DeleteWhere(
|
||||||
|
database,
|
||||||
|
fmt::format(
|
||||||
|
"`zone_id` = {} AND `instance_id` = {}",
|
||||||
|
zone_id,
|
||||||
|
instance_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user