#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; }