mirror of
https://github.com/EQEmu/Server.git
synced 2026-06-18 20:08:21 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b92eafd21b | |||
| d6d5d992cb | |||
| d524cb6a5a | |||
| e6469878ce | |||
| 9583099ace | |||
| cf3483b402 | |||
| 311af7bbe9 | |||
| be42b73f5c | |||
| f76c798910 | |||
| ae198ae043 | |||
| 520943ebf1 | |||
| 9ac306fe67 | |||
| 7a1d69d0d4 | |||
| c873fe5a22 | |||
| e06b0c4b0c | |||
| ed2130f649 |
@@ -1,3 +1,69 @@
|
|||||||
|
## [22.57.1] 10/22/2024
|
||||||
|
|
||||||
|
### Bots
|
||||||
|
|
||||||
|
* Enable Bot Commands Only if Rule Enabled ([#4519](https://github.com/EQEmu/Server/pull/4519)) @Kinglykrab 2024-10-22
|
||||||
|
* Fix pet buffs from saving duplicates every save ([#4520](https://github.com/EQEmu/Server/pull/4520)) @nytmyr 2024-10-22
|
||||||
|
|
||||||
|
### Loginserver
|
||||||
|
|
||||||
|
* Automatic Opcode File Creation ([#4521](https://github.com/EQEmu/Server/pull/4521)) @KimLS 2024-10-22
|
||||||
|
|
||||||
|
## [22.57.0] 10/20/2024
|
||||||
|
|
||||||
|
### Bots
|
||||||
|
|
||||||
|
* Add "silent" option to ^spawn and mute raid spawn ([#4494](https://github.com/EQEmu/Server/pull/4494)) @nytmyr 2024-10-05
|
||||||
|
* Add attack flag when told to attack ([#4490](https://github.com/EQEmu/Server/pull/4490)) @nytmyr 2024-09-29
|
||||||
|
* Fix timers loading on spawn and zone ([#4516](https://github.com/EQEmu/Server/pull/4516)) @nytmyr 2024-10-20
|
||||||
|
|
||||||
|
### Code
|
||||||
|
|
||||||
|
* Fixed a typo in Zoning.cpp ([#4515](https://github.com/EQEmu/Server/pull/4515)) @carolus21rex 2024-10-20
|
||||||
|
* Optimization Code Cleanup ([#4489](https://github.com/EQEmu/Server/pull/4489)) @Akkadius 2024-09-30
|
||||||
|
* Remove Extra Skill in EQ::skills::GetExtraDamageSkills() ([#4486](https://github.com/EQEmu/Server/pull/4486)) @Kinglykrab 2024-10-03
|
||||||
|
|
||||||
|
### Crash
|
||||||
|
|
||||||
|
* Fixes a crash when the faction_list db table is empty. ([#4511](https://github.com/EQEmu/Server/pull/4511)) @KimLS 2024-10-14
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
* Add character_instance_safereturns to tables_to_zero_id ([#4485](https://github.com/EQEmu/Server/pull/4485)) @Morzain 2024-09-26
|
||||||
|
* Correctly limit max targets of PBAOE ([#4507](https://github.com/EQEmu/Server/pull/4507)) @catapultam-habeo 2024-10-11
|
||||||
|
* FindBestZ selecting false zone floor as bestz - Results in roambox failures ([#4504](https://github.com/EQEmu/Server/pull/4504)) @fryguy503 2024-10-13
|
||||||
|
* Fix #set motd Crash ([#4495](https://github.com/EQEmu/Server/pull/4495)) @Kinglykrab 2024-10-05
|
||||||
|
* Fix `character_exp_modifiers` Default Values ([#4502](https://github.com/EQEmu/Server/pull/4502)) @Kinglykrab 2024-10-09
|
||||||
|
* Fix a display error regarding a few trader/buyer query errors ([#4514](https://github.com/EQEmu/Server/pull/4514)) @neckkola 2024-10-17
|
||||||
|
* Fix Group ID 0 in Group::SaveGroupLeaderAA() ([#4487](https://github.com/EQEmu/Server/pull/4487)) @Kinglykrab 2024-10-03
|
||||||
|
* Fix Mercenary Encounter Crash ([#4509](https://github.com/EQEmu/Server/pull/4509)) @Kinglykrab 2024-10-12
|
||||||
|
* Fix NPC::CanTalk() Crash ([#4499](https://github.com/EQEmu/Server/pull/4499)) @Kinglykrab 2024-10-07
|
||||||
|
* Fix Spells:DefaultAOEMaxTargets Default Value ([#4508](https://github.com/EQEmu/Server/pull/4508)) @Kinglykrab 2024-10-12
|
||||||
|
* Fix Targeted AOE Max Targets Rule ([#4488](https://github.com/EQEmu/Server/pull/4488)) @Kinglykrab 2024-10-03
|
||||||
|
* fixed a bug where it would use npc value instead of faction value in the database. ([#4491](https://github.com/EQEmu/Server/pull/4491)) @regneq 2024-09-29
|
||||||
|
* Master of Disguise should apply to illusions casted by others. ([#4506](https://github.com/EQEmu/Server/pull/4506)) @fryguy503 2024-10-11
|
||||||
|
* Spells - Self Only (Yellow) cast when non group member is targeted ([#4503](https://github.com/EQEmu/Server/pull/4503)) @fryguy503 2024-10-11
|
||||||
|
|
||||||
|
### Loginserver
|
||||||
|
|
||||||
|
* Larion loginserver support ([#4492](https://github.com/EQEmu/Server/pull/4492)) @KimLS 2024-10-03
|
||||||
|
* Login Fatal Error Spamming ([#4476](https://github.com/EQEmu/Server/pull/4476)) @KimLS 2024-10-09
|
||||||
|
|
||||||
|
### Logs
|
||||||
|
|
||||||
|
* Add NPC Trades to Player Events ([#4505](https://github.com/EQEmu/Server/pull/4505)) @Kinglykrab 2024-10-13
|
||||||
|
|
||||||
|
### Quest API
|
||||||
|
|
||||||
|
* Add Buff Fade Methods to Perl/Lua ([#4501](https://github.com/EQEmu/Server/pull/4501)) @Kinglykrab 2024-10-09
|
||||||
|
* Add EVENT_READ_ITEM to Perl/Lua ([#4497](https://github.com/EQEmu/Server/pull/4497)) @Kinglykrab 2024-10-08
|
||||||
|
* Add NPC List Filter Methods to Perl/Lua ([#4493](https://github.com/EQEmu/Server/pull/4493)) @Kinglykrab 2024-10-04
|
||||||
|
* Add Scripting Support to Mercenaries ([#4500](https://github.com/EQEmu/Server/pull/4500)) @Kinglykrab 2024-10-11
|
||||||
|
|
||||||
|
### Rules
|
||||||
|
|
||||||
|
* Add Rule to disable PVP Regions ([#4513](https://github.com/EQEmu/Server/pull/4513)) @Kinglykrab 2024-10-17
|
||||||
|
|
||||||
## [22.56.3] 9/23/2024
|
## [22.56.3] 9/23/2024
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
|||||||
@@ -171,6 +171,7 @@ void EQEmuConfig::parse_config()
|
|||||||
PluginDir = _root["server"]["directories"].get("plugins", "plugins/").asString();
|
PluginDir = _root["server"]["directories"].get("plugins", "plugins/").asString();
|
||||||
LuaModuleDir = _root["server"]["directories"].get("lua_modules", "lua_modules/").asString();
|
LuaModuleDir = _root["server"]["directories"].get("lua_modules", "lua_modules/").asString();
|
||||||
PatchDir = _root["server"]["directories"].get("patches", "./").asString();
|
PatchDir = _root["server"]["directories"].get("patches", "./").asString();
|
||||||
|
OpcodeDir = _root["server"]["directories"].get("opcodes", "./").asString();
|
||||||
SharedMemDir = _root["server"]["directories"].get("shared_memory", "shared/").asString();
|
SharedMemDir = _root["server"]["directories"].get("shared_memory", "shared/").asString();
|
||||||
LogDir = _root["server"]["directories"].get("logs", "logs/").asString();
|
LogDir = _root["server"]["directories"].get("logs", "logs/").asString();
|
||||||
|
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ class EQEmuConfig
|
|||||||
std::string PluginDir;
|
std::string PluginDir;
|
||||||
std::string LuaModuleDir;
|
std::string LuaModuleDir;
|
||||||
std::string PatchDir;
|
std::string PatchDir;
|
||||||
|
std::string OpcodeDir;
|
||||||
std::string SharedMemDir;
|
std::string SharedMemDir;
|
||||||
std::string LogDir;
|
std::string LogDir;
|
||||||
|
|
||||||
|
|||||||
@@ -789,50 +789,36 @@ std::string PlayerEventDiscordFormatter::FormatNPCHandinEvent(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string npc_info = fmt::format(
|
||||||
|
"{} ({})\n",
|
||||||
|
e.npc_name,
|
||||||
|
e.npc_id
|
||||||
|
);
|
||||||
|
|
||||||
|
npc_info += fmt::format(
|
||||||
|
"Is Quest Handin: {}",
|
||||||
|
e.is_quest_handin ? "Yes" : "No"
|
||||||
|
);
|
||||||
|
|
||||||
std::vector<DiscordField> f = {};
|
std::vector<DiscordField> f = {};
|
||||||
|
|
||||||
|
|
||||||
|
BuildDiscordField(&f, "NPC", npc_info);
|
||||||
|
|
||||||
if (!handin_items_info.empty()) {
|
if (!handin_items_info.empty()) {
|
||||||
BuildDiscordField(
|
BuildDiscordField(&f, "Handin Items", handin_items_info);
|
||||||
&f,
|
|
||||||
"Handin Items",
|
|
||||||
fmt::format(
|
|
||||||
"{}",
|
|
||||||
handin_items_info
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!handin_money_info.empty()) {
|
if (!handin_money_info.empty()) {
|
||||||
BuildDiscordField(
|
BuildDiscordField(&f, "Handin Money", handin_money_info);
|
||||||
&f,
|
|
||||||
"Handin Money",
|
|
||||||
fmt::format(
|
|
||||||
"{}",
|
|
||||||
handin_money_info
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!return_items_info.empty()) {
|
if (!return_items_info.empty()) {
|
||||||
BuildDiscordField(
|
BuildDiscordField(&f, "Return Items", return_items_info);
|
||||||
&f,
|
|
||||||
"Return Items",
|
|
||||||
fmt::format(
|
|
||||||
"{}",
|
|
||||||
return_items_info
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!return_money_info.empty()) {
|
if (!return_money_info.empty()) {
|
||||||
BuildDiscordField(
|
BuildDiscordField(&f, "Return Money", return_money_info);
|
||||||
&f,
|
|
||||||
"Return Money",
|
|
||||||
fmt::format(
|
|
||||||
"{}",
|
|
||||||
return_money_info
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<DiscordEmbed> embeds = {};
|
std::vector<DiscordEmbed> embeds = {};
|
||||||
|
|||||||
@@ -654,53 +654,53 @@ const int32_t RETENTION_DAYS_DEFAULT = 7;
|
|||||||
|
|
||||||
void PlayerEventLogs::SetSettingsDefaults()
|
void PlayerEventLogs::SetSettingsDefaults()
|
||||||
{
|
{
|
||||||
m_settings[PlayerEvent::GM_COMMAND].event_enabled = 1;
|
m_settings[PlayerEvent::GM_COMMAND].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::ZONING].event_enabled = 1;
|
m_settings[PlayerEvent::ZONING].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::AA_GAIN].event_enabled = 1;
|
m_settings[PlayerEvent::AA_GAIN].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::AA_PURCHASE].event_enabled = 1;
|
m_settings[PlayerEvent::AA_PURCHASE].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::FORAGE_SUCCESS].event_enabled = 0;
|
m_settings[PlayerEvent::FORAGE_SUCCESS].event_enabled = 0;
|
||||||
m_settings[PlayerEvent::FORAGE_FAILURE].event_enabled = 0;
|
m_settings[PlayerEvent::FORAGE_FAILURE].event_enabled = 0;
|
||||||
m_settings[PlayerEvent::FISH_SUCCESS].event_enabled = 0;
|
m_settings[PlayerEvent::FISH_SUCCESS].event_enabled = 0;
|
||||||
m_settings[PlayerEvent::FISH_FAILURE].event_enabled = 0;
|
m_settings[PlayerEvent::FISH_FAILURE].event_enabled = 0;
|
||||||
m_settings[PlayerEvent::ITEM_DESTROY].event_enabled = 1;
|
m_settings[PlayerEvent::ITEM_DESTROY].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::WENT_ONLINE].event_enabled = 0;
|
m_settings[PlayerEvent::WENT_ONLINE].event_enabled = 0;
|
||||||
m_settings[PlayerEvent::WENT_OFFLINE].event_enabled = 0;
|
m_settings[PlayerEvent::WENT_OFFLINE].event_enabled = 0;
|
||||||
m_settings[PlayerEvent::LEVEL_GAIN].event_enabled = 1;
|
m_settings[PlayerEvent::LEVEL_GAIN].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::LEVEL_LOSS].event_enabled = 1;
|
m_settings[PlayerEvent::LEVEL_LOSS].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::LOOT_ITEM].event_enabled = 1;
|
m_settings[PlayerEvent::LOOT_ITEM].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::MERCHANT_PURCHASE].event_enabled = 1;
|
m_settings[PlayerEvent::MERCHANT_PURCHASE].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::MERCHANT_SELL].event_enabled = 1;
|
m_settings[PlayerEvent::MERCHANT_SELL].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::GROUP_JOIN].event_enabled = 0;
|
m_settings[PlayerEvent::GROUP_JOIN].event_enabled = 0;
|
||||||
m_settings[PlayerEvent::GROUP_LEAVE].event_enabled = 0;
|
m_settings[PlayerEvent::GROUP_LEAVE].event_enabled = 0;
|
||||||
m_settings[PlayerEvent::RAID_JOIN].event_enabled = 0;
|
m_settings[PlayerEvent::RAID_JOIN].event_enabled = 0;
|
||||||
m_settings[PlayerEvent::RAID_LEAVE].event_enabled = 0;
|
m_settings[PlayerEvent::RAID_LEAVE].event_enabled = 0;
|
||||||
m_settings[PlayerEvent::GROUNDSPAWN_PICKUP].event_enabled = 1;
|
m_settings[PlayerEvent::GROUNDSPAWN_PICKUP].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::NPC_HANDIN].event_enabled = 1;
|
m_settings[PlayerEvent::NPC_HANDIN].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::SKILL_UP].event_enabled = 0;
|
m_settings[PlayerEvent::SKILL_UP].event_enabled = 0;
|
||||||
m_settings[PlayerEvent::TASK_ACCEPT].event_enabled = 1;
|
m_settings[PlayerEvent::TASK_ACCEPT].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::TASK_UPDATE].event_enabled = 1;
|
m_settings[PlayerEvent::TASK_UPDATE].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::TASK_COMPLETE].event_enabled = 1;
|
m_settings[PlayerEvent::TASK_COMPLETE].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::TRADE].event_enabled = 1;
|
m_settings[PlayerEvent::TRADE].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::GIVE_ITEM].event_enabled = 1;
|
m_settings[PlayerEvent::GIVE_ITEM].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::SAY].event_enabled = 0;
|
m_settings[PlayerEvent::SAY].event_enabled = 0;
|
||||||
m_settings[PlayerEvent::REZ_ACCEPTED].event_enabled = 1;
|
m_settings[PlayerEvent::REZ_ACCEPTED].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::DEATH].event_enabled = 1;
|
m_settings[PlayerEvent::DEATH].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::COMBINE_FAILURE].event_enabled = 1;
|
m_settings[PlayerEvent::COMBINE_FAILURE].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::COMBINE_SUCCESS].event_enabled = 1;
|
m_settings[PlayerEvent::COMBINE_SUCCESS].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::DROPPED_ITEM].event_enabled = 1;
|
m_settings[PlayerEvent::DROPPED_ITEM].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::SPLIT_MONEY].event_enabled = 1;
|
m_settings[PlayerEvent::SPLIT_MONEY].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::DZ_JOIN].event_enabled = 1;
|
m_settings[PlayerEvent::DZ_JOIN].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::DZ_LEAVE].event_enabled = 1;
|
m_settings[PlayerEvent::DZ_LEAVE].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::TRADER_PURCHASE].event_enabled = 1;
|
m_settings[PlayerEvent::TRADER_PURCHASE].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::TRADER_SELL].event_enabled = 1;
|
m_settings[PlayerEvent::TRADER_SELL].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::BANDOLIER_CREATE].event_enabled = 0;
|
m_settings[PlayerEvent::BANDOLIER_CREATE].event_enabled = 0;
|
||||||
m_settings[PlayerEvent::BANDOLIER_SWAP].event_enabled = 0;
|
m_settings[PlayerEvent::BANDOLIER_SWAP].event_enabled = 0;
|
||||||
m_settings[PlayerEvent::DISCOVER_ITEM].event_enabled = 1;
|
m_settings[PlayerEvent::DISCOVER_ITEM].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::POSSIBLE_HACK].event_enabled = 1;
|
m_settings[PlayerEvent::POSSIBLE_HACK].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::KILLED_NPC].event_enabled = 0;
|
m_settings[PlayerEvent::KILLED_NPC].event_enabled = 0;
|
||||||
m_settings[PlayerEvent::KILLED_NAMED_NPC].event_enabled = 1;
|
m_settings[PlayerEvent::KILLED_NAMED_NPC].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::KILLED_RAID_NPC].event_enabled = 1;
|
m_settings[PlayerEvent::KILLED_RAID_NPC].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::ITEM_CREATION].event_enabled = 1;
|
m_settings[PlayerEvent::ITEM_CREATION].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::GUILD_TRIBUTE_DONATE_ITEM].event_enabled = 1;
|
m_settings[PlayerEvent::GUILD_TRIBUTE_DONATE_ITEM].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::GUILD_TRIBUTE_DONATE_PLAT].event_enabled = 1;
|
m_settings[PlayerEvent::GUILD_TRIBUTE_DONATE_PLAT].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::PARCEL_SEND].event_enabled = 1;
|
m_settings[PlayerEvent::PARCEL_SEND].event_enabled = 1;
|
||||||
|
|||||||
@@ -860,10 +860,12 @@ namespace PlayerEvent {
|
|||||||
|
|
||||||
class HandinEntry {
|
class HandinEntry {
|
||||||
public:
|
public:
|
||||||
uint32 item_id;
|
uint32 item_id;
|
||||||
std::string item_name;
|
std::string item_name;
|
||||||
uint16 charges;
|
std::vector<uint32> augment_ids;
|
||||||
bool attuned;
|
std::vector<std::string> augment_names;
|
||||||
|
uint16 charges;
|
||||||
|
bool attuned;
|
||||||
|
|
||||||
// cereal
|
// cereal
|
||||||
template<class Archive>
|
template<class Archive>
|
||||||
@@ -872,6 +874,8 @@ namespace PlayerEvent {
|
|||||||
ar(
|
ar(
|
||||||
CEREAL_NVP(item_id),
|
CEREAL_NVP(item_id),
|
||||||
CEREAL_NVP(item_name),
|
CEREAL_NVP(item_name),
|
||||||
|
CEREAL_NVP(augment_ids),
|
||||||
|
CEREAL_NVP(augment_names),
|
||||||
CEREAL_NVP(charges),
|
CEREAL_NVP(charges),
|
||||||
CEREAL_NVP(attuned)
|
CEREAL_NVP(attuned)
|
||||||
);
|
);
|
||||||
@@ -905,6 +909,7 @@ namespace PlayerEvent {
|
|||||||
HandinMoney handin_money;
|
HandinMoney handin_money;
|
||||||
std::vector<HandinEntry> return_items;
|
std::vector<HandinEntry> return_items;
|
||||||
HandinMoney return_money;
|
HandinMoney return_money;
|
||||||
|
bool is_quest_handin;
|
||||||
|
|
||||||
// cereal
|
// cereal
|
||||||
template<class Archive>
|
template<class Archive>
|
||||||
@@ -916,7 +921,8 @@ namespace PlayerEvent {
|
|||||||
CEREAL_NVP(handin_items),
|
CEREAL_NVP(handin_items),
|
||||||
CEREAL_NVP(handin_money),
|
CEREAL_NVP(handin_money),
|
||||||
CEREAL_NVP(return_items),
|
CEREAL_NVP(return_items),
|
||||||
CEREAL_NVP(return_money)
|
CEREAL_NVP(return_money),
|
||||||
|
CEREAL_NVP(is_quest_handin)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -74,6 +74,11 @@ void PathManager::LoadPaths()
|
|||||||
m_patch_path = fs::relative(fs::path{m_server_path + "/" + c->PatchDir}).string();
|
m_patch_path = fs::relative(fs::path{m_server_path + "/" + c->PatchDir}).string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// patches
|
||||||
|
if (File::Exists(fs::path{ m_server_path + "/" + c->OpcodeDir }.string())) {
|
||||||
|
m_opcode_path = fs::relative(fs::path{ m_server_path + "/" + c->OpcodeDir }).string();
|
||||||
|
}
|
||||||
|
|
||||||
// shared_memory_path
|
// shared_memory_path
|
||||||
if (File::Exists(fs::path{m_server_path + "/" + c->SharedMemDir}.string())) {
|
if (File::Exists(fs::path{m_server_path + "/" + c->SharedMemDir}.string())) {
|
||||||
m_shared_memory_path = fs::relative(fs::path{ m_server_path + "/" + c->SharedMemDir }).string();
|
m_shared_memory_path = fs::relative(fs::path{ m_server_path + "/" + c->SharedMemDir }).string();
|
||||||
@@ -89,6 +94,7 @@ void PathManager::LoadPaths()
|
|||||||
LogInfo("lua_modules path [{}]", m_lua_modules_path);
|
LogInfo("lua_modules path [{}]", m_lua_modules_path);
|
||||||
LogInfo("maps path [{}]", m_maps_path);
|
LogInfo("maps path [{}]", m_maps_path);
|
||||||
LogInfo("patches path [{}]", m_patch_path);
|
LogInfo("patches path [{}]", m_patch_path);
|
||||||
|
LogInfo("opcode path [{}]", m_opcode_path);
|
||||||
LogInfo("plugins path [{}]", m_plugins_path);
|
LogInfo("plugins path [{}]", m_plugins_path);
|
||||||
LogInfo("quests path [{}]", m_quests_path);
|
LogInfo("quests path [{}]", m_quests_path);
|
||||||
LogInfo("shared_memory path [{}]", m_shared_memory_path);
|
LogInfo("shared_memory path [{}]", m_shared_memory_path);
|
||||||
@@ -129,6 +135,11 @@ const std::string &PathManager::GetPatchPath() const
|
|||||||
return m_patch_path;
|
return m_patch_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string &PathManager::GetOpcodePath() const
|
||||||
|
{
|
||||||
|
return m_opcode_path;
|
||||||
|
}
|
||||||
|
|
||||||
const std::string &PathManager::GetLuaModulesPath() const
|
const std::string &PathManager::GetLuaModulesPath() const
|
||||||
{
|
{
|
||||||
return m_lua_modules_path;
|
return m_lua_modules_path;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ public:
|
|||||||
[[nodiscard]] const std::string &GetLuaModulesPath() const;
|
[[nodiscard]] const std::string &GetLuaModulesPath() const;
|
||||||
[[nodiscard]] const std::string &GetMapsPath() const;
|
[[nodiscard]] const std::string &GetMapsPath() const;
|
||||||
[[nodiscard]] const std::string &GetPatchPath() const;
|
[[nodiscard]] const std::string &GetPatchPath() const;
|
||||||
|
[[nodiscard]] const std::string &GetOpcodePath() const;
|
||||||
[[nodiscard]] const std::string &GetPluginsPath() const;
|
[[nodiscard]] const std::string &GetPluginsPath() const;
|
||||||
[[nodiscard]] const std::string &GetQuestsPath() const;
|
[[nodiscard]] const std::string &GetQuestsPath() const;
|
||||||
[[nodiscard]] const std::string &GetServerPath() const;
|
[[nodiscard]] const std::string &GetServerPath() const;
|
||||||
@@ -24,6 +25,7 @@ private:
|
|||||||
std::string m_lua_modules_path;
|
std::string m_lua_modules_path;
|
||||||
std::string m_maps_path;
|
std::string m_maps_path;
|
||||||
std::string m_patch_path;
|
std::string m_patch_path;
|
||||||
|
std::string m_opcode_path;
|
||||||
std::string m_plugins_path;
|
std::string m_plugins_path;
|
||||||
std::string m_quests_path;
|
std::string m_quests_path;
|
||||||
std::string m_server_path;
|
std::string m_server_path;
|
||||||
|
|||||||
@@ -236,6 +236,10 @@ public:
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (buyers.empty()) {
|
||||||
|
return all_entries;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::string> char_ids{};
|
std::vector<std::string> char_ids{};
|
||||||
for (auto const &bl : buyers) {
|
for (auto const &bl : buyers) {
|
||||||
char_ids.push_back((std::to_string(bl.char_id)));
|
char_ids.push_back((std::to_string(bl.char_id)));
|
||||||
|
|||||||
@@ -120,6 +120,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
DeleteWhere(db, fmt::format("`char_id` = '{}';", char_id));
|
DeleteWhere(db, fmt::format("`char_id` = '{}';", char_id));
|
||||||
|
if (buy_line_ids.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
BaseBuyerBuyLinesRepository::DeleteWhere(
|
BaseBuyerBuyLinesRepository::DeleteWhere(
|
||||||
db,
|
db,
|
||||||
fmt::format("`id` IN({})", Strings::Implode(", ", buy_line_ids))
|
fmt::format("`id` IN({})", Strings::Implode(", ", buy_line_ids))
|
||||||
|
|||||||
@@ -217,6 +217,10 @@ public:
|
|||||||
delete_ids.push_back(std::to_string(e.id));
|
delete_ids.push_back(std::to_string(e.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (delete_ids.empty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return DeleteWhere(db, fmt::format("`id` IN({})", Strings::Implode(",", delete_ids)));
|
return DeleteWhere(db, fmt::format("`id` IN({})", Strings::Implode(",", delete_ids)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -338,6 +338,7 @@ RULE_STRING(World, IPExemptionZones, "", "Comma-delimited list of zones to exclu
|
|||||||
RULE_STRING(World, MOTD, "", "Server MOTD sent on login, change from empty to have this be used instead of variables table 'motd' value")
|
RULE_STRING(World, MOTD, "", "Server MOTD sent on login, change from empty to have this be used instead of variables table 'motd' value")
|
||||||
RULE_STRING(World, Rules, "", "Server Rules, change from empty to have this be used instead of variables table 'rules' value, lines are pipe (|) separated, example: A|B|C")
|
RULE_STRING(World, Rules, "", "Server Rules, change from empty to have this be used instead of variables table 'rules' value, lines are pipe (|) separated, example: A|B|C")
|
||||||
RULE_BOOL(World, EnableAutoLogin, false, "Enables or disables auto login of characters, allowing people to log characters in directly from loginserver to ingame")
|
RULE_BOOL(World, EnableAutoLogin, false, "Enables or disables auto login of characters, allowing people to log characters in directly from loginserver to ingame")
|
||||||
|
RULE_BOOL(World, EnablePVPRegions, true, "Enables or disables PVP Regions automatically setting your PVP flag")
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Zone)
|
RULE_CATEGORY(Zone)
|
||||||
@@ -515,6 +516,8 @@ RULE_BOOL(Spells, ManaTapsOnAnyClass, false, "Enabling this will allow you to ca
|
|||||||
RULE_INT(Spells, HealAmountMessageFilterThreshold, 100, "Lifetaps below this threshold will not have a message sent to the client (Heal will still process) 0 to Disable.")
|
RULE_INT(Spells, HealAmountMessageFilterThreshold, 100, "Lifetaps below this threshold will not have a message sent to the client (Heal will still process) 0 to Disable.")
|
||||||
RULE_BOOL(Spells, SnareOverridesSpeedBonuses, false, "Enabling will allow snares to override any speed bonuses the entity may have. Default: False")
|
RULE_BOOL(Spells, SnareOverridesSpeedBonuses, false, "Enabling will allow snares to override any speed bonuses the entity may have. Default: False")
|
||||||
RULE_INT(Spells, TargetedAOEMaxTargets, 4, "Max number of targets a Targeted AOE spell can cast on. Set to 0 for no limit.")
|
RULE_INT(Spells, TargetedAOEMaxTargets, 4, "Max number of targets a Targeted 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_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Combat)
|
RULE_CATEGORY(Combat)
|
||||||
|
|||||||
+1
-1
@@ -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 "22.56.3-dev" // always append -dev to the current version for custom-builds
|
#define CURRENT_VERSION "22.57.1-dev" // always append -dev to the current version for custom-builds
|
||||||
#define LOGIN_VERSION "0.8.0"
|
#define LOGIN_VERSION "0.8.0"
|
||||||
#define COMPILE_DATE __DATE__
|
#define COMPILE_DATE __DATE__
|
||||||
#define COMPILE_TIME __TIME__
|
#define COMPILE_TIME __TIME__
|
||||||
|
|||||||
@@ -7,6 +7,79 @@ extern bool run_server;
|
|||||||
#include "../common/eqemu_logsys.h"
|
#include "../common/eqemu_logsys.h"
|
||||||
#include "../common/misc.h"
|
#include "../common/misc.h"
|
||||||
#include "../common/path_manager.h"
|
#include "../common/path_manager.h"
|
||||||
|
#include "../common/file.h"
|
||||||
|
|
||||||
|
void CheckTitaniumOpcodeFile(const std::string &path) {
|
||||||
|
if (File::Exists(path)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto f = fopen(path.c_str(), "w");
|
||||||
|
if (f) {
|
||||||
|
fprintf(f, "#EQEmu Public Login Server OPCodes\n");
|
||||||
|
fprintf(f, "OP_SessionReady=0x0001\n");
|
||||||
|
fprintf(f, "OP_Login=0x0002\n");
|
||||||
|
fprintf(f, "OP_ServerListRequest=0x0004\n");
|
||||||
|
fprintf(f, "OP_PlayEverquestRequest=0x000d\n");
|
||||||
|
fprintf(f, "OP_PlayEverquestResponse=0x0021\n");
|
||||||
|
fprintf(f, "OP_ChatMessage=0x0016\n");
|
||||||
|
fprintf(f, "OP_LoginAccepted=0x0017\n");
|
||||||
|
fprintf(f, "OP_ServerListResponse=0x0018\n");
|
||||||
|
fprintf(f, "OP_Poll=0x0029\n");
|
||||||
|
fprintf(f, "OP_EnterChat=0x000f\n");
|
||||||
|
fprintf(f, "OP_PollResponse=0x0011\n");
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckSoDOpcodeFile(const std::string& path) {
|
||||||
|
if (File::Exists(path)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto f = fopen(path.c_str(), "w");
|
||||||
|
if (f) {
|
||||||
|
fprintf(f, "#EQEmu Public Login Server OPCodes\n");
|
||||||
|
fprintf(f, "OP_SessionReady=0x0001\n");
|
||||||
|
fprintf(f, "OP_Login=0x0002\n");
|
||||||
|
fprintf(f, "OP_ServerListRequest=0x0004\n");
|
||||||
|
fprintf(f, "OP_PlayEverquestRequest=0x000d\n");
|
||||||
|
fprintf(f, "OP_PlayEverquestResponse=0x0022\n");
|
||||||
|
fprintf(f, "OP_ChatMessage=0x0017\n");
|
||||||
|
fprintf(f, "OP_LoginAccepted=0x0018\n");
|
||||||
|
fprintf(f, "OP_ServerListResponse=0x0019\n");
|
||||||
|
fprintf(f, "OP_Poll=0x0029\n");
|
||||||
|
fprintf(f, "OP_LoginExpansionPacketData=0x0031\n");
|
||||||
|
fprintf(f, "OP_EnterChat=0x000f\n");
|
||||||
|
fprintf(f, "OP_PollResponse=0x0011\n");
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckLarionOpcodeFile(const std::string& path) {
|
||||||
|
if (File::Exists(path)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto f = fopen(path.c_str(), "w");
|
||||||
|
if (f) {
|
||||||
|
fprintf(f, "#EQEmu Public Login Server OPCodes\n");
|
||||||
|
fprintf(f, "OP_SessionReady=0x0001\n");
|
||||||
|
fprintf(f, "OP_Login=0x0002\n");
|
||||||
|
fprintf(f, "OP_ServerListRequest=0x0004\n");
|
||||||
|
fprintf(f, "OP_PlayEverquestRequest=0x000d\n");
|
||||||
|
fprintf(f, "OP_PlayEverquestResponse=0x0022\n");
|
||||||
|
fprintf(f, "OP_ChatMessage=0x0017\n");
|
||||||
|
fprintf(f, "OP_LoginAccepted=0x0018\n");
|
||||||
|
fprintf(f, "OP_ServerListResponse=0x0019\n");
|
||||||
|
fprintf(f, "OP_Poll=0x0029\n");
|
||||||
|
fprintf(f, "OP_EnterChat=0x000f\n");
|
||||||
|
fprintf(f, "OP_PollResponse=0x0011\n");
|
||||||
|
fprintf(f, "OP_SystemFingerprint=0x0016\n");
|
||||||
|
fprintf(f, "OP_ExpansionList=0x0030\n");
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ClientManager::ClientManager()
|
ClientManager::ClientManager()
|
||||||
{
|
{
|
||||||
@@ -19,14 +92,12 @@ ClientManager::ClientManager()
|
|||||||
|
|
||||||
std::string opcodes_path = fmt::format(
|
std::string opcodes_path = fmt::format(
|
||||||
"{}/{}",
|
"{}/{}",
|
||||||
path.GetServerPath(),
|
path.GetOpcodePath(),
|
||||||
server.config.GetVariableString(
|
"login_opcodes.conf"
|
||||||
"client_configuration",
|
|
||||||
"titanium_opcodes",
|
|
||||||
"login_opcodes.conf"
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CheckTitaniumOpcodeFile(opcodes_path);
|
||||||
|
|
||||||
if (!titanium_ops->LoadOpcodes(opcodes_path.c_str())) {
|
if (!titanium_ops->LoadOpcodes(opcodes_path.c_str())) {
|
||||||
LogError(
|
LogError(
|
||||||
"ClientManager fatal error: couldn't load opcodes for Titanium file [{0}]",
|
"ClientManager fatal error: couldn't load opcodes for Titanium file [{0}]",
|
||||||
@@ -58,14 +129,12 @@ ClientManager::ClientManager()
|
|||||||
|
|
||||||
opcodes_path = fmt::format(
|
opcodes_path = fmt::format(
|
||||||
"{}/{}",
|
"{}/{}",
|
||||||
path.GetServerPath(),
|
path.GetOpcodePath(),
|
||||||
server.config.GetVariableString(
|
"login_opcodes_sod.conf"
|
||||||
"client_configuration",
|
|
||||||
"sod_opcodes",
|
|
||||||
"login_opcodes.conf"
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CheckSoDOpcodeFile(opcodes_path);
|
||||||
|
|
||||||
if (!sod_ops->LoadOpcodes(opcodes_path.c_str())) {
|
if (!sod_ops->LoadOpcodes(opcodes_path.c_str())) {
|
||||||
LogError(
|
LogError(
|
||||||
"ClientManager fatal error: couldn't load opcodes for SoD file {0}",
|
"ClientManager fatal error: couldn't load opcodes for SoD file {0}",
|
||||||
@@ -98,14 +167,12 @@ ClientManager::ClientManager()
|
|||||||
|
|
||||||
opcodes_path = fmt::format(
|
opcodes_path = fmt::format(
|
||||||
"{}/{}",
|
"{}/{}",
|
||||||
path.GetServerPath(),
|
path.GetOpcodePath(),
|
||||||
server.config.GetVariableString(
|
"login_opcodes_larion.conf"
|
||||||
"client_configuration",
|
|
||||||
"larion_opcodes",
|
|
||||||
"login_opcodes.conf"
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CheckLarionOpcodeFile(opcodes_path);
|
||||||
|
|
||||||
if (!larion_ops->LoadOpcodes(opcodes_path.c_str())) {
|
if (!larion_ops->LoadOpcodes(opcodes_path.c_str())) {
|
||||||
LogError(
|
LogError(
|
||||||
"ClientManager fatal error: couldn't load opcodes for Larion file [{0}]",
|
"ClientManager fatal error: couldn't load opcodes for Larion file [{0}]",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "eqemu-server",
|
"name": "eqemu-server",
|
||||||
"version": "22.56.3",
|
"version": "22.57.1",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/EQEmu/Server.git"
|
"url": "https://github.com/EQEmu/Server.git"
|
||||||
|
|||||||
@@ -294,6 +294,13 @@ bool WorldBoot::DatabaseLoadRoutines(int argc, char **argv)
|
|||||||
database.ClearBuyerDetails();
|
database.ClearBuyerDetails();
|
||||||
LogInfo("Clearing buyer table details");
|
LogInfo("Clearing buyer table details");
|
||||||
|
|
||||||
|
if (RuleB(Bots, Enabled)) {
|
||||||
|
LogInfo("Clearing [bot_pet_buffs] table of stale entries");
|
||||||
|
database.QueryDatabase(
|
||||||
|
"DELETE FROM bot_pet_buffs WHERE NOT EXISTS (SELECT * FROM bot_pets WHERE bot_pets.pets_index = bot_pet_buffs.pets_index)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!content_db.LoadItems(hotfix_name)) {
|
if (!content_db.LoadItems(hotfix_name)) {
|
||||||
LogError("Error: Could not load item data. But ignoring");
|
LogError("Error: Could not load item data. But ignoring");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -828,7 +828,7 @@ bool BotDatabase::LoadTimers(Bot* b)
|
|||||||
BotTimer_Struct t{ };
|
BotTimer_Struct t{ };
|
||||||
|
|
||||||
for (const auto& e : l) {
|
for (const auto& e : l) {
|
||||||
if (t.timer_value < (Timer::GetCurrentTime() + t.recast_time)) {
|
if (e.timer_value < (Timer::GetCurrentTime() + e.recast_time)) {
|
||||||
t.timer_id = e.timer_id;
|
t.timer_id = e.timer_id;
|
||||||
t.timer_value = e.timer_value;
|
t.timer_value = e.timer_value;
|
||||||
t.recast_time = e.recast_time;
|
t.recast_time = e.recast_time;
|
||||||
@@ -1451,7 +1451,7 @@ bool BotDatabase::DeletePetBuffs(const uint32 bot_id)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
BotPetBuffsRepository::DeleteOne(database, saved_pet_index);
|
BotPetBuffsRepository::DeleteWhere(database, fmt::format("pets_index = {}", saved_pet_index));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
+251
-5
@@ -8677,14 +8677,16 @@ int Client::GetAccountAge() {
|
|||||||
|
|
||||||
void Client::CheckRegionTypeChanges()
|
void Client::CheckRegionTypeChanges()
|
||||||
{
|
{
|
||||||
if (!zone->HasWaterMap())
|
if (!zone->HasWaterMap()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto new_region = zone->watermap->ReturnRegionType(glm::vec3(m_Position));
|
auto new_region = zone->watermap->ReturnRegionType(glm::vec3(m_Position));
|
||||||
|
|
||||||
// still same region, do nothing
|
// still same region, do nothing
|
||||||
if (last_region_type == new_region)
|
if (last_region_type == new_region) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// If we got out of water clear any water aggro for water only npcs
|
// If we got out of water clear any water aggro for water only npcs
|
||||||
if (last_region_type == RegionTypeWater) {
|
if (last_region_type == RegionTypeWater) {
|
||||||
@@ -8695,13 +8697,15 @@ void Client::CheckRegionTypeChanges()
|
|||||||
last_region_type = new_region;
|
last_region_type = new_region;
|
||||||
|
|
||||||
// PVP is the only state we need to keep track of, so we can just return now for PVP servers
|
// PVP is the only state we need to keep track of, so we can just return now for PVP servers
|
||||||
if (RuleI(World, PVPSettings) > 0)
|
if (RuleI(World, PVPSettings) > 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (last_region_type == RegionTypePVP)
|
if (last_region_type == RegionTypePVP && RuleB(World, EnablePVPRegions)) {
|
||||||
temp_pvp = true;
|
temp_pvp = true;
|
||||||
else if (temp_pvp)
|
} else if (temp_pvp) {
|
||||||
temp_pvp = false;
|
temp_pvp = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::ProcessAggroMeter()
|
void Client::ProcessAggroMeter()
|
||||||
@@ -12316,6 +12320,248 @@ void Client::PlayerTradeEventLog(Trade *t, Trade *t2)
|
|||||||
RecordPlayerEventLogWithClient(trader2, PlayerEvent::TRADE, e);
|
RecordPlayerEventLogWithClient(trader2, PlayerEvent::TRADE, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::NPCHandinEventLog(Trade* t, NPC* n)
|
||||||
|
{
|
||||||
|
Client* c = t->GetOwner()->CastToClient();
|
||||||
|
|
||||||
|
std::vector<PlayerEvent::HandinEntry> hi = {};
|
||||||
|
std::vector<PlayerEvent::HandinEntry> ri = {};
|
||||||
|
PlayerEvent::HandinMoney hm{};
|
||||||
|
PlayerEvent::HandinMoney rm{};
|
||||||
|
|
||||||
|
if (
|
||||||
|
c->EntityVariableExists("HANDIN_ITEMS") &&
|
||||||
|
c->EntityVariableExists("HANDIN_MONEY") &&
|
||||||
|
c->EntityVariableExists("RETURN_ITEMS") &&
|
||||||
|
c->EntityVariableExists("RETURN_MONEY")
|
||||||
|
) {
|
||||||
|
const std::string& handin_items = c->GetEntityVariable("HANDIN_ITEMS");
|
||||||
|
const std::string& return_items = c->GetEntityVariable("RETURN_ITEMS");
|
||||||
|
const std::string& handin_money = c->GetEntityVariable("HANDIN_MONEY");
|
||||||
|
const std::string& return_money = c->GetEntityVariable("RETURN_MONEY");
|
||||||
|
|
||||||
|
// Handin Items
|
||||||
|
if (!handin_items.empty()) {
|
||||||
|
if (Strings::Contains(handin_items, ",")) {
|
||||||
|
const auto handin_data = Strings::Split(handin_items, ",");
|
||||||
|
for (const auto& h : handin_data) {
|
||||||
|
const auto item_data = Strings::Split(h, "|");
|
||||||
|
if (
|
||||||
|
item_data.size() == 3 &&
|
||||||
|
Strings::IsNumber(item_data[0]) &&
|
||||||
|
Strings::IsNumber(item_data[1]) &&
|
||||||
|
Strings::IsNumber(item_data[2])
|
||||||
|
) {
|
||||||
|
const uint32 item_id = Strings::ToUnsignedInt(item_data[0]);
|
||||||
|
if (item_id != 0) {
|
||||||
|
const auto* item = database.GetItem(item_id);
|
||||||
|
|
||||||
|
if (item) {
|
||||||
|
hi.emplace_back(
|
||||||
|
PlayerEvent::HandinEntry{
|
||||||
|
.item_id = item_id,
|
||||||
|
.item_name = item->Name,
|
||||||
|
.charges = static_cast<uint16>(Strings::ToUnsignedInt(item_data[1])),
|
||||||
|
.attuned = Strings::ToInt(item_data[2]) ? true : false
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (Strings::Contains(handin_items, "|")) {
|
||||||
|
const auto item_data = Strings::Split(handin_items, "|");
|
||||||
|
if (
|
||||||
|
item_data.size() == 3 &&
|
||||||
|
Strings::IsNumber(item_data[0]) &&
|
||||||
|
Strings::IsNumber(item_data[1]) &&
|
||||||
|
Strings::IsNumber(item_data[2])
|
||||||
|
) {
|
||||||
|
const uint32 item_id = Strings::ToUnsignedInt(item_data[0]);
|
||||||
|
const auto* item = database.GetItem(item_id);
|
||||||
|
|
||||||
|
if (item) {
|
||||||
|
hi.emplace_back(
|
||||||
|
PlayerEvent::HandinEntry{
|
||||||
|
.item_id = item_id,
|
||||||
|
.item_name = item->Name,
|
||||||
|
.charges = static_cast<uint16>(Strings::ToUnsignedInt(item_data[1])),
|
||||||
|
.attuned = Strings::ToInt(item_data[2]) ? true : false
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handin Money
|
||||||
|
if (!handin_money.empty()) {
|
||||||
|
const auto hms = Strings::Split(handin_money, "|");
|
||||||
|
|
||||||
|
hm.copper = Strings::ToUnsignedInt(hms[0]);
|
||||||
|
hm.silver = Strings::ToUnsignedInt(hms[1]);
|
||||||
|
hm.gold = Strings::ToUnsignedInt(hms[2]);
|
||||||
|
hm.platinum = Strings::ToUnsignedInt(hms[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return Items
|
||||||
|
if (!return_items.empty()) {
|
||||||
|
if (Strings::Contains(return_items, ",")) {
|
||||||
|
const auto return_data = Strings::Split(return_items, ",");
|
||||||
|
for (const auto& r : return_data) {
|
||||||
|
const auto item_data = Strings::Split(r, "|");
|
||||||
|
if (
|
||||||
|
item_data.size() == 3 &&
|
||||||
|
Strings::IsNumber(item_data[0]) &&
|
||||||
|
Strings::IsNumber(item_data[1]) &&
|
||||||
|
Strings::IsNumber(item_data[2])
|
||||||
|
) {
|
||||||
|
const uint32 item_id = Strings::ToUnsignedInt(item_data[0]);
|
||||||
|
const auto* item = database.GetItem(item_id);
|
||||||
|
|
||||||
|
if (item) {
|
||||||
|
ri.emplace_back(
|
||||||
|
PlayerEvent::HandinEntry{
|
||||||
|
.item_id = item_id,
|
||||||
|
.item_name = item->Name,
|
||||||
|
.charges = static_cast<uint16>(Strings::ToUnsignedInt(item_data[1])),
|
||||||
|
.attuned = Strings::ToInt(item_data[2]) ? true : false
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (Strings::Contains(return_items, "|")) {
|
||||||
|
const auto item_data = Strings::Split(return_items, "|");
|
||||||
|
if (
|
||||||
|
item_data.size() == 3 &&
|
||||||
|
Strings::IsNumber(item_data[0]) &&
|
||||||
|
Strings::IsNumber(item_data[1]) &&
|
||||||
|
Strings::IsNumber(item_data[2])
|
||||||
|
) {
|
||||||
|
const uint32 item_id = Strings::ToUnsignedInt(item_data[0]);
|
||||||
|
const auto* item = database.GetItem(item_id);
|
||||||
|
|
||||||
|
if (item) {
|
||||||
|
ri.emplace_back(
|
||||||
|
PlayerEvent::HandinEntry{
|
||||||
|
.item_id = item_id,
|
||||||
|
.item_name = item->Name,
|
||||||
|
.charges = static_cast<uint16>(Strings::ToUnsignedInt(item_data[1])),
|
||||||
|
.attuned = Strings::ToInt(item_data[2]) ? true : false
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return Money
|
||||||
|
if (!return_money.empty()) {
|
||||||
|
const auto rms = Strings::Split(return_money, "|");
|
||||||
|
rm.copper = static_cast<uint32>(Strings::ToUnsignedInt(rms[0]));
|
||||||
|
rm.silver = static_cast<uint32>(Strings::ToUnsignedInt(rms[1]));
|
||||||
|
rm.gold = static_cast<uint32>(Strings::ToUnsignedInt(rms[2]));
|
||||||
|
rm.platinum = static_cast<uint32>(Strings::ToUnsignedInt(rms[3]));
|
||||||
|
}
|
||||||
|
|
||||||
|
c->DeleteEntityVariable("HANDIN_ITEMS");
|
||||||
|
c->DeleteEntityVariable("HANDIN_MONEY");
|
||||||
|
c->DeleteEntityVariable("RETURN_ITEMS");
|
||||||
|
c->DeleteEntityVariable("RETURN_MONEY");
|
||||||
|
|
||||||
|
const bool handed_in_money = hm.platinum > 0 || hm.gold > 0 || hm.silver > 0 || hm.copper > 0;
|
||||||
|
|
||||||
|
const bool event_has_data_to_record = (
|
||||||
|
!hi.empty() || handed_in_money
|
||||||
|
);
|
||||||
|
|
||||||
|
if (player_event_logs.IsEventEnabled(PlayerEvent::NPC_HANDIN) && event_has_data_to_record) {
|
||||||
|
auto e = PlayerEvent::HandinEvent{
|
||||||
|
.npc_id = n->GetNPCTypeID(),
|
||||||
|
.npc_name = n->GetCleanName(),
|
||||||
|
.handin_items = hi,
|
||||||
|
.handin_money = hm,
|
||||||
|
.return_items = ri,
|
||||||
|
.return_money = rm,
|
||||||
|
.is_quest_handin = true
|
||||||
|
};
|
||||||
|
|
||||||
|
RecordPlayerEventLogWithClient(c, PlayerEvent::NPC_HANDIN, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 item_count = 0;
|
||||||
|
|
||||||
|
hm.platinum = t->pp;
|
||||||
|
hm.gold = t->gp;
|
||||||
|
hm.silver = t->sp;
|
||||||
|
hm.copper = t->cp;
|
||||||
|
|
||||||
|
for (uint16 i = EQ::invslot::TRADE_BEGIN; i <= EQ::invslot::TRADE_NPC_END; i++) {
|
||||||
|
if (c->GetInv().GetItem(i)) {
|
||||||
|
item_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hi.reserve(item_count);
|
||||||
|
|
||||||
|
if (item_count > 0) {
|
||||||
|
for (uint16 i = EQ::invslot::TRADE_BEGIN; i <= EQ::invslot::TRADE_NPC_END; i++) {
|
||||||
|
const EQ::ItemInstance* inst = c->GetInv().GetItem(i);
|
||||||
|
if (inst) {
|
||||||
|
hi.emplace_back(
|
||||||
|
PlayerEvent::HandinEntry{
|
||||||
|
.item_id = inst->GetItem()->ID,
|
||||||
|
.item_name = inst->GetItem()->Name,
|
||||||
|
.charges = static_cast<uint16>(inst->GetCharges()),
|
||||||
|
.attuned = inst->IsAttuned()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (inst->IsClassBag()) {
|
||||||
|
for (uint8 j = EQ::invbag::SLOT_BEGIN; j <= EQ::invbag::SLOT_END; j++) {
|
||||||
|
inst = c->GetInv().GetItem(i, j);
|
||||||
|
if (inst) {
|
||||||
|
hi.emplace_back(
|
||||||
|
PlayerEvent::HandinEntry{
|
||||||
|
.item_id = inst->GetItem()->ID,
|
||||||
|
.item_name = inst->GetItem()->Name,
|
||||||
|
.charges = static_cast<uint16>(inst->GetCharges()),
|
||||||
|
.attuned = inst->IsAttuned()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool handed_in_money = hm.platinum > 0 || hm.gold > 0 || hm.silver > 0 || hm.copper > 0;
|
||||||
|
|
||||||
|
ri = hi;
|
||||||
|
rm = hm;
|
||||||
|
|
||||||
|
const bool event_has_data_to_record = !hi.empty() || handed_in_money;
|
||||||
|
|
||||||
|
if (player_event_logs.IsEventEnabled(PlayerEvent::NPC_HANDIN) && event_has_data_to_record) {
|
||||||
|
auto e = PlayerEvent::HandinEvent{
|
||||||
|
.npc_id = n->GetNPCTypeID(),
|
||||||
|
.npc_name = n->GetCleanName(),
|
||||||
|
.handin_items = hi,
|
||||||
|
.handin_money = hm,
|
||||||
|
.return_items = ri,
|
||||||
|
.return_money = rm,
|
||||||
|
.is_quest_handin = false
|
||||||
|
};
|
||||||
|
|
||||||
|
RecordPlayerEventLogWithClient(c, PlayerEvent::NPC_HANDIN, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Client::ShowSpells(Client* c, ShowSpellType show_spell_type)
|
void Client::ShowSpells(Client* c, ShowSpellType show_spell_type)
|
||||||
{
|
{
|
||||||
std::string spell_string;
|
std::string spell_string;
|
||||||
|
|||||||
@@ -2227,6 +2227,7 @@ private:
|
|||||||
bool CanTradeFVNoDropItem();
|
bool CanTradeFVNoDropItem();
|
||||||
void SendMobPositions();
|
void SendMobPositions();
|
||||||
void PlayerTradeEventLog(Trade *t, Trade *t2);
|
void PlayerTradeEventLog(Trade *t, Trade *t2);
|
||||||
|
void NPCHandinEventLog(Trade* t, NPC* n);
|
||||||
|
|
||||||
// full and partial mail key cache
|
// full and partial mail key cache
|
||||||
std::string m_mail_key_full;
|
std::string m_mail_key_full;
|
||||||
|
|||||||
+2
-2
@@ -40,7 +40,7 @@ extern FastMath g_Math;
|
|||||||
void CatchSignal(int sig_num);
|
void CatchSignal(int sig_num);
|
||||||
|
|
||||||
|
|
||||||
int command_count; // how many commands we have
|
int command_count; // how many commands we have
|
||||||
|
|
||||||
// this is the pointer to the dispatch function, updated once
|
// this is the pointer to the dispatch function, updated once
|
||||||
// init has been performed to point at the real function
|
// init has been performed to point at the real function
|
||||||
@@ -96,7 +96,7 @@ int command_init(void)
|
|||||||
command_add("augmentitem", "Force augments an item. Must have the augment item window open.", AccountStatus::GMImpossible, command_augmentitem) ||
|
command_add("augmentitem", "Force augments an item. Must have the augment item window open.", AccountStatus::GMImpossible, command_augmentitem) ||
|
||||||
command_add("ban", "[Character Name] [Reason] - Ban by character name", AccountStatus::GMLeadAdmin, command_ban) ||
|
command_add("ban", "[Character Name] [Reason] - Ban by character name", AccountStatus::GMLeadAdmin, command_ban) ||
|
||||||
command_add("bugs", "[Close|Delete|Review|Search|View] - Handles player bug reports", AccountStatus::QuestTroupe, command_bugs) ||
|
command_add("bugs", "[Close|Delete|Review|Search|View] - Handles player bug reports", AccountStatus::QuestTroupe, command_bugs) ||
|
||||||
command_add("bot", "Type \"#bot help\" or \"^help\" to the see the list of available commands for bots.", AccountStatus::Player, command_bot) ||
|
(RuleB(Bots, Enabled) && command_add("bot", "Type \"#bot help\" or \"^help\" to the see the list of available commands for bots.", AccountStatus::Player, command_bot)) ||
|
||||||
command_add("camerashake", "[Duration (Milliseconds)] [Intensity (1-10)] - Shakes the camera on everyone's screen globally.", AccountStatus::QuestTroupe, command_camerashake) ||
|
command_add("camerashake", "[Duration (Milliseconds)] [Intensity (1-10)] - Shakes the camera on everyone's screen globally.", AccountStatus::QuestTroupe, command_camerashake) ||
|
||||||
command_add("castspell", "[Spell ID] [Instant (0 = False, 1 = True, Default is 1 if Unused)] - Cast a spell", AccountStatus::Guide, command_castspell) ||
|
command_add("castspell", "[Spell ID] [Instant (0 = False, 1 = True, Default is 1 if Unused)] - Cast a spell", AccountStatus::Guide, command_castspell) ||
|
||||||
command_add("chat", "[Channel ID] [Message] - Send a channel message to all zones", AccountStatus::GMMgmt, command_chat) ||
|
command_add("chat", "[Channel ID] [Message] - Send a channel message to all zones", AccountStatus::GMMgmt, command_chat) ||
|
||||||
|
|||||||
+7
-1
@@ -1096,7 +1096,7 @@ void EntityList::AESpell(
|
|||||||
max_targets = nullptr;
|
max_targets = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int max_targets_allowed = 4;
|
int max_targets_allowed = RuleI(Spells, DefaultAOEMaxTargets);;
|
||||||
if (max_targets) { // rains pass this in since they need to preserve the count through waves
|
if (max_targets) { // rains pass this in since they need to preserve the count through waves
|
||||||
max_targets_allowed = *max_targets;
|
max_targets_allowed = *max_targets;
|
||||||
} else if (spells[spell_id].aoe_max_targets) {
|
} else if (spells[spell_id].aoe_max_targets) {
|
||||||
@@ -1109,6 +1109,12 @@ void EntityList::AESpell(
|
|||||||
!IsEffectInSpell(spell_id, SE_Mez)
|
!IsEffectInSpell(spell_id, SE_Mez)
|
||||||
) {
|
) {
|
||||||
max_targets_allowed = RuleI(Spells, TargetedAOEMaxTargets);
|
max_targets_allowed = RuleI(Spells, TargetedAOEMaxTargets);
|
||||||
|
} else if (
|
||||||
|
IsPBAENukeSpell(spell_id) &&
|
||||||
|
IsDetrimentalSpell &&
|
||||||
|
!is_npc
|
||||||
|
) {
|
||||||
|
max_targets_allowed = RuleI(Spells, PointBlankAOEMaxTargets);
|
||||||
}
|
}
|
||||||
|
|
||||||
int target_hit_counter = 0;
|
int target_hit_counter = 0;
|
||||||
|
|||||||
+14
-6
@@ -31,12 +31,14 @@ Map::~Map() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
float Map::FindBestZ(glm::vec3 &start, glm::vec3 *result) const {
|
float Map::FindBestZ(glm::vec3 &start, glm::vec3 *result) const {
|
||||||
if (!imp)
|
if (!imp) {
|
||||||
return BEST_Z_INVALID;
|
return BEST_Z_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
glm::vec3 tmp;
|
glm::vec3 tmp;
|
||||||
if(!result)
|
if (!result) {
|
||||||
result = &tmp;
|
result = &tmp;
|
||||||
|
}
|
||||||
|
|
||||||
start.z += RuleI(Map, FindBestZHeightAdjust);
|
start.z += RuleI(Map, FindBestZHeightAdjust);
|
||||||
glm::vec3 from(start.x, start.y, start.z);
|
glm::vec3 from(start.x, start.y, start.z);
|
||||||
@@ -45,16 +47,22 @@ float Map::FindBestZ(glm::vec3 &start, glm::vec3 *result) const {
|
|||||||
bool hit = false;
|
bool hit = false;
|
||||||
|
|
||||||
hit = imp->rm->raycast((const RmReal*)&from, (const RmReal*)&to, (RmReal*)result, nullptr, &hit_distance);
|
hit = imp->rm->raycast((const RmReal*)&from, (const RmReal*)&to, (RmReal*)result, nullptr, &hit_distance);
|
||||||
if(hit) {
|
if (hit && zone->newzone_data.underworld != 0.0f && result->z < zone->newzone_data.underworld) {
|
||||||
|
hit = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hit) {
|
||||||
return result->z;
|
return result->z;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find nearest Z above us
|
// Find nearest Z above us
|
||||||
|
|
||||||
to.z = -BEST_Z_INVALID;
|
to.z = -BEST_Z_INVALID;
|
||||||
hit = imp->rm->raycast((const RmReal*)&from, (const RmReal*)&to, (RmReal*)result, nullptr, &hit_distance);
|
hit = imp->rm->raycast((const RmReal*)&from, (const RmReal*)&to, (RmReal*)result, nullptr, &hit_distance);
|
||||||
if (hit)
|
if (zone->newzone_data.max_z != 0.0f && result->z > zone->newzone_data.max_z) {
|
||||||
{
|
hit = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hit) {
|
||||||
return result->z;
|
return result->z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-175
@@ -90,8 +90,6 @@ void QuestManager::Process() {
|
|||||||
while (cur != end) {
|
while (cur != end) {
|
||||||
if (cur->Timer_.Enabled() && cur->Timer_.Check()) {
|
if (cur->Timer_.Enabled() && cur->Timer_.Check()) {
|
||||||
if (cur->mob) {
|
if (cur->mob) {
|
||||||
parse->EventMob(EVENT_TIMER, cur->mob, nullptr, [&]() { return cur->name; }, 0);
|
|
||||||
|
|
||||||
if (cur->mob->IsEncounter()) {
|
if (cur->mob->IsEncounter()) {
|
||||||
parse->EventEncounter(
|
parse->EventEncounter(
|
||||||
EVENT_TIMER,
|
EVENT_TIMER,
|
||||||
@@ -100,6 +98,8 @@ void QuestManager::Process() {
|
|||||||
0,
|
0,
|
||||||
nullptr
|
nullptr
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
parse->EventMob(EVENT_TIMER, cur->mob, nullptr, [&]() { return cur->name; }, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
//we MUST reset our iterator since the quest could have removed/added any
|
//we MUST reset our iterator since the quest could have removed/added any
|
||||||
@@ -4611,179 +4611,7 @@ int8 QuestManager::DoesAugmentFit(EQ::ItemInstance* inst, uint32 augment_id, uin
|
|||||||
}
|
}
|
||||||
|
|
||||||
void QuestManager::SendPlayerHandinEvent() {
|
void QuestManager::SendPlayerHandinEvent() {
|
||||||
QuestManagerCurrentQuestVars();
|
return;
|
||||||
if (!owner || !owner->IsNPC() || !initiator) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
!initiator->EntityVariableExists("HANDIN_ITEMS") &&
|
|
||||||
!initiator->EntityVariableExists("HANDIN_MONEY") &&
|
|
||||||
!initiator->EntityVariableExists("RETURN_ITEMS") &&
|
|
||||||
!initiator->EntityVariableExists("RETURN_MONEY")
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto handin_items = initiator->GetEntityVariable("HANDIN_ITEMS");
|
|
||||||
auto return_items = initiator->GetEntityVariable("RETURN_ITEMS");
|
|
||||||
auto handin_money = initiator->GetEntityVariable("HANDIN_MONEY");
|
|
||||||
auto return_money = initiator->GetEntityVariable("RETURN_MONEY");
|
|
||||||
|
|
||||||
std::vector<PlayerEvent::HandinEntry> hi = {};
|
|
||||||
std::vector<PlayerEvent::HandinEntry> ri = {};
|
|
||||||
PlayerEvent::HandinMoney hm{};
|
|
||||||
PlayerEvent::HandinMoney rm{};
|
|
||||||
|
|
||||||
// Handin Items
|
|
||||||
if (!handin_items.empty()) {
|
|
||||||
if (Strings::Contains(handin_items, ",")) {
|
|
||||||
const auto handin_data = Strings::Split(handin_items, ",");
|
|
||||||
for (const auto &h: handin_data) {
|
|
||||||
const auto item_data = Strings::Split(h, "|");
|
|
||||||
if (
|
|
||||||
item_data.size() == 3 &&
|
|
||||||
Strings::IsNumber(item_data[0]) &&
|
|
||||||
Strings::IsNumber(item_data[1]) &&
|
|
||||||
Strings::IsNumber(item_data[2])
|
|
||||||
) {
|
|
||||||
const auto item_id = static_cast<uint32>(Strings::ToUnsignedInt(item_data[0]));
|
|
||||||
if (item_id != 0) {
|
|
||||||
const auto *item = database.GetItem(item_id);
|
|
||||||
|
|
||||||
if (item) {
|
|
||||||
hi.emplace_back(
|
|
||||||
PlayerEvent::HandinEntry{
|
|
||||||
.item_id = item_id,
|
|
||||||
.item_name = item->Name,
|
|
||||||
.charges = static_cast<uint16>(Strings::ToUnsignedInt(item_data[1])),
|
|
||||||
.attuned = Strings::ToInt(item_data[2]) ? true : false
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (Strings::Contains(handin_items, "|")) {
|
|
||||||
const auto item_data = Strings::Split(handin_items, "|");
|
|
||||||
if (
|
|
||||||
item_data.size() == 3 &&
|
|
||||||
Strings::IsNumber(item_data[0]) &&
|
|
||||||
Strings::IsNumber(item_data[1]) &&
|
|
||||||
Strings::IsNumber(item_data[2])
|
|
||||||
) {
|
|
||||||
const auto item_id = static_cast<uint32>(Strings::ToUnsignedInt(item_data[0]));
|
|
||||||
const auto *item = database.GetItem(item_id);
|
|
||||||
|
|
||||||
if (item) {
|
|
||||||
hi.emplace_back(
|
|
||||||
PlayerEvent::HandinEntry{
|
|
||||||
.item_id = item_id,
|
|
||||||
.item_name = item->Name,
|
|
||||||
.charges = static_cast<uint16>(Strings::ToUnsignedInt(item_data[1])),
|
|
||||||
.attuned = Strings::ToInt(item_data[2]) ? true : false
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handin Money
|
|
||||||
if (!handin_money.empty()) {
|
|
||||||
const auto hms = Strings::Split(handin_money, "|");
|
|
||||||
hm.copper = static_cast<uint32>(Strings::ToUnsignedInt(hms[0]));
|
|
||||||
hm.silver = static_cast<uint32>(Strings::ToUnsignedInt(hms[1]));
|
|
||||||
hm.gold = static_cast<uint32>(Strings::ToUnsignedInt(hms[2]));
|
|
||||||
hm.platinum = static_cast<uint32>(Strings::ToUnsignedInt(hms[3]));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return Items
|
|
||||||
if (!return_items.empty()) {
|
|
||||||
if (Strings::Contains(return_items, ",")) {
|
|
||||||
const auto return_data = Strings::Split(return_items, ",");
|
|
||||||
for (const auto &r: return_data) {
|
|
||||||
const auto item_data = Strings::Split(r, "|");
|
|
||||||
if (
|
|
||||||
item_data.size() == 3 &&
|
|
||||||
Strings::IsNumber(item_data[0]) &&
|
|
||||||
Strings::IsNumber(item_data[1]) &&
|
|
||||||
Strings::IsNumber(item_data[2])
|
|
||||||
) {
|
|
||||||
const auto item_id = static_cast<uint32>(Strings::ToUnsignedInt(item_data[0]));
|
|
||||||
const auto *item = database.GetItem(item_id);
|
|
||||||
|
|
||||||
if (item) {
|
|
||||||
ri.emplace_back(
|
|
||||||
PlayerEvent::HandinEntry{
|
|
||||||
.item_id = item_id,
|
|
||||||
.item_name = item->Name,
|
|
||||||
.charges = static_cast<uint16>(Strings::ToUnsignedInt(item_data[1])),
|
|
||||||
.attuned = Strings::ToInt(item_data[2]) ? true : false
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (Strings::Contains(return_items, "|")) {
|
|
||||||
const auto item_data = Strings::Split(return_items, "|");
|
|
||||||
if (
|
|
||||||
item_data.size() == 3 &&
|
|
||||||
Strings::IsNumber(item_data[0]) &&
|
|
||||||
Strings::IsNumber(item_data[1]) &&
|
|
||||||
Strings::IsNumber(item_data[2])
|
|
||||||
) {
|
|
||||||
const auto item_id = static_cast<uint32>(Strings::ToUnsignedInt(item_data[0]));
|
|
||||||
const auto *item = database.GetItem(item_id);
|
|
||||||
|
|
||||||
if (item) {
|
|
||||||
ri.emplace_back(
|
|
||||||
PlayerEvent::HandinEntry{
|
|
||||||
.item_id = item_id,
|
|
||||||
.item_name = item->Name,
|
|
||||||
.charges = static_cast<uint16>(Strings::ToUnsignedInt(item_data[1])),
|
|
||||||
.attuned = Strings::ToInt(item_data[2]) ? true : false
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return Money
|
|
||||||
if (!return_money.empty()) {
|
|
||||||
const auto rms = Strings::Split(return_money, "|");
|
|
||||||
rm.copper = static_cast<uint32>(Strings::ToUnsignedInt(rms[0]));
|
|
||||||
rm.silver = static_cast<uint32>(Strings::ToUnsignedInt(rms[1]));
|
|
||||||
rm.gold = static_cast<uint32>(Strings::ToUnsignedInt(rms[2]));
|
|
||||||
rm.platinum = static_cast<uint32>(Strings::ToUnsignedInt(rms[3]));
|
|
||||||
}
|
|
||||||
|
|
||||||
initiator->DeleteEntityVariable("HANDIN_ITEMS");
|
|
||||||
initiator->DeleteEntityVariable("HANDIN_MONEY");
|
|
||||||
initiator->DeleteEntityVariable("RETURN_ITEMS");
|
|
||||||
initiator->DeleteEntityVariable("RETURN_MONEY");
|
|
||||||
|
|
||||||
bool handed_in_money = hm.platinum > 0 || hm.gold > 0 || hm.silver > 0 || hm.copper > 0;
|
|
||||||
|
|
||||||
bool event_has_data_to_record = (
|
|
||||||
!hi.empty() || handed_in_money
|
|
||||||
);
|
|
||||||
|
|
||||||
if (player_event_logs.IsEventEnabled(PlayerEvent::NPC_HANDIN) && event_has_data_to_record) {
|
|
||||||
auto e = PlayerEvent::HandinEvent{
|
|
||||||
.npc_id = owner->CastToNPC()->GetNPCTypeID(),
|
|
||||||
.npc_name = owner->GetCleanName(),
|
|
||||||
.handin_items = hi,
|
|
||||||
.handin_money = hm,
|
|
||||||
.return_items = ri,
|
|
||||||
.return_money = rm
|
|
||||||
};
|
|
||||||
|
|
||||||
RecordPlayerEventLogWithClient(initiator, PlayerEvent::NPC_HANDIN, e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string QuestManager::GetAutoLoginCharacterNameByAccountID(uint32 account_id)
|
std::string QuestManager::GetAutoLoginCharacterNameByAccountID(uint32 account_id)
|
||||||
|
|||||||
@@ -2964,7 +2964,6 @@ int Mob::CalcBuffDuration(Mob *caster, Mob *target, uint16 spell_id, int32 caste
|
|||||||
|
|
||||||
int res = CalcBuffDuration_formula(castlevel, formula, duration);
|
int res = CalcBuffDuration_formula(castlevel, formula, duration);
|
||||||
if (
|
if (
|
||||||
caster == target &&
|
|
||||||
(
|
(
|
||||||
target->aabonuses.IllusionPersistence ||
|
target->aabonuses.IllusionPersistence ||
|
||||||
target->spellbonuses.IllusionPersistence ||
|
target->spellbonuses.IllusionPersistence ||
|
||||||
|
|||||||
+16
-14
@@ -664,6 +664,8 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(tradingWith && tradingWith->IsNPC()) {
|
else if(tradingWith && tradingWith->IsNPC()) {
|
||||||
|
NPCHandinEventLog(trade, tradingWith->CastToNPC());
|
||||||
|
|
||||||
QSPlayerLogHandin_Struct* qs_audit = nullptr;
|
QSPlayerLogHandin_Struct* qs_audit = nullptr;
|
||||||
bool qs_log = false;
|
bool qs_log = false;
|
||||||
|
|
||||||
@@ -832,13 +834,13 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto loot_drop_entry = LootdropEntriesRepository::NewNpcEntity();
|
auto lde = LootdropEntriesRepository::NewNpcEntity();
|
||||||
loot_drop_entry.equip_item = 1;
|
lde.equip_item = 1;
|
||||||
loot_drop_entry.item_charges = static_cast<int8>(baginst->GetCharges());
|
lde.item_charges = static_cast<int8>(baginst->GetCharges());
|
||||||
|
|
||||||
tradingWith->CastToNPC()->AddLootDrop(
|
tradingWith->CastToNPC()->AddLootDrop(
|
||||||
bagitem,
|
bagitem,
|
||||||
loot_drop_entry,
|
lde,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
// Return quest items being traded to non-quest NPC when the rule is true
|
// Return quest items being traded to non-quest NPC when the rule is true
|
||||||
@@ -857,17 +859,17 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
auto lde = LootdropEntriesRepository::NewNpcEntity();
|
||||||
|
lde.equip_item = 1;
|
||||||
|
lde.item_charges = static_cast<int8>(inst->GetCharges());
|
||||||
|
|
||||||
|
tradingWith->CastToNPC()->AddLootDrop(
|
||||||
|
item,
|
||||||
|
lde,
|
||||||
|
true
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto new_loot_drop_entry = LootdropEntriesRepository::NewNpcEntity();
|
|
||||||
new_loot_drop_entry.equip_item = 1;
|
|
||||||
new_loot_drop_entry.item_charges = static_cast<int8>(inst->GetCharges());
|
|
||||||
|
|
||||||
tradingWith->CastToNPC()->AddLootDrop(
|
|
||||||
item,
|
|
||||||
new_loot_drop_entry,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
// Return quest items being traded to non-quest NPC when the rule is true
|
// Return quest items being traded to non-quest NPC when the rule is true
|
||||||
else if (restrict_quest_items_to_quest_npc && (!is_quest_npc && item->IsQuestItem())) {
|
else if (restrict_quest_items_to_quest_npc && (!is_quest_npc && item->IsQuestItem())) {
|
||||||
|
|||||||
@@ -3472,6 +3472,9 @@ bool ZoneDatabase::LoadFactionData()
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto& fmr_row = faction_max_results.begin();
|
auto& fmr_row = faction_max_results.begin();
|
||||||
|
if (fmr_row[0] == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
max_faction = Strings::ToUnsignedInt(fmr_row[0]);
|
max_faction = Strings::ToUnsignedInt(fmr_row[0]);
|
||||||
faction_array = new Faction *[max_faction + 1];
|
faction_array = new Faction *[max_faction + 1];
|
||||||
|
|||||||
+1
-1
@@ -737,7 +737,7 @@ void Client::ProcessMovePC(uint32 zoneID, uint32 instance_id, float x, float y,
|
|||||||
ZonePC(zoneID, instance_id, x, y, z, heading, ignorerestrictions, zm);
|
ZonePC(zoneID, instance_id, x, y, z, heading, ignorerestrictions, zm);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LogError("Client::ProcessMovePC received a reguest to perform an unsupported client zone operation");
|
LogError("Received a request to perform an unsupported client zone operation");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user