diff --git a/CHANGELOG.md b/CHANGELOG.md index 355658a66..62b0d6af6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,28 @@ +## [22.20.0] - 07/15/2023 + +### Bots + +* Remove orphaned commands related to botgroup ([#3489](https://github.com/EQEmu/Server/pull/3489)) @tuday2 2023-07-09 + +### Commands + +* Consolidate #set-like commands into a singular #set command ([#3486](https://github.com/EQEmu/Server/pull/3486)) @Kinglykrab 2023-07-15 + +### Feature + +* Add Support for item textures higher than 65,535 ([#3494](https://github.com/EQEmu/Server/pull/3494)) @Kinglykrab 2023-07-14 +* Update raid features ([#3443](https://github.com/EQEmu/Server/pull/3443)) @neckkola 2023-07-13 + +### Fixes + +* Fix Tradeskill Combines with augmented items ([#3490](https://github.com/EQEmu/Server/pull/3490)) @Kinglykrab 2023-07-15 +* Fix charmed pets to follow when charmed. ([#3488](https://github.com/EQEmu/Server/pull/3488)) @noudess 2023-07-08 +* Update bot naming check and add more explanation ([#3491](https://github.com/EQEmu/Server/pull/3491)) @tuday2 2023-07-13 + +### Quest API + +* Add Mob/Entity type check methods to Perl/Lua ([#3493](https://github.com/EQEmu/Server/pull/3493)) @Kinglykrab 2023-07-13 + ## [22.19.0] - 07/08/2023 ### Bots diff --git a/common/database/database_update_manifest.cpp b/common/database/database_update_manifest.cpp index cbfa25af9..8d24cfef4 100644 --- a/common/database/database_update_manifest.cpp +++ b/common/database/database_update_manifest.cpp @@ -4758,6 +4758,52 @@ CREATE TABLE `chatchannel_reserved_names` PRIMARY KEY (`id`) USING BTREE, UNIQUE KEY `name` (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +)" + }, + ManifestEntry{ + .version = 9230, + .description = "2023_06_23_raid_feature_updates", + .check = "SHOW COLUMNS FROM `raid_members` LIKE 'is_assister'", + .condition = "empty", + .match = "", + .sql = R"( + ALTER TABLE `raid_members` + ADD COLUMN `is_marker` TINYINT UNSIGNED DEFAULT(0) NOT NULL AFTER `islooter`, + ADD COLUMN `is_assister` TINYINT UNSIGNED DEFAULT(0) NOT NULL AFTER `is_marker`, + ADD COLUMN `note` VARCHAR(64) DEFAULT("") NOT NULL AFTER `is_assister`; + + ALTER TABLE `raid_details` + ADD COLUMN `marked_npc_1` SMALLINT UNSIGNED DEFAULT(0) NOT NULL AFTER `motd`, + ADD COLUMN `marked_npc_2` SMALLINT UNSIGNED DEFAULT(0) NOT NULL AFTER `marked_npc_1`, + ADD COLUMN `marked_npc_3` SMALLINT UNSIGNED DEFAULT(0) NOT NULL AFTER `marked_npc_2`; + )", + }, + ManifestEntry{ + .version = 9231, + .description = "2023_07_14_npc_unsigned_melee_texture.sql", + .check = "SHOW COLUMNS FROM `npc_types` LIKE 'd_melee_texture1'", + .condition = "contains", + .match = "int(11) signed", + .sql = R"(ALTER TABLE `npc_types` + MODIFY COLUMN `d_melee_texture1` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `armortint_blue`, + MODIFY COLUMN `d_melee_texture2` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `d_melee_texture1`; + )", + }, + ManifestEntry{ + .version = 9232, + .description = "2023_07_11_command_subsettings.sql", + .check = "SHOW TABLES LIKE 'command_subsettings'", + .condition = "empty", + .match = "", + .sql = R"(CREATE TABLE `command_subsettings` ( +`id` int UNSIGNED NOT NULL AUTO_INCREMENT, +`parent_command` varchar(32) NOT NULL, +`sub_command` varchar(32) NOT NULL, +`access_level` int(11) UNSIGNED NOT NULL DEFAULT 0, +`top_level_aliases` varchar(255) NOT NULL, +PRIMARY KEY (`id`), +UNIQUE INDEX `command`(`parent_command`, `sub_command`) +) )" }, diff --git a/common/emu_oplist.h b/common/emu_oplist.h index d8798c594..6e30333aa 100644 --- a/common/emu_oplist.h +++ b/common/emu_oplist.h @@ -316,6 +316,7 @@ N(OP_LootRequest), N(OP_ManaChange), N(OP_ManaUpdate), N(OP_MarkNPC), +N(OP_MarkRaidNPC), N(OP_Marquee), N(OP_MemorizeSpell), N(OP_Mend), @@ -398,6 +399,8 @@ N(OP_PVPLeaderBoardRequest), N(OP_PVPStats), N(OP_QueryResponseThing), N(OP_QueryUCSServerStatus), +N(OP_RaidDelegateAbility), +N(OP_RaidClearNPCMarks), N(OP_RaidInvite), N(OP_RaidJoin), N(OP_RaidUpdate), diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index 3e8f12694..d503f56bc 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -4105,7 +4105,9 @@ struct UpdateLeadershipAA_Struct { enum { - GroupLeadershipAbility_MarkNPC = 0 + GroupLeadershipAbility_MarkNPC = 0, + RaidLeadershipAbility_MarkNPC = 16, + RaidLeadershipAbility_MainAssist = 19 }; struct DoGroupLeadershipAbility_Struct @@ -4149,8 +4151,10 @@ struct InspectBuffs_Struct { struct RaidGeneral_Struct { /*00*/ uint32 action; //=10 /*04*/ char player_name[64]; //should both be the player's name -/*64*/ char leader_name[64]; -/*132*/ uint32 parameter; +/*68*/ uint32 unknown1; +/*72*/ char leader_name[64]; +/*136*/ uint32 parameter; +/*200*/ char note[64]; }; struct RaidAddMember_Struct { diff --git a/common/features.h b/common/features.h index 082f18897..d49e5f015 100644 --- a/common/features.h +++ b/common/features.h @@ -240,36 +240,22 @@ enum { //some random constants //Some hard coded statuses from commands and other places: enum { - minStatusToBeGM = 40, - minStatusToUseGMCommands = 80, - minStatusToKick = 150, - minStatusToAvoidFalling = 100, - minStatusToHaveInvalidSpells = 80, - minStatusToHaveInvalidSkills = 80, - minStatusToIgnoreZoneFlags = 80, + minStatusToBeGM = 40, + minStatusToUseGMCommands = 80, + minStatusToKick = 150, + minStatusToAvoidFalling = 100, + minStatusToIgnoreZoneFlags = 80, minStatusToSeeOthersZoneFlags = 80, - minStatusToEditOtherGuilds = 80, - commandMovecharSelfOnly = 80, //below this == only self move allowed - commandMovecharToSpecials = 200, //ability to send people to cshom/load zones - commandZoneToSpecials = 80, //zone to cshome, out of load zones - commandToggleAI = 250, //can turn NPC AI on and off - commandCastSpecials = 100, //can cast special spells - commandInstacast = 100, //insta-cast all #casted spells - commandLevelAboveCap = 100, //can #level players above level cap - commandLevelNPCAboveCap = 100, //can #level NPCs above level cap - commandSetSkillsOther = 100, //ability to setskills on others - commandRaceOthers = 100, //ability to #race on others - commandGenderOthers = 100, //ability to #gender on others - commandTextureOthers = 100, //ability to #texture on others - commandDoAnimOthers = 100, //can #doanim on others - commandLockZones = 101, //can lock or unlock zones - commandEditPlayerCorpses = 150, //can Edit Player Corpses - commandChangeFlags = 200, //ability to set/refresh flags - commandBanPlayers = 100, //can set bans on players - commandChangeDatarate = 201, //edit client's data rate - commandZoneToCoords = 0, //can #zone with coords - commandInterrogateInv = 100, //below this == only log on error state and self-only target dump - commandInvSnapshot = 150 //ability to clear/restore snapshots + minStatusToEditOtherGuilds = 80, + commandMovecharSelfOnly = 80, //below this == only self move allowed + commandMovecharToSpecials = 200, //ability to send people to cshom/load zones + commandCastSpecials = 100, //can cast special spells + commandInstacast = 100, //insta-cast all #casted spells + commandDoAnimOthers = 100, //can #doanim on others + commandLockZones = 101, //can lock or unlock zones + commandEditPlayerCorpses = 150, //can Edit Player Corpses + commandInterrogateInv = 100, //below this == only log on error state and self-only target dump + commandInvSnapshot = 150 //ability to clear/restore snapshots }; diff --git a/common/item_instance.cpp b/common/item_instance.cpp index 897512a1d..2b3c75428 100644 --- a/common/item_instance.cpp +++ b/common/item_instance.cpp @@ -720,12 +720,14 @@ EQ::ItemInstance* EQ::ItemInstance::RemoveAugment(uint8 index) bool EQ::ItemInstance::IsAugmented() { - if (!m_item || !m_item->IsClassCommon()) + if (!m_item || !m_item->IsClassCommon()) { return false; + } - for (int index = invaug::SOCKET_BEGIN; index <= invaug::SOCKET_END; ++index) { - if (GetAugmentItemID(index)) + for (uint8 slot_id = invaug::SOCKET_BEGIN; slot_id <= invaug::SOCKET_END; ++slot_id) { + if (GetAugmentItemID(slot_id)) { return true; + } } return false; diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index 30b6ad70a..a9ee64c94 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -35,6 +35,7 @@ #include "../path_manager.h" #include "../classes.h" #include "../races.h" +#include "../../zone/raids.h" #include #include @@ -2737,7 +2738,7 @@ namespace RoF2 { RaidLeadershipUpdate_Struct *inlaa = (RaidLeadershipUpdate_Struct *)__emu_buffer; auto outapp = - new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct)); + new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct)); structs::RaidLeadershipUpdate_Struct *outlaa = (structs::RaidLeadershipUpdate_Struct *)outapp->pBuffer; outlaa->action = inlaa->action; @@ -2746,6 +2747,18 @@ namespace RoF2 memcpy(&outlaa->raid, &inlaa->raid, sizeof(RaidLeadershipAA_Struct)); dest->FastQueuePacket(&outapp); } + else if (raid_gen->action == raidSetNote) + { + auto in_note = (RaidGeneral_Struct*)__emu_buffer; + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); + auto note = (RaidGeneral_Struct*)outapp->pBuffer; + note->action = raidSetNote; + strn0cpy(note->leader_name, in_note->leader_name, sizeof(note->leader_name)); + strn0cpy(note->player_name, in_note->player_name, sizeof(note->leader_name)); + strn0cpy(note->note, in_note->note, sizeof(note->note)); + dest->QueuePacket(outapp); + safe_delete(outapp); + } else { RaidGeneral_Struct* in_raid_general = (RaidGeneral_Struct*)__emu_buffer; diff --git a/common/repositories/base/base_command_subsettings_repository.h b/common/repositories/base/base_command_subsettings_repository.h new file mode 100644 index 000000000..1731f5470 --- /dev/null +++ b/common/repositories/base/base_command_subsettings_repository.h @@ -0,0 +1,364 @@ +/** + * 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://eqemu.gitbook.io/server/in-development/developer-area/repositories + */ + +#ifndef EQEMU_BASE_COMMAND_SUBSETTINGS_REPOSITORY_H +#define EQEMU_BASE_COMMAND_SUBSETTINGS_REPOSITORY_H + +#include "../../database.h" +#include "../../strings.h" +#include + + +class BaseCommandSubsettingsRepository { +public: + struct CommandSubsettings { + uint32_t id; + std::string parent_command; + std::string sub_command; + uint32_t access_level; + std::string top_level_aliases; + }; + + static std::string PrimaryKey() + { + return std::string("id"); + } + + static std::vector Columns() + { + return { + "id", + "parent_command", + "sub_command", + "access_level", + "top_level_aliases", + }; + } + + static std::vector SelectColumns() + { + return { + "id", + "parent_command", + "sub_command", + "access_level", + "top_level_aliases", + }; + } + + 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("command_subsettings"); + } + + static std::string BaseSelect() + { + return fmt::format( + "SELECT {} FROM {}", + SelectColumnsRaw(), + TableName() + ); + } + + static std::string BaseInsert() + { + return fmt::format( + "INSERT INTO {} ({}) ", + TableName(), + ColumnsRaw() + ); + } + + static CommandSubsettings NewEntity() + { + CommandSubsettings e{}; + + e.id = 0; + e.parent_command = ""; + e.sub_command = ""; + e.access_level = 0; + e.top_level_aliases = ""; + + return e; + } + + static CommandSubsettings GetCommandSubsettings( + const std::vector &command_subsettingss, + int command_subsettings_id + ) + { + for (auto &command_subsettings : command_subsettingss) { + if (command_subsettings.id == command_subsettings_id) { + return command_subsettings; + } + } + + return NewEntity(); + } + + static CommandSubsettings FindOne( + Database& db, + int command_subsettings_id + ) + { + auto results = db.QueryDatabase( + fmt::format( + "{} WHERE {} = {} LIMIT 1", + BaseSelect(), + PrimaryKey(), + command_subsettings_id + ) + ); + + auto row = results.begin(); + if (results.RowCount() == 1) { + CommandSubsettings e{}; + + e.id = static_cast(strtoul(row[0], nullptr, 10)); + e.parent_command = row[1] ? row[1] : ""; + e.sub_command = row[2] ? row[2] : ""; + e.access_level = static_cast(strtoul(row[3], nullptr, 10)); + e.top_level_aliases = row[4] ? row[4] : ""; + + return e; + } + + return NewEntity(); + } + + static int DeleteOne( + Database& db, + int command_subsettings_id + ) + { + auto results = db.QueryDatabase( + fmt::format( + "DELETE FROM {} WHERE {} = {}", + TableName(), + PrimaryKey(), + command_subsettings_id + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } + + static int UpdateOne( + Database& db, + const CommandSubsettings &e + ) + { + std::vector v; + + auto columns = Columns(); + + v.push_back(columns[1] + " = '" + Strings::Escape(e.parent_command) + "'"); + v.push_back(columns[2] + " = '" + Strings::Escape(e.sub_command) + "'"); + v.push_back(columns[3] + " = " + std::to_string(e.access_level)); + v.push_back(columns[4] + " = '" + Strings::Escape(e.top_level_aliases) + "'"); + + auto results = db.QueryDatabase( + fmt::format( + "UPDATE {} SET {} WHERE {} = {}", + TableName(), + Strings::Implode(", ", v), + PrimaryKey(), + e.id + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } + + static CommandSubsettings InsertOne( + Database& db, + CommandSubsettings e + ) + { + std::vector v; + + v.push_back(std::to_string(e.id)); + v.push_back("'" + Strings::Escape(e.parent_command) + "'"); + v.push_back("'" + Strings::Escape(e.sub_command) + "'"); + v.push_back(std::to_string(e.access_level)); + v.push_back("'" + Strings::Escape(e.top_level_aliases) + "'"); + + 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 &entries + ) + { + std::vector insert_chunks; + + for (auto &e: entries) { + std::vector v; + + v.push_back(std::to_string(e.id)); + v.push_back("'" + Strings::Escape(e.parent_command) + "'"); + v.push_back("'" + Strings::Escape(e.sub_command) + "'"); + v.push_back(std::to_string(e.access_level)); + v.push_back("'" + Strings::Escape(e.top_level_aliases) + "'"); + + insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); + } + + std::vector v; + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES {}", + BaseInsert(), + Strings::Implode(",", insert_chunks) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } + + static std::vector All(Database& db) + { + std::vector all_entries; + + auto results = db.QueryDatabase( + fmt::format( + "{}", + BaseSelect() + ) + ); + + all_entries.reserve(results.RowCount()); + + for (auto row = results.begin(); row != results.end(); ++row) { + CommandSubsettings e{}; + + e.id = static_cast(strtoul(row[0], nullptr, 10)); + e.parent_command = row[1] ? row[1] : ""; + e.sub_command = row[2] ? row[2] : ""; + e.access_level = static_cast(strtoul(row[3], nullptr, 10)); + e.top_level_aliases = row[4] ? row[4] : ""; + + all_entries.push_back(e); + } + + return all_entries; + } + + static std::vector GetWhere(Database& db, const std::string &where_filter) + { + std::vector 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) { + CommandSubsettings e{}; + + e.id = static_cast(strtoul(row[0], nullptr, 10)); + e.parent_command = row[1] ? row[1] : ""; + e.sub_command = row[2] ? row[2] : ""; + e.access_level = static_cast(strtoul(row[3], nullptr, 10)); + e.top_level_aliases = row[4] ? row[4] : ""; + + 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); + } + +}; + +#endif //EQEMU_BASE_COMMAND_SUBSETTINGS_REPOSITORY_H diff --git a/common/repositories/base/base_npc_types_repository.h b/common/repositories/base/base_npc_types_repository.h index 4a6a0f688..42e1f0ee3 100644 --- a/common/repositories/base/base_npc_types_repository.h +++ b/common/repositories/base/base_npc_types_repository.h @@ -66,8 +66,8 @@ public: uint8_t armortint_red; uint8_t armortint_green; uint8_t armortint_blue; - int32_t d_melee_texture1; - int32_t d_melee_texture2; + uint32_t d_melee_texture1; + uint32_t d_melee_texture2; std::string ammo_idfile; uint8_t prim_melee_type; uint8_t sec_melee_type; @@ -583,7 +583,7 @@ public: e.exp_mod = 100; e.heroic_strikethrough = 0; e.faction_amount = 0; - e.keeps_sold_items = 0; + e.keeps_sold_items = 1; return e; } @@ -666,8 +666,8 @@ public: e.armortint_red = static_cast(strtoul(row[43], nullptr, 10)); e.armortint_green = static_cast(strtoul(row[44], nullptr, 10)); e.armortint_blue = static_cast(strtoul(row[45], nullptr, 10)); - e.d_melee_texture1 = static_cast(atoi(row[46])); - e.d_melee_texture2 = static_cast(atoi(row[47])); + e.d_melee_texture1 = static_cast(strtoul(row[46], nullptr, 10)); + e.d_melee_texture2 = static_cast(strtoul(row[47], nullptr, 10)); e.ammo_idfile = row[48] ? row[48] : ""; e.prim_melee_type = static_cast(strtoul(row[49], nullptr, 10)); e.sec_melee_type = static_cast(strtoul(row[50], nullptr, 10)); @@ -1289,8 +1289,8 @@ public: e.armortint_red = static_cast(strtoul(row[43], nullptr, 10)); e.armortint_green = static_cast(strtoul(row[44], nullptr, 10)); e.armortint_blue = static_cast(strtoul(row[45], nullptr, 10)); - e.d_melee_texture1 = static_cast(atoi(row[46])); - e.d_melee_texture2 = static_cast(atoi(row[47])); + e.d_melee_texture1 = static_cast(strtoul(row[46], nullptr, 10)); + e.d_melee_texture2 = static_cast(strtoul(row[47], nullptr, 10)); e.ammo_idfile = row[48] ? row[48] : ""; e.prim_melee_type = static_cast(strtoul(row[49], nullptr, 10)); e.sec_melee_type = static_cast(strtoul(row[50], nullptr, 10)); @@ -1440,8 +1440,8 @@ public: e.armortint_red = static_cast(strtoul(row[43], nullptr, 10)); e.armortint_green = static_cast(strtoul(row[44], nullptr, 10)); e.armortint_blue = static_cast(strtoul(row[45], nullptr, 10)); - e.d_melee_texture1 = static_cast(atoi(row[46])); - e.d_melee_texture2 = static_cast(atoi(row[47])); + e.d_melee_texture1 = static_cast(strtoul(row[46], nullptr, 10)); + e.d_melee_texture2 = static_cast(strtoul(row[47], nullptr, 10)); e.ammo_idfile = row[48] ? row[48] : ""; e.prim_melee_type = static_cast(strtoul(row[49], nullptr, 10)); e.sec_melee_type = static_cast(strtoul(row[50], nullptr, 10)); diff --git a/common/repositories/base/base_raid_details_repository.h b/common/repositories/base/base_raid_details_repository.h index 7ce468c60..5479595bd 100644 --- a/common/repositories/base/base_raid_details_repository.h +++ b/common/repositories/base/base_raid_details_repository.h @@ -16,6 +16,7 @@ #include "../../strings.h" #include + class BaseRaidDetailsRepository { public: struct RaidDetails { @@ -23,6 +24,9 @@ public: int32_t loottype; int8_t locked; std::string motd; + uint16_t marked_npc_1; + uint16_t marked_npc_2; + uint16_t marked_npc_3; }; static std::string PrimaryKey() @@ -37,6 +41,9 @@ public: "loottype", "locked", "motd", + "marked_npc_1", + "marked_npc_2", + "marked_npc_3", }; } @@ -47,6 +54,9 @@ public: "loottype", "locked", "motd", + "marked_npc_1", + "marked_npc_2", + "marked_npc_3", }; } @@ -87,10 +97,13 @@ public: { RaidDetails e{}; - e.raidid = 0; - e.loottype = 0; - e.locked = 0; - e.motd = ""; + e.raidid = 0; + e.loottype = 0; + e.locked = 0; + e.motd = ""; + e.marked_npc_1 = 0; + e.marked_npc_2 = 0; + e.marked_npc_3 = 0; return e; } @@ -116,8 +129,9 @@ public: { auto results = db.QueryDatabase( fmt::format( - "{} WHERE id = {} LIMIT 1", + "{} WHERE {} = {} LIMIT 1", BaseSelect(), + PrimaryKey(), raid_details_id ) ); @@ -126,10 +140,13 @@ public: if (results.RowCount() == 1) { RaidDetails e{}; - e.raidid = static_cast(atoi(row[0])); - e.loottype = static_cast(atoi(row[1])); - e.locked = static_cast(atoi(row[2])); - e.motd = row[3] ? row[3] : ""; + e.raidid = static_cast(atoi(row[0])); + e.loottype = static_cast(atoi(row[1])); + e.locked = static_cast(atoi(row[2])); + e.motd = row[3] ? row[3] : ""; + e.marked_npc_1 = static_cast(strtoul(row[4], nullptr, 10)); + e.marked_npc_2 = static_cast(strtoul(row[5], nullptr, 10)); + e.marked_npc_3 = static_cast(strtoul(row[6], nullptr, 10)); return e; } @@ -167,6 +184,9 @@ public: v.push_back(columns[1] + " = " + std::to_string(e.loottype)); v.push_back(columns[2] + " = " + std::to_string(e.locked)); v.push_back(columns[3] + " = '" + Strings::Escape(e.motd) + "'"); + v.push_back(columns[4] + " = " + std::to_string(e.marked_npc_1)); + v.push_back(columns[5] + " = " + std::to_string(e.marked_npc_2)); + v.push_back(columns[6] + " = " + std::to_string(e.marked_npc_3)); auto results = db.QueryDatabase( fmt::format( @@ -192,6 +212,9 @@ public: v.push_back(std::to_string(e.loottype)); v.push_back(std::to_string(e.locked)); v.push_back("'" + Strings::Escape(e.motd) + "'"); + v.push_back(std::to_string(e.marked_npc_1)); + v.push_back(std::to_string(e.marked_npc_2)); + v.push_back(std::to_string(e.marked_npc_3)); auto results = db.QueryDatabase( fmt::format( @@ -225,6 +248,9 @@ public: v.push_back(std::to_string(e.loottype)); v.push_back(std::to_string(e.locked)); v.push_back("'" + Strings::Escape(e.motd) + "'"); + v.push_back(std::to_string(e.marked_npc_1)); + v.push_back(std::to_string(e.marked_npc_2)); + v.push_back(std::to_string(e.marked_npc_3)); insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); } @@ -258,10 +284,13 @@ public: for (auto row = results.begin(); row != results.end(); ++row) { RaidDetails e{}; - e.raidid = static_cast(atoi(row[0])); - e.loottype = static_cast(atoi(row[1])); - e.locked = static_cast(atoi(row[2])); - e.motd = row[3] ? row[3] : ""; + e.raidid = static_cast(atoi(row[0])); + e.loottype = static_cast(atoi(row[1])); + e.locked = static_cast(atoi(row[2])); + e.motd = row[3] ? row[3] : ""; + e.marked_npc_1 = static_cast(strtoul(row[4], nullptr, 10)); + e.marked_npc_2 = static_cast(strtoul(row[5], nullptr, 10)); + e.marked_npc_3 = static_cast(strtoul(row[6], nullptr, 10)); all_entries.push_back(e); } @@ -286,10 +315,13 @@ public: for (auto row = results.begin(); row != results.end(); ++row) { RaidDetails e{}; - e.raidid = static_cast(atoi(row[0])); - e.loottype = static_cast(atoi(row[1])); - e.locked = static_cast(atoi(row[2])); - e.motd = row[3] ? row[3] : ""; + e.raidid = static_cast(atoi(row[0])); + e.loottype = static_cast(atoi(row[1])); + e.locked = static_cast(atoi(row[2])); + e.motd = row[3] ? row[3] : ""; + e.marked_npc_1 = static_cast(strtoul(row[4], nullptr, 10)); + e.marked_npc_2 = static_cast(strtoul(row[5], nullptr, 10)); + e.marked_npc_3 = static_cast(strtoul(row[6], nullptr, 10)); all_entries.push_back(e); } diff --git a/common/repositories/base/base_raid_members_repository.h b/common/repositories/base/base_raid_members_repository.h index 3a0d34dcb..295325a9d 100644 --- a/common/repositories/base/base_raid_members_repository.h +++ b/common/repositories/base/base_raid_members_repository.h @@ -31,6 +31,9 @@ public: int8_t isgroupleader; int8_t israidleader; int8_t islooter; + uint8_t is_marker; + uint8_t is_assister; + std::string note; }; static std::string PrimaryKey() @@ -52,6 +55,9 @@ public: "isgroupleader", "israidleader", "islooter", + "is_marker", + "is_assister", + "note", }; } @@ -69,6 +75,9 @@ public: "isgroupleader", "israidleader", "islooter", + "is_marker", + "is_assister", + "note", }; } @@ -120,6 +129,9 @@ public: e.isgroupleader = 0; e.israidleader = 0; e.islooter = 0; + e.is_marker = 0; + e.is_assister = 0; + e.note = ""; return e; } @@ -167,6 +179,9 @@ public: e.isgroupleader = static_cast(atoi(row[8])); e.israidleader = static_cast(atoi(row[9])); e.islooter = static_cast(atoi(row[10])); + e.is_marker = static_cast(strtoul(row[11], nullptr, 10)); + e.is_assister = static_cast(strtoul(row[12], nullptr, 10)); + e.note = row[13] ? row[13] : ""; return e; } @@ -210,6 +225,9 @@ public: v.push_back(columns[8] + " = " + std::to_string(e.isgroupleader)); v.push_back(columns[9] + " = " + std::to_string(e.israidleader)); v.push_back(columns[10] + " = " + std::to_string(e.islooter)); + v.push_back(columns[11] + " = " + std::to_string(e.is_marker)); + v.push_back(columns[12] + " = " + std::to_string(e.is_assister)); + v.push_back(columns[13] + " = '" + Strings::Escape(e.note) + "'"); auto results = db.QueryDatabase( fmt::format( @@ -242,6 +260,9 @@ public: v.push_back(std::to_string(e.isgroupleader)); v.push_back(std::to_string(e.israidleader)); v.push_back(std::to_string(e.islooter)); + v.push_back(std::to_string(e.is_marker)); + v.push_back(std::to_string(e.is_assister)); + v.push_back("'" + Strings::Escape(e.note) + "'"); auto results = db.QueryDatabase( fmt::format( @@ -282,6 +303,9 @@ public: v.push_back(std::to_string(e.isgroupleader)); v.push_back(std::to_string(e.israidleader)); v.push_back(std::to_string(e.islooter)); + v.push_back(std::to_string(e.is_marker)); + v.push_back(std::to_string(e.is_assister)); + v.push_back("'" + Strings::Escape(e.note) + "'"); insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); } @@ -326,6 +350,9 @@ public: e.isgroupleader = static_cast(atoi(row[8])); e.israidleader = static_cast(atoi(row[9])); e.islooter = static_cast(atoi(row[10])); + e.is_marker = static_cast(strtoul(row[11], nullptr, 10)); + e.is_assister = static_cast(strtoul(row[12], nullptr, 10)); + e.note = row[13] ? row[13] : ""; all_entries.push_back(e); } @@ -361,6 +388,9 @@ public: e.isgroupleader = static_cast(atoi(row[8])); e.israidleader = static_cast(atoi(row[9])); e.islooter = static_cast(atoi(row[10])); + e.is_marker = static_cast(strtoul(row[11], nullptr, 10)); + e.is_assister = static_cast(strtoul(row[12], nullptr, 10)); + e.note = row[13] ? row[13] : ""; all_entries.push_back(e); } diff --git a/common/repositories/command_subsettings_repository.h b/common/repositories/command_subsettings_repository.h new file mode 100644 index 000000000..f7e65a2b6 --- /dev/null +++ b/common/repositories/command_subsettings_repository.h @@ -0,0 +1,221 @@ +#ifndef EQEMU_COMMAND_SUBSETTINGS_REPOSITORY_H +#define EQEMU_COMMAND_SUBSETTINGS_REPOSITORY_H + +#include "../database.h" +#include "../strings.h" +#include "base/base_command_subsettings_repository.h" + +class CommandSubsettingsRepository: public BaseCommandSubsettingsRepository { +public: + + /** + * This file was auto generated and can be modified and extended upon + * + * Base repository methods are automatically + * generated in the "base" version of this repository. The base repository + * is immutable and to be left untouched, while methods in this class + * are used as extension methods for more specific persistence-layer + * accessors or mutators. + * + * Base Methods (Subject to be expanded upon in time) + * + * Note: Not all tables are designed appropriately to fit functionality with all base methods + * + * InsertOne + * UpdateOne + * DeleteOne + * FindOne + * GetWhere(std::string where_filter) + * DeleteWhere(std::string where_filter) + * InsertMany + * All + * + * Example custom methods in a repository + * + * CommandSubsettingsRepository::GetByZoneAndVersion(int zone_id, int zone_version) + * CommandSubsettingsRepository::GetWhereNeverExpires() + * CommandSubsettingsRepository::GetWhereXAndY() + * CommandSubsettingsRepository::DeleteWhereXAndY() + * + * Most of the above could be covered by base methods, but if you as a developer + * find yourself re-using logic for other parts of the code, its best to just make a + * method that can be re-used easily elsewhere especially if it can use a base repository + * method and encapsulate filters there + */ + + // Custom extended repository methods here + static std::vector GetAll(Database& db) + { + // these are the base definitions for command_subsettings and can be over-ridden by the database + std::vector static_records = { + {.parent_command = "find", .sub_command = "aa", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findaa"}, + {.parent_command = "find", .sub_command = "character", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findcharacter"}, + {.parent_command = "find", .sub_command = "class", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findclass"}, + {.parent_command = "find", .sub_command = "currency", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findcurrency"}, + {.parent_command = "find", .sub_command = "deity", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "finddeity"}, + {.parent_command = "find", .sub_command = "emote", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findemote"}, + {.parent_command = "find", .sub_command = "faction", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findfaction"}, + {.parent_command = "find", .sub_command = "item", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "fi|finditem|itemsearch"}, + {.parent_command = "find", .sub_command = "language", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findlanguage"}, + {.parent_command = "find", .sub_command = "npc_type", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "fn|findnpc|findnpctype"}, + {.parent_command = "find", .sub_command = "race", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findrace"}, + {.parent_command = "find", .sub_command = "recipe", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findrecipe"}, + {.parent_command = "find", .sub_command = "skill", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findskill"}, + {.parent_command = "find", .sub_command = "spell", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "fs|findspell"}, + {.parent_command = "find", .sub_command = "task", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findtask"}, + {.parent_command = "find", .sub_command = "zone", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "fz|findzone"}, + {.parent_command = "set", .sub_command = "aa_exp", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setaaxp|setaaexp"}, + {.parent_command = "set", .sub_command = "aa_points", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setaapts|setaapoints"}, + {.parent_command = "set", .sub_command = "adventure_points", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setadventurepoints"}, + {.parent_command = "set", .sub_command = "alternate_currency", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setaltcurrency"}, + {.parent_command = "set", .sub_command = "animation", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setanim"}, + {.parent_command = "set", .sub_command = "anon", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setanon"}, + {.parent_command = "set", .sub_command = "bind", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "bind"}, + {.parent_command = "set", .sub_command = "checksum", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "updatechecksum"}, + {.parent_command = "set", .sub_command = "class_permanent", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "permaclass"}, + {.parent_command = "set", .sub_command = "crystals", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setcrystals"}, + {.parent_command = "set", .sub_command = "date", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "date"}, + {.parent_command = "set", .sub_command = "endurance", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setendurance"}, + {.parent_command = "set", .sub_command = "endurance_full", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "endurance"}, + {.parent_command = "set", .sub_command = "exp", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setxp|setexp"}, + {.parent_command = "set", .sub_command = "faction", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setfaction"}, + {.parent_command = "set", .sub_command = "flymode", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "flymode"}, + {.parent_command = "set", .sub_command = "freeze", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "freeze|unfreeze"}, + {.parent_command = "set", .sub_command = "gender", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "gender"}, + {.parent_command = "set", .sub_command = "gender_permanent", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "permagender"}, + {.parent_command = "set", .sub_command = "gm", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "gm"}, + {.parent_command = "set", .sub_command = "gm_speed", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "gmspeed"}, + {.parent_command = "set", .sub_command = "gm_status", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "flag"}, + {.parent_command = "set", .sub_command = "god_mode", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "godmode"}, + {.parent_command = "set", .sub_command = "haste", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "haste"}, + {.parent_command = "set", .sub_command = "hero_model", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "heromodel"}, + {.parent_command = "set", .sub_command = "hide_me", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "hideme"}, + {.parent_command = "set", .sub_command = "hp", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "sethp"}, + {.parent_command = "set", .sub_command = "hp_full", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "heal"}, + {.parent_command = "set", .sub_command = "invulnerable", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "invul|invulnerable"}, + {.parent_command = "set", .sub_command = "language", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setlanguage"}, + {.parent_command = "set", .sub_command = "last_name", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "lastname"}, + {.parent_command = "set", .sub_command = "level", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "level"}, + {.parent_command = "set", .sub_command = "loginserver_info", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setlsinfo"}, + {.parent_command = "set", .sub_command = "mana", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setmana"}, + {.parent_command = "set", .sub_command = "mana_full", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "mana"}, + {.parent_command = "set", .sub_command = "motd", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "motd"}, + {.parent_command = "set", .sub_command = "name", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "name"}, + {.parent_command = "set", .sub_command = "ooc_mute", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "oocmute"}, + {.parent_command = "set", .sub_command = "password", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setpass"}, + {.parent_command = "set", .sub_command = "pvp", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "pvp"}, + {.parent_command = "set", .sub_command = "pvp_points", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setpvppoints"}, + {.parent_command = "set", .sub_command = "race", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "race"}, + {.parent_command = "set", .sub_command = "race_permanent", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "permarace"}, + {.parent_command = "set", .sub_command = "server_locked", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "lock|serverlock|serverunlock|unlock"}, + {.parent_command = "set", .sub_command = "skill", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setskill"}, + {.parent_command = "set", .sub_command = "skill_all", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setallskill|setallskills|setskillall"}, + {.parent_command = "set", .sub_command = "skill_all_max", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "maxskills"}, + {.parent_command = "set", .sub_command = "start_zone", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setstartzone"}, + {.parent_command = "set", .sub_command = "temporary_name", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "tempname"}, + {.parent_command = "set", .sub_command = "texture", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "texture"}, + {.parent_command = "set", .sub_command = "time", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "time"}, + {.parent_command = "set", .sub_command = "time_zone", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "timezone"}, + {.parent_command = "set", .sub_command = "title", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "title"}, + {.parent_command = "set", .sub_command = "title_suffix", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "titlesuffix"}, + {.parent_command = "set", .sub_command = "weather", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "weather"}, + {.parent_command = "set", .sub_command = "zone", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "zclip|zcolor|zheader|zonelock|zsafecoords|zsky|zunderworld"}, + {.parent_command = "show", .sub_command = "aggro", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "aggro"}, + {.parent_command = "show", .sub_command = "buffs", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "showbuffs"}, + {.parent_command = "show", .sub_command = "buried_corpse_count", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "getplayerburiedcorpsecount"}, + {.parent_command = "show", .sub_command = "client_version_summary", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "cvs"}, + {.parent_command = "show", .sub_command = "currencies", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "viewcurrencies"}, + {.parent_command = "show", .sub_command = "distance", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "distance"}, + {.parent_command = "show", .sub_command = "emote", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "emoteview"}, + {.parent_command = "show", .sub_command = "field_of_view", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "fov"}, + {.parent_command = "show", .sub_command = "flags", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "flags"}, + {.parent_command = "show", .sub_command = "group_info", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "ginfo"}, + {.parent_command = "show", .sub_command = "hatelist", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "hatelist"}, + {.parent_command = "show", .sub_command = "inventory", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "peekinv"}, + {.parent_command = "show", .sub_command = "ip_lookup", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "iplookup"}, + {.parent_command = "show", .sub_command = "line_of_sight", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "checklos"}, + {.parent_command = "show", .sub_command = "network", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "network"}, + {.parent_command = "show", .sub_command = "network_stats", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "netstats"}, + {.parent_command = "show", .sub_command = "npc_global_loot", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "shownpcgloballoot"}, + {.parent_command = "show", .sub_command = "npc_stats", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "npcstats"}, + {.parent_command = "show", .sub_command = "npc_type", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "viewnpctype"}, + {.parent_command = "show", .sub_command = "peqzone_flags", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "peqzone_flags"}, + {.parent_command = "show", .sub_command = "petition", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "listpetition|viewpetition"}, + {.parent_command = "show", .sub_command = "petition_info", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "petitioninfo"}, + {.parent_command = "show", .sub_command = "proximity", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "proximity"}, + {.parent_command = "show", .sub_command = "quest_errors", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "questerrors"}, + {.parent_command = "show", .sub_command = "quest_globals", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "globalview"}, + {.parent_command = "show", .sub_command = "recipe", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "viewrecipe"}, + {.parent_command = "show", .sub_command = "server_info", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "serverinfo"}, + {.parent_command = "show", .sub_command = "skills", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "showskills"}, + {.parent_command = "show", .sub_command = "spawn_status", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "spawnstatus"}, + {.parent_command = "show", .sub_command = "spells", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "showspells"}, + {.parent_command = "show", .sub_command = "spells_list", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "showspellslist"}, + {.parent_command = "show", .sub_command = "stats", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "showstats"}, + {.parent_command = "show", .sub_command = "timers", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "timers"}, + {.parent_command = "show", .sub_command = "traps", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "trapinfo"}, + {.parent_command = "show", .sub_command = "uptime", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "uptime"}, + {.parent_command = "show", .sub_command = "variable", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "getvariable"}, + {.parent_command = "show", .sub_command = "version", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "version"}, + {.parent_command = "show", .sub_command = "waypoints", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "wpinfo"}, + {.parent_command = "show", .sub_command = "who", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "who"}, + {.parent_command = "show", .sub_command = "xtargets", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "xtargets"}, + {.parent_command = "show", .sub_command = "zone_global_loot", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "showzonegloballoot"}, + {.parent_command = "show", .sub_command = "zone_loot", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "viewzoneloot"}, + {.parent_command = "show", .sub_command = "zone_points", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "showzonepoints"}, + {.parent_command = "show", .sub_command = "zone_stats", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "zstats"}, + {.parent_command = "show", .sub_command = "zone_status", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "zonestatus"}, + }; + + auto db_sub_settings = All(db); + + // inject commands in the database that are not already there + std::vector new_records = {}; + for (const auto &r: static_records) { + bool found = false; + for (const auto &db_r: db_sub_settings) { + if (r.parent_command == db_r.parent_command && r.sub_command == db_r.sub_command) { + found = true; + } + } + + if (!found) { + LogInfo("New command [{}] sub-command [{}] added to database table [{}] !", r.parent_command, r.sub_command, TableName()); + new_records.emplace_back(r); + } + } + + if (!new_records.empty()) { + InsertMany(db, new_records); + // if any were added, we need to reload the list + db_sub_settings = All(db); + } + + // remove commands from the database that are not in the static list + bool any_deleted = false; + for (const auto &db_r: db_sub_settings) { + bool found = false; + for (const auto &r: static_records) { + if (r.parent_command == db_r.parent_command && r.sub_command == db_r.sub_command) { + found = true; + } + } + + if (!found) { + LogInfo("Command [{}] sub-command [{}] removed from database table [{}] !", db_r.parent_command, db_r.sub_command, TableName()); + DeleteWhere(db, fmt::format("parent_command = '{}' AND sub_command = '{}'", db_r.parent_command, db_r.sub_command)); + any_deleted = true; + } + } + + // if any were deleted, re-read the database + if (any_deleted) { + db_sub_settings = All(db); + } + + // return the final list of what's in the database + return db_sub_settings; + } +}; + +#endif //EQEMU_COMMAND_SUBSETTINGS_REPOSITORY_H diff --git a/common/repositories/raid_details_repository.h b/common/repositories/raid_details_repository.h index 524903cf2..61030c2fd 100644 --- a/common/repositories/raid_details_repository.h +++ b/common/repositories/raid_details_repository.h @@ -44,7 +44,24 @@ public: */ // Custom extended repository methods here + static int UpdateRaidMarkedNPC( + Database& db, + int32_t raid_id, + uint8_t marked_npc_number, + uint8_t value + ) { + auto results = db.QueryDatabase( + fmt::format( + "UPDATE `{}` SET `marked_npc_{}` = '{}' WHERE raidid = '{}';", + TableName(), + marked_npc_number, + value, + raid_id + ) + ); + return results.Success() ? results.RowsAffected() : 0; + } }; #endif //EQEMU_RAID_DETAILS_REPOSITORY_H diff --git a/common/repositories/raid_members_repository.h b/common/repositories/raid_members_repository.h index e8f5ddb82..2c2aae1de 100644 --- a/common/repositories/raid_members_repository.h +++ b/common/repositories/raid_members_repository.h @@ -44,7 +44,59 @@ public: */ // Custom extended repository methods here + static int UpdateRaidNote( + Database& db, + int32_t raid_id, + const std::string& note, + const std::string& character_name + ) { + auto results = db.QueryDatabase( + fmt::format("UPDATE `{}` SET `note` = '{}' WHERE raidid = '{}' AND name = '{}';", + TableName(), + Strings::Escape(note), + raid_id, + Strings::Escape(character_name) + ) + ); + return results.Success() ? results.RowsAffected() : 0; + } + + static int UpdateRaidAssister( + Database& db, + int32_t raid_id, + const std::string& character_name, + uint8_t value + ) { + auto results = db.QueryDatabase( + fmt::format( + "UPDATE `{}` SET `is_assister` = '{}' WHERE raidid = '{}' AND `name` = '{}';", + TableName(), + value, + raid_id, + Strings::Escape(character_name) + ) + ); + return results.Success() ? results.RowsAffected() : 0; + } + + static int UpdateRaidMarker( + Database& db, + int32_t raid_id, + const std::string& character_name, + uint8_t value + ) { + auto results = db.QueryDatabase( + fmt::format( + "UPDATE `{}` SET `is_marker` = '{}' WHERE raidid = '{}' AND `name` = '{}';", + TableName(), + value, + raid_id, + Strings::Escape(character_name) + ) + ); + + return results.Success() ? results.RowsAffected() : 0; + } }; - #endif //EQEMU_RAID_MEMBERS_REPOSITORY_H diff --git a/common/servertalk.h b/common/servertalk.h index f9740752f..901e2c35b 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -113,6 +113,7 @@ #define ServerOP_GroupFollowAck 0x0111 #define ServerOP_GroupCancelInvite 0x0112 #define ServerOP_RaidMOTD 0x0113 +#define ServerOP_RaidNote 0x0114 #define ServerOP_InstanceUpdateTime 0x014F #define ServerOP_AdventureRequest 0x0150 @@ -1075,6 +1076,10 @@ struct ServerRaidMOTD_Struct { char motd[0]; }; +struct ServerRaidNote_Struct { + uint32 rid; +}; + struct ServerLFGMatchesRequest_Struct { uint32 FromID; uint8 QuerierLevel; diff --git a/common/shareddb.cpp b/common/shareddb.cpp index d22de7056..44992f456 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -1635,25 +1635,29 @@ bool SharedDatabase::GetCommandSettings(std::map aliases = Strings::Split(row[2], '|'); - for (auto iter = aliases.begin(); iter != aliases.end(); ++iter) { - if (iter->empty()) + for (const auto& e : aliases) { + if (e.empty()) { continue; - command_settings[row[0]].second.push_back(*iter); + } + + command_settings[row[0]].second.push_back(e); } } - return true; + return true; } bool SharedDatabase::UpdateInjectedCommandSettings(const std::vector> &injected) @@ -1668,13 +1672,15 @@ bool SharedDatabase::UpdateInjectedCommandSettings(const std::vector &orphaned) { if (orphaned.size()) { - const std::string query = fmt::format( + std::string query = fmt::format( "DELETE FROM `command_settings` WHERE `command` IN ({})", Strings::ImplodePair(",", std::pair('\'', '\''), orphaned) ); - if (!QueryDatabase(query).Success()) { + auto results = QueryDatabase(query); + if (!results.Success()) { + return false; + } + + query = fmt::format( + "DELETE FROM `command_subsettings` WHERE `parent_command` IN ({})", + Strings::ImplodePair(",", std::pair('\'', '\''), orphaned) + ); + + auto results_two = QueryDatabase(query); + if (!results_two.Success()) { return false; } LogInfo( - "{} Orphaned Command{} Deleted", + "{} Orphaned Command{} Deleted | {} Orphaned Subcommand{} Deleted", orphaned.size(), - (orphaned.size() == 1 ? "" : "s") + orphaned.size() != 1 ? "s" : "", + results_two.RowsAffected(), + results_two.RowsAffected() != 1 ? "s" : "" ); } return true; } +bool SharedDatabase::GetCommandSubSettings(std::vector &command_subsettings) +{ + command_subsettings.clear(); + + const auto& l = CommandSubsettingsRepository::GetAll(*this); + + if (l.empty()) { + return false; + } + + command_subsettings.reserve(l.size()); + + for (const auto& e : l) { + command_subsettings.emplace_back(e); + } + + return true; +} + + bool SharedDatabase::LoadSkillCaps(const std::string &prefix) { skill_caps_mmf.reset(nullptr); diff --git a/common/shareddb.h b/common/shareddb.h index 2956fe9b2..55bc6b32f 100644 --- a/common/shareddb.h +++ b/common/shareddb.h @@ -28,6 +28,7 @@ #include "fixed_memory_hash_set.h" #include "fixed_memory_variable_hash_set.h" #include "say_link.h" +#include "repositories/command_subsettings_repository.h" #include #include @@ -77,6 +78,7 @@ public: bool GetCommandSettings(std::map>> &command_settings); bool UpdateInjectedCommandSettings(const std::vector> &injected); bool UpdateOrphanedCommandSettings(const std::vector &orphaned); + bool GetCommandSubSettings(std::vector &command_subsettings); uint32 GetTotalTimeEntitledOnAccount(uint32 AccountID); bool SetGMInvul(uint32 account_id, bool gminvul); bool SetGMFlymode(uint32 account_id, uint8 flymode); diff --git a/common/strings.cpp b/common/strings.cpp index b4cf5d011..5a806689e 100644 --- a/common/strings.cpp +++ b/common/strings.cpp @@ -882,3 +882,17 @@ std::string Strings::RemoveNumbers(std::string s) return s.substr(0, current); } + +std::string Strings::ZoneTime(const uint8 hours, const uint8 minutes) +{ + return fmt::format( + "{:02}:{:02} {}", + ( + (hours % 12) == 0 ? + 12 : + (hours % 12) + ), + minutes, + hours >= 13 ? "PM" : "AM" + ); +} diff --git a/common/strings.h b/common/strings.h index 0ef35f93f..818be96ef 100644 --- a/common/strings.h +++ b/common/strings.h @@ -130,6 +130,7 @@ public: static std::string Random(size_t length); static bool BeginsWith(const std::string& subject, const std::string& search); static bool EndsWith(const std::string& subject, const std::string& search); + static std::string ZoneTime(const uint8 hours, const uint8 minutes); template static std::string diff --git a/common/version.h b/common/version.h index 2e19f9c55..092fd7be9 100644 --- a/common/version.h +++ b/common/version.h @@ -25,7 +25,7 @@ // Build variables // these get injected during the build pipeline -#define CURRENT_VERSION "22.19.0-dev" // always append -dev to the current version for custom-builds +#define CURRENT_VERSION "22.20.0-dev" // always append -dev to the current version for custom-builds #define LOGIN_VERSION "0.8.0" #define COMPILE_DATE __DATE__ #define COMPILE_TIME __TIME__ @@ -42,7 +42,7 @@ * Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9229 +#define CURRENT_BINARY_DATABASE_VERSION 9232 #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9039 diff --git a/package.json b/package.json index 2fe8006bd..be8e658a4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eqemu-server", - "version": "22.19.0", + "version": "22.20.0", "repository": { "type": "git", "url": "https://github.com/EQEmu/Server.git" diff --git a/utils/patches/patch_RoF2.conf b/utils/patches/patch_RoF2.conf index 08e02b93c..ec63f7913 100644 --- a/utils/patches/patch_RoF2.conf +++ b/utils/patches/patch_RoF2.conf @@ -301,9 +301,7 @@ OP_LeadershipExpUpdate=0x2797 OP_PurchaseLeadershipAA=0x6c55 OP_UpdateLeadershipAA=0x0026 OP_MarkNPC=0x1fb5 -OP_MarkRaidNPC=0x5a58 #unimplemented OP_ClearNPCMarks=0x2003 -OP_ClearRaidNPCMarks=0x20d3 #unimplemented OP_DelegateAbility=0x76b8 OP_SetGroupTarget=0x2814 OP_Charm=0x5d92 @@ -544,6 +542,9 @@ OP_LFGResponse=0x0000 OP_RaidInvite=0x55ac OP_RaidUpdate=0x3973 OP_RaidJoin=0x0000 +OP_RaidDelegateAbility=0x2b33 +OP_MarkRaidNPC=0x5a58 +OP_RaidClearNPCMarks=0x20d3 # Button-push commands OP_Taunt=0x2703 diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp index c79debaaf..0136aa450 100644 --- a/world/zoneserver.cpp +++ b/world/zoneserver.cpp @@ -397,6 +397,14 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) { zoneserver_list.SendPacket(pack); break; } + case ServerOP_RaidNote: { + if (pack->size < sizeof(ServerRaidNote_Struct)) { + break; + } + + zoneserver_list.SendPacket(pack); + break; + } case ServerOP_SpawnCondition: { if (pack->size != sizeof(ServerSpawnCondition_Struct)) { break; diff --git a/zone/bot.cpp b/zone/bot.cpp index 89f13a64c..63b1adcbb 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -1273,8 +1273,11 @@ bool Bot::IsValidName(std::string& name) if (!isupper(name[0])) return false; - for (int i = 1; i < name.length(); ++i) { - if ((!RuleB(Bots, AllowCamelCaseNames) && !islower(name[i])) && name[i] != '_') { + for (char c : name.substr(1)) { + if (!RuleB(Bots, AllowCamelCaseNames) && !islower(c)) { + return false; + } + if (isdigit(c) || ispunct(c)) { return false; } } diff --git a/zone/bot_command.cpp b/zone/bot_command.cpp index 56e691bb2..f1c214a44 100644 --- a/zone/bot_command.cpp +++ b/zone/bot_command.cpp @@ -5501,11 +5501,6 @@ void bot_subcommand_bot_create(Client *c, const Seperator *sep) std::string bot_name = sep->arg[1]; bot_name = Strings::UcFirst(bot_name); - if (Strings::Contains(bot_name, "_")) { - c->Message(Chat::White, "Bot name cannot contain underscores!"); - return; - } - if (arguments < 2 || !sep->IsNumber(2)) { c->Message(Chat::White, "Invalid class!"); return; @@ -8858,8 +8853,8 @@ uint32 helper_bot_create(Client *bot_owner, std::string bot_name, uint8 bot_clas bot_owner->Message( Chat::White, fmt::format( - "'{}' is an invalid name. You may only use characters 'A-Z', 'a-z' and '_'.", - bot_name + "'{}' is an invalid name. You may only use characters 'A-Z' or 'a-z'. Mixed case {} allowed.", + bot_name, RuleB(Bots, AllowCamelCaseNames) ? "is" : "is not" ).c_str() ); return bot_id; diff --git a/zone/client.cpp b/zone/client.cpp index a74a922df..2b6682c88 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -1533,6 +1533,50 @@ bool Client::UpdateLDoNPoints(uint32 theme_id, int points) { return true; } +void Client::SetLDoNPoints(uint32 theme_id, uint32 points) +{ + switch (theme_id) { + case LDoNThemes::GUK: { + m_pp.ldon_points_guk = points; + break; + } + case LDoNThemes::MIR: { + m_pp.ldon_points_mir = points; + break; + } + case LDoNThemes::MMC: { + m_pp.ldon_points_mmc = points; + break; + } + case LDoNThemes::RUJ: { + m_pp.ldon_points_ruj = points; + break; + } + case LDoNThemes::TAK: { + m_pp.ldon_points_tak = points; + break; + } + } + + m_pp.ldon_points_available += points; + + auto outapp = new EQApplicationPacket(OP_AdventurePointsUpdate, sizeof(AdventurePoints_Update_Struct)); + + auto a = (AdventurePoints_Update_Struct*) outapp->pBuffer; + + a->ldon_available_points = m_pp.ldon_points_available; + a->ldon_guk_points = m_pp.ldon_points_guk; + a->ldon_mirugal_points = m_pp.ldon_points_mir; + a->ldon_mistmoore_points = m_pp.ldon_points_mmc; + a->ldon_rujarkian_points = m_pp.ldon_points_ruj; + a->ldon_takish_points = m_pp.ldon_points_tak; + + outapp->priority = 6; + + QueuePacket(outapp); + safe_delete(outapp); +} + void Client::SetSkill(EQ::skills::SkillType skillid, uint16 value) { if (skillid > EQ::skills::HIGHEST_SKILL) return; @@ -6546,24 +6590,30 @@ void Client::RemoveXTarget(Mob *m, bool OnlyAutoSlots) XTargets[i].dirty = true; } } + auto r = GetRaid(); + if (r) { + r->UpdateRaidXTargets(); + } } void Client::UpdateXTargetType(XTargetType Type, Mob *m, const char *Name) { - if(!XTargettingAvailable()) + if (!XTargettingAvailable()) { return; + } - for(int i = 0; i < GetMaxXTargets(); ++i) - { - if(XTargets[i].Type == Type) - { - if(m) + for (int i = 0; i < GetMaxXTargets(); ++i) { + if (XTargets[i].Type == Type) { + if (m) { XTargets[i].ID = m->GetID(); - else + } + else { XTargets[i].ID = 0; + } - if(Name) + if (Name) { strncpy(XTargets[i].Name, Name, 64); + } SendXTargetPacket(i, m); } @@ -6597,10 +6647,7 @@ void Client::SendXTargetPacket(uint32 Slot, Mob *m) if (strlen(XTargets[Slot].Name) && ((XTargets[Slot].Type == CurrentTargetPC) || (XTargets[Slot].Type == GroupTank) || (XTargets[Slot].Type == GroupAssist) || - (XTargets[Slot].Type == Puller) || - (XTargets[Slot].Type == RaidAssist1) || - (XTargets[Slot].Type == RaidAssist2) || - (XTargets[Slot].Type == RaidAssist3))) + (XTargets[Slot].Type == Puller))) { outapp->WriteUInt8(2); } @@ -6664,13 +6711,7 @@ void Client::RemoveGroupXTargets() { if ((XTargets[i].Type == GroupTank) || (XTargets[i].Type == GroupAssist) || - (XTargets[i].Type == Puller) || - (XTargets[i].Type == RaidAssist1) || - (XTargets[i].Type == RaidAssist2) || - (XTargets[i].Type == RaidAssist3) || - (XTargets[i].Type == GroupMarkTarget1) || - (XTargets[i].Type == GroupMarkTarget2) || - (XTargets[i].Type == GroupMarkTarget3)) + (XTargets[i].Type == Puller)) { XTargets[i].ID = 0; XTargets[i].Name[0] = 0; diff --git a/zone/client.h b/zone/client.h index c4ef78ca3..9581bd97a 100644 --- a/zone/client.h +++ b/zone/client.h @@ -602,6 +602,7 @@ public: inline void SetEXPModifier(uint32 zone_id, double exp_modifier, int16 instance_version = -1) { database.SetEXPModifier(CharacterID(), zone_id, exp_modifier, instance_version); }; bool UpdateLDoNPoints(uint32 theme_id, int points); + void SetLDoNPoints(uint32 theme_id, uint32 points); void SetPVPPoints(uint32 Points) { m_pp.PVPCurrentPoints = Points; } uint32 GetPVPPoints() { return m_pp.PVPCurrentPoints; } void AddPVPPoints(uint32 Points); @@ -1924,6 +1925,7 @@ private: public: void SetSharedTaskId(int64 shared_task_id); int64 GetSharedTaskId() const; + struct XTarget_Struct XTargets[XTARGET_HARDCAP]; private: bool m_exp_enabled; @@ -1976,7 +1978,6 @@ private: bool XTargetAutoAddHaters; bool m_dirtyautohaters; - struct XTarget_Struct XTargets[XTARGET_HARDCAP]; XTargetAutoHaters m_autohatermgr; XTargetAutoHaters *m_activeautohatermgr; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index d52b26cb4..0a0dea12a 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -328,6 +328,8 @@ void MapOpcodes() ConnectedOpcodes[OP_PVPLeaderBoardRequest] = &Client::Handle_OP_PVPLeaderBoardRequest; ConnectedOpcodes[OP_QueryUCSServerStatus] = &Client::Handle_OP_QueryUCSServerStatus; ConnectedOpcodes[OP_RaidInvite] = &Client::Handle_OP_RaidCommand; + ConnectedOpcodes[OP_RaidDelegateAbility] = &Client::Handle_OP_RaidDelegateAbility; + ConnectedOpcodes[OP_RaidClearNPCMarks] = &Client::Handle_OP_RaidClearNPCMarks; ConnectedOpcodes[OP_RandomReq] = &Client::Handle_OP_RandomReq; ConnectedOpcodes[OP_ReadBook] = &Client::Handle_OP_ReadBook; ConnectedOpcodes[OP_RecipeAutoCombine] = &Client::Handle_OP_RecipeAutoCombine; @@ -607,7 +609,6 @@ void Client::CompleteConnect() but not important for now. */ raid->SendRaidCreate(this); - raid->SendMakeLeaderPacketTo(raid->leadername, this); raid->SendRaidAdd(GetName(), this); raid->SendBulkRaid(this); raid->SendGroupUpdate(this); @@ -616,6 +617,7 @@ void Client::CompleteConnect() raid->UpdateRaidAAs(); raid->SendAllRaidLeadershipAA(); } + raid->SendMakeLeaderPacketTo(raid->leadername, this); uint32 grpID = raid->GetGroup(GetName()); if (grpID < 12) { raid->SendRaidGroupRemove(GetName(), grpID); @@ -636,6 +638,8 @@ void Client::CompleteConnect() raid->SendRaidLockTo(this); raid->SendHPManaEndPacketsTo(this); + raid->SendAssistTarget(this); + raid->SendMarkTargets(this); } } else { @@ -3043,8 +3047,22 @@ void Client::Handle_OP_AssistGroup(const EQApplicationPacket *app) LogDebug("Size mismatch in OP_AssistGroup expected [{}] got [{}]", sizeof(EntityId_Struct), app->size); return; } - QueuePacket(app); - return; + + EntityId_Struct* eid = (EntityId_Struct*)app->pBuffer; + Entity* entity = entity_list.GetID(eid->entity_id); + + if (entity && entity->IsMob()) { + Mob* new_target = entity->CastToMob(); + if (new_target && (GetGM() || + Distance(m_Position, new_target->GetPosition()) <= TARGETING_RANGE)) { + cheat_manager.SetExemptStatus(Assist, true); + EQApplicationPacket* outapp = new EQApplicationPacket(OP_Assist, sizeof(EntityId_Struct)); + eid = (EntityId_Struct*)outapp->pBuffer; + eid->entity_id = new_target->GetID(); + FastQueuePacket(&outapp); + safe_delete(outapp); + } + } } void Client::Handle_OP_AugmentInfo(const EQApplicationPacket *app) @@ -5850,6 +5868,31 @@ void Client::Handle_OP_DoGroupLeadershipAbility(const EQApplicationPacket *app) break; } + case RaidLeadershipAbility_MainAssist: + { + //This is not needed as it executes from opcode 0x2b33 which is sent + //with this opcode. + //if (GetTarget()) + //{ + // Raid* r = GetRaid(); + // if (r) + // { + // r->DelegateAbility(GetTarget()->CastToClient()->GetName()); + // } + //} + break; + } + case RaidLeadershipAbility_MarkNPC: + { + if (GetTarget() && GetTarget()->IsMob()) { + Raid* r = GetRaid(); + if (r) { + r->RaidMarkNPC(this, dglas->Parameter); + } + } + break; + + } default: LogDebug("Got unhandled OP_DoGroupLeadershipAbility Ability: [{}] Parameter: [{}]", dglas->Ability, dglas->Parameter); break; @@ -11934,6 +11977,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) if (raid->IsLocked()) { raid->SendRaidLockTo(c); } + raid->SendAssistTarget(c); + raid->SendMarkTargets(c); } } group->JoinRaidXTarget(raid); @@ -11948,6 +11993,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) if (raid->IsLocked()) { raid->SendRaidLockTo(this); } + raid->SendAssistTarget(this); + raid->SendMarkTargets(this); } } else @@ -11988,6 +12035,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) if (raid->IsLocked()) { raid->SendRaidLockTo(c); } + raid->SendAssistTarget(c); + raid->SendMarkTargets(c); } else { Client* c = nullptr; @@ -12004,6 +12053,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) if (raid->IsLocked()) { raid->SendRaidLockTo(c); } + raid->SendAssistTarget(c); + raid->SendMarkTargets(c); } } } @@ -12043,6 +12094,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) if (raid->IsLocked()) { raid->SendRaidLockTo(c); } + raid->SendAssistTarget(c); + raid->SendMarkTargets(c); } else { @@ -12060,6 +12113,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) if (raid->IsLocked()) { raid->SendRaidLockTo(c); } + raid->SendAssistTarget(c); + raid->SendMarkTargets(c); } } } @@ -12100,6 +12155,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) if (raid->IsLocked()) { raid->SendRaidLockTo(c); } + raid->SendAssistTarget(c); + raid->SendMarkTargets(c); } else { @@ -12116,6 +12173,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) if (raid->IsLocked()) { raid->SendRaidLockTo(c); } + raid->SendAssistTarget(c); + raid->SendMarkTargets(c); } } } @@ -12129,6 +12188,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) if (raid->IsLocked()) { raid->SendRaidLockTo(this); } + raid->SendAssistTarget(this); + raid->SendMarkTargets(this); } else { // neither has a group raid = new Raid(player_sending_invite); @@ -12143,6 +12204,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) if (raid->IsLocked()) { raid->SendRaidLockTo(this); } + raid->SendAssistTarget(this); + raid->SendMarkTargets(this); } } } @@ -12165,6 +12228,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) //Does not camp the Bots, just removes from the raid if (c_to_disband) { uint32 i = raid->GetPlayerIndex(raid_command_packet->leader_name); + raid->RemoveRaidDelegates(raid_command_packet->leader_name); + raid->SendRemoveAllRaidXTargets(raid_command_packet->leader_name); raid->SetNewRaidLeader(i); raid->HandleBotGroupDisband(c_to_disband->CharacterID()); raid->HandleOfflineBots(c_to_disband->CharacterID()); @@ -12180,11 +12245,13 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) if (gid < 12 && (raid->IsGroupLeader(b_to_disband->GetName()) || raid->GroupCount(gid) < 2)) { uint32 owner_id = b_to_disband->CastToBot()->GetOwner()->CastToClient()->CharacterID(); + raid->RemoveRaidDelegates(raid_command_packet->leader_name); + raid->UpdateRaidXTargets(); raid->HandleBotGroupDisband(owner_id, gid); - } else if (b_to_disband && raid->IsRaidMember(b_to_disband->GetName())) { + raid->RemoveRaidDelegates(raid_command_packet->leader_name); + raid->UpdateRaidXTargets(); Bot::RemoveBotFromRaid(b_to_disband); - } else if (gid < 12 && raid->GetGroupLeader(gid) && raid->GetGroupLeader(gid)->IsBot()) { c_doing_disband->Message( Chat::Yellow, @@ -12215,6 +12282,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) } } raid->SetNewRaidLeader(i); + raid->RemoveRaidDelegates(raid_command_packet->leader_name); + raid->UpdateRaidXTargets(); raid->RemoveMember(raid_command_packet->leader_name); Client* c = entity_list.GetClientByName(raid_command_packet->leader_name); if (c) { @@ -12268,9 +12337,9 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) if (client_to_update) { raid->SendRaidRemove(raid->members[x].member_name, client_to_update); raid->SendRaidCreate(client_to_update); - raid->SendMakeLeaderPacketTo(raid->leadername, client_to_update); raid->SendRaidAdd(raid->members[x].member_name, client_to_update); raid->SendBulkRaid(client_to_update); + raid->SendMakeLeaderPacketTo(raid->leadername, client_to_update); if (raid->IsLocked()) { raid->SendRaidLockTo(client_to_update); } @@ -12318,9 +12387,9 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) raid->GroupUpdate(raid_command_packet->parameter); /* If our old was a group send update there too */ - if (old_group < 12) + if (old_group < 12) { raid->GroupUpdate(old_group); - + } } } /* Move player to ungrouped bank */ @@ -12381,7 +12450,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) } raid->GroupUpdate(oldgrp); - } +} } Client* client_moved = entity_list.GetClientByName(raid_command_packet->leader_name); @@ -12479,7 +12548,18 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) raid->SendRaidMOTDToWorld(); break; } + case RaidCommandSetNote: + { + Raid* raid = entity_list.GetRaidByClient(this); + if (!raid) { + break; + } + + raid->SaveRaidNote(raid_command_packet->leader_name, raid_command_packet->note); + raid->SendRaidNotesToWorld(); + break; + } default: { Message(Chat::Red, "Raid command (%d) NYI", raid_command_packet->action); break; @@ -15799,14 +15879,87 @@ void Client::Handle_OP_XTargetRequest(const EQApplicationPacket *app) case RaidAssist1: case RaidAssist2: case RaidAssist3: + { + struct AssistType { + XTargetType type; + int32 assist_slot; + }; + + std::vector assist_types = { + { RaidAssist1, MAIN_ASSIST_1_SLOT }, + { RaidAssist2, MAIN_ASSIST_2_SLOT }, + { RaidAssist3, MAIN_ASSIST_3_SLOT } + }; + + for (auto& t : assist_types) { + if (t.type == Type) { + Raid* r = GetRaid(); + if (r) { + Client* ma = entity_list.GetClientByName(r->main_assister_pcs[t.assist_slot]); + if (ma) { + UpdateXTargetType(t.type, ma, ma->GetName()); + } + } + } + } + break; + } + case RaidAssist1Target: case RaidAssist2Target: case RaidAssist3Target: + { + struct AssistType { + XTargetType type; + int32 assist_slot; + }; + + std::vector assist_types = { + { RaidAssist1Target, MAIN_ASSIST_1_SLOT }, + { RaidAssist2Target, MAIN_ASSIST_2_SLOT }, + { RaidAssist3Target, MAIN_ASSIST_3_SLOT } + }; + + for (auto& t : assist_types) { + if (t.type == Type) { + Raid* r = GetRaid(); + if (r) { + Client* ma = entity_list.GetClientByName(r->main_assister_pcs[t.assist_slot]); + if (ma && ma->GetTarget()) { + UpdateXTargetType(t.type, ma->GetTarget(), ma->GetTarget()->GetName()); + } + } + } + } + break; + } + case RaidMarkTarget1: case RaidMarkTarget2: case RaidMarkTarget3: { - // Not implemented yet. + struct AssistType { + XTargetType type; + int32 assist_slot; + }; + + std::vector assist_types = { + { RaidMarkTarget1, MAIN_MARKER_1_SLOT }, + { RaidMarkTarget2, MAIN_MARKER_2_SLOT }, + { RaidMarkTarget3, MAIN_MARKER_3_SLOT } + }; + + for (auto& t : assist_types) { + if (t.type == Type) { + Raid* r = GetRaid(); + if (r) { + auto mm = entity_list.GetNPCByID(r->marked_npcs[t.assist_slot]); + if (mm) { + UpdateXTargetType(t.type, mm->CastToMob(), mm->CastToMob()->GetName()); + } + } + } + } break; } @@ -16190,3 +16343,52 @@ void Client::RecordKilledNPCEvent(NPC *n) } } } + +void Client::Handle_OP_RaidDelegateAbility(const EQApplicationPacket *app) +{ + if (app->size != sizeof(DelegateAbility_Struct)) { + LogDebug( + "Size mismatch in OP_RaidDelegateAbility expected [{}] got [{}]", + sizeof(DelegateAbility_Struct), + app->size + ); + DumpPacket(app); + return; + } + + DelegateAbility_Struct *das = (DelegateAbility_Struct *) app->pBuffer; + + switch (das->DelegateAbility) { + case RaidDelegateMainAssist: { + auto r = GetRaid(); + if (r) { + r->DelegateAbilityAssist(this, das->Name); + } + break; + } + case RaidDelegateMainMarker: { + auto r = GetRaid(); + if (r) { + r->DelegateAbilityMark(this, das->Name); + } + break; + } + default: + LogDebug("RaidDelegateAbility default case"); + break; + } +} + +void Client::Handle_OP_RaidClearNPCMarks(const EQApplicationPacket* app) +{ + if (app->size != 0) { + LogDebug("Size mismatch in OP_RaidClearNPCMark expected [{}] got [{}]", 0, app->size); + DumpPacket(app); + return; + } + + auto r = GetRaid(); + if (r) { + r->RaidClearNPCMarks(this); + } +} diff --git a/zone/client_packet.h b/zone/client_packet.h index 887372cde..f779974ba 100644 --- a/zone/client_packet.h +++ b/zone/client_packet.h @@ -241,7 +241,9 @@ void Handle_OP_PVPLeaderBoardRequest(const EQApplicationPacket *app); void Handle_OP_QueryUCSServerStatus(const EQApplicationPacket *app); void Handle_OP_RaidCommand(const EQApplicationPacket *app); - void Handle_OP_RandomReq(const EQApplicationPacket *app); + void Handle_OP_RaidDelegateAbility(const EQApplicationPacket* app); + void Handle_OP_RaidClearNPCMarks(const EQApplicationPacket* app); + void Handle_OP_RandomReq(const EQApplicationPacket* app); void Handle_OP_ReadBook(const EQApplicationPacket *app); void Handle_OP_RecipeAutoCombine(const EQApplicationPacket *app); void Handle_OP_RecipeDetails(const EQApplicationPacket *app); diff --git a/zone/command.cpp b/zone/command.cpp index 266e57fe9..96a7a9613 100644 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -1,8 +1,8 @@ - #include #include #include #include +#include "../common/repositories/command_subsettings_repository.h" #ifdef _WINDOWS #define strcasecmp _stricmp @@ -40,16 +40,17 @@ extern FastMath g_Math; 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 // init has been performed to point at the real function int (*command_dispatch)(Client *, std::string, bool) = command_notavail; -std::map commandlist; -std::map commandaliases; -std::vector command_delete_list; -std::map commands_map; +std::map commandlist; +std::map commandaliases; +std::vector command_delete_list; +std::map commands_map; +std::vector command_subsettings; /* * command_notavail @@ -94,7 +95,6 @@ int command_init(void) command_add("attack", "[Entity Name] - Make your NPC target attack an entity by name", AccountStatus::GMLeadAdmin, command_attack) || 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("bind", "Sets your targets bind spot to their current location", AccountStatus::GMMgmt, command_bind) || 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) || command_add("camerashake", "[Duration (Milliseconds)] [Intensity (1-10)] - Shakes the camera on everyone's screen globally.", AccountStatus::QuestTroupe, command_camerashake) || @@ -106,7 +106,6 @@ int command_init(void) command_add("countitem", "[Item ID] - Counts the specified Item ID in your or your target's inventory", AccountStatus::GMLeadAdmin, command_countitem) || command_add("damage", "[Amount] - Damage yourself or your target", AccountStatus::GMAdmin, command_damage) || command_add("databuckets", "View|Delete [key] [limit]- View data buckets, limit 50 default or Delete databucket by key", AccountStatus::QuestTroupe, command_databuckets) || - command_add("date", "[Year] [Month] [Day] [Hour] [Minute] - Set EQ time (Hour and Minute are optional)", AccountStatus::EQSupport, command_date) || command_add("dbspawn2", "[Spawngroup ID] [Respawn] [Variance] [Condition ID] [Condition Minimum] - Spawn an NPC from a predefined row in the spawn2 table, Respawn and Variance are in Seconds (condition is optional)", AccountStatus::GMAdmin, command_dbspawn2) || command_add("delacct", "[Account ID|Account Name] - Delete an account by ID or Name", AccountStatus::GMLeadAdmin, command_delacct) || command_add("delpetition", "[petition number] - Delete a petition", AccountStatus::ApprenticeGuide, command_delpetition) || @@ -124,7 +123,6 @@ int command_init(void) command_add("emote", "[Name|World|Zone] [type] [message] - Send an emote message by name, to the world, or to your zone (^ separator allows multiple messages to be sent at once)", AccountStatus::QuestTroupe, command_emote) || command_add("emptyinventory", "Clears your or your target's entire inventory (Equipment, General, Bank, and Shared Bank)", AccountStatus::GMImpossible, command_emptyinventory) || command_add("enablerecipe", "[Recipe ID] - Enables a Recipe", AccountStatus::QuestTroupe, command_enablerecipe) || - command_add("endurance", "Restores your or your target's endurance.", AccountStatus::Guide, command_endurance) || command_add("entityvariable", "[clear|delete|set|view] - Modify entity variables for yourself or your target", AccountStatus::GMAdmin, command_entityvariable) || command_add("exptoggle", "[Toggle] - Toggle your or your target's experience gain.", AccountStatus::QuestTroupe, command_exptoggle) || command_add("faction", "[Find (criteria | all ) | Review (criteria | all) | Reset (id)] - Resets Player's Faction", AccountStatus::QuestTroupe, command_faction) || @@ -133,59 +131,39 @@ int command_init(void) command_add("size", "Change your targets size (alias of #feature size)", AccountStatus::QuestTroupe, command_feature) || command_add("find", "Search command used to find various things", AccountStatus::Guide, command_find) || command_add("fixmob", "[race|gender|texture|helm|face|hair|haircolor|beard|beardcolor|heritage|tattoo|detail] [next|prev] - Manipulate appearance of your target", AccountStatus::QuestTroupe, command_fixmob) || - command_add("flag", "[Status] [Account Name] - Refresh your admin status, or set an account's Admin status if arguments provided", AccountStatus::Player, command_flag) || command_add("flagedit", "Edit zone flags on your target. Use #flagedit help for more info.", AccountStatus::GMAdmin, command_flagedit) || - command_add("flymode", "[0/1/2/3/4/5] - Set your or your player target's flymode to ground/flying/levitate/water/floating/levitate_running", AccountStatus::Guide, command_flymode) || - command_add("freeze", "Freeze your target", AccountStatus::QuestTroupe, command_freeze) || - command_add("gassign", "[Grid ID] - Assign targetted NPC to predefined wandering grid id", AccountStatus::GMAdmin, command_gassign) || command_add("gearup", "Developer tool to quickly equip yourself or your target", AccountStatus::GMMgmt, command_gearup) || - command_add("gender", "[0/1/2] - Change your or your target's gender to male/female/neuter", AccountStatus::Guide, command_gender) || command_add("giveitem", "[itemid] [charges] - Summon an item onto your target's cursor. Charges are optional.", AccountStatus::GMMgmt, command_giveitem) || command_add("givemoney", "[Platinum] [Gold] [Silver] [Copper] - Gives specified amount of money to you or your player target", AccountStatus::GMMgmt, command_givemoney) || - command_add("gm", "[On|Off] - Modify your or your target's GM Flag", AccountStatus::QuestTroupe, command_gm) || - command_add("gmspeed", "[On|Off] - Turn GM Speed On or Off for you or your player target", AccountStatus::GMAdmin, command_gmspeed) || command_add("gmzone", "[Zone ID|Zone Short Name] [Version] [Instance Identifier] - Zones to a private GM instance (Version defaults to 0 and Instance Identifier defaults to 'gmzone' if not used)", AccountStatus::GMAdmin, command_gmzone) || - command_add("godmode", "[on/off] - Turns on/off hideme, gmspeed, invul, and flymode.", AccountStatus::GMMgmt, command_godmode) || command_add("goto", "[playername] or [x y z] [h] - Teleport to the provided coordinates or to your target", AccountStatus::Steward, command_goto) || command_add("grid", "[add/delete] [grid_num] [wandertype] [pausetype] - Create/delete a wandering grid", AccountStatus::GMAreas, command_grid) || command_add("guild", "Guild manipulation commands. Use argument help for more info.", AccountStatus::Steward, command_guild) || - command_add("haste", "[Percentage] - Set your or your target's GM Bonus Haste (100 is 100% more Attack Speed)", AccountStatus::GMAdmin, command_haste) || - command_add("heal", "Completely heal your target", AccountStatus::Steward, command_heal) || command_add("help", "[Search Criteria] - List available commands and their description, specify partial command as argument to search", AccountStatus::Player, command_help) || - command_add("heromodel", "[Hero Model] [Slot] - Set your or your target's appearance to a full set of Hero's Forge Armor, if slot is set, sends exact model just to slot.", AccountStatus::GMMgmt, command_heromodel) || - command_add("hideme", "[On|Off] or [0|1] - Hide yourself from players below your status level.", AccountStatus::QuestTroupe, command_hideme) || command_add("hotfix", "[hotfix_name] - Reloads shared memory into a hotfix, equiv to load_shared_memory followed by apply_shared_memory", AccountStatus::GMImpossible, command_hotfix) || command_add("hp", "Refresh your HP bar from the server.", AccountStatus::Player, command_hp) || - command_add("incstat", "Increases or Decreases a client's stats permanently.", AccountStatus::GMMgmt, command_incstat) || command_add("instance", "Modify Instances", AccountStatus::GMMgmt, command_instance) || command_add("interrogateinv", "use [help] argument for available options", AccountStatus::Player, command_interrogateinv) || command_add("interrupt", "[Message ID] [Color] - Interrupt your casting. Arguments are optional.", AccountStatus::Guide, command_interrupt) || command_add("invsnapshot", "Manipulates inventory snapshots for your current target", AccountStatus::QuestTroupe, command_invsnapshot) || - command_add("invul", "[On|Off]] - Turn player target's or your invulnerable flag on or off", AccountStatus::QuestTroupe, command_invul) || command_add("ipban", "[IP] - Ban IP", AccountStatus::GMMgmt, command_ipban) || command_add("kick", "[Character Name] - Disconnect a player by name", AccountStatus::GMLeadAdmin, command_kick) || command_add("kill", "Kill your target", AccountStatus::GMAdmin, command_kill) || command_add("killallnpcs", "[npc_name] - Kills all npcs by search name, leave blank for all attackable NPC's", AccountStatus::GMMgmt, command_killallnpcs) || - command_add("lastname", "[Last Name] - Set your or your player target's last name (use \"-1\" to remove last name)", AccountStatus::Guide, command_lastname) || - command_add("level", "[Level] - Set your or your target's level", AccountStatus::Steward, command_level) || command_add("list", "[npcs|players|corpses|doors|objects] [search] - Search entities", AccountStatus::ApprenticeGuide, command_list) || command_add("lootsim", "[npc_type_id] [loottable_id] [iterations] - Runs benchmark simulations using real loot logic to report numbers and data", AccountStatus::GMImpossible, command_lootsim) || command_add("load_shared_memory", "[shared_memory_name] - Reloads shared memory and uses the input as output", AccountStatus::GMImpossible, command_load_shared_memory) || command_add("loc", "Print out your or your target's current location and heading", AccountStatus::Player, command_loc) || command_add("logs", "Manage anything to do with logs", AccountStatus::GMImpossible, command_logs) || command_add("makepet", "[Pet Name] - Make a pet", AccountStatus::Guide, command_makepet) || - command_add("mana", "Fill your or your target's mana", AccountStatus::Guide, command_mana) || - command_add("maxskills", "Maxes skills for you or your player target.", AccountStatus::GMMgmt, command_max_all_skills) || command_add("memspell", "[Spell ID] [Spell Gem] - Memorize a Spell by ID to the specified Spell Gem for you or your target", AccountStatus::Guide, command_memspell) || command_add("merchantshop", "Closes or opens your target merchant's shop", AccountStatus::GMAdmin, command_merchantshop) || command_add("modifynpcstat", "[Stat] [Value] - Modifies an NPC's stats temporarily.", AccountStatus::GMLeadAdmin, command_modifynpcstat) || - command_add("motd", "[Message of the Day] - Set Message of the Day (leave empty to have no Message of the Day)", AccountStatus::GMLeadAdmin, command_motd) || command_add("movechar", "[Character ID|Character Name] [Zone ID|Zone Short Name] - Move an offline character to the specified zone", AccountStatus::Guide, command_movechar) || command_add("movement", "Various movement commands", AccountStatus::GMMgmt, command_movement) || command_add("myskills", "Show details about your current skill levels", AccountStatus::Player, command_myskills) || command_add("mysql", "[Help|Query] [SQL Query] - Mysql CLI, see 'Help' for options.", AccountStatus::GMImpossible, command_mysql) || command_add("mystats", "Show details about you or your pet", AccountStatus::Guide, command_mystats) || - command_add("name", "[New Name] - Rename your player target", AccountStatus::GMLeadAdmin, command_name) || command_add("npccast", "[targetname/entityid] [spellid] - Causes NPC target to cast spellid on targetname/entityid", AccountStatus::QuestTroupe, command_npccast) || command_add("npcedit", "[column] [value] - Mega NPC editing command", AccountStatus::GMAdmin, command_npcedit) || command_add("npceditmass", "[name-search] [column] [value] - Mass (Zone wide) NPC data editing command", AccountStatus::GMAdmin, command_npceditmass) || @@ -199,20 +177,13 @@ int command_init(void) command_add("nukebuffs", "[Beneficial|Detrimental|Help] - Strip all buffs by type on you or your target (no argument to remove all buffs)", AccountStatus::Guide, command_nukebuffs) || command_add("nukeitem", "[Item ID] - Removes the specified Item ID from you or your player target's inventory", AccountStatus::GMLeadAdmin, command_nukeitem) || command_add("object", "List|Add|Edit|Move|Rotate|Copy|Save|Undo|Delete - Manipulate static and tradeskill objects within the zone", AccountStatus::GMAdmin, command_object) || - command_add("oocmute", "[0|1] - Enable or Disable Server OOC", AccountStatus::GMMgmt, command_oocmute) || command_add("opcode", "Reloads all opcodes from server patch files", AccountStatus::GMMgmt, command_reload) || command_add("path", "view and edit pathing", AccountStatus::GMMgmt, command_path) || command_add("peqzone", "[Zone ID|Zone Short Name] - Teleports you to the specified zone if you meet the requirements.", AccountStatus::Player, command_peqzone) || - command_add("permaclass", "[Class ID] - Change your or your player target's class, changed client is disconnected", AccountStatus::QuestTroupe, command_permaclass) || - command_add("permagender", "[Gender ID] - Change your or your player target's gender", AccountStatus::QuestTroupe, command_permagender) || - command_add("permarace", "[Race ID] - Change your or your player target's race", AccountStatus::QuestTroupe, command_permarace) || command_add("petitems", "View your pet's items if you have one", AccountStatus::ApprenticeGuide, command_petitems) || command_add("picklock", "Analog for ldon pick lock for the newer clients since we still don't have it working.", AccountStatus::Player, command_picklock) || command_add("profanity", "Manage censored language.", AccountStatus::GMLeadAdmin, command_profanity) || command_add("push", "[Back Push] [Up Push] - Lets you do spell push on an NPC", AccountStatus::GMLeadAdmin, command_push) || - command_add("pvp", "[On|Off] - Set you or your player target's PVP status", AccountStatus::GMAdmin, command_pvp) || - command_add("qglobal", "[On|Off|View] - Toggles quest global functionality for your NPC target", AccountStatus::GMAdmin, command_qglobal) || - command_add("race", "[racenum] - Change your or your target's race. Use racenum 0 to return to normal", AccountStatus::Guide, command_race) || command_add("raidloot", "[All|GroupLeader|RaidLeader|Selected] - Sets your Raid Loot Type if you have permission to do so.", AccountStatus::Player, command_raidloot) || command_add("randomfeatures", "Temporarily randomizes the Facial Features of your target", AccountStatus::QuestTroupe, command_randomfeatures) || command_add("refreshgroup", "Refreshes Group for you or your player target.", AccountStatus::Player, command_refreshgroup) || @@ -233,29 +204,8 @@ int command_init(void) command_add("scribespells", "[Max level] [Min level] - Scribe all spells for you or your player target that are usable by them, up to level specified. (may freeze client for a few seconds)", AccountStatus::GMLeadAdmin, command_scribespells) || command_add("sendzonespawns", "Refresh spawn list for all clients in zone", AccountStatus::GMLeadAdmin, command_sendzonespawns) || command_add("sensetrap", "Analog for ldon sense trap for the newer clients since we still don't have it working.", AccountStatus::Player, command_sensetrap) || - command_add("serverlock", "[0|1] - Lock or Unlock the World Server (0 = Unlocked, 1 = Locked)", AccountStatus::GMLeadAdmin, command_serverlock) || - command_add("serverrules", "Read this server's rules", AccountStatus::Player, command_serverrules) || - command_add("setaapts", "[AA|Group|Raid] [AA Amount] - Set your or your player target's Available AA Points by Type", AccountStatus::GMAdmin, command_setaapts) || - command_add("setaaxp", "[AA|Group|Raid] [AA Experience] - Set your or your player target's AA Experience by Type", AccountStatus::GMAdmin, command_setaaxp) || - command_add("setadventurepoints", "[Theme] [Points] - Set your or your player target's available Adventure Points by Theme", AccountStatus::GMLeadAdmin, command_set_adventure_points) || - command_add("setaltcurrency", "[Currency ID] [Amount] - Set your or your target's available Alternate Currency by Currency ID", AccountStatus::GMAdmin, command_setaltcurrency) || - command_add("setanim", "[Animation ID (IDs are 0 to 4)] - Set target's appearance to Animation ID", AccountStatus::GMMgmt, command_setanim) || - command_add("setanon", "[Anonymous Flag] - Set you or your target's Anonymous Flag (0 = Not Anonymous, 1 = Anonymous, 2 = Roleplaying)", AccountStatus::QuestTroupe, command_setanon) || - command_add("setcrystals", "[value] - Set your or your player target's available radiant or ebon crystals", AccountStatus::GMAdmin, command_setcrystals) || - command_add("setendurance", "[Endurance] - Set your or your target's Endurance", AccountStatus::GMAdmin, command_setendurance) || - command_add("setfaction", "[Faction ID] - Sets targeted NPC's faction in the database", AccountStatus::GMAreas, command_setfaction) || - command_add("sethp", "[Health] - Set your or your target's Health", AccountStatus::GMAdmin, command_sethp) || - command_add("setlanguage", "[Language ID] [Value] - Set your or your target's Language by ID to Value", AccountStatus::Guide, command_setlanguage) || - command_add("setlsinfo", "[Email] [Password] - Set loginserver email address and password (if supported by loginserver)", AccountStatus::Steward, command_setlsinfo) || - command_add("setmana", "[Mana] - Set your or your target's Mana", AccountStatus::GMAdmin, command_setmana) || - command_add("setpass", "[Account Name] [Password] - Set local password by account name", AccountStatus::GMLeadAdmin, command_setpass) || - command_add("setpvppoints", "[Amount] - Set your or your player target's PVP points", AccountStatus::GMAdmin, command_setpvppoints) || - command_add("setskill", "[skillnum] [value] - Set your target's skill skillnum to value", AccountStatus::Guide, command_setskill) || - command_add("setskillall", "[Skill Level] - Set all of your or your target's skills to the specified skill level", AccountStatus::Guide, command_setskillall) || - command_add("setstartzone", "[Zone ID|Zone Short Name] - Sets your or your target's starting zone (Use '0' or 'Reset' to allow the player use of /setstartcity)", AccountStatus::QuestTroupe, command_setstartzone) || - command_add("setstat", "Sets the stats to a specific value.", AccountStatus::Max, command_setstat) || - command_add("setxp", "[value] - Set your or your player target's experience", AccountStatus::GMAdmin, command_setxp) || - command_add("show", "List command used to show various things", AccountStatus::Guide, command_show) || + command_add("set", "Set command used to set various things", AccountStatus::Guide, command_set) || + command_add("show", "Show command used to show various things", AccountStatus::Guide, command_show) || command_add("shutdown", "Shut this zone process down", AccountStatus::GMLeadAdmin, command_shutdown) || command_add("spawn", "[name] [race] [level] [material] [hp] [gender] [class] [priweapon] [secweapon] [merchantid] - Spawn an NPC", AccountStatus::Steward, command_spawn) || command_add("spawneditmass", "[Search Criteria] [Edit Option] [Edit Value] [Apply] Mass editing spawn command (Apply is optional, 0 = False, 1 = True, default is False)", AccountStatus::GMLeadAdmin, command_spawneditmass) || @@ -267,43 +217,27 @@ int command_init(void) command_add("suspend", "[name] [days] [reason] - Suspend by character name and for specificed number of days", AccountStatus::GMLeadAdmin, command_suspend) || command_add("suspendmulti", "[Character Name One|Character Name Two|etc] [Days] [Reason] - Suspend multiple characters by name for specified number of days", AccountStatus::GMLeadAdmin, command_suspendmulti) || command_add("task", "(subcommand) - Task system commands", AccountStatus::GMLeadAdmin, command_task) || - command_add("tempname", "[newname] - Temporarily renames your target. Leave name blank to restore the original name.", AccountStatus::GMAdmin, command_tempname) || command_add("petname", "[newname] - Temporarily renames your pet. Leave name blank to restore the original name.", AccountStatus::GMAdmin, command_petname) || - command_add("texture", "[Texture] [Helmet Texture] - Change your or your target's texture (Helmet Texture defaults to 0 if not used)", AccountStatus::Steward, command_texture) || - command_add("time", "[Hour] [Minute] - Set world time to specified time", AccountStatus::EQSupport, command_time) || - command_add("timezone", "[Hour] [Minutes] - Set timezone (Minutes are optional)", AccountStatus::EQSupport, command_timezone) || - command_add("title", "[Title] - Set your or your player target's title (use \"-1\" to remove title)", AccountStatus::Guide, command_title) || - command_add("titlesuffix", "[Title Suffix] - Set your or your player target's title suffix (use \"-1\" to remove title suffix)", AccountStatus::Guide, command_titlesuffix) || command_add("traindisc", "[level] - Trains all the disciplines usable by the target, up to level specified. (may freeze client for a few seconds)", AccountStatus::GMLeadAdmin, command_traindisc) || command_add("tune", "Calculate statistical values related to combat.", AccountStatus::GMAdmin, command_tune) || command_add("undye", "Remove dye from all of your or your target's armor slots", AccountStatus::GMAdmin, command_undye) || - command_add("unfreeze", "Unfreeze your target", AccountStatus::QuestTroupe, command_unfreeze) || command_add("unmemspell", "[Spell ID] - Unmemorize a Spell by ID for you or your target", AccountStatus::Guide, command_unmemspell) || command_add("unmemspells", " Unmemorize all spells for you or your target", AccountStatus::Guide, command_unmemspells) || command_add("unscribespell", "[Spell ID] - Unscribe a spell from your or your target's spell book by Spell ID", AccountStatus::GMCoder, command_unscribespell) || command_add("unscribespells", "Clear out your or your player target's spell book.", AccountStatus::GMCoder, command_unscribespells) || command_add("untraindisc", "[Spell ID] - Untrain your or your target's discipline by Spell ID", AccountStatus::GMCoder, command_untraindisc) || command_add("untraindiscs", "Untrains all disciplines from your target.", AccountStatus::GMCoder, command_untraindiscs) || - command_add("updatechecksum", "update client checksum", AccountStatus::GMImpossible, command_updatechecksum) || command_add("wc", "[Slot ID] [Material] [Hero Forge Model] [Elite Material] - Sets the specified slot for you or your target to a material, Hero Forge Model and Elite Material are optional", AccountStatus::GMMgmt, command_wc) || - command_add("weather", "[0/1/2/3] (Off/Rain/Snow/Manual) - Change the weather", AccountStatus::QuestTroupe, command_weather) || command_add("worldshutdown", "Shut down world and all zones", AccountStatus::GMMgmt, command_worldshutdown) || command_add("wp", "[add|delete] [grid_id] [pause] [waypoint_id] [-h] - Add or delete a waypoint by grid ID. (-h to use current heading)", AccountStatus::GMAreas, command_wp) || command_add("wpadd", "[pause] [-h] - Add your current location as a waypoint to your NPC target's AI path. (-h to use current heading)", AccountStatus::GMAreas, command_wpadd) || command_add("worldwide", "Performs world-wide GM functions such as cast (can be extended for other commands). Use caution", AccountStatus::GMImpossible, command_worldwide) || - command_add("zclip", "[Minimum Clip] [Maximum Clip] [Fog Minimum Clip] [Fog Maximum Clip] [Permanent (0 = False, 1 = True)] - Change zone clipping", AccountStatus::QuestTroupe, command_zclip) || - command_add("zcolor", "[Red] [Green] [Blue] [Permanent (0 = False, 1 = True)] - Change sky color", AccountStatus::QuestTroupe, command_zcolor) || - command_add("zheader", "[Zone ID|Zone Short Name] [Version] - Load a zone header from the database", AccountStatus::QuestTroupe, command_zheader) || command_add("zone", "[Zone ID|Zone Short Name] [X] [Y] [Z] - Teleport to specified Zone by ID or Short Name (coordinates are optional)", AccountStatus::Guide, command_zone) || command_add("zonebootup", "[ZoneServerID] [shortname] - Make a zone server boot a specific zone", AccountStatus::GMLeadAdmin, command_zonebootup) || command_add("zoneinstance", "[Instance ID] [X] [Y] [Z] - Teleport to specified Instance by ID (coordinates are optional)", AccountStatus::Guide, command_zone_instance) || - command_add("zonelock", "[List|Lock|Unlock] [Zone ID|Zone Short Name] - Set or get lock status of a Zone by ID or Short Name", AccountStatus::GMAdmin, command_zonelock) || command_add("zoneshutdown", "[shortname] - Shut down a zone server", AccountStatus::GMLeadAdmin, command_zoneshutdown) || command_add("zopp", "Troubleshooting command - Sends a fake item packet to you. No server reference is created.", AccountStatus::GMImpossible, command_zopp) || - command_add("zsafecoords", "[X] [Y] [Z] [Heading] [Permanent (0 = False, 1 = True)] - Set the current zone's safe coordinates", AccountStatus::QuestTroupe, command_zsafecoords) || - command_add("zsave", " Saves zheader to the database", AccountStatus::QuestTroupe, command_zsave) || - command_add("zsky", "[Sky Type] [Permanent (0 = False, 1 = True)] - Change zone sky type", AccountStatus::QuestTroupe, command_zsky) || - command_add("zunderworld", "[Z] [Permanent (0 = False, 1 = True)] - Change zone underworld Z", AccountStatus::QuestTroupe, command_zunderworld) + command_add("zsave", " Saves zheader to the database", AccountStatus::QuestTroupe, command_zsave) ) { command_deinit(); return -1; @@ -311,102 +245,17 @@ int command_init(void) std::map>> command_settings; database.GetCommandSettings(command_settings); + database.GetCommandSubSettings(command_subsettings); std::vector> injected_command_settings; std::vector orphaned_command_settings; - // static aliases - struct StaticAlias { - std::string command; - std::vector aliases; - }; - - std::vector static_aliases = { - { - .command = "find", - .aliases = { - "fi", - "fn", - "fs", - "fz", - "findaa", - "findcharacter", - "findclass", - "findcurrency", - "finddeity", - "findemote", - "findfaction", - "finditem", - "findlanguage", - "findnpc", - "findnpctype", - "findrace", - "findrecipe", - "findskill", - "findspell", - "findtask", - "findzone", - "itemsearch" - } - }, - { - .command = "show", - .aliases = { - "aggro", - "checklos", - "cvs", - "distance", - "emoteview", - "flags", - "fov", - "getplayerburiedcorpsecount", - "getvariable", - "ginfo", - "globalview", - "hatelist", - "iplookup", - "listpetition", - "network", - "netstats", - "npcstats", - "peekinv", - "petitioninfo", - "peqzone_flags", - "proximity", - "questerrors", - "serverinfo", - "showbuffs", - "shownpcgloballoot", - "showskills", - "showspells", - "showspellslist", - "showstats", - "showzonegloballoot", - "showzonepoints", - "spawnstatus", - "timers", - "trapinfo", - "uptime", - "version", - "viewcurrencies", - "viewnpctype", - "viewpetition", - "viewrecipe", - "viewzoneloot", - "who", - "wpinfo", - "xtargets", - "zonestatus", - "zstats" - } - }, - }; - - // inject static aliases + // inject static sub command aliases + // .e.g old #fi routes to #find item or #itemsearch routes to #find item for (auto& cs : command_settings) { - for (const auto& sa : static_aliases) { - if (cs.first == sa.command) { - for (const auto& alias : sa.aliases) { + for (const auto& e : command_subsettings) { + if (cs.first == e.parent_command) { + for (const auto& alias : Strings::Split(e.top_level_aliases, "|")) { cs.second.second.emplace_back(alias); } } @@ -418,7 +267,7 @@ int command_init(void) if (cl == commandlist.end()) { orphaned_command_settings.push_back(cs.first); LogInfo( - "Command [{}] no longer exists... Deleting orphaned entry from `command_settings` table...", + "Command [{}] no longer exists. Deleting orphaned entry from `command_settings` table.", cs.first ); } @@ -436,7 +285,7 @@ int command_init(void) if (cs == command_settings.end()) { injected_command_settings.emplace_back(w.first, w.second->admin); LogInfo( - "New Command [{}] found. Adding to `command_settings` table with admin [{}]...", + "New Command [{}] found. Adding to `command_settings` table with admin status [{}]", w.first, w.second->admin ); @@ -452,6 +301,7 @@ int command_init(void) } w.second->admin = cs->second.first; + LogCommands( "Command [{}] set to admin level [{}]", w.first, @@ -476,7 +326,7 @@ int command_init(void) continue; } - commandlist[a] = w.second; + commandlist[a] = w.second; commandaliases[a] = w.first; LogCommands( @@ -498,6 +348,7 @@ int command_init(void) return command_count; } + /* * command_deinit * clears the command list, freeing resources @@ -549,23 +400,24 @@ int command_add(std::string command_name, std::string description, uint8 admin, } auto c = new CommandRecord; - c->admin = admin; + + c->admin = admin; c->description = description; - c->function = function; + c->function = function; - commands_map[command_name] = admin; - - commandlist[command_name] = c; + commands_map[command_name] = admin; + commandlist[command_name] = c; commandaliases[command_name] = command_name; + command_delete_list.push_back(c); command_count++; return 0; } -uint8 GetCommandStatus(Client *c, std::string command_name) { - auto command_status = commands_map[command_name]; - return command_status; +uint8 GetCommandStatus(std::string command_name) +{ + return commands_map[command_name]; } /* @@ -591,9 +443,46 @@ int command_realdispatch(Client *c, std::string message, bool ignore_status) } auto cur = commandlist[cstr]; - if (!ignore_status && c->Admin() < cur->admin) { - c->Message(Chat::White, "Your status is not high enough to use this command."); - return -1; + + bool is_subcommand = false; + bool can_use_subcommand = false; + bool found_subcommand_setting = false; + + const auto arguments = sep.argnum; + + if (arguments >= 2) { + const std::string& sub_command = sep.arg[1]; + + for (const auto &e : command_subsettings) { + if (e.sub_command == sub_command) { + can_use_subcommand = c->Admin() >= static_cast(e.access_level); + is_subcommand = true; + found_subcommand_setting = true; + break; + } + } + + if (!found_subcommand_setting) { + for (const auto &e: command_subsettings) { + if (e.sub_command == sub_command) { + can_use_subcommand = c->Admin() >= static_cast(e.access_level); + is_subcommand = true; + break; + } + } + } + } + + if (!ignore_status) { + if (!is_subcommand && c->Admin() < cur->admin) { + c->Message(Chat::White, "Your status is not high enough to use this command."); + return -1; + } + + if (is_subcommand && !can_use_subcommand) { + c->Message(Chat::White, "Your status is not high enough to use this subcommand."); + return -1; + } } /* QS: Player_Log_Issued_Commands */ @@ -648,7 +537,10 @@ void command_help(Client *c, const Seperator *sep) for (const auto& cur : commandlist) { if (!search_criteria.empty()) { - if (!Strings::Contains(cur.first, search_criteria) && !Strings::Contains(cur.second->description, search_criteria)) { + if ( + !Strings::Contains(cur.first, search_criteria) && + !Strings::Contains(cur.second->description, search_criteria) + ) { continue; } } @@ -668,10 +560,9 @@ void command_help(Client *c, const Seperator *sep) c->Message( Chat::White, fmt::format( - "{} | Status: {} | {}", + "{} | {}", command_link, - cur.second->admin, - !cur.second->description.empty() ? cur.second->description : "" + cur.second->description ).c_str() ); @@ -703,88 +594,6 @@ void command_help(Client *c, const Seperator *sep) ); } -void command_findaliases(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (!arguments) { - c->Message(Chat::White, "Usage: #findaliases [Search Critera]"); - return; - } - - std::string search_criteria = Strings::ToLower(sep->argplus[1]); - - auto find_iter = commandaliases.find(search_criteria); - if (find_iter == commandaliases.end()) { - c->Message( - Chat::White, - fmt::format( - "No commands or aliases found matching '{}'.", - search_criteria - ).c_str() - ); - return; - } - - auto command_iter = commandlist.find(find_iter->second); - if ( - find_iter->second.empty() || - command_iter == commandlist.end() - ) { - c->Message(Chat::White, "An unknown condition occurred."); - return; - } - - auto current_commmand_link = Saylink::Silent( - fmt::format( - "{}{}", - COMMAND_CHAR, - command_iter->first - ) - ); - - int alias_count = 0; - int alias_number = 1; - std::string alias_link; - for (const auto& a : commandaliases) { - if ( - find_iter->second != a.second || - c->Admin() < command_iter->second->admin - ) { - continue; - } - - alias_link = Saylink::Silent( - fmt::format( - "{}{}", - COMMAND_CHAR, - a.first - ) - ); - - c->Message( - Chat::White, - fmt::format( - "Alias {} | {}", - alias_number, - alias_link - ).c_str() - ); - - alias_count++; - alias_number++; - } - - c->Message( - Chat::White, - fmt::format( - "{} Alias{} listed for {}.", - alias_count, - alias_count != 1 ? "es" : "", - current_commmand_link - ).c_str() - ); -} - void command_hotfix(Client *c, const Seperator *sep) { auto items_count = database.GetItemsCount(); @@ -977,7 +786,6 @@ void command_bot(Client *c, const Seperator *sep) #include "gm_commands/attack.cpp" #include "gm_commands/augmentitem.cpp" #include "gm_commands/ban.cpp" -#include "gm_commands/bind.cpp" #include "gm_commands/bugs.cpp" #include "gm_commands/camerashake.cpp" #include "gm_commands/castspell.cpp" @@ -988,7 +796,6 @@ void command_bot(Client *c, const Seperator *sep) #include "gm_commands/countitem.cpp" #include "gm_commands/damage.cpp" #include "gm_commands/databuckets.cpp" -#include "gm_commands/date.cpp" #include "gm_commands/dbspawn2.cpp" #include "gm_commands/delacct.cpp" #include "gm_commands/delpetition.cpp" @@ -1007,63 +814,42 @@ void command_bot(Client *c, const Seperator *sep) #include "gm_commands/emote.cpp" #include "gm_commands/emptyinventory.cpp" #include "gm_commands/enablerecipe.cpp" -#include "gm_commands/endurance.cpp" #include "gm_commands/entityvariable.cpp" #include "gm_commands/exptoggle.cpp" #include "gm_commands/faction.cpp" #include "gm_commands/feature.cpp" #include "gm_commands/find.cpp" #include "gm_commands/fixmob.cpp" -#include "gm_commands/flag.cpp" #include "gm_commands/flagedit.cpp" -#include "gm_commands/flymode.cpp" -#include "gm_commands/freeze.cpp" -#include "gm_commands/gassign.cpp" #include "gm_commands/gearup.cpp" -#include "gm_commands/gender.cpp" #include "gm_commands/giveitem.cpp" #include "gm_commands/givemoney.cpp" -#include "gm_commands/gm.cpp" -#include "gm_commands/gmspeed.cpp" #include "gm_commands/gmzone.cpp" -#include "gm_commands/godmode.cpp" #include "gm_commands/goto.cpp" #include "gm_commands/grid.cpp" #include "gm_commands/guild.cpp" -#include "gm_commands/haste.cpp" -#include "gm_commands/heal.cpp" -#include "gm_commands/heromodel.cpp" -#include "gm_commands/hideme.cpp" #include "gm_commands/hp.cpp" -#include "gm_commands/incstat.cpp" #include "gm_commands/instance.cpp" #include "gm_commands/interrogateinv.cpp" #include "gm_commands/interrupt.cpp" #include "gm_commands/invsnapshot.cpp" -#include "gm_commands/invul.cpp" #include "gm_commands/ipban.cpp" #include "gm_commands/kick.cpp" #include "gm_commands/kill.cpp" #include "gm_commands/killallnpcs.cpp" -#include "gm_commands/lastname.cpp" -#include "gm_commands/level.cpp" #include "gm_commands/list.cpp" #include "gm_commands/lootsim.cpp" #include "gm_commands/loc.cpp" #include "gm_commands/logs.cpp" #include "gm_commands/makepet.cpp" -#include "gm_commands/mana.cpp" -#include "gm_commands/max_all_skills.cpp" #include "gm_commands/memspell.cpp" #include "gm_commands/merchantshop.cpp" #include "gm_commands/modifynpcstat.cpp" -#include "gm_commands/motd.cpp" #include "gm_commands/movechar.cpp" #include "gm_commands/movement.cpp" #include "gm_commands/myskills.cpp" #include "gm_commands/mysql.cpp" #include "gm_commands/mystats.cpp" -#include "gm_commands/name.cpp" #include "gm_commands/npccast.cpp" #include "gm_commands/npcedit.cpp" #include "gm_commands/npceditmass.cpp" @@ -1077,20 +863,13 @@ void command_bot(Client *c, const Seperator *sep) #include "gm_commands/nukebuffs.cpp" #include "gm_commands/nukeitem.cpp" #include "gm_commands/object.cpp" -#include "gm_commands/oocmute.cpp" #include "gm_commands/path.cpp" #include "gm_commands/peqzone.cpp" -#include "gm_commands/permaclass.cpp" -#include "gm_commands/permagender.cpp" -#include "gm_commands/permarace.cpp" #include "gm_commands/petitems.cpp" #include "gm_commands/petname.cpp" #include "gm_commands/picklock.cpp" #include "gm_commands/profanity.cpp" #include "gm_commands/push.cpp" -#include "gm_commands/pvp.cpp" -#include "gm_commands/qglobal.cpp" -#include "gm_commands/race.cpp" #include "gm_commands/raidloot.cpp" #include "gm_commands/randomfeatures.cpp" #include "gm_commands/refreshgroup.cpp" @@ -1109,28 +888,7 @@ void command_bot(Client *c, const Seperator *sep) #include "gm_commands/scribespells.cpp" #include "gm_commands/sendzonespawns.cpp" #include "gm_commands/sensetrap.cpp" -#include "gm_commands/serverlock.cpp" -#include "gm_commands/serverrules.cpp" -#include "gm_commands/set_adventure_points.cpp" -#include "gm_commands/setaapts.cpp" -#include "gm_commands/setaaxp.cpp" -#include "gm_commands/setaltcurrency.cpp" -#include "gm_commands/setanim.cpp" -#include "gm_commands/setanon.cpp" -#include "gm_commands/setcrystals.cpp" -#include "gm_commands/setendurance.cpp" -#include "gm_commands/setfaction.cpp" -#include "gm_commands/sethp.cpp" -#include "gm_commands/setlanguage.cpp" -#include "gm_commands/setlsinfo.cpp" -#include "gm_commands/setmana.cpp" -#include "gm_commands/setpass.cpp" -#include "gm_commands/setpvppoints.cpp" -#include "gm_commands/setskill.cpp" -#include "gm_commands/setskillall.cpp" -#include "gm_commands/setstartzone.cpp" -#include "gm_commands/setstat.cpp" -#include "gm_commands/setxp.cpp" +#include "gm_commands/set.cpp" #include "gm_commands/show.cpp" #include "gm_commands/shutdown.cpp" #include "gm_commands/spawn.cpp" @@ -1144,39 +902,23 @@ void command_bot(Client *c, const Seperator *sep) #include "gm_commands/suspend.cpp" #include "gm_commands/suspendmulti.cpp" #include "gm_commands/task.cpp" -#include "gm_commands/tempname.cpp" -#include "gm_commands/texture.cpp" -#include "gm_commands/time.cpp" -#include "gm_commands/timezone.cpp" -#include "gm_commands/title.cpp" -#include "gm_commands/titlesuffix.cpp" #include "gm_commands/traindisc.cpp" #include "gm_commands/tune.cpp" #include "gm_commands/undye.cpp" -#include "gm_commands/unfreeze.cpp" #include "gm_commands/unmemspell.cpp" #include "gm_commands/unmemspells.cpp" #include "gm_commands/unscribespell.cpp" #include "gm_commands/unscribespells.cpp" -#include "gm_commands/updatechecksum.cpp" #include "gm_commands/untraindisc.cpp" #include "gm_commands/untraindiscs.cpp" #include "gm_commands/wc.cpp" -#include "gm_commands/weather.cpp" #include "gm_commands/worldshutdown.cpp" #include "gm_commands/worldwide.cpp" #include "gm_commands/wp.cpp" #include "gm_commands/wpadd.cpp" -#include "gm_commands/zclip.cpp" -#include "gm_commands/zcolor.cpp" -#include "gm_commands/zheader.cpp" #include "gm_commands/zone.cpp" #include "gm_commands/zonebootup.cpp" -#include "gm_commands/zonelock.cpp" #include "gm_commands/zoneshutdown.cpp" #include "gm_commands/zone_instance.cpp" #include "gm_commands/zopp.cpp" -#include "gm_commands/zsafecoords.cpp" #include "gm_commands/zsave.cpp" -#include "gm_commands/zsky.cpp" -#include "gm_commands/zunderworld.cpp" diff --git a/zone/command.h b/zone/command.h index 34cad6fad..f54265656 100644 --- a/zone/command.h +++ b/zone/command.h @@ -26,7 +26,7 @@ void command_deinit(void); int command_add(std::string command_name, std::string description, uint8 admin, CmdFuncPtr function); int command_notavail(Client *c, std::string message, bool ignore_status); int command_realdispatch(Client *c, std::string message, bool ignore_status); -uint8 GetCommandStatus(Client *c, std::string command_name); +uint8 GetCommandStatus(std::string command_name); void ListModifyNPCStatMap(Client *c); std::map GetModifyNPCStatMap(); std::string GetModifyNPCStatDescription(std::string stat); @@ -46,7 +46,6 @@ void command_apply_shared_memory(Client *c, const Seperator *sep); void command_attack(Client *c, const Seperator *sep); void command_augmentitem(Client *c, const Seperator *sep); void command_ban(Client *c, const Seperator *sep); -void command_bind(Client *c, const Seperator *sep); void command_bugs(Client *c, const Seperator *sep); void command_camerashake(Client *c, const Seperator *sep); void command_castspell(Client *c, const Seperator *sep); @@ -57,7 +56,6 @@ void command_corpsefix(Client *c, const Seperator *sep); void command_countitem(Client *c, const Seperator *sep); void command_damage(Client *c, const Seperator *sep); void command_databuckets(Client *c, const Seperator *sep); -void command_date(Client *c, const Seperator *sep); void command_dbspawn2(Client *c, const Seperator *sep); void command_delacct(Client *c, const Seperator *sep); void command_delpetition(Client *c, const Seperator *sep); @@ -75,7 +73,6 @@ void command_editmassrespawn(Client *c, const Seperator *sep); void command_emote(Client *c, const Seperator *sep); void command_emptyinventory(Client *c, const Seperator *sep); void command_enablerecipe(Client *c, const Seperator *sep); -void command_endurance(Client *c, const Seperator *sep); void command_entityvariable(Client *c, const Seperator *sep); void command_exptoggle(Client *c, const Seperator *sep); void command_faction(Client *c, const Seperator *sep); @@ -83,40 +80,25 @@ void command_faction_association(Client *c, const Seperator *sep); void command_feature(Client *c, const Seperator *sep); void command_find(Client *c, const Seperator *sep); void command_fixmob(Client *c, const Seperator *sep); -void command_flag(Client *c, const Seperator *sep); void command_flagedit(Client *c, const Seperator *sep); -void command_flymode(Client *c, const Seperator *sep); -void command_freeze(Client *c, const Seperator *sep); -void command_gassign(Client *c, const Seperator *sep); void command_gearup(Client *c, const Seperator *sep); -void command_gender(Client *c, const Seperator *sep); void command_giveitem(Client *c, const Seperator *sep); void command_givemoney(Client *c, const Seperator *sep); -void command_gm(Client *c, const Seperator *sep); -void command_gmspeed(Client *c, const Seperator *sep); void command_gmzone(Client *c, const Seperator *sep); -void command_godmode(Client* c, const Seperator *sep); void command_goto(Client *c, const Seperator *sep); void command_grid(Client *c, const Seperator *sep); void command_guild(Client *c, const Seperator *sep); -void command_haste(Client *c, const Seperator *sep); -void command_heal(Client *c, const Seperator *sep); void command_help(Client *c, const Seperator *sep); -void command_heromodel(Client *c, const Seperator *sep); -void command_hideme(Client *c, const Seperator *sep); void command_hotfix(Client *c, const Seperator *sep); void command_hp(Client *c, const Seperator *sep); -void command_incstat(Client *c, const Seperator *sep); void command_instance(Client *c, const Seperator *sep); void command_interrogateinv(Client *c, const Seperator *sep); void command_interrupt(Client *c, const Seperator *sep); void command_invsnapshot(Client *c, const Seperator *sep); -void command_invul(Client *c, const Seperator *sep); void command_ipban(Client *c, const Seperator *sep); void command_kick(Client *c, const Seperator *sep); void command_killallnpcs(Client *c, const Seperator *sep); void command_kill(Client *c, const Seperator *sep); -void command_lastname(Client *c, const Seperator *sep); void command_level(Client *c, const Seperator *sep); void command_list(Client *c, const Seperator *sep); void command_lootsim(Client *c, const Seperator *sep); @@ -124,18 +106,14 @@ void command_load_shared_memory(Client *c, const Seperator *sep); void command_loc(Client *c, const Seperator *sep); void command_logs(Client *c, const Seperator *sep); void command_makepet(Client *c, const Seperator *sep); -void command_mana(Client *c, const Seperator *sep); -void command_max_all_skills(Client *c, const Seperator *sep); void command_memspell(Client *c, const Seperator *sep); void command_merchantshop(Client *c, const Seperator *sep); void command_modifynpcstat(Client *c, const Seperator *sep); -void command_motd(Client *c, const Seperator *sep); void command_movechar(Client *c, const Seperator *sep); void command_movement(Client *c, const Seperator *sep); void command_myskills(Client *c, const Seperator *sep); void command_mysql(Client *c, const Seperator *sep); void command_mystats(Client *c, const Seperator *sep); -void command_name(Client *c, const Seperator *sep); void command_npccast(Client *c, const Seperator *sep); void command_npcedit(Client *c, const Seperator *sep); void command_npceditmass(Client *c, const Seperator *sep); @@ -152,16 +130,11 @@ void command_object(Client *c, const Seperator *sep); void command_oocmute(Client *c, const Seperator *sep); void command_path(Client *c, const Seperator *sep); void command_peqzone(Client *c, const Seperator *sep); -void command_permaclass(Client *c, const Seperator *sep); -void command_permagender(Client *c, const Seperator *sep); -void command_permarace(Client *c, const Seperator *sep); void command_petitems(Client *c, const Seperator *sep); void command_picklock(Client *c, const Seperator *sep); void command_profanity(Client *c, const Seperator *sep); void command_push(Client *c, const Seperator *sep); -void command_pvp(Client *c, const Seperator *sep); -void command_qglobal(Client *c, const Seperator *sep); -void command_race(Client *c, const Seperator *sep); +void command_pvp(Client *c, const Seperator *sep);; void command_raidloot(Client* c, const Seperator* sep); void command_randomfeatures(Client *c, const Seperator *sep); void command_refreshgroup(Client *c, const Seperator *sep); @@ -175,33 +148,13 @@ void command_revoke(Client *c, const Seperator *sep); void command_roambox(Client *c, const Seperator *sep); void command_rules(Client *c, const Seperator *sep); void command_save(Client *c, const Seperator *sep); -void command_serverlock(Client *c, const Seperator *sep); void command_scale(Client *c, const Seperator *sep); void command_scribespell(Client *c, const Seperator *sep); void command_scribespells(Client *c, const Seperator *sep); void command_sendzonespawns(Client *c, const Seperator *sep); void command_sensetrap(Client *c, const Seperator *sep); void command_serverrules(Client *c, const Seperator *sep); -void command_set_adventure_points(Client *c, const Seperator *sep); -void command_setaapts(Client *c, const Seperator *sep); -void command_setaaxp(Client *c, const Seperator *sep); -void command_setaltcurrency(Client *c, const Seperator *sep); -void command_setanim(Client *c, const Seperator *sep); -void command_setanon(Client *c, const Seperator *sep); -void command_setcrystals(Client *c, const Seperator *sep); -void command_setendurance(Client *c, const Seperator *sep); -void command_setfaction(Client *c, const Seperator *sep); -void command_sethp(Client *c, const Seperator *sep); -void command_setlanguage(Client *c, const Seperator *sep); -void command_setlsinfo(Client *c, const Seperator *sep); -void command_setmana(Client *c, const Seperator *sep); -void command_setpass(Client *c, const Seperator *sep); -void command_setpvppoints(Client *c, const Seperator *sep); -void command_setskill(Client *c, const Seperator *sep); -void command_setskillall(Client *c, const Seperator *sep); -void command_setstartzone(Client *c, const Seperator *sep); -void command_setstat(Client *c, const Seperator *sep); -void command_setxp(Client *c, const Seperator *sep); +void command_set(Client *c, const Seperator *sep); void command_show(Client *c, const Seperator *sep); void command_shutdown(Client *c, const Seperator *sep); void command_spawn(Client *c, const Seperator *sep); @@ -214,43 +167,28 @@ void command_summonitem(Client *c, const Seperator *sep); void command_suspend(Client *c, const Seperator *sep); void command_suspendmulti(Client *c, const Seperator *sep); void command_task(Client *c, const Seperator *sep); -void command_tempname(Client *c, const Seperator *sep); void command_petname(Client *c, const Seperator *sep); -void command_texture(Client *c, const Seperator *sep); -void command_time(Client *c, const Seperator *sep); -void command_timezone(Client *c, const Seperator *sep); -void command_title(Client *c, const Seperator *sep); -void command_titlesuffix(Client *c, const Seperator *sep); void command_traindisc(Client *c, const Seperator *sep); void command_tune(Client *c, const Seperator *sep); void command_undye(Client *c, const Seperator *sep); -void command_unfreeze(Client *c, const Seperator *sep); void command_unmemspell(Client *c, const Seperator *sep); void command_unmemspells(Client *c, const Seperator *sep); void command_unscribespell(Client *c, const Seperator *sep); void command_unscribespells(Client *c, const Seperator *sep); void command_untraindisc(Client *c, const Seperator *sep); void command_untraindiscs(Client *c, const Seperator *sep); -void command_updatechecksum(Client* c, const Seperator* sep); void command_wc(Client *c, const Seperator *sep); -void command_weather(Client *c, const Seperator *sep); void command_worldshutdown(Client *c, const Seperator *sep); void command_wp(Client *c, const Seperator *sep); void command_wpadd(Client *c, const Seperator *sep); void command_worldwide(Client *c, const Seperator *sep); -void command_zclip(Client *c, const Seperator *sep); -void command_zcolor(Client *c, const Seperator *sep); -void command_zheader(Client *c, const Seperator *sep); void command_zone(Client *c, const Seperator *sep); void command_zone_instance(Client *c, const Seperator *sep); void command_zonebootup(Client *c, const Seperator *sep); -void command_zonelock(Client *c, const Seperator *sep); void command_zoneshutdown(Client *c, const Seperator *sep); void command_zopp(Client *c, const Seperator *sep); void command_zsafecoords(Client *c, const Seperator *sep); void command_zsave(Client *c, const Seperator *sep); -void command_zsky(Client *c, const Seperator *sep); -void command_zunderworld(Client *c, const Seperator *sep); #include "bot.h" void command_bot(Client*c, const Seperator *sep); diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index 6dc6ea70a..3d885d40b 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -2315,17 +2315,17 @@ void Perl__removetitle(int title_set) quest_manager.removetitle(title_set); } -void Perl__wearchange(uint8 slot, uint16 texture_id) +void Perl__wearchange(uint8 slot, uint32 texture_id) { quest_manager.wearchange(slot, texture_id); } -void Perl__wearchange(uint8 slot, uint16 texture_id, uint32 hero_forge_model_id) +void Perl__wearchange(uint8 slot, uint32 texture_id, uint32 hero_forge_model_id) { quest_manager.wearchange(slot, texture_id, hero_forge_model_id); } -void Perl__wearchange(uint8 slot, uint16 texture_id, uint32 hero_forge_model_id, uint32 elite_material_id) +void Perl__wearchange(uint8 slot, uint32 texture_id, uint32 hero_forge_model_id, uint32 elite_material_id) { quest_manager.wearchange(slot, texture_id, hero_forge_model_id, elite_material_id); } @@ -6214,9 +6214,9 @@ void perl_register_quest() package.add("varlink", (std::string(*)(uint32, int16, uint32, uint32, uint32, uint32, uint32, uint32, bool))&Perl__varlink); package.add("voicetell", &Perl__voicetell); package.add("we", &Perl__we); - package.add("wearchange", (void(*)(uint8, uint16))&Perl__wearchange); - package.add("wearchange", (void(*)(uint8, uint16, uint32))&Perl__wearchange); - package.add("wearchange", (void(*)(uint8, uint16, uint32, uint32))&Perl__wearchange); + package.add("wearchange", (void(*)(uint8, uint32))&Perl__wearchange); + package.add("wearchange", (void(*)(uint8, uint32, uint32))&Perl__wearchange); + package.add("wearchange", (void(*)(uint8, uint32, uint32, uint32))&Perl__wearchange); package.add("whisper", &Perl__whisper); package.add("write", &Perl__write); package.add("ze", &Perl__ze); diff --git a/zone/entity.cpp b/zone/entity.cpp index 052b0afc7..94582eb79 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -2244,6 +2244,18 @@ Raid* EntityList::GetRaidByBot(const Bot* bot) return nullptr; } +Raid* EntityList::GetRaidByName(const char* name) +{ + for (const auto& r : raid_list) { + for (const auto& m : r->members) { + if (Strings::EqualFold(m.member_name, name)) { + return r; + } + } + } + return nullptr; +} + Client *EntityList::GetClientByAccID(uint32 accid) { auto it = client_list.begin(); diff --git a/zone/entity.h b/zone/entity.h index 3bf128fc7..672a4f31f 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -198,6 +198,7 @@ public: Raid *GetRaidByID(uint32 id); Raid* GetRaidByBotName(const char* name); Raid* GetRaidByBot(const Bot* bot); + Raid* GetRaidByName(const char* name); Corpse *GetCorpseByOwner(Client* client); Corpse *GetCorpseByOwnerWithinRange(Client* client, Mob* center, int range); diff --git a/zone/gm_commands/bind.cpp b/zone/gm_commands/bind.cpp deleted file mode 100755 index f90e131af..000000000 --- a/zone/gm_commands/bind.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "../client.h" - -void command_bind(Client *c, const Seperator *sep) -{ - Client *target = c; - if (c->GetTarget() && c->GetTarget()->IsClient()) { - target = c->GetTarget()->CastToClient(); - } - - bool bind_allowed = ( - !zone->GetInstanceID() || - ( - zone->GetInstanceID() != 0 && - zone->IsInstancePersistent() - ) - ); - - if (!bind_allowed) { - c->Message(Chat::White, "You cannot bind here."); - return; - } - - target->SetBindPoint(); - - c->Message( - Chat::White, - fmt::format( - "Set Bind Point for {} | Zone: {}", - c->GetTargetDescription(target), - zone->GetZoneDescription() - ).c_str() - ); - - c->Message( - Chat::White, - fmt::format( - "Set Bind Point for {} | XYZ: {:.2f}, {:.2f}, {:.2f}", - c->GetTargetDescription(target), - target->GetX(), - target->GetY(), - target->GetZ() - ).c_str() - ); -} diff --git a/zone/gm_commands/date.cpp b/zone/gm_commands/date.cpp deleted file mode 100755 index 08cde4e60..000000000 --- a/zone/gm_commands/date.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "../client.h" - -void command_date(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if ( - !arguments || - !sep->IsNumber(1) || - !sep->IsNumber(2) || - !sep->IsNumber(3) - ) { - c->Message(Chat::White, "Usage: #date [Year] [Month] [Day] [Hour] [Minute]"); - return; - } - - TimeOfDay_Struct eq_time; - zone->zone_time.GetCurrentEQTimeOfDay(time(0), &eq_time); - - auto year = static_cast(Strings::ToUnsignedInt(sep->arg[1])); - auto month = static_cast(Strings::ToUnsignedInt(sep->arg[2])); - auto day = static_cast(Strings::ToUnsignedInt(sep->arg[3])); - - auto hour = !sep->IsNumber(4) ? eq_time.hour : static_cast(Strings::ToUnsignedInt(sep->arg[4]) + 1); - auto minute = !sep->IsNumber(5) ? eq_time.minute : static_cast(Strings::ToUnsignedInt(sep->arg[5])); - - c->Message( - Chat::White, - fmt::format("Setting world time to {}/{}/{} {:02}:{:02} {}.", - year, - month, - day, - ( - (hour % 12) == 0 ? - 12 : - (hour % 12) - ), - minute, - ( - hour >= 13 ? - "PM" : - "AM" - ) - ).c_str() - ); - - zone->SetDate(year, month, day, hour, minute); - - LogInfo( - "{} :: Setting world time to {}/{}/{} {:02}:{:02} {}.", - c->GetCleanName(), - year, - month, - day, - ( - (hour % 12) == 0 ? - 12 : - (hour % 12) - ), - minute, - ( - hour >= 13 ? - "PM" : - "AM" - ) - ); -} - diff --git a/zone/gm_commands/endurance.cpp b/zone/gm_commands/endurance.cpp deleted file mode 100755 index 7f113a949..000000000 --- a/zone/gm_commands/endurance.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "../client.h" - -void command_endurance(Client *c, const Seperator *sep) -{ - Mob* target = c; - if (c->GetTarget()) { - target = c->GetTarget(); - } - - int endurance = 0; - if (target->IsClient()) { - endurance = target->CastToClient()->GetMaxEndurance(); - target->CastToClient()->SetEndurance(endurance); - } else { - endurance = target->GetMaxEndurance(); - target->SetEndurance(endurance); - } - - c->Message( - Chat::White, - fmt::format( - "Set {} to full Endurance ({}).", - c->GetTargetDescription(target), - endurance - ).c_str() - ); -} - diff --git a/zone/gm_commands/faction.cpp b/zone/gm_commands/faction.cpp old mode 100755 new mode 100644 diff --git a/zone/gm_commands/find.cpp b/zone/gm_commands/find.cpp index 910c0a677..126de26b5 100644 --- a/zone/gm_commands/find.cpp +++ b/zone/gm_commands/find.cpp @@ -78,8 +78,19 @@ void command_find(Client *c, const Seperator *sep) // build the rewrite string std::string rewrite = fmt::format("#find {} {}", cmd.cmd, Strings::Join(args, " ")); - // rewrite to #find + // rewrite to #find > c->SendGMCommand(rewrite); + + c->Message( + Chat::Gray, + fmt::format( + "{} is now located under {}, using {}.", + sep->arg[0], + Saylink::Silent("#find"), + Saylink::Silent(rewrite) + ).c_str() + ); + return; } } diff --git a/zone/gm_commands/find/currency.cpp b/zone/gm_commands/find/currency.cpp index dde937824..c7b2f6b6a 100644 --- a/zone/gm_commands/find/currency.cpp +++ b/zone/gm_commands/find/currency.cpp @@ -2,7 +2,7 @@ void FindCurrency(Client *c, const Seperator *sep) { - const auto can_summon_items = c->Admin() >= GetCommandStatus(c, "summonitem"); + const auto can_summon_items = c->Admin() >= GetCommandStatus("summonitem"); if (sep->IsNumber(2)) { const auto item_id = Strings::ToUnsignedInt(sep->arg[2]); diff --git a/zone/gm_commands/find/item.cpp b/zone/gm_commands/find/item.cpp index a0400f521..aaea2638e 100644 --- a/zone/gm_commands/find/item.cpp +++ b/zone/gm_commands/find/item.cpp @@ -71,7 +71,11 @@ void FindItem(Client *c, const Seperator *sep) auto found_count = 0; for (const auto& e : l) { - const auto* item = database.GetItem(e); + const auto item = database.GetItem(e); + if (!item) { + continue; + } + std::string summon_links = Saylink::Silent( fmt::format( "#si {}", @@ -97,9 +101,10 @@ void FindItem(Client *c, const Seperator *sep) c->Message( Chat::White, fmt::format( - "{} | {}", + "{} | {} ({})", summon_links, - database.CreateItemLink(e) + database.CreateItemLink(e), + Strings::Commify(item->ID) ).c_str() ); diff --git a/zone/gm_commands/find/npctype.cpp b/zone/gm_commands/find/npctype.cpp index bf8fc95d6..a25bce0f0 100644 --- a/zone/gm_commands/find/npctype.cpp +++ b/zone/gm_commands/find/npctype.cpp @@ -33,7 +33,7 @@ void FindNPCType(Client *c, const Seperator *sep) return; } - const auto can_spawn_npcs = c->Admin() >= GetCommandStatus(c, "#npctypespawn"); + const auto can_spawn_npcs = c->Admin() >= GetCommandStatus("#npctypespawn"); auto found_count = 0; diff --git a/zone/gm_commands/find/recipe.cpp b/zone/gm_commands/find/recipe.cpp index 2a675dc26..0d8b18951 100644 --- a/zone/gm_commands/find/recipe.cpp +++ b/zone/gm_commands/find/recipe.cpp @@ -4,7 +4,7 @@ void FindRecipe(Client *c, const Seperator *sep) { - const auto can_view_recipes = c->Admin() >= GetCommandStatus(c, "viewrecipe"); + const auto can_view_recipes = c->Admin() >= GetCommandStatus("viewrecipe"); if (sep->IsNumber(2)) { const auto recipe_id = static_cast(Strings::ToUnsignedInt(sep->arg[2])); diff --git a/zone/gm_commands/find/spell.cpp b/zone/gm_commands/find/spell.cpp index 5aa157cbc..58887f67a 100644 --- a/zone/gm_commands/find/spell.cpp +++ b/zone/gm_commands/find/spell.cpp @@ -7,7 +7,7 @@ void FindSpell(Client *c, const Seperator *sep) return; } - const auto can_cast_spells = c->Admin() >= GetCommandStatus(c, "castspell"); + const auto can_cast_spells = c->Admin() >= GetCommandStatus("castspell"); if (sep->IsNumber(2)) { const auto spell_id = Strings::ToUnsignedInt(sep->arg[2]); diff --git a/zone/gm_commands/find/task.cpp b/zone/gm_commands/find/task.cpp index dd38433ca..3fea5a591 100644 --- a/zone/gm_commands/find/task.cpp +++ b/zone/gm_commands/find/task.cpp @@ -7,7 +7,7 @@ void FindTask(Client *c, const Seperator *sep) return; } - const auto can_assign_tasks = c->Admin() >= GetCommandStatus(c, "task"); + const auto can_assign_tasks = c->Admin() >= GetCommandStatus("task"); if (sep->IsNumber(2)) { const auto task_id = Strings::ToUnsignedInt(sep->arg[2]); diff --git a/zone/gm_commands/find/zone.cpp b/zone/gm_commands/find/zone.cpp index 92cb55968..74e6e35de 100644 --- a/zone/gm_commands/find/zone.cpp +++ b/zone/gm_commands/find/zone.cpp @@ -19,7 +19,7 @@ void FindZone(Client *c, const Seperator *sep) ); search_string = Expansion::ExpansionName[Strings::ToInt(sep->arg[3])]; - search_type = "Expansion"; + search_type = "expansion"; } else if (is_id_search) { query += fmt::format( "zoneidnumber = {}", @@ -27,7 +27,7 @@ void FindZone(Client *c, const Seperator *sep) ); search_string = sep->arg[2]; - search_type = "Expansion"; + search_type = "ID"; } else if (is_short_name_search) { query += fmt::format( "LOWER(`long_name`) LIKE '%%{}%%' OR LOWER(`short_name`) LIKE '%%{}%%'", @@ -36,7 +36,7 @@ void FindZone(Client *c, const Seperator *sep) ); search_string = sep->argplus[2]; - search_type = "Expansion"; + search_type = "name"; } query += " ORDER BY `zoneidnumber` ASC LIMIT 50"; diff --git a/zone/gm_commands/flag.cpp b/zone/gm_commands/flag.cpp deleted file mode 100755 index 12135fbe3..000000000 --- a/zone/gm_commands/flag.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include "../client.h" -#include "../worldserver.h" - -extern WorldServer worldserver; - -void command_flag(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (!arguments) { - auto target = c->GetTarget() && c->GetTarget()->IsClient() ? c->GetTarget()->CastToClient() : c; - if (target != c) { - c->Message( - Chat::White, - fmt::format( - "Status level has been refreshed for {}.", - target->GetCleanName() - ).c_str() - ); - - target->Message( - Chat::White, - fmt::format( - "Your status level has been refreshed by {}.", - c->GetCleanName() - ).c_str() - ); - } else { - c->Message(Chat::White, "Your status level has been refreshed."); - } - target->UpdateAdmin(); - return; - } - - - if ( - !sep->IsNumber(1) || - strlen(sep->arg[2]) == 0 - ) { - c->Message(Chat::White, "Usage: #flag [Status] [Account Name]"); - return; - } - - auto status = Strings::ToInt(sep->arg[1]); - if (status < -2 || status > 255) { - c->Message(Chat::White, "The lowest a status level can go is -2 and the highest a status level can go is 255."); - return; - } - - std::string account_name = sep->argplus[2]; - auto account_id = database.GetAccountIDByChar(account_name.c_str()); - - if (c->Admin() < commandChangeFlags) { //this check makes banning players by less than this level impossible, but i'll leave it in anyways - c->Message(Chat::White, "You may only refresh your own flag, doing so now."); - c->UpdateAdmin(); - } else { - if (status > c->Admin()) { - c->Message( - Chat::White, - fmt::format( - "You cannot set someone's status level to {} because your status level is only {}.", - status, - c->Admin() - ).c_str() - ); - } else if (status < 0 && c->Admin() < commandBanPlayers) { - c->Message(Chat::White, "Your status level is not high enough to ban or suspend."); - } else if (!database.SetAccountStatus(account_name, status)) { - c->Message(Chat::White, "Failed to set status level."); - } - else { - c->Message(Chat::White, "Set GM Flag on account."); - - std::string user; - std::string loginserver; - ParseAccountString(account_name, user, loginserver); - - account_id = database.GetAccountIDByName(account_name, loginserver); - - ServerPacket pack(ServerOP_FlagUpdate, sizeof(ServerFlagUpdate_Struct)); - ServerFlagUpdate_Struct *sfus = (ServerFlagUpdate_Struct *) pack.pBuffer; - sfus->account_id = account_id; - sfus->admin = status; - worldserver.SendPacket(&pack); - } - } -} - diff --git a/zone/gm_commands/flymode.cpp b/zone/gm_commands/flymode.cpp deleted file mode 100755 index 46ebc40b9..000000000 --- a/zone/gm_commands/flymode.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "../client.h" -#include "../../common/data_verification.h" - -void command_flymode(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (!arguments || !sep->IsNumber(1)) { - return; - } - - Mob *target = c; - if (c->GetTarget()) { - target = c->GetTarget(); - } - - auto flymode_id = Strings::ToUnsignedInt(sep->arg[1]); - if (!EQ::ValueWithin(flymode_id, EQ::constants::GravityBehavior::Ground, EQ::constants::GravityBehavior::LevitateWhileRunning)) { - c->Message(Chat::White, "Usage:: #flymode [Flymode ID]"); - c->Message(Chat::White, "0 = Ground, 1 = Flying, 2 = Levitating, 3 = Water, 4 = Floating, 5 = Levitating While Running"); - return; - } - - target->SetFlyMode(static_cast(flymode_id)); - target->SendAppearancePacket(AT_Levitate, flymode_id); - uint32 account = c->AccountID(); - database.SetGMFlymode(account, flymode_id); - c->Message( - Chat::White, - fmt::format( - "Fly Mode for {} is now {} ({}).", - c->GetTargetDescription(target), - EQ::constants::GetFlyModeName(flymode_id), - flymode_id - ).c_str() - ); -} - - diff --git a/zone/gm_commands/freeze.cpp b/zone/gm_commands/freeze.cpp deleted file mode 100755 index 0b002b124..000000000 --- a/zone/gm_commands/freeze.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "../client.h" - -void command_freeze(Client *c, const Seperator *sep) -{ - if (!c->GetTarget()) { - c->Message(Chat::White, "You must have a target to use this command."); - return; - } - - auto target = c->GetTarget(); - if (c == target) { - c->Message(Chat::White, "You cannot freeze yourself."); - return; - } - - target->SendAppearancePacket(AT_Anim, ANIM_FREEZE); - - c->Message( - Chat::White, - fmt::format( - "You have frozen {}.", - c->GetTargetDescription(target) - ).c_str() - ); -} - diff --git a/zone/gm_commands/gassign.cpp b/zone/gm_commands/gassign.cpp deleted file mode 100755 index 4c4b61aa9..000000000 --- a/zone/gm_commands/gassign.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "../client.h" - -void command_gassign(Client *c, const Seperator *sep) -{ - if (!c->GetTarget() || !c->GetTarget()->IsNPC()) { - c->Message(Chat::White, "You must target an NPC to use this command."); - return; - } - - int arguments = sep->argnum; - if (!arguments || !sep->IsNumber(1)) { - c->Message(Chat::White, "Usage: #gassign [Grid ID]"); - return; - } - - auto grid_id = Strings::ToUnsignedInt(sep->arg[1]); - - auto target = c->GetTarget()->CastToNPC(); - if (target->GetSpawnPointID() > 0) { - database.AssignGrid(c, grid_id, target->GetID()); - } -} - diff --git a/zone/gm_commands/gender.cpp b/zone/gm_commands/gender.cpp deleted file mode 100755 index 42e7396c4..000000000 --- a/zone/gm_commands/gender.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "../client.h" - -void command_gender(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (!arguments || !sep->IsNumber(1)) { - c->Message(Chat::White, "Usage: #gender [Gender ID]"); - c->Message(Chat::White, "Genders: 0 = Male, 1 = Female, 2 = Neuter"); - return; - } - - Mob *target = c; - if (c->GetTarget() && c->Admin() >= commandGenderOthers) { - target = c->GetTarget(); - } - - auto gender_id = Strings::ToInt(sep->arg[1]); - if (gender_id < 0 || gender_id > 2) { - c->Message(Chat::White, "Usage: #gender [Gender ID]"); - c->Message(Chat::White, "Genders: 0 = Male, 1 = Female, 2 = Neuter"); - return; - } - - target->SendIllusionPacket( - target->GetRace(), - gender_id - ); - - c->Message( - Chat::White, - fmt::format( - "Gender changed for {} to {} ({}).", - c->GetTargetDescription(target), - GetGenderName(gender_id), - gender_id - ).c_str() - ); -} diff --git a/zone/gm_commands/gm.cpp b/zone/gm_commands/gm.cpp deleted file mode 100755 index fb5560b74..000000000 --- a/zone/gm_commands/gm.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "../client.h" - -void command_gm(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (!arguments) { - c->Message(Chat::White, "Usage: #gm [On|Off]"); - return; - } - - bool gm_flag = atobool(sep->arg[1]); - Client *target = c; - if (c->GetTarget() && c->GetTarget()->IsClient()) { - target = c->GetTarget()->CastToClient(); - } - - target->SetGM(gm_flag); - if (c != target) { - c->Message( - Chat::White, - fmt::format( - "{} is {} flagged as a GM.", - c->GetTargetDescription(target), - gm_flag ? "now" : "no longer" - ).c_str() - ); - } -} diff --git a/zone/gm_commands/gmspeed.cpp b/zone/gm_commands/gmspeed.cpp deleted file mode 100755 index 627082c74..000000000 --- a/zone/gm_commands/gmspeed.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "../client.h" - -void command_gmspeed(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (!arguments) { - c->Message(Chat::White, "Usage: #gmspeed [On|Off]"); - return; - } - - bool gm_speed_flag = atobool(sep->arg[1]); - Client *target = c; - if (c->GetTarget() && c->GetTarget()->IsClient()) { - target = c->GetTarget()->CastToClient(); - } - - database.SetGMSpeed( - target->AccountID(), - gm_speed_flag ? 1 : 0 - ); - - c->Message( - Chat::White, - fmt::format( - "Turning GM Speed {} for {}.", - gm_speed_flag ? "on" : "off", - c->GetTargetDescription(target) - ).c_str() - ); - - c->Message( - Chat::White, - fmt::format( - "Note: {} must zone for it to take effect.", - c->GetTargetDescription(target, TargetDescriptionType::UCYou) - ).c_str() - ); -} - diff --git a/zone/gm_commands/godmode.cpp b/zone/gm_commands/godmode.cpp deleted file mode 100644 index 81ecbe93d..000000000 --- a/zone/gm_commands/godmode.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "../client.h" -#include "../../common/repositories/account_repository.h" - -void command_godmode(Client *c, const Seperator *sep) -{ - bool state = atobool(sep->arg[1]); - uint32 account_id = c->AccountID(); - - if (sep->arg[1][0] != 0) { - auto a = AccountRepository::FindOne(database, c->AccountID()); - if (a.id > 0) { - a.flymode = state ? 1 : 0; - a.gmspeed = state ? 1 : 0; - a.invulnerable = state ? 1 : 0; - a.hideme = state ? 1 : 0; - } - - c->SetInvul(state); - c->SendAppearancePacket(AT_Levitate, state); - c->SetHideMe(state); - c->Message( - Chat::White, - "Turning GodMode %s for %s (zone for gmspeed to take effect)", - state ? "On" : "Off", - c->GetName() - ); - - AccountRepository::UpdateOne(database, a); - } - else { - c->Message(Chat::White, "Usage: #godmode [on/off]"); - } -} diff --git a/zone/gm_commands/heal.cpp b/zone/gm_commands/heal.cpp deleted file mode 100755 index 904cf4baf..000000000 --- a/zone/gm_commands/heal.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "../client.h" - -void command_heal(Client *c, const Seperator *sep) -{ - Mob* target = c; - if (c->GetTarget()) { - target = c->GetTarget(); - } - - target->Heal(); - - c->Message( - Chat::White, - fmt::format( - "Set {} to full Health ({}).", - c->GetTargetDescription(target), - target->GetMaxHP() - ).c_str() - ); -} - diff --git a/zone/gm_commands/heromodel.cpp b/zone/gm_commands/heromodel.cpp deleted file mode 100755 index f6c35b142..000000000 --- a/zone/gm_commands/heromodel.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "../client.h" - -void command_heromodel(Client *c, const Seperator *sep) -{ - auto arguments = sep->argnum; - if (!arguments) { - c->Message(Chat::White, "Usage: #heromodel [Hero Model]"); - c->Message(Chat::White, "Usage: #heromodel [Hero Model] [Slot]"); - c->Message( - Chat::White, - fmt::format( - "Example: {}", - Saylink::Silent("#heromodel 63") - ).c_str() - ); - return; - } - - Mob* t = c; - if (c->GetTarget()) { - t = c->GetTarget(); - } - - auto hero_forge_model = Strings::IsNumber(sep->arg[1]) ? Strings::ToUnsignedInt(sep->arg[1]) : 0; - - if (arguments > 1) { - auto slot = static_cast(Strings::ToUnsignedInt(sep->arg[2])); - c->GetTarget()->SendTextureWC(slot, 0, hero_forge_model, 0, 0, 0); - } else { - if (hero_forge_model) { - // Conversion to simplify the command arguments - // Hero's Forge model is actually model * 1000 + texture * 100 + wearslot - // Hero's Forge Model slot 7 is actually for Robes, but it still needs to use wearslot 1 in the packet - hero_forge_model *= 100; - - for (uint8 slot = 0; slot < 7; slot++) { - c->GetTarget()->SendTextureWC(slot, 0, (hero_forge_model + slot), 0, 0, 0); - } - } else { - c->Message(Chat::White, "Hero's Forge Model must be greater than 0."); - } - } -} - diff --git a/zone/gm_commands/incstat.cpp b/zone/gm_commands/incstat.cpp deleted file mode 100755 index 14ad4a235..000000000 --- a/zone/gm_commands/incstat.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "../client.h" - -void command_incstat(Client *c, const Seperator *sep) -{ - if (sep->arg[1][0] && sep->arg[2][0] && c->GetTarget() != 0 && c->GetTarget()->IsClient()) { - c->GetTarget()->CastToClient()->IncStats(Strings::ToInt(sep->arg[1]), Strings::ToInt(sep->arg[2])); - } - else { - c->Message(Chat::White, "This command is used to permanently increase or decrease a players stats."); - c->Message(Chat::White, "Usage: #setstat {type} {value by which to increase or decrease}"); - c->Message( - Chat::White, - "Note: The value is in increments of 2, so a value of 3 will actually increase the stat by 6" - ); - c->Message(Chat::White, "Types: Str: 0, Sta: 1, Agi: 2, Dex: 3, Int: 4, Wis: 5, Cha: 6"); - } -} - diff --git a/zone/gm_commands/invul.cpp b/zone/gm_commands/invul.cpp deleted file mode 100755 index 398cd5174..000000000 --- a/zone/gm_commands/invul.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "../client.h" - -void command_invul(Client *c, const Seperator *sep) { - int arguments = sep->argnum; - if (!arguments) { - c->Message(Chat::White, "Usage: #invul [On|Off]"); - return; - } - - bool invul_flag = atobool(sep->arg[1]); - Client *target = c; - if (c->GetTarget() && c->GetTarget()->IsClient()) { - target = c->GetTarget()->CastToClient(); - } - - target->SetInvul(invul_flag); - uint32 account = target->AccountID(); - database.SetGMInvul(account, invul_flag); - c->Message( - Chat::White, - fmt::format( - "{} {} now {}.", - c->GetTargetDescription(target, TargetDescriptionType::UCYou), - c == target ? "are" : "is", - invul_flag ? "invulnerable" : "vulnerable" - ).c_str() - ); -} diff --git a/zone/gm_commands/lastname.cpp b/zone/gm_commands/lastname.cpp deleted file mode 100755 index 070f5023a..000000000 --- a/zone/gm_commands/lastname.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "../client.h" - -void command_lastname(Client *c, const Seperator *sep) -{ - Client *target = c; - if (c->GetTarget() && c->GetTarget()->IsClient()) { - target = c->GetTarget()->CastToClient(); - } - - LogInfo("#lastname request from [{}] for [{}]", c->GetCleanName(), target->GetCleanName()); - - bool is_remove = !strcasecmp(sep->argplus[1], "-1"); - std::string last_name = is_remove ? "" : sep->argplus[1]; - - if (last_name.size() > 64) { - c->Message(Chat::White, "Last name must be 64 characters or less."); - return; - } - - target->ChangeLastName(last_name); - - c->Message( - Chat::White, - fmt::format( - "Last name has been {}{} for {}{}", - is_remove ? "removed" : "changed", - !is_remove ? " and saved" : "", - c->GetTargetDescription(target), - ( - is_remove ? - "." : - fmt::format( - " to '{}'.", - last_name - ) - ) - ).c_str() - ); -} - diff --git a/zone/gm_commands/level.cpp b/zone/gm_commands/level.cpp deleted file mode 100644 index 37f6a4bb2..000000000 --- a/zone/gm_commands/level.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "../client.h" - -void command_level(Client *c, const Seperator *sep) -{ - const auto arguments = sep->argnum; - if (!arguments || !sep->IsNumber(1)) { - c->Message(Chat::White, "Usage: #level [Level]"); - return; - } - - Mob* t = c; - if (c->GetTarget()) { - t = c->GetTarget(); - } - - auto level = static_cast(Strings::ToUnsignedInt(sep->arg[1])); - auto max_level = static_cast(RuleI(Character, MaxLevel)); - - if (c != t && c->Admin() < RuleI(GM, MinStatusToLevelTarget)) { - c->Message(Chat::White, "Your status is not high enough to change another person's level."); - return; - } - - if ( - level > max_level && - c->Admin() < commandLevelAboveCap - ) { - c->Message( - Chat::White, - fmt::format( - "Level {} is above the Maximum Level of {} and your status is not high enough to go beyond the cap.", - level, - max_level - ).c_str() - ); - return; - } - - t->SetLevel(level, true); - if (t->IsClient()) { - t->CastToClient()->SendLevelAppearance(); - - if (RuleB(Bots, Enabled) && RuleB(Bots, BotLevelsWithOwner)) { - Bot::LevelBotWithClient(t->CastToClient(), level, true); - } - } -} diff --git a/zone/gm_commands/mana.cpp b/zone/gm_commands/mana.cpp deleted file mode 100755 index 8808a568e..000000000 --- a/zone/gm_commands/mana.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "../client.h" - -void command_mana(Client *c, const Seperator *sep) -{ - auto target = c->GetTarget() ? c->GetTarget() : c; - int mana = 0; - if (target->IsClient()) { - mana = target->CastToClient()->CalcMaxMana(); - target->CastToClient()->SetMana(mana); - } - else { - mana = target->CalcMaxMana(); - target->SetMana(mana); - } - - c->Message( - Chat::White, - fmt::format( - "Set {} to full Mana ({}).", - c->GetTargetDescription(target), - mana - ).c_str() - ); -} - diff --git a/zone/gm_commands/name.cpp b/zone/gm_commands/name.cpp deleted file mode 100755 index 58dda8e75..000000000 --- a/zone/gm_commands/name.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "../client.h" - -void command_name(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (!arguments) { - c->Message(Chat::White, "Usage: #name [New Name] - Rename your player target"); - return; - } - - if (c->GetTarget() && c->GetTarget()->IsClient()) { - auto target = c->GetTarget()->CastToClient(); - - std::string new_name = sep->arg[1]; - std::string old_name = target->GetCleanName(); - - if (target->ChangeFirstName(new_name.c_str(), c->GetCleanName())) { - c->Message( - Chat::White, - fmt::format( - "Successfully renamed {} to {}", - old_name, - new_name - ).c_str() - ); - - c->Message(Chat::White, "Sending player to char select."); - - target->Kick("Name was changed"); - } else { - c->Message( - Chat::White, - fmt::format( - "Unable to rename {}. Check that the new name '{}' isn't already taken.", - old_name, - new_name - ).c_str() - ); - } - } -} - diff --git a/zone/gm_commands/permaclass.cpp b/zone/gm_commands/permaclass.cpp deleted file mode 100755 index 1c8d9924f..000000000 --- a/zone/gm_commands/permaclass.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "../client.h" - -void command_permaclass(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (!arguments || !sep->IsNumber(1)) { - c->Message(Chat::White, "Usage: #permaclass [Class ID]"); - return; - } - - Client *target = c; - if (c->GetTarget() && c->GetTarget()->IsClient()) { - target = c->GetTarget()->CastToClient(); - } - - auto class_id = Strings::ToInt(sep->arg[1]); - - LogInfo("Class changed by {} for {} to {} ({})", - c->GetCleanName(), - c->GetTargetDescription(target), - GetClassIDName(class_id), - class_id - ); - - target->SetBaseClass(class_id); - target->Save(); - target->Kick("Class was changed."); - - if (c != target) { - c->Message( - Chat::White, - fmt::format( - "Class changed for {} to {} ({}).", - c->GetTargetDescription(target), - GetClassIDName(class_id), - class_id - ).c_str() - ); - } -} diff --git a/zone/gm_commands/permagender.cpp b/zone/gm_commands/permagender.cpp deleted file mode 100755 index a23cbce95..000000000 --- a/zone/gm_commands/permagender.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "../client.h" - -void command_permagender(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (!arguments || !sep->IsNumber(1)) { - c->Message(Chat::White, "Usage: #permagender [Gender ID]"); - c->Message(Chat::White, "Genders: 0 = Male, 1 = Female, 2 = Neuter"); - return; - } - - Client *target = c; - if (c->GetTarget() && c->GetTarget()->IsClient()) { - target = c->GetTarget()->CastToClient(); - } - - auto gender_id = Strings::ToInt(sep->arg[1]); - if (gender_id < 0 || gender_id > 2) { - c->Message(Chat::White, "Usage: #permagender [Gender ID]"); - c->Message(Chat::White, "Genders: 0 = Male, 1 = Female, 2 = Neuter"); - return; - } - - LogInfo("Gender changed by {} for {} to {} ({})", - c->GetCleanName(), - c->GetTargetDescription(target), - GetGenderName(gender_id), - gender_id - ); - - target->SetBaseGender(gender_id); - target->Save(); - target->SendIllusionPacket(target->GetRace(), gender_id); - - c->Message( - Chat::White, - fmt::format( - "Gender changed for {} to {} ({}).", - c->GetTargetDescription(target), - GetGenderName(gender_id), - gender_id - ).c_str() - ); -} diff --git a/zone/gm_commands/permarace.cpp b/zone/gm_commands/permarace.cpp deleted file mode 100755 index 2595e1838..000000000 --- a/zone/gm_commands/permarace.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "../client.h" - -void command_permarace(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (!arguments || !sep->IsNumber(1)) { - c->Message(Chat::White, "Usage: #permarace [Race ID]"); - c->Message( - Chat::White, - "NOTE: Not all models are global. If a model is not global, it will appear as a human on character select and in zones without the model." - ); - return; - } - - Client *target = c; - if (c->GetTarget() && c->GetTarget()->IsClient()) { - target = c->GetTarget()->CastToClient(); - } - - auto race_id = Strings::ToInt(sep->arg[1]); - auto gender_id = Mob::GetDefaultGender(race_id, target->GetBaseGender()); - - LogInfo("Race changed by {} for {} to {} ({})", - c->GetCleanName(), - c->GetTargetDescription(target), - GetRaceIDName(race_id), - race_id - ); - - target->SetBaseRace(race_id); - target->SetBaseGender(gender_id); - target->Save(); - target->SendIllusionPacket(race_id, gender_id); - - c->Message( - Chat::White, - fmt::format( - "Race changed for {} to {} ({}).", - c->GetTargetDescription(target), - GetRaceIDName(race_id), - race_id - ).c_str() - ); -} diff --git a/zone/gm_commands/pvp.cpp b/zone/gm_commands/pvp.cpp deleted file mode 100755 index ed9992b10..000000000 --- a/zone/gm_commands/pvp.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "../client.h" - -void command_pvp(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (!arguments) { - c->Message(Chat::White, "Usage: #pvp [On|Off]"); - return; - } - - bool pvp_state = atobool(sep->arg[1]); - Client* target = c; - if (c->GetTarget() && c->GetTarget()->IsClient()) { - target = c->GetTarget()->CastToClient(); - } - - target->SetPVP(pvp_state); - if (c != target) { - c->Message( - Chat::White, - fmt::format( - "{} now follow{} the ways of {}.", - c->GetTargetDescription(target, TargetDescriptionType::UCYou), - c != target ? "s" : "", - pvp_state ? "Discord" : "Order" - ).c_str() - ); - } -} diff --git a/zone/gm_commands/qglobal.cpp b/zone/gm_commands/qglobal.cpp deleted file mode 100755 index e065b23ff..000000000 --- a/zone/gm_commands/qglobal.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include "../client.h" - -void command_qglobal(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (!arguments) { - c->Message(Chat::White, "Usage: #qglobal on - Enables target NPC's ability to view quest globals"); - c->Message(Chat::White, "Usage: #qglobal off - Disables target NPC's ability to view quest globals"); - c->Message(Chat::White, "Usage: #qglobal view - View target NPC's ability to view quest globals"); - return; - } - - - if (!c->GetTarget() || !c->GetTarget()->IsNPC()) { - c->Message(Chat::White, "You must target an NPC to use this command."); - return; - } - - auto target = c->GetTarget()->CastToNPC(); - - bool is_off = !strcasecmp(sep->arg[1], "off"); - bool is_on = !strcasecmp(sep->arg[1], "on"); - bool is_view = !strcasecmp(sep->arg[1], "view"); - if ( - !is_off && - !is_on && - !is_view - ) { - c->Message(Chat::White, "Usage: #qglobal on - Enables target NPC's ability to view quest globals"); - c->Message(Chat::White, "Usage: #qglobal off - Disables target NPC's ability to view quest globals"); - c->Message(Chat::White, "Usage: #qglobal view - View target NPC's ability to view quest globals"); - return; - } - - if (is_off) { - auto query = fmt::format( - "UPDATE npc_types SET qglobal = 0 WHERE id = {}", - target->GetNPCTypeID() - ); - auto results = content_db.QueryDatabase(query); - - if (!results.Success()) { - c->Message( - Chat::White, - fmt::format( - "Failed to disable quest global flag for {}.", - c->GetTargetDescription(target) - ).c_str() - ); - return; - } - - auto repop_link = Saylink::Silent("#repop", "repop"); - - c->Message( - Chat::White, - fmt::format( - "{} will no longer be able to view quest globals, {} them to apply this change.", - c->GetTargetDescription(target), - repop_link - ).c_str() - ); - return; - } else if (is_on) { - auto query = fmt::format( - "UPDATE npc_types SET qglobal = 1 WHERE id = {}", - target->GetNPCTypeID() - ); - auto results = content_db.QueryDatabase(query); - - if (!results.Success()) { - c->Message( - Chat::White, - fmt::format( - "Failed to enable quest global flag for {}.", - c->GetTargetDescription(target) - ).c_str() - ); - return; - } - - auto repop_link = Saylink::Silent("#repop", "repop"); - - c->Message( - Chat::White, - fmt::format( - "{} will now be able to view quest globals, {} them to apply this change.", - c->GetTargetDescription(target), - repop_link - ).c_str() - ); - return; - } else if (!strcasecmp(sep->arg[1], "view")) { - const NPCType *npc_type = content_db.LoadNPCTypesData(target->GetNPCTypeID()); - if (!npc_type) { - c->Message( - Chat::White, - fmt::format( - "NPC ID {} was not found.", - target->GetNPCTypeID() - ).c_str() - ); - return; - } - - c->Message( - Chat::White, - fmt::format( - "{} {} view quest globals.", - c->GetTargetDescription(target), - npc_type->qglobal ? "can" : "cannot" - ).c_str() - ); - } -} - diff --git a/zone/gm_commands/race.cpp b/zone/gm_commands/race.cpp deleted file mode 100755 index cc3b51888..000000000 --- a/zone/gm_commands/race.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "../client.h" - -void command_race(Client *c, const Seperator *sep) -{ - Mob *target = c->CastToMob(); - - if (sep->IsNumber(1)) { - auto race = Strings::ToInt(sep->arg[1]); - if ((race >= 0 && race <= RuleI(NPC, MaxRaceID)) || (race >= 2253 && race <= 2259)) { - if ((c->GetTarget()) && c->Admin() >= commandRaceOthers) { - target = c->GetTarget(); - } - target->SendIllusionPacket(race); - } - else { - c->Message( - Chat::White, - fmt::format( - "Usage: #race [0-{}, 2253-2259] (0 for back to normal)", - RuleI(NPC, MaxRaceID)).c_str()); - } - } - else { - c->Message( - Chat::White, - fmt::format("Usage: #race [0-{}, 2253-2259] (0 for back to normal)", RuleI(NPC, MaxRaceID)).c_str()); - } -} - diff --git a/zone/gm_commands/serverlock.cpp b/zone/gm_commands/serverlock.cpp deleted file mode 100644 index cd2c38ff9..000000000 --- a/zone/gm_commands/serverlock.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "../client.h" -#include "../worldserver.h" - -extern WorldServer worldserver; - -void command_serverlock(Client *c, const Seperator *sep) -{ - if (!sep->IsNumber(1)) { - c->Message(Chat::White, "Usage: #serverlock [0|1] - Lock or Unlock the World Server (0 = Unlocked, 1 = Locked)"); - return; - } - - auto is_locked = Strings::ToInt(sep->arg[1]) ? true : false; - - auto pack = new ServerPacket(ServerOP_Lock, sizeof(ServerLock_Struct)); - auto l = (ServerLock_Struct *) pack->pBuffer; - strn0cpy(l->character_name, c->GetCleanName(), sizeof(l->character_name)); - l->is_locked = is_locked; - worldserver.SendPacket(pack); - safe_delete(pack); -} - diff --git a/zone/gm_commands/set.cpp b/zone/gm_commands/set.cpp new file mode 100644 index 000000000..6a345a0d4 --- /dev/null +++ b/zone/gm_commands/set.cpp @@ -0,0 +1,174 @@ +#include "../client.h" +#include "set/aa_exp.cpp" +#include "set/aa_points.cpp" +#include "set/adventure_points.cpp" +#include "set/alternate_currency.cpp" +#include "set/animation.cpp" +#include "set/anon.cpp" +#include "set/bind_point.cpp" +#include "set/checksum.cpp" +#include "set/class_permanent.cpp" +#include "set/crystals.cpp" +#include "set/date.cpp" +#include "set/endurance.cpp" +#include "set/endurance_full.cpp" +#include "set/exp.cpp" +#include "set/flymode.cpp" +#include "set/frozen.cpp" +#include "set/gender.cpp" +#include "set/gender_permanent.cpp" +#include "set/gm.cpp" +#include "set/gm_speed.cpp" +#include "set/gm_status.cpp" +#include "set/god_mode.cpp" +#include "set/haste.cpp" +#include "set/hero_model.cpp" +#include "set/hide_me.cpp" +#include "set/hp.cpp" +#include "set/hp_full.cpp" +#include "set/invulnerable.cpp" +#include "set/language.cpp" +#include "set/last_name.cpp" +#include "set/level.cpp" +#include "set/loginserver_info.cpp" +#include "set/mana.cpp" +#include "set/mana_full.cpp" +#include "set/name.cpp" +#include "set/ooc_mute.cpp" +#include "set/password.cpp" +#include "set/pvp.cpp" +#include "set/pvp_points.cpp" +#include "set/race.cpp" +#include "set/race_permanent.cpp" +#include "set/server_locked.cpp" +#include "set/skill.cpp" +#include "set/skill_all.cpp" +#include "set/skill_all_max.cpp" +#include "set/start_zone.cpp" +#include "set/temporary_name.cpp" +#include "set/texture.cpp" +#include "set/time.cpp" +#include "set/time_zone.cpp" +#include "set/title.cpp" +#include "set/title_suffix.cpp" +#include "set/weather.cpp" +#include "set/zone.cpp" + +void command_set(Client *c, const Seperator *sep) +{ + struct Cmd { + std::string cmd{}; // command + std::string u{}; // usage + void (*fn)(Client *c, const Seperator *sep) = nullptr; // function + std::vector a{}; // aliases + }; + + std::vector commands = { + Cmd{.cmd = "aa_exp", .u = "aa_exp [aa|group|raid] [Amount]", .fn = SetAAEXP, .a = {"#setaaxp"}}, + Cmd{.cmd = "aa_points", .u = "aa_points [aa|group|raid] [Amount]", .fn = SetAAPoints, .a = {"#setaapts"}}, + Cmd{.cmd = "adventure_points", .u = "adventure_points [Theme ID] [Amount]", .fn = SetAdventurePoints, .a = {"#set_adventure_points"}}, + Cmd{.cmd = "alternate_currency", .u = "alternate_currency [Currency ID] [Amount]", .fn = SetAlternateCurrency, .a = {"#setaltcurrency"}}, + Cmd{.cmd = "animation", .u = "animation [Animation ID]", .fn = SetAnimation, .a = {"#setanim"}}, + Cmd{.cmd = "anon", .u = "anon [Character ID] [Anonymous Flag] or #set anon [Anonymous Flag]", .fn = SetAnon, .a = {"#setanon"}}, + Cmd{.cmd = "bind_point", .u = "bind_point", .fn = SetBindPoint, .a = {"#setbind"}}, + Cmd{.cmd = "checksum", .u = "checksum", .fn = SetChecksum, .a = {"#updatechecksum"}}, + Cmd{.cmd = "class_permanent", .u = "class_permanent [Class ID]", .fn = SetClassPermanent, .a = {"#permaclass"}}, + Cmd{.cmd = "crystals", .u = "crystals [ebon|radiant] [Amount]", .fn = SetCrystals, .a = {"#setcrystals"}}, + Cmd{.cmd = "date", .u = "date [Year] [Month] [Day] [Hour] [Minute] (Hour and Minute are optional)", .fn = SetDate, .a = {"#date"}}, + Cmd{.cmd = "endurance", .u = "endurance [Amount]", .fn = SetEndurance, .a = {"#setendurance"}}, + Cmd{.cmd = "endurance_full", .u = "endurance_full", .fn = SetEnduranceFull, .a = {"#endurance"}}, + Cmd{.cmd = "exp", .u = "exp [aa|exp] [Amount]", .fn = SetEXP, .a = {"#setxp"}}, + Cmd{.cmd = "flymode", .u = "flymode [Flymode ID]", .fn = SetFlymode, .a = {"#flymode"}}, + Cmd{.cmd = "frozen", .u = "frozen [on|off]", .fn = SetFrozen, .a = {"#freeze", "#unfreeze"}}, + Cmd{.cmd = "gender", .u = "gender [Gender ID]", .fn = SetGender, .a = {"#gender"}}, + Cmd{.cmd = "gender_permanent", .u = "gender_permanent [Gender ID]", .fn = SetGenderPermanent, .a = {"#permagender"}}, + Cmd{.cmd = "gm", .u = "gm [on|off]", .fn = SetGM, .a = {"#flymode"}}, + Cmd{.cmd = "gm_speed", .u = "gm_speed [on|off]", .fn = SetGMSpeed, .a = {"#gmspeed"}}, + Cmd{.cmd = "gm_status", .u = "gm_status [GM Status] [Account]", .fn = SetGMStatus, .a = {"#flag"}}, + Cmd{.cmd = "god_mode", .u = "god_mode [on|off]", .fn = SetGodMode, .a = {"#godmode"}}, + Cmd{.cmd = "haste", .u = "haste [Percentage]", .fn = SetHaste, .a = {"#haste"}}, + Cmd{.cmd = "hide_me", .u = "hide_me [on|off]", .fn = SetHideMe, .a = {"#hideme"}}, + Cmd{.cmd = "hero_model", .u = "hero_model [Hero Model] [Slot] (Slot is optional)", .fn = SetHeroModel, .a = {"#heromodel"}}, + Cmd{.cmd = "hp", .u = "hp [Amount]", .fn = SetHP, .a = {"#sethp"}}, + Cmd{.cmd = "hp_full", .u = "hp_full", .fn = SetHPFull, .a = {"#heal"}}, + Cmd{.cmd = "invulnerable", .u = "invulnerable", .fn = SetInvulnerable, .a = {"#invul"}}, + Cmd{.cmd = "language", .u = "language [Language ID] [Language Level]", .fn = SetLanguage, .a = {"#setlanguage"}}, + Cmd{.cmd = "last_name", .u = "last_name [Last Name]", .fn = SetLastName, .a = {"#lastname"}}, + Cmd{.cmd = "level", .u = "level [Level]", .fn = SetLevel, .a = {"#level"}}, + Cmd{.cmd = "loginserver_info", .u = "loginserver_info [Email] [Password]", .fn = SetLoginserverInfo, .a = {"#setlsinfo"}}, + Cmd{.cmd = "mana", .u = "mana [Amount]", .fn = SetMana, .a = {"#setmana"}}, + Cmd{.cmd = "mana_full", .u = "mana_full", .fn = SetManaFull, .a = {"#mana"}}, + Cmd{.cmd = "name", .u = "name", .fn = SetName, .a = {"#name"}}, + Cmd{.cmd = "ooc_mute", .u = "ooc_mute", .fn = SetOOCMute, .a = {"#oocmute"}}, + Cmd{.cmd = "password", .u = "password [Account Name] [Password] (account table password)", .fn = SetPassword, .a = {"#setpass"}}, + Cmd{.cmd = "pvp", .u = "pvp [on|off]", .fn = SetPVP, .a = {"#pvp"}}, + Cmd{.cmd = "pvp_points", .u = "pvp_points [Amount]", .fn = SetPVPPoints, .a = {"#setpvppoints"}}, + Cmd{.cmd = "race", .u = "race [Race ID]", .fn = SetRace, .a = {"#race"}}, + Cmd{.cmd = "race_permanent", .u = "race_permanent [Race ID]", .fn = SetRacePermanent, .a = {"#permarace"}}, + Cmd{.cmd = "server_locked", .u = "server_locked [on|off]", .fn = SetServerLocked, .a = {"#lock", "#serverlock", "#serverunlock", "#unlock"}}, + Cmd{.cmd = "skill", .u = "skill [Skill ID] [Skill Level]", .fn = SetSkill, .a = {"#setskill"}}, + Cmd{.cmd = "skill_all", .u = "skill_all [Skill Level]", .fn = SetSkillAll, .a = {"#setskillall"}}, + Cmd{.cmd = "skill_all_max", .u = "skill_all_max", .fn = SetSkillAllMax, .a = {"#maxskills"}}, + Cmd{.cmd = "start_zone", .u = "endurance [Amount]", .fn = SetStartZone, .a = {"#setstartzone"}}, + Cmd{.cmd = "temporary_name", .u = "temporary_name [Name]", .fn = SetTemporaryName, .a = {"#tempname"}}, + Cmd{.cmd = "texture", .u = "texture [Texture ID]", .fn = SetTexture, .a = {"#texture"}}, + Cmd{.cmd = "time", .u = "time [Hour] [Minute]", .fn = SetTime, .a = {"#time"}}, + Cmd{.cmd = "time_zone", .u = "time_zone [Hour] [Minute]", .fn = SetTimeZone, .a = {"#timezone"}}, + Cmd{.cmd = "title", .u = "title [Title]", .fn = SetTitle, .a = {"#title"}}, + Cmd{.cmd = "title_suffix", .u = "title_suffix [Title Suffix]", .fn = SetTitleSuffix, .a = {"#titlesuffix"}}, + Cmd{.cmd = "temporary_name", .u = "temporary_name [Name]", .fn = SetTemporaryName, .a = {"#tempname"}}, + Cmd{.cmd = "weather", .u = "weather [0|1|2|3]", .fn = SetWeather, .a = {"#weather"}}, + Cmd{.cmd = "zone", .u = "zone [option]", .fn = SetZoneData, .a = {"#zclip", "#zcolor", "#zheader", "#zonelock", "#zsafecoords", "#zsky", "#zunderworld"}}, + }; + + // Check for arguments + const auto arguments = sep->argnum; + + // look for alias or command + for (const auto &cmd: commands) { + // Check for alias first + for (const auto &alias: cmd.a) { + if (!alias.empty() && Strings::EqualFold(alias, sep->arg[0])) { + // build string from sep args + std::vector args = {}; + + // skip the first arg + for (auto i = 1; i <= arguments; i++) { + args.emplace_back(sep->arg[i]); + } + + // build the rewrite string + const std::string& rewrite = fmt::format("#set {} {}", cmd.cmd, Strings::Join(args, " ")); + + // rewrite to #set > + c->SetEntityVariable("old_command", Strings::Replace(alias, "#", "")); + c->SendGMCommand(rewrite); + c->DeleteEntityVariable("old_command"); + + c->Message( + Chat::Gray, + fmt::format( + "{} is now located under {}, using {}.", + sep->arg[0], + Saylink::Silent("#set"), + Saylink::Silent(rewrite) + ).c_str() + ); + + return; + } + } + + // Check for command + if (cmd.cmd == Strings::ToLower(sep->arg[1])) { + cmd.fn(c, sep); + return; + } + } + + // Command not found + c->Message(Chat::White, "Command not found. Usage: #set [command]"); + for (const auto &cmd: commands) { + c->Message(Chat::White, fmt::format("Usage: #set {}", cmd.u).c_str()); + } +} diff --git a/zone/gm_commands/set/aa_exp.cpp b/zone/gm_commands/set/aa_exp.cpp new file mode 100755 index 000000000..9ca995357 --- /dev/null +++ b/zone/gm_commands/set/aa_exp.cpp @@ -0,0 +1,69 @@ +#include "../../client.h" +#include "../../groups.h" +#include "../../raids.h" +#include "../../raids.h" + +void SetAAEXP(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 3 || !sep->IsNumber(3)) { + c->Message(Chat::White, "Usage: #set aa_exp [aa|group|raid] [Amount]"); + return; + } + + auto t = c; + if (c->GetTarget() && c->GetTarget()->IsClient()) { + t = c->GetTarget()->CastToClient(); + } + + const std::string& aa_type = Strings::ToLower(sep->arg[2]); + const uint32 aa_experience = Strings::ToUnsignedInt(sep->arg[3]); + + std::string group_raid_string; + + const bool is_aa = Strings::EqualFold(aa_type, "aa"); + const bool is_group = Strings::EqualFold(aa_type, "group"); + const bool is_raid = Strings::EqualFold(aa_type, "raid"); + + if ( + !is_aa && + !is_group && + !is_raid + ) { + c->Message(Chat::White, "Usage: #set aa_exp [aa|group|raid] [Amount]"); + return; + } + + if (is_aa) { + t->SetEXP( + t->GetEXP(), + aa_experience, + false + ); + } else if (is_group) { + group_raid_string = "Group "; + + t->SetLeadershipEXP( + aa_experience, + t->GetRaidEXP() + ); + } else if (is_raid) { + group_raid_string = "Raid "; + + t->SetLeadershipEXP( + t->GetGroupEXP(), + aa_experience + ); + } + + c->Message( + Chat::White, + fmt::format( + "{} now {} {} {}AA Experience.", + c->GetTargetDescription(t, TargetDescriptionType::UCYou), + c == t ? "have" : "has", + Strings::Commify(aa_experience), + group_raid_string + ).c_str() + ); +} diff --git a/zone/gm_commands/set/aa_points.cpp b/zone/gm_commands/set/aa_points.cpp new file mode 100755 index 000000000..ab1bb8bfd --- /dev/null +++ b/zone/gm_commands/set/aa_points.cpp @@ -0,0 +1,66 @@ +#include "../../client.h" +#include "../../groups.h" +#include "../../raids.h" +#include "../../raids.h" + +void SetAAPoints(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 3 || !sep->IsNumber(3)) { + c->Message(Chat::White, "Usage: #set aa_points [aa|group|raid] [Amount]"); + return; + } + + auto t = c; + if (c->GetTarget() && c->GetTarget()->IsClient()) { + t = c->GetTarget()->CastToClient(); + } + + const std::string& aa_type = Strings::ToLower(sep->arg[2]); + const uint32 aa_points = Strings::ToUnsignedInt(sep->arg[3]); + + std::string group_raid_string; + + const bool is_aa = Strings::EqualFold(aa_type, "aa"); + const bool is_group = Strings::EqualFold(aa_type, "group"); + const bool is_raid = Strings::EqualFold(aa_type, "raid"); + + if ( + !is_aa && + !is_group && + !is_raid + ) { + c->Message(Chat::White, "Usage: #set aa_points [aa|group|raid] [Amount]"); + return; + } + + if (is_aa) { + t->GetPP().aapoints = aa_points; + t->GetPP().expAA = 0; + t->SendAlternateAdvancementStats(); + } else if (is_group || is_raid) { + if (is_group) { + group_raid_string = "Group "; + t->GetPP().group_leadership_points = aa_points; + t->GetPP().group_leadership_exp = 0; + } else if (is_raid) { + group_raid_string = "Raid "; + t->GetPP().raid_leadership_points = aa_points; + t->GetPP().raid_leadership_exp = 0; + } + + t->SendLeadershipEXPUpdate(); + } + + c->Message( + Chat::White, + fmt::format( + "{} now {} {} {}AA Point{}.", + c->GetTargetDescription(t, TargetDescriptionType::UCYou), + c == t ? "have" : "has", + Strings::Commify(aa_points), + group_raid_string, + aa_points != 1 ? "s" : "" + ).c_str() + ); +} diff --git a/zone/gm_commands/set/adventure_points.cpp b/zone/gm_commands/set/adventure_points.cpp new file mode 100755 index 000000000..3b49d06ec --- /dev/null +++ b/zone/gm_commands/set/adventure_points.cpp @@ -0,0 +1,66 @@ +#include "../../client.h" +#include "../../../common/data_verification.h" + +void SetAdventurePoints(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 3 || !sep->IsNumber(2) || !sep->IsNumber(3)) { + c->Message(Chat::White, "Usage: #set adventure_points [Theme] [Points]"); + + c->Message(Chat::White, "Valid themes are as follows:"); + + for (const auto& e : EQ::constants::GetLDoNThemeMap()) { + if (e.first != LDoNThemes::Unused) { + c->Message( + Chat::White, + fmt::format( + "Theme {} | {}", + e.first, + e.second + ).c_str() + ); + } + } + + return; + } + + auto t = c; + if (c->GetTarget() && c->GetTarget()->IsClient()) { + t = c->GetTarget()->CastToClient(); + } + + const uint32 theme_id = Strings::ToUnsignedInt(sep->arg[2]); + const uint32 points = Strings::ToUnsignedInt(sep->arg[3]); + + if (!EQ::ValueWithin(theme_id, LDoNThemes::GUK, LDoNThemes::TAK)) { + c->Message(Chat::White, "Valid themes are as follows:"); + + for (const auto& e : EQ::constants::GetLDoNThemeMap()) { + if (e.first != LDoNThemes::Unused) { + c->Message( + Chat::White, + fmt::format( + "Theme {} | {}", + e.first, + e.second + ).c_str() + ); + } + } + + return; + } + + c->Message( + Chat::White, + fmt::format( + "Set {} Points to {} for {}.", + EQ::constants::GetLDoNThemeName(theme_id), + Strings::Commify(points), + c->GetTargetDescription(t) + ).c_str() + ); + + t->SetLDoNPoints(theme_id, points); +} diff --git a/zone/gm_commands/set/alternate_currency.cpp b/zone/gm_commands/set/alternate_currency.cpp new file mode 100644 index 000000000..3718076fe --- /dev/null +++ b/zone/gm_commands/set/alternate_currency.cpp @@ -0,0 +1,43 @@ +#include "../../client.h" + +void SetAlternateCurrency(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 3 || !sep->IsNumber(2) || !sep->IsNumber(3)) { + c->Message(Chat::White, "Usage: #set alternate_currency [Currency ID] [Amount]"); + return; + } + + auto t = c; + if (c->GetTarget() && c->GetTarget()->IsClient()) { + t = c->GetTarget()->CastToClient(); + } + + const uint32 currency_id = Strings::ToUnsignedInt(sep->arg[2]); + const uint32 currency_item_id = zone->GetCurrencyItemID(currency_id); + const uint32 currency_amount = Strings::ToUnsignedInt(sep->arg[3]); + + if (!currency_item_id) { + c->Message( + Chat::White, + fmt::format( + "Currency ID {} could not be found.", + currency_id + ).c_str() + ); + return; + } + + t->SetAlternateCurrencyValue(currency_id, currency_amount); + + c->Message( + Chat::White, + fmt::format( + "{} now {} {} {}.", + c->GetTargetDescription(t, TargetDescriptionType::UCYou), + c == t ? "have" : "has", + Strings::Commify(currency_amount), + database.CreateItemLink(currency_item_id) + ).c_str() + ); +} diff --git a/zone/gm_commands/set/animation.cpp b/zone/gm_commands/set/animation.cpp new file mode 100755 index 000000000..416235067 --- /dev/null +++ b/zone/gm_commands/set/animation.cpp @@ -0,0 +1,63 @@ +#include "../../client.h" + +void SetAnimation(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2 || !sep->IsNumber(2)) { + c->Message(Chat::White, "Usage: #set animation [Animation ID]"); + + for (const auto& a : EQ::constants::GetSpawnAnimationMap()) { + c->Message( + Chat::White, + fmt::format( + "Animation {} | {}", + a.first, + a.second + ).c_str() + ); + } + + return; + } + + Mob* t = c; + if (c->GetTarget()) { + t = c->GetTarget(); + } + + const auto animation_id = static_cast(Strings::ToUnsignedInt(sep->arg[2])); + if ( + !EQ::ValueWithin( + animation_id, + static_cast(eaStanding), + static_cast(eaLooting) + ) + ) { + c->Message(Chat::White, "Usage: #set animation [Animation ID]"); + + for (const auto& a : EQ::constants::GetSpawnAnimationMap()) { + c->Message( + Chat::White, + fmt::format( + "Animation {} | {}", + a.first, + a.second + ).c_str() + ); + } + + return; + } + + t->SetAppearance(static_cast(animation_id), false); + + c->Message( + Chat::White, + fmt::format( + "Set animation to {} ({}) for {}.", + EQ::constants::GetSpawnAnimationName(animation_id), + animation_id, + c->GetTargetDescription(t) + ).c_str() + ); +} diff --git a/zone/gm_commands/setanon.cpp b/zone/gm_commands/set/anon.cpp similarity index 70% rename from zone/gm_commands/setanon.cpp rename to zone/gm_commands/set/anon.cpp index 2b50c3def..e0b84f7fb 100755 --- a/zone/gm_commands/setanon.cpp +++ b/zone/gm_commands/set/anon.cpp @@ -1,18 +1,19 @@ -#include "../client.h" -#include "../../common/repositories/character_data_repository.h" +#include "../../client.h" +#include "../../../common/repositories/character_data_repository.h" -void command_setanon(Client *c, const Seperator *sep) +void SetAnon(Client *c, const Seperator *sep) { - auto arguments = sep->argnum; - if (!arguments || !sep->IsNumber(1) || arguments > 2) { - c->Message(Chat::White, "Usage: #setanon [Anonymous Flag]"); - c->Message(Chat::White, "Usage: #setanon [Character ID] [Anonymous Flag]"); + const auto arguments = sep->argnum; + if (arguments < 2 || !sep->IsNumber(2)) { + c->Message(Chat::White, "Usage: #set anon [Anonymous Flag]"); + c->Message(Chat::White, "Usage: #set anon [Character ID] [Anonymous Flag]"); c->Message(Chat::White, "Note: 0 = Not Anonymous, 1 = Anonymous, 2 = Roleplaying"); return; } - if (arguments == 1) { - const uint8 anon_flag = static_cast(Strings::ToUnsignedInt(sep->arg[1])); + if (arguments == 2) { + const uint8 anon_flag = static_cast(Strings::ToUnsignedInt(sep->arg[2])); + auto t = c; if (c->GetTarget() && c->GetTarget()->IsClient() && c->GetGM()) { t = c->GetTarget()->CastToClient(); @@ -26,8 +27,8 @@ void command_setanon(Client *c, const Seperator *sep) } else if (anon_flag == Anonymity::Roleplaying) { anon_setting = "now Roleplaying"; } else { - c->Message(Chat::White, "Usage: #setanon [Anonymous Flag]"); - c->Message(Chat::White, "Usage: #setanon [Character ID] [Anonymous Flag]"); + c->Message(Chat::White, "Usage: #set anon [Anonymous Flag]"); + c->Message(Chat::White, "Usage: #set anon [Character ID] [Anonymous Flag]"); c->Message(Chat::White, "Note: 0 = Not Anonymous, 1 = Anonymous, 2 = Roleplaying"); return; } @@ -43,9 +44,9 @@ void command_setanon(Client *c, const Seperator *sep) anon_setting ).c_str() ); - } else if (arguments == 2) { - const auto character_id = Strings::ToInt(sep->arg[1]); - const uint8 anon_flag = static_cast(Strings::ToUnsignedInt(sep->arg[2])); + } else if (arguments == 3) { + const int character_id = Strings::ToInt(sep->arg[2]); + const uint8 anon_flag = static_cast(Strings::ToUnsignedInt(sep->arg[3])); auto e = CharacterDataRepository::FindOne(content_db, character_id); if (!e.id) { @@ -56,6 +57,7 @@ void command_setanon(Client *c, const Seperator *sep) character_id ).c_str() ); + return; } @@ -72,6 +74,7 @@ void command_setanon(Client *c, const Seperator *sep) character_id ).c_str() ); + return; } @@ -83,8 +86,8 @@ void command_setanon(Client *c, const Seperator *sep) } else if (anon_flag == Anonymity::Roleplaying) { anon_setting = "now Roleplaying"; } else { - c->Message(Chat::White, "Usage: #setanon [Anonymous Flag]"); - c->Message(Chat::White, "Usage: #setanon [Character ID] [Anonymous Flag]"); + c->Message(Chat::White, "Usage: #set anon [Anonymous Flag]"); + c->Message(Chat::White, "Usage: #set anon [Character ID] [Anonymous Flag]"); c->Message(Chat::White, "Note: 0 = Not Anonymous, 1 = Anonymous, 2 = Roleplaying"); return; } diff --git a/zone/gm_commands/set/bind_point.cpp b/zone/gm_commands/set/bind_point.cpp new file mode 100755 index 000000000..8d5bbb626 --- /dev/null +++ b/zone/gm_commands/set/bind_point.cpp @@ -0,0 +1,45 @@ +#include "../../client.h" + +void SetBindPoint(Client *c, const Seperator *sep) +{ + auto t = c; + if (c->GetTarget() && c->GetTarget()->IsClient()) { + t = c->GetTarget()->CastToClient(); + } + + const bool bind_allowed = ( + !zone->GetInstanceID() || + ( + zone->GetInstanceID() && + zone->IsInstancePersistent() + ) + ); + + if (!bind_allowed) { + c->Message(Chat::White, "You cannot bind here."); + return; + } + + t->SetBindPoint(); + + c->Message( + Chat::White, + fmt::format( + "Set Bind Point for {} | Zone: {}", + c->GetTargetDescription(t, TargetDescriptionType::UCSelf), + zone->GetZoneDescription() + ).c_str() + ); + + c->Message( + Chat::White, + fmt::format( + "Set Bind Point for {} | XYZH: {:.2f}, {:.2f}, {:.2f}, {:.2f}", + c->GetTargetDescription(t, TargetDescriptionType::UCSelf), + t->GetX(), + t->GetY(), + t->GetZ(), + t->GetHeading() + ).c_str() + ); +} diff --git a/zone/gm_commands/updatechecksum.cpp b/zone/gm_commands/set/checksum.cpp similarity index 81% rename from zone/gm_commands/updatechecksum.cpp rename to zone/gm_commands/set/checksum.cpp index f84fafb28..76df72d29 100755 --- a/zone/gm_commands/updatechecksum.cpp +++ b/zone/gm_commands/set/checksum.cpp @@ -1,10 +1,10 @@ -#include "../client.h" -#include "../worldserver.h" -#include "../../common/repositories/account_repository.h" +#include "../../client.h" +#include "../../worldserver.h" +#include "../../../common/repositories/account_repository.h" extern WorldServer worldserver; -void command_updatechecksum(Client *c, const Seperator *sep) +void SetChecksum(Client *c, const Seperator *sep) { auto account = AccountRepository::FindOne(database, c->AccountID()); if (!account.id) { diff --git a/zone/gm_commands/set/class_permanent.cpp b/zone/gm_commands/set/class_permanent.cpp new file mode 100755 index 000000000..abce4979f --- /dev/null +++ b/zone/gm_commands/set/class_permanent.cpp @@ -0,0 +1,40 @@ +#include "../../client.h" + +void SetClassPermanent(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2 || !sep->IsNumber(2)) { + c->Message(Chat::White, "Usage: #set class_permanent [Class ID]"); + return; + } + + auto t = c; + if (c->GetTarget() && c->GetTarget()->IsClient()) { + t = c->GetTarget()->CastToClient(); + } + + const uint32 class_id = Strings::ToUnsignedInt(sep->arg[2]); + + LogInfo("Class changed by {} for {} to {} ({}).", + c->GetCleanName(), + c->GetTargetDescription(t), + GetClassIDName(class_id), + class_id + ); + + t->SetBaseClass(class_id); + t->Save(); + t->Kick("Class was changed."); + + if (c != t) { + c->Message( + Chat::White, + fmt::format( + "Class changed for {} to {} ({}).", + c->GetTargetDescription(t), + GetClassIDName(class_id), + class_id + ).c_str() + ); + } +} diff --git a/zone/gm_commands/set/crystals.cpp b/zone/gm_commands/set/crystals.cpp new file mode 100755 index 000000000..84bfc3525 --- /dev/null +++ b/zone/gm_commands/set/crystals.cpp @@ -0,0 +1,48 @@ +#include "../../client.h" + +void SetCrystals(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2 || !sep->IsNumber(3)) { + c->Message(Chat::White, "Usage: #setcrystals [ebon|radiant] [Amount]"); + return; + } + + auto t = c; + if (c->GetTarget() && c->GetTarget()->IsClient()) { + t = c->GetTarget()->CastToClient(); + } + + const std::string& crystal_type = Strings::ToLower(sep->arg[2]); + const uint32 crystal_amount = Strings::ToUnsignedInt(sep->arg[3]); + + const bool is_ebon = Strings::EqualFold(crystal_type, "ebon"); + const bool is_radiant = Strings::EqualFold(crystal_type, "radiant"); + if (!is_ebon && !is_radiant) { + c->Message(Chat::White, "Usage: #setcrystals [ebon|radiant] [Amount]"); + return; + } + + const uint32 crystal_item_id = ( + is_ebon ? + RuleI(Zone, EbonCrystalItemID) : + RuleI(Zone, RadiantCrystalItemID) + ); + + if (is_radiant) { + t->SetRadiantCrystals(crystal_amount); + } else { + t->SetEbonCrystals(crystal_amount); + } + + c->Message( + Chat::White, + fmt::format( + "{} now {} {} {}.", + c->GetTargetDescription(t, TargetDescriptionType::UCYou), + c == t ? "have" : "has", + Strings::Commify(crystal_amount), + database.CreateItemLink(crystal_item_id) + ).c_str() + ); +} diff --git a/zone/gm_commands/set/date.cpp b/zone/gm_commands/set/date.cpp new file mode 100755 index 000000000..cac21e061 --- /dev/null +++ b/zone/gm_commands/set/date.cpp @@ -0,0 +1,46 @@ +#include "../../client.h" + +void SetDate(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if ( + arguments < 2 || + !sep->IsNumber(2) || + !sep->IsNumber(3) || + !sep->IsNumber(4) + ) { + c->Message(Chat::White, "Usage: #date [Year] [Month] [Day] [Hour] [Minute]"); + c->Message(Chat::White, "Hour and Minute are optional"); + return; + } + + TimeOfDay_Struct eq_time; + zone->zone_time.GetCurrentEQTimeOfDay(time(0), &eq_time); + + const uint16 year = Strings::ToUnsignedInt(sep->arg[2]); + const uint8 month = Strings::ToUnsignedInt(sep->arg[3]); + const uint8 day = Strings::ToUnsignedInt(sep->arg[4]); + const uint8 hour = !sep->IsNumber(5) ? eq_time.hour : Strings::ToUnsignedInt(sep->arg[5]) + 1; + const uint8 minute = !sep->IsNumber(6) ? eq_time.minute : Strings::ToUnsignedInt(sep->arg[6]); + + c->Message( + Chat::White, + fmt::format("Setting world time to {}/{}/{} {}.", + year, + month, + day, + Strings::ZoneTime(hour, minute) + ).c_str() + ); + + zone->SetDate(year, month, day, hour, minute); + + LogInfo( + "{} :: Setting world time to {}/{}/{} {}.", + c->GetCleanName(), + year, + month, + day, + Strings::ZoneTime(hour, minute) + ); +} diff --git a/zone/gm_commands/set/endurance.cpp b/zone/gm_commands/set/endurance.cpp new file mode 100644 index 000000000..f4a8c375b --- /dev/null +++ b/zone/gm_commands/set/endurance.cpp @@ -0,0 +1,40 @@ +#include "../../client.h" + +void SetEndurance(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2 || !sep->IsNumber(2)) { + c->Message(Chat::White, "Usage: #set endurance [Endurance]"); + return; + } + + int endurance = Strings::ToInt(sep->arg[2]); + + Mob* t = c; + if (c->GetTarget()) { + t = c->GetTarget(); + } + + if (t->IsClient()) { + if (endurance >= t->CastToClient()->GetMaxEndurance()) { + endurance = t->CastToClient()->GetMaxEndurance(); + } + + t->CastToClient()->SetEndurance(endurance); + } else { + if (endurance >= t->GetMaxEndurance()) { + endurance = t->GetMaxEndurance(); + } + + t->SetEndurance(endurance); + } + + c->Message( + Chat::White, + fmt::format( + "Set {} to {} Endurance.", + c->GetTargetDescription(t), + Strings::Commify(endurance) + ).c_str() + ); +} diff --git a/zone/gm_commands/set/endurance_full.cpp b/zone/gm_commands/set/endurance_full.cpp new file mode 100755 index 000000000..8b493e41e --- /dev/null +++ b/zone/gm_commands/set/endurance_full.cpp @@ -0,0 +1,29 @@ +#include "../../client.h" + +void SetEnduranceFull(Client *c, const Seperator *sep) +{ + Mob* t = c; + if (c->GetTarget()) { + t = c->GetTarget(); + } + + int endurance; + + if (t->IsClient()) { + endurance = t->CastToClient()->GetMaxEndurance(); + t->CastToClient()->SetEndurance(endurance); + } else { + endurance = t->GetMaxEndurance(); + t->SetEndurance(endurance); + } + + c->Message( + Chat::White, + fmt::format( + "Set {} to full Endurance ({}).", + c->GetTargetDescription(t), + Strings::Commify(endurance) + ).c_str() + ); +} + diff --git a/zone/gm_commands/set/exp.cpp b/zone/gm_commands/set/exp.cpp new file mode 100755 index 000000000..20274d878 --- /dev/null +++ b/zone/gm_commands/set/exp.cpp @@ -0,0 +1,49 @@ +#include "../../client.h" + +void SetEXP(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 3 || !sep->IsNumber(3)) { + c->Message(Chat::White, "Usage: #set exp [aa|exp] [Amount]"); + return; + } + + auto t = c; + if (c->GetTarget() && c->GetTarget()->IsClient()) { + t = c->GetTarget()->CastToClient(); + } + + const std::string& type = Strings::ToLower(sep->arg[2]); + + const bool is_aa = Strings::EqualFold(type, "aa"); + const bool is_exp = Strings::EqualFold(type, "exp"); + if (!is_aa && !is_exp) { + c->Message(Chat::White, "Usage: #set exp [aa|exp] [Amount]"); + return; + } + + const uint32 amount = Strings::ToUnsignedInt(sep->arg[3]); + + if (is_aa) { + t->SetEXP( + t->GetEXP(), + amount + ); + } else if (is_exp) { + t->SetEXP( + amount, + t->GetAAXP() + ); + } + + c->Message( + Chat::White, + fmt::format( + "{} now {} {} {}experience.", + c->GetTargetDescription(t, TargetDescriptionType::UCYou), + c == t ? "have" : "has", + Strings::Commify(amount), + is_aa ? "AA " : "" + ).c_str() + ); +} diff --git a/zone/gm_commands/set/flymode.cpp b/zone/gm_commands/set/flymode.cpp new file mode 100755 index 000000000..864c4a938 --- /dev/null +++ b/zone/gm_commands/set/flymode.cpp @@ -0,0 +1,69 @@ +#include "../../client.h" +#include "../../../common/data_verification.h" + +void SetFlymode(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2 || !sep->IsNumber(2)) { + c->Message(Chat::White, "Usage: #set flymode [Flymode ID]"); + + for (const auto& e : EQ::constants::GetFlyModeMap()) { + c->Message( + Chat::White, + fmt::format( + "Flymode {} | {}", + e.first, + e.second + ).c_str() + ); + } + + return; + } + + Mob* t = c; + if (c->GetTarget()) { + t = c->GetTarget(); + } + + const int8 flymode_id = Strings::ToInt(sep->arg[2]); + if ( + !EQ::ValueWithin( + flymode_id, + EQ::constants::GravityBehavior::Ground, + EQ::constants::GravityBehavior::LevitateWhileRunning + ) + ) { + c->Message(Chat::White, "Usage: #set flymode [Flymode ID]"); + + for (const auto& e : EQ::constants::GetFlyModeMap()) { + c->Message( + Chat::White, + fmt::format( + "Flymode {} | {}", + e.first, + e.second + ).c_str() + ); + } + + return; + } + + t->SetFlyMode(static_cast(flymode_id)); + t->SendAppearancePacket(AT_Levitate, flymode_id); + + const uint32 account = c->AccountID(); + + database.SetGMFlymode(account, flymode_id); + + c->Message( + Chat::White, + fmt::format( + "Fly Mode for {} is now {} ({}).", + c->GetTargetDescription(t), + EQ::constants::GetFlyModeName(flymode_id), + flymode_id + ).c_str() + ); +} diff --git a/zone/gm_commands/set/frozen.cpp b/zone/gm_commands/set/frozen.cpp new file mode 100755 index 000000000..b46de5cce --- /dev/null +++ b/zone/gm_commands/set/frozen.cpp @@ -0,0 +1,34 @@ +#include "../../client.h" + +void SetFrozen(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2) { + c->Message(Chat::White, "Usage: #set frozen [on|off]"); + return; + } + + if (!c->GetTarget()) { + c->Message(Chat::White, "You must have a target to use this command."); + return; + } + + const bool is_frozen = Strings::ToBool(sep->arg[2]); + + auto t = c->GetTarget(); + if (c == t) { + c->Message(Chat::White, "You cannot use this command on yourself."); + return; + } + + t->SendAppearancePacket(AT_Anim, is_frozen ? ANIM_FREEZE : ANIM_STAND); + + c->Message( + Chat::White, + fmt::format( + "You have {}frozen {}.", + !is_frozen ? "un" : "", + c->GetTargetDescription(t) + ).c_str() + ); +} diff --git a/zone/gm_commands/set/gender.cpp b/zone/gm_commands/set/gender.cpp new file mode 100755 index 000000000..5ad6fdf9f --- /dev/null +++ b/zone/gm_commands/set/gender.cpp @@ -0,0 +1,38 @@ +#include "../../client.h" + +void SetGender(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2 || !sep->IsNumber(2)) { + c->Message(Chat::White, "Usage: #set gender [Gender ID]"); + c->Message(Chat::White, "Genders: 0 = Male, 1 = Female, 2 = Neuter"); + return; + } + + Mob *t = c; + if (c->GetTarget()) { + t = c->GetTarget(); + } + + const uint8 gender_id = Strings::ToUnsignedInt(sep->arg[2]); + if (!EQ::ValueWithin(gender_id, MALE, NEUTER)) { + c->Message(Chat::White, "Usage: #set gender [Gender ID]"); + c->Message(Chat::White, "Genders: 0 = Male, 1 = Female, 2 = Neuter"); + return; + } + + t->SendIllusionPacket( + t->GetRace(), + gender_id + ); + + c->Message( + Chat::White, + fmt::format( + "Gender changed for {} to {} ({}).", + c->GetTargetDescription(t), + GetGenderName(gender_id), + gender_id + ).c_str() + ); +} diff --git a/zone/gm_commands/set/gender_permanent.cpp b/zone/gm_commands/set/gender_permanent.cpp new file mode 100755 index 000000000..6d05e0690 --- /dev/null +++ b/zone/gm_commands/set/gender_permanent.cpp @@ -0,0 +1,44 @@ +#include "../../client.h" + +void SetGenderPermanent(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2 || !sep->IsNumber(2)) { + c->Message(Chat::White, "Usage: #set gender_permanent [Gender ID]"); + c->Message(Chat::White, "Genders: 0 = Male, 1 = Female, 2 = Neuter"); + return; + } + + auto t = c; + if (c->GetTarget() && c->GetTarget()->IsClient()) { + t = c->GetTarget()->CastToClient(); + } + + const uint8 gender_id = Strings::ToInt(sep->arg[2]); + if (!EQ::ValueWithin(gender_id, MALE, NEUTER)) { + c->Message(Chat::White, "Usage: #set gender_permanent [Gender ID]"); + c->Message(Chat::White, "Genders: 0 = Male, 1 = Female, 2 = Neuter"); + return; + } + + LogInfo("Gender changed by {} for {} to {} ({})", + c->GetCleanName(), + c->GetTargetDescription(t), + GetGenderName(gender_id), + gender_id + ); + + t->SetBaseGender(gender_id); + t->Save(); + t->SendIllusionPacket(t->GetRace(), gender_id); + + c->Message( + Chat::White, + fmt::format( + "Gender changed for {} to {} ({}).", + c->GetTargetDescription(t), + GetGenderName(gender_id), + gender_id + ).c_str() + ); +} diff --git a/zone/gm_commands/set/gm.cpp b/zone/gm_commands/set/gm.cpp new file mode 100755 index 000000000..19aca7826 --- /dev/null +++ b/zone/gm_commands/set/gm.cpp @@ -0,0 +1,30 @@ +#include "../../client.h" + +void SetGM(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2) { + c->Message(Chat::White, "Usage: #set gm [on|off]"); + return; + } + + auto t = c; + if (c->GetTarget() && c->GetTarget()->IsClient()) { + t = c->GetTarget()->CastToClient(); + } + + const bool gm_flag = Strings::ToBool(sep->arg[2]); + + t->SetGM(gm_flag); + + if (c != t) { + c->Message( + Chat::White, + fmt::format( + "{} is {} flagged as a GM.", + c->GetTargetDescription(t), + gm_flag ? "now" : "no longer" + ).c_str() + ); + } +} diff --git a/zone/gm_commands/set/gm_speed.cpp b/zone/gm_commands/set/gm_speed.cpp new file mode 100755 index 000000000..ffcef33b3 --- /dev/null +++ b/zone/gm_commands/set/gm_speed.cpp @@ -0,0 +1,39 @@ +#include "../../client.h" + +void SetGMSpeed(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2) { + c->Message(Chat::White, "Usage: #set gmspeed [on|off]"); + return; + } + + auto t = c; + if (c->GetTarget() && c->GetTarget()->IsClient()) { + t = c->GetTarget()->CastToClient(); + } + + const bool gm_speed = Strings::ToBool(sep->arg[2]); + + database.SetGMSpeed( + t->AccountID(), + gm_speed ? 1 : 0 + ); + + c->Message( + Chat::White, + fmt::format( + "Turning GM Speed {} for {}.", + gm_speed ? "on" : "off", + c->GetTargetDescription(t) + ).c_str() + ); + + c->Message( + Chat::White, + fmt::format( + "Note: {} must zone for it to take effect.", + c->GetTargetDescription(t, TargetDescriptionType::UCYou) + ).c_str() + ); +} diff --git a/zone/gm_commands/set/gm_status.cpp b/zone/gm_commands/set/gm_status.cpp new file mode 100644 index 000000000..aae8dcff3 --- /dev/null +++ b/zone/gm_commands/set/gm_status.cpp @@ -0,0 +1,97 @@ +#include "../../client.h" +#include "../../worldserver.h" + +extern WorldServer worldserver; + +void SetGMStatus(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2) { + auto t = c; + if (c->GetTarget() && c->GetTarget()->IsClient()) { + t = c->GetTarget()->CastToClient(); + } + + c->Message( + Chat::White, + fmt::format( + "Status level has been refreshed for {}.", + c->GetTargetDescription(t) + ).c_str() + ); + + if (t != c) { + t->Message( + Chat::White, + fmt::format( + "Your status level has been refreshed by {}.", + c->GetCleanName() + ).c_str() + ); + } + + t->UpdateAdmin(); + return; + } + + + if ( + !sep->IsNumber(2) || + !strlen(sep->arg[3]) + ) { + c->Message(Chat::White, "Usage: #set gm_status [Status] [Account Name]"); + return; + } + + const int gm_status = Strings::ToInt(sep->arg[2]); + if (!EQ::ValueWithin(gm_status, -2, UINT8_MAX)) { + c->Message(Chat::White, "The lowest a status level can go is -2 and the highest a status level can go is 255."); + return; + } + + const std::string& account_name = sep->argplus[3]; + + if (gm_status > c->Admin()) { + c->Message( + Chat::White, + fmt::format( + "You cannot set someone's status level to {} because your status level is only {}.", + gm_status, + c->Admin() + ).c_str() + ); + } else if (!database.SetAccountStatus(account_name, gm_status)) { + c->Message( + Chat::White, + fmt::format( + "Failed to set status level to {} for account {}.", + gm_status, + account_name + ).c_str() + ); + } else { + c->Message( + Chat::White, + fmt::format( + "Set GM status to {} on account {}.", + gm_status, + account_name + ).c_str() + ); + + std::string user; + std::string loginserver; + ParseAccountString(account_name, user, loginserver); + + const uint32 account_id = database.GetAccountIDByName(account_name, loginserver); + + ServerPacket pack(ServerOP_FlagUpdate, sizeof(ServerFlagUpdate_Struct)); + + auto s = (ServerFlagUpdate_Struct *) pack.pBuffer; + s->account_id = account_id; + s->admin = gm_status; + + worldserver.SendPacket(&pack); + } +} + diff --git a/zone/gm_commands/set/god_mode.cpp b/zone/gm_commands/set/god_mode.cpp new file mode 100644 index 000000000..1075d0091 --- /dev/null +++ b/zone/gm_commands/set/god_mode.cpp @@ -0,0 +1,42 @@ +#include "../../client.h" +#include "../../../common/repositories/account_repository.h" + +void SetGodMode(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2) { + c->Message(Chat::White, "Usage: #set god_mode [on|off]"); + return; + } + + auto t = c; + if (c->GetTarget() && c->GetTarget()->IsClient()) { + t = c->GetTarget()->CastToClient(); + } + + const bool god_mode = Strings::ToBool(sep->arg[2]); + const uint32 account_id = c->AccountID(); + + auto a = AccountRepository::FindOne(database, c->AccountID()); + if (a.id) { + a.flymode = god_mode ? 1 : 0; + a.gmspeed = god_mode ? 1 : 0; + a.invulnerable = god_mode ? 1 : 0; + a.hideme = god_mode ? 1 : 0; + } + + c->SetInvul(god_mode); + c->SendAppearancePacket(AT_Levitate, god_mode); + c->SetHideMe(god_mode); + + c->Message( + Chat::White, + fmt::format( + "Turning God Mode {} for {}, zone for GM Speed to take effect.", + god_mode ? "on" : "off", + c->GetTargetDescription(t) + ).c_str() + ); + + AccountRepository::UpdateOne(database, a); +} diff --git a/zone/gm_commands/haste.cpp b/zone/gm_commands/set/haste.cpp old mode 100755 new mode 100644 similarity index 59% rename from zone/gm_commands/haste.cpp rename to zone/gm_commands/set/haste.cpp index d5e19f569..ea4712745 --- a/zone/gm_commands/haste.cpp +++ b/zone/gm_commands/set/haste.cpp @@ -1,10 +1,10 @@ -#include "../client.h" +#include "../../client.h" -void command_haste(Client *c, const Seperator *sep) +void SetHaste(Client *c, const Seperator *sep) { const auto arguments = sep->argnum; - if (!arguments || !sep->IsNumber(1)) { - c->Message(Chat::White, "Usage: #haste [Percentage] - Set GM Bonus Haste (100 is 100% more Attack Speed)"); + if (arguments < 2 || !sep->IsNumber(2)) { + c->Message(Chat::White, "Usage: #set haste [Percentage] - Set GM Bonus Haste (100 is 100% more Attack Speed)"); return; } @@ -13,7 +13,7 @@ void command_haste(Client *c, const Seperator *sep) t = c->GetTarget()->CastToClient(); } - const auto extra_haste = Strings::ToInt(sep->arg[1]); + const int extra_haste = Strings::ToInt(sep->arg[2]); t->SetExtraHaste(extra_haste); t->CalcBonuses(); @@ -28,4 +28,3 @@ void command_haste(Client *c, const Seperator *sep) ).c_str() ); } - diff --git a/zone/gm_commands/set/hero_model.cpp b/zone/gm_commands/set/hero_model.cpp new file mode 100755 index 000000000..f98b5d5e2 --- /dev/null +++ b/zone/gm_commands/set/hero_model.cpp @@ -0,0 +1,44 @@ +#include "../../client.h" + +void SetHeroModel(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2 || !sep->IsNumber(2)) { + c->Message(Chat::White, "Usage: #set hero_model [Hero Model]"); + c->Message(Chat::White, "Usage: #set hero_model [Hero Model] [Slot]"); + c->Message( + Chat::White, + fmt::format( + "Example: {}", + Saylink::Silent("#heromodel 63") + ).c_str() + ); + return; + } + + Mob* t = c; + if (c->GetTarget()) { + t = c->GetTarget(); + } + + uint32 hero_forge_model = Strings::ToUnsignedInt(sep->arg[2]); + + if (arguments > 2) { + const uint8 slot = Strings::ToUnsignedInt(sep->arg[3]); + c->GetTarget()->SendTextureWC(slot, 0, hero_forge_model, 0, 0, 0); + } else { + if (!hero_forge_model) { + c->Message(Chat::White, "Hero's Forge Model must be greater than 0."); + return; + } + + // Conversion to simplify the command arguments + // Hero's Forge model is actually model * 1000 + texture * 100 + wearslot + // Hero's Forge Model slot 7 is actually for Robes, but it still needs to use wearslot 1 in the packet + hero_forge_model *= 100; + + for (uint8 slot = 0; slot < 7; slot++) { + c->GetTarget()->SendTextureWC(slot, 0, (hero_forge_model + slot), 0, 0, 0); + } + } +} diff --git a/zone/gm_commands/hideme.cpp b/zone/gm_commands/set/hide_me.cpp similarity index 50% rename from zone/gm_commands/hideme.cpp rename to zone/gm_commands/set/hide_me.cpp index 108807d8d..8b2e580f1 100755 --- a/zone/gm_commands/hideme.cpp +++ b/zone/gm_commands/set/hide_me.cpp @@ -1,11 +1,10 @@ -#include "../client.h" +#include "../../client.h" -void command_hideme(Client *c, const Seperator *sep) +void SetHideMe(Client *c, const Seperator *sep) { const auto arguments = sep->argnum; - if (!arguments) { - c->Message(Chat::White, "Usage: #hideme [On|Off]"); - c->Message(Chat::White, "Usage: #hideme [0|1]"); + if (arguments < 2) { + c->Message(Chat::White, "Usage: #set hide_me [on|off]"); return; } @@ -14,17 +13,17 @@ void command_hideme(Client *c, const Seperator *sep) t = c->GetTarget()->CastToClient(); } - const auto is_hidden = Strings::ToBool(sep->arg[1]); + const bool is_hidden = Strings::ToBool(sep->arg[2]); t->SetHideMe(is_hidden); c->Message( Chat::White, fmt::format( - "{} {} now {} to players below a status level of {}.", + "{} {} now {}visible to players below a status level of {}.", c->GetTargetDescription(t, TargetDescriptionType::UCYou), c == t ? "are" : "is", - is_hidden ? "invisible" : "visible", + is_hidden ? "in" : "", t->Admin() ).c_str() ); diff --git a/zone/gm_commands/set/hp.cpp b/zone/gm_commands/set/hp.cpp new file mode 100644 index 000000000..3078cc98c --- /dev/null +++ b/zone/gm_commands/set/hp.cpp @@ -0,0 +1,33 @@ +#include "../../client.h" + +void SetHP(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2 || !sep->IsNumber(2)) { + c->Message(Chat::White, "Usage: #set hp [Amount]"); + return; + } + + Mob* t = c; + if (c->GetTarget()) { + t = c->GetTarget(); + } + + int64 health = Strings::ToBigInt(sep->arg[2]); + + if (health >= t->GetMaxHP()) { + health = t->GetMaxHP(); + } + + t->SetHP(health); + t->SendHPUpdate(); + + c->Message( + Chat::White, + fmt::format( + "Set {} to {} Health.", + c->GetTargetDescription(t), + Strings::Commify(health) + ).c_str() + ); +} diff --git a/zone/gm_commands/set/hp_full.cpp b/zone/gm_commands/set/hp_full.cpp new file mode 100755 index 000000000..b823b7fc5 --- /dev/null +++ b/zone/gm_commands/set/hp_full.cpp @@ -0,0 +1,20 @@ +#include "../../client.h" + +void SetHPFull(Client *c, const Seperator *sep) +{ + Mob* t = c; + if (c->GetTarget()) { + t = c->GetTarget(); + } + + t->Heal(); + + c->Message( + Chat::White, + fmt::format( + "Set {} to full Health ({}).", + c->GetTargetDescription(t), + Strings::Commify(t->GetMaxHP()) + ).c_str() + ); +} diff --git a/zone/gm_commands/set/invulnerable.cpp b/zone/gm_commands/set/invulnerable.cpp new file mode 100755 index 000000000..f8efcb2d7 --- /dev/null +++ b/zone/gm_commands/set/invulnerable.cpp @@ -0,0 +1,32 @@ +#include "../../client.h" + +void SetInvulnerable(Client *c, const Seperator *sep) { + const auto arguments = sep->argnum; + if (arguments < 2) { + c->Message(Chat::White, "Usage: #set invulnerable [on|off]"); + return; + } + + auto t = c; + if (c->GetTarget() && c->GetTarget()->IsClient()) { + t = c->GetTarget()->CastToClient(); + } + + const bool invulnerable = Strings::ToBool(sep->arg[2]); + + t->SetInvul(invulnerable); + + const uint32 account_id = t->AccountID(); + + database.SetGMInvul(account_id, invulnerable); + + c->Message( + Chat::White, + fmt::format( + "{} {} now {}vulnerable.", + c->GetTargetDescription(t, TargetDescriptionType::UCYou), + c == t ? "are" : "is", + invulnerable ? "in" : "" + ).c_str() + ); +} diff --git a/zone/gm_commands/set/language.cpp b/zone/gm_commands/set/language.cpp new file mode 100755 index 000000000..f16c01850 --- /dev/null +++ b/zone/gm_commands/set/language.cpp @@ -0,0 +1,54 @@ +#include "../../client.h" +#include "../../../common/languages.h" +#include "../../../common/data_verification.h" + +void SetLanguage(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 3 || !sep->IsNumber(2) || !sep->IsNumber(3)) { + c->Message(Chat::White, "Usage: #set language [Language ID] [Language Value]"); + c->Message(Chat::White, "Language ID = 0 to 27"); + c->Message(Chat::White, "Language Value = 0 to 100"); + return; + } + + auto t = c; + if (c->GetTarget() && c->GetTarget()->IsClient()) { + t = c->GetTarget()->CastToClient(); + } + + const int language_id = Strings::ToInt(sep->arg[2]); + const int language_value = Strings::ToInt(sep->arg[3]); + if ( + !EQ::ValueWithin(language_id, LANG_COMMON_TONGUE, LANG_UNKNOWN) || + !EQ::ValueWithin(language_value, 0, MAX_LANGUAGE_SKILL) + ) { + c->Message(Chat::White, "Usage: #set language [Language ID] [Language Value]"); + c->Message(Chat::White, "Language ID = 0 to 27"); + c->Message(Chat::White, "Language Value = 0 to 100"); + return; + } + + LogInfo( + "Set language request from [{}], Target: [{}] Language ID: [{}] Language Value: [{}]", + c->GetCleanName(), + c->GetTargetDescription(t), + language_id, + language_value + ); + + t->SetLanguageSkill(language_id, language_value); + + if (c != t) { + c->Message( + Chat::White, + fmt::format( + "Set {} ({}) to {} for {}.", + EQ::constants::GetLanguageName(language_id), + language_id, + language_value, + c->GetTargetDescription(t) + ).c_str() + ); + } +} diff --git a/zone/gm_commands/set/last_name.cpp b/zone/gm_commands/set/last_name.cpp new file mode 100755 index 000000000..8fd23789e --- /dev/null +++ b/zone/gm_commands/set/last_name.cpp @@ -0,0 +1,46 @@ +#include "../../client.h" + +void SetLastName(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2) { + c->Message(Chat::White, "Usage: #set lastname [Last Name]"); + c->Message(Chat::White, "Note: Use \"-1\" to remove last name."); + return; + } + + auto t = c; + if (c->GetTarget() && c->GetTarget()->IsClient()) { + t = c->GetTarget()->CastToClient(); + } + + LogInfo("#lastname request from [{}] for [{}]", c->GetCleanName(), t->GetCleanName()); + + const bool is_remove = Strings::EqualFold(sep->argplus[2], "-1"); + const std::string& last_name = !is_remove ? sep->argplus[2] : ""; + + if (last_name.size() > 64) { + c->Message(Chat::White, "Last name must be 64 characters or less."); + return; + } + + t->ChangeLastName(last_name); + + c->Message( + Chat::White, + fmt::format( + "Last name has been {}{} for {}{}", + is_remove ? "removed" : "changed", + !is_remove ? " and saved" : "", + c->GetTargetDescription(t), + ( + is_remove ? + "." : + fmt::format( + " to '{}'.", + last_name + ) + ) + ).c_str() + ); +} diff --git a/zone/gm_commands/set/level.cpp b/zone/gm_commands/set/level.cpp new file mode 100644 index 000000000..549de0b8b --- /dev/null +++ b/zone/gm_commands/set/level.cpp @@ -0,0 +1,34 @@ +#include "../../bot.h" +#include "../../client.h" + +void SetLevel(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2 || !sep->IsNumber(2)) { + c->Message(Chat::White, "Usage: #set level [Level]"); + return; + } + + Mob* t = c; + if (c->GetTarget()) { + t = c->GetTarget(); + } + + const uint8 max_level = RuleI(Character, MaxLevel); + const uint8 level = Strings::ToUnsignedInt(sep->arg[2]); + + if (c != t && c->Admin() < RuleI(GM, MinStatusToLevelTarget)) { + c->Message(Chat::White, "Your status is not high enough to change another person's level."); + return; + } + + t->SetLevel(level, true); + + if (t->IsClient()) { + t->CastToClient()->SendLevelAppearance(); + + if (RuleB(Bots, Enabled) && RuleB(Bots, BotLevelsWithOwner)) { + Bot::LevelBotWithClient(t->CastToClient(), level, true); + } + } +} diff --git a/zone/gm_commands/setlsinfo.cpp b/zone/gm_commands/set/loginserver_info.cpp similarity index 50% rename from zone/gm_commands/setlsinfo.cpp rename to zone/gm_commands/set/loginserver_info.cpp index 280c3e6f1..3e42216de 100755 --- a/zone/gm_commands/setlsinfo.cpp +++ b/zone/gm_commands/set/loginserver_info.cpp @@ -1,24 +1,30 @@ -#include "../client.h" -#include "../worldserver.h" +#include "../../client.h" +#include "../../worldserver.h" extern WorldServer worldserver; -void command_setlsinfo(Client *c, const Seperator *sep) +void SetLoginserverInfo(Client *c, const Seperator *sep) { - int arguments = sep->argnum; - if (arguments < 2) { - c->Message(Chat::White, "Usage: #setlsinfo [Email] [Password]"); + const auto arguments = sep->argnum; + if (arguments < 3) { + c->Message(Chat::White, "Usage: #set lsinfo [Email] [Password]"); return; } + const std::string& email = sep->arg[2]; + const std::string& password = sep->arg[3]; + auto pack = new ServerPacket(ServerOP_LSAccountUpdate, sizeof(ServerLSAccountUpdate_Struct)); + auto s = (ServerLSAccountUpdate_Struct *) pack->pBuffer; + s->useraccountid = c->LSAccountID(); strn0cpy(s->useraccount, c->AccountName(), 30); - strn0cpy(s->user_email, sep->arg[1], 100); - strn0cpy(s->userpassword, sep->arg[2], 50); + strn0cpy(s->user_email, email.c_str(), 100); + strn0cpy(s->userpassword, password.c_str(), 50); + worldserver.SendPacket(pack); safe_delete(pack); + c->Message(Chat::White, "Your email and local loginserver password have been set."); } - diff --git a/zone/gm_commands/set/mana.cpp b/zone/gm_commands/set/mana.cpp new file mode 100644 index 000000000..68779dc47 --- /dev/null +++ b/zone/gm_commands/set/mana.cpp @@ -0,0 +1,41 @@ +#include "../../client.h" + +void SetMana(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2 || !sep->IsNumber(2)) { + c->Message(Chat::White, "Usage: #set mana [Amount]"); + return; + } + + Mob* t = c; + if (c->GetTarget()) { + t = c->GetTarget(); + } + + int64 mana = Strings::ToBigInt(sep->arg[2]); + + if (t->IsClient()) { + if (mana >= t->CastToClient()->CalcMaxMana()) { + mana = t->CastToClient()->CalcMaxMana(); + } + + t->CastToClient()->SetMana(mana); + } else { + if (mana >= t->CalcMaxMana()) { + mana = t->CalcMaxMana(); + } + + t->SetMana(mana); + } + + c->Message( + Chat::White, + fmt::format( + "Set {} to {} Mana.", + c->GetTargetDescription(t), + Strings::Commify(mana) + ).c_str() + ); +} + diff --git a/zone/gm_commands/set/mana_full.cpp b/zone/gm_commands/set/mana_full.cpp new file mode 100755 index 000000000..5b9ad77bb --- /dev/null +++ b/zone/gm_commands/set/mana_full.cpp @@ -0,0 +1,28 @@ +#include "../../client.h" + +void SetManaFull(Client *c, const Seperator *sep) +{ + Mob* t = c; + if (c->GetTarget()) { + t = c->GetTarget(); + } + + int64 mana; + + if (t->IsClient()) { + mana = t->CastToClient()->CalcMaxMana(); + t->CastToClient()->SetMana(mana); + } else { + mana = t->CalcMaxMana(); + t->SetMana(mana); + } + + c->Message( + Chat::White, + fmt::format( + "Set {} to full Mana ({}).", + c->GetTargetDescription(t), + Strings::Commify(mana) + ).c_str() + ); +} diff --git a/zone/gm_commands/motd.cpp b/zone/gm_commands/set/motd.cpp similarity index 52% rename from zone/gm_commands/motd.cpp rename to zone/gm_commands/set/motd.cpp index 55a6d8ccc..f22cad89b 100755 --- a/zone/gm_commands/motd.cpp +++ b/zone/gm_commands/set/motd.cpp @@ -1,15 +1,24 @@ -#include "../client.h" -#include "../worldserver.h" +#include "../../client.h" +#include "../../worldserver.h" extern WorldServer worldserver; void command_motd(Client *c, const Seperator *sep) { + const auto arguments = sep->argnum; + if (arguments < 2) { + c->Message(Chat::White, "Usage: #set motd [Message]"); + return; + } + + const std::string& message = sep->argplus[2]; + auto pack = new ServerPacket(ServerOP_Motd, sizeof(ServerMotd_Struct)); + auto m = (ServerMotd_Struct *) pack->pBuffer; strn0cpy(m->myname, c->GetName(), sizeof(m->myname)); - strn0cpy(m->motd, sep->argplus[1], sizeof(m->motd)); + strn0cpy(m->motd, message.c_str(), sizeof(m->motd)); + worldserver.SendPacket(pack); safe_delete(pack); } - diff --git a/zone/gm_commands/set/name.cpp b/zone/gm_commands/set/name.cpp new file mode 100755 index 000000000..0e3ca531a --- /dev/null +++ b/zone/gm_commands/set/name.cpp @@ -0,0 +1,43 @@ +#include "../../client.h" + +void SetName(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2) { + c->Message(Chat::White, "Usage: #set name [Name]"); + return; + } + + if (c->GetTarget() && c->GetTarget()->IsClient()) { + auto t = c->GetTarget()->CastToClient(); + + std::string new_name = sep->arg[2]; + std::string old_name = t->GetCleanName(); + + if (t->ChangeFirstName(new_name.c_str(), c->GetCleanName())) { + c->Message( + Chat::White, + fmt::format( + "Successfully renamed {} to {}", + old_name, + new_name + ).c_str() + ); + + c->Message(Chat::White, "Sending player to char select."); + + t->Kick("Name was changed"); + + return; + } + + c->Message( + Chat::White, + fmt::format( + "Unable to rename {}. Check that the new name '{}' isn't already taken.", + old_name, + new_name + ).c_str() + ); + } +} diff --git a/zone/gm_commands/oocmute.cpp b/zone/gm_commands/set/ooc_mute.cpp similarity index 55% rename from zone/gm_commands/oocmute.cpp rename to zone/gm_commands/set/ooc_mute.cpp index d8711eccf..4f2db4e87 100755 --- a/zone/gm_commands/oocmute.cpp +++ b/zone/gm_commands/set/ooc_mute.cpp @@ -1,20 +1,23 @@ -#include "../client.h" -#include "../worldserver.h" +#include "../../client.h" +#include "../../worldserver.h" extern WorldServer worldserver; -void command_oocmute(Client *c, const Seperator *sep) +void SetOOCMute(Client *c, const Seperator *sep) { - if (!sep->IsNumber(1)) { - c->Message(Chat::White, "Usage: #oocmute [0|1] - Enable or Disable Server OOC"); + const auto arguments = sep->argnum; + if (arguments < 2) { + c->Message(Chat::White, "Usage: #set ooc_mute [on|off]"); return; } - bool is_muted = Strings::ToInt(sep->arg[1]) ? true : false; + const bool is_muted = Strings::ToBool(sep->arg[2]); ServerPacket pack(ServerOP_OOCMute, sizeof(ServerOOCMute_Struct)); + auto o = (ServerOOCMute_Struct*) pack.pBuffer; o->is_muted = is_muted; + worldserver.SendPacket(&pack); c->Message( @@ -25,4 +28,3 @@ void command_oocmute(Client *c, const Seperator *sep) ).c_str() ); } - diff --git a/zone/gm_commands/set/password.cpp b/zone/gm_commands/set/password.cpp new file mode 100755 index 000000000..d057daa4b --- /dev/null +++ b/zone/gm_commands/set/password.cpp @@ -0,0 +1,52 @@ +#include "../../client.h" + +void SetPassword(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 3) { + c->Message(Chat::White, "Usage: #set password [Account Name] [Password] [Loginserver]"); + return; + } + + std::string account_name = sep->arg[2]; + std::string password = sep->arg[3]; + std::string loginserver = arguments >= 4 ? sep->arg[4] : "eqemu"; + + int16 status = 0; + + const uint32 account_id = database.GetAccountIDByName(account_name, loginserver, &status); + if (!account_id) { + c->Message( + Chat::White, + fmt::format( + "Account {} was not found.", + account_name + ).c_str() + ); + return; + } + + if (status > c->Admin()) { + c->Message( + Chat::White, + fmt::format( + "You cannot change the password for Account {} as its status is higher than yours.", + account_name + ).c_str() + ); + return; + } + + c->Message( + Chat::White, + fmt::format( + "Password {} changed for Account {}.", + ( + database.SetLocalPassword(account_id, password.c_str()) ? + "successfully" : + "failed" + ), + account_name + ).c_str() + ); +} diff --git a/zone/gm_commands/set/pvp.cpp b/zone/gm_commands/set/pvp.cpp new file mode 100755 index 000000000..f851ddea1 --- /dev/null +++ b/zone/gm_commands/set/pvp.cpp @@ -0,0 +1,30 @@ +#include "../../client.h" + +void SetPVP(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2) { + c->Message(Chat::White, "Usage: #set pvp [on|off]"); + return; + } + + auto t = c; + if (c->GetTarget() && c->GetTarget()->IsClient()) { + t = c->GetTarget()->CastToClient(); + } + + const bool pvp_state = Strings::ToBool(sep->arg[2]); + + t->SetPVP(pvp_state); + + if (c != t) { + c->Message( + Chat::White, + fmt::format( + "{} now follows the ways of {}.", + c->GetTargetDescription(t), + pvp_state ? "Discord" : "Order" + ).c_str() + ); + } +} diff --git a/zone/gm_commands/set/pvp_points.cpp b/zone/gm_commands/set/pvp_points.cpp new file mode 100755 index 000000000..1562eaf12 --- /dev/null +++ b/zone/gm_commands/set/pvp_points.cpp @@ -0,0 +1,33 @@ +#include "../../client.h" + +void SetPVPPoints(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2 || !sep->IsNumber(2)) { + c->Message(Chat::White, "Usage: #set pvp_points [Amount]"); + return; + } + + auto t = c; + if (c->GetTarget() && c->GetTarget()->IsClient()) { + t = c->GetTarget()->CastToClient(); + } + + const uint32 pvp_points = Strings::ToUnsignedInt(sep->arg[2]); + + t->SetPVPPoints(pvp_points); + t->Save(); + t->SendPVPStats(); + + c->Message( + Chat::White, + fmt::format( + "{} now {} {} PVP Point{}.", + c->GetTargetDescription(t, TargetDescriptionType::UCYou), + c == t ? "have" : "has", + Strings::Commify(pvp_points), + pvp_points != 1 ? "s" : "" + ).c_str() + ); +} + diff --git a/zone/gm_commands/set/race.cpp b/zone/gm_commands/set/race.cpp new file mode 100755 index 000000000..5f9eb37ac --- /dev/null +++ b/zone/gm_commands/set/race.cpp @@ -0,0 +1,52 @@ +#include "../../client.h" + +void SetRace(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2 || !sep->IsNumber(2)) { + c->Message( + Chat::White, + fmt::format( + "Usage: #set race [0-{}, 2253-2259] (0 for back to normal)", + RuleI(NPC, MaxRaceID) + ).c_str() + ); + + return; + } + + Mob* t = c; + if (c->GetTarget()) { + t = c->GetTarget(); + } + + const uint16 race_id = Strings::ToUnsignedInt(sep->arg[2]); + + if ( + !EQ::ValueWithin(race_id, RACE_DOUG_0, RuleI(NPC, MaxRaceID)) && + !EQ::ValueWithin(race_id, 2253, 2259) + ) { + c->Message( + Chat::White, + fmt::format( + "Usage: #race [0-{}, 2253-2259] (0 for back to normal)", + RuleI(NPC, MaxRaceID) + ).c_str() + ); + + return; + } + + t->SendIllusionPacket(race_id); + + c->Message( + Chat::White, + fmt::format( + "{} {} now temporarily a(n) {} ({}).", + c->GetTargetDescription(t, TargetDescriptionType::UCYou), + c == t ? "are" : "is", + GetRaceIDName(race_id), + race_id + ).c_str() + ); +} diff --git a/zone/gm_commands/set/race_permanent.cpp b/zone/gm_commands/set/race_permanent.cpp new file mode 100755 index 000000000..bc6a094ee --- /dev/null +++ b/zone/gm_commands/set/race_permanent.cpp @@ -0,0 +1,45 @@ +#include "../../client.h" + +void SetRacePermanent(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2 || !sep->IsNumber(2)) { + c->Message(Chat::White, "Usage: #set race_permanent [Race ID]"); + c->Message( + Chat::White, + "NOTE: Not all models are global. If a model is not global, it will appear as a Human on character select and in zones without the model." + ); + + return; + } + + auto t = c; + if (c->GetTarget() && c->GetTarget()->IsClient()) { + t = c->GetTarget()->CastToClient(); + } + + const uint16 race_id = Strings::ToUnsignedInt(sep->arg[2]); + const uint8 gender_id = Mob::GetDefaultGender(race_id, t->GetBaseGender()); + + LogInfo("Race changed by {} for {} to {} ({})", + c->GetCleanName(), + c->GetTargetDescription(t), + GetRaceIDName(race_id), + race_id + ); + + t->SetBaseRace(race_id); + t->SetBaseGender(gender_id); + t->Save(); + t->SendIllusionPacket(race_id, gender_id); + + c->Message( + Chat::White, + fmt::format( + "Race changed for {} to {} ({}).", + c->GetTargetDescription(t), + GetRaceIDName(race_id), + race_id + ).c_str() + ); +} diff --git a/zone/gm_commands/set/server_locked.cpp b/zone/gm_commands/set/server_locked.cpp new file mode 100644 index 000000000..73e92dad3 --- /dev/null +++ b/zone/gm_commands/set/server_locked.cpp @@ -0,0 +1,33 @@ +#include "../../client.h" +#include "../../worldserver.h" + +extern WorldServer worldserver; + +void SetServerLocked(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2) { + c->Message(Chat::White, "Usage: #set server_locked [on|off]"); + return; + } + + bool is_locked = Strings::ToBool(sep->arg[2]); + + if (c->EntityVariableExists("old_command")) { + const std::string& old_command = c->GetEntityVariable("old_command"); + if (old_command == "lock" || old_command == "serverlock") { + is_locked = true; + } else if (old_command == "unlock" || old_command == "serverunlock") { + is_locked = false; + } + } + + auto pack = new ServerPacket(ServerOP_Lock, sizeof(ServerLock_Struct)); + + auto l = (ServerLock_Struct *) pack->pBuffer; + strn0cpy(l->character_name, c->GetCleanName(), sizeof(l->character_name)); + l->is_locked = is_locked; + + worldserver.SendPacket(pack); + safe_delete(pack); +} diff --git a/zone/gm_commands/setskill.cpp b/zone/gm_commands/set/skill.cpp similarity index 67% rename from zone/gm_commands/setskill.cpp rename to zone/gm_commands/set/skill.cpp index 428a9cc48..b6071a9f6 100755 --- a/zone/gm_commands/setskill.cpp +++ b/zone/gm_commands/set/skill.cpp @@ -1,11 +1,10 @@ -#include "../client.h" +#include "../../client.h" -void command_setskill(Client *c, const Seperator *sep) +void SetSkill(Client *c, const Seperator *sep) { const auto arguments = sep->argnum; - - if (arguments < 2 || !sep->IsNumber(1) || !sep->IsNumber(2)) { - c->Message(Chat::White, "Usage: #setskill [Skill ID] [Skill Value]"); + if (arguments < 3 || !sep->IsNumber(2) || !sep->IsNumber(3)) { + c->Message(Chat::White, "Usage: #set skill [Skill ID] [Skill Value]"); return; } @@ -14,11 +13,11 @@ void command_setskill(Client *c, const Seperator *sep) t = c->GetTarget()->CastToClient(); } - const auto skill_id = Strings::ToInt(sep->arg[1]); - const auto skill_value = Strings::ToInt(sep->arg[2]); + const uint16 skill_id = Strings::ToUnsignedInt(sep->arg[2]); + const uint16 skill_value = Strings::ToUnsignedInt(sep->arg[3]); if (!EQ::ValueWithin(skill_id, EQ::skills::Skill1HBlunt, EQ::skills::HIGHEST_SKILL)) { - c->Message(Chat::White, "Usage: #setskill [Skill ID] [Skill Value]"); + c->Message(Chat::White, "Usage: #set skill [Skill ID] [Skill Value]"); c->Message(Chat::White, fmt::format("Skill ID: 0 to {}", EQ::skills::HIGHEST_SKILL).c_str()); return; } @@ -43,4 +42,3 @@ void command_setskill(Client *c, const Seperator *sep) ); } } - diff --git a/zone/gm_commands/set/skill_all.cpp b/zone/gm_commands/set/skill_all.cpp new file mode 100755 index 000000000..1094b4bea --- /dev/null +++ b/zone/gm_commands/set/skill_all.cpp @@ -0,0 +1,39 @@ +#include "../../client.h" + +void SetSkillAll(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2 || !sep->IsNumber(2)) { + c->Message(Chat::White, "Usage: #set skill_all [Skill Level]"); + return; + } + + auto t = c; + if (c->GetTarget() && c->GetTarget()->IsClient()) { + t = c->GetTarget()->CastToClient(); + } + + const uint16 skill_level = Strings::ToUnsignedInt(sep->arg[2]); + + for (const auto& s : EQ::skills::GetSkillTypeMap()) { + if (t->CanHaveSkill(s.first) && t->MaxSkill(s.first)) { + if (c != t) { + c->Message( + Chat::White, + fmt::format( + "Setting {} ({}) to {} for {}.", + s.second, + s.first, + skill_level > t->MaxSkill(s.first) ? t->MaxSkill(s.first) : skill_level, + c->GetTargetDescription(t) + ).c_str() + ); + } + + t->SetSkill( + s.first, + skill_level > t->MaxSkill(s.first) ? t->MaxSkill(s.first) : skill_level + ); + } + } +} diff --git a/zone/gm_commands/max_all_skills.cpp b/zone/gm_commands/set/skill_all_max.cpp similarity index 74% rename from zone/gm_commands/max_all_skills.cpp rename to zone/gm_commands/set/skill_all_max.cpp index d032265ec..0565721f8 100755 --- a/zone/gm_commands/max_all_skills.cpp +++ b/zone/gm_commands/set/skill_all_max.cpp @@ -1,6 +1,6 @@ -#include "../client.h" +#include "../../client.h" -void command_max_all_skills(Client *c, const Seperator *sep) +void SetSkillAllMax(Client *c, const Seperator *sep) { auto t = c; if (c->GetTarget() && c->GetTarget()->IsClient()) { @@ -17,4 +17,3 @@ void command_max_all_skills(Client *c, const Seperator *sep) ).c_str() ); } - diff --git a/zone/gm_commands/set/start_zone.cpp b/zone/gm_commands/set/start_zone.cpp new file mode 100755 index 000000000..71748ccb9 --- /dev/null +++ b/zone/gm_commands/set/start_zone.cpp @@ -0,0 +1,51 @@ +#include "../../client.h" + +void SetStartZone(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2) { + c->Message(Chat::White, "Usage: #set start_zone [Zone ID|Zone Short Name]"); + c->Message( + Chat::White, + "Optional Usage: Use '#set start_zone reset' or '#set start_zone 0' to clear a starting zone. Player can select a starting zone using /setstartcity" + ); + return; + } + + auto t = c; + if (c->GetTarget() && c->GetTarget()->IsClient()) { + t = c->GetTarget()->CastToClient(); + } + + const uint32 zone_id = ( + sep->IsNumber(2) ? + Strings::ToUnsignedInt(sep->arg[2]) : + ZoneID(sep->arg[2]) + ); + + t->SetStartZone(zone_id); + + const bool is_reset = ( + Strings::EqualFold(sep->arg[2], "reset") || + zone_id == 0 + ); + + c->Message( + Chat::White, + fmt::format( + "Start Zone {} for {} |{}", + is_reset ? "Reset" : "Changed", + c->GetTargetDescription(t, TargetDescriptionType::UCSelf), + ( + zone_id ? + fmt::format( + " {} ({}) ID: {}", + ZoneLongName(zone_id), + ZoneName(zone_id), + zone_id + ) : + "" + ) + ).c_str() + ); +} diff --git a/zone/gm_commands/set/temporary_name.cpp b/zone/gm_commands/set/temporary_name.cpp new file mode 100755 index 000000000..f04577c5b --- /dev/null +++ b/zone/gm_commands/set/temporary_name.cpp @@ -0,0 +1,38 @@ +#include "../../client.h" + +void SetTemporaryName(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2) { + c->Message(Chat::White, "Usage: #set temporary_name [New Name]"); + c->Message(Chat::White, "Note: This command requires a target, even if the target is yourself."); + return; + } + + if (!c->GetTarget()) { + c->Message(Chat::White, "Usage: #set temporary_name [New Name]"); + c->Message(Chat::White, "Note: This command requires a target, even if the target is yourself."); + return; + } + + Mob* t = c->GetTarget(); + + const std::string& temporary_name = strlen(sep->arg[2]) ? sep->arg[2] : ""; + + t->TempName(temporary_name.c_str()); + + if (temporary_name.length()) { + const std::string& current_name = t->GetName(); + + c->Message( + Chat::White, + fmt::format( + "Renamed {} to {} temporarily.", + current_name, + temporary_name + ).c_str() + ); + } else { + c->Message(Chat::White, "Restored your target's original name."); + } +} diff --git a/zone/gm_commands/set/texture.cpp b/zone/gm_commands/set/texture.cpp new file mode 100755 index 000000000..e08cc530d --- /dev/null +++ b/zone/gm_commands/set/texture.cpp @@ -0,0 +1,56 @@ +#include "../../client.h" + +void SetTexture(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2 || !sep->IsNumber(2)) { + c->Message(Chat::White, "Usage: #set texture [Texture] [Helmet Texture]"); + return; + } + + const uint16 texture = Strings::ToUnsignedInt(sep->arg[2]); + const uint8 helmet_texture = ( + sep->IsNumber(3) ? + Strings::ToUnsignedInt(sep->arg[3]) : + 0 + ); + + Mob* t = c; + if (c->GetTarget()) { + t = c->GetTarget(); + } + + if (IsPlayerRace(t->GetModel())) { // Player Races Wear Armor, so Wearchange is sent instead + for ( + int texture_slot = EQ::textures::textureBegin; + texture_slot <= EQ::textures::LastTintableTexture; + texture_slot++ + ) { + t->SendTextureWC(texture_slot, texture); + } + } else { // Non-Player Races only need Illusion Packets to be sent for texture + t->SendIllusionPacket( + t->GetModel(), + t->GetGender(), + texture, + helmet_texture + ); + } + + c->Message( + Chat::White, + fmt::format( + "Texture Changed for {} | Texture: {}{}", + c->GetTargetDescription(t, TargetDescriptionType::UCSelf), + texture, + ( + IsPlayerRace(t->GetModel()) ? + "" : + fmt::format( + " Helmet Texture: {}", + helmet_texture + ) + ) + ).c_str() + ); +} diff --git a/zone/gm_commands/set/time.cpp b/zone/gm_commands/set/time.cpp new file mode 100755 index 000000000..6cd3ab57b --- /dev/null +++ b/zone/gm_commands/set/time.cpp @@ -0,0 +1,67 @@ +#include "../../client.h" + +void SetTime(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2 || !sep->IsNumber(2)) { + c->Message(Chat::White, "Usage: #set time [Hour] [Minute]"); + + TimeOfDay_Struct world_time; + zone->zone_time.GetCurrentEQTimeOfDay(time(0), &world_time); + + auto time_string = fmt::format( + "{} (Timezone: {})", + Strings::ZoneTime(world_time.hour, world_time.minute), + Strings::ZoneTime(zone->zone_time.getEQTimeZoneHr(), zone->zone_time.getEQTimeZoneHr()) + ); + + c->Message( + Chat::White, + fmt::format( + "It is currently {}.", + time_string + ).c_str() + ); + + return; + } + + uint8 minutes = 0; + uint8 hours = Strings::ToUnsignedInt(sep->arg[2]) + 1; + + if (hours > 24) { + hours = 24; + } + + uint8 real_hours = ( + (hours - 1) > 0 ? + (hours - 1) : + 0 + ); + + if (sep->IsNumber(3)) { + minutes = Strings::ToUnsignedInt(sep->arg[3]); + + if (minutes > 59) { + minutes = 59; + } + } + + c->Message( + Chat::White, + fmt::format( + "Setting world time to {} (Timezone: {}).", + Strings::ZoneTime(hours, minutes), + Strings::ZoneTime(zone->zone_time.getEQTimeZoneHr(), zone->zone_time.getEQTimeZoneHr()) + ).c_str() + ); + + zone->SetTime(real_hours, minutes); + + LogInfo( + "{} :: Setting world time to {} (Timezone: {})", + c->GetCleanName(), + Strings::ZoneTime(hours, minutes), + Strings::ZoneTime(zone->zone_time.getEQTimeZoneHr(), zone->zone_time.getEQTimeZoneHr()) + ); +} diff --git a/zone/gm_commands/set/time_zone.cpp b/zone/gm_commands/set/time_zone.cpp new file mode 100755 index 000000000..cb96700c6 --- /dev/null +++ b/zone/gm_commands/set/time_zone.cpp @@ -0,0 +1,58 @@ +#include "../../client.h" + +void SetTimeZone(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2 || sep->IsNumber(2)) { + c->Message(Chat::White, "Usage: #set time_zone [Hour] [Minute]"); + c->Message( + Chat::White, + fmt::format( + "Current time zone is {}.", + Strings::ZoneTime(zone->zone_time.getEQTimeZoneHr(), zone->zone_time.getEQTimeZoneMin()) + ).c_str() + ); + return; + } + + uint8 minutes = 0; + uint8 hours = Strings::ToUnsignedInt(sep->arg[2]); + + if (hours > 24) { + hours = 24; + } + + uint8 real_hours = ( + (hours - 1) > 0 ? + (hours - 1) : + 0 + ); + + if (sep->IsNumber(3)) { + minutes = Strings::ToUnsignedInt(sep->arg[3]); + + if (minutes > 59) { + minutes = 59; + } + } + + c->Message( + Chat::White, + fmt::format( + "Setting timezone to {}.", + Strings::ZoneTime(hours, minutes) + ).c_str() + ); + + const int new_timezone = ((hours * 60) + minutes); + zone->zone_time.setEQTimeZone(new_timezone); + content_db.SetZoneTZ(zone->GetZoneID(), zone->GetInstanceVersion(), new_timezone); + + auto outapp = new EQApplicationPacket(OP_TimeOfDay, sizeof(TimeOfDay_Struct)); + + auto t = (TimeOfDay_Struct *) outapp->pBuffer; + zone->zone_time.GetCurrentEQTimeOfDay(time(0), t); + + entity_list.QueueClients(c, outapp); + safe_delete(outapp); +} diff --git a/zone/gm_commands/set/title.cpp b/zone/gm_commands/set/title.cpp new file mode 100755 index 000000000..a6fc8a6e2 --- /dev/null +++ b/zone/gm_commands/set/title.cpp @@ -0,0 +1,55 @@ +#include "../../client.h" +#include "../../titles.h" + +void SetTitle(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 2) { + c->Message(Chat::White, "Usage: #set title [Title]"); + c->Message(Chat::White, "Note: Use \"-1\" to remove title."); + return; + } + + const bool is_remove = Strings::EqualFold(sep->argplus[2], "-1"); + std::string title = !is_remove ? sep->argplus[2] : ""; + + auto t = c; + if (c->GetTarget() && c->GetTarget()->IsClient()) { + t = c->GetTarget()->CastToClient(); + } + + if (title.size() > 31) { + c->Message(Chat::White, "Title must be 31 characters or less."); + return; + } + + if (!title.empty()) { + Strings::FindReplace(title, "_", " "); + } + + if (is_remove) { + t->SetAATitle(title); + } else { + title_manager.CreateNewPlayerTitle(t, title); + } + + t->Save(); + + c->Message( + Chat::White, + fmt::format( + "Title has been {}{} for {}{}", + is_remove ? "removed" : "changed", + !is_remove ? " and saved" : "", + c->GetTargetDescription(t), + ( + is_remove ? + "." : + fmt::format( + " to '{}'.", + title + ) + ) + ).c_str() + ); +} diff --git a/zone/gm_commands/titlesuffix.cpp b/zone/gm_commands/set/title_suffix.cpp similarity index 55% rename from zone/gm_commands/titlesuffix.cpp rename to zone/gm_commands/set/title_suffix.cpp index cc5581d96..1b4619dc4 100755 --- a/zone/gm_commands/titlesuffix.cpp +++ b/zone/gm_commands/set/title_suffix.cpp @@ -1,23 +1,21 @@ -#include "../client.h" -#include "../titles.h" +#include "../../client.h" +#include "../../titles.h" -void command_titlesuffix(Client *c, const Seperator *sep) +void SetTitleSuffix(Client *c, const Seperator *sep) { - int arguments = sep->argnum; + const auto arguments = sep->argnum; if (!arguments) { - c->Message( - Chat::White, - "Usage: #titlesuffix [Title Suffix] (use \"-1\" to remove title suffix)" - ); + c->Message(Chat::White, "Usage: #set title_suffix [Title Suffix]"); + c->Message(Chat::White, "Note: Use \"-1\" to remove title."); return; } - bool is_remove = !strcasecmp(sep->argplus[1], "-1"); + const bool is_remove = !strcasecmp(sep->argplus[1], "-1"); std::string suffix = is_remove ? "" : sep->argplus[1]; - auto target = c; + auto t = c; if (c->GetTarget() && c->GetTarget()->IsClient()) { - target = c->GetTarget()->CastToClient(); + t = c->GetTarget()->CastToClient(); } if (suffix.size() > 31) { @@ -30,12 +28,12 @@ void command_titlesuffix(Client *c, const Seperator *sep) } if (is_remove) { - target->SetTitleSuffix(suffix); + t->SetTitleSuffix(suffix); } else { - title_manager.CreateNewPlayerSuffix(target, suffix); + title_manager.CreateNewPlayerSuffix(t, suffix); } - target->Save(); + t->Save(); c->Message( Chat::White, @@ -43,7 +41,7 @@ void command_titlesuffix(Client *c, const Seperator *sep) "Title suffix has been {}{} for {}{}", is_remove ? "removed" : "changed", !is_remove ? " and saved" : "", - c->GetTargetDescription(target), + c->GetTargetDescription(t), ( is_remove ? "." : diff --git a/zone/gm_commands/weather.cpp b/zone/gm_commands/set/weather.cpp similarity index 69% rename from zone/gm_commands/weather.cpp rename to zone/gm_commands/set/weather.cpp index 6289275f1..028ba2387 100755 --- a/zone/gm_commands/weather.cpp +++ b/zone/gm_commands/set/weather.cpp @@ -1,27 +1,27 @@ -#include "../client.h" +#include "../../client.h" -void command_weather(Client *c, const Seperator *sep) +void SetWeather(Client *c, const Seperator *sep) { - if (!sep->IsNumber(1)) { + const auto arguments = sep->argnum; + if (arguments < 2 || !sep->IsNumber(2)) { c->Message(Chat::White, "Usage: #weather [0|1|2] - [Off|Rain|Snow]"); c->Message(Chat::White, "Usage: #weather 3 [Type] [Intensity] - Manually set weather type and intensity"); return; } - int arguments = sep->argnum; - if (arguments == 1) { - auto new_weather = static_cast(Strings::ToUnsignedInt(sep->arg[1])); - uint8 new_intensity = 0; + if (arguments == 2) { + uint8 new_weather = Strings::ToUnsignedInt(sep->arg[2]); + uint8 new_intensity = 0; std::string weather_message = "The sky clears."; if (new_weather == EQ::constants::WeatherTypes::Snowing) { weather_message = "Snowflakes begin to fall from the sky."; - new_weather = EQ::constants::WeatherTypes::Snowing; - new_intensity = 0x02; + new_weather = EQ::constants::WeatherTypes::Snowing; + new_intensity = 2; } else if (new_weather == EQ::constants::WeatherTypes::Raining) { weather_message = "Raindrops begin to fall from the sky."; - new_weather = EQ::constants::WeatherTypes::Raining; - new_intensity = 0x01; // This is how it's done in Fear, and you can see a decent distance with it at this value + new_weather = EQ::constants::WeatherTypes::Raining; + new_intensity = 1; // This is how it's done in Fear, and you can see a decent distance with it at this value } zone->zone_weather = new_weather; @@ -35,21 +35,20 @@ void command_weather(Client *c, const Seperator *sep) outapp->pBuffer[4] = new_intensity; } - c->Message(Chat::White, weather_message.c_str()); entity_list.QueueClients(c, outapp); safe_delete(outapp); - } else if (arguments == 3) { - auto command_type = static_cast(Strings::ToUnsignedInt(sep->arg[1])); - uint8 new_weather = EQ::constants::WeatherTypes::None; - uint8 new_intensity = 0; + } else if (arguments == 4) { + const uint8 command_type = Strings::ToUnsignedInt(sep->arg[2]); + uint8 new_weather = EQ::constants::WeatherTypes::None; + uint8 new_intensity = 0; std::string weather_message; if (zone->zone_weather == EQ::constants::WeatherTypes::None) { if (command_type > EQ::constants::WeatherTypes::Snowing) { - new_weather = static_cast(Strings::ToUnsignedInt(sep->arg[2])); - new_intensity = static_cast(Strings::ToUnsignedInt(sep->arg[3])); + new_weather = Strings::ToUnsignedInt(sep->arg[3]); + new_intensity = Strings::ToUnsignedInt(sep->arg[4]); weather_message = fmt::format( "Sending {} ({}) with an intensity of {}.", @@ -59,12 +58,12 @@ void command_weather(Client *c, const Seperator *sep) ); } else if (command_type == EQ::constants::WeatherTypes::Snowing) { weather_message = "Snowflakes begin to fall from the sky."; - new_weather = EQ::constants::WeatherTypes::Snowing; - new_intensity = 0x02; + new_weather = EQ::constants::WeatherTypes::Snowing; + new_intensity = 2; } else if (command_type == EQ::constants::WeatherTypes::Raining) { weather_message = "Raindrops begin to fall from the sky."; - new_weather = EQ::constants::WeatherTypes::Raining; - new_intensity = 0x01; // This is how it's done in Fear, and you can see a decent distance with it at this value + new_weather = EQ::constants::WeatherTypes::Raining; + new_intensity = 1; // This is how it's done in Fear, and you can see a decent distance with it at this value } zone->zone_weather = new_weather; @@ -86,7 +85,7 @@ void command_weather(Client *c, const Seperator *sep) if (zone->zone_weather == EQ::constants::WeatherTypes::Snowing) { weather_message = "The sky clears as the snow stops falling."; - outapp->pBuffer[0] = 0x01; // Snow has it's own shutoff packet + outapp->pBuffer[0] = 1; // Snow has it's own shutoff packet } else if (zone->zone_weather == EQ::constants::WeatherTypes::Raining) { weather_message = "The sky clears as the rain ceases to fall."; } @@ -100,4 +99,3 @@ void command_weather(Client *c, const Seperator *sep) } } } - diff --git a/zone/gm_commands/set/zone.cpp b/zone/gm_commands/set/zone.cpp new file mode 100755 index 000000000..a79acf6bf --- /dev/null +++ b/zone/gm_commands/set/zone.cpp @@ -0,0 +1,455 @@ +#include "../../client.h" + +void SetZoneData(Client *c, const Seperator *sep) +{ + const auto arguments = sep->argnum; + if (arguments < 3) { + c->Message( + Chat::White, + "Usage: #set zone clipping [Minimum Clip] [Maximum Clip] [Fog Minimum Clip] [Fog Maximum Clip] [Permanent (0 = False, 1 = True)] (Permanent is optional)" + ); + c->Message( + Chat::White, + "Usage: #set zone color [Red] [Green] [Blue] [Permanent (0 = False, 1 = True)] (Permanent is optional)" + ); + c->Message( + Chat::White, + "Usage: #set zone header [Zone ID|Zone Short Name] [Version]" + ); + c->Message( + Chat::White, + "Usage: #set zone locked [on|off] [Zone ID|Zone Short Name]" + ); + c->Message( + Chat::White, + "Usage: #set zone safe_coordinates [X] [Y] [Z] [Heading] [Permanent (0 = False, 1 = True)] (Permanent is optional)" + ); + c->Message( + Chat::White, + "Usage: #set zone sky [Sky Type] [Permanent (0 = False, 1 = True)] (Permanent is optional)" + ); + c->Message( + Chat::White, + "Usage: #set zone underworld [Z] [Permanent (0 = False, 1 = True)] (Permanent is optional)" + ); + return; + } + + const bool is_clipping = Strings::EqualFold(sep->arg[2], "clipping"); + const bool is_color = Strings::EqualFold(sep->arg[2], "color"); + const bool is_header = Strings::EqualFold(sep->arg[2], "header"); + const bool is_locked = Strings::EqualFold(sep->arg[2], "locked"); + const bool is_safe_coordinates = Strings::EqualFold(sep->arg[2], "safe_coordinates"); + const bool is_sky = Strings::EqualFold(sep->arg[2], "sky"); + const bool is_underworld = Strings::EqualFold(sep->arg[2], "underworld"); + + if ( + !is_clipping && + !is_color && + !is_header && + !is_locked && + !is_safe_coordinates && + !is_sky && + !is_underworld + ) { + c->Message( + Chat::White, + "Usage: #set zone clipping [Minimum Clip] [Maximum Clip] [Fog Minimum Clip] [Fog Maximum Clip] [Permanent (0 = False, 1 = True)] (Permanent is optional)" + ); + c->Message( + Chat::White, + "Usage: #set zone color [Red] [Green] [Blue] [Permanent (0 = False, 1 = True)] (Permanent is optional)" + ); + c->Message( + Chat::White, + "Usage: #set zone header [Zone ID|Zone Short Name] [Version]" + ); + c->Message( + Chat::White, + "Usage: #set zone locked [on|off] [Zone ID|Zone Short Name]" + ); + c->Message( + Chat::White, + "Usage: #set zone safe_coordinates [X] [Y] [Z] [Heading] [Permanent (0 = False, 1 = True)] (Permanent is optional)" + ); + c->Message( + Chat::White, + "Usage: #set zone sky [Sky Type] [Permanent (0 = False, 1 = True)] (Permanent is optional)" + ); + c->Message( + Chat::White, + "Usage: #set zone underworld [Z] [Permanent (0 = False, 1 = True)] (Permanent is optional)" + ); + return; + } + + if (is_clipping) { + const float minimum_clip = sep->arg[3] ? Strings::ToFloat(sep->arg[3]) : 0.0f; + const float maximum_clip = sep->arg[4] ? Strings::ToFloat(sep->arg[4]) : 0.0f; + const float minimum_fog_clip = sep->arg[5] ? Strings::ToFloat(sep->arg[5]) : 0.0f; + const float maximum_fog_clip = sep->arg[6] ? Strings::ToFloat(sep->arg[6]) : 0.0f; + const bool permanent = sep->arg[7] ? Strings::ToBool(sep->arg[7]) : false; + + if (minimum_clip < 0.0f || maximum_clip < 0.0f) { + c->Message(Chat::White, "Minimum Clip and Maximum Clip must be greater than or equal 0.0."); + return; + } else if (minimum_clip > maximum_clip) { + c->Message(Chat::White, "Minimum Clip must be less than or equal to Maximum Clip!"); + return; + } else { + zone->newzone_data.minclip = minimum_clip; + zone->newzone_data.maxclip = maximum_clip; + + if (minimum_fog_clip) { + for (float &fog_index: zone->newzone_data.fog_minclip) { + fog_index = minimum_fog_clip; + } + } + + if (maximum_fog_clip) { + for (float &fog_index: zone->newzone_data.fog_maxclip) { + fog_index = maximum_fog_clip; + } + } + + if (permanent) { + std::string query = fmt::format( + "UPDATE zone SET minclip = {:.2f}, maxclip = {:.2f} WHERE zoneidnumber = {} AND version = {}", + minimum_clip, + maximum_clip, + zone->GetZoneID(), + zone->GetInstanceVersion() + ); + + database.QueryDatabase(query); + + if (minimum_fog_clip) { + query = fmt::format( + "UPDATE zone SET fog_minclip = {:.2f} WHERE zoneidnumber = {} AND version = {}", + minimum_fog_clip, + zone->GetZoneID(), + zone->GetInstanceVersion() + ); + database.QueryDatabase(query); + } + + if (maximum_fog_clip) { + query = fmt::format( + "UPDATE zone SET fog_maxclip = {:.2f} WHERE zoneidnumber = {} AND version = {}", + maximum_fog_clip, + zone->GetZoneID(), + zone->GetInstanceVersion() + ); + database.QueryDatabase(query); + } + } + + auto outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); + memcpy(outapp->pBuffer, &zone->newzone_data, outapp->size); + entity_list.QueueClients(c, outapp); + safe_delete(outapp); + + c->Message( + Chat::White, + fmt::format( + "Clipping Changed | Zone: {} Permanent: {}", + zone->GetZoneDescription(), + permanent ? "Yes" : "No" + ).c_str() + ); + + c->Message( + Chat::White, + fmt::format( + "Clipping Changed | Minimum Clip: {:.2f} Maximum Clip: {:.2f}", + minimum_clip, + maximum_clip + ).c_str() + ); + + if (minimum_fog_clip || maximum_fog_clip) { + c->Message( + Chat::White, + fmt::format( + "Clipping Changed | Fog Minimum Clip: {:.2f} Fog Maximum Clip: {:.2f}", + minimum_fog_clip, + maximum_fog_clip + ).c_str() + ); + } + } + } else if (is_color) { + if ( + arguments < 3 || + !sep->IsNumber(3) || + !sep->IsNumber(4) || + !sep->IsNumber(5) + ) { + c->Message(Chat::White, "Usage: #set zone color [Red] [Green] [Blue] [Permanent (0 = False, 1 = True)]"); + return; + } + + const uint8 red = Strings::ToUnsignedInt(sep->arg[3]); + const uint8 green = Strings::ToUnsignedInt(sep->arg[4]); + const uint8 blue = Strings::ToUnsignedInt(sep->arg[5]); + const bool permanent = sep->arg[6] ? Strings::ToBool(sep->arg[6]) : false; + + if ( + !EQ::ValueWithin(red, 0, UINT8_MAX) || + !EQ::ValueWithin(green, 0, UINT8_MAX) || + !EQ::ValueWithin(blue, 0, UINT8_MAX) + ) { + c->Message(Chat::White, "Colors cannot be less than 0 or greater than 255."); + return; + } + + if (permanent) { + const std::string& query = fmt::format( + "UPDATE zone SET fog_red = {}, fog_green = {}, fog_blue = {} " + "WHERE zoneidnumber = {} AND version = {}", + red, + green, + blue, + zone->GetZoneID(), + zone->GetInstanceVersion() + ); + database.QueryDatabase(query); + } + + for (uint8 fog_index = 0; fog_index < 4; fog_index++) { + zone->newzone_data.fog_red[fog_index] = red; + zone->newzone_data.fog_green[fog_index] = green; + zone->newzone_data.fog_blue[fog_index] = blue; + } + + auto outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); + memcpy(outapp->pBuffer, &zone->newzone_data, outapp->size); + entity_list.QueueClients(c, outapp); + safe_delete(outapp); + + c->Message( + Chat::White, + fmt::format( + "Fog Color Changed | Zone: {} Red: {} Green: {} Blue: {} Permanent: {}", + zone->GetZoneDescription(), + red, + green, + blue, + permanent ? "Yes" : "No" + ).c_str() + ); + } else if (is_header) { + if (arguments < 3) { + c->Message(Chat::White, "Usage: #set zone header [Zone ID|Zone Short Name] [Version]"); + return; + } + + const auto zone_id = ( + sep->IsNumber(3) ? + Strings::ToUnsignedInt(sep->arg[3]) : + ZoneID(sep->arg[3]) + ); + if (!zone_id) { + c->Message( + Chat::White, + fmt::format( + "Zone ID {} could not be found.", + zone_id + ).c_str() + ); + return; + } + + const std::string& zone_short_name = ZoneName(zone_id); + const std::string& zone_long_name = ZoneLongName(zone_id); + const auto version = ( + sep->IsNumber(4) ? + Strings::ToUnsignedInt(sep->arg[4]) : + 0 + ); + + auto outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); + memcpy(outapp->pBuffer, &zone->newzone_data, outapp->size); + entity_list.QueueClients(c, outapp); + safe_delete(outapp); + + zone_store.LoadZones(content_db); + + c->Message( + Chat::White, + fmt::format( + "Zone Header Load {} | Zone: {} ({}){}", + ( + zone->LoadZoneCFG(zone_short_name.c_str(), version) ? + "Succeeded" : + "Failed" + ), + zone_long_name, + zone_short_name, + ( + version ? + fmt::format( + " Version: {}", + version + ) : + "" + ) + ).c_str() + ); + } else if (is_locked) { + if (arguments < 4) { + c->Message(Chat::White, "Usage: #set zone locked [on|off] [Zone ID|Zone Short Name]"); + return; + } + + const bool is_locked = Strings::ToBool(sep->arg[3]); + + const uint32 zone_id = ( + sep->IsNumber(4) ? + Strings::ToUnsignedInt(sep->arg[4]) : + ZoneID(sep->arg[4]) + ); + const std::string& zone_short_name = Strings::ToLower(ZoneName(zone_id, true)); + + const bool is_unknown_zone = Strings::EqualFold(zone_short_name, "unknown"); + if (!zone_id || is_unknown_zone) { + c->Message(Chat::White, "Usage: #set zone locked [on|off] [Zone ID|Zone Short Name]"); + return; + } + + auto pack = new ServerPacket(ServerOP_LockZone, sizeof(ServerLockZone_Struct)); + + auto l = (ServerLockZone_Struct *) pack->pBuffer; + strn0cpy(l->adminname, c->GetName(), sizeof(l->adminname)); + l->op = is_locked ? ServerLockType::Lock : ServerLockType::Unlock; + l->zoneID = zone_id; + + worldserver.SendPacket(pack); + safe_delete(pack); + } else if (is_safe_coordinates) { + if ( + arguments < 3 || + !sep->IsNumber(3) || + !sep->IsNumber(4) || + !sep->IsNumber(5) + ) { + c->Message(Chat::White, "Usage: #set zone safe_coordinates [X] [Y] [Z] [Heading] [Permanent (0 = False, 1 = True)]"); + c->Message(Chat::White, "Not sending Heading defaults to current Heading and the change is temporary."); + return; + } + + const float x = Strings::ToFloat(sep->arg[3]); + const float y = Strings::ToFloat(sep->arg[4]); + const float z = Strings::ToFloat(sep->arg[5]); + const float heading = sep->arg[6] ? Strings::ToFloat(sep->arg[6]) : c->GetHeading(); + const bool permanent = sep->arg[7] ? Strings::ToBool(sep->arg[7]) : false; + + if (permanent) { + const std::string& query = fmt::format( + "UPDATE zone SET safe_x = {:.2f}, safe_y = {:.2f}, safe_z = {:.2f}, safe_heading = {:.2f} WHERE zoneidnumber = {} AND version = {}", + x, + y, + z, + heading, + zone->GetZoneID(), + zone->GetInstanceVersion() + ); + database.QueryDatabase(query); + } + + zone->newzone_data.safe_x = x; + zone->newzone_data.safe_y = y; + zone->newzone_data.safe_z = z; + + auto outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); + memcpy(outapp->pBuffer, &zone->newzone_data, outapp->size); + entity_list.QueueClients(c, outapp); + safe_delete(outapp); + + c->Message( + Chat::White, + fmt::format( + "Safe Coordinates Changed | Zone: {} XYZ: {:.2f}, {:.2f}, {:.2f} Heading: {:.2f} Permanent: {} ", + zone->GetZoneDescription(), + x, + y, + z, + heading, + permanent ? "Yes" : "No" + ).c_str() + ); + } else if (is_sky) { + if (arguments < 3 || !sep->IsNumber(3)) { + c->Message(Chat::White, "Usage: #set zone sky [Sky Type] [Permanent (0 = False, 1 = True)]"); + return; + } + + const uint8 sky_type = Strings::ToUnsignedInt(sep->arg[3]); + const bool permanent = sep->arg[4] ? Strings::ToBool(sep->arg[4]) : false; + + if (!EQ::ValueWithin(sky_type, 0, UINT8_MAX)) { + c->Message(Chat::White, "Sky Type cannot be less than 0 or greater than 255!"); + return; + } + + if (permanent) { + const std::string& query = fmt::format( + "UPDATE zone SET sky = {} WHERE zoneidnumber = {} AND version = {}", + sky_type, + zone->GetZoneID(), + zone->GetInstanceVersion() + ); + database.QueryDatabase(query); + } + + zone->newzone_data.sky = sky_type; + auto outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); + memcpy(outapp->pBuffer, &zone->newzone_data, outapp->size); + entity_list.QueueClients(c, outapp); + safe_delete(outapp); + + c->Message( + Chat::White, + fmt::format( + "Sky Changed | Zone: {} Sky Type: {} Permanent: {}", + zone->GetZoneDescription(), + sky_type, + permanent ? "Yes" : "No" + ).c_str() + ); + } else if (is_underworld) { + if (arguments < 3 || !sep->IsNumber(3)) { + c->Message(Chat::White, "Usage: #set zone underworld [Z] [Permanent (0 = False, 1 = True)]"); + return; + } + + const float z = Strings::ToFloat(sep->arg[3]); + const bool permanent = sep->arg[4] ? Strings::ToBool(sep->arg[4]) : false; + + if (permanent) { + auto query = fmt::format( + "UPDATE zone SET underworld = {:.2f} WHERE zoneidnumber = {} AND version = {}", + z, + zone->GetZoneID(), + zone->GetInstanceVersion() + ); + database.QueryDatabase(query); + } + + zone->newzone_data.underworld = z; + auto outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); + memcpy(outapp->pBuffer, &zone->newzone_data, outapp->size); + entity_list.QueueClients(c, outapp); + safe_delete(outapp); + + c->Message( + Chat::White, + fmt::format( + "Underworld Z Changed | Zone: {} Z: {:.2f} Permanent: {}", + zone->GetZoneDescription(), + z, + permanent ? "Yes" : "No" + ).c_str() + ); + } +} diff --git a/zone/gm_commands/set_adventure_points.cpp b/zone/gm_commands/set_adventure_points.cpp deleted file mode 100755 index 89a309b94..000000000 --- a/zone/gm_commands/set_adventure_points.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "../client.h" -#include "../../common/data_verification.h" - -void command_set_adventure_points(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - - if ( - !arguments || - !sep->IsNumber(1) || - !sep->IsNumber(2) - ) { - c->Message(Chat::White, "Usage: #setadventurepoints [Theme] [Points]"); - c->Message(Chat::White, "Valid themes are as follows."); - auto theme_map = EQ::constants::GetLDoNThemeMap(); - for (const auto& theme : theme_map) { - c->Message( - Chat::White, - fmt::format( - "Theme {} | {}", - theme.first, - theme.second - ).c_str() - ); - } - c->Message(Chat::White, "Note: Theme 0 splits the points evenly across all Themes."); - return; - } - - auto target = c; - if (c->GetTarget() && c->GetTarget()->IsClient()) { - target = c->GetTarget()->CastToClient(); - } - - auto theme_id = Strings::ToUnsignedInt(sep->arg[1]); - if (!EQ::ValueWithin(theme_id, LDoNThemes::Unused, LDoNThemes::TAK)) { - c->Message(Chat::White, "Valid themes are as follows."); - auto& theme_map = EQ::constants::GetLDoNThemeMap(); - for (const auto& theme : theme_map) { - c->Message( - Chat::White, - fmt::format( - "Theme {} | {}", - theme.first, - theme.second - ).c_str() - ); - } - c->Message(Chat::White, "Note: Theme 0 splits the points evenly across all Themes."); - return; - } - - auto points = Strings::ToInt(sep->arg[2]); - - c->Message( - Chat::White, - fmt::format( - "{} for {}.", - ( - theme_id == LDoNThemes::Unused ? - fmt::format( - "Splitting {} Points Evenly", - points - ) : - fmt::format( - "Adding {} {} Points", - points, - EQ::constants::GetLDoNThemeName(theme_id) - ) - ), - c->GetTargetDescription(target) - ).c_str() - ); - - target->UpdateLDoNPoints(theme_id, points); -} diff --git a/zone/gm_commands/setaapts.cpp b/zone/gm_commands/setaapts.cpp deleted file mode 100755 index 86b8c2994..000000000 --- a/zone/gm_commands/setaapts.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "../client.h" -#include "../groups.h" -#include "../raids.h" -#include "../raids.h" - -void command_setaapts(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (arguments <= 1 || !sep->IsNumber(2)) { - c->Message(Chat::White, "Usage: #setaapts [AA|Group|Raid] [AA Amount]"); - return; - } - - Client *target = c; - if (c->GetTarget() && c->GetTarget()->IsClient()) { - target = c->GetTarget()->CastToClient(); - } - - std::string aa_type = Strings::ToLower(sep->arg[1]); - std::string group_raid_string; - uint32 aa_points = static_cast(std::min(Strings::ToUnsignedBigInt(sep->arg[2]), (uint64) 2000000000)); - bool is_aa = aa_type.find("aa") != std::string::npos; - bool is_group = aa_type.find("group") != std::string::npos; - bool is_raid = aa_type.find("raid") != std::string::npos; - if (!is_aa && !is_group && !is_raid) { - c->Message(Chat::White, "Usage: #setaapts [AA|Group|Raid] [AA Amount]"); - return; - } - - if (is_aa) { - target->GetPP().aapoints = aa_points; - target->GetPP().expAA = 0; - target->SendAlternateAdvancementStats(); - } - else if (is_group || is_raid) { - if (is_group) { - group_raid_string = "Group "; - target->GetPP().group_leadership_points = aa_points; - target->GetPP().group_leadership_exp = 0; - } - else if (is_raid) { - group_raid_string = "Raid "; - target->GetPP().raid_leadership_points = aa_points; - target->GetPP().raid_leadership_exp = 0; - } - target->SendLeadershipEXPUpdate(); - } - - std::string aa_message = fmt::format( - "{} now {} {} {}AA Point{}.", - c->GetTargetDescription(target, TargetDescriptionType::UCYou), - c == target ? "have" : "has", - aa_points, - group_raid_string, - aa_points != 1 ? "s" : "" - - ); - c->Message( - Chat::White, - aa_message.c_str() - ); -} - diff --git a/zone/gm_commands/setaaxp.cpp b/zone/gm_commands/setaaxp.cpp deleted file mode 100755 index dbf81320f..000000000 --- a/zone/gm_commands/setaaxp.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "../client.h" -#include "../groups.h" -#include "../raids.h" -#include "../raids.h" - -void command_setaaxp(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (arguments <= 1 || !sep->IsNumber(2)) { - c->Message(Chat::White, "Usage: #setaaxp [AA|Group|Raid] [AA Experience]"); - return; - } - - Client *target = c; - if (c->GetTarget() && c->GetTarget()->IsClient()) { - target = c->GetTarget()->CastToClient(); - } - - std::string aa_type = Strings::ToLower(sep->arg[1]); - std::string group_raid_string; - uint32 aa_experience = static_cast(std::min( - Strings::ToUnsignedBigInt(sep->arg[2]), - (uint64) 2000000000 - )); - bool is_aa = aa_type.find("aa") != std::string::npos; - bool is_group = aa_type.find("group") != std::string::npos; - bool is_raid = aa_type.find("raid") != std::string::npos; - if (!is_aa && !is_group && !is_raid) { - c->Message(Chat::White, "Usage: #setaaxp [AA|Group|Raid] [AA Experience]"); - return; - } - - if (is_aa) { - target->SetEXP( - target->GetEXP(), - aa_experience, - false - ); - } - else if (is_group) { - group_raid_string = "Group "; - target->SetLeadershipEXP( - aa_experience, - target->GetRaidEXP() - ); - } - else if (is_raid) { - group_raid_string = "Raid "; - target->SetLeadershipEXP( - target->GetGroupEXP(), - aa_experience - ); - } - - std::string aa_exp_message = fmt::format( - "{} now {} {} {}AA Experience.", - c->GetTargetDescription(target, TargetDescriptionType::UCYou), - c == target ? "have" : "has", - aa_experience, - group_raid_string - ); - c->Message( - Chat::White, - aa_exp_message.c_str() - ); -} - diff --git a/zone/gm_commands/setaltcurrency.cpp b/zone/gm_commands/setaltcurrency.cpp deleted file mode 100644 index d3208cc0c..000000000 --- a/zone/gm_commands/setaltcurrency.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "../client.h" - -void command_setaltcurrency(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if ( - arguments < 2 || - !sep->IsNumber(1) || - !sep->IsNumber(2) - ) { - c->Message(Chat::White, "Command Syntax: #setaltcurrency [Currency ID] [Amount]"); - return; - } - - auto target = c; - if (c->GetTarget() && c->GetTarget()->IsClient()) { - target = c->GetTarget()->CastToClient(); - } - - auto currency_id = Strings::ToUnsignedInt(sep->arg[1]); - auto amount = static_cast(std::min(Strings::ToBigInt(sep->arg[2]), (int64) 2000000000)); - uint32 currency_item_id = zone->GetCurrencyItemID(currency_id); - if (!currency_item_id) { - c->Message( - Chat::White, - fmt::format( - "Currency ID {} could not be found.", - currency_id - ).c_str() - ); - return; - } - - target->SetAlternateCurrencyValue(currency_id, amount); - - c->Message( - Chat::White, - fmt::format( - "{} now {} {} {}.", - c->GetTargetDescription(target, TargetDescriptionType::UCYou), - c == target ? "have" : "has", - ( - amount ? - std::to_string(amount) : - "no" - ), - database.CreateItemLink(currency_item_id) - ).c_str() - ); -} - diff --git a/zone/gm_commands/setanim.cpp b/zone/gm_commands/setanim.cpp deleted file mode 100755 index 72f16edc9..000000000 --- a/zone/gm_commands/setanim.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "../client.h" - -void command_setanim(Client *c, const Seperator *sep) -{ - const auto arguments = sep->argnum; - if (!arguments || !sep->IsNumber(1)) { - c->Message(Chat::White, "Usage: #setanim [Animation ID]"); - - uint32 animation_number = 1; - for (const auto& a : EQ::constants::GetSpawnAnimationMap()) { - c->Message( - Chat::White, - fmt::format( - "Animation {} | ID: {} Name: {}", - animation_number, - a.first, - a.second - ).c_str() - ); - - animation_number++; - } - return; - } - - Mob* target = c; - if (c->GetTarget()) { - target = c->GetTarget(); - } - - const auto animation_id = static_cast(Strings::ToUnsignedInt(sep->arg[1])); - if ( - !EQ::ValueWithin( - animation_id, - static_cast(eaStanding), - static_cast(eaLooting) - ) - ) { - c->Message(Chat::White, "Usage: #setanim [Animation ID]"); - - uint32 animation_number = 1; - for (const auto& a : EQ::constants::GetSpawnAnimationMap()) { - c->Message( - Chat::White, - fmt::format( - "Animation {} | ID: {} Name: {}", - animation_number, - a.first, - a.second - ).c_str() - ); - - animation_number++; - } - return; - } - - target->SetAppearance(static_cast(animation_id), false); - - const auto animation_name = EQ::constants::GetSpawnAnimationName(animation_id); - - c->Message( - Chat::White, - fmt::format( - "Set animation to {} ({}) for {}.", - animation_name, - animation_id, - c->GetTargetDescription(target) - ).c_str() - ); -} - diff --git a/zone/gm_commands/setcrystals.cpp b/zone/gm_commands/setcrystals.cpp deleted file mode 100755 index b2befc92a..000000000 --- a/zone/gm_commands/setcrystals.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "../client.h" - -void command_setcrystals(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (arguments <= 1 || !sep->IsNumber(2)) { - c->Message(Chat::White, "Usage: #setcrystals [Ebon|Radiant] [Crystal Amount]"); - return; - } - - Client *target = c; - if (c->GetTarget() && c->GetTarget()->IsClient()) { - target = c->GetTarget()->CastToClient(); - } - - std::string crystal_type = Strings::ToLower(sep->arg[1]); - uint32 crystal_amount = static_cast(std::min( - Strings::ToUnsignedBigInt(sep->arg[2]), - (uint64) 2000000000 - )); - bool is_ebon = crystal_type.find("ebon") != std::string::npos; - bool is_radiant = crystal_type.find("radiant") != std::string::npos; - if (!is_ebon && !is_radiant) { - c->Message(Chat::White, "Usage: #setcrystals [Ebon|Radiant] [Crystal Amount]"); - return; - } - - uint32 crystal_item_id = ( - is_ebon ? - RuleI(Zone, EbonCrystalItemID) : - RuleI(Zone, RadiantCrystalItemID) - ); - - auto crystal_link = database.CreateItemLink(crystal_item_id); - if (is_radiant) { - target->SetRadiantCrystals(crystal_amount); - } else { - target->SetEbonCrystals(crystal_amount); - } - - c->Message( - Chat::White, - fmt::format( - "{} now {} {} {}.", - c->GetTargetDescription(target, TargetDescriptionType::UCYou), - c == target ? "have" : "has", - crystal_amount, - crystal_link - ).c_str() - ); -} - diff --git a/zone/gm_commands/setendurance.cpp b/zone/gm_commands/setendurance.cpp deleted file mode 100644 index 86da26008..000000000 --- a/zone/gm_commands/setendurance.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "../client.h" - -void command_setendurance(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (!arguments || !sep->IsNumber(1)) { - c->Message(Chat::White, "Usage: #setendurance [Endurance]"); - return; - } - - auto endurance = static_cast(std::min(Strings::ToBigInt(sep->arg[1]), (int64) 2000000000)); - bool set_to_max = false; - Mob* target = c; - if (c->GetTarget()) { - target = c->GetTarget(); - } - - if (target->IsClient()) { - if (endurance >= target->CastToClient()->GetMaxEndurance()) { - endurance = target->CastToClient()->GetMaxEndurance(); - set_to_max = true; - } - - target->CastToClient()->SetEndurance(endurance); - } else { - if (endurance >= target->GetMaxEndurance()) { - endurance = target->GetMaxEndurance(); - set_to_max = true; - } - - target->SetEndurance(endurance); - } - - c->Message( - Chat::White, - fmt::format( - "Set {} to {} Endurance{}.", - c->GetTargetDescription(target), - ( - set_to_max ? - "full" : - std::to_string(endurance) - ), - ( - set_to_max ? - fmt::format( - " ({})", - endurance - ) : - "" - ) - ).c_str() - ); -} diff --git a/zone/gm_commands/setfaction.cpp b/zone/gm_commands/setfaction.cpp deleted file mode 100755 index a3d8a82a3..000000000 --- a/zone/gm_commands/setfaction.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "../client.h" - -void command_setfaction(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (!arguments || !sep->IsNumber(1)) { - c->Message(Chat::White, "Usage: #setfaction [Faction ID]"); - return; - } - - if ( - !c->GetTarget() || - ( - c->GetTarget() && - c->GetTarget()->IsClient() - ) - ) { - c->Message(Chat::White, "You must target an NPC to use this command."); - return; - } - - NPC* target = c->GetTarget()->CastToNPC(); - auto npc_id = target->GetNPCTypeID(); - auto faction_id = Strings::ToInt(sep->arg[1]); - auto faction_name = content_db.GetFactionName(faction_id); - if (!faction_name.empty()) { - c->Message( - Chat::White, - fmt::format( - "Faction Changed | Name: {} ({}) Faction: {} ({}).", - target->GetCleanName(), - npc_id, - content_db.GetFactionName(faction_id), - faction_id - ).c_str() - ); - - std::string query = fmt::format( - "UPDATE npc_types SET npc_faction_id = {} WHERE id = {}", - faction_id, - npc_id - ); - content_db.QueryDatabase(query); - } else { - c->Message( - Chat::White, - "Invalid Faction ID, please specify a valid Faction ID." - ); - } -} - diff --git a/zone/gm_commands/sethp.cpp b/zone/gm_commands/sethp.cpp deleted file mode 100644 index 9c1463e13..000000000 --- a/zone/gm_commands/sethp.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "../client.h" - -void command_sethp(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (!arguments || !sep->IsNumber(1)) { - c->Message(Chat::White, "Usage: #sethp [Health]"); - return; - } - - auto health = static_cast(std::min(Strings::ToBigInt(sep->arg[1]), (int64) 2000000000)); - bool set_to_max = false; - Mob* target = c; - if (c->GetTarget()) { - target = c->GetTarget(); - } - - if (health >= target->GetMaxHP()) { - health = target->GetMaxHP(); - set_to_max = true; - } - - target->SetHP(health); - target->SendHPUpdate(); - - c->Message( - Chat::White, - fmt::format( - "Set {} to {} Health{}.", - c->GetTargetDescription(target), - ( - set_to_max ? - "full" : - std::to_string(health) - ), - ( - set_to_max ? - fmt::format( - " ({})", - health - ) : - "" - ) - ).c_str() - ); -} - diff --git a/zone/gm_commands/setlanguage.cpp b/zone/gm_commands/setlanguage.cpp deleted file mode 100755 index ad9b400ef..000000000 --- a/zone/gm_commands/setlanguage.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "../client.h" -#include "../../common/languages.h" -#include "../../common/data_verification.h" - -void command_setlanguage(Client *c, const Seperator *sep) -{ - auto target = c; - if (c->GetTarget() && c->GetTarget()->IsClient()) { - target = c->GetTarget()->CastToClient(); - } - - auto language_id = sep->IsNumber(1) ? Strings::ToInt(sep->arg[1]) : -1; - auto language_value = sep->IsNumber(2) ? Strings::ToInt(sep->arg[2]) : -1; - if (!strcasecmp(sep->arg[1], "list")) { - for (const auto& language : EQ::constants::GetLanguageMap()) { - c->Message( - Chat::White, - fmt::format( - "Language {}: {}", - language.first, - language.second - ).c_str() - ); - } - } else if ( - !EQ::ValueWithin(language_id, LANG_COMMON_TONGUE, LANG_UNKNOWN) || - !EQ::ValueWithin(language_value, 0, 100) - ) { - c->Message(Chat::White, "Usage: #setlanguage [Language ID] [Language Value]"); - c->Message(Chat::White, "Usage: #setlanguage [List]"); - c->Message(Chat::White, "Language ID = 0 to 27"); - c->Message(Chat::White, "Language Value = 0 to 100"); - } else { - LogInfo( - "Set language request from [{}], Target: [{}] Language ID: [{}] Language Value: [{}]", - c->GetCleanName(), - c->GetTargetDescription(target), - language_id, - language_value - ); - - target->SetLanguageSkill(language_id, language_value); - - if (c != target) { - c->Message( - Chat::White, - fmt::format( - "Set {} ({}) to {} for {}.", - EQ::constants::GetLanguageName(language_id), - language_id, - language_value, - c->GetTargetDescription(target) - ).c_str() - ); - } - } -} diff --git a/zone/gm_commands/setmana.cpp b/zone/gm_commands/setmana.cpp deleted file mode 100644 index 57e2e6ece..000000000 --- a/zone/gm_commands/setmana.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "../client.h" - -void command_setmana(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (!arguments || !sep->IsNumber(1)) { - c->Message(Chat::White, "Usage: #setmana [Mana]"); - return; - } - - auto mana = static_cast(std::min(Strings::ToBigInt(sep->arg[1]), (int64) 2000000000)); - bool set_to_max = false; - Mob* target = c; - if (c->GetTarget()) { - target = c->GetTarget(); - } - - if (target->IsClient()) { - if (mana >= target->CastToClient()->CalcMaxMana()) { - mana = target->CastToClient()->CalcMaxMana(); - set_to_max = true; - } - - target->CastToClient()->SetMana(mana); - } else { - if (mana >= target->CalcMaxMana()) { - mana = target->CalcMaxMana(); - set_to_max = true; - } - - target->SetMana(mana); - } - - c->Message( - Chat::White, - fmt::format( - "Set {} to {} Mana{}.", - c->GetTargetDescription(target), - ( - set_to_max ? - "full" : - std::to_string(mana) - ), - ( - set_to_max ? - fmt::format( - " ({})", - mana - ) : - "" - ) - ).c_str() - ); -} - diff --git a/zone/gm_commands/setpass.cpp b/zone/gm_commands/setpass.cpp deleted file mode 100755 index 88b02fdf0..000000000 --- a/zone/gm_commands/setpass.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "../client.h" - -void command_setpass(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (arguments < 2) { - c->Message(Chat::White, "Usage: #setpass [Account Name] [Password]"); - return; - } - - std::string account_name; - std::string loginserver; - ParseAccountString(sep->arg[1], account_name, loginserver); - int16 status = 0; - auto account_id = database.GetAccountIDByName(account_name, loginserver, &status); - if (!account_id) { - c->Message( - Chat::White, - fmt::format( - "Account {} not found.", - account_name - ).c_str() - ); - return; - } - - if (status > c->Admin()) { - c->Message( - Chat::White, - fmt::format( - "You cannot change the password for Account {} as its status is higher than yours.", - account_name - ).c_str() - ); - return; - } - - c->Message( - Chat::White, - fmt::format( - "Password {} changed for Account {}.", - ( - database.SetLocalPassword(account_id, sep->arg[2]) ? - "successfully" : - "failed" - ), - account_name - ).c_str() - ); -} - diff --git a/zone/gm_commands/setpvppoints.cpp b/zone/gm_commands/setpvppoints.cpp deleted file mode 100755 index 15b24a01a..000000000 --- a/zone/gm_commands/setpvppoints.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "../client.h" - -void command_setpvppoints(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (!arguments || !sep->IsNumber(1)) { - c->Message(Chat::White, "Command Syntax: #setpvppoints [Amount]"); - return; - } - - Client *target = c; - if (c->GetTarget() && c->GetTarget()->IsClient()) { - target = c->GetTarget()->CastToClient(); - } - - uint32 pvp_points = static_cast(std::min(Strings::ToUnsignedBigInt(sep->arg[1]), (uint64) 2000000000)); - target->SetPVPPoints(pvp_points); - target->Save(); - target->SendPVPStats(); - std::string pvp_message = fmt::format( - "{} now {} {} PVP Point{}.", - c->GetTargetDescription(target, TargetDescriptionType::UCYou), - c == target ? "have" : "has", - pvp_points, - pvp_points != 1 ? "s" : "" - ); - c->Message( - Chat::White, - pvp_message.c_str() - ); -} - diff --git a/zone/gm_commands/setskillall.cpp b/zone/gm_commands/setskillall.cpp deleted file mode 100755 index 16f38a5ef..000000000 --- a/zone/gm_commands/setskillall.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "../client.h" - -void command_setskillall(Client *c, const Seperator *sep) -{ - const auto arguments = sep->argnum; - - if (!arguments || !sep->IsNumber(1)) { - c->Message(Chat::White, "Usage: #setskillall [Skill Level] - Set all of your or your target's skills to the specified skill level"); - return; - } - - auto t = c; - if (c->GetTarget() && c->GetTarget()->IsClient()) { - t = c->GetTarget()->CastToClient(); - } - - if (c->Admin() < commandSetSkillsOther && t != c) { - c->Message(Chat::White, "Your status is not high enough to set another player's skills."); - return; - } - - auto skill_level = static_cast(Strings::ToUnsignedInt(sep->arg[1])); - - for (const auto& s : EQ::skills::GetSkillTypeMap()) { - if (c != t) { - c->Message( - Chat::White, - fmt::format( - "Setting {} ({}) to {} for {}.", - s.second, - s.first, - skill_level > t->MaxSkill(s.first) ? t->MaxSkill(s.first) : skill_level, - c->GetTargetDescription(t) - ).c_str() - ); - } - - t->SetSkill( - s.first, - skill_level > t->MaxSkill(s.first) ? t->MaxSkill(s.first) : skill_level - ); - } -} diff --git a/zone/gm_commands/setstartzone.cpp b/zone/gm_commands/setstartzone.cpp deleted file mode 100755 index 7accda12e..000000000 --- a/zone/gm_commands/setstartzone.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "../client.h" - -void command_setstartzone(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (!arguments) { - c->Message(Chat::White, "Usage: #setstartzone [Zone ID|Zone Short Name]"); - c->Message( - Chat::White, - "Optional Usage: Use '#setstartzone Reset' or '#setstartzone 0' to clear a starting zone. Player can select a starting zone using /setstartcity" - ); - return; - } - - auto target = c; - if (c->GetTarget() && c->GetTarget()->IsClient()) { - target = c->GetTarget()->CastToClient(); - } - - auto zone_id = ( - sep->IsNumber(1) ? - Strings::ToUnsignedInt(sep->arg[1]) : - ZoneID(sep->arg[1]) - ); - - target->SetStartZone(zone_id); - - bool is_reset = ( - !strcasecmp(sep->arg[1], "reset") || - zone_id == 0 - ); - - c->Message( - Chat::White, - fmt::format( - "Start Zone {} for {} |{}", - is_reset ? "Reset" : "Changed", - c->GetTargetDescription(target, TargetDescriptionType::UCSelf), - ( - zone_id ? - fmt::format( - " {} ({}) ID: {}", - ZoneLongName(zone_id), - ZoneName(zone_id), - zone_id - ) : - "" - ) - ).c_str() - ); -} - diff --git a/zone/gm_commands/setstat.cpp b/zone/gm_commands/setstat.cpp deleted file mode 100755 index 7e4c42cd3..000000000 --- a/zone/gm_commands/setstat.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "../client.h" - -void command_setstat(Client *c, const Seperator *sep) -{ - if (sep->arg[1][0] && sep->arg[2][0] && c->GetTarget() != 0 && c->GetTarget()->IsClient()) { - c->GetTarget()->CastToClient()->SetStats(Strings::ToInt(sep->arg[1]), Strings::ToInt(sep->arg[2])); - } - else { - c->Message(Chat::White, "This command is used to permanently increase or decrease a players stats."); - c->Message(Chat::White, "Usage: #setstat {type} {value the stat should be}"); - c->Message(Chat::White, "Types: Str: 0, Sta: 1, Agi: 2, Dex: 3, Int: 4, Wis: 5, Cha: 6"); - } -} - diff --git a/zone/gm_commands/setxp.cpp b/zone/gm_commands/setxp.cpp deleted file mode 100755 index 8aa810b0b..000000000 --- a/zone/gm_commands/setxp.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "../client.h" - -void command_setxp(Client *c, const Seperator *sep) -{ - Client *t = c; - - if (c->GetTarget() && c->GetTarget()->IsClient()) { - t = c->GetTarget()->CastToClient(); - } - - if (sep->IsNumber(1)) { - if (Strings::ToInt(sep->arg[1]) > 9999999) { - c->Message(Chat::White, "Error: Value too high."); - } - else { - t->AddEXP(Strings::ToInt(sep->arg[1])); - } - } - else { - c->Message(Chat::White, "Usage: #setxp number"); - } -} - diff --git a/zone/gm_commands/show.cpp b/zone/gm_commands/show.cpp index d88410984..2bea01355 100755 --- a/zone/gm_commands/show.cpp +++ b/zone/gm_commands/show.cpp @@ -121,8 +121,19 @@ void command_show(Client *c, const Seperator *sep) // build the rewrite string const std::string& rewrite = fmt::format("#show {} {}", cmd.cmd, Strings::Join(args, " ")); - // rewrite to #show + // rewrite to #show > c->SendGMCommand(rewrite); + + c->Message( + Chat::Gray, + fmt::format( + "{} is now located under {}, using {}.", + sep->arg[0], + Saylink::Silent("#show"), + Saylink::Silent(rewrite) + ).c_str() + ); + return; } } diff --git a/zone/gm_commands/show/recipe.cpp b/zone/gm_commands/show/recipe.cpp index 0bc980316..95cae95cc 100644 --- a/zone/gm_commands/show/recipe.cpp +++ b/zone/gm_commands/show/recipe.cpp @@ -6,7 +6,7 @@ void ShowRecipe(Client *c, const Seperator *sep) { if (!sep->IsNumber(2)) { - c->Message(Chat::White, "Command Syntax: #show recipe [Recipe ID]"); + c->Message(Chat::White, "Usage: #show recipe [Recipe ID]"); return; } @@ -43,7 +43,7 @@ void ShowRecipe(Client *c, const Seperator *sep) ); uint32 entry_number = 1; - const bool can_summon_items = c->Admin() >= GetCommandStatus(c, "summonitem"); + const bool can_summon_items = c->Admin() >= GetCommandStatus("summonitem"); for (const auto& e : re) { c->Message( diff --git a/zone/gm_commands/tempname.cpp b/zone/gm_commands/tempname.cpp deleted file mode 100755 index 849549472..000000000 --- a/zone/gm_commands/tempname.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "../client.h" - -void command_tempname(Client *c, const Seperator *sep) -{ - Mob *target; - target = c->GetTarget(); - - if (!target) { - c->Message(Chat::White, "Usage: #tempname newname (requires a target)"); - } - else if (strlen(sep->arg[1]) > 0) { - char *oldname = strdup(target->GetName()); - target->TempName(sep->arg[1]); - c->Message(Chat::White, "Renamed %s to %s", oldname, sep->arg[1]); - free(oldname); - } - else { - target->TempName(); - c->Message(Chat::White, "Restored the original name"); - } -} - diff --git a/zone/gm_commands/texture.cpp b/zone/gm_commands/texture.cpp deleted file mode 100755 index 518b91549..000000000 --- a/zone/gm_commands/texture.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "../client.h" - -void command_texture(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (!arguments || !sep->IsNumber(1)) { - c->Message(Chat::White, "Usage: #texture [Texture] [Helmet Texture]"); - return; - } - - auto texture = static_cast(std::min(Strings::ToUnsignedInt(sep->arg[1]), (uint32) 65535)); - auto helmet_texture = static_cast( - sep->IsNumber(2) ? - std::min(Strings::ToUnsignedInt(sep->arg[2]), (uint32) 255) : - 0 - ); - - Mob* target = c; - if (c->GetTarget() && c->Admin() >= commandTextureOthers) { - target = c->GetTarget(); - } - - if (IsPlayerRace(target->GetModel())) { // Player Races Wear Armor, so Wearchange is sent instead - for ( - int texture_slot = EQ::textures::textureBegin; - texture_slot <= EQ::textures::LastTintableTexture; - texture_slot++ - ) { - target->SendTextureWC(texture_slot, texture); - } - } else { // Non-Player Races only need Illusion Packets to be sent for texture - target->SendIllusionPacket( - target->GetModel(), - target->GetGender(), - texture, - helmet_texture - ); - } - - c->Message( - Chat::White, - fmt::format( - "Texture Changed for {} | Texture: {}{}", - c->GetTargetDescription(target, TargetDescriptionType::UCSelf), - texture, - ( - IsPlayerRace(target->GetModel()) ? - "" : - fmt::format( - " Helmet Texture: {}", - helmet_texture - ) - ) - ).c_str() - ); -} - diff --git a/zone/gm_commands/time.cpp b/zone/gm_commands/time.cpp deleted file mode 100755 index 7df178eca..000000000 --- a/zone/gm_commands/time.cpp +++ /dev/null @@ -1,128 +0,0 @@ -#include "../client.h" - -void command_time(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (!arguments || !sep->IsNumber(1)) { - c->Message(Chat::White, "Usage: #time [Hour] [Minute]"); - - TimeOfDay_Struct world_time; - zone->zone_time.GetCurrentEQTimeOfDay(time(0), &world_time); - - auto time_string = fmt::format( - "{:02}:{:02} {} (Timezone: {:02}:{:02} {})", - ( - ((world_time.hour - 1) % 12) == 0 ? - 12 : - ((world_time.hour - 1) % 12) - ), - world_time.minute, - ( - world_time.hour >= 13 ? - "PM" : - "AM" - ), - ( - ((zone->zone_time.getEQTimeZoneHr() - 1) % 12) == 0 ? - 12 : - ((zone->zone_time.getEQTimeZoneHr() - 1) % 12) - ), - zone->zone_time.getEQTimeZoneMin(), - ( - zone->zone_time.getEQTimeZoneHr() >= 13 ? - "PM" : - "AM" - ) - ); - - c->Message( - Chat::White, - fmt::format( - "It is currently {}.", - time_string - ).c_str() - ); - - return; - } - - uint8 minutes = 0; - auto hours = static_cast(Strings::ToUnsignedInt(sep->arg[1]) + 1); - - if (hours > 24) { - hours = 24; - } - - uint8 real_hours = ( - (hours - 1) > 0 ? - (hours - 1) : - 0 - ); - - if (sep->IsNumber(2)) { - minutes = static_cast(Strings::ToUnsignedInt(sep->arg[2])); - - if (minutes > 59) { - minutes = 59; - } - } - - c->Message( - Chat::White, - fmt::format( - "Setting world time to {:02}:{:02} {} (Timezone: {:02}:{:02} {}).", - ( - (hours % 12) == 0 ? - 12 : - (hours % 12) - ), - minutes, - ( - hours >= 13 ? - "PM" : - "AM" - ), - ( - ((zone->zone_time.getEQTimeZoneHr() - 1) % 12) == 0 ? - 12 : - ((zone->zone_time.getEQTimeZoneHr() - 1) % 12) - ), - zone->zone_time.getEQTimeZoneMin(), - ( - zone->zone_time.getEQTimeZoneHr() >= 13 ? - "PM" : - "AM" - ) - ).c_str() - ); - - zone->SetTime(real_hours, minutes); - - LogInfo( - "{} :: Setting world time to {:02}:{:02} {} (Timezone: {:02}:{:02} {})", - c->GetCleanName(), - ( - (hours % 12) == 0 ? - 12 : - (hours % 12) - ), - minutes, - ( - hours >= 13 ? - "PM" : - "AM" - ), - ( - ((zone->zone_time.getEQTimeZoneHr() - 1) % 12) == 0 ? - 12 : - ((zone->zone_time.getEQTimeZoneHr() - 1) % 12) - ), - zone->zone_time.getEQTimeZoneMin(), - ( - zone->zone_time.getEQTimeZoneHr() >= 13 ? - "PM" : - "AM" - ) - ); -} - diff --git a/zone/gm_commands/timezone.cpp b/zone/gm_commands/timezone.cpp deleted file mode 100755 index 9270f1445..000000000 --- a/zone/gm_commands/timezone.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include "../client.h" - -void command_timezone(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (!arguments || !sep->IsNumber(1)) { - c->Message(Chat::White, "Usage: #timezone [Hour] [Minute]"); - c->Message( - Chat::White, - fmt::format( - "Current timezone is {:02}:{:02} {}.", - ( - ((zone->zone_time.getEQTimeZoneHr() - 1) % 12) == 0 ? - 12 : - ((zone->zone_time.getEQTimeZoneHr() - 1) % 12) - ), - zone->zone_time.getEQTimeZoneMin(), - ( - zone->zone_time.getEQTimeZoneHr() >= 13 ? - "PM" : - "AM" - ) - ).c_str() - ); - return; - } - - uint8 minutes = 0; - auto hours = static_cast(Strings::ToUnsignedInt(sep->arg[1])); - - if (hours > 24) { - hours = 24; - } - - uint8 real_hours = ( - (hours - 1) > 0 ? - (hours - 1) : - 0 - ); - - if (sep->IsNumber(2)) { - minutes = static_cast(Strings::ToUnsignedInt(sep->arg[2])); - - if (minutes > 59) { - minutes = 59; - } - } - - c->Message( - Chat::White, - fmt::format( - "Setting timezone to {:02}:{:02} {}.", - ( - (real_hours % 12) == 0 ? - 12 : - (real_hours % 12) - ), - minutes, - ( - hours >= 13 ? - "PM" : - "AM" - ) - ).c_str() - ); - - uint32 new_timezone = ((hours * 60) + minutes); - zone->zone_time.setEQTimeZone(new_timezone); - content_db.SetZoneTZ(zone->GetZoneID(), zone->GetInstanceVersion(), new_timezone); - - auto outapp = new EQApplicationPacket(OP_TimeOfDay, sizeof(TimeOfDay_Struct)); - TimeOfDay_Struct *tod = (TimeOfDay_Struct *) outapp->pBuffer; - zone->zone_time.GetCurrentEQTimeOfDay(time(0), tod); - entity_list.QueueClients(c, outapp); - safe_delete(outapp); -} - diff --git a/zone/gm_commands/title.cpp b/zone/gm_commands/title.cpp deleted file mode 100755 index 653355608..000000000 --- a/zone/gm_commands/title.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "../client.h" -#include "../titles.h" - -void command_title(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (!arguments) { - c->Message(Chat::White, "Usage: #title [Title] (use \"-1\" to remove title)"); - return; - } - - bool is_remove = !strcasecmp(sep->argplus[1], "-1"); - std::string title = is_remove ? "" : sep->argplus[1]; - - auto target = c; - if (c->GetTarget() && c->GetTarget()->IsClient()) { - target = c->GetTarget()->CastToClient(); - } - - if (title.size() > 31) { - c->Message(Chat::White, "Title must be 31 characters or less."); - return; - } - - if (!title.empty()) { - Strings::FindReplace(title, "_", " "); - } - - if (is_remove) { - target->SetAATitle(title); - } else { - title_manager.CreateNewPlayerTitle(target, title); - } - - target->Save(); - - c->Message( - Chat::White, - fmt::format( - "Title has been {}{} for {}{}", - is_remove ? "removed" : "changed", - !is_remove ? " and saved" : "", - c->GetTargetDescription(target), - ( - is_remove ? - "." : - fmt::format( - " to '{}'.", - title - ) - ) - ).c_str() - ); -} - - diff --git a/zone/gm_commands/unfreeze.cpp b/zone/gm_commands/unfreeze.cpp deleted file mode 100755 index c9658fb7b..000000000 --- a/zone/gm_commands/unfreeze.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "../client.h" - -void command_unfreeze(Client *c, const Seperator *sep) -{ - if (!c->GetTarget()) { - c->Message(Chat::White, "You must have a target to use this command."); - return; - } - - auto target = c->GetTarget(); - target->SendAppearancePacket(AT_Anim, ANIM_STAND); - - c->Message( - Chat::White, - fmt::format( - "You have unfrozen {}.", - c->GetTargetDescription(target) - ).c_str() - ); -} - diff --git a/zone/gm_commands/wc.cpp b/zone/gm_commands/wc.cpp index ada629b7f..4fc60e9be 100755 --- a/zone/gm_commands/wc.cpp +++ b/zone/gm_commands/wc.cpp @@ -19,13 +19,14 @@ void command_wc(Client *c, const Seperator *sep) t = c->GetTarget(); } - const auto slot_id = static_cast(Strings::ToUnsignedInt(sep->arg[1])); - const auto texture = static_cast(Strings::ToUnsignedInt(sep->arg[2])); - uint32 hero_forge_model = 0; - uint32 elite_material = 0; + const uint8 slot_id = Strings::ToUnsignedInt(sep->arg[1]); + const uint32 texture = Strings::ToUnsignedInt(sep->arg[2]); + uint32 hero_forge_model = 0; + uint32 elite_material = 0; if (arguments >= 3 && sep->IsNumber(3)) { hero_forge_model = Strings::ToUnsignedInt(sep->arg[3]); + if (EQ::ValueWithin(hero_forge_model, 1, 999)) { // Shorthand Hero Forge ID. Otherwise use the value the user entered. hero_forge_model = (hero_forge_model * 100) + slot_id; } @@ -35,7 +36,7 @@ void command_wc(Client *c, const Seperator *sep) elite_material = Strings::ToUnsignedInt(sep->arg[4]); } - c->GetTarget()->SendTextureWC( + t->SendTextureWC( slot_id, texture, hero_forge_model, diff --git a/zone/gm_commands/zclip.cpp b/zone/gm_commands/zclip.cpp deleted file mode 100755 index 09c7e0e64..000000000 --- a/zone/gm_commands/zclip.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include "../client.h" - -void command_zclip(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (arguments <= 3) { - c->Message( - Chat::White, - "Usage: #zclip [Minimum Clip] [Maximum Clip] [Fog Minimum Clip] [Fog Maximum Clip] [Permanent (0 = False, 1 = True)]" - ); - return; - } - - auto minimum_clip = sep->arg[1] ? Strings::ToFloat(sep->arg[1]) : 0; - auto maximum_clip = sep->arg[2] ? Strings::ToFloat(sep->arg[2]) : 0; - auto minimum_fog_clip = sep->arg[3] ? Strings::ToFloat(sep->arg[3]) : 0; - auto maximum_fog_clip = sep->arg[4] ? Strings::ToFloat(sep->arg[4]) : 0; - - auto permanent = sep->arg[5] ? atobool(sep->arg[5]) : false; - if (minimum_clip <= 0 || maximum_clip <= 0) { - c->Message(Chat::White, "Minimum Clip and Maximum Clip must be greater than 0."); - return; - } - else if (minimum_clip > maximum_clip) { - c->Message(Chat::White, "Minimum Clip must be less than or equal to Maximum Clip!"); - return; - } - else { - zone->newzone_data.minclip = minimum_clip; - zone->newzone_data.maxclip = maximum_clip; - - if (minimum_fog_clip) { - for (float &fog_index: zone->newzone_data.fog_minclip) { - fog_index = minimum_fog_clip; - } - } - - if (maximum_fog_clip) { - for (float &fog_index: zone->newzone_data.fog_maxclip) { - fog_index = maximum_fog_clip; - } - } - - if (permanent) { - auto query = fmt::format( - "UPDATE zone SET minclip = {:.2f}, maxclip = {:.2f} WHERE zoneidnumber = {} AND version = {}", - minimum_clip, - maximum_clip, - zone->GetZoneID(), - zone->GetInstanceVersion() - ); - database.QueryDatabase(query); - - if (minimum_fog_clip) { - query = fmt::format( - "UPDATE zone SET fog_minclip = {:.2f} WHERE zoneidnumber = {} AND version = {}", - minimum_fog_clip, - zone->GetZoneID(), - zone->GetInstanceVersion() - ); - database.QueryDatabase(query); - } - - if (maximum_fog_clip) { - query = fmt::format( - "UPDATE zone SET fog_maxclip = {:.2f} WHERE zoneidnumber = {} AND version = {}", - maximum_fog_clip, - zone->GetZoneID(), - zone->GetInstanceVersion() - ); - database.QueryDatabase(query); - } - } - - auto outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); - memcpy(outapp->pBuffer, &zone->newzone_data, outapp->size); - entity_list.QueueClients(c, outapp); - safe_delete(outapp); - - c->Message( - Chat::White, - fmt::format( - "Clipping Changed | Zone: {} Permanent: {}", - zone->GetZoneDescription(), - permanent ? "Yes" : "No" - ).c_str() - ); - - c->Message( - Chat::White, - fmt::format( - "Clipping Changed | Minimum Clip: {:.2f} Maximum Clip: {:.2f}", - minimum_clip, - maximum_clip - ).c_str() - ); - - if (minimum_fog_clip || maximum_fog_clip) { - c->Message( - Chat::White, - fmt::format( - "Clipping Changed | Fog Minimum Clip: {:.2f} Fog Maximum Clip: {:.2f}", - minimum_fog_clip, - maximum_fog_clip - ).c_str() - ); - } - } -} - diff --git a/zone/gm_commands/zcolor.cpp b/zone/gm_commands/zcolor.cpp deleted file mode 100755 index 9e107d1f6..000000000 --- a/zone/gm_commands/zcolor.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "../client.h" - -void command_zcolor(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if ( - !arguments || - !sep->IsNumber(1) || - !sep->IsNumber(2) || - !sep->IsNumber(3) - ) { - c->Message(Chat::White, "Usage: #zcolor [Red] [Green] [Blue] [Permanent (0 = False, 1 = True)]"); - return; - } - - auto red = Strings::ToUnsignedInt(sep->arg[1]); - auto green = Strings::ToUnsignedInt(sep->arg[2]); - auto blue = Strings::ToUnsignedInt(sep->arg[3]); - auto permanent = sep->arg[4] ? atobool(sep->arg[4]) : false; - if ( - red < 0 || - red > 255 || - green < 0 || - green > 255 || - blue < 0 || - blue > 255 - ) { - c->Message(Chat::White, "Colors cannot be less than 0 or greater than 255."); - return; - } - - if (permanent) { - auto query = fmt::format( - "UPDATE zone SET fog_red = {}, fog_green = {}, fog_blue = {} " - "WHERE zoneidnumber = {} AND version = {}", - red, - green, - blue, - zone->GetZoneID(), - zone->GetInstanceVersion() - ); - database.QueryDatabase(query); - } - - for (int fog_index = 0; fog_index < 4; fog_index++) { - zone->newzone_data.fog_red[fog_index] = static_cast(red); - zone->newzone_data.fog_green[fog_index] = static_cast(green); - zone->newzone_data.fog_blue[fog_index] = static_cast(blue); - } - - auto outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); - memcpy(outapp->pBuffer, &zone->newzone_data, outapp->size); - entity_list.QueueClients(c, outapp); - safe_delete(outapp); - - c->Message( - Chat::White, - fmt::format( - "Fog Color Changed | Zone: {} Red: {} Green: {} Blue: {} Permanent: {}", - zone->GetZoneDescription(), - red, - green, - blue, - permanent ? "Yes" : "No" - ).c_str() - ); -} diff --git a/zone/gm_commands/zheader.cpp b/zone/gm_commands/zheader.cpp deleted file mode 100755 index 2b486fb10..000000000 --- a/zone/gm_commands/zheader.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "../client.h" - -void command_zheader(Client *c, const Seperator *sep) -{ - const auto arguments = sep->argnum; - if (!arguments) { - c->Message(Chat::White, "Usage: #zheader [Zone ID|Zone Short Name] [Version]"); - return; - } - - const auto zone_id = ( - sep->IsNumber(1) ? - Strings::ToUnsignedInt(sep->arg[1]) : - ZoneID(sep->arg[1]) - ); - if (!zone_id) { - c->Message( - Chat::White, - fmt::format( - "Zone ID {} could not be found.", - zone_id - ).c_str() - ); - return; - } - - auto zone_short_name = ZoneName(zone_id); - auto zone_long_name = ZoneLongName(zone_id); - const auto version = ( - sep->IsNumber(2) ? - Strings::ToUnsignedInt(sep->arg[2]) : - 0 - ); - - auto outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); - memcpy(outapp->pBuffer, &zone->newzone_data, outapp->size); - entity_list.QueueClients(c, outapp); - safe_delete(outapp); - - zone_store.LoadZones(content_db); - - c->Message( - Chat::White, - fmt::format( - "Zone Header Load {} | Zone: {} ({}){}", - ( - zone->LoadZoneCFG(zone_short_name, version) ? - "Succeeded" : - "Failed" - ), - zone_long_name, - zone_short_name, - ( - version ? - fmt::format( - " Version: {}", - version - ) : - "" - ) - ).c_str() - ); -} diff --git a/zone/gm_commands/zonelock.cpp b/zone/gm_commands/zonelock.cpp deleted file mode 100755 index 1f0de1f0a..000000000 --- a/zone/gm_commands/zonelock.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "../client.h" -#include "../worldserver.h" - -extern WorldServer worldserver; - -void command_zonelock(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (!arguments) { - c->Message(Chat::White, "Usage: #zonelock list - Lists Locked Zones"); - if (c->Admin() >= commandLockZones) { - c->Message( - Chat::White, - "Usage: #zonelock lock [Zone ID] or #zonelock lock [Zone Short Name] - Locks a Zone by ID or Short Name" - ); - c->Message( - Chat::White, - "Usage: #zonelock unlock [Zone ID] or #zonelock unlock [Zone Short Name] - Unlocks a Zone by ID or Short Name" - ); - } - return; - } - - std::string lock_type = Strings::ToLower(sep->arg[1]); - bool is_list = lock_type.find("list") != std::string::npos; - bool is_lock = lock_type.find("lock") != std::string::npos; - bool is_unlock = lock_type.find("unlock") != std::string::npos; - if (!is_list && !is_lock && !is_unlock) { - c->Message(Chat::White, "Usage: #zonelock list - Lists Locked Zones"); - if (c->Admin() >= commandLockZones) { - c->Message( - Chat::White, - "Usage: #zonelock lock [Zone ID] or #zonelock lock [Zone Short Name] - Locks a Zone by ID or Short Name" - ); - c->Message( - Chat::White, - "Usage: #zonelock unlock [Zone ID] or #zonelock unlock [Zone Short Name] - Unlocks a Zone by ID or Short Name" - ); - } - return; - } - - auto pack = new ServerPacket(ServerOP_LockZone, sizeof(ServerLockZone_Struct)); - ServerLockZone_Struct *lock_zone = (ServerLockZone_Struct *) pack->pBuffer; - strn0cpy(lock_zone->adminname, c->GetName(), sizeof(lock_zone->adminname)); - - if (is_list) { - lock_zone->op = ServerLockType::List; - worldserver.SendPacket(pack); - } - else if (!is_list && c->Admin() >= commandLockZones) { - auto zone_id = ( - sep->IsNumber(2) ? - static_cast(Strings::ToUnsignedInt(sep->arg[2])) : - static_cast(ZoneID(sep->arg[2])) - ); - std::string zone_short_name = Strings::ToLower(ZoneName(zone_id, true)); - bool is_unknown_zone = zone_short_name.find("unknown") != std::string::npos; - if (zone_id && !is_unknown_zone) { - lock_zone->op = is_lock ? ServerLockType::Lock : ServerLockType::Unlock; - lock_zone->zoneID = zone_id; - worldserver.SendPacket(pack); - } - else { - c->Message( - Chat::White, - fmt::format( - "Usage: #zonelock {0} [Zone ID] or #zonelock {0} [Zone Short Name]", - is_lock ? "lock" : "unlock" - ).c_str() - ); - } - } - safe_delete(pack); -} - diff --git a/zone/gm_commands/zsafecoords.cpp b/zone/gm_commands/zsafecoords.cpp deleted file mode 100755 index 4f3e5be4b..000000000 --- a/zone/gm_commands/zsafecoords.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "../client.h" - -void command_zsafecoords(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if ( - !arguments || - !sep->IsNumber(1) || - !sep->IsNumber(2) || - !sep->IsNumber(3) - ) { - c->Message(Chat::White, "Usage: #zsafecoords [X] [Y] [Z] [Heading] [Permanent (0 = False, 1 = True)]"); - c->Message(Chat::White, "Not sending Heading defaults to current Heading and the change is temporary."); - return; - } - - auto x = Strings::ToFloat(sep->arg[1]); - auto y = Strings::ToFloat(sep->arg[2]); - auto z = Strings::ToFloat(sep->arg[3]); - auto heading = sep->arg[3] ? Strings::ToFloat(sep->arg[3]) : c->GetHeading(); - auto permanent = sep->arg[4] ? atobool(sep->arg[4]) : false; - if (permanent) { - auto query = fmt::format( - "UPDATE zone SET safe_x = {:.2f}, safe_y = {:.2f}, safe_z = {:.2f}, safe_heading = {:.2f} WHERE zoneidnumber = {} AND version = {}", - x, - y, - z, - heading, - zone->GetZoneID(), - zone->GetInstanceVersion() - ); - database.QueryDatabase(query); - } - - zone->newzone_data.safe_x = x; - zone->newzone_data.safe_y = y; - zone->newzone_data.safe_z = z; - - auto outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); - memcpy(outapp->pBuffer, &zone->newzone_data, outapp->size); - entity_list.QueueClients(c, outapp); - safe_delete(outapp); - - c->Message( - Chat::White, - fmt::format( - "Safe Coordinates Changed | Zone: {} XYZ: {:.2f}, {:.2f}, {:.2f} Heading: {:.2f} Permanent: {} ", - zone->GetZoneDescription(), - x, - y, - z, - heading, - permanent ? "Yes" : "No" - ).c_str() - ); -} - diff --git a/zone/gm_commands/zsky.cpp b/zone/gm_commands/zsky.cpp deleted file mode 100755 index 5802b7011..000000000 --- a/zone/gm_commands/zsky.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "../client.h" - -void command_zsky(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (!arguments || !sep->IsNumber(1)) { - c->Message(Chat::White, "Usage: #zsky [Sky Type] [Permanent (0 = False, 1 = True)]"); - return; - } - - auto sky_type = Strings::ToUnsignedInt(sep->arg[1]); - auto permanent = sep->arg[2] ? atobool(sep->arg[2]) : false; - if (sky_type < 0 || sky_type > 255) { - c->Message(Chat::White, "Sky Type cannot be less than 0 or greater than 255!"); - return; - } - - if (permanent) { - auto query = fmt::format( - "UPDATE zone SET sky = {} WHERE zoneidnumber = {} AND version = {}", - sky_type, - zone->GetZoneID(), - zone->GetInstanceVersion() - ); - database.QueryDatabase(query); - } - - zone->newzone_data.sky = static_cast(sky_type); - auto outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); - memcpy(outapp->pBuffer, &zone->newzone_data, outapp->size); - entity_list.QueueClients(c, outapp); - safe_delete(outapp); - - c->Message( - Chat::White, - fmt::format( - "Sky Changed | Zone: {} Sky Type: {} Permanent: {}", - zone->GetZoneDescription(), - sky_type, - permanent ? "Yes" : "No" - ).c_str() - ); -} diff --git a/zone/gm_commands/zunderworld.cpp b/zone/gm_commands/zunderworld.cpp deleted file mode 100755 index 8f7c8832d..000000000 --- a/zone/gm_commands/zunderworld.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "../client.h" - -void command_zunderworld(Client *c, const Seperator *sep) -{ - int arguments = sep->argnum; - if (!arguments || !sep->IsNumber(1)) { - c->Message(Chat::White, "Usage: #zunderworld [Z] [Permanent (0 = False, 1 = True)]"); - return; - } - - auto z = Strings::ToFloat(sep->arg[1]); - auto permanent = sep->arg[2] ? atobool(sep->arg[2]) : false; - if (permanent) { - auto query = fmt::format( - "UPDATE zone SET underworld = {:.2f} WHERE zoneidnumber = {} AND version = {}", - z, - zone->GetZoneID(), - zone->GetInstanceVersion() - ); - database.QueryDatabase(query); - } - - zone->newzone_data.underworld = z; - auto outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); - memcpy(outapp->pBuffer, &zone->newzone_data, outapp->size); - entity_list.QueueClients(c, outapp); - safe_delete(outapp); - - c->Message( - Chat::White, - fmt::format( - "Underworld Z Changed | Zone: {} Z: {:.2f} Permanent: {}", - zone->GetZoneDescription(), - z, - permanent ? "Yes" : "No" - ).c_str() - ); -} diff --git a/zone/inventory.cpp b/zone/inventory.cpp index 5db281eed..027d88f53 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -3135,21 +3135,6 @@ uint32 Client::GetEquippedItemFromTextureSlot(uint8 material_slot) const return 0; } -#if 0 -int32 Client::GetEquipmentMaterial(uint8 material_slot) -{ - const ItemData *item; - - item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot)); - if(item != 0) - { - return item->Material; - } - - return 0; -} -#endif - uint32 Client::GetEquipmentColor(uint8 material_slot) const { if (material_slot > EQ::textures::LastTexture) diff --git a/zone/lua_entity.cpp b/zone/lua_entity.cpp index abff39b8f..26ae9df1b 100644 --- a/zone/lua_entity.cpp +++ b/zone/lua_entity.cpp @@ -78,6 +78,21 @@ bool Lua_Entity::IsBot() { return self->IsBot(); } +bool Lua_Entity::IsAura() { + Lua_Safe_Call_Bool(); + return self->IsAura(); +} + +bool Lua_Entity::IsOfClientBot() { + Lua_Safe_Call_Bool(); + return self->IsOfClientBot(); +} + +bool Lua_Entity::IsOfClientBotMerc() { + Lua_Safe_Call_Bool(); + return self->IsOfClientBotMerc(); +} + int Lua_Entity::GetID() { Lua_Safe_Call_Bool(); return self->GetID(); @@ -138,6 +153,7 @@ luabind::scope lua_register_entity() { .def("CastToNPC", &Lua_Entity::CastToNPC) .def("CastToObject", &Lua_Entity::CastToObject) .def("GetID", &Lua_Entity::GetID) + .def("IsAura", &Lua_Entity::IsAura) .def("IsBeacon", &Lua_Entity::IsBeacon) .def("IsBot", &Lua_Entity::IsBot) .def("IsClient", &Lua_Entity::IsClient) @@ -149,6 +165,8 @@ luabind::scope lua_register_entity() { .def("IsNPC", &Lua_Entity::IsNPC) .def("IsNPCCorpse", &Lua_Entity::IsNPCCorpse) .def("IsObject", &Lua_Entity::IsObject) + .def("IsOfClientBot", &Lua_Entity::IsOfClientBot) + .def("IsOfClientBotMerc", &Lua_Entity::IsOfClientBotMerc) .def("IsPlayerCorpse", &Lua_Entity::IsPlayerCorpse) .def("IsTrap", &Lua_Entity::IsTrap); } diff --git a/zone/lua_entity.h b/zone/lua_entity.h index 5d7d5447e..0b08b8a0c 100644 --- a/zone/lua_entity.h +++ b/zone/lua_entity.h @@ -47,6 +47,9 @@ public: bool IsBeacon(); bool IsEncounter(); bool IsBot(); + bool IsAura(); + bool IsOfClientBot(); + bool IsOfClientBotMerc(); int GetID(); Lua_Client CastToClient(); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index 7d6c6e959..3eea28dbd 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -5145,8 +5145,8 @@ void lua_create_npc(luabind::adl::object table, float x, float y, float z, float LuaCreateNPCParse(max_dmg, uint32, 4); LuaCreateNPCParse(attack_count, int16, 0); LuaCreateNPCParseString(special_abilities, 512, ""); - LuaCreateNPCParse(d_melee_texture1, uint16, 0); - LuaCreateNPCParse(d_melee_texture2, uint16, 0); + LuaCreateNPCParse(d_melee_texture1, uint32, 0); + LuaCreateNPCParse(d_melee_texture2, uint32, 0); LuaCreateNPCParseString(ammo_idfile, 30, ""); LuaCreateNPCParse(prim_melee_type, uint8, 0); LuaCreateNPCParse(sec_melee_type, uint8, 0); diff --git a/zone/lua_mob.cpp b/zone/lua_mob.cpp index d707ee2eb..1db691d97 100644 --- a/zone/lua_mob.cpp +++ b/zone/lua_mob.cpp @@ -1902,17 +1902,17 @@ void Lua_Mob::SetSlotTint(int material_slot, int red_tint, int green_tint, int b self->SetSlotTint(material_slot, red_tint, green_tint, blue_tint); } -void Lua_Mob::WearChange(uint8 material_slot, uint16 texture) { +void Lua_Mob::WearChange(uint8 material_slot, uint32 texture) { Lua_Safe_Call_Void(); self->WearChange(material_slot, texture); } -void Lua_Mob::WearChange(uint8 material_slot, uint16 texture, uint32 color) { +void Lua_Mob::WearChange(uint8 material_slot, uint32 texture, uint32 color) { Lua_Safe_Call_Void(); self->WearChange(material_slot, texture, color); } -void Lua_Mob::WearChange(uint8 material_slot, uint16 texture, uint32 color, uint32 heros_forge_model) { +void Lua_Mob::WearChange(uint8 material_slot, uint32 texture, uint32 color, uint32 heros_forge_model) { Lua_Safe_Call_Void(); self->WearChange(material_slot, texture, color, heros_forge_model); } @@ -3127,6 +3127,12 @@ std::string Lua_Mob::GetRacePlural() return self->GetRacePlural(); } +bool Lua_Mob::IsTemporaryPet() +{ + Lua_Safe_Call_Bool(); + return self->IsTempPet(); +} + luabind::scope lua_register_mob() { return luabind::class_("Mob") .def(luabind::constructor<>()) @@ -3518,6 +3524,7 @@ luabind::scope lua_register_mob() { .def("IsStunned", (bool(Lua_Mob::*)(void))&Lua_Mob::IsStunned) .def("IsTargetable", (bool(Lua_Mob::*)(void))&Lua_Mob::IsTargetable) .def("IsTargeted", &Lua_Mob::IsTargeted) + .def("IsTemporaryPet", &Lua_Mob::IsTemporaryPet) .def("IsTrackable", (bool(Lua_Mob::*)(void))&Lua_Mob::IsTrackable) .def("IsWarriorClass", &Lua_Mob::IsWarriorClass) .def("Kill", (void(Lua_Mob::*)(void))&Lua_Mob::Kill) @@ -3642,9 +3649,9 @@ luabind::scope lua_register_mob() { .def("TryMoveAlong", (void(Lua_Mob::*)(float,float,bool))&Lua_Mob::TryMoveAlong) .def("UnStun", (void(Lua_Mob::*)(void))&Lua_Mob::UnStun) .def("WalkTo", (void(Lua_Mob::*)(double, double, double))&Lua_Mob::WalkTo) - .def("WearChange", (void(Lua_Mob::*)(uint8,uint16))&Lua_Mob::WearChange) - .def("WearChange", (void(Lua_Mob::*)(uint8,uint16,uint32))&Lua_Mob::WearChange) - .def("WearChange", (void(Lua_Mob::*)(uint8,uint16,uint32,uint32))&Lua_Mob::WearChange) + .def("WearChange", (void(Lua_Mob::*)(uint8,uint32))&Lua_Mob::WearChange) + .def("WearChange", (void(Lua_Mob::*)(uint8,uint32,uint32))&Lua_Mob::WearChange) + .def("WearChange", (void(Lua_Mob::*)(uint8,uint32,uint32,uint32))&Lua_Mob::WearChange) .def("WipeHateList", (void(Lua_Mob::*)(void))&Lua_Mob::WipeHateList); } diff --git a/zone/lua_mob.h b/zone/lua_mob.h index 0d5a5e1d0..320e7a3ef 100644 --- a/zone/lua_mob.h +++ b/zone/lua_mob.h @@ -386,9 +386,9 @@ public: void TarGlobal(const char *varname, const char *value, const char *duration, int npc_id, int char_id, int zone_id); void DelGlobal(const char *varname); void SetSlotTint(int material_slot, int red_tint, int green_tint, int blue_tint); - void WearChange(uint8 material_slot, uint16 texture); - void WearChange(uint8 material_slot, uint16 texture, uint32 color); - void WearChange(uint8 material_slot, uint16 texture, uint32 color, uint32 heros_forge_model); + void WearChange(uint8 material_slot, uint32 texture); + void WearChange(uint8 material_slot, uint32 texture, uint32 color); + void WearChange(uint8 material_slot, uint32 texture, uint32 color, uint32 heros_forge_model); void DoKnockback(Lua_Mob caster, uint32 push_back, uint32 push_up); void AddNimbusEffect(int effect_id); void RemoveNimbusEffect(int effect_id); @@ -556,6 +556,7 @@ public: Lua_Mob_List GetCloseMobList(float distance, bool ignore_self); std::string GetClassPlural(); std::string GetRacePlural(); + bool IsTemporaryPet(); }; #endif diff --git a/zone/merc.h b/zone/merc.h index 4b6f260fc..127d15a53 100644 --- a/zone/merc.h +++ b/zone/merc.h @@ -277,8 +277,8 @@ protected: uint16 skills[EQ::skills::HIGHEST_SKILL + 1]; uint32 equipment[EQ::invslot::EQUIPMENT_COUNT]; //this is an array of item IDs - uint16 d_melee_texture1; //this is an item Material value - uint16 d_melee_texture2; //this is an item Material value (offhand) + uint32 d_melee_texture1; //this is an item Material value + uint32 d_melee_texture2; //this is an item Material value (offhand) uint8 prim_melee_type; //Sets the Primary Weapon attack message and animation uint8 sec_melee_type; //Sets the Secondary Weapon attack message and animation diff --git a/zone/mob.cpp b/zone/mob.cpp index 8aa0a71a7..cde8f1f34 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -5425,6 +5425,14 @@ void Mob::SetTarget(Mob *mob) if (IsClient() && GetTarget()) { GetTarget()->SendHPUpdate(true); } + + if (IsOfClientBot()) { + Raid* r = GetRaid(); + if (r) { + r->UpdateRaidXTargets(); + r->SendRaidAssistTarget(); + } + } } // For when we want a Ground Z at a location we are not at yet diff --git a/zone/mob.h b/zone/mob.h index 14deb85c4..38cf03e05 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -290,15 +290,15 @@ public: EQ::skills::SkillType AttackAnimation(int Hand, const EQ::ItemInstance* weapon, EQ::skills::SkillType skillinuse = EQ::skills::Skill1HBlunt); - int32 GetTextureProfileMaterial(uint8 material_slot) const; - int32 GetTextureProfileColor(uint8 material_slot) const; - int32 GetTextureProfileHeroForgeModel(uint8 material_slot) const; + uint32 GetTextureProfileMaterial(uint8 material_slot) const; + uint32 GetTextureProfileColor(uint8 material_slot) const; + uint32 GetTextureProfileHeroForgeModel(uint8 material_slot) const; virtual void SendArmorAppearance(Client *one_client = nullptr); - virtual void SendTextureWC(uint8 slot, uint16 texture, uint32 hero_forge_model = 0, uint32 elite_material = 0, uint32 unknown06 = 0, uint32 unknown18 = 0); + virtual void SendTextureWC(uint8 slot, uint32 texture, uint32 hero_forge_model = 0, uint32 elite_material = 0, uint32 unknown06 = 0, uint32 unknown18 = 0); virtual void SendWearChange(uint8 material_slot, Client *one_client = nullptr); virtual void SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uint8 blue_tint); - virtual void WearChange(uint8 material_slot, uint16 texture, uint32 color = 0, uint32 hero_forge_model = 0); + virtual void WearChange(uint8 material_slot, uint32 texture, uint32 color = 0, uint32 hero_forge_model = 0); void ChangeSize(float in_size, bool bNoRestriction = false); void DoAnim(const int animation_id, int animation_speed = 0, bool ackreq = true, eqFilterType filter = FilterNone); @@ -308,7 +308,7 @@ public: void SendLevelAppearance(); void SendStunAppearance(); void SendTargetable(bool on, Client *specific_target = nullptr); - void SetMobTextureProfile(uint8 material_slot, uint16 texture, uint32 color = 0, uint32 hero_forge_model = 0); + void SetMobTextureProfile(uint8 material_slot, uint32 texture, uint32 color = 0, uint32 hero_forge_model = 0); //Spell void SendSpellEffect(uint32 effect_id, uint32 duration, uint32 finish_delay, bool zone_wide, @@ -503,9 +503,9 @@ public: virtual uint8 ConvertItemTypeToSkillID(uint8 item_type); virtual uint16 GetSkill(EQ::skills::SkillType skill_num) const { return 0; } virtual uint32 GetEquippedItemFromTextureSlot(uint8 material_slot) const { return(0); } - virtual int32 GetEquipmentMaterial(uint8 material_slot) const; + virtual uint32 GetEquipmentMaterial(uint8 material_slot) const; virtual uint8 GetEquipmentType(uint8 material_slot) const; - virtual int32 GetHerosForgeModel(uint8 material_slot) const; + virtual uint32 GetHerosForgeModel(uint8 material_slot) const; virtual uint32 GetEquipmentColor(uint8 material_slot) const; virtual uint32 IsEliteMaterialItem(uint8 material_slot) const; bool CanClassEquipItem(uint32 item_id); diff --git a/zone/mob_appearance.cpp b/zone/mob_appearance.cpp index 8608ee9da..1c8c157bf 100644 --- a/zone/mob_appearance.cpp +++ b/zone/mob_appearance.cpp @@ -30,18 +30,15 @@ #include "bot.h" -/** - * Stores internal representation of mob texture by material slot - * - * @param material_slot - * @param texture - * @param color - * @param hero_forge_model - */ -void Mob::SetMobTextureProfile(uint8 material_slot, uint16 texture, uint32 color, uint32 hero_forge_model) +void Mob::SetMobTextureProfile( + uint8 material_slot, + uint32 texture, + uint32 color, + uint32 hero_forge_model +) { - Log(Logs::Detail, Logs::MobAppearance, - "[%s] material_slot: %u texture: %u color: %u hero_forge_model: %u", + LogMobAppearanceDetail( + "[{}] material_slot [{}] texture [{}] color [{}] hero_forge_model [{}]", GetCleanName(), material_slot, texture, @@ -100,13 +97,7 @@ void Mob::SetMobTextureProfile(uint8 material_slot, uint16 texture, uint32 color } } -/** - * Returns internal representation of mob texture by material - * - * @param material_slot - * @return - */ -int32 Mob::GetTextureProfileMaterial(uint8 material_slot) const +uint32 Mob::GetTextureProfileMaterial(uint8 material_slot) const { switch (material_slot) { case EQ::textures::armorHead: @@ -132,13 +123,7 @@ int32 Mob::GetTextureProfileMaterial(uint8 material_slot) const } } -/** - * Returns internal representation of mob texture by color - * - * @param material_slot - * @return - */ -int32 Mob::GetTextureProfileColor(uint8 material_slot) const +uint32 Mob::GetTextureProfileColor(uint8 material_slot) const { switch (material_slot) { case EQ::textures::armorHead: @@ -164,13 +149,7 @@ int32 Mob::GetTextureProfileColor(uint8 material_slot) const } } -/** - * Returns internal representation of mob texture by HerosForgeModel - * - * @param material_slot - * @return - */ -int32 Mob::GetTextureProfileHeroForgeModel(uint8 material_slot) const +uint32 Mob::GetTextureProfileHeroForgeModel(uint8 material_slot) const { switch (material_slot) { case EQ::textures::armorHead: @@ -196,25 +175,19 @@ int32 Mob::GetTextureProfileHeroForgeModel(uint8 material_slot) const } } -/** - * Gets the material or texture for a slot (leather / plate etc.) - * - * @param material_slot - * @return - */ -int32 Mob::GetEquipmentMaterial(uint8 material_slot) const +uint32 Mob::GetEquipmentMaterial(uint8 material_slot) const { - uint32 equipment_material = 0; - int32 texture_profile_material = GetTextureProfileMaterial(material_slot); + uint32 equipment_material = 0; + const uint32 texture_profile_material = GetTextureProfileMaterial(material_slot); LogMobAppearance( - "[{}] material_slot: {} texture_profile_material: {}", + "[{}] material_slot [{}] texture_profile_material [{}]", clean_name, material_slot, texture_profile_material ); - if (texture_profile_material > 0) { + if (texture_profile_material) { return texture_profile_material; } @@ -230,7 +203,7 @@ int32 Mob::GetEquipmentMaterial(uint8 material_slot) const return 0; } - const auto* inst = CastToClient()->m_inv[inventory_slot]; + const auto inst = CastToClient()->m_inv[inventory_slot]; if (inst) { const auto augment = inst->GetOrnamentationAugment(); @@ -238,7 +211,7 @@ int32 Mob::GetEquipmentMaterial(uint8 material_slot) const if (augment) { item = augment->GetItem(); if (item && strlen(item->IDFile) > 2 && Strings::IsNumber(&item->IDFile[2])) { - equipment_material = Strings::ToInt(&item->IDFile[2]); + equipment_material = Strings::ToUnsignedInt(&item->IDFile[2]); } } else if (inst->GetOrnamentationIDFile()) { equipment_material = inst->GetOrnamentationIDFile(); @@ -247,10 +220,9 @@ int32 Mob::GetEquipmentMaterial(uint8 material_slot) const } if (!equipment_material && strlen(item->IDFile) > 2 && Strings::IsNumber(&item->IDFile[2])) { - equipment_material = Strings::ToInt(&item->IDFile[2]); + equipment_material = Strings::ToUnsignedInt(&item->IDFile[2]); } - } - else { + } else { equipment_material = item->Material; } } @@ -260,8 +232,8 @@ int32 Mob::GetEquipmentMaterial(uint8 material_slot) const uint8 Mob::GetEquipmentType(uint8 material_slot) const { - auto item_type = static_cast(EQ::item::ItemType2HBlunt); - auto item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot)); + const auto item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot)); + auto item_type = static_cast(EQ::item::ItemType2HBlunt); if (item) { const auto is_equipped_weapon = EQ::ValueWithin(material_slot, EQ::textures::weaponPrimary, EQ::textures::weaponSecondary); @@ -273,7 +245,7 @@ uint8 Mob::GetEquipmentType(uint8 material_slot) const return item_type; } - const auto* inst = CastToClient()->m_inv[inventory_slot]; + const auto inst = CastToClient()->m_inv[inventory_slot]; if (inst) { item_type = inst->GetItemType(); } @@ -284,36 +256,26 @@ uint8 Mob::GetEquipmentType(uint8 material_slot) const return item_type; } -/** - * @param material_slot - * @return - */ uint32 Mob::GetEquipmentColor(uint8 material_slot) const { - const EQ::ItemData *item = nullptr; - if (armor_tint.Slot[material_slot].Color) { return armor_tint.Slot[material_slot].Color; } - item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot)); - if (item != nullptr) { + const auto item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot)); + if (item) { return item->Color; } return 0; } -/** - * @param material_slot - * @return - */ -int32 Mob::GetHerosForgeModel(uint8 material_slot) const +uint32 Mob::GetHerosForgeModel(uint8 material_slot) const { - uint32 hero_model = 0; + uint32 heros_forge_model = 0; if (EQ::ValueWithin(material_slot, 0, EQ::textures::weaponPrimary)) { - const EQ::ItemData *item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot)); - const auto slot = EQ::InventoryProfile::CalcSlotFromMaterial(material_slot); + auto item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot)); + const auto slot = EQ::InventoryProfile::CalcSlotFromMaterial(material_slot); if (item && slot != INVALID_INDEX) { if (IsClient()) { @@ -322,33 +284,33 @@ int32 Mob::GetHerosForgeModel(uint8 material_slot) const const auto augment = inst->GetOrnamentationAugment(); if (augment) { - item = augment->GetItem(); - hero_model = item->HerosForgeModel; + item = augment->GetItem(); + heros_forge_model = item->HerosForgeModel; } else if (inst->GetOrnamentHeroModel()) { - hero_model = inst->GetOrnamentHeroModel(); + heros_forge_model = inst->GetOrnamentHeroModel(); } } } - if (hero_model == 0) { - hero_model = item->HerosForgeModel; + if (!heros_forge_model) { + heros_forge_model = item->HerosForgeModel; } } if (IsNPC()) { - hero_model = CastToNPC()->GetHeroForgeModel(); + heros_forge_model = CastToNPC()->GetHeroForgeModel(); /** * Robes require full model number, and should only be sent to chest, arms, wrists, and legs slots */ if ( - hero_model > 1000 && + heros_forge_model > 1000 && material_slot != EQ::textures::armorChest && material_slot != EQ::textures::armorArms && material_slot != EQ::textures::armorWrist && material_slot != EQ::textures::armorLegs ) { - hero_model = 0; + heros_forge_model = 0; } } } @@ -359,21 +321,21 @@ int32 Mob::GetHerosForgeModel(uint8 material_slot) const * Otherwise, use the exact Model if model is > 999 * Robes for example are 11607 to 12107 in RoF */ - if (EQ::ValueWithin(hero_model, 1, 999)) { - hero_model *= 100; - hero_model += material_slot; + if (EQ::ValueWithin(heros_forge_model, 1, 999)) { + heros_forge_model *= 100; + heros_forge_model += material_slot; } - return hero_model; + return heros_forge_model; } uint32 NPC::GetEquippedItemFromTextureSlot(uint8 material_slot) const { - if (material_slot > 8) { + if (material_slot >= EQ::textures::materialCount) { return 0; } - int16 inventory_slot = EQ::InventoryProfile::CalcSlotFromMaterial(material_slot); + const int16 inventory_slot = EQ::InventoryProfile::CalcSlotFromMaterial(material_slot); if (inventory_slot == INVALID_INDEX) { return 0; } @@ -381,10 +343,6 @@ uint32 NPC::GetEquippedItemFromTextureSlot(uint8 material_slot) const return equipment[inventory_slot]; } -/** - * NPCs typically use this function for sending appearance - * @param one_client - */ void Mob::SendArmorAppearance(Client *one_client) { /** @@ -402,114 +360,84 @@ void Mob::SendArmorAppearance(Client *one_client) if (IsPlayerRace(race)) { if (!IsClient()) { - for (uint8 i = 0; i <= EQ::textures::materialCount; ++i) { - const EQ::ItemData *item = database.GetItem(GetEquippedItemFromTextureSlot(i)); - if (item != nullptr) { - SendWearChange(i, one_client); + for (uint8 slot_id = 0; slot_id <= EQ::textures::materialCount; ++slot_id) { + const auto item = database.GetItem(GetEquippedItemFromTextureSlot(slot_id)); + if (item) { + SendWearChange(slot_id, one_client); } } } } - for (uint8 i = 0; i <= EQ::textures::materialCount; ++i) { - if (GetTextureProfileMaterial(i)) { - SendWearChange(i, one_client); + for (uint8 slot_id = 0; slot_id <= EQ::textures::materialCount; ++slot_id) { + if (GetTextureProfileMaterial(slot_id)) { + SendWearChange(slot_id, one_client); } } } -/** - * @param material_slot - * @param one_client - */ void Mob::SendWearChange(uint8 material_slot, Client *one_client) { - auto packet = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct)); - auto *wear_change = (WearChange_Struct *) packet->pBuffer; + auto packet = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct)); + auto w = (WearChange_Struct *) packet->pBuffer; Log(Logs::Detail, Logs::MobAppearance, "[%s]", GetCleanName() ); - wear_change->spawn_id = GetID(); - wear_change->material = static_cast(GetEquipmentMaterial(material_slot)); - wear_change->elite_material = IsEliteMaterialItem(material_slot); - wear_change->hero_forge_model = static_cast(GetHerosForgeModel(material_slot)); + w->spawn_id = GetID(); + w->material = static_cast(GetEquipmentMaterial(material_slot)); + w->elite_material = IsEliteMaterialItem(material_slot); + w->hero_forge_model = static_cast(GetHerosForgeModel(material_slot)); if (IsBot()) { - auto item_inst = CastToBot()->GetBotItem(EQ::InventoryProfile::CalcSlotFromMaterial(material_slot)); - if (item_inst) - wear_change->color.Color = item_inst->GetColor(); - else - wear_change->color.Color = 0; - } - else { - wear_change->color.Color = GetEquipmentColor(material_slot); + const auto item_inst = CastToBot()->GetBotItem(EQ::InventoryProfile::CalcSlotFromMaterial(material_slot)); + w->color.Color = item_inst ? item_inst->GetColor() : 0; + } else { + w->color.Color = GetEquipmentColor(material_slot); } - wear_change->wear_slot_id = material_slot; + w->wear_slot_id = material_slot; // Part of a bug fix to ensure heroforge models send to other clients in zone. - queue_wearchange_slot = wear_change->hero_forge_model ? material_slot : -1; + queue_wearchange_slot = w->hero_forge_model ? material_slot : -1; if (!one_client) { entity_list.QueueClients(this, packet); - } - else { + } else { one_client->QueuePacket(packet, false, Client::CLIENT_CONNECTED); } safe_delete(packet); } -/** - * - * @param slot - * @param texture - * @param hero_forge_model - * @param elite_material - * @param unknown06 - * @param unknown18 - */ void Mob::SendTextureWC( uint8 slot, - uint16 texture, + uint32 texture, uint32 hero_forge_model, uint32 elite_material, uint32 unknown06, uint32 unknown18 ) { - auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct)); - auto *wear_change = (WearChange_Struct *) outapp->pBuffer; + auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct)); + auto w = (WearChange_Struct *) outapp->pBuffer; - if (IsClient()) { - wear_change->color.Color = GetEquipmentColor(slot); - } - else { - wear_change->color.Color = GetArmorTint(slot); - } + w->color.Color = IsClient() ? GetEquipmentColor(slot) : GetArmorTint(slot); + w->spawn_id = GetID(); + w->material = texture; + w->wear_slot_id = slot; + w->unknown06 = unknown06; + w->elite_material = elite_material; + w->hero_forge_model = hero_forge_model; + w->unknown18 = unknown18; - wear_change->spawn_id = GetID(); - wear_change->material = texture; - wear_change->wear_slot_id = slot; - wear_change->unknown06 = unknown06; - wear_change->elite_material = elite_material; - wear_change->hero_forge_model = hero_forge_model; - wear_change->unknown18 = unknown18; - - SetMobTextureProfile(slot, texture, wear_change->color.Color, hero_forge_model); + SetMobTextureProfile(slot, texture, w->color.Color, hero_forge_model); entity_list.QueueClients(this, outapp); safe_delete(outapp); } -/** - * @param material_slot - * @param red_tint - * @param green_tint - * @param blue_tint - */ void Mob::SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uint8 blue_tint) { uint32 color; @@ -520,13 +448,13 @@ void Mob::SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uin armor_tint.Slot[material_slot].Color = color; auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct)); - auto *wc = (WearChange_Struct *) outapp->pBuffer; + auto w = (WearChange_Struct *) outapp->pBuffer; - wc->spawn_id = GetID(); - wc->material = GetEquipmentMaterial(material_slot); - wc->hero_forge_model = GetHerosForgeModel(material_slot); - wc->color.Color = color; - wc->wear_slot_id = material_slot; + w->spawn_id = GetID(); + w->material = GetEquipmentMaterial(material_slot); + w->hero_forge_model = GetHerosForgeModel(material_slot); + w->color.Color = color; + w->wear_slot_id = material_slot; SetMobTextureProfile(material_slot, texture, color); @@ -534,32 +462,25 @@ void Mob::SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uin safe_delete(outapp); } -/** - * @param material_slot - * @param texture - * @param color - * @param hero_forge_model - */ -void Mob::WearChange(uint8 material_slot, uint16 texture, uint32 color, uint32 hero_forge_model) +void Mob::WearChange( + uint8 material_slot, + uint32 texture, + uint32 color, + uint32 hero_forge_model +) { armor_tint.Slot[material_slot].Color = color; - /** - * Change internal values - */ SetMobTextureProfile(material_slot, texture, color, hero_forge_model); - /** - * Packet update - */ - auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct)); - auto *wear_change = (WearChange_Struct *) outapp->pBuffer; + auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct)); + auto w = (WearChange_Struct *) outapp->pBuffer; - wear_change->spawn_id = GetID(); - wear_change->material = texture; - wear_change->hero_forge_model = hero_forge_model; - wear_change->color.Color = color; - wear_change->wear_slot_id = material_slot; + w->spawn_id = GetID(); + w->material = texture; + w->hero_forge_model = hero_forge_model; + w->color.Color = color; + w->wear_slot_id = material_slot; entity_list.QueueClients(this, outapp); safe_delete(outapp); diff --git a/zone/npc.cpp b/zone/npc.cpp index 5b3061d0b..34eee7aad 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -1408,8 +1408,8 @@ NPC* NPC::SpawnNPC(const char* spawncommand, const glm::vec4& position, Client* npc_type->texture = Strings::ToInt(sep.arg[3]); npc_type->light = 0; npc_type->runspeed = 1.25f; - npc_type->d_melee_texture1 = Strings::ToInt(sep.arg[7]); - npc_type->d_melee_texture2 = Strings::ToInt(sep.arg[8]); + npc_type->d_melee_texture1 = Strings::ToUnsignedInt(sep.arg[7]); + npc_type->d_melee_texture2 = Strings::ToUnsignedInt(sep.arg[8]); npc_type->merchanttype = Strings::ToInt(sep.arg[9]); npc_type->bodytype = Strings::ToInt(sep.arg[10]); @@ -1789,16 +1789,16 @@ uint32 ZoneDatabase::NPCSpawnDB(uint8 command, const char* zone, uint32 zone_ver return false; } -int32 NPC::GetEquipmentMaterial(uint8 material_slot) const +uint32 NPC::GetEquipmentMaterial(uint8 material_slot) const { - int32 texture_profile_material = GetTextureProfileMaterial(material_slot); + const uint32 texture_profile_material = GetTextureProfileMaterial(material_slot); Log(Logs::Detail, Logs::MobAppearance, "[%s] material_slot: %u", clean_name, material_slot ); - if (texture_profile_material > 0) { + if (texture_profile_material) { return texture_profile_material; } @@ -1833,12 +1833,12 @@ int32 NPC::GetEquipmentMaterial(uint8 material_slot) const return d_melee_texture2; default: //they have nothing in the slot, and its not a special slot... they get nothing. - return (0); + return 0; } } //they have some loot item in this slot, pass it up to the default handler - return (Mob::GetEquipmentMaterial(material_slot)); + return Mob::GetEquipmentMaterial(material_slot); } uint32 NPC::GetMaxDamage(uint8 tlevel) @@ -2967,15 +2967,13 @@ uint32 NPC::GetSpawnPointID() const return 0; } -void NPC::NPCSlotTexture(uint8 slot, uint16 texture) +void NPC::NPCSlotTexture(uint8 slot, uint32 texture) { - if (slot == EQ::invslot::slotNeck) { + if (slot == EQ::textures::TextureSlot::weaponPrimary) { d_melee_texture1 = texture; - } - else if (slot == EQ::invslot::slotBack) { + } else if (slot == EQ::textures::TextureSlot::weaponSecondary) { d_melee_texture2 = texture; - } - else if (slot < EQ::invslot::slotShoulders) { + } else { // Reserved for texturing individual armor slots } } diff --git a/zone/npc.h b/zone/npc.h index 7aa791649..578f80649 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -350,7 +350,7 @@ public: int GetClosestWaypoint(const glm::vec3& location); uint32 GetEquippedItemFromTextureSlot(uint8 material_slot) const; // returns item id - int32 GetEquipmentMaterial(uint8 material_slot) const; + uint32 GetEquipmentMaterial(uint8 material_slot) const; void NextGuardPosition(); void SaveGuardSpot(bool ClearGuardSpot = false); @@ -452,7 +452,7 @@ public: bool GetDepop() { return p_depop; } - void NPCSlotTexture(uint8 slot, uint16 texture); // Sets new material values for slots + void NPCSlotTexture(uint8 slot, uint32 texture); // Sets new material values for slots uint32 GetAdventureTemplate() const { return adventure_template_id; } void AddSpellToNPCList(int16 iPriority, uint16 iSpellID, uint32 iType, int16 iManaCost, int32 iRecastDelay, int16 iResistAdjust, int8 min_hp, int8 max_hp); @@ -648,9 +648,9 @@ protected: uint32 equipment[EQ::invslot::EQUIPMENT_COUNT]; //this is an array of item IDs uint32 herosforgemodel; //this is the Hero Forge Armor Model (i.e 63 or 84 or 203) - uint16 d_melee_texture1; + uint32 d_melee_texture1; //this is an item Material value - uint16 d_melee_texture2; //this is an item Material value (offhand) + uint32 d_melee_texture2; //this is an item Material value (offhand) const char* ammo_idfile; //this determines projectile graphic "IT###" (see item field 'idfile') uint8 prim_melee_type; //Sets the Primary Weapon attack message and animation uint8 sec_melee_type; //Sets the Secondary Weapon attack message and animation diff --git a/zone/perl_mob.cpp b/zone/perl_mob.cpp index bb59b33a8..264b9b5b2 100644 --- a/zone/perl_mob.cpp +++ b/zone/perl_mob.cpp @@ -21,16 +21,16 @@ bool Perl_Mob_IsNPC(Mob* self) // @categories Script Utility return self->IsNPC(); } -bool Perl_Mob_IsBot(Mob* self) // @categories Script Utility -{ - return self->IsBot(); -} - bool Perl_Mob_IsMob(Mob* self) // @categories Script Utility { return self->IsMob(); } +bool Perl_Mob_IsMerc(Mob* self) // @categories Script Utility +{ + return self->IsMerc(); +} + bool Perl_Mob_IsCorpse(Mob* self) // @categories Script Utility, Corpse { return self->IsCorpse(); @@ -66,6 +66,36 @@ bool Perl_Mob_IsBeacon(Mob* self) // @categories Script Utility return self->IsBeacon(); } +bool Perl_Mob_IsEncounter(Mob* self) // @categories Script Utility +{ + return self->IsEncounter(); +} + +bool Perl_Mob_IsBot(Mob* self) // @categories Script Utility +{ + return self->IsBot(); +} + +bool Perl_Mob_IsAura(Mob* self) // @categories Script Utility +{ + return self->IsAura(); +} + +bool Perl_Mob_IsOfClientBot(Mob* self) // @categories Script Utility +{ + return self->IsOfClientBot(); +} + +bool Perl_Mob_IsOfClientBotMerc(Mob* self) // @categories Script Utility +{ + return self->IsOfClientBotMerc(); +} + +bool Perl_Mob_IsTemporaryPet(Mob* self) // @categories Script Utility +{ + return self->IsTempPet(); +} + Client* Perl_Mob_CastToClient(Mob* self) // @categories Account and Character, Script Utility { return self->CastToClient(); @@ -146,17 +176,17 @@ void Perl_Mob_SendWearChange(Mob* self, uint8_t material_slot) // @categories Sc self->SendWearChange(material_slot); } -int32_t Perl_Mob_GetEquipment(Mob* self, uint8_t material_slot) // @categories Inventory and Items +uint32_t Perl_Mob_GetEquipment(Mob* self, uint8_t material_slot) // @categories Inventory and Items { return self->GetEquippedItemFromTextureSlot(material_slot); } -int32_t Perl_Mob_GetEquipmentMaterial(Mob* self, uint8_t material_slot) // @categories Inventory and Items +uint32_t Perl_Mob_GetEquipmentMaterial(Mob* self, uint8_t material_slot) // @categories Inventory and Items { return self->GetEquipmentMaterial(material_slot); } -int32_t Perl_Mob_GetEquipmentColor(Mob* self, uint8_t material_slot) // @categories Inventory and Items +uint32_t Perl_Mob_GetEquipmentColor(Mob* self, uint8_t material_slot) // @categories Inventory and Items { return self->GetEquipmentColor(material_slot); } @@ -2032,17 +2062,17 @@ void Perl_Mob_SetSlotTint(Mob* self, uint8 material_slot, uint8 red_tint, uint8 self->SetSlotTint(material_slot, red_tint, green_tint, blue_tint); } -void Perl_Mob_WearChange(Mob* self, uint8 material_slot, uint16 texture) // @categories Script Utility +void Perl_Mob_WearChange(Mob* self, uint8 material_slot, uint32 texture) // @categories Script Utility { self->WearChange(material_slot, texture); } -void Perl_Mob_WearChange(Mob* self, uint8 material_slot, uint16 texture, uint32 color) // @categories Script Utility +void Perl_Mob_WearChange(Mob* self, uint8 material_slot, uint32 texture, uint32 color) // @categories Script Utility { self->WearChange(material_slot, texture, color); } -void Perl_Mob_WearChange(Mob* self, uint8 material_slot, uint16 texture, uint32 color, uint32 hero_forge_model) // @categories Script Utility +void Perl_Mob_WearChange(Mob* self, uint8 material_slot, uint32 texture, uint32 color, uint32 hero_forge_model) // @categories Script Utility { self->WearChange(material_slot, texture, color, hero_forge_model); } @@ -3443,6 +3473,7 @@ void perl_register_mob() package.add("IsAmnesiad", &Perl_Mob_IsAmnesiad); package.add("IsAttackAllowed", (bool(*)(Mob*, Mob*))&Perl_Mob_IsAttackAllowed); package.add("IsAttackAllowed", (bool(*)(Mob*, Mob*, bool))&Perl_Mob_IsAttackAllowed); + package.add("IsAura", &Perl_Mob_IsAura); package.add("IsBeacon", &Perl_Mob_IsBeacon); package.add("IsBeneficialAllowed", &Perl_Mob_IsBeneficialAllowed); package.add("IsBerserk", &Perl_Mob_IsBerserk); @@ -3453,6 +3484,7 @@ void perl_register_mob() package.add("IsCorpse", &Perl_Mob_IsCorpse); package.add("IsDoor", &Perl_Mob_IsDoor); package.add("IsEliteMaterialItem", &Perl_Mob_IsEliteMaterialItem); + package.add("IsEncounter", &Perl_Mob_IsEncounter); package.add("IsEngaged", &Perl_Mob_IsEngaged); package.add("IsEnraged", &Perl_Mob_IsEnraged); package.add("IsFeared", &Perl_Mob_IsFeared); @@ -3462,12 +3494,15 @@ void perl_register_mob() package.add("IsInvisible", (bool(*)(Mob*))&Perl_Mob_IsInvisible); package.add("IsInvisible", (bool(*)(Mob*, Mob*))&Perl_Mob_IsInvisible); package.add("IsMeleeDisabled", &Perl_Mob_IsMeleeDisabled); + package.add("IsMerc", &Perl_Mob_IsMerc); package.add("IsMezzed", &Perl_Mob_IsMezzed); package.add("IsMob", &Perl_Mob_IsMob); package.add("IsMoving", &Perl_Mob_IsMoving); package.add("IsNPC", &Perl_Mob_IsNPC); package.add("IsNPCCorpse", &Perl_Mob_IsNPCCorpse); package.add("IsObject", &Perl_Mob_IsObject); + package.add("IsOfClientBot", &Perl_Mob_IsOfClientBot); + package.add("IsOfClientBotMerc", &Perl_Mob_IsOfClientBotMerc); package.add("IsPausedTimer", &Perl_Mob_IsPausedTimer); package.add("IsPet", &Perl_Mob_IsPet); package.add("IsPlayerCorpse", &Perl_Mob_IsPlayerCorpse); @@ -3478,6 +3513,7 @@ void perl_register_mob() package.add("IsStunned", &Perl_Mob_IsStunned); package.add("IsTargetable", &Perl_Mob_IsTargetable); package.add("IsTargeted", &Perl_Mob_IsTargeted); + package.add("IsTemporaryPet", &Perl_Mob_IsTemporaryPet); package.add("IsTrackable", &Perl_Mob_IsTrackable); package.add("IsTrap", &Perl_Mob_IsTrap); package.add("IsWarriorClass", &Perl_Mob_IsWarriorClass); @@ -3669,9 +3705,9 @@ void perl_register_mob() package.add("TypesTempPet", (void(*)(Mob*, uint32, const char*, uint32, bool, Mob*))&Perl_Mob_TypesTempPet); package.add("TypesTempPet", (void(*)(Mob*, uint32, const char*, uint32, bool, Mob*, bool))&Perl_Mob_TypesTempPet); package.add("WalkTo", &Perl_Mob_WalkTo); - package.add("WearChange", (void(*)(Mob*, uint8, uint16))&Perl_Mob_WearChange); - package.add("WearChange", (void(*)(Mob*, uint8, uint16, uint32))&Perl_Mob_WearChange); - package.add("WearChange", (void(*)(Mob*, uint8, uint16, uint32, uint32))&Perl_Mob_WearChange); + package.add("WearChange", (void(*)(Mob*, uint8, uint32))&Perl_Mob_WearChange); + package.add("WearChange", (void(*)(Mob*, uint8, uint32, uint32))&Perl_Mob_WearChange); + package.add("WearChange", (void(*)(Mob*, uint8, uint32, uint32, uint32))&Perl_Mob_WearChange); package.add("WipeHateList", &Perl_Mob_WipeHateList); } diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index eb841555d..a60cfad0d 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -3573,7 +3573,7 @@ void QuestManager::removetitle(int titleset) { initiator->RemoveTitle(titleset); } -void QuestManager::wearchange(uint8 slot, uint16 texture, uint32 hero_forge_model /*= 0*/, uint32 elite_material /*= 0*/) +void QuestManager::wearchange(uint8 slot, uint32 texture, uint32 hero_forge_model, uint32 elite_material) { QuestManagerCurrentQuestVars(); diff --git a/zone/questmgr.h b/zone/questmgr.h index be31f4a65..6085f3ab7 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -298,7 +298,7 @@ public: bool IsRunning(); void FlyMode(GravityBehavior flymode); uint8 FactionValue(); - void wearchange(uint8 slot, uint16 texture, uint32 hero_forge_model = 0, uint32 elite_material = 0); + void wearchange(uint8 slot, uint32 texture, uint32 hero_forge_model = 0, uint32 elite_material = 0); void voicetell(const char *str, int macronum, int racenum, int gendernum); void LearnRecipe(uint32 recipe_id); void SendMail(const char *to, const char *from, const char *subject, const char *message); diff --git a/zone/raids.cpp b/zone/raids.cpp index 869bb867f..c0385167d 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -18,6 +18,8 @@ #include "../common/strings.h" #include "../common/events/player_event_logs.h" +#include "../common/repositories/raid_details_repository.h" +#include "../common/repositories/raid_members_repository.h" #include "client.h" #include "entity.h" @@ -49,6 +51,12 @@ Raid::Raid(uint32 raidID) LootType = 4; m_autohatermgr.SetOwner(nullptr, nullptr, this); + + for (int i = 0; i < MAX_NO_RAID_MAIN_ASSISTERS; i++) { + memset(main_assister_pcs[i], 0, 64); + memset(main_marker_pcs[i], 0, 64); + marked_npcs[i] = 0; + } } Raid::Raid(Client* nLeader) @@ -68,6 +76,12 @@ Raid::Raid(Client* nLeader) LootType = 4; m_autohatermgr.SetOwner(nullptr, nullptr, this); + + for (int i = 0; i < MAX_NO_RAID_MAIN_ASSISTERS; i++) { + memset(main_assister_pcs[i], 0, 64); + memset(main_marker_pcs[i], 0, 64); + marked_npcs[i] = 0; + } } Raid::~Raid() @@ -186,6 +200,9 @@ void Raid::AddMember(Client *c, uint32 group, bool rleader, bool groupleader, bo rga->instance_id = zone->GetInstanceID(); worldserver.SendPacket(pack); safe_delete(pack); + + SendAssistTarget(c); + } void Raid::AddBot(Bot* b, uint32 group, bool raid_leader, bool group_leader, bool looter) @@ -311,7 +328,7 @@ void Raid::MoveMember(const char *name, uint32 newGroup) LearnMembers(); VerifyRaid(); SendRaidMoveAll(name); - + auto pack = new ServerPacket(ServerOP_RaidChangeGroup, sizeof(ServerRaidGeneralAction_Struct)); auto* rga = (ServerRaidGeneralAction_Struct*) pack->pBuffer; strn0cpy(rga->playername, name, sizeof(rga->playername)); @@ -1133,6 +1150,15 @@ void Raid::SendRaidAdd(const char *who, Client *to) ram->isGroupLeader = m.is_group_leader; to->QueuePacket(outapp); safe_delete(outapp); + + if (IsAssister(m.member_name)) { + SendRaidAssisterTo(m.member_name, to); + } + + if (IsMarker(m.member_name)) { + SendRaidMarkerTo(m.member_name, to); + } + return; } } @@ -1156,6 +1182,15 @@ void Raid::SendRaidAddAll(const char *who) QueuePacket(outapp); safe_delete(outapp); + + if (IsAssister(m.member_name)) { + SendRaidAssister(m.member_name); + } + + if (IsMarker(m.member_name)) { + SendRaidMarker(m.member_name); + } + return; } } @@ -1280,6 +1315,7 @@ void Raid::SendBulkRaid(Client *to) SendRaidAdd(m.member_name, to); } } + SendRaidNotes(); } void Raid::QueuePacket(const EQApplicationPacket *app, bool ack_req) @@ -1634,28 +1670,17 @@ void Raid::SetRaidDetails() void Raid::GetRaidDetails() { - std::string query = StringFormat("SELECT locked, loottype, motd FROM raid_details WHERE raidid = %lu", - (unsigned long)GetID()); - auto results = database.QueryDatabase(query); - - if (!results.Success()) { + auto raid_details = RaidDetailsRepository::FindOne(database, GetID()); + if (raid_details.raidid == 0) { return; } - if (results.RowCount() == 0) { - LogError( - "Error getting raid details for raid [{}]: [{}]", - (unsigned long) GetID(), - results.ErrorMessage().c_str() - ); - return; - } - - auto row = results.begin(); - - locked = Strings::ToInt(row[0]); - LootType = Strings::ToInt(row[1]); - motd = std::string(row[2]); + locked = raid_details.locked; + LootType = raid_details.loottype; + motd = raid_details.motd; + marked_npcs[0] = raid_details.marked_npc_1; + marked_npcs[1] = raid_details.marked_npc_2; + marked_npcs[2] = raid_details.marked_npc_3; } void Raid::SaveRaidMOTD() @@ -1672,7 +1697,7 @@ bool Raid::LearnMembers() const auto query = fmt::format( "SELECT name, groupid, _class, level, " - "isgroupleader, israidleader, islooter, bot_id " + "isgroupleader, israidleader, islooter, is_marker, is_assister, bot_id, note " "FROM raid_members WHERE raidid = {} ORDER BY groupid", GetID() ); @@ -1695,6 +1720,7 @@ bool Raid::LearnMembers() members[i].member = nullptr; strn0cpy(members[i].member_name, row[0], sizeof(members[i].member_name)); + strn0cpy(members[i].note, row[10], sizeof(members[i].note)); uint32 group_id = Strings::ToUnsignedInt(row[1]); if (group_id >= MAX_RAID_GROUPS) { @@ -1704,15 +1730,16 @@ bool Raid::LearnMembers() members[i].group_number = group_id; } - members[i]._class = Strings::ToUnsignedInt(row[2]); - members[i].level = Strings::ToUnsignedInt(row[3]); + members[i]._class = Strings::ToUnsignedInt(row[2]); + members[i].level = Strings::ToUnsignedInt(row[3]); members[i].is_group_leader = Strings::ToBool(row[4]); members[i].is_raid_leader = Strings::ToBool(row[5]); - members[i].is_looter = Strings::ToBool(row[6]); - members[i].is_bot = Strings::ToBool(row[7]) > 0; + members[i].is_looter = Strings::ToBool(row[6]); + members[i].main_marker = Strings::ToUnsignedInt(row[7]); + members[i].main_assister = Strings::ToUnsignedInt(row[8]); + members[i].is_bot = Strings::ToBool(row[9]) > 0; ++i; } - return true; } @@ -1741,6 +1768,18 @@ void Raid::VerifyRaid() else { m.member = nullptr; } + + for (int i = 0; i < MAX_NO_RAID_MAIN_MARKERS; i++) { + if (m.main_marker == i + 1) { + strcpy(main_marker_pcs[i], m.member_name); + } + } + + for (int i = 0; i < MAX_NO_RAID_MAIN_ASSISTERS; i++) { + if (m.main_assister == i + 1) { + strcpy(main_assister_pcs[i], m.member_name); + } + } } if (m.is_raid_leader) { @@ -2048,7 +2087,7 @@ void Raid::QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_re if (m.is_bot) { continue; } - + if (m.member->IsClient()) { continue; } @@ -2118,9 +2157,12 @@ bool Raid::DoesAnyMemberHaveExpeditionLockout(const std::string& expedition_name Mob* Raid::GetRaidMainAssistOne() { - for (const auto& m : GetMembers()) { - if (m.is_raid_main_assist_one) { - return m.member->CastToMob(); + for (int i = MAIN_ASSIST_1_SLOT; i < MAX_NO_RAID_MAIN_ASSISTERS; i++) { + if (strlen(main_assister_pcs[i]) > 0) { + auto ma = entity_list.GetMob(main_assister_pcs[i]); + if (ma) { + return ma; + } } } return nullptr; @@ -2203,3 +2245,707 @@ void Raid::SetNewRaidLeader(uint32 i) } } } + +void Raid::SaveRaidNote(std::string who, std::string note) +{ + if (who.empty() || note.empty()) { + return; + } + + auto result = RaidMembersRepository::UpdateRaidNote(database, GetID(), note, who); + if (!result) { + LogError("Unable to update the raid note for player [{}] in guild [{}].", + who, + GetID() + ); + } +} + +std::vector Raid::GetMembersWithNotes() +{ + std::vector raid_members; + for (const auto& m : members) { + if (strlen(m.note) != 0) { + raid_members.emplace_back(m); + } + } + return raid_members; +} + +void Raid::SendRaidNotes() +{ + LearnMembers(); + VerifyRaid(); + + for (const auto& c : GetMembersWithNotes()) { + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); + auto note = (RaidGeneral_Struct*)outapp->pBuffer; + note->action = raidSetNote; + strn0cpy(note->leader_name, c.member_name, 64); + strn0cpy(note->player_name, GetLeaderName().c_str(), 64); + strn0cpy(note->note, c.note, 64); + QueuePacket(outapp); + safe_delete(outapp); + } +} +void Raid::SendRaidNotesToWorld() +{ + auto pack = new ServerPacket(ServerOP_RaidNote, sizeof(ServerRaidNote_Struct)); + auto snote = (ServerRaidNote_Struct*)pack->pBuffer; + snote->rid = GetID(); + worldserver.SendPacket(pack); + safe_delete(pack); +} + +void Raid::DelegateAbilityAssist(Mob* delegator, const char* delegatee) +{ + auto raid_delegatee = entity_list.GetRaidByName(delegatee); + if (!raid_delegatee) { + delegator->CastToClient()->MessageString(Chat::Cyan, NOT_IN_YOUR_RAID, delegatee); + return; + } + uint32 raid_delegatee_id = raid_delegatee->GetID(); + uint32 raid_delegator_id = GetID(); + if (raid_delegatee_id != raid_delegator_id) { + delegator->CastToClient()->MessageString(Chat::Cyan, NOT_IN_YOUR_RAID, delegatee); + return; + } + + auto rm = &members[GetPlayerIndex(delegatee)]; + if (!rm) { + return; + } + auto c = rm->member; + if (!c) { + return; + } + + auto slot = FindNextRaidDelegateSlot(FindNextAssisterSlot); + auto ma = rm->main_assister; + if (slot == -1 && !ma) { + delegator->CastToClient()->MessageString(Chat::Cyan, MAX_MAIN_RAID_ASSISTERS); + return; + } + + auto outapp = new EQApplicationPacket(OP_RaidDelegateAbility, sizeof(DelegateAbility_Struct)); + DelegateAbility_Struct* das = (DelegateAbility_Struct*)outapp->pBuffer; + if (ma) { + das->Action = ClearDelegate; + memset(main_assister_pcs[ma - 1], 0, 64); + rm->main_assister = DELEGATE_OFF; + auto result = RaidMembersRepository::UpdateRaidAssister( + database, + GetID(), + delegatee, + DELEGATE_OFF + ); + if (!result) { + LogError("Unable to clear raid main assister for player: [{}].", + delegatee + ); + } + } + else { + if (slot >= MAIN_ASSIST_1_SLOT) { + strcpy(main_assister_pcs[slot], delegatee); + rm->main_assister = slot + 1; + das->Action = SetDelegate; + auto result = RaidMembersRepository::UpdateRaidAssister( + database, + GetID(), + delegatee, + slot + 1 + ); + if (!result) { + LogError("Unable to set raid main assister for player: [{}] to [{}].", + delegatee, + slot + 1 + ); + } + } + } + das->DelegateAbility = RaidDelegateMainAssist; + das->MemberNumber = slot + 1; + das->EntityID = c->GetID(); + strcpy(das->Name, delegatee); + QueuePacket(outapp); + safe_delete(outapp); + UpdateRaidXTargets(); +} + +void Raid::UpdateRaidXTargets() +{ + struct AssistUpdate { + XTargetType assist_type; + XTargetType assist_target_type; + int32 slot; + }; + + std::vector assist_updates = { + AssistUpdate{.assist_type = RaidAssist1, .assist_target_type = RaidAssist1Target, .slot = MAIN_ASSIST_1_SLOT}, + AssistUpdate{.assist_type = RaidAssist2, .assist_target_type = RaidAssist2Target, .slot = MAIN_ASSIST_2_SLOT}, + AssistUpdate{.assist_type = RaidAssist3, .assist_target_type = RaidAssist3Target, .slot = MAIN_ASSIST_3_SLOT}, + }; + + for (const auto& u : assist_updates) { + if (strlen(main_assister_pcs[u.slot]) > 0) { + auto m = entity_list.GetMob(main_assister_pcs[u.slot]); + if (m) { + UpdateXTargetType(u.assist_type, m, m->GetName()); + auto n = m->GetTarget(); + if (n && n->GetHP() > 0) { + UpdateXTargetType(u.assist_target_type, n, n->GetName()); + } + else { + UpdateXTargetType(u.assist_target_type, nullptr); + } + } + } + else { + UpdateXTargetType(u.assist_type, nullptr); + UpdateXTargetType(u.assist_target_type, nullptr); + } + } + + struct MarkedUpdate { + XTargetType mark_target; + int32 slot; + }; + + std::vector marked_updates = { + MarkedUpdate{.mark_target = RaidMarkTarget1, .slot = MAIN_MARKER_1_SLOT}, + MarkedUpdate{.mark_target = RaidMarkTarget2, .slot = MAIN_MARKER_2_SLOT}, + MarkedUpdate{.mark_target = RaidMarkTarget3, .slot = MAIN_MARKER_3_SLOT}, + }; + + for (auto& u : marked_updates) { + if (marked_npcs[u.slot]) { + auto m = entity_list.GetMob(marked_npcs[u.slot]); + if (m && m->GetHP() > 0) { + UpdateXTargetType(u.mark_target, m, m->GetName()); + } + else { + UpdateXTargetType(u.mark_target, nullptr); + } + } + else { + UpdateXTargetType(u.mark_target, nullptr); + } + } +} + +void Raid::DelegateAbilityMark(Mob* delegator, const char* delegatee) +{ + auto raid_delegatee = entity_list.GetRaidByName(delegatee); + if (!raid_delegatee) { + delegator->CastToClient()->MessageString(Chat::Cyan, NOT_IN_YOUR_RAID, delegatee); + return; + } + uint32 raid_delegatee_id = raid_delegatee->GetID(); + uint32 raid_delegator_id = GetID(); + if (raid_delegatee_id != raid_delegator_id) { + delegator->CastToClient()->MessageString(Chat::Cyan, NOT_IN_YOUR_RAID, delegatee); + return; + } + + auto rm = &members[GetPlayerIndex(delegatee)]; + if (!rm) { + return; + } + auto c = rm->member; + if (!c) { + return; + } + + auto slot = FindNextRaidDelegateSlot(FindNextMarkerSlot); + auto mm = rm->main_marker; + + if (slot == -1 && !mm) { + delegator->CastToClient()->MessageString(Chat::Cyan, MAX_MAIN_RAID_MARKERS); + return; + } + + auto outapp = new EQApplicationPacket(OP_RaidDelegateAbility, sizeof(DelegateAbility_Struct)); + DelegateAbility_Struct* das = (DelegateAbility_Struct*)outapp->pBuffer; + if (mm) { + das->Action = ClearDelegate; + memset(main_marker_pcs[mm - 1], 0, 64); + rm->main_marker = DELEGATE_OFF; + auto result = RaidMembersRepository::UpdateRaidMarker( + database, + GetID(), + delegatee, + DELEGATE_OFF + ); + if (!result) { + LogError("Unable to clear rain main marker for player: [{}].", delegatee); + } + } + else { + if (slot >= 0) { + strcpy(main_marker_pcs[slot], c->GetName()); + rm->main_marker = slot + 1; + das->Action = SetDelegate; + auto result = RaidMembersRepository::UpdateRaidMarker( + database, + GetID(), + delegatee, + slot + 1 + ); + if (!result) { + LogError("Unable to set raid main marker for player: [{}] to [{}].", delegatee, slot + 1); + } + } + } + das->DelegateAbility = RaidDelegateMainMarker; + das->MemberNumber = 0; + das->EntityID = c->GetID(); + strcpy(das->Name, delegatee); + QueuePacket(outapp); + safe_delete(outapp); +} + +int Raid::FindNextRaidDelegateSlot(int option) +{ + if (option == FindNextRaidMainMarkerSlot) { + for (int i = 0; i < MAX_NO_RAID_MAIN_MARKERS; i++) { + if (strlen(main_marker_pcs[i]) == 0) { + return i; + } + } + } + else if (option == FindNextRaidMainAssisterSlot) { + for (int i = 0; i < MAX_NO_RAID_MAIN_ASSISTERS; i++) { + if (strlen(main_assister_pcs[i]) == 0) { + return i; + } + } + } + + return -1; +} + +void Raid::UpdateXTargetType(XTargetType Type, Mob *m, const char *name) +{ + for (const auto &rm: members) { + if (!rm.member || rm.is_bot || !rm.member->XTargettingAvailable()) { + continue; + } + + for (int i = 0; i < rm.member->GetMaxXTargets(); ++i) { + if (rm.member->XTargets[i].Type == Type) { + if (m) { + rm.member->XTargets[i].ID = m->GetID(); + } + else { + rm.member->XTargets[i].ID = 0; + } + + if (name) { + strncpy(rm.member->XTargets[i].Name, name, 64); + } + + rm.member->SendXTargetPacket(i, m); + } + } + } +} + +void Raid::RaidMarkNPC(Mob* mob, uint32 parameter) +{ + Client* c = mob->CastToClient(); + if (!c || !c->GetTarget() || parameter < 1 || parameter > 3) { + LogDebug("RaidMarkNPC Failed sanity checks."); + return; + } + + for (int i = 0; i < MAX_NO_RAID_MAIN_MARKERS; i++) { + auto cname = c->GetCleanName(); + if (strcasecmp(main_marker_pcs[i], cname) == 0 || strcasecmp(leadername, cname) == 0) { + marked_npcs[parameter - 1] = c->GetTarget()->GetID(); + auto result = RaidDetailsRepository::UpdateRaidMarkedNPC( + database, + GetID(), + parameter, + marked_npcs[parameter - 1] + ); + if (!result) { + LogError("Unable to set MarkedNPC{} from slot: [{}] for guild [{}].", + parameter, + parameter - 1, + GetID() + ); + } + + auto outapp = new EQApplicationPacket(OP_MarkRaidNPC, sizeof(MarkNPC_Struct)); + MarkNPC_Struct* mnpcs = (MarkNPC_Struct*)outapp->pBuffer; + mnpcs->TargetID = marked_npcs[parameter - 1]; + mnpcs->Number = parameter; + strcpy(mnpcs->Name, c->GetTarget()->GetCleanName()); + QueuePacket(outapp); + safe_delete(outapp); + UpdateXtargetMarkedNPC(); + return; + } + } + //client is not delegated the mark ability + c->MessageString(Chat::Cyan, NOT_DELEGATED_MARKER); + return; +} + +void Raid::UpdateXtargetMarkedNPC() +{ + for (int i = 0; i < MAX_MARKED_NPCS; i++) { + auto mm = entity_list.GetNPCByID(marked_npcs[i]); + if (mm) { + UpdateXTargetType(static_cast(RaidMarkTarget1 + i), mm->CastToMob(), mm->CastToMob()->GetName()); + } + else { + UpdateXTargetType(static_cast(RaidMarkTarget1 + i), nullptr); + } + } +} + +void Raid::RaidClearNPCMarks(Client* c) +{ + auto mob_id = c->GetID(); + + if (Strings::EqualFold(main_marker_pcs[MAIN_MARKER_1_SLOT], c->GetCleanName()) || + Strings::EqualFold(main_marker_pcs[MAIN_MARKER_2_SLOT], c->GetCleanName()) || + Strings::EqualFold(main_marker_pcs[MAIN_MARKER_3_SLOT], c->GetCleanName())) { + for (int i = 0; i < MAX_MARKED_NPCS; i++) { + if (marked_npcs[i]) { + auto npc_name = entity_list.GetNPCByID(marked_npcs[i])->GetCleanName(); + RaidMessageString(nullptr, Chat::Cyan, RAID_NO_LONGER_MARKED, npc_name); + } + marked_npcs[i] = 0; + auto result = RaidDetailsRepository::UpdateRaidMarkedNPC( + database, + GetID(), + i + 1, + 0 + ); + if (!result) { + LogError("Unable to clear MarkedNPC{} from slot: [{}] for guild [{}].", i + 1, i, GetID()); + } + } + + auto outapp = new EQApplicationPacket(OP_RaidClearNPCMarks, sizeof(MarkNPC_Struct)); + MarkNPC_Struct* mnpcs = (MarkNPC_Struct*)outapp->pBuffer; + mnpcs->TargetID = 0; + mnpcs->Number = 0; + QueuePacket(outapp); + safe_delete(outapp); + UpdateXtargetMarkedNPC(); + } + else { + c->MessageString(Chat::Cyan, NOT_DELEGATED_MARKER); + } +} + +void Raid::RemoveRaidDelegates(const char* delegatee) +{ + auto ma = members[GetPlayerIndex(delegatee)].main_assister; + auto mm = members[GetPlayerIndex(delegatee)].main_marker; + + if (ma) { + SendRemoveRaidXTargets(static_cast(RaidAssist1 + ma - 1)); + SendRemoveRaidXTargets(static_cast(RaidAssist1Target + ma - 1)); + DelegateAbilityAssist(leader->CastToMob(), delegatee); + } + + if (mm) { + SendRemoveRaidXTargets(static_cast(RaidMarkTarget1 + mm - 1)); + DelegateAbilityMark(leader->CastToMob(), delegatee); + } +} + +void Raid::SendRemoveAllRaidXTargets(const char* client_name) +{ + + auto c = entity_list.GetClientByName(client_name); + + for (int i = 0; i < c->GetMaxXTargets(); ++i) + { + if ((c->XTargets[i].Type == RaidAssist1) || + (c->XTargets[i].Type == RaidAssist2) || + (c->XTargets[i].Type == RaidAssist3) || + (c->XTargets[i].Type == RaidAssist1Target) || + (c->XTargets[i].Type == RaidAssist2Target) || + (c->XTargets[i].Type == RaidAssist3Target) || + (c->XTargets[i].Type == RaidMarkTarget1) || + (c->XTargets[i].Type == RaidMarkTarget2) || + (c->XTargets[i].Type == RaidMarkTarget3)) + { + c->XTargets[i].ID = 0; + c->XTargets[i].Name[0] = 0; + c->SendXTargetPacket(i, nullptr); + } + } +} + +void Raid::SendRemoveRaidXTargets(XTargetType Type) +{ + for (const auto &m: members) { + if (m.member && !m.is_bot) { + for (int i = 0; i < m.member->GetMaxXTargets(); ++i) { + if (m.member->XTargets[i].Type == Type) { + m.member->XTargets[i].ID = 0; + m.member->XTargets[i].Name[0] = 0; + m.member->SendXTargetPacket(i, nullptr); + } + } + } + } +} + +void Raid::SendRemoveAllRaidXTargets() +{ + for (const auto &m: members) { + if (m.member && !m.is_bot) { + for (int i = 0; i < m.member->GetMaxXTargets(); ++i) { + if ((m.member->XTargets[i].Type == RaidAssist1) || + (m.member->XTargets[i].Type == RaidAssist2) || + (m.member->XTargets[i].Type == RaidAssist3) || + (m.member->XTargets[i].Type == RaidAssist1Target) || + (m.member->XTargets[i].Type == RaidAssist2Target) || + (m.member->XTargets[i].Type == RaidAssist3Target) || + (m.member->XTargets[i].Type == RaidMarkTarget1) || + (m.member->XTargets[i].Type == RaidMarkTarget2) || + (m.member->XTargets[i].Type == RaidMarkTarget3)) { + m.member->XTargets[i].ID = 0; + m.member->XTargets[i].Name[0] = 0; + m.member->SendXTargetPacket(i, nullptr); + } + } + } + } +} + +// Send a packet to the entire raid notifying them of the group target selected by the Main Assist. +void Raid::SendRaidAssistTarget() +{ + uint16 assist_target_id = 0; + uint16 number = 0; + Mob* target = nullptr; + + struct AssistTypes { + MainAssistType main_assist_type_slot; + MainAssistType main_assist_number; + }; + + std::vector assist_types = { + {.main_assist_type_slot = MAIN_ASSIST_1_SLOT, .main_assist_number = MAIN_ASSIST_1}, + {.main_assist_type_slot = MAIN_ASSIST_2_SLOT, .main_assist_number = MAIN_ASSIST_2}, + {.main_assist_type_slot = MAIN_ASSIST_3_SLOT, .main_assist_number = MAIN_ASSIST_3} + }; + + for (auto &a: assist_types) { + if (strlen(main_assister_pcs[a.main_assist_type_slot]) > 0) { + auto player = entity_list.GetMob(main_assister_pcs[a.main_assist_type_slot]); + if (player) { + target = player->GetTarget(); + if (target) { + assist_target_id = target->GetID(); + number = a.main_assist_number; + break; + } + } + } + } + + if (assist_target_id) { + auto outapp = new EQApplicationPacket(OP_SetGroupTarget, sizeof(MarkNPC_Struct)); + MarkNPC_Struct* mnpcs = (MarkNPC_Struct*)outapp->pBuffer; + mnpcs->TargetID = assist_target_id; + mnpcs->Number = number; + + for (const auto& m : members) { + if (m.member && !m.is_bot) { + m.member->QueuePacket(outapp); + } + } + safe_delete(outapp); + } +} + +void Raid::SendAssistTarget(Client *c) +{ + if (!c || c->IsBot()) { + return; + } + + uint16 assist_target_id = 0; + uint16 number = 0; + Mob *target = nullptr; + + struct AssistTypes { + MainAssistType main_assist_type_slot; + MainAssistType main_assist_number; + }; + + std::vector assist_types = { + {.main_assist_type_slot = MAIN_ASSIST_1_SLOT, .main_assist_number = MAIN_ASSIST_1}, + {.main_assist_type_slot = MAIN_ASSIST_2_SLOT, .main_assist_number = MAIN_ASSIST_2}, + {.main_assist_type_slot = MAIN_ASSIST_3_SLOT, .main_assist_number = MAIN_ASSIST_3} + }; + + for (auto &a: assist_types) { + if (strlen(main_assister_pcs[a.main_assist_type_slot]) > 0) { + auto player = entity_list.GetMob(main_assister_pcs[a.main_assist_type_slot]); + if (player) { + target = player->GetTarget(); + if (target) { + assist_target_id = target->GetID(); + number = a.main_assist_number; + break; + } + } + } + } + + if (assist_target_id) { + auto outapp = new EQApplicationPacket(OP_SetGroupTarget, sizeof(MarkNPC_Struct)); + MarkNPC_Struct *mnpcs = (MarkNPC_Struct *) outapp->pBuffer; + mnpcs->TargetID = assist_target_id; + mnpcs->Number = number; + c->QueuePacket(outapp); + safe_delete(outapp); + } +} + +bool Raid::IsAssister(const char* who) +{ + for (auto & main_assister_pc : main_assister_pcs) { + if (strcasecmp(main_assister_pc, who) == 0) { + return true; + } + } + + return false; +} + +void Raid::SendRaidAssisterTo(const char* assister, Client* to) +{ + if (strlen(assister) == 0 || !to || to->IsBot()) { + return; + } + + auto mob = entity_list.GetMob(assister); + if (mob) { + auto m_id = mob->GetID(); + if (m_id) { + auto outapp = new EQApplicationPacket(OP_RaidDelegateAbility, sizeof(DelegateAbility_Struct)); + DelegateAbility_Struct* das = (DelegateAbility_Struct*)outapp->pBuffer; + das->Action = SetDelegate; + das->DelegateAbility = RaidDelegateMainAssist; + das->MemberNumber = 0; + das->EntityID = m_id; + strcpy(das->Name, assister); + to->QueuePacket(outapp); + safe_delete(outapp); + } + } +} + +void Raid::SendRaidAssister(const char* assister) +{ + if (strlen(assister) == 0) { + return; + } + + auto mob = entity_list.GetMob(assister); + + if (mob) { + auto m_id = mob->GetID(); + if (m_id) { + auto outapp = new EQApplicationPacket(OP_RaidDelegateAbility, sizeof(DelegateAbility_Struct)); + DelegateAbility_Struct* das = (DelegateAbility_Struct*)outapp->pBuffer; + das->Action = SetDelegate; + das->DelegateAbility = RaidDelegateMainAssist; + das->MemberNumber = 0; + das->EntityID = m_id; + strcpy(das->Name, assister); + QueuePacket(outapp); + safe_delete(outapp); + } + } +} +bool Raid::IsMarker(const char* who) +{ + for (int i = 0; i < MAX_NO_RAID_MAIN_MARKERS; i++) { + if (Strings::EqualFold(main_marker_pcs[i], who)) { + return 1; + } + } + return 0; +} + +void Raid::SendRaidMarkerTo(const char* marker, Client* to) +{ + if (strlen(marker) == 0 || !to || to->IsBot()) { + return; + } + + auto mob = entity_list.GetMob(marker); + if (mob) { + auto m_id = mob->GetID(); + if (m_id) { + auto outapp = new EQApplicationPacket(OP_RaidDelegateAbility, sizeof(DelegateAbility_Struct)); + DelegateAbility_Struct* das = (DelegateAbility_Struct*)outapp->pBuffer; + das->Action = SetDelegate; + das->DelegateAbility = RaidDelegateMainMarker; + das->MemberNumber = 0; + das->EntityID = m_id; + strcpy(das->Name, marker); + to->QueuePacket(outapp); + safe_delete(outapp); + } + } +} + +void Raid::SendRaidMarker(const char* marker) +{ + if (strlen(marker) == 0) { + return; + } + + auto mob = entity_list.GetMob(marker); + if (mob) { + auto m_id = mob->GetID(); + if (m_id) { + auto outapp = new EQApplicationPacket(OP_RaidDelegateAbility, sizeof(DelegateAbility_Struct)); + DelegateAbility_Struct* das = (DelegateAbility_Struct*)outapp->pBuffer; + das->Action = SetDelegate; + das->DelegateAbility = RaidDelegateMainMarker; + das->MemberNumber = 0; + das->EntityID = m_id; + strcpy(das->Name, marker); + QueuePacket(outapp); + safe_delete(outapp); + } + } +} + +void Raid::SendMarkTargets(Client* c) +{ + if (!c || c->IsBot()) { + return; + } + + for (int i = 0; i < MAX_MARKED_NPCS; i++) { + if (marked_npcs[i] > 0) { + auto marked_mob = entity_list.GetMob(marked_npcs[i]); + if (marked_mob) { + auto outapp = new EQApplicationPacket(OP_MarkRaidNPC, sizeof(MarkNPC_Struct)); + MarkNPC_Struct* mnpcs = (MarkNPC_Struct*)outapp->pBuffer; + mnpcs->TargetID = marked_npcs[i]; + mnpcs->Number = i + 1; + strcpy(mnpcs->Name, marked_mob->GetCleanName()); + QueuePacket(outapp); + safe_delete(outapp); + } + } + } + UpdateXtargetMarkedNPC(); +} diff --git a/zone/raids.h b/zone/raids.h index 5b73ce063..551b1fcaa 100644 --- a/zone/raids.h +++ b/zone/raids.h @@ -21,6 +21,7 @@ #include "../common/types.h" #include "groups.h" #include "xtargetautohaters.h" +#include "client.h" class Client; class EQApplicationPacket; @@ -75,9 +76,46 @@ enum { //raid command types RaidCommandSetNote = 36, }; +enum { + FindNextMarkerSlot = 1, + FindNextAssisterSlot = 2, + RaidDelegateMainAssist = 3, + RaidDelegateMainMarker = 4 +}; + +typedef enum { + MAIN_ASSIST_1_SLOT = 0, + MAIN_ASSIST_2_SLOT = 1, + MAIN_ASSIST_3_SLOT = 2, + MAIN_ASSIST_1 = 1, + MAIN_ASSIST_2 = 2, + MAIN_ASSIST_3 = 3, +} MainAssistType; + +typedef enum { + MAIN_MARKER_1_SLOT = 0, + MAIN_MARKER_2_SLOT = 1, + MAIN_MARKER_3_SLOT = 2, + MAIN_MARKER_1 = 1, + MAIN_MARKER_2 = 2, + MAIN_MARKER_3 = 3, +} MainMarkerType; + +enum { + ClearDelegate = 1, + SetDelegate = 0, + FindNextRaidMainMarkerSlot = 1, + FindNextRaidMainAssisterSlot = 2, + DELEGATE_OFF = 0, + DELEGATE_ON = 1 +}; + + constexpr uint8_t MAX_RAID_GROUPS = 12; constexpr uint8_t MAX_RAID_MEMBERS = 72; const uint32 RAID_GROUPLESS = 0xFFFFFFFF; +#define MAX_NO_RAID_MAIN_ASSISTERS 3 +#define MAX_NO_RAID_MAIN_MARKERS 3 struct RaidMember{ char member_name[64]; @@ -85,9 +123,12 @@ struct RaidMember{ uint32 group_number; uint8 _class; uint8 level; + char note[64]; bool is_group_leader; bool is_raid_leader; bool is_looter; + uint8 main_marker; + uint8 main_assister; bool is_bot = false; bool is_raid_main_assist_one = false; }; @@ -131,6 +172,8 @@ public: bool IsRaidMember(Client *c); void UpdateLevel(const char *name, int newLevel); void SetNewRaidLeader(uint32 i); + bool IsAssister(const char* who); + bool IsMarker(const char* who); uint32 GetFreeGroup(); uint8 GroupCount(uint32 gid); @@ -188,6 +231,17 @@ public: void SendEndurancePacketFrom(Mob *mob); void RaidSay(const char *msg, Client *c, uint8 language, uint8 lang_skill); void RaidGroupSay(const char *msg, Client *c, uint8 language, uint8 lang_skill); + void SaveRaidNote(std::string who, std::string note); + std::vector GetMembersWithNotes(); + void DelegateAbilityAssist(Mob* mob, const char* who); + void DelegateAbilityMark(Mob* mob, const char* who); + void RaidMarkNPC(Mob* mob, uint32 parameter); + void UpdateXTargetType(XTargetType Type, Mob* m, const char* name = (const char*)nullptr); + int FindNextRaidDelegateSlot(int option); + void UpdateXtargetMarkedNPC(); + void RaidClearNPCMarks(Client* c); + void RemoveRaidDelegates(const char* delegatee); + void UpdateRaidXTargets(); //Packet Functions void SendRaidCreate(Client *to); @@ -200,7 +254,13 @@ public: void SendRaidMove(const char* who, Client *to); void SendRaidMoveAll(const char* who); void SendBulkRaid(Client *to); - + void SendRaidNotes(); + void SendRaidNotesToWorld(); + void SendRemoveRaidXTargets(XTargetType Type); + void SendRemoveAllRaidXTargets(); + void SendRemoveAllRaidXTargets(const char* client_name); + void SendRaidAssistTarget(); + void SendAssistTarget(Client* c); void GroupUpdate(uint32 gid, bool initial = true); void SendGroupUpdate(Client *to); void SendGroupDisband(Client *to); @@ -218,6 +278,11 @@ public: void SendRaidMOTD(Client *c); void SendRaidMOTD(); void SendRaidMOTDToWorld(); + void SendRaidAssisterTo(const char* assister, Client* to); + void SendRaidAssister(const char* assister); + void SendRaidMarkerTo(const char* marker, Client* to); + void SendRaidMarker(const char* marker); + void SendMarkTargets(Client* c); void QueuePacket(const EQApplicationPacket *app, bool ack_req = true); @@ -259,6 +324,9 @@ public: RaidMember members[MAX_RAID_MEMBERS]; char leadername[64]; + char main_assister_pcs[MAX_NO_RAID_MAIN_ASSISTERS][64]; + char main_marker_pcs[MAX_NO_RAID_MAIN_MARKERS][64]; + uint32 marked_npcs[MAX_MARKED_NPCS]; protected: Client *leader; bool locked; diff --git a/zone/string_ids.h b/zone/string_ids.h index 208fc030b..1ab51ab40 100644 --- a/zone/string_ids.h +++ b/zone/string_ids.h @@ -368,6 +368,7 @@ #define PETITION_DELETED 5054 //Your petition was successfully deleted. #define ALREADY_IN_RAID 5060 //%1 is already in a raid. #define ALREADY_IN_YOUR_RAID 5077 //%1 is already in your raid. +#define NOT_IN_YOUR_RAID 5082 //%1 is not in your raid. #define GAIN_RAIDEXP 5085 //You gained raid experience! #define DUNGEON_SEALED 5141 //The gateway to the dungeon is sealed off to you. Perhaps you would be able to enter if you needed to adventure there. #define ADVENTURE_COMPLETE 5147 //You received %1 points for successfully completing the adventure. @@ -433,9 +434,13 @@ #define LEADERSHIP_EXP_ON 8653 // #define LEADERSHIP_EXP_OFF 8654 // #define CURRENT_SPELL_EFFECTS 8757 //%1's current spell effects: +#define MAX_MAIN_RAID_ASSISTERS 8782 //Max number of main assists reached (3) +#define MAX_MAIN_RAID_MARKERS 8783 //Max number of main markers reached (3) +#define NOT_DELEGATED_MARKER 8794 //You have not been delegated Raid Mark #define GAIN_GROUP_LEADERSHIP_EXP 8788 // #define GAIN_RAID_LEADERSHIP_EXP 8789 // #define BUFF_MINUTES_REMAINING 8799 //%1 (%2 minutes remaining) +#define RAID_NO_LONGER_MARKED 8801 //%1 is no longer marked #define YOU_HAVE_BEEN_GIVEN 8994 //You have been given: %1 #define NO_MORE_TRAPS 9002 //You have already placed your maximum number of traps. #define FEAR_TOO_HIGH 9035 //Your target is too high of a level for your fear spell. diff --git a/zone/tradeskills.cpp b/zone/tradeskills.cpp index e654f4828..fc4635804 100644 --- a/zone/tradeskills.cpp +++ b/zone/tradeskills.cpp @@ -389,6 +389,7 @@ void Object::HandleCombine(Client* user, const NewCombine_Struct* in_combine, Ob } DBTradeskillRecipe_Struct spec; + bool is_augmented = false; if (parse->PlayerHasQuestSub(EVENT_COMBINE)) { if (parse->EventPlayer(EVENT_COMBINE, user, std::to_string(in_combine->container_slot), 0) == 1) { @@ -399,11 +400,16 @@ void Object::HandleCombine(Client* user, const NewCombine_Struct* in_combine, Ob } } - if (!content_db.GetTradeRecipe(container, c_type, some_id, user->CharacterID(), &spec)) { + if (!content_db.GetTradeRecipe(container, c_type, some_id, user, &spec, &is_augmented)) { LogTradeskillsDetail("Check 2"); - user->MessageString(Chat::Emote,TRADESKILL_NOCOMBINE); + if (!is_augmented) { + user->MessageString(Chat::Emote, TRADESKILL_NOCOMBINE); + } else { + user->Message(Chat::Emote, "You must remove augments from all component items before you can attempt this combine."); + } + auto outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0); user->QueuePacket(outapp); safe_delete(outapp); @@ -592,7 +598,7 @@ void Object::HandleAutoCombine(Client* user, const RecipeAutoCombine_Struct* rac //ask the database for the recipe to make sure it exists... DBTradeskillRecipe_Struct spec; - if (!content_db.GetTradeRecipe(rac->recipe_id, rac->object_type, rac->some_id, user->CharacterID(), &spec)) { + if (!content_db.GetTradeRecipe(rac->recipe_id, rac->object_type, rac->some_id, user, &spec)) { LogError("Unknown recipe for HandleAutoCombine: [{}]\n", rac->recipe_id); user->QueuePacket(outapp); safe_delete(outapp); @@ -1231,25 +1237,28 @@ void Client::CheckIncreaseTradeskill(int16 bonusstat, int16 stat_modifier, float } bool ZoneDatabase::GetTradeRecipe( - const EQ::ItemInstance *container, + const EQ::ItemInstance* container, uint8 c_type, uint32 some_id, - uint32 char_id, - DBTradeskillRecipe_Struct *spec + Client* c, + DBTradeskillRecipe_Struct* spec, + bool* is_augmented ) { - if (container == nullptr) { - LogTradeskills("Container null"); + if (!container) { return false; } - std::string containers;// make where clause segment for container(s) - if (some_id == 0) { - containers = StringFormat("= %u", c_type); // world combiner so no item number + if (!c) { + return false; + } + + std::string containers; // make where clause segment for container(s) + if (!some_id) { // world combiner so no item number + containers = fmt::format("= {}", c_type); + } else { // container in inventory + containers = fmt::format("IN ({}, {})", c_type, some_id); } - else { - containers = StringFormat("IN (%u,%u)", c_type, some_id); - } // container in inventory //Could prolly watch for stacks in this loop and handle them properly... //just increment sum and count accordingly @@ -1257,26 +1266,31 @@ bool ZoneDatabase::GetTradeRecipe( std::string buf2; uint32 count = 0; uint32 sum = 0; - for (uint8 i = 0; i < 10; i++) { // TODO: need to determine if this is bound to world/item container size - LogTradeskills("Fetching item [{}]", i); - const EQ::ItemInstance *inst = container->GetItem(i); + for (uint8 slot_id = EQ::invbag::SLOT_BEGIN; slot_id < EQ::invbag::SLOT_COUNT; slot_id++) { // TODO: need to determine if this is bound to world/item container size + LogTradeskills("Fetching item [{}]", slot_id); + + const auto inst = container->GetItem(slot_id); if (!inst) { continue; } - const EQ::ItemData *item = database.GetItem(inst->GetItem()->ID); + if (inst->IsAugmented()) { + *is_augmented = true; + return false; + } + + const auto item = database.GetItem(inst->GetItem()->ID); if (!item) { LogTradeskills("item [{}] not found!", inst->GetItem()->ID); continue; } if (first) { - buf2 += StringFormat("%d", item->ID); + buf2 += fmt::format("{}", item->ID); first = false; - } - else { - buf2 += StringFormat(",%d", item->ID); + } else { + buf2 += fmt::format(", {}", item->ID); } sum += item->ID; @@ -1284,99 +1298,110 @@ bool ZoneDatabase::GetTradeRecipe( LogTradeskills( "Item in container index [{}] item [{}] found [{}]", - i, + slot_id, item->ID, count ); } - //no items == no recipe - if (count == 0) { + // no items == no recipe + if (!count) { return false; } - std::string query = StringFormat("SELECT tre.recipe_id " - "FROM tradeskill_recipe_entries AS tre " - "INNER JOIN tradeskill_recipe AS tr ON (tre.recipe_id = tr.id) " - "WHERE tr.enabled AND (( tre.item_id IN(%s) AND tre.componentcount > 0) " - "OR ( tre.item_id %s AND tre.iscontainer=1 ))" - "GROUP BY tre.recipe_id HAVING sum(tre.componentcount) = %u " - "AND sum(tre.item_id * tre.componentcount) = %u", - buf2.c_str(), containers.c_str(), count, sum); - auto results = QueryDatabase(query); + std::string query = fmt::format( + "SELECT tre.recipe_id FROM tradeskill_recipe_entries AS tre " + "INNER JOIN tradeskill_recipe AS tr ON (tre.recipe_id = tr.id) " + "WHERE tr.enabled AND ((tre.item_id IN ({}) AND tre.componentcount > 0) " + "OR (tre.item_id {} AND tre.iscontainer = 1))" + "GROUP BY tre.recipe_id HAVING SUM(tre.componentcount) = {} " + "AND SUM(tre.item_id * tre.componentcount) = {}", + buf2, + containers, + count, + sum + ); + + auto results = QueryDatabase(query); if (!results.Success()) { - LogError("Error in GetTradeRecipe search, query: [{}]", query.c_str()); - LogError("Error in GetTradeRecipe search, error: [{}]", results.ErrorMessage().c_str()); + LogError("Error in search, query: [{}]", query.c_str()); + LogError("Error in search, error: [{}]", results.ErrorMessage().c_str()); return false; } - if (results.RowCount() > 1) { - //multiple recipes, partial match... do an extra query to get it exact. - //this happens when combining components for a smaller recipe - //which is completely contained within another recipe - first = true; - uint32 index = 0; - buf2 = ""; - for (auto row = results.begin(); row != results.end(); ++row, ++index) { - uint32 recipeid = (uint32)Strings::ToInt(row[0]); - if(first) { - buf2 += StringFormat("%u", recipeid); - first = false; - } else - buf2 += StringFormat(",%u", recipeid); - - //length limit on buf2 - if(index == 214) { //Maximum number of recipe matches (19 * 215 = 4096) - LogError("GetTradeRecipe warning: Too many matches. Unable to search all recipe entries. Searched [{}] of [{}] possible entries", index + 1, results.RowCount()); - break; - } - } - - query = StringFormat("SELECT tre.recipe_id " - "FROM tradeskill_recipe_entries AS tre " - "WHERE tre.recipe_id IN (%s) " - "GROUP BY tre.recipe_id HAVING sum(tre.componentcount) = %u " - "AND sum(tre.item_id * tre.componentcount) = %u", buf2.c_str(), count, sum - ); - results = QueryDatabase(query); - if (!results.Success()) { - LogError("Error in GetTradeRecipe, re-query: [{}]", query.c_str()); - LogError("Error in GetTradeRecipe, error: [{}]", results.ErrorMessage().c_str()); - return false; - } - } - - if (results.RowCount() < 1) - return false; - if (results.RowCount() > 1) { - //The recipe is not unique, so we need to compare the container were using. - uint32 containerId = 0; + //multiple recipes, partial match... do an extra query to get it exact. + //this happens when combining components for a smaller recipe + //which is completely contained within another recipe + first = true; + uint32 index = 0; + buf2 = ""; + for (auto row : results) { + const uint32 recipe_id = Strings::ToUnsignedInt(row[0]); + if (first) { + buf2 += fmt::format("{}", recipe_id); + first = false; + } else { + buf2 += fmt::format(", {}", recipe_id); + } - if (some_id) { //Standard container - containerId = some_id; - } - else if (c_type) {//World container - containerId = c_type; - } - else { //Invalid container - return false; + // length limit on buf2 + if (index == 214) { // Maximum number of recipe matches (19 * 215 = 4096) + LogError( + "Warning: Too many matches. Unable to search all recipe entries. Searched [{}] of [{}] possible entries", + index + 1, + results.RowCount()); + break; + } + + ++index; } - query = StringFormat( - "SELECT tre.recipe_id " - "FROM tradeskill_recipe_entries AS tre " - "WHERE tre.recipe_id IN (%s) " - "AND tre.item_id = %u;", buf2.c_str(), containerId + query = fmt::format( + "SELECT tre.recipe_id FROM tradeskill_recipe_entries AS tre " + "WHERE tre.recipe_id IN ({}) GROUP BY tre.recipe_id HAVING sum(tre.componentcount) = {} " + "AND sum(tre.item_id * tre.componentcount) = {}", + buf2, + count, + sum ); results = QueryDatabase(query); if (!results.Success()) { - LogError("Error in GetTradeRecipe, re-query: [{}]", query.c_str()); - LogError("Error in GetTradeRecipe, error: [{}]", results.ErrorMessage().c_str()); + LogError("Re-query: [{}]", query.c_str()); + LogError("Error: [{}]", results.ErrorMessage().c_str()); + return false; + } + } + + if (results.RowCount() < 1) { + return false; + } + + if (results.RowCount() > 1) { //The recipe is not unique, so we need to compare the container were using. + uint32 container_item_id = 0; + + if (some_id) { // Standard container + container_item_id = some_id; + } else if (c_type) { // World container + container_item_id = c_type; + } else { // Invalid container return false; } - if (results.RowCount() == 0) { //Recipe contents matched more than 1 recipe, but not in this container + query = fmt::format( + "SELECT tre.recipe_id FROM tradeskill_recipe_entries AS tre WHERE tre.recipe_id IN ({}) AND tre.item_id = {}", + buf2, + container_item_id + ); + + results = QueryDatabase(query); + if (!results.Success()) { + LogError("Re-query: [{}]", query); + LogError("Error: [{}]", results.ErrorMessage()); + return false; + } + + if (!results.RowCount()) { //Recipe contents matched more than 1 recipe, but not in this container LogError("Combine error: Incorrect container is being used!"); return false; } @@ -1385,44 +1410,47 @@ bool ZoneDatabase::GetTradeRecipe( LogError( "Combine error: Recipe is not unique! [{}] matches found for container [{}]. Continuing with first recipe match", results.RowCount(), - containerId + container_item_id ); } } auto row = results.begin(); - uint32 recipe_id = (uint32)Strings::ToInt(row[0]); + const uint32 recipe_id = Strings::ToUnsignedInt(row[0]); //Right here we verify that we actually have ALL of the tradeskill components.. //instead of part which is possible with experimentation. //This is here because something's up with the query above.. it needs to be rethought out - bool has_components = true; - query = StringFormat("SELECT item_id, componentcount " - "FROM tradeskill_recipe_entries " - "WHERE recipe_id = %i AND componentcount > 0", - recipe_id); - results = QueryDatabase(query); - if (!results.Success()) { - return GetTradeRecipe(recipe_id, c_type, some_id, char_id, spec); - } + query = fmt::format( + "SELECT item_id, componentcount FROM tradeskill_recipe_entries WHERE componentcount > 0 AND recipe_id = {}", + recipe_id + ); - if (results.RowCount() == 0) { - return GetTradeRecipe(recipe_id, c_type, some_id, char_id, spec); + results = QueryDatabase(query); + if (!results.Success() || !results.RowCount()) { + return GetTradeRecipe(recipe_id, c_type, some_id, c, spec); } - for (auto row = results.begin(); row != results.end(); ++row) { + for (auto row : results) { int component_count = 0; - for (int x = EQ::invbag::SLOT_BEGIN; x < EQ::invtype::WORLD_SIZE; x++) { - const EQ::ItemInstance* inst = container->GetItem(x); - if(!inst) - continue; + for (uint8 slot_id = EQ::invbag::SLOT_BEGIN; slot_id < EQ::invtype::WORLD_SIZE; slot_id++) { + const auto inst = container->GetItem(slot_id); + if (!inst) { + continue; + } - const EQ::ItemData* item = database.GetItem(inst->GetItem()->ID); - if (!item) - continue; + if (inst->IsAugmented()) { + *is_augmented = true; + return false; + } - if (item->ID == Strings::ToInt(row[0])) { + const auto item = database.GetItem(inst->GetItem()->ID); + if (!item) { + continue; + } + + if (item->ID == Strings::ToUnsignedInt(row[0])) { component_count++; } @@ -1439,29 +1467,30 @@ bool ZoneDatabase::GetTradeRecipe( } } - return GetTradeRecipe(recipe_id, c_type, some_id, char_id, spec); + return GetTradeRecipe(recipe_id, c_type, some_id, c, spec); } bool ZoneDatabase::GetTradeRecipe( uint32 recipe_id, uint8 c_type, uint32 some_id, - uint32 char_id, - DBTradeskillRecipe_Struct *spec + Client* c, + DBTradeskillRecipe_Struct* spec ) { - std::string container_where_filter; - if (some_id == 0) { - // world combiner so no item number - container_where_filter = StringFormat("= %u", c_type); - } - else { - // container in inventory - container_where_filter = StringFormat("IN (%u,%u)", c_type, some_id); + if (!c) { + return false; } - std::string query = StringFormat( - SQL ( + std::string container_where_filter; + if (!some_id) { // world combiner so no item number + container_where_filter = fmt::format("= {}", c_type); + } else { // container in inventory + container_where_filter = fmt::format("IN ({}, {})", c_type, some_id); + } + + std::string query = fmt::format( + SQL( SELECT tradeskill_recipe.id, tradeskill_recipe.tradeskill, @@ -1476,85 +1505,91 @@ bool ZoneDatabase::GetTradeRecipe( tradeskill_recipe INNER JOIN tradeskill_recipe_entries ON tradeskill_recipe.id = tradeskill_recipe_entries.recipe_id WHERE - tradeskill_recipe.id = %lu - AND tradeskill_recipe_entries.item_id %s + tradeskill_recipe.id = {} + AND tradeskill_recipe_entries.item_id {} AND tradeskill_recipe.enabled GROUP BY tradeskill_recipe.id - ) - , - (unsigned long) recipe_id, - container_where_filter.c_str() + ), + recipe_id, + container_where_filter ); - auto results = QueryDatabase(query); + auto results = QueryDatabase(query); if (!results.Success()) { - LogError("Error in GetTradeRecipe, query: [{}]", query.c_str()); - LogError("Error in GetTradeRecipe, error: [{}]", results.ErrorMessage().c_str()); + LogError("Error, query: [{}]", query.c_str()); + LogError("Error: [{}]", results.ErrorMessage().c_str()); return false; } - if (results.RowCount() != 1) { + if (!results.RowCount()) { return false; } auto row = results.begin(); - spec->tradeskill = (EQ::skills::SkillType) Strings::ToInt(row[1]); - spec->skill_needed = (int16) Strings::ToInt(row[2]); - spec->trivial = (uint16) Strings::ToInt(row[3]); - spec->nofail = Strings::ToInt(row[4]) ? true : false; - spec->replace_container = Strings::ToInt(row[5]) ? true : false; + spec->tradeskill = static_cast(Strings::ToUnsignedInt(row[1])); + spec->skill_needed = Strings::ToInt(row[2]); + spec->trivial = Strings::ToUnsignedInt(row[3]); + spec->nofail = Strings::ToBool(row[4]); + spec->replace_container = Strings::ToBool(row[5]); spec->name = row[6]; - spec->must_learn = (uint8) Strings::ToInt(row[7]); - spec->quest = Strings::ToInt(row[8]) ? true : false; + spec->must_learn = Strings::ToUnsignedInt(row[7]); + spec->quest = Strings::ToBool(row[8]); spec->has_learnt = false; spec->madecount = 0; spec->recipe_id = recipe_id; auto r = CharRecipeListRepository::GetWhere( database, - fmt::format("char_id = {} and recipe_id = {}", char_id, recipe_id) + fmt::format( + "char_id = {} and recipe_id = {}", + c->CharacterID(), + recipe_id + ) ); if (!r.empty() && r[0].recipe_id) { //If this exists we learned it LogTradeskills("made_count [{}]", r[0].madecount); spec->has_learnt = true; - spec->madecount = (uint32) r[0].madecount; + spec->madecount = static_cast(r[0].madecount); } //Pull the on-success items... - query = StringFormat("SELECT item_id,successcount FROM tradeskill_recipe_entries " - "WHERE successcount > 0 AND recipe_id = %u", recipe_id); - results = QueryDatabase(query); + query = fmt::format( + "SELECT item_id, successcount FROM tradeskill_recipe_entries WHERE successcount > 0 AND recipe_id = {}", + recipe_id + ); + results = QueryDatabase(query); if (!results.Success()) { return false; } - if(results.RowCount() < 1 && !spec->quest) { - LogError("Error in GetTradeRecept success: no success items returned"); + if (!results.RowCount() && !spec->quest) { + LogError("Error in success: no success items returned"); return false; } spec->onsuccess.clear(); - for(auto row = results.begin(); row != results.end(); ++row) { - uint32 item = (uint32)Strings::ToInt(row[0]); - uint8 num = (uint8) Strings::ToInt(row[1]); - spec->onsuccess.emplace_back(std::pair(item, num)); + for(auto row : results) { + const uint32 item_id = Strings::ToUnsignedInt(row[0]); + const uint8 success_count = Strings::ToUnsignedInt(row[1]); + spec->onsuccess.emplace_back(std::pair(item_id, success_count)); } - spec->onfail.clear(); + spec->onfail.clear(); + //Pull the on-fail items... - query = StringFormat( - "SELECT item_id, failcount FROM tradeskill_recipe_entries " - "WHERE failcount > 0 AND recipe_id = %u", recipe_id + query = fmt::format( + "SELECT item_id, failcount FROM tradeskill_recipe_entries WHERE failcount > 0 AND recipe_id = {}", + recipe_id ); results = QueryDatabase(query); if (results.Success()) { - for (auto row = results.begin(); row != results.end(); ++row) { - uint32 item = (uint32) Strings::ToInt(row[0]); - uint8 num = (uint8) Strings::ToInt(row[1]); - spec->onfail.emplace_back(std::pair(item, num)); + for (auto row : results) { + const uint32 item_id = Strings::ToUnsignedInt(row[0]); + const uint8 fail_count = Strings::ToUnsignedInt(row[1]); + spec->onfail.emplace_back(std::pair(item_id, fail_count)); } } @@ -1566,18 +1601,17 @@ bool ZoneDatabase::GetTradeRecipe( } // Pull the salvage list - query = StringFormat( - "SELECT item_id, salvagecount " - "FROM tradeskill_recipe_entries " - "WHERE salvagecount > 0 AND recipe_id = %u", recipe_id + query = fmt::format( + "SELECT item_id, salvagecount FROM tradeskill_recipe_entries WHERE salvagecount > 0 AND recipe_id = {}", + recipe_id ); results = QueryDatabase(query); if (results.Success()) { - for (auto row = results.begin(); row != results.end(); ++row) { - uint32 item = (uint32) Strings::ToInt(row[0]); - uint8 num = (uint8) Strings::ToInt(row[1]); - spec->salvage.emplace_back(std::pair(item, num)); + for (auto row : results) { + const uint32 item_id = Strings::ToUnsignedInt(row[0]); + const uint8 salvage_count = Strings::ToUnsignedInt(row[1]); + spec->salvage.emplace_back(std::pair(item_id, salvage_count)); } } diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index 09ab02a74..8af0eb378 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -1548,6 +1548,16 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) r->SendRaidMOTD(); break; } + case ServerOP_RaidNote: { + auto snote = (ServerRaidNote_Struct*)pack->pBuffer; + if (snote->rid > 0) { + Raid* r = entity_list.GetRaidByID(snote->rid); + if (r) { + r->SendRaidNotes(); + } + } + break; + } case ServerOP_SpawnPlayerCorpse: { SpawnPlayerCorpse_Struct* s = (SpawnPlayerCorpse_Struct*)pack->pBuffer; Corpse* NewCorpse = database.LoadCharacterCorpse(s->player_corpse_id); diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index f9cb3a310..995fa0439 100755 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -687,7 +687,7 @@ bool ZoneDatabase::LoadCharacterData(uint32 character_id, PlayerProfile_Struct* pp->ldon_points_ruj = Strings::ToInt(row[r]); r++; // "ldon_points_ruj, " pp->ldon_points_tak = Strings::ToInt(row[r]); r++; // "ldon_points_tak, " pp->ldon_points_available = Strings::ToInt(row[r]); r++; // "ldon_points_available, " - pp->tribute_time_remaining = Strings::ToInt(row[r]); r++; // "tribute_time_remaining, " + pp->tribute_time_remaining = Strings::ToUnsignedInt(row[r]); r++; // "tribute_time_remaining, " pp->showhelm = Strings::ToInt(row[r]); r++; // "show_helm, " pp->career_tribute_points = Strings::ToInt(row[r]); r++; // "career_tribute_points, " pp->tribute_points = Strings::ToInt(row[r]); r++; // "tribute_points, " @@ -2269,8 +2269,8 @@ const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 client else tmpNPCType->special_abilities[0] = '\0'; - tmpNPCType->d_melee_texture1 = Strings::ToInt(row[28]); - tmpNPCType->d_melee_texture2 = Strings::ToInt(row[29]); + tmpNPCType->d_melee_texture1 = Strings::ToUnsignedInt(row[28]); + tmpNPCType->d_melee_texture2 = Strings::ToUnsignedInt(row[29]); tmpNPCType->prim_melee_type = Strings::ToInt(row[30]); tmpNPCType->sec_melee_type = Strings::ToInt(row[31]); tmpNPCType->runspeed = Strings::ToFloat(row[32]); diff --git a/zone/zonedb.h b/zone/zonedb.h index c35ee885d..e98b85aeb 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -599,8 +599,8 @@ public: void DeleteMerchantTemp(uint32 npcid, uint32 slot, uint32 zone_id, uint32 instance_id); /* Tradeskills */ - bool GetTradeRecipe(const EQ::ItemInstance* container, uint8 c_type, uint32 some_id, uint32 char_id, DBTradeskillRecipe_Struct *spec); - bool GetTradeRecipe(uint32 recipe_id, uint8 c_type, uint32 some_id, uint32 char_id, DBTradeskillRecipe_Struct *spec); + bool GetTradeRecipe(const EQ::ItemInstance* container, uint8 c_type, uint32 some_id, Client* c, DBTradeskillRecipe_Struct* spec, bool* is_augmented); + bool GetTradeRecipe(uint32 recipe_id, uint8 c_type, uint32 some_id, Client* c, DBTradeskillRecipe_Struct* spec); uint32 GetZoneForage(uint32 ZoneID, uint8 skill); /* for foraging */ uint32 GetZoneFishing(uint32 ZoneID, uint8 skill, uint32 &npc_id, uint8 &npc_chance); void UpdateRecipeMadecount(uint32 recipe_id, uint32 char_id, uint32 madecount); diff --git a/zone/zonedump.h b/zone/zonedump.h index 7de07c0fd..1ab90468f 100644 --- a/zone/zonedump.h +++ b/zone/zonedump.h @@ -99,8 +99,8 @@ struct NPCType int charm_atk; int16 attack_count; char special_abilities[512]; - uint16 d_melee_texture1; - uint16 d_melee_texture2; + uint32 d_melee_texture1; + uint32 d_melee_texture2; char ammo_idfile[30]; uint8 prim_melee_type; uint8 sec_melee_type;