Merge branch 'master' of git://github.com/zinnschlag/openmw into companion

This commit is contained in:
scrawl 2013-03-31 14:50:03 +02:00
commit 1a2daa3bc1
41 changed files with 490 additions and 160 deletions

View file

@ -627,10 +627,10 @@ std::string bodyPartFlags(int flags)
std::string properties = "";
if (flags == 0) properties += "[None] ";
if (flags & ESM::BodyPart::BPF_Female) properties += "Female ";
if (flags & ESM::BodyPart::BPF_Playable) properties += "Playable ";
if (flags & ESM::BodyPart::BPF_NotPlayable) properties += "NotPlayable ";
int unused = (0xFFFFFFFF ^
(ESM::BodyPart::BPF_Female|
ESM::BodyPart::BPF_Playable));
ESM::BodyPart::BPF_NotPlayable));
if (flags & unused) properties += "Invalid ";
properties += str(boost::format("(0x%08X)") % flags);
return properties;

View file

@ -207,7 +207,7 @@ void CSMDoc::Document::createBase()
{
ESM::Skill record;
record.mIndex = i;
record.mId = ESM::Skill::getIndexToId (record.mIndex);
record.mId = ESM::Skill::indexToId (record.mIndex);
record.blank();
getData().getSkills().add (record);

View file

@ -33,7 +33,8 @@ namespace CSMWorld
Display_GmstVarType,
Display_GlobalVarType,
Display_Specialisation,
Display_Attribute
Display_Attribute,
Display_Boolean
};
std::string mTitle;

View file

@ -1,6 +1,8 @@
#ifndef CSM_WOLRD_COLUMNS_H
#define CSM_WOLRD_COLUMNS_H
#include <sstream>
#include <boost/lexical_cast.hpp>
#include "columnbase.hpp"
@ -285,6 +287,128 @@ namespace CSMWorld
}
};
template<typename ESXRecordT>
struct NameColumn : public Column<ESXRecordT>
{
NameColumn() : Column<ESXRecordT> ("Name", ColumnBase::Display_String) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return QString::fromUtf8 (record.get().mName.c_str());
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mName = data.toString().toUtf8().constData();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct AttributesColumn : public Column<ESXRecordT>
{
int mIndex;
AttributesColumn (int index)
: Column<ESXRecordT> ("Attribute #" + boost::lexical_cast<std::string> (index),
ColumnBase::Display_Attribute), mIndex (index) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return record.get().mData.mAttribute[mIndex];
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mData.mAttribute[mIndex] = data.toInt();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct SkillsColumn : public Column<ESXRecordT>
{
int mIndex;
bool mMajor;
SkillsColumn (int index, bool major)
: Column<ESXRecordT> ((major ? "Major Skill #" : "Minor Skill #")+
boost::lexical_cast<std::string> (index), ColumnBase::Display_String),
mIndex (index), mMajor (major)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
int skill = record.get().mData.mSkills[mIndex][mMajor ? 1 : 0];
return QString::fromUtf8 (ESM::Skill::indexToId (skill).c_str());
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
std::istringstream stream (data.toString().toUtf8().constData());
int index = -1;
char c;
stream >> c >> index;
if (index!=-1)
{
ESXRecordT record2 = record.get();
record2.mData.mSkills[mIndex][mMajor ? 1 : 0] = index;
record.setModified (record2);
}
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct PlayableColumn : public Column<ESXRecordT>
{
PlayableColumn() : Column<ESXRecordT> ("Playable", ColumnBase::Display_Boolean) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return record.get().mData.mIsPlayable!=0;
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mData.mIsPlayable = data.toInt();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
}
#endif

View file

@ -44,9 +44,23 @@ CSMWorld::Data::Data()
mSkills.addColumn (new UseValueColumn<ESM::Skill> (i));
mSkills.addColumn (new DescriptionColumn<ESM::Skill>);
mClasses.addColumn (new StringIdColumn<ESM::Class>);
mClasses.addColumn (new RecordStateColumn<ESM::Class>);
mClasses.addColumn (new NameColumn<ESM::Class>);
mClasses.addColumn (new AttributesColumn<ESM::Class> (0));
mClasses.addColumn (new AttributesColumn<ESM::Class> (1));
mClasses.addColumn (new SpecialisationColumn<ESM::Class>);
for (int i=0; i<5; ++i)
mClasses.addColumn (new SkillsColumn<ESM::Class> (i, true));
for (int i=0; i<5; ++i)
mClasses.addColumn (new SkillsColumn<ESM::Class> (i, false));
mClasses.addColumn (new PlayableColumn<ESM::Class>);
mClasses.addColumn (new DescriptionColumn<ESM::Class>);
addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global);
addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst);
addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill);
addModel (new IdTable (&mClasses), UniversalId::Type_Classes, UniversalId::Type_Class);
}
CSMWorld::Data::~Data()
@ -122,6 +136,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base)
case ESM::REC_GLOB: mGlobals.load (reader, base); break;
case ESM::REC_GMST: mGmsts.load (reader, base); break;
case ESM::REC_SKIL: mSkills.load (reader, base); break;
case ESM::REC_CLAS: mClasses.load (reader, base); break;
default:

View file

@ -9,6 +9,7 @@
#include <components/esm/loadglob.hpp>
#include <components/esm/loadgmst.hpp>
#include <components/esm/loadskil.hpp>
#include <components/esm/loadclas.hpp>
#include "idcollection.hpp"
#include "universalid.hpp"
@ -22,6 +23,7 @@ namespace CSMWorld
IdCollection<ESM::Global> mGlobals;
IdCollection<ESM::GameSetting> mGmsts;
IdCollection<ESM::Skill> mSkills;
IdCollection<ESM::Class> mClasses;
std::vector<QAbstractItemModel *> mModels;
std::map<UniversalId::Type, QAbstractItemModel *> mModelIndex;

View file

@ -20,6 +20,7 @@ namespace
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Globals, "Global Variables" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Gmsts, "Game Settings" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Skills, "Skills" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Classes, "Classes" },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker
};
@ -29,6 +30,7 @@ namespace
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Global, "Global Variable" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Gmst, "Game Setting" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Skill, "Skill" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Class, "Class" },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker
};

View file

@ -39,7 +39,9 @@ namespace CSMWorld
Type_Gmsts,
Type_Gmst,
Type_Skills,
Type_Skill
Type_Skill,
Type_Classes,
Type_Class
};
private:

View file

@ -90,6 +90,10 @@ void CSVDoc::View::setupWorldMenu()
connect (skills, SIGNAL (triggered()), this, SLOT (addSkillsSubView()));
world->addAction (skills);
QAction *classes = new QAction (tr ("Classes"), this);
connect (classes, SIGNAL (triggered()), this, SLOT (addClassesSubView()));
world->addAction (classes);
mVerify = new QAction (tr ("&Verify"), this);
connect (mVerify, SIGNAL (triggered()), this, SLOT (verify()));
world->addAction (mVerify);
@ -253,6 +257,11 @@ void CSVDoc::View::addSkillsSubView()
addSubView (CSMWorld::UniversalId::Type_Skills);
}
void CSVDoc::View::addClassesSubView()
{
addSubView (CSMWorld::UniversalId::Type_Classes);
}
void CSVDoc::View::abortOperation (int type)
{
mDocument->abortOperation (type);

View file

@ -117,6 +117,8 @@ namespace CSVDoc
void addGmstsSubView();
void addSkillsSubView();
void addClassesSubView();
};
}

View file

@ -17,6 +17,9 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
manager.add (CSMWorld::UniversalId::Type_Skills,
new CSVDoc::SubViewFactoryWithCreateFlag<TableSubView> (false));
manager.add (CSMWorld::UniversalId::Type_Global,
new CSVDoc::SubViewFactoryWithCreateFlag<DialogueSubView> (true));
manager.add (CSMWorld::UniversalId::Type_Classes,
new CSVDoc::SubViewFactoryWithCreateFlag<TableSubView> (true));
// manager.add (CSMWorld::UniversalId::Type_Global,
// new CSVDoc::SubViewFactoryWithCreateFlag<DialogueSubView> (true));
}

View file

@ -44,6 +44,11 @@ namespace MWRender
class Animation;
}
namespace MWMechanics
{
class Movement;
}
namespace MWWorld
{
class Fallback;
@ -54,7 +59,7 @@ namespace MWWorld
class ESMStore;
class RefData;
typedef std::vector<std::pair<MWWorld::Ptr,Ogre::Vector3> > PtrMovementList;
typedef std::vector<std::pair<MWWorld::Ptr,MWMechanics::Movement> > PtrMovementList;
}
namespace MWBase

View file

@ -24,6 +24,18 @@
#include <boost/lexical_cast.hpp>
namespace
{
bool isGold (const MWWorld::Ptr& ptr)
{
return Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_001")
|| Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_005")
|| Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_010")
|| Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_025")
|| Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_100");
}
}
namespace MWClass
{
void Miscellaneous::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
@ -110,25 +122,15 @@ namespace MWClass
std::string Miscellaneous::getUpSoundId (const MWWorld::Ptr& ptr) const
{
MWWorld::LiveCellRef<ESM::Miscellaneous> *ref =
ptr.get<ESM::Miscellaneous>();
if (ref->mBase->mName == MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sGold")->getString())
{
if (isGold(ptr))
return std::string("Item Gold Up");
}
return std::string("Item Misc Up");
}
std::string Miscellaneous::getDownSoundId (const MWWorld::Ptr& ptr) const
{
MWWorld::LiveCellRef<ESM::Miscellaneous> *ref =
ptr.get<ESM::Miscellaneous>();
if (ref->mBase->mName == MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sGold")->getString())
{
if (isGold(ptr))
return std::string("Item Gold Down");
}
return std::string("Item Misc Down");
}
@ -159,19 +161,15 @@ namespace MWClass
int count = ptr.getRefData().getCount();
bool isGold = Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_001")
|| Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_005")
|| Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_010")
|| Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_025")
|| Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_100");
bool gold = isGold(ptr);
if (isGold && ptr.getCellRef().mGoldValue != 1)
if (gold && ptr.getCellRef().mGoldValue != 1)
count = ptr.getCellRef().mGoldValue;
else if (isGold)
else if (gold)
count *= ref->mBase->mData.mValue;
std::string countString;
if (!isGold)
if (!gold)
countString = MWGui::ToolTips::getCountString(count);
else // gold displays its count also if it's 1.
countString = " (" + boost::lexical_cast<std::string>(count) + ")";
@ -187,7 +185,7 @@ namespace MWClass
std::string text;
if (!isGold)
if (!gold)
{
text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight);
text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}");
@ -211,7 +209,7 @@ namespace MWClass
const MWWorld::ESMStore &store =
MWBase::Environment::get().getWorld()->getStore();
if (MWWorld::Class::get(ptr).getName(ptr) == store.get<ESM::GameSetting>().find("sGold")->getString()) {
if (isGold(ptr)) {
int goldAmount = ptr.getRefData().getCount();
std::string base = "Gold_001";

View file

@ -368,7 +368,7 @@ namespace MWClass
moveSpeed = runSpeed;
else
moveSpeed = walkSpeed;
if(getMovementSettings(ptr).mLeftRight != 0 && getMovementSettings(ptr).mForwardBackward == 0)
if(getMovementSettings(ptr).mPosition[0] != 0 && getMovementSettings(ptr).mPosition[1] == 0)
moveSpeed *= 0.75f;
return moveSpeed;
@ -414,14 +414,24 @@ namespace MWClass
Ogre::Vector3 Npc::getMovementVector (const MWWorld::Ptr& ptr) const
{
Ogre::Vector3 vector;
vector.x = getMovementSettings(ptr).mLeftRight;
vector.y = getMovementSettings(ptr).mForwardBackward;
vector.z = getMovementSettings(ptr).mUpDown;
return vector;
MWMechanics::Movement &movement = getMovementSettings(ptr);
Ogre::Vector3 vec(movement.mPosition);
movement.mPosition[0] = 0.0f;
movement.mPosition[1] = 0.0f;
movement.mPosition[2] = 0.0f;
return vec;
}
Ogre::Vector3 Npc::getRotationVector (const MWWorld::Ptr& ptr) const
{
MWMechanics::Movement &movement = getMovementSettings(ptr);
Ogre::Vector3 vec(movement.mRotation);
movement.mRotation[0] = 0.0f;
movement.mRotation[1] = 0.0f;
movement.mRotation[2] = 0.0f;
return vec;
}
bool Npc::isEssential (const MWWorld::Ptr& ptr) const
{
MWWorld::LiveCellRef<ESM::NPC> *ref =

View file

@ -96,6 +96,9 @@ namespace MWClass
///< Return desired movement vector (determined based on movement settings,
/// stance and stats).
virtual Ogre::Vector3 getRotationVector (const MWWorld::Ptr& ptr) const;
///< Return desired rotations, as euler angles.
virtual float getCapacity (const MWWorld::Ptr& ptr) const;
///< Return total weight that fits into the object. Throws an exception, if the object can't
/// hold other objects.

View file

@ -140,13 +140,8 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender)
if (isInventory())
{
const MWWorld::Store<ESM::GameSetting> &gmst =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
// the player is trying to sell an item, check if the merchant accepts it
// also, don't allow selling gold (let's be better than Morrowind at this, can we?)
if (!MWBase::Environment::get().getWindowManager()->getTradeWindow()->npcAcceptsItem(object) ||
MWWorld::Class::get(object).getName(object) == gmst.find("sGold")->getString())
if (!MWBase::Environment::get().getWindowManager()->getTradeWindow()->npcAcceptsItem(object))
{
// user notification "i don't buy this item"
MWBase::Environment::get().getWindowManager()->

View file

@ -19,6 +19,49 @@
using namespace MWGui;
using namespace Widgets;
namespace
{
int wrap(int index, int max)
{
if (index < 0)
return max - 1;
else if (index >= max)
return 0;
else
return index;
}
int countParts(const std::string &part, const std::string &race, bool male)
{
/// \todo loop through the whole store for appropriate bodyparts instead of looking for fixed IDs
const MWWorld::Store<ESM::BodyPart> &store =
MWBase::Environment::get().getWorld()->getStore().get<ESM::BodyPart>();
std::string prefix =
"b_n_" + race + ((male) ? "_m_" : "_f_") + part;
std::string suffix;
suffix.reserve(prefix.size() + 3);
int count = -1;
do {
++count;
suffix = "_" + (boost::format("%02d") % (count + 1)).str();
}
while (store.search(prefix + suffix) != 0);
if (count == 0 && part == "hair") {
count = -1;
do {
++count;
suffix = (boost::format("%02d") % (count + 1)).str();
}
while (store.search(prefix + suffix) != 0);
}
return count;
}
}
RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager)
: WindowModal("openmw_chargen_race.layout", parWindowManager)
, mGenderIndex(0)
@ -144,45 +187,6 @@ void RaceDialog::setRaceId(const std::string &raceId)
updateSpellPowers();
}
int wrap(int index, int max)
{
if (index < 0)
return max - 1;
else if (index >= max)
return 0;
else
return index;
}
int countParts(const std::string &part, const std::string &race, bool male)
{
const MWWorld::Store<ESM::BodyPart> &store =
MWBase::Environment::get().getWorld()->getStore().get<ESM::BodyPart>();
std::string prefix =
"b_n_" + race + ((male) ? "_m_" : "_f_") + part;
std::string suffix;
suffix.reserve(prefix.size() + 3);
int count = -1;
do {
++count;
suffix = "_" + (boost::format("%02d") % (count + 1)).str();
}
while (store.search(prefix + suffix) != 0);
if (count == 0 && part == "hair") {
count = -1;
do {
++count;
suffix = (boost::format("%02d") % (count + 1)).str();
}
while (store.search(prefix + suffix) != 0);
}
return count;
}
void RaceDialog::close()
{
delete mPreview;
@ -229,28 +233,67 @@ void RaceDialog::onSelectNextGender(MyGUI::Widget*)
void RaceDialog::onSelectPreviousFace(MyGUI::Widget*)
{
mFaceIndex = wrap(mFaceIndex - 1, mFaceCount);
do
mFaceIndex = wrap(mFaceIndex - 1, mFaceCount);
while (!isFacePlayable());
updatePreview();
}
void RaceDialog::onSelectNextFace(MyGUI::Widget*)
{
mFaceIndex = wrap(mFaceIndex + 1, mFaceCount);
do
mFaceIndex = wrap(mFaceIndex + 1, mFaceCount);
while (!isFacePlayable());
updatePreview();
}
void RaceDialog::onSelectPreviousHair(MyGUI::Widget*)
{
mHairIndex = wrap(mHairIndex - 1, mHairCount);
do
mHairIndex = wrap(mHairIndex - 1, mHairCount);
while (!isHairPlayable());
updatePreview();
}
void RaceDialog::onSelectNextHair(MyGUI::Widget*)
{
mHairIndex = wrap(mHairIndex + 1, mHairCount);
do
mHairIndex = wrap(mHairIndex + 1, mHairCount);
while (!isHairPlayable());
updatePreview();
}
bool RaceDialog::isFacePlayable()
{
std::string prefix =
"b_n_" + mCurrentRaceId + ((mGenderIndex == 0) ? "_m_" : "_f_");
std::string headIndex = (boost::format("%02d") % (mFaceIndex + 1)).str();
const MWWorld::Store<ESM::BodyPart> &parts =
MWBase::Environment::get().getWorld()->getStore().get<ESM::BodyPart>();
if (parts.search(prefix + "head_" + headIndex) == 0)
return !(parts.find(prefix + "head" + headIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable);
else
return !(parts.find(prefix + "head_" + headIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable);
}
bool RaceDialog::isHairPlayable()
{
std::string prefix =
"b_n_" + mCurrentRaceId + ((mGenderIndex == 0) ? "_m_" : "_f_");
std::string hairIndex = (boost::format("%02d") % (mHairIndex + 1)).str();
const MWWorld::Store<ESM::BodyPart> &parts =
MWBase::Environment::get().getWorld()->getStore().get<ESM::BodyPart>();
if (parts.search(prefix + "hair_" + hairIndex) == 0)
return !(parts.find(prefix + "hair" + hairIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable);
else
return !(parts.find(prefix + "hair_" + hairIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable);
}
void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index)
{
if (_index == MyGUI::ITEM_NONE)
@ -273,11 +316,16 @@ void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index)
void RaceDialog::recountParts()
{
mFaceCount = countParts("head", mCurrentRaceId, mGenderIndex == 0);
mHairCount = countParts("hair", mCurrentRaceId, mGenderIndex == 0);
mFaceIndex = 0;
mHairIndex = 0;
mFaceCount = countParts("head", mCurrentRaceId, mGenderIndex == 0);
mHairCount = countParts("hair", mCurrentRaceId, mGenderIndex == 0);
while (!isHairPlayable())
mHairIndex = wrap(mHairIndex + 1, mHairCount);
while (!isFacePlayable())
mFaceIndex = wrap(mFaceIndex + 1, mFaceCount);
}
// update widget content

View file

@ -81,6 +81,9 @@ namespace MWGui
void updatePreview();
void recountParts();
bool isHairPlayable();
bool isFacePlayable();
MyGUI::ImageBox* mPreviewImage;
MyGUI::ListBox* mRaceList;
MyGUI::ScrollBar* mHeadRotate;

View file

@ -129,13 +129,10 @@ namespace MWGui
MWWorld::Ptr gold;
MWWorld::ContainerStore& playerStore = mWindowManager.getInventoryWindow()->getContainerStore();
const MWWorld::Store<ESM::GameSetting> &gmst =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
for (MWWorld::ContainerStoreIterator it = playerStore.begin();
it != playerStore.end(); ++it)
{
if (MWWorld::Class::get(*it).getName(*it) == gmst.find("sGold")->getString())
if (Misc::StringUtils::ciEqual(it->getCellRef().mRefID, "gold_001"))
{
goldFound = true;
gold = *it;
@ -342,6 +339,9 @@ namespace MWGui
bool TradeWindow::npcAcceptsItem(MWWorld::Ptr item)
{
if (Misc::StringUtils::ciEqual(item.getCellRef().mRefID, "gold_001"))
return false;
int services = 0;
if (mPtr.getTypeName() == typeid(ESM::NPC).name())
{

View file

@ -287,8 +287,6 @@ namespace MWInput
triedToMove = true;
mPlayer.setLeftRight (1);
}
else
mPlayer.setLeftRight (0);
if (actionIsActive(A_MoveForward))
{
@ -302,8 +300,6 @@ namespace MWInput
mPlayer.setAutoMove (false);
mPlayer.setForwardBackward (-1);
}
else
mPlayer.setForwardBackward (0);
mPlayer.setSneak(actionIsActive(A_Sneak));
@ -312,8 +308,6 @@ namespace MWInput
mPlayer.setUpDown (1);
triedToMove = true;
}
else
mPlayer.setUpDown (0);
if (mAlwaysRunActive)
mPlayer.setRunState(!actionIsActive(A_Run));
@ -542,11 +536,11 @@ namespace MWInput
{
resetIdleTime();
float x = arg.state.X.rel * mCameraSensitivity * 0.2;
float y = arg.state.Y.rel * mCameraSensitivity * 0.2 * (mInvertY ? -1 : 1) * mUIYMultiplier;
float x = arg.state.X.rel * mCameraSensitivity * 0.2f;
float y = arg.state.Y.rel * mCameraSensitivity * 0.2f * (mInvertY ? -1 : 1) * mUIYMultiplier;
MWBase::World *world = MWBase::Environment::get().getWorld();
world->rotateObject(world->getPlayer().getPlayer(), -y, 0.f, x, true);
mPlayer.setYaw(x);
mPlayer.setPitch(-y);
if (arg.state.Z.rel)
MWBase::Environment::get().getWorld()->changeVanityModeScale(arg.state.Z.rel);

View file

@ -2,6 +2,8 @@
#include <OgreVector3.h>
#include "movement.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
@ -56,7 +58,10 @@ void Activators::update(float duration, bool paused)
if(!paused)
{
for(PtrControllerMap::iterator iter(mActivators.begin());iter != mActivators.end();++iter)
iter->second.update(duration);
{
Movement movement;
iter->second.update(duration, movement);
}
}
}

View file

@ -17,6 +17,7 @@
#include "../mwbase/windowmanager.hpp"
#include "creaturestats.hpp"
#include "movement.hpp"
namespace MWMechanics
{
@ -266,7 +267,8 @@ namespace MWMechanics
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
{
Ogre::Vector3 movement = iter->second.update(duration);
Movement movement;
iter->second.update(duration, movement);
mMovement.push_back(std::make_pair(iter->first, movement));
}
MWBase::Environment::get().getWorld()->doPhysics(mMovement, duration);

View file

@ -7,6 +7,7 @@
#include <map>
#include "character.hpp"
#include "movement.hpp"
#include "../mwbase/world.hpp"
namespace Ogre

View file

@ -21,6 +21,8 @@
#include <OgreStringConverter.h>
#include "movement.hpp"
#include "../mwrender/animation.hpp"
#include "../mwbase/environment.hpp"
@ -73,6 +75,9 @@ static const struct {
{ CharState_SneakLeft, "sneakleft" },
{ CharState_SneakRight, "sneakright" },
{ CharState_TurnLeft, "turnleft" },
{ CharState_TurnRight, "turnright" },
{ CharState_Jump, "jump" },
{ CharState_Death1, "death1" },
@ -168,21 +173,20 @@ void CharacterController::markerEvent(float time, const std::string &evt)
}
Ogre::Vector3 CharacterController::update(float duration)
void CharacterController::update(float duration, Movement &movement)
{
Ogre::Vector3 movement(0.0f);
float speed = 0.0f;
if(!(getState() >= CharState_Death1))
{
const MWBase::World *world = MWBase::Environment::get().getWorld();
const MWWorld::Class &cls = MWWorld::Class::get(mPtr);
const Ogre::Vector3 &vec = cls.getMovementVector(mPtr);
bool onground = world->isOnGround(mPtr);
bool inwater = world->isSwimming(mPtr);
bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run);
bool sneak = cls.getStance(mPtr, MWWorld::Class::Sneak);
const Ogre::Vector3 &vec = cls.getMovementVector(mPtr);
const Ogre::Vector3 &rot = cls.getRotationVector(mPtr);
speed = cls.getSpeed(mPtr);
/* FIXME: The state should be set to Jump, and X/Y movement should be disallowed except
@ -192,14 +196,14 @@ Ogre::Vector3 CharacterController::update(float duration)
float x = cls.getJump(mPtr);
if(vec.x == 0 && vec.y == 0)
movement.z += x*duration;
movement.mPosition[2] += x*duration;
else
{
/* FIXME: this would be more correct if we were going into a jumping state,
* rather than normal walking/idle states. */
//Ogre::Vector3 lat = Ogre::Vector3(vec.x, vec.y, 0.0f).normalisedCopy();
//movement += Ogre::Vector3(lat.x, lat.y, 1.0f) * x * 0.707f * duration;
movement.z += x * 0.707f * duration;
movement.mPosition[2] += x * 0.707f * duration;
}
//decrease fatigue by fFatigueJumpBase + (1 - normalizedEncumbrance) * fFatigueJumpMult;
@ -216,7 +220,7 @@ Ogre::Vector3 CharacterController::update(float duration)
: (sneak ? CharState_SneakLeft : (isrunning ? CharState_RunLeft : CharState_WalkLeft)), true);
// Apply any forward/backward movement manually
movement.y += vec.y * (speed*duration);
movement.mPosition[1] += vec.y * (speed*duration);
}
else if(vec.y != 0.0f && speed > 0.0f)
{
@ -228,20 +232,32 @@ Ogre::Vector3 CharacterController::update(float duration)
setState(inwater ? (isrunning ? CharState_SwimRunBack : CharState_SwimWalkBack)
: (sneak ? CharState_SneakBack : (isrunning ? CharState_RunBack : CharState_WalkBack)), true);
// Apply any sideways movement manually
movement.x += vec.x * (speed*duration);
movement.mPosition[0] += vec.x * (speed*duration);
}
else if(rot.z != 0.0f && !inwater && !sneak)
{
if(rot.z > 0.0f)
setState(CharState_TurnRight, true);
else if(rot.z < 0.0f)
setState(CharState_TurnLeft, true);
}
else if(mAnimQueue.size() == 0)
setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true);
movement.mRotation[0] += rot.x * duration;
movement.mRotation[1] += rot.y * duration;
movement.mRotation[2] += rot.z * duration;
}
if(mAnimation && !mSkipAnim)
{
mAnimation->setSpeed(speed);
movement += mAnimation->runAnimation(duration);
Ogre::Vector3 moved = mAnimation->runAnimation(duration);
movement.mPosition[0] += moved.x;
movement.mPosition[1] += moved.y;
movement.mPosition[2] += moved.z;
}
mSkipAnim = false;
return movement;
}

View file

@ -13,6 +13,8 @@ namespace MWRender
namespace MWMechanics
{
class Movement;
enum CharacterState {
CharState_SpecialIdle,
CharState_Idle,
@ -52,6 +54,9 @@ enum CharacterState {
CharState_SneakLeft,
CharState_SneakRight,
CharState_TurnLeft,
CharState_TurnRight,
CharState_Jump,
/* Death states must be last! */
@ -87,7 +92,7 @@ public:
void updatePtr(const MWWorld::Ptr &ptr);
Ogre::Vector3 update(float duration);
void update(float duration, Movement &movement);
void playGroup(const std::string &groupname, int mode, int count);
void skipAnim();

View file

@ -6,11 +6,14 @@ namespace MWMechanics
/// Desired movement for an actor
struct Movement
{
signed char mLeftRight; // 1: wants to move left, -1: wants to move right
signed char mForwardBackward; // 1:wants to move forward, -1: wants to move backward
signed char mUpDown;
float mPosition[3];
float mRotation[3];
Movement() : mLeftRight (0), mForwardBackward (0), mUpDown(0) {}
Movement()
{
mPosition[0] = mPosition[1] = mPosition[2] = 0.0f;
mRotation[0] = mRotation[1] = mRotation[2] = 0.0f;
}
};
}

View file

@ -262,37 +262,29 @@ void RenderingManager::scaleObject (const MWWorld::Ptr& ptr, const Ogre::Vector3
ptr.getRefData().getBaseNode()->setScale(scale);
}
bool RenderingManager::rotateObject( const MWWorld::Ptr &ptr, Ogre::Vector3 &rot, bool adjust)
bool RenderingManager::rotateObject(const MWWorld::Ptr &ptr, Ogre::Vector3 &rot, bool adjust)
{
bool isActive = ptr.getRefData().getBaseNode() != 0;
bool isPlayer = isActive && ptr.getRefData().getHandle() == "player";
bool force = true;
if (isPlayer)
force = mPlayer->rotate(rot, adjust);
MWWorld::Class::get(ptr).adjustRotation(ptr, rot.x, rot.y, rot.z);
MWWorld::Class::get(ptr).adjustRotation(ptr, rot.x, rot.y, rot.z);
if (!isPlayer && isActive)
{
Ogre::Quaternion xr(Ogre::Radian(-rot.x), Ogre::Vector3::UNIT_X);
Ogre::Quaternion yr(Ogre::Radian(-rot.y), Ogre::Vector3::UNIT_Y);
Ogre::Quaternion zr(Ogre::Radian(-rot.z), Ogre::Vector3::UNIT_Z);
Ogre::Quaternion xref(Ogre::Radian(-ptr.getRefData().getPosition().rot[0]), Ogre::Vector3::UNIT_X);
Ogre::Quaternion yref(Ogre::Radian(-ptr.getRefData().getPosition().rot[1]), Ogre::Vector3::UNIT_Y);
Ogre::Quaternion zref(Ogre::Radian(-ptr.getRefData().getPosition().rot[2]), Ogre::Vector3::UNIT_Z);
Ogre::Quaternion newo = adjust ? (xr * yr * zr) * (xref*yref*zref) : xr * yr * zr;
Ogre::Matrix3 mat;
newo.ToRotationMatrix(mat);
Ogre::Radian ax,ay,az;
mat.ToEulerAnglesXYZ(ax,ay,az);
rot.x = -ax.valueRadians();
rot.y = -ay.valueRadians();
rot.z = -az.valueRadians();
if(adjust)
{
const float *objRot = ptr.getRefData().getPosition().rot;
rot.x += objRot[0];
rot.y += objRot[1];
rot.z += objRot[2];
}
Ogre::Quaternion newo = Ogre::Quaternion(Ogre::Radian(-rot.x), Ogre::Vector3::UNIT_X) *
Ogre::Quaternion(Ogre::Radian(-rot.y), Ogre::Vector3::UNIT_Y) *
Ogre::Quaternion(Ogre::Radian(-rot.z), Ogre::Vector3::UNIT_Z);
ptr.getRefData().getBaseNode()->setOrientation(newo);
}
else if(isPlayer)

View file

@ -316,5 +316,7 @@ op 0x20001f9: Drop, explicit reference
op 0x20001fa: DropSoulGem
op 0x20001fb: DropSoulGem, explicit reference
op 0x20001fc: OnDeath
op 0x20001fd: IsWerewolf
op 0x20001fe: IsWerewolf, explicit reference
opcodes 0x20001fd-0x3ffffff unused
opcodes 0x20001ff-0x3ffffff unused

View file

@ -1046,6 +1046,18 @@ namespace MWScript
}
};
template <class R>
class OpIsWerewolf : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
MWWorld::Ptr ptr = R()(runtime);
runtime.push(MWWorld::Class::get(ptr).getNpcStats(ptr).isWerewolf());
}
};
const int numberOfAttributes = 8;
const int opcodeGetAttribute = 0x2000027;
@ -1137,6 +1149,9 @@ namespace MWScript
const int opcodeOnDeath = 0x20001fc;
const int opcodeIsWerewolf = 0x20001fd;
const int opcodeIsWerewolfExplicit = 0x20001fe;
void registerExtensions (Compiler::Extensions& extensions)
{
static const char *attributes[numberOfAttributes] =
@ -1252,6 +1267,8 @@ namespace MWScript
extensions.registerInstruction ("lowerrank", "", opcodeLowerRank, opcodeLowerRankExplicit);
extensions.registerFunction ("ondeath", 'l', "", opcodeOnDeath);
extensions.registerFunction ("iswerewolf", 'l', "", opcodeIsWerewolf, opcodeIsWerewolfExplicit);
}
void installOpcodes (Interpreter::Interpreter& interpreter)
@ -1368,6 +1385,9 @@ namespace MWScript
interpreter.installSegment5 (opcodeLowerRankExplicit, new OpLowerRank<ExplicitRef>);
interpreter.installSegment5 (opcodeOnDeath, new OpOnDeath);
interpreter.installSegment5 (opcodeIsWerewolf, new OpIsWerewolf<ImplicitRef>);
interpreter.installSegment5 (opcodeIsWerewolfExplicit, new OpIsWerewolf<ExplicitRef>);
}
}
}

View file

@ -142,6 +142,11 @@ namespace MWWorld
return Ogre::Vector3 (0, 0, 0);
}
Ogre::Vector3 Class::getRotationVector (const Ptr& ptr) const
{
return Ogre::Vector3 (0, 0, 0);
}
std::pair<std::vector<int>, bool> Class::getEquipmentSlots (const Ptr& ptr) const
{
return std::make_pair (std::vector<int>(), false);

View file

@ -150,6 +150,9 @@ namespace MWWorld
///< Return desired movement vector (determined based on movement settings,
/// stance and stats).
virtual Ogre::Vector3 getRotationVector (const Ptr& ptr) const;
///< Return desired rotations, as euler angles.
virtual std::pair<std::vector<int>, bool> getEquipmentSlots (const Ptr& ptr) const;
///< \return first: Return IDs of the slot this object can be equipped in; second: can object
/// stay stacked when equipped?

View file

@ -42,14 +42,14 @@ namespace MWWorld
if (mAutoMove)
value = 1;
MWWorld::Class::get (ptr).getMovementSettings (ptr).mForwardBackward = value;
MWWorld::Class::get (ptr).getMovementSettings (ptr).mPosition[1] = value;
}
void Player::setLeftRight (int value)
{
MWWorld::Ptr ptr = getPlayer();
MWWorld::Class::get (ptr).getMovementSettings (ptr).mLeftRight = value;
MWWorld::Class::get (ptr).getMovementSettings (ptr).mPosition[0] = value;
}
void Player::setForwardBackward (int value)
@ -61,14 +61,14 @@ namespace MWWorld
if (mAutoMove)
value = 1;
MWWorld::Class::get (ptr).getMovementSettings (ptr).mForwardBackward = value;
MWWorld::Class::get (ptr).getMovementSettings (ptr).mPosition[1] = value;
}
void Player::setUpDown(int value)
{
MWWorld::Ptr ptr = getPlayer();
MWWorld::Class::get (ptr).getMovementSettings (ptr).mUpDown = value;
MWWorld::Class::get (ptr).getMovementSettings (ptr).mPosition[2] = value;
}
void Player::setRunState(bool run)
@ -84,6 +84,22 @@ namespace MWWorld
MWWorld::Class::get (ptr).setStance (ptr, MWWorld::Class::Sneak, sneak);
}
void Player::setYaw(float yaw)
{
MWWorld::Ptr ptr = getPlayer();
MWWorld::Class::get(ptr).getMovementSettings(ptr).mRotation[2] = yaw;
}
void Player::setPitch(float pitch)
{
MWWorld::Ptr ptr = getPlayer();
MWWorld::Class::get(ptr).getMovementSettings(ptr).mRotation[0] = pitch;
}
void Player::setRoll(float roll)
{
MWWorld::Ptr ptr = getPlayer();
MWWorld::Class::get(ptr).getMovementSettings(ptr).mRotation[1] = roll;
}
MWMechanics::DrawState_ Player::getDrawState()
{
MWWorld::Ptr ptr = getPlayer();

View file

@ -67,6 +67,10 @@ namespace MWWorld
void setRunState(bool run);
void setSneak(bool sneak);
void setYaw(float yaw);
void setPitch(float pitch);
void setRoll(float roll);
};
}
#endif

View file

@ -13,6 +13,7 @@
#include "../mwbase/scriptmanager.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/movement.hpp"
#include "../mwrender/sky.hpp"
#include "../mwrender/player.hpp"
@ -805,18 +806,15 @@ namespace MWWorld
mPhysics->scaleObject(ptr);
}
void World::rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust)
void World::rotateObjectImp (const Ptr& ptr, Ogre::Vector3 rot, bool adjust)
{
Ogre::Vector3 rot;
rot.x = Ogre::Degree(x).valueRadians();
rot.y = Ogre::Degree(y).valueRadians();
rot.z = Ogre::Degree(z).valueRadians();
if (mRendering->rotateObject(ptr, rot, adjust))
{
// rotate physically iff renderer confirm so
float *objRot = ptr.getRefData().getPosition().rot;
objRot[0] = rot.x, objRot[1] = rot.y, objRot[2] = rot.z;
objRot[0] = rot.x;
objRot[1] = rot.y;
objRot[2] = rot.z;
if (ptr.getRefData().getBaseNode() != 0) {
mPhysics->rotateObject(ptr);
@ -824,6 +822,14 @@ namespace MWWorld
}
}
void World::rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust)
{
rotateObjectImp(ptr, Ogre::Vector3(Ogre::Degree(x).valueRadians(),
Ogre::Degree(y).valueRadians(),
Ogre::Degree(z).valueRadians()),
adjust);
}
void World::safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos)
{
copyObjectToCell(ptr,Cell,pos);
@ -873,13 +879,18 @@ namespace MWWorld
player = iter;
continue;
}
Ogre::Vector3 vec = mPhysics->move(iter->first, iter->second, duration,
rotateObjectImp(iter->first, Ogre::Vector3(iter->second.mRotation), true);
Ogre::Vector3 vec = mPhysics->move(iter->first, Ogre::Vector3(iter->second.mPosition), duration,
!isSwimming(iter->first) && !isFlying(iter->first));
moveObjectImp(iter->first, vec.x, vec.y, vec.z);
}
if(player != actors.end())
{
Ogre::Vector3 vec = mPhysics->move(player->first, player->second, duration,
rotateObjectImp(player->first, Ogre::Vector3(player->second.mRotation), true);
Ogre::Vector3 vec = mPhysics->move(player->first, Ogre::Vector3(player->second.mPosition), duration,
!isSwimming(player->first) && !isFlying(player->first));
moveObjectImp(player->first, vec.x, vec.y, vec.z);
}

View file

@ -90,6 +90,8 @@ namespace MWWorld
int getDaysPerMonth (int month) const;
void rotateObjectImp (const Ptr& ptr, Ogre::Vector3 rot, bool adjust);
bool moveObjectImp (const Ptr& ptr, float x, float y, float z);
///< @return true if the active cell (cell player is in) changed

View file

@ -106,6 +106,12 @@ namespace Compiler
mLoc.mLiteral.clear();
return true;
}
else if (c==':')
{
// treat : as a whitespace :(
mLoc.mLiteral.clear();
return true;
}
else if (std::isdigit (c))
{
bool cont = false;

View file

@ -33,7 +33,7 @@ struct BodyPart
enum Flags
{
BPF_Female = 1,
BPF_Playable = 2
BPF_NotPlayable = 2
};
enum MeshType

View file

@ -35,4 +35,18 @@ void Class::save(ESMWriter &esm)
esm.writeHNOString("DESC", mDescription);
}
void Class::blank()
{
mName.clear();
mDescription.clear();
mData.mAttribute[0] = mData.mAttribute[1] = 0;
mData.mSpecialization = 0;
mData.mIsPlayable = 0;
mData.mCalc = 0;
for (int i=0; i<5; ++i)
for (int i2=0; i2<2; ++i2)
mData.mSkills[i][i2] = 0;
}
}

View file

@ -65,6 +65,10 @@ struct Class
void load(ESMReader &esm);
void save(ESMWriter &esm);
void blank();
///< Set record to default state (does not touch the ID/index).
};
}
#endif

View file

@ -2,6 +2,8 @@
#include <sstream>
#include <components/misc/stringops.hpp>
#include "esmreader.hpp"
#include "esmwriter.hpp"
@ -103,8 +105,9 @@ void Skill::load(ESMReader &esm)
// create an ID from the index and the name (only used in the editor and likely to change in the
// future)
mId = getIndexToId (mIndex);
mId = indexToId (mIndex);
}
void Skill::save(ESMWriter &esm)
{
esm.writeHNT("INDX", mIndex);
@ -120,7 +123,7 @@ void Skill::save(ESMWriter &esm)
mDescription.clear();
}
std::string Skill::getIndexToId (int index)
std::string Skill::indexToId (int index)
{
std::ostringstream stream;

View file

@ -79,7 +79,7 @@ struct Skill
void blank();
///< Set record to default state (does not touch the ID/index).
static std::string getIndexToId (int index);
static std::string indexToId (int index);
};
}
#endif