Implement auto calculated potion values

fix-osga-rotate-wildly
Evil Eye 10 months ago
parent e6f64f5e71
commit 958f70736f

@ -154,6 +154,7 @@
Bug #7832: Ingredient tooltips show magnitude for Fortify Maximum Magicka effect Bug #7832: Ingredient tooltips show magnitude for Fortify Maximum Magicka effect
Bug #7840: First run of the launcher doesn't save viewing distance as the default value Bug #7840: First run of the launcher doesn't save viewing distance as the default value
Bug #7841: Editor: "Dirty" water heights are saved in modified CELLs Bug #7841: Editor: "Dirty" water heights are saved in modified CELLs
Bug #7859: AutoCalc flag is not used to calculate potion value
Feature #2566: Handle NAM9 records for manual cell references Feature #2566: Handle NAM9 records for manual cell references
Feature #3537: Shader-based water ripples Feature #3537: Shader-based water ripples
Feature #5173: Support for NiFogProperty Feature #5173: Support for NiFogProperty

@ -1,5 +1,6 @@
#include "labels.hpp" #include "labels.hpp"
#include <components/esm3/loadalch.hpp>
#include <components/esm3/loadbody.hpp> #include <components/esm3/loadbody.hpp>
#include <components/esm3/loadcell.hpp> #include <components/esm3/loadcell.hpp>
#include <components/esm3/loadcont.hpp> #include <components/esm3/loadcont.hpp>
@ -987,3 +988,16 @@ std::string recordFlags(uint32_t flags)
properties += Misc::StringUtils::format("(0x%08X)", flags); properties += Misc::StringUtils::format("(0x%08X)", flags);
return properties; return properties;
} }
std::string potionFlags(int flags)
{
std::string properties;
if (flags == 0)
properties += "[None] ";
if (flags & ESM::Potion::Autocalc)
properties += "Autocalc ";
if (flags & (0xFFFFFFFF ^ ESM::Enchantment::Autocalc))
properties += "Invalid ";
properties += Misc::StringUtils::format("(0x%08X)", flags);
return properties;
}

@ -60,6 +60,7 @@ std::string itemListFlags(int flags);
std::string lightFlags(int flags); std::string lightFlags(int flags);
std::string magicEffectFlags(int flags); std::string magicEffectFlags(int flags);
std::string npcFlags(int flags); std::string npcFlags(int flags);
std::string potionFlags(int flags);
std::string raceFlags(int flags); std::string raceFlags(int flags);
std::string spellFlags(int flags); std::string spellFlags(int flags);
std::string weaponFlags(int flags); std::string weaponFlags(int flags);

@ -479,7 +479,7 @@ namespace EsmTool
std::cout << " Script: " << mData.mScript << std::endl; std::cout << " Script: " << mData.mScript << std::endl;
std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Weight: " << mData.mData.mWeight << std::endl;
std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl;
std::cout << " AutoCalc: " << mData.mData.mAutoCalc << std::endl; std::cout << " Flags: " << potionFlags(mData.mData.mFlags) << std::endl;
printEffectList(mData.mEffects); printEffectList(mData.mEffects);
std::cout << " Deleted: " << mIsDeleted << std::endl; std::cout << " Deleted: " << mIsDeleted << std::endl;
} }

@ -33,7 +33,7 @@ QVariant CSMWorld::PotionRefIdAdapter::getData(const RefIdColumn* column, const
data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Potion))); data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Potion)));
if (column == mAutoCalc) if (column == mAutoCalc)
return record.get().mData.mAutoCalc != 0; return record.get().mData.mFlags & ESM::Potion::Autocalc;
// to show nested tables in dialogue subview, see IdTree::hasChildren() // to show nested tables in dialogue subview, see IdTree::hasChildren()
if (column == mColumns.mEffects) if (column == mColumns.mEffects)
@ -51,7 +51,7 @@ void CSMWorld::PotionRefIdAdapter::setData(
ESM::Potion potion = record.get(); ESM::Potion potion = record.get();
if (column == mAutoCalc) if (column == mAutoCalc)
potion.mData.mAutoCalc = value.toInt(); potion.mData.mFlags = value.toBool();
else else
{ {
InventoryRefIdAdapter<ESM::Potion>::setData(column, data, index, value); InventoryRefIdAdapter<ESM::Potion>::setData(column, data, index, value);

@ -19,6 +19,7 @@
#include "../mwrender/renderinginterface.hpp" #include "../mwrender/renderinginterface.hpp"
#include "../mwmechanics/alchemy.hpp" #include "../mwmechanics/alchemy.hpp"
#include "../mwmechanics/spellutil.hpp"
#include "classmodel.hpp" #include "classmodel.hpp"
@ -65,9 +66,7 @@ namespace MWClass
int Potion::getValue(const MWWorld::ConstPtr& ptr) const int Potion::getValue(const MWWorld::ConstPtr& ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Potion>* ref = ptr.get<ESM::Potion>(); return MWMechanics::getPotionValue(*ptr.get<ESM::Potion>()->mBase);
return ref->mBase->mData.mValue;
} }
const ESM::RefId& Potion::getUpSoundId(const MWWorld::ConstPtr& ptr) const const ESM::RefId& Potion::getUpSoundId(const MWWorld::ConstPtr& ptr) const
@ -101,7 +100,7 @@ namespace MWClass
std::string text; std::string text;
text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight);
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}");
info.effects = MWGui::Widgets::MWEffectList::effectListFromESM(&ref->mBase->mEffects); info.effects = MWGui::Widgets::MWEffectList::effectListFromESM(&ref->mBase->mEffects);

@ -250,7 +250,7 @@ const ESM::Potion* MWMechanics::Alchemy::getRecord(const ESM::Potion& toFind) co
if (iter->mName != toFind.mName || iter->mScript != toFind.mScript if (iter->mName != toFind.mName || iter->mScript != toFind.mScript
|| iter->mData.mWeight != toFind.mData.mWeight || iter->mData.mValue != toFind.mData.mValue || iter->mData.mWeight != toFind.mData.mWeight || iter->mData.mValue != toFind.mData.mValue
|| iter->mData.mAutoCalc != toFind.mData.mAutoCalc) || iter->mData.mFlags != toFind.mData.mFlags)
continue; continue;
// Don't choose an ID that came from the content files, would have unintended side effects // Don't choose an ID that came from the content files, would have unintended side effects
@ -310,7 +310,7 @@ void MWMechanics::Alchemy::addPotion(const std::string& name)
newRecord.mData.mWeight /= countIngredients(); newRecord.mData.mWeight /= countIngredients();
newRecord.mData.mValue = mValue; newRecord.mData.mValue = mValue;
newRecord.mData.mAutoCalc = 0; newRecord.mData.mFlags = 0;
newRecord.mRecordFlags = 0; newRecord.mRecordFlags = 0;
newRecord.mName = name; newRecord.mName = name;

@ -2,6 +2,7 @@
#include <limits> #include <limits>
#include <components/esm3/loadalch.hpp>
#include <components/esm3/loadench.hpp> #include <components/esm3/loadench.hpp>
#include <components/esm3/loadmgef.hpp> #include <components/esm3/loadmgef.hpp>
@ -48,7 +49,7 @@ namespace MWMechanics
bool appliedOnce = magicEffect->mData.mFlags & ESM::MagicEffect::AppliedOnce; bool appliedOnce = magicEffect->mData.mFlags & ESM::MagicEffect::AppliedOnce;
int minMagn = hasMagnitude ? effect.mMagnMin : 1; int minMagn = hasMagnitude ? effect.mMagnMin : 1;
int maxMagn = hasMagnitude ? effect.mMagnMax : 1; int maxMagn = hasMagnitude ? effect.mMagnMax : 1;
if (method != EffectCostMethod::GameEnchantment) if (method == EffectCostMethod::PlayerSpell || method == EffectCostMethod::GameSpell)
{ {
minMagn = std::max(1, minMagn); minMagn = std::max(1, minMagn);
maxMagn = std::max(1, maxMagn); maxMagn = std::max(1, maxMagn);
@ -57,21 +58,28 @@ namespace MWMechanics
if (!appliedOnce) if (!appliedOnce)
duration = std::max(1, duration); duration = std::max(1, duration);
static const float fEffectCostMult = store.get<ESM::GameSetting>().find("fEffectCostMult")->mValue.getFloat(); static const float fEffectCostMult = store.get<ESM::GameSetting>().find("fEffectCostMult")->mValue.getFloat();
static const float iAlchemyMod = store.get<ESM::GameSetting>().find("iAlchemyMod")->mValue.getFloat();
int durationOffset = 0; int durationOffset = 0;
int minArea = 0; int minArea = 0;
float costMult = fEffectCostMult;
if (method == EffectCostMethod::PlayerSpell) if (method == EffectCostMethod::PlayerSpell)
{ {
durationOffset = 1; durationOffset = 1;
minArea = 1; minArea = 1;
} }
else if (method == EffectCostMethod::GamePotion)
{
minArea = 1;
costMult = iAlchemyMod;
}
float x = 0.5 * (minMagn + maxMagn); float x = 0.5 * (minMagn + maxMagn);
x *= 0.1 * magicEffect->mData.mBaseCost; x *= 0.1 * magicEffect->mData.mBaseCost;
x *= durationOffset + duration; x *= durationOffset + duration;
x += 0.05 * std::max(minArea, effect.mArea) * magicEffect->mData.mBaseCost; x += 0.05 * std::max(minArea, effect.mArea) * magicEffect->mData.mBaseCost;
return x * fEffectCostMult; return x * costMult;
} }
int calcSpellCost(const ESM::Spell& spell) int calcSpellCost(const ESM::Spell& spell)
@ -140,6 +148,16 @@ namespace MWMechanics
return enchantment.mData.mCharge; return enchantment.mData.mCharge;
} }
int getPotionValue(const ESM::Potion& potion)
{
if (potion.mData.mFlags & ESM::Potion::Autocalc)
{
float cost = getTotalCost(potion.mEffects, EffectCostMethod::GamePotion);
return std::round(cost);
}
return potion.mData.mValue;
}
float calcSpellBaseSuccessChance(const ESM::Spell* spell, const MWWorld::Ptr& actor, ESM::RefId* effectiveSchool) float calcSpellBaseSuccessChance(const ESM::Spell* spell, const MWWorld::Ptr& actor, ESM::RefId* effectiveSchool)
{ {
// Morrowind for some reason uses a formula slightly different from magicka cost calculation // Morrowind for some reason uses a formula slightly different from magicka cost calculation

@ -8,6 +8,7 @@ namespace ESM
struct ENAMstruct; struct ENAMstruct;
struct Enchantment; struct Enchantment;
struct MagicEffect; struct MagicEffect;
struct Potion;
struct Spell; struct Spell;
} }
@ -23,6 +24,7 @@ namespace MWMechanics
GameSpell, GameSpell,
PlayerSpell, PlayerSpell,
GameEnchantment, GameEnchantment,
GamePotion,
}; };
float calcEffectCost(const ESM::ENAMstruct& effect, const ESM::MagicEffect* magicEffect = nullptr, float calcEffectCost(const ESM::ENAMstruct& effect, const ESM::MagicEffect* magicEffect = nullptr,
@ -33,6 +35,8 @@ namespace MWMechanics
int getEffectiveEnchantmentCastCost(const ESM::Enchantment& enchantment, const MWWorld::Ptr& actor); int getEffectiveEnchantmentCastCost(const ESM::Enchantment& enchantment, const MWWorld::Ptr& actor);
int getEnchantmentCharge(const ESM::Enchantment& enchantment); int getEnchantmentCharge(const ESM::Enchantment& enchantment);
int getPotionValue(const ESM::Potion& potion);
/** /**
* @param spell spell to cast * @param spell spell to cast
* @param actor calculate spell success chance for this actor (depends on actor's skills) * @param actor calculate spell success chance for this actor (depends on actor's skills)

@ -36,7 +36,7 @@ namespace ESM
mName = esm.getHString(); mName = esm.getHString();
break; break;
case fourCC("ALDT"): case fourCC("ALDT"):
esm.getHT(mData.mWeight, mData.mValue, mData.mAutoCalc); esm.getHT(mData.mWeight, mData.mValue, mData.mFlags);
hasData = true; hasData = true;
break; break;
case fourCC("ENAM"): case fourCC("ENAM"):
@ -80,7 +80,7 @@ namespace ESM
mRecordFlags = 0; mRecordFlags = 0;
mData.mWeight = 0; mData.mWeight = 0;
mData.mValue = 0; mData.mValue = 0;
mData.mAutoCalc = 0; mData.mFlags = 0;
mName.clear(); mName.clear();
mModel.clear(); mModel.clear();
mIcon.clear(); mIcon.clear();

@ -25,11 +25,16 @@ namespace ESM
/// Return a string descriptor for this record type. Currently used for debugging / error logs only. /// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string_view getRecordType() { return "Potion"; } static std::string_view getRecordType() { return "Potion"; }
enum Flags
{
Autocalc = 1 // Determines value
};
struct ALDTstruct struct ALDTstruct
{ {
float mWeight; float mWeight;
int32_t mValue; int32_t mValue;
int32_t mAutoCalc; int32_t mFlags;
}; };
ALDTstruct mData; ALDTstruct mData;

Loading…
Cancel
Save