mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-03-29 22:20:33 +00:00
Merge remote-tracking branch 'upstream/master' into launcher-model
This commit is contained in:
commit
2b25178aef
@ -39,6 +39,8 @@ namespace MWBase
|
||||
|
||||
virtual void addActor (const MWWorld::Ptr& ptr) = 0;
|
||||
///< Register an actor for stats management
|
||||
///
|
||||
/// \note Dead actors are ignored.
|
||||
|
||||
virtual void removeActor (const MWWorld::Ptr& ptr) = 0;
|
||||
///< Deregister an actor for stats management
|
||||
@ -74,6 +76,9 @@ namespace MWBase
|
||||
|
||||
virtual void restoreDynamicStats() = 0;
|
||||
///< If the player is sleeping, this should be called every hour.
|
||||
|
||||
virtual int countDeaths (const std::string& id) const = 0;
|
||||
///< Return the number of deaths for actors with the given ID.
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ namespace ESM
|
||||
struct Cell;
|
||||
struct Class;
|
||||
struct Potion;
|
||||
struct Spell;
|
||||
}
|
||||
|
||||
namespace ESMS
|
||||
@ -238,6 +239,11 @@ namespace MWBase
|
||||
///< Create a new recrod (of type potion) in the ESM store.
|
||||
/// \return ID, pointer to created record
|
||||
|
||||
virtual std::pair<std::string, const ESM::Spell *> createRecord (const ESM::Spell& record)
|
||||
= 0;
|
||||
///< Create a new recrod (of type spell) in the ESM store.
|
||||
/// \return ID, pointer to created record
|
||||
|
||||
virtual std::pair<std::string, const ESM::Class *> createRecord (const ESM::Class& record)
|
||||
= 0;
|
||||
///< Create a new recrod (of type class) in the ESM store.
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/actiontalk.hpp"
|
||||
#include "../mwworld/actionopen.hpp"
|
||||
#include "../mwworld/customdata.hpp"
|
||||
#include "../mwworld/containerstore.hpp"
|
||||
#include "../mwworld/physicssystem.hpp"
|
||||
@ -55,9 +56,9 @@ namespace MWClass
|
||||
data->mCreatureStats.getAttribute(5).set (ref->base->mData.mEndurance);
|
||||
data->mCreatureStats.getAttribute(6).set (ref->base->mData.mPersonality);
|
||||
data->mCreatureStats.getAttribute(7).set (ref->base->mData.mLuck);
|
||||
data->mCreatureStats.getHealth().set (ref->base->mData.mHealth);
|
||||
data->mCreatureStats.getMagicka().set (ref->base->mData.mMana);
|
||||
data->mCreatureStats.getFatigue().set (ref->base->mData.mFatigue);
|
||||
data->mCreatureStats.setHealth (ref->base->mData.mHealth);
|
||||
data->mCreatureStats.setMagicka (ref->base->mData.mMana);
|
||||
data->mCreatureStats.setFatigue (ref->base->mData.mFatigue);
|
||||
|
||||
data->mCreatureStats.setLevel(ref->base->mData.mLevel);
|
||||
|
||||
@ -130,7 +131,10 @@ namespace MWClass
|
||||
boost::shared_ptr<MWWorld::Action> Creature::activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor) const
|
||||
{
|
||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::ActionTalk (ptr));
|
||||
if (MWWorld::Class::get (ptr).getCreatureStats (ptr).isDead())
|
||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::ActionOpen(ptr));
|
||||
else
|
||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::ActionTalk (ptr));
|
||||
}
|
||||
|
||||
MWWorld::ContainerStore& Creature::getContainerStore (const MWWorld::Ptr& ptr)
|
||||
@ -149,6 +153,14 @@ namespace MWClass
|
||||
return ref->base->mScript;
|
||||
}
|
||||
|
||||
bool Creature::isEssential (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref =
|
||||
ptr.get<ESM::Creature>();
|
||||
|
||||
return ref->base->mFlags & ESM::Creature::Essential;
|
||||
}
|
||||
|
||||
void Creature::registerSelf()
|
||||
{
|
||||
boost::shared_ptr<Class> instance (new Creature);
|
||||
|
@ -56,6 +56,9 @@ namespace MWClass
|
||||
///< Returns total weight of objects inside this object (including modifications from magic
|
||||
/// effects). Throws an exception, if the object can't hold other objects.
|
||||
|
||||
virtual bool isEssential (const MWWorld::Ptr& ptr) const;
|
||||
///< Is \a ptr essential? (i.e. may losing \a ptr make the game unwinnable)
|
||||
|
||||
static void registerSelf();
|
||||
|
||||
virtual std::string getModel(const MWWorld::Ptr &ptr) const;
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/actiontalk.hpp"
|
||||
#include "../mwworld/actionopen.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
#include "../mwworld/customdata.hpp"
|
||||
#include "../mwworld/physicssystem.hpp"
|
||||
@ -89,15 +90,22 @@ namespace MWClass
|
||||
data->mCreatureStats.getAttribute(5).set (ref->base->mNpdt52.mEndurance);
|
||||
data->mCreatureStats.getAttribute(6).set (ref->base->mNpdt52.mPersonality);
|
||||
data->mCreatureStats.getAttribute(7).set (ref->base->mNpdt52.mLuck);
|
||||
data->mCreatureStats.getHealth().set (ref->base->mNpdt52.mHealth);
|
||||
data->mCreatureStats.getMagicka().set (ref->base->mNpdt52.mMana);
|
||||
data->mCreatureStats.getFatigue().set (ref->base->mNpdt52.mFatigue);
|
||||
data->mCreatureStats.setHealth (ref->base->mNpdt52.mHealth);
|
||||
data->mCreatureStats.setMagicka (ref->base->mNpdt52.mMana);
|
||||
data->mCreatureStats.setFatigue (ref->base->mNpdt52.mFatigue);
|
||||
|
||||
data->mCreatureStats.setLevel(ref->base->mNpdt52.mLevel);
|
||||
}
|
||||
else
|
||||
{
|
||||
/// \todo do something with mNpdt12 maybe:p
|
||||
for (int i=0; i<8; ++i)
|
||||
data->mCreatureStats.getAttribute (i).set (10);
|
||||
|
||||
for (int i=0; i<3; ++i)
|
||||
data->mCreatureStats.setDynamic (i, 10);
|
||||
|
||||
data->mCreatureStats.setLevel (1);
|
||||
}
|
||||
|
||||
data->mCreatureStats.setHello(ref->base->mAiData.mHello);
|
||||
@ -182,7 +190,10 @@ namespace MWClass
|
||||
boost::shared_ptr<MWWorld::Action> Npc::activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor) const
|
||||
{
|
||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::ActionTalk (ptr));
|
||||
if (MWWorld::Class::get (ptr).getCreatureStats (ptr).isDead())
|
||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::ActionOpen(ptr));
|
||||
else
|
||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::ActionTalk (ptr));
|
||||
}
|
||||
|
||||
MWWorld::ContainerStore& Npc::getContainerStore (const MWWorld::Ptr& ptr)
|
||||
@ -308,7 +319,15 @@ namespace MWClass
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
bool Npc::isEssential (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::NPC> *ref =
|
||||
ptr.get<ESM::NPC>();
|
||||
|
||||
return ref->base->mFlags & ESM::NPC::Essential;
|
||||
}
|
||||
|
||||
void Npc::registerSelf()
|
||||
{
|
||||
boost::shared_ptr<Class> instance (new Npc);
|
||||
|
@ -90,6 +90,9 @@ namespace MWClass
|
||||
|
||||
virtual void adjustRotation(const MWWorld::Ptr& ptr,float& x,float& y,float& z) const;
|
||||
|
||||
virtual bool isEssential (const MWWorld::Ptr& ptr) const;
|
||||
///< Is \a ptr essential? (i.e. may losing \a ptr make the game unwinnable)
|
||||
|
||||
static void registerSelf();
|
||||
|
||||
virtual std::string getModel(const MWWorld::Ptr &ptr) const;
|
||||
|
@ -85,6 +85,7 @@ MWGui::JournalWindow::JournalWindow (MWBase::WindowManager& parWindowManager)
|
||||
: WindowBase("openmw_journal.layout", parWindowManager)
|
||||
, mLastPos(0)
|
||||
, mVisible(false)
|
||||
, mPageNumber(0)
|
||||
{
|
||||
//setCoord(0,0,498, 342);
|
||||
center();
|
||||
|
@ -8,16 +8,21 @@
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
|
||||
#include "../mwworld/player.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
|
||||
#include "../mwmechanics/spells.hpp"
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwmechanics/spellsuccess.hpp"
|
||||
|
||||
|
||||
#include "tooltips.hpp"
|
||||
#include "widgets.hpp"
|
||||
#include "class.hpp"
|
||||
#include "inventorywindow.hpp"
|
||||
#include "tradewindow.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -297,7 +302,46 @@ namespace MWGui
|
||||
|
||||
void SpellCreationDialog::onBuyButtonClicked (MyGUI::Widget* sender)
|
||||
{
|
||||
if (mEffects.size() <= 0)
|
||||
{
|
||||
mWindowManager.messageBox ("#{sNotifyMessage30}", std::vector<std::string>());
|
||||
return;
|
||||
}
|
||||
|
||||
if (mNameEdit->getCaption () == "")
|
||||
{
|
||||
mWindowManager.messageBox ("#{sNotifyMessage10}", std::vector<std::string>());
|
||||
return;
|
||||
}
|
||||
|
||||
if (mMagickaCost->getCaption() == "0")
|
||||
{
|
||||
mWindowManager.messageBox ("#{sEnchantmentMenu8}", std::vector<std::string>());
|
||||
return;
|
||||
}
|
||||
|
||||
if (boost::lexical_cast<int>(mPriceLabel->getCaption()) > mWindowManager.getInventoryWindow()->getPlayerGold())
|
||||
{
|
||||
mWindowManager.messageBox ("#{sNotifyMessage18}", std::vector<std::string>());
|
||||
return;
|
||||
}
|
||||
|
||||
mSpell.mName = mNameEdit->getCaption();
|
||||
|
||||
mWindowManager.getTradeWindow()->addOrRemoveGold(-boost::lexical_cast<int>(mPriceLabel->getCaption()));
|
||||
|
||||
MWBase::Environment::get().getSoundManager()->playSound ("Item Gold Up", 1.0, 1.0);
|
||||
|
||||
std::pair<std::string, const ESM::Spell*> result = MWBase::Environment::get().getWorld()->createRecord(mSpell);
|
||||
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
|
||||
MWMechanics::Spells& spells = stats.getSpells();
|
||||
spells.add (result.first);
|
||||
|
||||
MWBase::Environment::get().getSoundManager()->playSound ("Item Gold Up", 1.0, 1.0);
|
||||
|
||||
mWindowManager.removeGuiMode (GM_SpellCreation);
|
||||
}
|
||||
|
||||
void SpellCreationDialog::open()
|
||||
@ -311,6 +355,47 @@ namespace MWGui
|
||||
mWindowManager.removeGuiMode (GM_SpellCreation);
|
||||
}
|
||||
|
||||
void SpellCreationDialog::notifyEffectsChanged ()
|
||||
{
|
||||
float y = 0;
|
||||
|
||||
for (std::vector<ESM::ENAMstruct>::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it)
|
||||
{
|
||||
float x = 0.5 * it->mMagnMin + it->mMagnMax;
|
||||
|
||||
const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().magicEffects.find(it->mEffectID);
|
||||
x *= 0.1 * effect->mData.mBaseCost;
|
||||
x *= 1 + it->mDuration;
|
||||
x += 0.05 * std::max(1, it->mArea) * effect->mData.mBaseCost;
|
||||
|
||||
float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore().gameSettings.find("fEffectCostMult")->getFloat();
|
||||
y += x * fEffectCostMult;
|
||||
y = std::max(1.f,y);
|
||||
|
||||
if (effect->mData.mFlags & ESM::MagicEffect::CastTarget)
|
||||
y *= 1.5;
|
||||
}
|
||||
|
||||
mSpell.mData.mCost = int(y);
|
||||
|
||||
ESM::EffectList effectList;
|
||||
effectList.mList = mEffects;
|
||||
mSpell.mEffects = effectList;
|
||||
mSpell.mData.mType = ESM::Spell::ST_Spell;
|
||||
|
||||
mMagickaCost->setCaption(boost::lexical_cast<std::string>(int(y)));
|
||||
|
||||
float fSpellMakingValueMult = MWBase::Environment::get().getWorld()->getStore().gameSettings.find("fSpellMakingValueMult")->getFloat();
|
||||
|
||||
/// \todo mercantile
|
||||
int price = int(y) * fSpellMakingValueMult;
|
||||
|
||||
mPriceLabel->setCaption(boost::lexical_cast<std::string>(int(price)));
|
||||
|
||||
float chance = MWMechanics::getSpellSuccessChance(&mSpell, MWBase::Environment::get().getWorld()->getPlayer().getPlayer());
|
||||
mSuccessChance->setCaption(boost::lexical_cast<std::string>(int(chance)));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@ -372,6 +457,9 @@ namespace MWGui
|
||||
|
||||
ToolTips::createMagicEffectToolTip (w, *it);
|
||||
}
|
||||
|
||||
mEffects.clear();
|
||||
updateEffectsView ();
|
||||
}
|
||||
|
||||
void EffectEditorBase::setWidgets (Widgets::MWList *availableEffectsList, MyGUI::ScrollView *usedEffectsView)
|
||||
@ -411,8 +499,23 @@ namespace MWGui
|
||||
|
||||
void EffectEditorBase::onAvailableEffectClicked (MyGUI::Widget* sender)
|
||||
{
|
||||
if (mEffects.size() >= 8)
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage28}", std::vector<std::string>());
|
||||
return;
|
||||
}
|
||||
|
||||
short effectId = *sender->getUserData<short>();
|
||||
|
||||
for (std::vector<ESM::ENAMstruct>::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it)
|
||||
{
|
||||
if (it->mEffectID == effectId)
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->messageBox ("#{sOnetypeEffectMessage}", std::vector<std::string>());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().magicEffects.find(effectId);
|
||||
|
||||
mAddEffectDialog.newEffect (effect);
|
||||
@ -492,6 +595,8 @@ namespace MWGui
|
||||
}
|
||||
|
||||
mUsedEffectsView->setCanvasSize(size);
|
||||
|
||||
notifyEffectsChanged();
|
||||
}
|
||||
|
||||
void EffectEditorBase::onEffectAdded (ESM::ENAMstruct effect)
|
||||
|
@ -116,6 +116,7 @@ namespace MWGui
|
||||
void startEditing();
|
||||
void setWidgets (Widgets::MWList* availableEffectsList, MyGUI::ScrollView* usedEffectsView);
|
||||
|
||||
virtual void notifyEffectsChanged () {}
|
||||
};
|
||||
|
||||
class SpellCreationDialog : public WindowBase, public ReferenceInterface, public EffectEditorBase
|
||||
@ -133,6 +134,7 @@ namespace MWGui
|
||||
void onCancelButtonClicked (MyGUI::Widget* sender);
|
||||
void onBuyButtonClicked (MyGUI::Widget* sender);
|
||||
|
||||
virtual void notifyEffectsChanged ();
|
||||
|
||||
MyGUI::EditBox* mNameEdit;
|
||||
MyGUI::TextBox* mMagickaCost;
|
||||
@ -143,6 +145,8 @@ namespace MWGui
|
||||
|
||||
Widgets::MWEffectList* mUsedEffectsList;
|
||||
|
||||
ESM::Spell mSpell;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -24,8 +24,8 @@ namespace MWMechanics
|
||||
{
|
||||
// magic effects
|
||||
adjustMagicEffects (ptr);
|
||||
calculateCreatureStatModifiers (ptr);
|
||||
calculateDynamicStats (ptr);
|
||||
calculateCreatureStatModifiers (ptr);
|
||||
|
||||
// AI
|
||||
CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr);
|
||||
@ -73,13 +73,17 @@ namespace MWMechanics
|
||||
double magickaFactor =
|
||||
creatureStats.getMagicEffects().get (EffectKey (84)).mMagnitude * 0.1 + 0.5;
|
||||
|
||||
creatureStats.getHealth().setBase(
|
||||
static_cast<int> (0.5 * (strength + endurance)) + creatureStats.getLevelHealthBonus ());
|
||||
DynamicStat<float> health = creatureStats.getHealth();
|
||||
health.setBase (static_cast<int> (0.5 * (strength + endurance)) + creatureStats.getLevelHealthBonus ());
|
||||
creatureStats.setHealth (health);
|
||||
|
||||
creatureStats.getMagicka().setBase(
|
||||
static_cast<int> (intelligence + magickaFactor * intelligence));
|
||||
|
||||
creatureStats.getFatigue().setBase(strength+willpower+agility+endurance);
|
||||
DynamicStat<float> magicka = creatureStats.getMagicka();
|
||||
magicka.setBase (static_cast<int> (intelligence + magickaFactor * intelligence));
|
||||
creatureStats.setMagicka (magicka);
|
||||
|
||||
DynamicStat<float> fatigue = creatureStats.getFatigue();
|
||||
fatigue.setBase (strength+willpower+agility+endurance);
|
||||
creatureStats.setFatigue (fatigue);
|
||||
}
|
||||
|
||||
void Actors::calculateRestoration (const MWWorld::Ptr& ptr, float duration)
|
||||
@ -92,8 +96,10 @@ namespace MWMechanics
|
||||
bool stunted = stats.getMagicEffects ().get(MWMechanics::EffectKey(136)).mMagnitude > 0;
|
||||
|
||||
int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified ();
|
||||
stats.getHealth().setCurrent(stats.getHealth ().getCurrent ()
|
||||
+ 0.1 * endurance);
|
||||
|
||||
DynamicStat<float> health = stats.getHealth();
|
||||
health.setCurrent (health.getCurrent() + 0.1 * endurance);
|
||||
stats.setHealth (health);
|
||||
|
||||
const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
||||
|
||||
@ -109,13 +115,19 @@ namespace MWMechanics
|
||||
|
||||
float x = fFatigueReturnBase + fFatigueReturnMult * (1 - normalizedEncumbrance);
|
||||
x *= fEndFatigueMult * endurance;
|
||||
stats.getFatigue ().setCurrent (stats.getFatigue ().getCurrent () + 3600 * x);
|
||||
|
||||
|
||||
DynamicStat<float> fatigue = stats.getFatigue();
|
||||
fatigue.setCurrent (fatigue.getCurrent() + 3600 * x);
|
||||
stats.setFatigue (fatigue);
|
||||
|
||||
if (!stunted)
|
||||
{
|
||||
float fRestMagicMult = store.gameSettings.find("fRestMagicMult")->getFloat ();
|
||||
stats.getMagicka().setCurrent (stats.getMagicka ().getCurrent ()
|
||||
+ fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified ());
|
||||
|
||||
DynamicStat<float> magicka = stats.getMagicka();
|
||||
magicka.setCurrent (magicka.getCurrent()
|
||||
+ fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified());
|
||||
stats.setMagicka (magicka);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -137,21 +149,26 @@ namespace MWMechanics
|
||||
|
||||
// dynamic stats
|
||||
MagicEffects effects = creatureStats.getMagicEffects();
|
||||
creatureStats.getHealth().setModifier(
|
||||
effects.get(EffectKey(80)).mMagnitude - effects.get(EffectKey(18)).mMagnitude);
|
||||
|
||||
creatureStats.getMagicka().setModifier(
|
||||
effects.get(EffectKey(81)).mMagnitude - effects.get(EffectKey(19)).mMagnitude);
|
||||
|
||||
creatureStats.getFatigue().setModifier(
|
||||
effects.get(EffectKey(82)).mMagnitude - effects.get(EffectKey(20)).mMagnitude);
|
||||
|
||||
for (int i=0; i<3; ++i)
|
||||
{
|
||||
DynamicStat<float> stat = creatureStats.getDynamic (i);
|
||||
|
||||
stat.setModifier (
|
||||
effects.get (EffectKey(80+i)).mMagnitude - effects.get (EffectKey(18+i)).mMagnitude);
|
||||
|
||||
creatureStats.setDynamic (i, stat);
|
||||
}
|
||||
}
|
||||
|
||||
Actors::Actors() : mDuration (0) {}
|
||||
|
||||
void Actors::addActor (const MWWorld::Ptr& ptr)
|
||||
{
|
||||
mActors.insert (ptr);
|
||||
if (!MWWorld::Class::get (ptr).getCreatureStats (ptr).isDead())
|
||||
mActors.insert (ptr);
|
||||
else
|
||||
MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, "death1", 2);
|
||||
}
|
||||
|
||||
void Actors::removeActor (const MWWorld::Ptr& ptr)
|
||||
@ -184,13 +201,51 @@ namespace MWMechanics
|
||||
{
|
||||
float totalDuration = mDuration;
|
||||
mDuration = 0;
|
||||
|
||||
std::set<MWWorld::Ptr>::iterator iter (mActors.begin());
|
||||
|
||||
for (std::set<MWWorld::Ptr>::iterator iter (mActors.begin()); iter!=mActors.end(); ++iter)
|
||||
while (iter!=mActors.end())
|
||||
{
|
||||
updateActor (*iter, totalDuration);
|
||||
if (!MWWorld::Class::get (*iter).getCreatureStats (*iter).isDead())
|
||||
{
|
||||
updateActor (*iter, totalDuration);
|
||||
|
||||
if (iter->getTypeName()==typeid (ESM::NPC).name())
|
||||
updateNpc (*iter, totalDuration, paused);
|
||||
if (iter->getTypeName()==typeid (ESM::NPC).name())
|
||||
updateNpc (*iter, totalDuration, paused);
|
||||
}
|
||||
|
||||
if (MWWorld::Class::get (*iter).getCreatureStats (*iter).isDead())
|
||||
{
|
||||
// workaround: always keep player alive for now
|
||||
// \todo remove workaround, once player death can be handled
|
||||
if (iter->getRefData().getHandle()=="player")
|
||||
{
|
||||
MWMechanics::DynamicStat<float> stat (
|
||||
MWWorld::Class::get (*iter).getCreatureStats (*iter).getHealth());
|
||||
|
||||
if (stat.getModified()<1)
|
||||
{
|
||||
stat.setModified (1, 0);
|
||||
MWWorld::Class::get (*iter).getCreatureStats (*iter).setHealth (stat);
|
||||
}
|
||||
|
||||
MWWorld::Class::get (*iter).getCreatureStats (*iter).resurrect();
|
||||
++iter;
|
||||
continue;
|
||||
}
|
||||
|
||||
++mDeathCount[MWWorld::Class::get (*iter).getId (*iter)];
|
||||
|
||||
MWBase::Environment::get().getWorld()->playAnimationGroup (*iter, "death1", 0);
|
||||
|
||||
if (MWWorld::Class::get (*iter).isEssential (*iter))
|
||||
MWBase::Environment::get().getWindowManager()->messageBox (
|
||||
"#{sKilledEssential}", std::vector<std::string>());
|
||||
|
||||
mActors.erase (iter++);
|
||||
}
|
||||
else
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
@ -211,4 +266,14 @@ namespace MWMechanics
|
||||
calculateRestoration (*iter, 3600);
|
||||
}
|
||||
}
|
||||
|
||||
int Actors::countDeaths (const std::string& id) const
|
||||
{
|
||||
std::map<std::string, int>::const_iterator iter = mDeathCount.find (id);
|
||||
|
||||
if (iter!=mDeathCount.end())
|
||||
return iter->second;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
namespace Ogre
|
||||
{
|
||||
@ -22,6 +23,7 @@ namespace MWMechanics
|
||||
{
|
||||
std::set<MWWorld::Ptr> mActors;
|
||||
float mDuration;
|
||||
std::map<std::string, int> mDeathCount;
|
||||
|
||||
void updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused);
|
||||
|
||||
@ -40,6 +42,8 @@ namespace MWMechanics
|
||||
|
||||
void addActor (const MWWorld::Ptr& ptr);
|
||||
///< Register an actor for stats management
|
||||
///
|
||||
/// \note Dead actors are ignored.
|
||||
|
||||
void removeActor (const MWWorld::Ptr& ptr);
|
||||
///< Deregister an actor for stats management
|
||||
@ -59,6 +63,9 @@ namespace MWMechanics
|
||||
|
||||
void restoreDynamicStats();
|
||||
///< If the player is sleeping, this should be called every hour.
|
||||
|
||||
int countDeaths (const std::string& id) const;
|
||||
///< Return the number of deaths for actors with the given ID.
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <map>
|
||||
|
||||
#include <components/esm/loadskil.hpp>
|
||||
#include <components/esm/loadappa.hpp>
|
||||
@ -28,7 +29,7 @@
|
||||
|
||||
std::set<MWMechanics::EffectKey> MWMechanics::Alchemy::listEffects() const
|
||||
{
|
||||
std::set<EffectKey> effects;
|
||||
std::map<EffectKey, int> effects;
|
||||
|
||||
for (TIngredientsIterator iter (mIngredients.begin()); iter!=mIngredients.end(); ++iter)
|
||||
{
|
||||
@ -38,57 +39,23 @@ std::set<MWMechanics::EffectKey> MWMechanics::Alchemy::listEffects() const
|
||||
|
||||
for (int i=0; i<4; ++i)
|
||||
if (ingredient->base->mData.mEffectID[i]!=-1)
|
||||
effects.insert (EffectKey (
|
||||
{
|
||||
EffectKey key (
|
||||
ingredient->base->mData.mEffectID[i], ingredient->base->mData.mSkills[i]!=-1 ?
|
||||
ingredient->base->mData.mSkills[i] : ingredient->base->mData.mAttributes[i]));
|
||||
ingredient->base->mData.mSkills[i] : ingredient->base->mData.mAttributes[i]);
|
||||
|
||||
++effects[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return effects;
|
||||
}
|
||||
|
||||
void MWMechanics::Alchemy::filterEffects (std::set<EffectKey>& effects) const
|
||||
{
|
||||
std::set<EffectKey>::iterator iter = effects.begin();
|
||||
std::set<EffectKey> effects2;
|
||||
|
||||
while (iter!=effects.end())
|
||||
{
|
||||
bool remove = false;
|
||||
|
||||
const EffectKey& key = *iter;
|
||||
|
||||
{ // dodge pointless g++ warning
|
||||
for (TIngredientsIterator iter (mIngredients.begin()); iter!=mIngredients.end(); ++iter)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
if (iter->isEmpty())
|
||||
continue;
|
||||
|
||||
const MWWorld::LiveCellRef<ESM::Ingredient> *ingredient = iter->get<ESM::Ingredient>();
|
||||
|
||||
for (int i=0; i<4; ++i)
|
||||
if (key.mId==ingredient->base->mData.mEffectID[i] &&
|
||||
(key.mArg==ingredient->base->mData.mSkills[i] ||
|
||||
key.mArg==ingredient->base->mData.mAttributes[i]))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
remove = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (remove)
|
||||
effects.erase (iter++);
|
||||
else
|
||||
++iter;
|
||||
}
|
||||
for (std::map<EffectKey, int>::const_iterator iter (effects.begin()); iter!=effects.end(); ++iter)
|
||||
if (iter->second>1)
|
||||
effects2.insert (iter->first);
|
||||
|
||||
return effects2;
|
||||
}
|
||||
|
||||
void MWMechanics::Alchemy::applyTools (int flags, float& value) const
|
||||
@ -159,7 +126,6 @@ void MWMechanics::Alchemy::updateEffects()
|
||||
|
||||
// find effects
|
||||
std::set<EffectKey> effects (listEffects());
|
||||
filterEffects (effects);
|
||||
|
||||
// general alchemy factor
|
||||
float x = getChance();
|
||||
|
@ -46,10 +46,7 @@ namespace MWMechanics
|
||||
int mValue;
|
||||
|
||||
std::set<EffectKey> listEffects() const;
|
||||
///< List all effects of all used ingredients.
|
||||
|
||||
void filterEffects (std::set<EffectKey>& effects) const;
|
||||
///< Filter out effects not shared by all ingredients.
|
||||
///< List all effects shared by at least two ingredients.
|
||||
|
||||
void applyTools (int flags, float& value) const;
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
namespace MWMechanics
|
||||
{
|
||||
CreatureStats::CreatureStats()
|
||||
: mLevelHealthBonus(0.f)
|
||||
: mLevel (0), mHello (0), mFight (0), mFlee (0), mAlarm (0), mLevelHealthBonus(0.f), mDead (false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -118,22 +118,7 @@ namespace MWMechanics
|
||||
return mAttributes[index];
|
||||
}
|
||||
|
||||
DynamicStat<float> &CreatureStats::getHealth()
|
||||
{
|
||||
return mDynamic[0];
|
||||
}
|
||||
|
||||
DynamicStat<float> &CreatureStats::getMagicka()
|
||||
{
|
||||
return mDynamic[1];
|
||||
}
|
||||
|
||||
DynamicStat<float> &CreatureStats::getFatigue()
|
||||
{
|
||||
return mDynamic[2];
|
||||
}
|
||||
|
||||
DynamicStat<float> &CreatureStats::getDynamic(int index)
|
||||
const DynamicStat<float> &CreatureStats::getDynamic(int index) const
|
||||
{
|
||||
if (index < 0 || index > 2) {
|
||||
throw std::runtime_error("dynamic stat index is out of range");
|
||||
@ -171,19 +156,30 @@ namespace MWMechanics
|
||||
|
||||
void CreatureStats::setHealth(const DynamicStat<float> &value)
|
||||
{
|
||||
mDynamic[0] = value;
|
||||
setDynamic (0, value);
|
||||
}
|
||||
|
||||
void CreatureStats::setMagicka(const DynamicStat<float> &value)
|
||||
{
|
||||
mDynamic[1] = value;
|
||||
setDynamic (1, value);
|
||||
}
|
||||
|
||||
void CreatureStats::setFatigue(const DynamicStat<float> &value)
|
||||
{
|
||||
mDynamic[2] = value;
|
||||
setDynamic (2, value);
|
||||
}
|
||||
|
||||
void CreatureStats::setDynamic (int index, const DynamicStat<float> &value)
|
||||
{
|
||||
if (index < 0 || index > 2)
|
||||
throw std::runtime_error("dynamic stat index is out of range");
|
||||
|
||||
mDynamic[index] = value;
|
||||
|
||||
if (index==0 && mDynamic[index].getCurrent()<1)
|
||||
mDead = true;
|
||||
}
|
||||
|
||||
void CreatureStats::setLevel(int level)
|
||||
{
|
||||
mLevel = level;
|
||||
@ -218,4 +214,21 @@ namespace MWMechanics
|
||||
{
|
||||
mAlarm = value;
|
||||
}
|
||||
|
||||
bool CreatureStats::isDead() const
|
||||
{
|
||||
return mDead;
|
||||
}
|
||||
|
||||
void CreatureStats::resurrect()
|
||||
{
|
||||
if (mDead)
|
||||
{
|
||||
if (mDynamic[0].getCurrent()<1)
|
||||
mDynamic[0].setCurrent (1);
|
||||
|
||||
if (mDynamic[0].getCurrent()>=1)
|
||||
mDead = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,8 +29,8 @@ namespace MWMechanics
|
||||
int mFlee;
|
||||
int mAlarm;
|
||||
AiSequence mAiSequence;
|
||||
|
||||
float mLevelHealthBonus;
|
||||
bool mDead;
|
||||
|
||||
public:
|
||||
CreatureStats();
|
||||
@ -43,6 +43,8 @@ namespace MWMechanics
|
||||
|
||||
const DynamicStat<float> & getFatigue() const;
|
||||
|
||||
const DynamicStat<float> & getDynamic (int index) const;
|
||||
|
||||
const Spells & getSpells() const;
|
||||
|
||||
const ActiveSpells & getActiveSpells() const;
|
||||
@ -59,24 +61,14 @@ namespace MWMechanics
|
||||
|
||||
int getAlarm() const;
|
||||
|
||||
|
||||
Stat<int> & getAttribute(int index);
|
||||
|
||||
DynamicStat<float> & getHealth();
|
||||
|
||||
DynamicStat<float> & getMagicka();
|
||||
|
||||
DynamicStat<float> & getFatigue();
|
||||
|
||||
DynamicStat<float> & getDynamic(int index);
|
||||
|
||||
Spells & getSpells();
|
||||
|
||||
ActiveSpells & getActiveSpells();
|
||||
|
||||
MagicEffects & getMagicEffects();
|
||||
|
||||
|
||||
void setAttribute(int index, const Stat<int> &value);
|
||||
|
||||
void setHealth(const DynamicStat<float> &value);
|
||||
@ -85,6 +77,8 @@ namespace MWMechanics
|
||||
|
||||
void setFatigue(const DynamicStat<float> &value);
|
||||
|
||||
void setDynamic (int index, const DynamicStat<float> &value);
|
||||
|
||||
void setSpells(const Spells &spells);
|
||||
|
||||
void setActiveSpells(const ActiveSpells &active);
|
||||
@ -111,6 +105,10 @@ namespace MWMechanics
|
||||
// small hack to allow the fact that Health permanently increases by 10% of endurance on each level up
|
||||
void increaseLevelHealthBonus(float value);
|
||||
float getLevelHealthBonus() const;
|
||||
|
||||
bool isDead() const;
|
||||
|
||||
void resurrect();
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -153,12 +153,14 @@ namespace MWMechanics
|
||||
// forced update and current value adjustments
|
||||
mActors.updateActor (ptr, 0);
|
||||
|
||||
creatureStats.getHealth().setCurrent(creatureStats.getHealth().getModified());
|
||||
creatureStats.getMagicka().setCurrent(creatureStats.getMagicka().getModified());
|
||||
creatureStats.getFatigue().setCurrent(creatureStats.getFatigue().getModified());
|
||||
for (int i=0; i<2; ++i)
|
||||
{
|
||||
DynamicStat<float> stat = creatureStats.getDynamic (i);
|
||||
stat.setCurrent (stat.getModified());
|
||||
creatureStats.setDynamic (i, stat);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MechanicsManager::MechanicsManager()
|
||||
: mUpdatePlayer (true), mClassSelected (false),
|
||||
mRaceSelected (false)
|
||||
@ -324,4 +326,9 @@ namespace MWMechanics
|
||||
buildPlayer();
|
||||
mUpdatePlayer = true;
|
||||
}
|
||||
|
||||
int MechanicsManager::countDeaths (const std::string& id) const
|
||||
{
|
||||
return mActors.countDeaths (id);
|
||||
}
|
||||
}
|
||||
|
@ -41,6 +41,8 @@ namespace MWMechanics
|
||||
|
||||
virtual void addActor (const MWWorld::Ptr& ptr);
|
||||
///< Register an actor for stats management
|
||||
///
|
||||
/// \note Dead actors are ignored.
|
||||
|
||||
virtual void removeActor (const MWWorld::Ptr& ptr);
|
||||
///< Deregister an actor for stats management
|
||||
@ -76,6 +78,10 @@ namespace MWMechanics
|
||||
|
||||
virtual void restoreDynamicStats();
|
||||
///< If the player is sleeping, this should be called every hour.
|
||||
|
||||
virtual int countDeaths (const std::string& id) const;
|
||||
///< Return the number of deaths for actors with the given ID.
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -27,9 +27,8 @@ namespace MWMechanics
|
||||
return schoolSkillMap[school];
|
||||
}
|
||||
|
||||
inline int getSpellSchool(const std::string& spellId, const MWWorld::Ptr& actor)
|
||||
inline int getSpellSchool(const ESM::Spell* spell, const MWWorld::Ptr& actor)
|
||||
{
|
||||
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(spellId);
|
||||
NpcStats& stats = MWWorld::Class::get(actor).getNpcStats(actor);
|
||||
|
||||
// determine the spell's school
|
||||
@ -60,27 +59,34 @@ namespace MWMechanics
|
||||
return school;
|
||||
}
|
||||
|
||||
inline int getSpellSchool(const std::string& spellId, const MWWorld::Ptr& actor)
|
||||
{
|
||||
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(spellId);
|
||||
return getSpellSchool(spell, actor);
|
||||
}
|
||||
|
||||
|
||||
// UESP wiki / Morrowind/Spells:
|
||||
// Chance of success is (Spell's skill * 2 + Willpower / 5 + Luck / 10 - Spell cost - Sound magnitude) * (Current fatigue + Maximum Fatigue * 1.5) / Maximum fatigue * 2
|
||||
/**
|
||||
* @param spellId ID of spell
|
||||
* @param spell spell to cast
|
||||
* @param actor calculate spell success chance for this actor (depends on actor's skills)
|
||||
* @attention actor has to be an NPC and not a creature!
|
||||
* @return success chance from 0 to 100 (in percent)
|
||||
*/
|
||||
inline float getSpellSuccessChance (const std::string& spellId, const MWWorld::Ptr& actor)
|
||||
inline float getSpellSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor)
|
||||
{
|
||||
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(spellId);
|
||||
|
||||
if (spell->mData.mFlags & ESM::Spell::F_Always // spells with this flag always succeed (usually birthsign spells)
|
||||
|| spell->mData.mType == ESM::Spell::ST_Power) // powers always succeed, but can be cast only once per day
|
||||
return 100.0;
|
||||
|
||||
if (spell->mEffects.mList.size() == 0)
|
||||
return 0.0;
|
||||
|
||||
NpcStats& stats = MWWorld::Class::get(actor).getNpcStats(actor);
|
||||
CreatureStats& creatureStats = MWWorld::Class::get(actor).getCreatureStats(actor);
|
||||
|
||||
int skillLevel = stats.getSkill (getSpellSchool(spellId, actor)).getModified();
|
||||
int skillLevel = stats.getSkill (getSpellSchool(spell, actor)).getModified();
|
||||
|
||||
// Sound magic effect (reduces spell casting chance)
|
||||
int soundMagnitude = creatureStats.getMagicEffects().get (MWMechanics::EffectKey (48)).mMagnitude;
|
||||
@ -98,6 +104,12 @@ namespace MWMechanics
|
||||
|
||||
return chance;
|
||||
}
|
||||
|
||||
inline float getSpellSuccessChance (const std::string& spellId, const MWWorld::Ptr& actor)
|
||||
{
|
||||
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(spellId);
|
||||
return getSpellSuccessChance(spell, actor);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -67,7 +67,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
|
||||
// material system
|
||||
sh::OgrePlatform* platform = new sh::OgrePlatform("General", (resDir / "materials").string());
|
||||
if (!boost::filesystem::exists (cacheDir))
|
||||
boost::filesystem::create_directory (cacheDir);
|
||||
boost::filesystem::create_directories (cacheDir);
|
||||
platform->setCacheFolder (cacheDir.string());
|
||||
mFactory = new sh::Factory(platform);
|
||||
|
||||
|
@ -206,5 +206,6 @@ op 0x200019f: GetPcSleep
|
||||
op 0x20001a0: ShowMap
|
||||
op 0x20001a1: FillMap
|
||||
op 0x20001a2: WakeUpPc
|
||||
opcodes 0x20001a3-0x3ffffff unused
|
||||
op 0x20001a3: GetDeadCount
|
||||
opcodes 0x20001a4-0x3ffffff unused
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/dialoguemanager.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/player.hpp"
|
||||
@ -155,7 +156,7 @@ namespace MWScript
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
Interpreter::Type_Integer value;
|
||||
Interpreter::Type_Float value;
|
||||
|
||||
if (mIndex==0 && MWWorld::Class::get (ptr).hasItemHealth (ptr))
|
||||
{
|
||||
@ -185,13 +186,15 @@ namespace MWScript
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
Interpreter::Type_Integer value = runtime[0].mInteger;
|
||||
Interpreter::Type_Float value = runtime[0].mFloat;
|
||||
runtime.pop();
|
||||
|
||||
MWWorld::Class::get(ptr)
|
||||
.getCreatureStats(ptr)
|
||||
.getDynamic(mIndex)
|
||||
.setModified(value, 0);
|
||||
MWMechanics::DynamicStat<float> stat (MWWorld::Class::get (ptr).getCreatureStats (ptr)
|
||||
.getDynamic (mIndex));
|
||||
|
||||
stat.setModified (value, 0);
|
||||
|
||||
MWWorld::Class::get (ptr).getCreatureStats (ptr).setDynamic (mIndex, stat);
|
||||
}
|
||||
};
|
||||
|
||||
@ -208,17 +211,21 @@ namespace MWScript
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
Interpreter::Type_Integer diff = runtime[0].mInteger;
|
||||
Interpreter::Type_Float diff = runtime[0].mFloat;
|
||||
runtime.pop();
|
||||
|
||||
MWMechanics::CreatureStats& stats = MWWorld::Class::get (ptr).getCreatureStats (ptr);
|
||||
|
||||
Interpreter::Type_Integer current = stats.getDynamic(mIndex).getCurrent();
|
||||
Interpreter::Type_Float current = stats.getDynamic(mIndex).getCurrent();
|
||||
|
||||
stats.getDynamic(mIndex).setModified(
|
||||
diff + stats.getDynamic(mIndex).getModified(), 0);
|
||||
MWMechanics::DynamicStat<float> stat (MWWorld::Class::get (ptr).getCreatureStats (ptr)
|
||||
.getDynamic (mIndex));
|
||||
|
||||
stats.getDynamic(mIndex).setCurrent(diff + current);
|
||||
stat.setModified (diff + stat.getModified(), 0);
|
||||
|
||||
stat.setCurrent (diff + current);
|
||||
|
||||
MWWorld::Class::get (ptr).getCreatureStats (ptr).setDynamic (mIndex, stat);
|
||||
}
|
||||
};
|
||||
|
||||
@ -235,14 +242,19 @@ namespace MWScript
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
Interpreter::Type_Integer diff = runtime[0].mInteger;
|
||||
Interpreter::Type_Float diff = runtime[0].mFloat;
|
||||
runtime.pop();
|
||||
|
||||
MWMechanics::CreatureStats& stats = MWWorld::Class::get (ptr).getCreatureStats (ptr);
|
||||
|
||||
Interpreter::Type_Integer current = stats.getDynamic(mIndex).getCurrent();
|
||||
Interpreter::Type_Float current = stats.getDynamic(mIndex).getCurrent();
|
||||
|
||||
stats.getDynamic(mIndex).setCurrent (diff + current);
|
||||
MWMechanics::DynamicStat<float> stat (MWWorld::Class::get (ptr).getCreatureStats (ptr)
|
||||
.getDynamic (mIndex));
|
||||
|
||||
stat.setCurrent (diff + current);
|
||||
|
||||
MWWorld::Class::get (ptr).getCreatureStats (ptr).setDynamic (mIndex, stat);
|
||||
}
|
||||
};
|
||||
|
||||
@ -580,6 +592,17 @@ namespace MWScript
|
||||
/// \todo modify disposition towards the player
|
||||
}
|
||||
};
|
||||
|
||||
class OpGetDeadCount : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
std::string id = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime[0].mInteger = MWBase::Environment::get().getMechanicsManager()->countDeaths (id);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const int numberOfAttributes = 8;
|
||||
@ -632,6 +655,8 @@ namespace MWScript
|
||||
const int opcodeGetLevelExplicit = 0x200018d;
|
||||
const int opcodeSetLevel = 0x200018e;
|
||||
const int opcodeSetLevelExplicit = 0x200018f;
|
||||
|
||||
const int opcodeGetDeadCount = 0x20001a3;
|
||||
|
||||
void registerExtensions (Compiler::Extensions& extensions)
|
||||
{
|
||||
@ -676,16 +701,16 @@ namespace MWScript
|
||||
|
||||
for (int i=0; i<numberOfDynamics; ++i)
|
||||
{
|
||||
extensions.registerFunction (get + dynamics[i], 'l', "",
|
||||
extensions.registerFunction (get + dynamics[i], 'f', "",
|
||||
opcodeGetDynamic+i, opcodeGetDynamicExplicit+i);
|
||||
|
||||
extensions.registerInstruction (set + dynamics[i], "l",
|
||||
extensions.registerInstruction (set + dynamics[i], "f",
|
||||
opcodeSetDynamic+i, opcodeSetDynamicExplicit+i);
|
||||
|
||||
extensions.registerInstruction (mod + dynamics[i], "l",
|
||||
extensions.registerInstruction (mod + dynamics[i], "f",
|
||||
opcodeModDynamic+i, opcodeModDynamicExplicit+i);
|
||||
|
||||
extensions.registerInstruction (modCurrent + dynamics[i], "l",
|
||||
extensions.registerInstruction (modCurrent + dynamics[i], "f",
|
||||
opcodeModCurrentDynamic+i, opcodeModCurrentDynamicExplicit+i);
|
||||
|
||||
extensions.registerFunction (get + dynamics[i] + getRatio, 'f', "",
|
||||
@ -718,6 +743,8 @@ namespace MWScript
|
||||
|
||||
extensions.registerInstruction("setlevel", "l", opcodeSetLevel, opcodeSetLevelExplicit);
|
||||
extensions.registerFunction("getlevel", 'l', "", opcodeGetLevel, opcodeGetLevelExplicit);
|
||||
|
||||
extensions.registerFunction("getdeadcount", 'l', "c", opcodeGetDeadCount);
|
||||
}
|
||||
|
||||
void installOpcodes (Interpreter::Interpreter& interpreter)
|
||||
@ -795,6 +822,7 @@ namespace MWScript
|
||||
interpreter.installSegment5 (opcodeSetLevel, new OpSetLevel<ImplicitRef>);
|
||||
interpreter.installSegment5 (opcodeSetLevelExplicit, new OpSetLevel<ExplicitRef>);
|
||||
|
||||
interpreter.installSegment5 (opcodeGetDeadCount, new OpGetDeadCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -157,6 +157,11 @@ namespace MWWorld
|
||||
throw std::runtime_error ("encumbrance not supported by class");
|
||||
}
|
||||
|
||||
bool Class::isEssential (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const Class& Class::get (const std::string& key)
|
||||
{
|
||||
std::map<std::string, boost::shared_ptr<Class> >::const_iterator iter = sClasses.find (key);
|
||||
|
@ -186,6 +186,11 @@ namespace MWWorld
|
||||
///
|
||||
/// (default implementations: throws an exception)
|
||||
|
||||
virtual bool isEssential (const MWWorld::Ptr& ptr) const;
|
||||
///< Is \a ptr essential? (i.e. may losing \a ptr make the game unwinnable)
|
||||
///
|
||||
/// (default implementation: return false)
|
||||
|
||||
static const Class& get (const std::string& key);
|
||||
///< If there is no class for this \a key, an exception is thrown.
|
||||
|
||||
|
@ -810,6 +810,20 @@ namespace MWWorld
|
||||
return std::make_pair (stream.str(), created);
|
||||
}
|
||||
|
||||
std::pair<std::string, const ESM::Spell *> World::createRecord (const ESM::Spell& record)
|
||||
{
|
||||
/// \todo See function above.
|
||||
std::ostringstream stream;
|
||||
stream << "$dynamic" << mNextDynamicRecord++;
|
||||
|
||||
const ESM::Spell *created =
|
||||
&mStore.spells.list.insert (std::make_pair (stream.str(), record)).first->second;
|
||||
|
||||
mStore.all.insert (std::make_pair (stream.str(), ESM::REC_SPEL));
|
||||
|
||||
return std::make_pair (stream.str(), created);
|
||||
}
|
||||
|
||||
const ESM::Cell *World::createRecord (const ESM::Cell& record)
|
||||
{
|
||||
if (record.mData.mFlags & ESM::Cell::Interior)
|
||||
|
@ -256,6 +256,10 @@ namespace MWWorld
|
||||
///< Create a new recrod (of type potion) in the ESM store.
|
||||
/// \return ID, pointer to created record
|
||||
|
||||
virtual std::pair<std::string, const ESM::Spell *> createRecord (const ESM::Spell& record);
|
||||
///< Create a new recrod (of type spell) in the ESM store.
|
||||
/// \return ID, pointer to created record
|
||||
|
||||
virtual std::pair<std::string, const ESM::Class *> createRecord (const ESM::Class& record);
|
||||
///< Create a new recrod (of type class) in the ESM store.
|
||||
/// \return ID, pointer to created record
|
||||
|
@ -71,7 +71,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource)
|
||||
{
|
||||
cShape = static_cast<BulletShape *>(resource);
|
||||
resourceName = cShape->getName();
|
||||
cShape->collide = false;
|
||||
cShape->mCollide = false;
|
||||
mBoundingBox = NULL;
|
||||
cShape->boxTranslation = Ogre::Vector3(0,0,0);
|
||||
cShape->boxRotation = Ogre::Quaternion::IDENTITY;
|
||||
@ -108,7 +108,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource)
|
||||
handleNode(node,0,NULL,hasCollisionNode,false,false);
|
||||
|
||||
//if collide = false, then it does a second pass which create a shape for raycasting.
|
||||
if(cShape->collide == false)
|
||||
if(cShape->mCollide == false)
|
||||
{
|
||||
handleNode(node,0,NULL,hasCollisionNode,false,true);
|
||||
}
|
||||
@ -177,6 +177,7 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags,
|
||||
if (node->name.find("marker") != std::string::npos)
|
||||
{
|
||||
flags |= 0x800;
|
||||
cShape->mIgnore = true;
|
||||
}
|
||||
|
||||
// Check for extra data
|
||||
@ -254,7 +255,7 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags,
|
||||
}
|
||||
else if (node->recType == Nif::RC_NiTriShape && (isCollisionNode || !hasCollisionNode))
|
||||
{
|
||||
cShape->collide = !(flags&0x800);
|
||||
cShape->mCollide = !(flags&0x800);
|
||||
handleNiTriShape(dynamic_cast<Nif::NiTriShape*>(node), flags,node->trafo.rotation,node->trafo.pos,node->trafo.scale,raycastingOnly);
|
||||
}
|
||||
else if(node->recType == Nif::RC_RootCollisionNode)
|
||||
|
@ -157,10 +157,15 @@
|
||||
shUniform(float4, shadowFar_fadeStart) @shSharedParameter(shadowFar_fadeStart)
|
||||
#endif
|
||||
|
||||
#if UNDERWATER
|
||||
#if (UNDERWATER) || (FOG)
|
||||
shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix)
|
||||
shUniform(float, waterLevel) @shSharedParameter(waterLevel)
|
||||
shUniform(float4, cameraPos) @shAutoConstant(cameraPos, camera_position)
|
||||
#endif
|
||||
|
||||
#if UNDERWATER
|
||||
|
||||
shUniform(float, waterLevel) @shSharedParameter(waterLevel)
|
||||
|
||||
shUniform(float4, lightDirectionWS0) @shAutoConstant(lightDirectionWS0, light_position, 0)
|
||||
|
||||
shSampler2D(causticMap)
|
||||
@ -211,8 +216,12 @@
|
||||
|
||||
|
||||
float3 caustics = float3(1,1,1);
|
||||
#if UNDERWATER
|
||||
|
||||
#if (UNDERWATER) || (FOG)
|
||||
float3 worldPos = shMatrixMult(worldMatrix, float4(objSpacePositionPassthrough,1)).xyz;
|
||||
#endif
|
||||
|
||||
#if UNDERWATER
|
||||
float3 waterEyePos = float3(1,1,1);
|
||||
// NOTE: this calculation would be wrong for non-uniform scaling
|
||||
float4 worldNormal = shMatrixMult(worldMatrix, float4(normal.xyz, 0));
|
||||
|
@ -187,11 +187,13 @@
|
||||
shUniform(float4, shadowFar_fadeStart) @shSharedParameter(shadowFar_fadeStart)
|
||||
#endif
|
||||
|
||||
#if (UNDERWATER) || (FOG)
|
||||
shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix)
|
||||
shUniform(float4, cameraPos) @shAutoConstant(cameraPos, camera_position)
|
||||
#endif
|
||||
|
||||
#if UNDERWATER
|
||||
shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix)
|
||||
shUniform(float, waterLevel) @shSharedParameter(waterLevel)
|
||||
shUniform(float4, cameraPos) @shAutoConstant(cameraPos, camera_position)
|
||||
shUniform(float4, lightDirectionWS0) @shAutoConstant(lightDirectionWS0, light_position, 0)
|
||||
|
||||
shSampler2D(causticMap)
|
||||
@ -222,9 +224,12 @@
|
||||
|
||||
|
||||
float3 caustics = float3(1,1,1);
|
||||
#if (UNDERWATER) || (FOG)
|
||||
float3 worldPos = shMatrixMult(worldMatrix, float4(objSpacePosition,1)).xyz;
|
||||
#endif
|
||||
|
||||
#if UNDERWATER
|
||||
|
||||
float3 worldPos = shMatrixMult(worldMatrix, float4(objSpacePosition,1)).xyz;
|
||||
float3 waterEyePos = float3(1,1,1);
|
||||
// NOTE: this calculation would be wrong for non-uniform scaling
|
||||
float4 worldNormal = shMatrixMult(worldMatrix, float4(normal.xyz, 0));
|
||||
@ -373,7 +378,6 @@
|
||||
|
||||
shOutputColour(0).xyz = gammaCorrectOutput(shOutputColour(0).xyz);
|
||||
|
||||
|
||||
#if MRT
|
||||
shOutputColour(1) = float4(depth / far,1,1,1);
|
||||
#endif
|
||||
|
@ -22,7 +22,6 @@
|
||||
<Property key="Caption" value="#{sEnchantmentMenu4}"/>
|
||||
</Widget>
|
||||
<Widget type="TextBox" skin="SandText" position="280 0 258 24" name="MagickaCost">
|
||||
<Property key="Caption" value="1"/>
|
||||
<Property key="TextAlign" value="Right HCenter"/>
|
||||
</Widget>
|
||||
|
||||
@ -31,7 +30,6 @@
|
||||
<Property key="Caption" value="#{sSpellmakingMenu1}"/>
|
||||
</Widget>
|
||||
<Widget type="TextBox" skin="SandText" position="280 24 258 24" name="SuccessChance">
|
||||
<Property key="Caption" value="39"/>
|
||||
<Property key="TextAlign" value="Right HCenter"/>
|
||||
</Widget>
|
||||
|
||||
@ -64,7 +62,6 @@
|
||||
<Property key="Caption" value="#{sBarterDialog7}"/>
|
||||
</Widget>
|
||||
<Widget type="AutoSizedTextBox" skin="SandText" name="PriceLabel">
|
||||
<Property key="Caption" value="30"/>
|
||||
</Widget>
|
||||
|
||||
|
||||
|
@ -16,7 +16,8 @@ Ogre::Resource(creator, name, handle, group, isManual, loader)
|
||||
we have none as such. Full details can be set through scripts.
|
||||
*/
|
||||
Shape = NULL;
|
||||
collide = true;
|
||||
mCollide = true;
|
||||
mIgnore = false;
|
||||
createParamDictionary("BulletShape");
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,9 @@ public:
|
||||
Ogre::Vector3 boxTranslation;
|
||||
Ogre::Quaternion boxRotation;
|
||||
//this flag indicate if the shape is used for collision or if it's for raycasting only.
|
||||
bool collide;
|
||||
bool mCollide;
|
||||
|
||||
bool mIgnore;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -169,6 +169,7 @@ namespace Physic
|
||||
RigidBody::RigidBody(btRigidBody::btRigidBodyConstructionInfo& CI,std::string name)
|
||||
: btRigidBody(CI)
|
||||
, mName(name)
|
||||
, mIgnore(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -327,7 +328,7 @@ namespace Physic
|
||||
|
||||
btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo(0,newMotionState,hfShape);
|
||||
RigidBody* body = new RigidBody(CI,name);
|
||||
body->collide = true;
|
||||
body->mCollide = true;
|
||||
body->getWorldTransform().setOrigin(btVector3( (x+0.5)*triSize*(sqrtVerts-1), (y+0.5)*triSize*(sqrtVerts-1), (maxh+minh)/2.f));
|
||||
|
||||
HeightField hf;
|
||||
@ -397,7 +398,8 @@ namespace Physic
|
||||
//create the real body
|
||||
btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo(0,newMotionState,shape->Shape);
|
||||
RigidBody* body = new RigidBody(CI,name);
|
||||
body->collide = shape->collide;
|
||||
body->mCollide = shape->mCollide;
|
||||
body->mIgnore = shape->mIgnore;
|
||||
|
||||
if(scaledBoxTranslation != 0)
|
||||
*scaledBoxTranslation = shape->boxTranslation * scale;
|
||||
@ -414,7 +416,9 @@ namespace Physic
|
||||
{
|
||||
if(body)
|
||||
{
|
||||
if(body->collide)
|
||||
if (body->mIgnore)
|
||||
return;
|
||||
if(body->mCollide)
|
||||
{
|
||||
dynamicsWorld->addRigidBody(body,COL_WORLD,COL_WORLD|COL_ACTOR_INTERNAL|COL_ACTOR_EXTERNAL);
|
||||
}
|
||||
|
@ -152,7 +152,8 @@ namespace Physic
|
||||
std::string mName;
|
||||
|
||||
//is this body used for raycasting only?
|
||||
bool collide;
|
||||
bool mCollide;
|
||||
bool mIgnore;
|
||||
};
|
||||
|
||||
struct HeightField
|
||||
|
Loading…
x
Reference in New Issue
Block a user