1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-11 15:40:39 +00:00

Better formula for enchantment cost and code refactorization.

This commit is contained in:
Miroslav Puda 2013-05-27 14:42:08 +02:00
parent 56edc1b213
commit 4788b5e226
4 changed files with 75 additions and 47 deletions

View File

@ -70,7 +70,7 @@ namespace MWGui
mPrice->setCaption(boost::lexical_cast<std::string>(mEnchanting.getEnchantPrice())); mPrice->setCaption(boost::lexical_cast<std::string>(mEnchanting.getEnchantPrice()));
switch(mEnchanting.getEnchantType()) switch(mEnchanting.getCastStyle())
{ {
case 0: case 0:
mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastOnce","Cast Once")); mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastOnce","Cast Once"));
@ -169,7 +169,7 @@ namespace MWGui
image->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onRemoveItem); image->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onRemoveItem);
mEnchanting.setOldItem(item); mEnchanting.setOldItem(item);
mEnchanting.nextEnchantType(); mEnchanting.nextCastStyle();
updateLabels(); updateLabels();
} }
@ -248,7 +248,7 @@ namespace MWGui
void EnchantingDialog::onTypeButtonClicked(MyGUI::Widget* sender) void EnchantingDialog::onTypeButtonClicked(MyGUI::Widget* sender)
{ {
mEnchanting.nextEnchantType(); mEnchanting.nextCastStyle();
updateLabels(); updateLabels();
} }

View File

@ -12,7 +12,7 @@
namespace MWMechanics namespace MWMechanics
{ {
Enchanting::Enchanting(): Enchanting::Enchanting():
mEnchantType(0) mCastStyle(ESM::CS_CastOnce)
{} {}
void Enchanting::setOldItem(MWWorld::Ptr oldItem) void Enchanting::setOldItem(MWWorld::Ptr oldItem)
@ -41,9 +41,9 @@ namespace MWMechanics
mEffectList=effectList; mEffectList=effectList;
} }
int Enchanting::getEnchantType() const int Enchanting::getCastStyle() const
{ {
return mEnchantType; return mCastStyle;
} }
void Enchanting::setSoulGem(MWWorld::Ptr soulGem) void Enchanting::setSoulGem(MWWorld::Ptr soulGem)
@ -74,11 +74,11 @@ namespace MWMechanics
MWWorld::Class::get (mEnchanter).skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 1); MWWorld::Class::get (mEnchanter).skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 1);
} }
if(mEnchantType==3) if(mCastStyle==3)
{ {
enchantment.mData.mCharge=0; enchantment.mData.mCharge=0;
} }
enchantment.mData.mType = mEnchantType; enchantment.mData.mType = mCastStyle;
enchantment.mData.mCost = getEnchantCost(); enchantment.mData.mCost = getEnchantCost();
enchantment.mEffects = mEffectList; enchantment.mEffects = mEffectList;
@ -98,78 +98,97 @@ namespace MWMechanics
return true; return true;
} }
void Enchanting::nextEnchantType() void Enchanting::nextCastStyle()
{ {
mEnchantType++; mCastStyle++;
if (itemEmpty()) if (itemEmpty())
{ {
mEnchantType = 0; mCastStyle = 0;
return; return;
} }
if ((mObjectType == typeid(ESM::Armor).name())||(mObjectType == typeid(ESM::Clothing).name())) if ((mObjectType == typeid(ESM::Armor).name())||(mObjectType == typeid(ESM::Clothing).name()))
{ {
int soulConstAmount = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("iSoulAmountForConstantEffect")->getInt(); int soulConstAmount = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("iSoulAmountForConstantEffect")->getInt();
switch(mEnchantType) switch(mCastStyle)
{ {
case 1: case 1:
mEnchantType = 2; mCastStyle = 2;
case 3: case 3:
if(getGemCharge()<soulConstAmount) if(getGemCharge()<soulConstAmount)
mEnchantType=2; mCastStyle=2;
case 4: case 4:
mEnchantType = 2; mCastStyle = 2;
} }
} }
else if(mObjectType == typeid(ESM::Weapon).name()) else if(mObjectType == typeid(ESM::Weapon).name())
{ {
switch(mEnchantType) switch(mCastStyle)
{ {
case 3: case 3:
mEnchantType = 1; mCastStyle = 1;
} }
} }
else if(mObjectType == typeid(ESM::Book).name()) else if(mObjectType == typeid(ESM::Book).name())
{ {
mEnchantType=0; mCastStyle=0;
} }
} }
/*
* Vanilla enchant cost formula:
*
* Touch/Self: (min + max) * baseCost * 0.025 * duration + area * baseCost * 0.025
* Target: 1.5 * ((min + max) * baseCost * 0.025 * duration + area * baseCost * 0.025)
* Constant eff: (min + max) * baseCost * 2.5 + area * baseCost * 0.025
*
* For multiple effects - cost of each effect is multiplied by number of effects that follows +1.
*
* Note: Minimal value inside formula for 'min' and 'max' is 1. So in vanilla:
* (0 + 0) == (1 + 0) == (1 + 1) => 2 or (2 + 0) == (1 + 2) => 3
*
* Formula on UESPWiki is not entirely correct.
*/
float Enchanting::getEnchantCost() const float Enchanting::getEnchantCost() const
{ {
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); if (mEffectList.mList.empty())
float cost = 0; // No effects added, cost = 0
std::vector<ESM::ENAMstruct> mEffects = mEffectList.mList; return 0;
int i=mEffects.size();
if(i<=0)
return 0;
/* const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
Formula from http://www.uesp.net/wiki/Morrowind:Enchant std::vector<ESM::ENAMstruct> mEffects = mEffectList.mList;
*/
float enchantmentCost = 0;
int effectsLeftCnt = mEffects.size();
float baseCost, magnitudeCost, areaCost;
int magMin, magMax, area;
for (std::vector<ESM::ENAMstruct>::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it) for (std::vector<ESM::ENAMstruct>::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it)
{ {
const ESM::MagicEffect* effect = store.get<ESM::MagicEffect>().find(it->mEffectID); baseCost = (store.get<ESM::MagicEffect>().find(it->mEffectID))->mData.mBaseCost;
// To reflect vanilla behavior
magMin = (it->mMagnMin == 0) ? 1 : it->mMagnMin;
magMax = (it->mMagnMax == 0) ? 1 : it->mMagnMax;
area = (it->mArea == 0) ? 1 : it->mArea;
float cost1 = ((it->mMagnMin + it->mMagnMax)*it->mDuration*effect->mData.mBaseCost*0.025); if (mCastStyle == ESM::CS_ConstantEffect)
float cost2 = (std::max(1, it->mArea)*0.125*effect->mData.mBaseCost);
if(mEnchantType==3)
{ {
int constDurationMultipler = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("fEnchantmentConstantDurationMult")->getFloat(); magnitudeCost = (magMin + magMax) * baseCost * 2.5;
cost1 *= constDurationMultipler; }
cost2 *= 2; else
{
magnitudeCost = (magMin + magMax) * it->mDuration * baseCost * 0.025;
if(it->mRange == ESM::RT_Target)
magnitudeCost *= 1.5;
} }
if(it->mRange == ESM::RT_Target)
cost1 *= 1.5;
float fullcost = cost1+cost2; areaCost = area * 0.025 * baseCost;
fullcost*= i; if (it->mRange == ESM::RT_Target)
i--; areaCost *= 1.5;
cost+=fullcost; enchantmentCost += (magnitudeCost + areaCost) * effectsLeftCnt;
--effectsLeftCnt;
} }
return cost;
return enchantmentCost;
} }
int Enchanting::getEnchantPrice() const int Enchanting::getEnchantPrice() const
@ -236,7 +255,7 @@ namespace MWMechanics
+ (0.125 * creatureStats.getAttribute (ESM::Attribute::Luck).getModified())); + (0.125 * creatureStats.getAttribute (ESM::Attribute::Luck).getModified()));
float chance2 = 2.5 * getEnchantCost(); float chance2 = 2.5 * getEnchantCost();
if(mEnchantType==3) if(mCastStyle==3)
{ {
float constantChance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("fEnchantmentConstantChanceMult")->getFloat(); float constantChance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("fEnchantmentConstantChanceMult")->getFloat();
chance2 /= constantChance; chance2 /= constantChance;

View File

@ -14,7 +14,7 @@ namespace MWMechanics
MWWorld::Ptr mSoulGemPtr; MWWorld::Ptr mSoulGemPtr;
MWWorld::Ptr mEnchanter; MWWorld::Ptr mEnchanter;
int mEnchantType; int mCastStyle;
bool mSelfEnchanting; bool mSelfEnchanting;
@ -34,8 +34,8 @@ namespace MWMechanics
void setEffect(ESM::EffectList effectList); void setEffect(ESM::EffectList effectList);
void setSoulGem(MWWorld::Ptr soulGem); void setSoulGem(MWWorld::Ptr soulGem);
bool create(); //Return true if created, false if failed. bool create(); //Return true if created, false if failed.
void nextEnchantType(); //Set enchant type to next possible type (for mOldItemPtr object) void nextCastStyle(); //Set enchant type to next possible type (for mOldItemPtr object)
int getEnchantType() const; int getCastStyle() const;
float getEnchantCost() const; float getEnchantCost() const;
int getEnchantPrice() const; int getEnchantPrice() const;
float getMaxEnchantValue() const; float getMaxEnchantValue() const;

View File

@ -23,6 +23,15 @@ enum RangeType
RT_Target = 2 RT_Target = 2
}; };
// Casting style (in enchanting)
enum Type
{
CS_CastOnce = 0,
CS_WhenStrikes = 1,
CS_WhenUsed = 2,
CS_ConstantEffect = 3
};
#pragma pack(push) #pragma pack(push)
#pragma pack(1) #pragma pack(1)