Merge branch 'master' of https://github.com/OpenMW/openmw into osg

Conflicts:
	apps/openmw/mwmechanics/aicombat.cpp
	apps/openmw/mwmechanics/aitravel.cpp
This commit is contained in:
scrawl 2015-06-14 16:14:56 +02:00
commit cad18969e3
56 changed files with 322 additions and 298 deletions

View file

@ -830,12 +830,12 @@ std::string npcFlags(int flags)
std::string properties = "";
if (flags == 0) properties += "[None] ";
// Mythicmods and the ESM component differ. Mythicmods says
// 0x8=None and 0x10=AutoCalc, while our code defines 0x8 as
// AutoCalc. The former seems to be correct. All Bethesda
// records have bit 0x8 set. A suspiciously large portion of
// females have autocalc turned off.
if (flags & ESM::NPC::Autocalc) properties += "Unknown ";
if (flags & 0x00000010) properties += "Autocalc ";
// 0x8=None and 0x10=AutoCalc, while our code previously defined
// 0x8 as AutoCalc. The former seems to be correct. All Bethesda
// records have bit 0x8 set. Previously, suspiciously large portion
// of females had autocalc turned off.
if (flags & 0x00000008) properties += "Unknown ";
if (flags & ESM::NPC::Autocalc) properties += "Autocalc ";
if (flags & ESM::NPC::Female) properties += "Female ";
if (flags & ESM::NPC::Respawn) properties += "Respawn ";
if (flags & ESM::NPC::Essential) properties += "Essential ";
@ -847,8 +847,8 @@ std::string npcFlags(int flags)
// however the only unknown bit occurs on ALL records, and
// relatively few NPCs have this bit set.
int unused = (0xFFFFFFFF ^
(ESM::NPC::Autocalc|
0x00000010|
(0x00000008|
ESM::NPC::Autocalc|
ESM::NPC::Female|
ESM::NPC::Respawn|
ESM::NPC::Essential|

View file

@ -490,7 +490,7 @@ bool Launcher::MainDialog::writeSettings()
// Game settings
QFile file(userPath + QString("openmw.cfg"));
if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) {
if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) {
// File cannot be opened or created
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error writing OpenMW configuration file"));
@ -503,8 +503,10 @@ bool Launcher::MainDialog::writeSettings()
return false;
}
QTextStream stream(&file);
stream.setCodec(QTextCodec::codecForName("UTF-8"));
mGameSettings.writeFileWithComments(file);
mGameSettings.writeFile(stream);
file.close();
// Graphics settings
@ -523,7 +525,6 @@ bool Launcher::MainDialog::writeSettings()
return false;
}
QTextStream stream(&file);
stream.setDevice(&file);
stream.setCodec(QTextCodec::codecForName("UTF-8"));

View file

@ -648,7 +648,7 @@ void CSMTools::ReferenceableCheckStage::npcCheck (
if (npc.mNpdtType == ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS) //12 = autocalculated
{
if ((npc.mFlags & ESM::NPC::Autocalc) == 0) //0x0008 = autocalculated flag
if ((npc.mFlags & ESM::NPC::Autocalc) == 0) //0x0010 = autocalculated flag
{
messages.push_back (std::make_pair (id, npc.mId + " mNpdtType or flags mismatch!")); //should not happend?
return;

View file

@ -37,10 +37,18 @@ void CSMWorld::PotionRefIdAdapter::setData (const RefIdColumn *column, RefIdData
Record<ESM::Potion>& record = static_cast<Record<ESM::Potion>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Potion)));
ESM::Potion potion = record.get();
if (column==mAutoCalc)
record.get().mData.mAutoCalc = value.toInt();
potion.mData.mAutoCalc = value.toInt();
else
{
InventoryRefIdAdapter<ESM::Potion>::setData (column, data, index, value);
return;
}
record.setModified(potion);
}
@ -71,12 +79,19 @@ void CSMWorld::ApparatusRefIdAdapter::setData (const RefIdColumn *column, RefIdD
Record<ESM::Apparatus>& record = static_cast<Record<ESM::Apparatus>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Apparatus)));
ESM::Apparatus apparatus = record.get();
if (column==mType)
record.get().mData.mType = value.toInt();
apparatus.mData.mType = value.toInt();
else if (column==mQuality)
record.get().mData.mQuality = value.toFloat();
apparatus.mData.mQuality = value.toFloat();
else
{
InventoryRefIdAdapter<ESM::Apparatus>::setData (column, data, index, value);
return;
}
record.setModified(apparatus);
}
@ -114,14 +129,22 @@ void CSMWorld::ArmorRefIdAdapter::setData (const RefIdColumn *column, RefIdData&
Record<ESM::Armor>& record = static_cast<Record<ESM::Armor>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Armor)));
ESM::Armor armor = record.get();
if (column==mType)
record.get().mData.mType = value.toInt();
armor.mData.mType = value.toInt();
else if (column==mHealth)
record.get().mData.mHealth = value.toInt();
armor.mData.mHealth = value.toInt();
else if (column==mArmor)
record.get().mData.mArmor = value.toInt();
armor.mData.mArmor = value.toInt();
else
{
EnchantableRefIdAdapter<ESM::Armor>::setData (column, data, index, value);
return;
}
record.setModified(armor);
}
CSMWorld::BookRefIdAdapter::BookRefIdAdapter (const EnchantableColumns& columns,
@ -151,12 +174,20 @@ void CSMWorld::BookRefIdAdapter::setData (const RefIdColumn *column, RefIdData&
Record<ESM::Book>& record = static_cast<Record<ESM::Book>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Book)));
ESM::Book book = record.get();
if (column==mScroll)
record.get().mData.mIsScroll = value.toInt();
book.mData.mIsScroll = value.toInt();
else if (column==mSkill)
record.get().mData.mSkillID = value.toInt();
book.mData.mSkillID = value.toInt();
else
{
EnchantableRefIdAdapter<ESM::Book>::setData (column, data, index, value);
return;
}
record.setModified(book);
}
CSMWorld::ClothingRefIdAdapter::ClothingRefIdAdapter (const EnchantableColumns& columns,
@ -186,10 +217,18 @@ void CSMWorld::ClothingRefIdAdapter::setData (const RefIdColumn *column, RefIdDa
Record<ESM::Clothing>& record = static_cast<Record<ESM::Clothing>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Clothing)));
ESM::Clothing clothing = record.get();
if (column==mType)
record.get().mData.mType = value.toInt();
clothing.mData.mType = value.toInt();
else
{
EnchantableRefIdAdapter<ESM::Clothing>::setData (column, data, index, value);
return;
}
record.setModified(clothing);
}
CSMWorld::ContainerRefIdAdapter::ContainerRefIdAdapter (const NameColumns& columns,
@ -226,24 +265,32 @@ void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdD
Record<ESM::Container>& record = static_cast<Record<ESM::Container>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container)));
ESM::Container container = record.get();
if (column==mWeight)
record.get().mWeight = value.toFloat();
container.mWeight = value.toFloat();
else if (column==mOrganic)
{
if (value.toInt())
record.get().mFlags |= ESM::Container::Organic;
container.mFlags |= ESM::Container::Organic;
else
record.get().mFlags &= ~ESM::Container::Organic;
container.mFlags &= ~ESM::Container::Organic;
}
else if (column==mRespawn)
{
if (value.toInt())
record.get().mFlags |= ESM::Container::Respawn;
container.mFlags |= ESM::Container::Respawn;
else
record.get().mFlags &= ~ESM::Container::Respawn;
container.mFlags &= ~ESM::Container::Respawn;
}
else
{
NameRefIdAdapter<ESM::Container>::setData (column, data, index, value);
return;
}
record.setModified(container);
}
CSMWorld::CreatureColumns::CreatureColumns (const ActorColumns& actorColumns)
@ -303,20 +350,22 @@ void CSMWorld::CreatureRefIdAdapter::setData (const RefIdColumn *column, RefIdDa
Record<ESM::Creature>& record = static_cast<Record<ESM::Creature>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature)));
ESM::Creature creature = record.get();
if (column==mColumns.mType)
record.get().mData.mType = value.toInt();
creature.mData.mType = value.toInt();
else if (column==mColumns.mSoul)
record.get().mData.mSoul = value.toInt();
creature.mData.mSoul = value.toInt();
else if (column==mColumns.mScale)
record.get().mScale = value.toFloat();
creature.mScale = value.toFloat();
else if (column==mColumns.mOriginal)
record.get().mOriginal = value.toString().toUtf8().constData();
creature.mOriginal = value.toString().toUtf8().constData();
else if (column==mColumns.mCombat)
record.get().mData.mCombat = value.toInt();
creature.mData.mCombat = value.toInt();
else if (column==mColumns.mMagic)
record.get().mData.mMagic = value.toInt();
creature.mData.mMagic = value.toInt();
else if (column==mColumns.mStealth)
record.get().mData.mStealth = value.toInt();
creature.mData.mStealth = value.toInt();
else
{
std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
@ -325,15 +374,21 @@ void CSMWorld::CreatureRefIdAdapter::setData (const RefIdColumn *column, RefIdDa
if (iter!=mColumns.mFlags.end())
{
if (value.toInt()!=0)
record.get().mFlags |= iter->second;
creature.mFlags |= iter->second;
else
record.get().mFlags &= ~iter->second;
creature.mFlags &= ~iter->second;
}
else
{
ActorRefIdAdapter<ESM::Creature>::setData (column, data, index, value);
return;
}
}
record.setModified(creature);
}
CSMWorld::DoorRefIdAdapter::DoorRefIdAdapter (const NameColumns& columns,
const RefIdColumn *openSound, const RefIdColumn *closeSound)
: NameRefIdAdapter<ESM::Door> (UniversalId::Type_Door, columns), mOpenSound (openSound),
@ -361,12 +416,20 @@ void CSMWorld::DoorRefIdAdapter::setData (const RefIdColumn *column, RefIdData&
Record<ESM::Door>& record = static_cast<Record<ESM::Door>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Door)));
ESM::Door door = record.get();
if (column==mOpenSound)
record.get().mOpenSound = value.toString().toUtf8().constData();
door.mOpenSound = value.toString().toUtf8().constData();
else if (column==mCloseSound)
record.get().mCloseSound = value.toString().toUtf8().constData();
door.mCloseSound = value.toString().toUtf8().constData();
else
{
NameRefIdAdapter<ESM::Door>::setData (column, data, index, value);
return;
}
record.setModified(door);
}
CSMWorld::LightColumns::LightColumns (const InventoryColumns& columns)
@ -409,14 +472,16 @@ void CSMWorld::LightRefIdAdapter::setData (const RefIdColumn *column, RefIdData&
Record<ESM::Light>& record = static_cast<Record<ESM::Light>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Light)));
ESM::Light light = record.get();
if (column==mColumns.mTime)
record.get().mData.mTime = value.toInt();
light.mData.mTime = value.toInt();
else if (column==mColumns.mRadius)
record.get().mData.mRadius = value.toInt();
light.mData.mRadius = value.toInt();
else if (column==mColumns.mColor)
record.get().mData.mColor = value.toInt();
light.mData.mColor = value.toInt();
else if (column==mColumns.mSound)
record.get().mSound = value.toString().toUtf8().constData();
light.mSound = value.toString().toUtf8().constData();
else
{
std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
@ -425,15 +490,21 @@ void CSMWorld::LightRefIdAdapter::setData (const RefIdColumn *column, RefIdData&
if (iter!=mColumns.mFlags.end())
{
if (value.toInt()!=0)
record.get().mData.mFlags |= iter->second;
light.mData.mFlags |= iter->second;
else
record.get().mData.mFlags &= ~iter->second;
light.mData.mFlags &= ~iter->second;
}
else
{
InventoryRefIdAdapter<ESM::Light>::setData (column, data, index, value);
return;
}
}
record.setModified (light);
}
CSMWorld::MiscRefIdAdapter::MiscRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *key)
: InventoryRefIdAdapter<ESM::Miscellaneous> (UniversalId::Type_Miscellaneous, columns), mKey (key)
{}
@ -456,10 +527,18 @@ void CSMWorld::MiscRefIdAdapter::setData (const RefIdColumn *column, RefIdData&
Record<ESM::Miscellaneous>& record = static_cast<Record<ESM::Miscellaneous>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Miscellaneous)));
ESM::Miscellaneous misc = record.get();
if (column==mKey)
record.get().mData.mIsKey = value.toInt();
misc.mData.mIsKey = value.toInt();
else
{
InventoryRefIdAdapter<ESM::Miscellaneous>::setData (column, data, index, value);
return;
}
record.setModified(misc);
}
CSMWorld::NpcColumns::NpcColumns (const ActorColumns& actorColumns)
@ -525,16 +604,18 @@ void CSMWorld::NpcRefIdAdapter::setData (const RefIdColumn *column, RefIdData& d
Record<ESM::NPC>& record = static_cast<Record<ESM::NPC>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc)));
ESM::NPC npc = record.get();
if (column==mColumns.mRace)
record.get().mRace = value.toString().toUtf8().constData();
npc.mRace = value.toString().toUtf8().constData();
else if (column==mColumns.mClass)
record.get().mClass = value.toString().toUtf8().constData();
npc.mClass = value.toString().toUtf8().constData();
else if (column==mColumns.mFaction)
record.get().mFaction = value.toString().toUtf8().constData();
npc.mFaction = value.toString().toUtf8().constData();
else if (column==mColumns.mHair)
record.get().mHair = value.toString().toUtf8().constData();
npc.mHair = value.toString().toUtf8().constData();
else if (column==mColumns.mHead)
record.get().mHead = value.toString().toUtf8().constData();
npc.mHead = value.toString().toUtf8().constData();
else
{
std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
@ -543,15 +624,25 @@ void CSMWorld::NpcRefIdAdapter::setData (const RefIdColumn *column, RefIdData& d
if (iter!=mColumns.mFlags.end())
{
if (value.toInt()!=0)
record.get().mFlags |= iter->second;
npc.mFlags |= iter->second;
else
record.get().mFlags &= ~iter->second;
npc.mFlags &= ~iter->second;
if (iter->second == ESM::NPC::Autocalc)
npc.mNpdtType = (value.toInt() != 0) ? ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS
: ESM::NPC::NPC_DEFAULT;
}
else
{
ActorRefIdAdapter<ESM::NPC>::setData (column, data, index, value);
return;
}
}
record.setModified (npc);
}
CSMWorld::NpcAttributesRefIdAdapter::NpcAttributesRefIdAdapter ()
{}

View file

@ -673,44 +673,32 @@ namespace MWMechanics
return false;
}
void AiCombat::buildNewPath(const MWWorld::Ptr& actor, const MWWorld::Ptr& target)
bool AiCombat::doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell)
{
osg::Vec3f newPathTarget = target.getRefData().getPosition().asVec3();
float dist;
if (!mPathFinder.getPath().empty())
{
ESM::Pathgrid::Point lastPt = mPathFinder.getPath().back();
osg::Vec3f currPathTarget(PathFinder::MakeOsgVec3(lastPt));
dist = (newPathTarget - currPathTarget).length();
osg::Vec3f currPathTarget(PathFinder::MakeOsgVec3(mPathFinder.getPath().back()));
osg::Vec3f newPathTarget = PathFinder::MakeOsgVec3(dest);
float dist = (newPathTarget - currPathTarget).length();
float targetPosThreshold = (cell->isExterior()) ? 300.0f : 100.0f;
return dist > targetPosThreshold;
}
else dist = 1e+38F; // necessarily construct a new path
float targetPosThreshold = (actor.getCell()->getCell()->isExterior())? 300.0f : 100.0f;
//construct new path only if target has moved away more than on [targetPosThreshold]
if(dist > targetPosThreshold)
{
ESM::Position pos = actor.getRefData().getPosition();
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos));
ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(newPathTarget));
if(!mPathFinder.isPathConstructed())
mPathFinder.buildPath(start, dest, actor.getCell(), false);
else
{
PathFinder newPathFinder;
newPathFinder.buildPath(start, dest, actor.getCell(), false);
// necessarily construct a new path
return true;
}
}
if(!mPathFinder.getPath().empty())
void AiCombat::buildNewPath(const MWWorld::Ptr& actor, const MWWorld::Ptr& target)
{
newPathFinder.syncStart(mPathFinder.getPath());
mPathFinder = newPathFinder;
}
}
ESM::Pathgrid::Point newPathTarget = PathFinder::MakePathgridPoint(target.getRefData().getPosition());
//construct new path only if target has moved away more than on [targetPosThreshold]
if (doesPathNeedRecalc(newPathTarget, actor.getCell()->getCell()))
{
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(actor.getRefData().getPosition()));
mPathFinder.buildSyncedPath(start, newPathTarget, actor.getCell(), false);
}
}

View file

@ -51,6 +51,9 @@ namespace MWMechanics
virtual void writeState(ESM::AiSequence::AiSequence &sequence) const;
protected:
virtual bool doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell);
private:
int mTargetActorId;

View file

@ -28,9 +28,9 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po
ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
/// Stops the actor when it gets too close to a unloaded cell
const ESM::Cell *cell = actor.getCell()->getCell();
{
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
const ESM::Cell *cell = actor.getCell()->getCell();
Movement &movement = actor.getClass().getMovementSettings(actor);
//Ensure pursuer doesn't leave loaded cells
@ -65,8 +65,8 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po
//***********************
if(mTimer > 0.25)
{
if(distance(mPrevDest, dest) > 10) { //Only rebuild path if it's moved
mPathFinder.buildPath(start, dest, actor.getCell(), true); //Rebuild path, in case the target has moved
if (doesPathNeedRecalc(dest, cell)) { //Only rebuild path if it's moved
mPathFinder.buildSyncedPath(start, dest, actor.getCell(), true); //Rebuild path, in case the target has moved
mPrevDest = dest;
}
@ -121,3 +121,8 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po
return false;
}
bool MWMechanics::AiPackage::doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell)
{
return distance(mPrevDest, dest) > 10;
}

View file

@ -4,6 +4,8 @@
#include "pathfinding.hpp"
#include <components/esm/defs.hpp>
#include "../mwworld/cellstore.hpp"
#include "obstacle.hpp"
#include "aistate.hpp"
@ -71,6 +73,8 @@ namespace MWMechanics
/** \return If the actor has arrived at his destination **/
bool pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Point dest, float duration);
virtual bool doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell);
// TODO: all this does not belong here, move into temporary storage
PathFinder mPathFinder;
ObstacleCheck mObstacleCheck;

View file

@ -49,64 +49,31 @@ namespace MWMechanics
bool AiTravel::execute (const MWWorld::Ptr& actor, AiState& state, float duration)
{
MWBase::World *world = MWBase::Environment::get().getWorld();
ESM::Position pos = actor.getRefData().getPosition();
Movement &movement = actor.getClass().getMovementSettings(actor);
const ESM::Cell *cell = actor.getCell()->getCell();
actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, false);
actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing);
MWWorld::Ptr player = world->getPlayerPtr();
if(cell->mData.mX != player.getCell()->getCell()->mData.mX)
{
int sideX = PathFinder::sgn(cell->mData.mX - player.getCell()->getCell()->mData.mX);
//check if actor is near the border of an inactive cell. If so, stop walking.
if(sideX * (pos.pos[0] - cell->mData.mX*ESM::Land::REAL_SIZE) >
sideX * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
{
movement.mPosition[1] = 0;
return false;
}
}
if(cell->mData.mY != player.getCell()->getCell()->mData.mY)
{
int sideY = PathFinder::sgn(cell->mData.mY - player.getCell()->getCell()->mData.mY);
//check if actor is near the border of an inactive cell. If so, stop walking.
if(sideY * (pos.pos[1] - cell->mData.mY*ESM::Land::REAL_SIZE) >
sideY * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
{
movement.mPosition[1] = 0;
return false;
}
}
if (!isWithinMaxRange(osg::Vec3f(mX, mY, mZ), pos.asVec3()))
return false;
if (pathTo(actor, ESM::Pathgrid::Point(static_cast<int>(mX), static_cast<int>(mY), static_cast<int>(mZ)), duration))
{
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
return true;
}
return false;
}
bool AiTravel::doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell)
{
bool cellChange = cell->mData.mX != mCellX || cell->mData.mY != mCellY;
if (!mPathFinder.isPathConstructed() || cellChange)
{
mCellX = cell->mData.mX;
mCellY = cell->mData.mY;
ESM::Pathgrid::Point dest(static_cast<int>(mX), static_cast<int>(mY), static_cast<int>(mZ));
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos));
mPathFinder.buildPath(start, dest, actor.getCell(), true);
}
if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1]))
{
movement.mPosition[1] = 0;
return true;
}
zTurn(actor, osg::DegreesToRadians(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])));
movement.mPosition[1] = 1;
return false;
}

View file

@ -34,6 +34,9 @@ namespace MWMechanics
virtual int getTypeId() const;
protected:
virtual bool doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell);
private:
float mX;
float mY;

View file

@ -298,23 +298,35 @@ namespace MWMechanics
return false;
}
// used by AiCombat, see header for the rationale
bool PathFinder::syncStart(const std::list<ESM::Pathgrid::Point> &path)
// see header for the rationale
void PathFinder::buildSyncedPath(const ESM::Pathgrid::Point &startPoint,
const ESM::Pathgrid::Point &endPoint,
const MWWorld::CellStore* cell,
bool allowShortcuts)
{
if (mPath.size() < 2)
return false; //nothing to pop
std::list<ESM::Pathgrid::Point>::const_iterator oldStart = path.begin();
{
// if path has one point, then it's the destination.
// don't need to worry about bad path for this case
buildPath(startPoint, endPoint, cell, allowShortcuts);
}
else
{
const ESM::Pathgrid::Point oldStart(*getPath().begin());
buildPath(startPoint, endPoint, cell, allowShortcuts);
if (mPath.size() >= 2)
{
// if 2nd waypoint of new path == 1st waypoint of old,
// delete 1st waypoint of new path.
std::list<ESM::Pathgrid::Point>::iterator iter = ++mPath.begin();
if( (*iter).mX == oldStart->mX
&& (*iter).mY == oldStart->mY
&& (*iter).mZ == oldStart->mZ)
if (iter->mX == oldStart.mX
&& iter->mY == oldStart.mY
&& iter->mZ == oldStart.mZ)
{
mPath.pop_front();
return true;
}
return false;
}
}
}
}

View file

@ -61,13 +61,13 @@ namespace MWMechanics
/** Synchronize new path with old one to avoid visiting 1 waypoint 2 times
@note
If the first point is chosen as the nearest one
the situation can occur when the 1st point of the new path is undesirable
(i.e. the 2nd point of new path == the 1st point of old path).
@param path - old path
@return true if such point was found and deleted
BuildPath() takes closest PathGrid point to NPC as first point of path.
This is undesireable if NPC has just passed a Pathgrid point, as this
makes the 2nd point of the new path == the 1st point of old path.
Which results in NPC "running in a circle" back to the just passed waypoint.
*/
bool syncStart(const std::list<ESM::Pathgrid::Point> &path);
void buildSyncedPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint,
const MWWorld::CellStore* cell, bool allowShortcuts = true);
void addPointToPath(ESM::Pathgrid::Point &point)
{

View file

@ -188,7 +188,7 @@ namespace MWWorld
const T *ptr = search(id);
if (ptr == 0) {
std::ostringstream msg;
msg << "Object '" << id << "' not found (const)";
msg << T::getRecordType() << " '" << id << "' not found";
throw std::runtime_error(msg.str());
}
return ptr;
@ -202,7 +202,7 @@ namespace MWWorld
if(ptr == 0)
{
std::ostringstream msg;
msg << "Object starting with '"<<id<<"' not found (const)";
msg << T::getRecordType() << " starting with '"<<id<<"' not found";
throw std::runtime_error(msg.str());
}
return ptr;
@ -989,7 +989,7 @@ namespace MWWorld
const T *ptr = search(index);
if (ptr == 0) {
std::ostringstream msg;
msg << "Object with index " << index << " not found";
msg << T::getRecordType() << " with index " << index << " not found";
throw std::runtime_error(msg.str());
}
return ptr;

View file

@ -1,7 +1,6 @@
#include "gamesettings.hpp"
#include "launchersettings.hpp"
#include <QTextCodec>
#include <QTextStream>
#include <QDir>
#include <QString>
@ -174,138 +173,6 @@ bool Config::GameSettings::writeFile(QTextStream &stream)
return true;
}
// Policy:
//
// - Always ignore a line beginning with '#' or empty lines
//
// - If a line in file exists with matching key and first part of value (before ',',
// '\n', etc) also matches, then replace the line with that of mUserSettings.
// - else remove line (TODO: maybe replace the line with '#' in front instead?)
//
// - If there is no corresponding line in file, add at the end
//
bool Config::GameSettings::writeFileWithComments(QFile &file)
{
QTextStream stream(&file);
stream.setCodec(QTextCodec::codecForName("UTF-8"));
// slurp
std::vector<QString> fileCopy;
QString line = stream.readLine();
while (!line.isNull())
{
fileCopy.push_back(line);
line = stream.readLine();
}
stream.seek(0);
// empty file, no comments to keep
if (fileCopy.empty())
return writeFile(stream);
// Temp copy of settings to save, but with the keys appended with the first part of the value
//
// ATTENTION!
//
// A hack to avoid looping through each line, makes use of the fact that fallbacks values
// are comma separated.
QMap<QString, QString> userSettingsCopy;
QRegExp settingRegex("^([^=]+)\\s*=\\s*([^,]+)(.*)$");
QString settingLine;
QMap<QString, QString>::const_iterator settingsIter = mUserSettings.begin();
for (; settingsIter != mUserSettings.end(); ++settingsIter)
{
settingLine = settingsIter.key()+"="+settingsIter.value();
if (settingRegex.indexIn(settingLine) != -1)
{
userSettingsCopy[settingRegex.cap(1)+"="+settingRegex.cap(2)] =
(settingRegex.captureCount() < 3) ? "" : settingRegex.cap(3);
}
}
QString keyVal;
for (std::vector<QString>::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter)
{
// skip empty or comment lines
if ((*iter).isEmpty() || (*iter).contains(QRegExp("^\\s*#")))
continue;
// look for a key in the line
if (settingRegex.indexIn(*iter) == -1 || settingRegex.captureCount() < 2)
{
// no key or first part of value found in line, replace with a null string which
// will be remved later
*iter = QString();
continue;
}
// look for a matching key in user settings
keyVal = settingRegex.cap(1)+"="+settingRegex.cap(2);
QMap<QString, QString>::iterator it = userSettingsCopy.find(keyVal);
if (it == userSettingsCopy.end())
{
// no such key+valStart, replace with a null string which will be remved later
*iter = QString();
}
else
{
*iter = QString(it.key()+it.value());
userSettingsCopy.erase(it);
}
}
// write the new config file
QString key;
QString value;
for (std::vector<QString>::iterator iter = fileCopy.begin(); iter != fileCopy.end(); ++iter)
{
if ((*iter).isNull())
continue;
// Below is based on readFile() code, if that changes corresponding change may be
// required (for example duplicates may be inserted if the rules don't match)
if ((*iter).isEmpty() || (*iter).contains(QRegExp("^\\s*#")))
{
stream << *iter << "\n";
continue;
}
if (settingRegex.indexIn(*iter) == -1 || settingRegex.captureCount() < 2)
continue;
// Quote paths with spaces
key = settingRegex.cap(1);
value = settingRegex.cap(2)+settingRegex.cap(3);
if (key == QLatin1String("data")
|| key == QLatin1String("data-local")
|| key == QLatin1String("resources"))
{
if (value.contains(QChar(' ')))
{
value.remove(QChar('\"')); // Remove quotes
stream << key << "=\"" << value << "\"\n";
continue;
}
}
stream << key << "=" << value << "\n";
}
// new entries
if (!userSettingsCopy.empty())
{
QMap<QString, QString>::const_iterator it = userSettingsCopy.begin();
for (; it != userSettingsCopy.end(); ++it)
{
stream << it.key() << it.value() << "\n";
}
}
file.resize(file.pos());
return true;
}
bool Config::GameSettings::hasMaster()
{
bool result = false;

View file

@ -4,7 +4,6 @@
#include <QTextStream>
#include <QStringList>
#include <QString>
#include <QFile>
#include <QMap>
#include <boost/filesystem/path.hpp>
@ -67,7 +66,6 @@ namespace Config
bool readUserFile(QTextStream &stream);
bool writeFile(QTextStream &stream);
bool writeFileWithComments(QFile &file);
void setContentList(const QStringList& fileNames);
QStringList getContentList() const;

View file

@ -12,6 +12,8 @@ class ESMWriter;
struct Activator
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Activator"; }
std::string mId, mName, mScript, mModel;

View file

@ -19,6 +19,9 @@ struct Potion
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Potion"; }
struct ALDTstruct
{
float mWeight;

View file

@ -16,6 +16,8 @@ class ESMWriter;
struct Apparatus
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Apparatus"; }
enum AppaType
{

View file

@ -66,6 +66,8 @@ struct PartReferenceList
struct Armor
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Armor"; }
enum Type
{

View file

@ -12,6 +12,8 @@ class ESMWriter;
struct BodyPart
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "BodyPart"; }
enum MeshPart
{

View file

@ -15,6 +15,8 @@ class ESMWriter;
struct Book
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Book"; }
struct BKDTstruct
{

View file

@ -14,6 +14,8 @@ class ESMWriter;
struct BirthSign
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "BirthSign"; }
std::string mId, mName, mDescription, mTexture;

View file

@ -56,6 +56,8 @@ typedef std::list<CellRef> CellRefTracker;
struct Cell
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Cell"; }
enum Flags
{

View file

@ -18,6 +18,8 @@ class ESMWriter;
struct Class
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Class"; }
enum AutoCalc
{

View file

@ -18,6 +18,8 @@ class ESMWriter;
struct Clothing
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Clothing"; }
enum Type
{

View file

@ -36,6 +36,8 @@ struct InventoryList
struct Container
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Container"; }
enum Flags
{

View file

@ -22,6 +22,8 @@ class ESMWriter;
struct Creature
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Creature"; }
// Default is 0x48?
enum Flags

View file

@ -21,6 +21,8 @@ class ESMWriter;
struct Dialogue
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Dialogue"; }
enum Type
{

View file

@ -12,6 +12,8 @@ class ESMWriter;
struct Door
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Door"; }
std::string mId, mName, mModel, mScript, mOpenSound, mCloseSound;

View file

@ -18,6 +18,8 @@ class ESMWriter;
struct Enchantment
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Enchantment"; }
enum Type
{

View file

@ -30,6 +30,8 @@ struct RankData
struct Faction
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Faction"; }
std::string mId, mName;

View file

@ -18,6 +18,8 @@ class ESMWriter;
struct Global
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Global"; }
std::string mId;
Variant mValue;

View file

@ -19,6 +19,8 @@ class ESMWriter;
struct GameSetting
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "GameSetting"; }
std::string mId;

View file

@ -21,6 +21,8 @@ class ESMWriter;
struct DialInfo
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "DialInfo"; }
enum Gender
{

View file

@ -16,6 +16,8 @@ class ESMWriter;
struct Ingredient
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Ingredient"; }
struct IRDTstruct
{

View file

@ -18,6 +18,8 @@ class ESMWriter;
struct Land
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Land"; }
Land();
~Land();

View file

@ -46,6 +46,8 @@ struct LevelledListBase
struct CreatureLevList: LevelledListBase
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "CreatureLevList"; }
enum Flags
{
@ -64,6 +66,8 @@ struct CreatureLevList: LevelledListBase
struct ItemLevList: LevelledListBase
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "ItemLevList"; }
enum Flags
{

View file

@ -17,6 +17,8 @@ class ESMWriter;
struct Light
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Light"; }
enum Flags
{

View file

@ -12,6 +12,8 @@ class ESMWriter;
struct Lockpick
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Lockpick"; }
struct Data
{

View file

@ -28,6 +28,8 @@ class ESMWriter;
struct LandTexture
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "LandTexture"; }
std::string mId, mTexture;
int mIndex;

View file

@ -13,6 +13,8 @@ class ESMWriter;
struct MagicEffect
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "MagicEffect"; }
std::string mId;

View file

@ -17,6 +17,8 @@ class ESMWriter;
struct Miscellaneous
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Miscellaneous"; }
struct MCDTstruct
{

View file

@ -23,6 +23,8 @@ class ESMWriter;
struct NPC
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "NPC"; }
// Services
enum Services
@ -55,7 +57,7 @@ struct NPC
Female = 0x0001,
Essential = 0x0002,
Respawn = 0x0004,
Autocalc = 0x0008,
Autocalc = 0x0010,
Skeleton = 0x0400, // Skeleton blood effect (white)
Metal = 0x0800 // Metal blood effect (golden?)
};

View file

@ -16,6 +16,8 @@ class ESMWriter;
struct Pathgrid
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Pathgrid"; }
struct DATAstruct
{

View file

@ -12,6 +12,8 @@ class ESMWriter;
struct Probe
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Probe"; }
struct Data
{

View file

@ -18,6 +18,8 @@ class ESMWriter;
struct Race
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Race"; }
struct SkillBonus
{

View file

@ -19,6 +19,8 @@ class ESMWriter;
struct Region
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Region"; }
#pragma pack(push)
#pragma pack(1)

View file

@ -12,6 +12,8 @@ class ESMWriter;
struct Repair
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Repair"; }
struct Data
{

View file

@ -20,6 +20,8 @@ class Script
{
public:
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Script"; }
struct SCHDstruct
{

View file

@ -20,6 +20,8 @@ class ESMWriter;
struct Skill
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Skill"; }
std::string mId;

View file

@ -16,6 +16,8 @@ class ESMWriter;
struct SoundGenerator
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "SoundGenerator"; }
enum Type
{

View file

@ -17,6 +17,8 @@ struct SOUNstruct
struct Sound
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Sound"; }
SOUNstruct mData;
std::string mId, mSound;

View file

@ -14,6 +14,8 @@ class ESMWriter;
struct Spell
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Spell"; }
enum SpellType
{

View file

@ -20,6 +20,8 @@ class ESMWriter;
struct StartScript
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "StartScript"; }
std::string mData;
std::string mId;

View file

@ -23,6 +23,8 @@ class ESMWriter;
struct Static
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Static"; }
std::string mId, mModel;

View file

@ -16,6 +16,8 @@ class ESMWriter;
struct Weapon
{
static unsigned int sRecordId;
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string getRecordType() { return "Weapon"; }
enum Type
{