From c2ad76ee661fcfee8532ce73c4a89992b68d00ea Mon Sep 17 00:00:00 2001 From: wincent Date: Thu, 30 May 2024 10:54:38 +0200 Subject: [PATCH] Moved to a dedicated nejlika fle --- dGame/CMakeLists.txt | 3 +- dGame/Nejlika.cpp | 307 ++++++++++++++++++ dGame/Nejlika.h | 67 ++++ dGame/dInventory/Item.cpp | 1 + dGame/dUtilities/SlashCommandHandler.cpp | 9 - .../SlashCommands/GMZeroCommands.cpp | 30 -- .../dUtilities/SlashCommands/GMZeroCommands.h | 1 - 7 files changed, 377 insertions(+), 41 deletions(-) create mode 100644 dGame/Nejlika.cpp create mode 100644 dGame/Nejlika.h diff --git a/dGame/CMakeLists.txt b/dGame/CMakeLists.txt index 26eb859a..db93276c 100644 --- a/dGame/CMakeLists.txt +++ b/dGame/CMakeLists.txt @@ -6,7 +6,8 @@ set(DGAME_SOURCES "Character.cpp" "TeamManager.cpp" "TradingManager.cpp" "User.cpp" - "UserManager.cpp") + "UserManager.cpp" + "Nejlika.cpp") include_directories( ${PROJECT_SOURCE_DIR}/dScripts diff --git a/dGame/Nejlika.cpp b/dGame/Nejlika.cpp new file mode 100644 index 00000000..fef991ee --- /dev/null +++ b/dGame/Nejlika.cpp @@ -0,0 +1,307 @@ +#include "Nejlika.h" + +#include "SlashCommandHandler.h" + +#include +#include +#include +#include +#include + +void nejlika::Initalize() +{ + Command itemDescriptionCommand{ + .help = "Special UI command, does nothing when used in chat.", + .info = "Special UI command, does nothing when used in chat.", + .aliases = {"d"}, + .handle = ItemDescription, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + SlashCommandHandler::RegisterCommand(itemDescriptionCommand); +} + +void nejlika::ItemDescription(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + auto requestId = GeneralUtils::TryParse(splitArgs[0]); + + if (!requestId.has_value()) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid item ID."); + return; + } + + auto itemId = GeneralUtils::TryParse(splitArgs[1]); + + if (!itemId.has_value()) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid item ID."); + return; + } + + auto* inventoryComponent = entity->GetComponent(); + + if (!inventoryComponent) { + return; + } + + auto* item = inventoryComponent->FindItemById(itemId.value()); + + if (!item) { + ChatPackets::SendSystemMessage(sysAddr, u"Item not found."); + return; + } + + const auto& itemData = item->GetConfig(); + + LDFBaseData* modifiersData = nullptr; + + for (const auto& data : itemData) { + if (data->GetKey() == u"modifiers") { + modifiersData = data; + break; + } + } + + if (!modifiersData) { + return; + } + + const auto modifiersStr = dynamic_cast*>(modifiersData)->GetValueAsString(); + + if (modifiersStr.empty()) { + return; + } + + std::stringstream name; + std::stringstream desc; + + auto parts = GeneralUtils::SplitString(modifiersStr, '&'); + + if (parts.size() != 2) { + return; + } + + auto names = GeneralUtils::SplitString(parts[0], ';'); + + std::vector itemNames; + + for (const auto& name : names) { + ItemName itemName(name); + + itemNames.push_back(itemName); + } + + name << ItemName::GenerateHtmlString(itemNames) << "\n"; + + auto modifiers = GeneralUtils::SplitString(parts[1], ';'); + + for (const auto& modifier : modifiers) { + ItemModifier itemModifier(modifier); + + desc << itemModifier.GenerateHtmlString() << "\n"; + } + + std::stringstream messageName; + messageName << "desc" << requestId.value(); + + AMFArrayValue amfArgs; + + amfArgs.Insert("t", true); + amfArgs.Insert("d", desc.str()); + amfArgs.Insert("n", name.str()); + + GameMessages::SendUIMessageServerToSingleClient(entity, sysAddr, messageName.str(), amfArgs); +} + +nejlika::ItemModifier::ItemModifier(const std::string& config) { + auto splitConfig = GeneralUtils::SplitString(config, ','); + + if (splitConfig.size() != 3) { + return; + } + + type = static_cast(GeneralUtils::TryParse(splitConfig[0]).value()); + value = GeneralUtils::TryParse(splitConfig[1]).value(); + isPercentage = GeneralUtils::TryParse(splitConfig[2]).value(); +} + +std::string nejlika::ItemModifier::ToString() const { + std::stringstream ss; + ss << static_cast(type) << ',' << value << ',' << isPercentage; + return ss.str(); +} + +std::string nejlika::ItemModifier::GenerateHtmlString() const { + // "Physical: +20%\n..." + + std::stringstream ss; + + ss << " colorMap = { + {ItemModifierType::Health, "#750000"}, + {ItemModifierType::Armor, "#525252"}, + {ItemModifierType::Imagination, "#0077FF"}, + {ItemModifierType::Slashing, "#666666"}, + {ItemModifierType::Piercing, "#4f4f4f"}, + {ItemModifierType::Bludgeoning, "#e84646"}, + {ItemModifierType::Fire, "#ff0000"}, + {ItemModifierType::Cold, "#94d0f2"}, + {ItemModifierType::Lightning, "#00a2ff"}, + {ItemModifierType::Corruption, "#3d00ad"}, + {ItemModifierType::Psychic, "#4b0161"} + }; + + static const std::unordered_map namesMap = { + {ItemModifierType::Health, "Health"}, + {ItemModifierType::Armor, "Armor"}, + {ItemModifierType::Imagination, "Imagination"}, + {ItemModifierType::Slashing, "Slashing"}, + {ItemModifierType::Piercing, "Piercing"}, + {ItemModifierType::Bludgeoning, "Bludgeoning"}, + {ItemModifierType::Fire, "Fire"}, + {ItemModifierType::Cold, "Cold"}, + {ItemModifierType::Lightning, "Lightning"}, + {ItemModifierType::Corruption, "Corruption"}, + {ItemModifierType::Psychic, "Psychic"} + }; + + const auto color = colorMap.find(type); + + if (color != colorMap.end()) { + ss << color->second; + } else { + ss << "#FFFFFF"; + } + + ss << "\">"; + + const auto name = namesMap.find(type); + + if (name != namesMap.end()) { + ss << name->second; + } else { + ss << "Unknown"; + } + + ss << ": "; + + if (value > 0) { + ss << "+"; + } + else if (value < 0) { + ss << "-"; + } + + // Only show 2 decimal places + ss << std::fixed << std::setprecision(2) << std::abs(value); + + if (isPercentage) { + ss << "%"; + } + + ss << ""; + + return ss.str(); +} + +nejlika::ItemName::ItemName(const std::string& config) { + auto splitConfig = GeneralUtils::SplitString(config, ','); + + if (splitConfig.size() != 3) { + return; + } + + type = static_cast(GeneralUtils::TryParse(splitConfig[0]).value()); + name = splitConfig[1]; + prefix = GeneralUtils::TryParse(splitConfig[2]).value(); +} + +std::string nejlika::ItemName::ToString() const { + std::stringstream ss; + ss << static_cast(type) << ',' << name << ',' << prefix; + return ss.str(); +} + +std::string nejlika::ItemName::GenerateHtmlString() const { + std::stringstream ss; + + ss << " colorMap = { + {ItemNameType::Common, "#FFFFFF"}, + {ItemNameType::Uncommon, "#00FF00"}, + {ItemNameType::Rare, "#0077FF"}, + {ItemNameType::Epic, "#FF00FF"}, + {ItemNameType::Legendary, "#FF7700"}, + {ItemNameType::Relic, "#FFC391"} + }; + + const auto color = colorMap.find(type); + + if (color != colorMap.end()) { + ss << color->second; + } else { + ss << "#FFFFFF"; + } + + ss << "\">"; + + ss << name; + + ss << ""; + + return ss.str(); +} + +std::string nejlika::ItemName::GenerateHtmlString(const std::vector& names) { + // Prefix-1 Prefix-2 NAME Suffix-1 Suffix-2 + std::stringstream ss; + + for (const auto& name : names) { + if (name.prefix) { + ss << name.GenerateHtmlString() << "\n"; + } + } + + ss << "NAME"; + + for (const auto& name : names) { + if (!name.prefix && !name.name.empty()) { + ss << name.GenerateHtmlString() << "\n"; + } + } + + // Remove the last newline + auto str = ss.str(); + + if (!str.empty() && str.back() == '\n') { + str.pop_back(); + } + + return str; +} + + diff --git a/dGame/Nejlika.h b/dGame/Nejlika.h new file mode 100644 index 00000000..a3bd7e8f --- /dev/null +++ b/dGame/Nejlika.h @@ -0,0 +1,67 @@ +#pragma once + +namespace nejlika +{ + +void Initalize(); + +void ItemDescription(Entity* entity, const SystemAddress& sysAddr, const std::string args); + +enum class ItemModifierType : uint8_t +{ + Health, + Armor, + Imagination, + Slashing, + Piercing, + Bludgeoning, + Fire, + Cold, + Lightning, + Corruption, + Psychic +}; + +struct ItemModifier +{ + ItemModifierType type; + float value; + bool isPercentage; + + ItemModifier(ItemModifierType type, float value, bool isPercentage) : type(type), value(value), isPercentage(isPercentage) {} + + ItemModifier(const std::string& config); + + std::string ToString() const; + + std::string GenerateHtmlString() const; +}; + +enum class ItemNameType : uint8_t +{ + Common, + Uncommon, + Rare, + Epic, + Legendary, + Relic +}; + +struct ItemName +{ + ItemNameType type; + std::string name; + bool prefix; + + ItemName(ItemNameType type, const std::string& name, bool prefix) : type(type), name(name), prefix(prefix) {} + + ItemName(const std::string& config); + + std::string ToString() const; + + std::string GenerateHtmlString() const; + + static std::string GenerateHtmlString(const std::vector& names); +}; + +} \ No newline at end of file diff --git a/dGame/dInventory/Item.cpp b/dGame/dInventory/Item.cpp index 32603761..183e4122 100644 --- a/dGame/dInventory/Item.cpp +++ b/dGame/dInventory/Item.cpp @@ -41,6 +41,7 @@ namespace { { "userModelMod", "um" }, { "userModelOpt", "uo" }, { "reforgedLOT", "rl" }, + { "modifiers", "mod" } }; } diff --git a/dGame/dUtilities/SlashCommandHandler.cpp b/dGame/dUtilities/SlashCommandHandler.cpp index 18aff7b5..428ccbcb 100644 --- a/dGame/dUtilities/SlashCommandHandler.cpp +++ b/dGame/dUtilities/SlashCommandHandler.cpp @@ -1427,13 +1427,4 @@ void SlashCommandHandler::Startup() { .requiredLevel = eGameMasterLevel::CIVILIAN }; RegisterCommand(removeIgnoreCommand); - - Command itemDescriptionCommand{ - .help = "Special UI command, does nothing when used in chat.", - .info = "Special UI command, does nothing when used in chat.", - .aliases = {"d"}, - .handle = GMZeroCommands::ItemDescription, - .requiredLevel = eGameMasterLevel::CIVILIAN - }; - RegisterCommand(itemDescriptionCommand); } diff --git a/dGame/dUtilities/SlashCommands/GMZeroCommands.cpp b/dGame/dUtilities/SlashCommands/GMZeroCommands.cpp index d071776f..6c9811c2 100644 --- a/dGame/dUtilities/SlashCommands/GMZeroCommands.cpp +++ b/dGame/dUtilities/SlashCommands/GMZeroCommands.cpp @@ -225,36 +225,6 @@ namespace GMZeroCommands { ChatPackets::SendSystemMessage(sysAddr, u"Map: " + (GeneralUtils::to_u16string(zoneId.GetMapID())) + u"\nClone: " + (GeneralUtils::to_u16string(zoneId.GetCloneID())) + u"\nInstance: " + (GeneralUtils::to_u16string(zoneId.GetInstanceID()))); } - void ItemDescription(Entity* entity, const SystemAddress& sysAddr, const std::string args) { - auto splitArgs = GeneralUtils::SplitString(args, ' '); - if (splitArgs.empty()) return; - - auto requestId = GeneralUtils::TryParse(splitArgs[0]); - - if (!requestId.has_value()) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid item ID."); - return; - } - - auto itemId = GeneralUtils::TryParse(splitArgs[1]); - - if (!itemId.has_value()) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid item ID."); - return; - } - - std::stringstream messageName; - messageName << "desc" << requestId.value(); - - AMFArrayValue amfArgs; - - amfArgs.Insert("t", true); - amfArgs.Insert("d", "Test description"); - amfArgs.Insert("n", messageName.str()); - - GameMessages::SendUIMessageServerToSingleClient(entity, sysAddr, messageName.str(), amfArgs); - } - //For client side commands void ClientHandled(Entity* entity, const SystemAddress& sysAddr, const std::string args) {} diff --git a/dGame/dUtilities/SlashCommands/GMZeroCommands.h b/dGame/dUtilities/SlashCommands/GMZeroCommands.h index 64d71d46..d3f6753d 100644 --- a/dGame/dUtilities/SlashCommands/GMZeroCommands.h +++ b/dGame/dUtilities/SlashCommands/GMZeroCommands.h @@ -15,7 +15,6 @@ namespace GMZeroCommands { void LeaveZone(Entity* entity, const SystemAddress& sysAddr, const std::string args); void Resurrect(Entity* entity, const SystemAddress& sysAddr, const std::string args); void InstanceInfo(Entity* entity, const SystemAddress& sysAddr, const std::string args); - void ItemDescription(Entity* entity, const SystemAddress& sysAddr, const std::string args); void ClientHandled(Entity* entity, const SystemAddress& sysAddr, const std::string args); }