Implement auto calculated potion values

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

@ -154,6 +154,7 @@
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 #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 #3537: Shader-based water ripples
Feature #5173: Support for NiFogProperty

@ -1,5 +1,6 @@
#include "labels.hpp"
#include <components/esm3/loadalch.hpp>
#include <components/esm3/loadbody.hpp>
#include <components/esm3/loadcell.hpp>
#include <components/esm3/loadcont.hpp>
@ -987,3 +988,16 @@ std::string recordFlags(uint32_t flags)
properties += Misc::StringUtils::format("(0x%08X)", flags);
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 magicEffectFlags(int flags);
std::string npcFlags(int flags);
std::string potionFlags(int flags);
std::string raceFlags(int flags);
std::string spellFlags(int flags);
std::string weaponFlags(int flags);

@ -479,7 +479,7 @@ namespace EsmTool
std::cout << " Script: " << mData.mScript << std::endl;
std::cout << " Weight: " << mData.mData.mWeight << 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);
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)));
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()
if (column == mColumns.mEffects)
@ -51,7 +51,7 @@ void CSMWorld::PotionRefIdAdapter::setData(
ESM::Potion potion = record.get();
if (column == mAutoCalc)
potion.mData.mAutoCalc = value.toInt();
potion.mData.mFlags = value.toBool();
else
{
InventoryRefIdAdapter<ESM::Potion>::setData(column, data, index, value);

@ -19,6 +19,7 @@
#include "../mwrender/renderinginterface.hpp"
#include "../mwmechanics/alchemy.hpp"
#include "../mwmechanics/spellutil.hpp"
#include "classmodel.hpp"
@ -65,9 +66,7 @@ namespace MWClass
int Potion::getValue(const MWWorld::ConstPtr& ptr) const
{
const MWWorld::LiveCellRef<ESM::Potion>* ref = ptr.get<ESM::Potion>();
return ref->mBase->mData.mValue;
return MWMechanics::getPotionValue(*ptr.get<ESM::Potion>()->mBase);
}
const ESM::RefId& Potion::getUpSoundId(const MWWorld::ConstPtr& ptr) const
@ -101,7 +100,7 @@ namespace MWClass
std::string text;
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);

@ -250,7 +250,7 @@ const ESM::Potion* MWMechanics::Alchemy::getRecord(const ESM::Potion& toFind) co
if (iter->mName != toFind.mName || iter->mScript != toFind.mScript
|| 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;
// 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.mValue = mValue;
newRecord.mData.mAutoCalc = 0;
newRecord.mData.mFlags = 0;
newRecord.mRecordFlags = 0;
newRecord.mName = name;

@ -2,6 +2,7 @@
#include <limits>
#include <components/esm3/loadalch.hpp>
#include <components/esm3/loadench.hpp>
#include <components/esm3/loadmgef.hpp>
@ -48,7 +49,7 @@ namespace MWMechanics
bool appliedOnce = magicEffect->mData.mFlags & ESM::MagicEffect::AppliedOnce;
int minMagn = hasMagnitude ? effect.mMagnMin : 1;
int maxMagn = hasMagnitude ? effect.mMagnMax : 1;
if (method != EffectCostMethod::GameEnchantment)
if (method == EffectCostMethod::PlayerSpell || method == EffectCostMethod::GameSpell)
{
minMagn = std::max(1, minMagn);
maxMagn = std::max(1, maxMagn);
@ -57,21 +58,28 @@ namespace MWMechanics
if (!appliedOnce)
duration = std::max(1, duration);
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 minArea = 0;
float costMult = fEffectCostMult;
if (method == EffectCostMethod::PlayerSpell)
{
durationOffset = 1;
minArea = 1;
}
else if (method == EffectCostMethod::GamePotion)
{
minArea = 1;
costMult = iAlchemyMod;
}
float x = 0.5 * (minMagn + maxMagn);
x *= 0.1 * magicEffect->mData.mBaseCost;
x *= durationOffset + duration;
x += 0.05 * std::max(minArea, effect.mArea) * magicEffect->mData.mBaseCost;
return x * fEffectCostMult;
return x * costMult;
}
int calcSpellCost(const ESM::Spell& spell)
@ -140,6 +148,16 @@ namespace MWMechanics
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)
{
// Morrowind for some reason uses a formula slightly different from magicka cost calculation

@ -8,6 +8,7 @@ namespace ESM
struct ENAMstruct;
struct Enchantment;
struct MagicEffect;
struct Potion;
struct Spell;
}
@ -23,6 +24,7 @@ namespace MWMechanics
GameSpell,
PlayerSpell,
GameEnchantment,
GamePotion,
};
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 getEnchantmentCharge(const ESM::Enchantment& enchantment);
int getPotionValue(const ESM::Potion& potion);
/**
* @param spell spell to cast
* @param actor calculate spell success chance for this actor (depends on actor's skills)

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

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

Loading…
Cancel
Save