#include "UpgradeEffect.h" #include "GeneralUtils.h" #include "GameMessages.h" #include "InventoryComponent.h" #include #include using namespace nejlika; nejlika::UpgradeEffect::UpgradeEffect(const nlohmann::json& json) { Load(json); } nlohmann::json nejlika::UpgradeEffect::ToJson() const { nlohmann::json json; json["trigger-type"] = static_cast(triggerType); nlohmann::json modifiersJson = nlohmann::json::array(); for (const auto& modifier : modifiers) { modifiersJson.push_back(modifier.ToJson()); } json["modifiers"] = modifiersJson; if (!chance.empty()) { nlohmann::json chanceJson = nlohmann::json::array(); for (const auto& scale : chance) { chanceJson.push_back({ {"level", scale.level}, {"value", scale.value} }); } json["chance"] = chanceJson; } if (effectID != 0) { json["effect-id"] = effectID; } if (!effectType.empty()) { json["effect-type"] = effectType; } if (!conditions.empty()) { nlohmann::json conditionsJson = nlohmann::json::array(); for (const auto& condition : conditions) { conditionsJson.push_back(magic_enum::enum_name(condition)); } json["conditions"] = conditionsJson; } if (equipSkillID != 0) { json["grant-skill-id"] = equipSkillID; } return json; } std::vector nejlika::UpgradeEffect::GenerateModifiers(int32_t level) const { std::vector result; for (const auto& modifier : modifiers) { auto instances = modifier.GenerateModifiers(level); result.insert(result.end(), instances.begin(), instances.end()); } return result; } void nejlika::UpgradeEffect::Load(const nlohmann::json& json) { triggerType = magic_enum::enum_cast(json["trigger-type"].get()).value_or(UpgradeTriggerType::OnHit); modifiers.clear(); if (json.contains("modifiers")){ for (const auto& modifier : json["modifiers"]) { ModifierTemplate effect(modifier); modifiers.push_back(effect); } } if (json.contains("chance")) { chance.clear(); for (const auto& scale : json["chance"]) { chance.push_back({ scale["level"].get(), scale["value"].get() }); } } if (json.contains("effect-id")) { effectID = json["effect-id"].get(); } if (json.contains("effect-type")) { effectType = json["effect-type"].get(); } if (json.contains("conditions")) { conditions.clear(); for (const auto& condition : json["conditions"]) { conditions.push_back(magic_enum::enum_cast(condition.get()).value_or(UpgradeTriggerCondition::None)); } } if (json.contains("grant-skill-id")) { equipSkillID = json["grant-skill-id"].get(); } } float nejlika::UpgradeEffect::CalculateChance(int32_t level) const { if (chance.empty()) { return 1; } // Find the highest level that is less than or equal to the given level float value = 0; for (const auto& scale : chance) { if (scale.level <= level) { value = scale.value; } } return value; } bool nejlika::UpgradeEffect::CheckConditions(LWOOBJID origin, const TriggerParameters& params) const { auto* entity = Game::entityManager->GetEntity(origin); if (!entity) { return false; } auto* inventory = entity->GetComponent(); if (!inventory) { return false; } const auto& skills = inventory->GetSkills(); const auto& equipped = inventory->GetEquippedItems(); for (const auto& condition : conditions) { switch (condition) { case UpgradeTriggerCondition::PrimaryAbility: if (params.SelectedBehaviorSlot != BehaviorSlot::Primary) { return false; } break; case UpgradeTriggerCondition::UseSkill: if (params.SkillID != equipSkillID) { return false; } case UpgradeTriggerCondition::None: break; case UpgradeTriggerCondition::Unarmed: if (equipped.contains("special_r")) { return false; } break; case UpgradeTriggerCondition::Melee: if (!equipped.contains("special_r")) { return false; } break; case UpgradeTriggerCondition::TwoHanded: { if (!equipped.contains("special_r")) { return false; } const auto& weaponLot = equipped.at("special_r").lot; const auto& info = Inventory::FindItemComponent(weaponLot); if (!info.isTwoHanded) { return false; } break; } case UpgradeTriggerCondition::Shield: if (!equipped.contains("special_l")) { return false; } break; default: break; } } return true; } void nejlika::UpgradeEffect::OnTrigger(LWOOBJID origin) const { auto* entity = Game::entityManager->GetEntity(origin); if (!entity) { return; } auto* inventory = entity->GetComponent(); if (!inventory) { return; } } std::vector nejlika::UpgradeEffect::Trigger(const std::vector& modifiers, int32_t level, UpgradeTriggerType triggerType, LWOOBJID origin, const TriggerParameters& params) { std::vector result; for (const auto& modifier : modifiers) { if (modifier.GetTriggerType() != triggerType) { continue; } if (!modifier.CheckConditions(origin, params)) { continue; } float chanceRoll = GeneralUtils::GenerateRandomNumber(0, 1); if (chanceRoll > modifier.CalculateChance(level)) { continue; } std::cout << "Triggering effect trigger type: " << magic_enum::enum_name(triggerType) << std::endl; modifier.OnTrigger(origin); auto instances = modifier.GenerateModifiers(level); result.insert(result.end(), instances.begin(), instances.end()); if (modifier.effectID == 0) { continue; } GameMessages::SendPlayFXEffect( origin, modifier.effectID, GeneralUtils::UTF8ToUTF16(modifier.effectType), std::to_string(GeneralUtils::GenerateRandomNumber()) ); } return result; } void nejlika::UpgradeEffect::AddSkill(LWOOBJID origin) const { auto* entity = Game::entityManager->GetEntity(origin); if (!entity) { return; } auto* inventory = entity->GetComponent(); if (!inventory) { return; } if (triggerType != UpgradeTriggerType::Active) { return; } if (equipSkillID != 0) { inventory->AddSkill(equipSkillID); } } void nejlika::UpgradeEffect::RemoveSkill(LWOOBJID origin) const { auto* entity = Game::entityManager->GetEntity(origin); if (!entity) { return; } auto* inventory = entity->GetComponent(); if (!inventory) { return; } if (triggerType != UpgradeTriggerType::Active) { return; } if (equipSkillID != 0) { inventory->RemoveSkill(equipSkillID); } } std::string nejlika::UpgradeEffect::GenerateHtmlString(const std::vector& effects, int32_t level) { std::stringstream ss; for (const auto& effect : effects) { const auto chance = effect.CalculateChance(level); for (const auto& condition : effect.conditions) { if (condition == UpgradeTriggerCondition::None || condition == UpgradeTriggerCondition::UseSkill) { continue; } ss << ""; switch (condition) { case UpgradeTriggerCondition::PrimaryAbility: ss << "On main-hand attack"; break; case UpgradeTriggerCondition::Melee: ss << "Requires melee weapon"; break; case UpgradeTriggerCondition::TwoHanded: ss << "Requires two-handed weapon"; break; case UpgradeTriggerCondition::Shield: ss << "Requires a shield"; break; case UpgradeTriggerCondition::Unarmed: ss << "Requires unarmed attack"; break; } ss << "\n\n"; } if (chance < 1.0f) { ss << "" << chance * 100 << "% chance to trigger\n"; } std::cout << "Level " << level << " chance: " << chance << std::endl; ss << ModifierInstance::GenerateHtmlString(effect.GenerateModifiers(level)); } return ss.str(); }