mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-30 22:45:34 +00:00
Merge remote-tracking branch 'pakanek/enchanting-mechanics'
This commit is contained in:
commit
bbec3680c6
4 changed files with 136 additions and 68 deletions
|
@ -61,30 +61,32 @@ namespace MWGui
|
||||||
void EnchantingDialog::updateLabels()
|
void EnchantingDialog::updateLabels()
|
||||||
{
|
{
|
||||||
std::stringstream enchantCost;
|
std::stringstream enchantCost;
|
||||||
enchantCost << std::setprecision(1) << std::fixed << mEnchanting.getEnchantCost();
|
enchantCost << std::setprecision(1) << std::fixed << mEnchanting.getEnchantPoints();
|
||||||
mEnchantmentPoints->setCaption(enchantCost.str() + " / " + boost::lexical_cast<std::string>(mEnchanting.getMaxEnchantValue()));
|
mEnchantmentPoints->setCaption(enchantCost.str() + " / " + boost::lexical_cast<std::string>(mEnchanting.getMaxEnchantValue()));
|
||||||
|
|
||||||
mCharge->setCaption(boost::lexical_cast<std::string>(mEnchanting.getGemCharge()));
|
mCharge->setCaption(boost::lexical_cast<std::string>(mEnchanting.getGemCharge()));
|
||||||
|
|
||||||
mCastCost->setCaption(boost::lexical_cast<std::string>(mEnchanting.getEnchantCost()));
|
std::stringstream castCost;
|
||||||
|
castCost << std::setprecision(1) << std::fixed << mEnchanting.getCastCost();
|
||||||
|
mCastCost->setCaption(boost::lexical_cast<std::string>(castCost.str()));
|
||||||
|
|
||||||
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 ESM::CastingStyle_CastOnce:
|
||||||
mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastOnce","Cast Once"));
|
mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastOnce","Cast Once"));
|
||||||
mAddEffectDialog.constantEffect=false;
|
mAddEffectDialog.constantEffect=false;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case ESM::CastingStyle_WhenStrikes:
|
||||||
mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenStrikes", "When Strikes"));
|
mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenStrikes", "When Strikes"));
|
||||||
mAddEffectDialog.constantEffect=false;
|
mAddEffectDialog.constantEffect=false;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case ESM::CastingStyle_WhenUsed:
|
||||||
mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenUsed", "When Used"));
|
mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenUsed", "When Used"));
|
||||||
mAddEffectDialog.constantEffect=false;
|
mAddEffectDialog.constantEffect=false;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case ESM::CastingStyle_ConstantEffect:
|
||||||
mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastConstant", "Cast Constant"));
|
mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastConstant", "Cast Constant"));
|
||||||
mAddEffectDialog.constantEffect=true;
|
mAddEffectDialog.constantEffect=true;
|
||||||
break;
|
break;
|
||||||
|
@ -169,7 +171,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 +250,7 @@ namespace MWGui
|
||||||
|
|
||||||
void EnchantingDialog::onTypeButtonClicked(MyGUI::Widget* sender)
|
void EnchantingDialog::onTypeButtonClicked(MyGUI::Widget* sender)
|
||||||
{
|
{
|
||||||
mEnchanting.nextEnchantType();
|
mEnchanting.nextCastStyle();
|
||||||
updateLabels();
|
updateLabels();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,7 +280,7 @@ namespace MWGui
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mEnchanting.getEnchantCost() > mEnchanting.getMaxEnchantValue())
|
if (mEnchanting.getEnchantPoints() > mEnchanting.getMaxEnchantValue())
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage29}");
|
MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage29}");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
Enchanting::Enchanting():
|
Enchanting::Enchanting():
|
||||||
mEnchantType(0)
|
mCastStyle(ESM::CastingStyle_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,12 +74,12 @@ 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==ESM::CastingStyle_ConstantEffect)
|
||||||
{
|
{
|
||||||
enchantment.mData.mCharge=0;
|
enchantment.mData.mCharge=0;
|
||||||
}
|
}
|
||||||
enchantment.mData.mType = mEnchantType;
|
enchantment.mData.mType = mCastStyle;
|
||||||
enchantment.mData.mCost = getEnchantCost();
|
enchantment.mData.mCost = getEnchantPoints();
|
||||||
enchantment.mEffects = mEffectList;
|
enchantment.mEffects = mEffectList;
|
||||||
|
|
||||||
const ESM::Enchantment *enchantmentPtr = MWBase::Environment::get().getWorld()->createRecord (enchantment);
|
const ESM::Enchantment *enchantmentPtr = MWBase::Environment::get().getWorld()->createRecord (enchantment);
|
||||||
|
@ -98,87 +98,142 @@ namespace MWMechanics
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Enchanting::nextEnchantType()
|
void Enchanting::nextCastStyle()
|
||||||
{
|
{
|
||||||
mEnchantType++;
|
|
||||||
if (itemEmpty())
|
if (itemEmpty())
|
||||||
{
|
{
|
||||||
mEnchantType = 0;
|
mCastStyle = ESM::CastingStyle_WhenUsed;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((mObjectType == typeid(ESM::Armor).name())||(mObjectType == typeid(ESM::Clothing).name()))
|
|
||||||
|
const bool powerfulSoul = getGemCharge() >= \
|
||||||
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("iSoulAmountForConstantEffect")->getInt();
|
||||||
|
if ((mObjectType == typeid(ESM::Armor).name()) || (mObjectType == typeid(ESM::Clothing).name()))
|
||||||
|
{ // Armor or Clothing
|
||||||
|
switch(mCastStyle)
|
||||||
{
|
{
|
||||||
int soulConstAmount = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("iSoulAmountForConstantEffect")->getInt();
|
case ESM::CastingStyle_WhenUsed:
|
||||||
switch(mEnchantType)
|
if (powerfulSoul)
|
||||||
{
|
mCastStyle = ESM::CastingStyle_ConstantEffect;
|
||||||
case 1:
|
return;
|
||||||
mEnchantType = 2;
|
default: // takes care of Constant effect too
|
||||||
case 3:
|
mCastStyle = ESM::CastingStyle_WhenUsed;
|
||||||
if(getGemCharge()<soulConstAmount)
|
return;
|
||||||
mEnchantType=2;
|
|
||||||
case 4:
|
|
||||||
mEnchantType = 2;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(mObjectType == typeid(ESM::Weapon).name())
|
else if(mObjectType == typeid(ESM::Weapon).name())
|
||||||
|
{ // Weapon
|
||||||
|
switch(mCastStyle)
|
||||||
{
|
{
|
||||||
switch(mEnchantType)
|
case ESM::CastingStyle_WhenStrikes:
|
||||||
{
|
mCastStyle = ESM::CastingStyle_WhenUsed;
|
||||||
case 3:
|
return;
|
||||||
mEnchantType = 1;
|
case ESM::CastingStyle_WhenUsed:
|
||||||
|
if (powerfulSoul)
|
||||||
|
mCastStyle = ESM::CastingStyle_ConstantEffect;
|
||||||
|
else
|
||||||
|
mCastStyle = ESM::CastingStyle_WhenStrikes;
|
||||||
|
return;
|
||||||
|
default: // takes care of Constant effect too
|
||||||
|
mCastStyle = ESM::CastingStyle_WhenStrikes;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(mObjectType == typeid(ESM::Book).name())
|
else if(mObjectType == typeid(ESM::Book).name())
|
||||||
{
|
{ // Scroll or Book
|
||||||
mEnchantType=0;
|
mCastStyle = ESM::CastingStyle_CastOnce;
|
||||||
}
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Enchanting::getEnchantCost() const
|
// Fail case
|
||||||
{
|
mCastStyle = ESM::CastingStyle_CastOnce;
|
||||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
}
|
||||||
float cost = 0;
|
|
||||||
std::vector<ESM::ENAMstruct> mEffects = mEffectList.mList;
|
|
||||||
int i=mEffects.size();
|
|
||||||
if(i<=0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Formula from http://www.uesp.net/wiki/Morrowind:Enchant
|
* 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::getEnchantPoints() const
|
||||||
|
{
|
||||||
|
if (mEffectList.mList.empty())
|
||||||
|
// No effects added, cost = 0
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||||
|
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::CastingStyle_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(effect->mData.mFlags & ESM::MagicEffect::CastTarget)
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float Enchanting::getCastCost() const
|
||||||
|
{
|
||||||
|
if (mCastStyle == ESM::CastingStyle_ConstantEffect)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const float enchantCost = getEnchantPoints();
|
||||||
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||||
|
MWMechanics::NpcStats &stats = MWWorld::Class::get(player).getNpcStats(player);
|
||||||
|
int eSkill = stats.getSkill(ESM::Skill::Enchant).getModified();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Each point of enchant skill above/under 10 subtracts/adds
|
||||||
|
* one percent of enchantment cost while minimum is 1.
|
||||||
|
*/
|
||||||
|
const float castCost = enchantCost - (enchantCost / 100) * (eSkill - 10);
|
||||||
|
|
||||||
|
return (castCost < 1) ? 1 : castCost;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int Enchanting::getEnchantPrice() const
|
int Enchanting::getEnchantPrice() const
|
||||||
{
|
{
|
||||||
if(mEnchanter.isEmpty())
|
if(mEnchanter.isEmpty())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
float priceMultipler = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("fEnchantmentValueMult")->getFloat();
|
float priceMultipler = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("fEnchantmentValueMult")->getFloat();
|
||||||
int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mEnchanter, (getEnchantCost() * priceMultipler), true);
|
int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mEnchanter, (getEnchantPoints() * priceMultipler), true);
|
||||||
return price;
|
return price;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,8 +290,8 @@ namespace MWMechanics
|
||||||
(0.25 * creatureStats.getAttribute (ESM::Attribute::Intelligence).getModified())
|
(0.25 * creatureStats.getAttribute (ESM::Attribute::Intelligence).getModified())
|
||||||
+ (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 * getEnchantPoints();
|
||||||
if(mEnchantType==3)
|
if(mCastStyle==ESM::CastingStyle_ConstantEffect)
|
||||||
{
|
{
|
||||||
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;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
#include <components/esm/effectlist.hpp>
|
#include <components/esm/effectlist.hpp>
|
||||||
|
#include <components/esm/defs.hpp>
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
|
@ -13,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;
|
||||||
|
|
||||||
|
@ -33,9 +34,10 @@ 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 getEnchantPoints() const;
|
||||||
|
float getCastCost() const;
|
||||||
int getEnchantPrice() const;
|
int getEnchantPrice() const;
|
||||||
float getMaxEnchantValue() const;
|
float getMaxEnchantValue() const;
|
||||||
int getGemCharge() const;
|
int getGemCharge() const;
|
||||||
|
|
|
@ -23,6 +23,15 @@ enum RangeType
|
||||||
RT_Target = 2
|
RT_Target = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Casting style (in enchanting)
|
||||||
|
enum CastingStyle
|
||||||
|
{
|
||||||
|
CastingStyle_CastOnce = 0,
|
||||||
|
CastingStyle_WhenStrikes = 1,
|
||||||
|
CastingStyle_WhenUsed = 2,
|
||||||
|
CastingStyle_ConstantEffect = 3
|
||||||
|
};
|
||||||
|
|
||||||
#pragma pack(push)
|
#pragma pack(push)
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue