#pragma once namespace Papyrus::PhasmalistFunctions { static constexpr float magicWeight = 0.1; float getMagicEffectStrength(RE::EffectSetting* magicEffect, float magnitude, float area, float duration) { float result = magicEffect->data.baseCost; if (magnitude > 0) { result *= magnitude; } if (area > 0) { result *= area; } if (duration > 0) { result *= duration; } return result; } float getEnchantmentStrength(RE::EnchantmentItem* ench) { if (!ench) { return 0.0; } float result = 0; const auto effects = ench->As()->effects; for (int i = effects.size() - 1; i >= 0; i--) { result += getMagicEffectStrength( effects[i]->baseEffect, effects[i]->GetMagnitude(), effects[i]->GetArea(), effects[i]->GetDuration()); } return result * magicWeight; } float getSpellStrength(RE::SpellItem* spell) { if (!spell) { return 0.0; } /* * // Sum of effect costs float result = 0; for (int i = papyrusSpell::GetNumEffects(spell) - 1; i >= 0; i--) { result += getMagicEffectStrength( papyrusSpell::GetNthEffectMagicEffect(spell, i), papyrusSpell::GetNthEffectMagnitude(spell, i), papyrusSpell::GetNthEffectDuration(spell, i), papyrusSpell::GetNthEffectArea(spell, i)); } */ /* * // The costliest effect int iCostliestEffect = papyrusSpell::GetCostliestEffectIndex(spell); float result = getMagicEffectStrength( papyrusSpell::GetNthEffectMagicEffect(spell, iCostliestEffect), papyrusSpell::GetNthEffectMagnitude(spell, iCostliestEffect), papyrusSpell::GetNthEffectDuration(spell, iCostliestEffect), papyrusSpell::GetNthEffectArea(spell, iCostliestEffect) ); */ // 2.0.10: Switch to flat magicka correlation return spell->GetData1()->costOverride * 1.5; } float getAdditionalExtendDataStrength(RE::InventoryEntryData* itemStack, float physicalStrength) { float strength = 0; if (!itemStack->extraLists) { return strength; } for (const auto& xList : *itemStack->extraLists) { const auto xEnch = xList->GetByType(); if (xEnch && xEnch->enchantment) { strength += getEnchantmentStrength(xEnch->enchantment) * xList->GetCount(); } const auto xTempered = xList->GetByType(); if (xTempered && xTempered->health > 1.0) { strength += physicalStrength * (xTempered->health - 1.0) * 20 * xList->GetCount(); } } return strength; } float getItemStackStrength(RE::InventoryEntryData* itemStack) { float strength = 0; float physicalStrength = 0; if (itemStack->object) { if (itemStack->object->IsWeapon()) { RE::TESObjectWEAP* asWeapon = itemStack->object->As(); if (asWeapon) { float baseDmg = asWeapon->GetAttackDamage() * 1.5; float speed = asWeapon->GetSpeed(); physicalStrength = baseDmg * speed; strength += physicalStrength; strength += getEnchantmentStrength(asWeapon->As()->formEnchanting); } } if (itemStack->object->IsArmor()) { RE::TESObjectARMO* asArmor = itemStack->object->As(); if (asArmor) { physicalStrength = asArmor->GetArmorRating(); strength += physicalStrength; strength += getEnchantmentStrength(asArmor->As()->formEnchanting); } } if (itemStack->object->IsBook()) { RE::TESObjectBOOK* asBook = itemStack->object->As(); if (asBook && asBook->TeachesSpell()) { return getSpellStrength(asBook->GetSpell()); } } } strength = strength * itemStack->countDelta; strength += getAdditionalExtendDataStrength(itemStack, physicalStrength); return strength; } float calculateContentStrength(RE::StaticFunctionTag* tag, RE::TESObjectREFR* container) { if (!container) { return 0.0; } float strength = 0; const auto inv = container->GetInventory(); for (const auto& [item, data] : inv) { const auto& [count, entry] = data; if (count > 0) { strength += getItemStackStrength(entry.get()); } } return strength; } inline void Bind(VM& a_vm) { BIND(calculateContentStrength); logger::info("Registered calculateContentStrength"sv); } }