Closes #1092: Implement sleep interruption. Fix levelled list flags for creatures. Change World::copyObjectToCell to search for the correct cell.

pull/22/head
scrawl 11 years ago
parent 69381c49c7
commit 52b9ebff9d

@ -717,16 +717,26 @@ std::string landFlags(int flags)
return properties;
}
std::string leveledListFlags(int flags)
std::string itemListFlags(int flags)
{
std::string properties = "";
if (flags == 0) properties += "[None] ";
if (flags & ESM::LeveledListBase::AllLevels) properties += "AllLevels ";
// This flag apparently not present on creature lists...
if (flags & ESM::LeveledListBase::Each) properties += "Each ";
if (flags & ESM::ItemLevList::AllLevels) properties += "AllLevels ";
if (flags & ESM::ItemLevList::Each) properties += "Each ";
int unused = (0xFFFFFFFF ^
(ESM::LeveledListBase::AllLevels|
ESM::LeveledListBase::Each));
(ESM::ItemLevList::AllLevels|
ESM::ItemLevList::Each));
if (flags & unused) properties += "Invalid ";
properties += str(boost::format("(0x%08X)") % flags);
return properties;
}
std::string creatureListFlags(int flags)
{
std::string properties = "";
if (flags == 0) properties += "[None] ";
if (flags & ESM::CreatureLevList::AllLevels) properties += "AllLevels ";
int unused = (0xFFFFFFFF ^ ESM::CreatureLevList::AllLevels);
if (flags & unused) properties += "Invalid ";
properties += str(boost::format("(0x%08X)") % flags);
return properties;

@ -50,7 +50,8 @@ std::string cellFlags(int flags);
std::string containerFlags(int flags);
std::string creatureFlags(int flags);
std::string landFlags(int flags);
std::string leveledListFlags(int flags);
std::string creatureListFlags(int flags);
std::string itemListFlags(int flags);
std::string lightFlags(int flags);
std::string magicEffectFlags(int flags);
std::string npcFlags(int flags);

@ -834,7 +834,8 @@ template<>
void Record<ESM::CreatureLevList>::print()
{
std::cout << " Chance for None: " << (int)mData.mChanceNone << std::endl;
std::cout << " Flags: " << leveledListFlags(mData.mFlags) << std::endl;
std::cout << " Flags: " << creatureListFlags(mData.mFlags) << std::endl;
std::cout << " Chance none: " << mData.mChanceNone << std::endl;
std::cout << " Number of items: " << mData.mList.size() << std::endl;
std::vector<ESM::LeveledListBase::LevelItem>::iterator iit;
for (iit = mData.mList.begin(); iit != mData.mList.end(); iit++)
@ -846,11 +847,12 @@ template<>
void Record<ESM::ItemLevList>::print()
{
std::cout << " Chance for None: " << (int)mData.mChanceNone << std::endl;
std::cout << " Flags: " << leveledListFlags(mData.mFlags) << std::endl;
std::cout << " Flags: " << itemListFlags(mData.mFlags) << std::endl;
std::cout << " Chance none: " << mData.mChanceNone << std::endl;
std::cout << " Number of items: " << mData.mList.size() << std::endl;
std::vector<ESM::LeveledListBase::LevelItem>::iterator iit;
for (iit = mData.mList.begin(); iit != mData.mList.end(); iit++)
std::cout << " Inventory: Count: " << iit->mLevel
std::cout << " Inventory: Level: " << iit->mLevel
<< " Item: " << iit->mId << std::endl;
}

@ -460,6 +460,9 @@ namespace MWBase
virtual void confiscateStolenItems(const MWWorld::Ptr& ptr) = 0;
virtual void goToJail () = 0;
/// Spawn a random creature from a levelled list next to the player
virtual void spawnRandomCreature(const std::string& creatureList) = 0;
};
}

@ -48,6 +48,7 @@ namespace MWGui
, mRemainingTime(0.05)
, mCurHour(0)
, mManualHours(1)
, mInterruptAt(-1)
{
getWidget(mDateTimeText, "DateTimeText");
getWidget(mRestText, "RestText");
@ -156,7 +157,8 @@ namespace MWGui
void WaitDialog::startWaiting(int hoursToWait)
{
MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(0.2);
MWBase::World* world = MWBase::Environment::get().getWorld();
world->getFader ()->fadeOut(0.2);
setVisible(false);
mProgressBar.setVisible (true);
@ -164,6 +166,30 @@ namespace MWGui
mCurHour = 0;
mHours = hoursToWait;
// FIXME: move this somewhere else?
mInterruptAt = -1;
MWWorld::Ptr player = world->getPlayerPtr();
if (mSleeping && player.getCell()->isExterior())
{
std::string regionstr = player.getCell()->mCell->mRegion;
if (!regionstr.empty())
{
const ESM::Region *region = world->getStore().get<ESM::Region>().find (regionstr);
if (!region->mSleepList.empty())
{
float fSleepRandMod = world->getStore().get<ESM::GameSetting>().find("fSleepRandMod")->getFloat();
int x = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * hoursToWait; // [0, hoursRested]
float y = fSleepRandMod * hoursToWait;
if (x > y)
{
float fSleepRestMod = world->getStore().get<ESM::GameSetting>().find("fSleepRestMod")->getFloat();
mInterruptAt = int(fSleepRestMod * hoursToWait);
mInterruptCreatureList = region->mSleepList;
}
}
}
}
mRemainingTime = 0.05;
mProgressBar.setProgress (0, mHours);
}
@ -206,6 +232,13 @@ namespace MWGui
if (!mWaiting)
return;
if (mCurHour == mInterruptAt)
{
MWBase::Environment::get().getWindowManager()->messageBox("#{sSleepInterrupt}");
MWBase::Environment::get().getWorld()->spawnRandomCreature(mInterruptCreatureList);
stopWaiting();
}
mRemainingTime -= dt;
while (mRemainingTime < 0)

@ -51,6 +51,9 @@ namespace MWGui
int mManualHours; // stores the hours to rest selected via slider
float mRemainingTime;
int mInterruptAt;
std::string mInterruptCreatureList;
WaitDialogProgressBar mProgressBar;
void onUntilHealedButtonClicked(MyGUI::Widget* sender);

@ -515,7 +515,7 @@ namespace MWMechanics
if (magnitude > 0)
{
ESM::Position ipos = ptr.getRefData().getPosition();
Ogre::Vector3 pos(ipos.pos[0],ipos.pos[1],ipos.pos[2]);
Ogre::Vector3 pos(ipos.pos);
Ogre::Quaternion rot(Ogre::Radian(-ipos.rot[2]), Ogre::Vector3::UNIT_Z);
const float distance = 50;
pos = pos + distance*rot.yAxis();

@ -860,6 +860,7 @@ void CharacterController::update(float duration)
bool onground = world->isOnGround(mPtr);
bool inwater = world->isSwimming(mPtr);
bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run);
isrunning = true;
bool sneak = cls.getStance(mPtr, MWWorld::Class::Sneak);
bool flying = world->isFlying(mPtr);
Ogre::Vector3 vec = cls.getMovementVector(mPtr);

@ -11,7 +11,7 @@ namespace MWMechanics
{
/// @return ID of resulting item, or empty if none
std::string getLevelledItem (const ESM::LeveledListBase* levItem, unsigned char failChance=0)
inline std::string getLevelledItem (const ESM::LeveledListBase* levItem, bool creature, unsigned char failChance=0)
{
const std::vector<ESM::LeveledListBase::LevelItem>& items = levItem->mList;
@ -20,29 +20,33 @@ namespace MWMechanics
failChance += levItem->mChanceNone;
float random = static_cast<float> (std::rand()) / RAND_MAX;
if (random < failChance/100.f)
int random = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
if (random < failChance)
return std::string();
std::vector<std::string> candidates;
int highestLevel = 0;
for (std::vector<ESM::LeveledListBase::LevelItem>::const_iterator it = items.begin(); it != items.end(); ++it)
{
if (it->mLevel > highestLevel)
if (it->mLevel > highestLevel && it->mLevel <= playerLevel)
highestLevel = it->mLevel;
}
// For levelled creatures, the flags are swapped. This file format just makes so much sense.
bool allLevels = levItem->mFlags & ESM::ItemLevList::AllLevels;
if (creature)
allLevels = levItem->mFlags & ESM::CreatureLevList::AllLevels;
std::pair<int, std::string> highest = std::make_pair(-1, "");
for (std::vector<ESM::LeveledListBase::LevelItem>::const_iterator it = items.begin(); it != items.end(); ++it)
{
if (playerLevel >= it->mLevel
&& (levItem->mFlags & ESM::LeveledListBase::AllLevels || it->mLevel == highestLevel))
&& (allLevels || it->mLevel == highestLevel))
{
candidates.push_back(it->mId);
if (it->mLevel >= highest.first)
highest = std::make_pair(it->mLevel, it->mId);
}
}
if (candidates.empty())
return std::string();

@ -321,7 +321,7 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::
}
else
{
std::string id = MWMechanics::getLevelledItem(ref.getPtr().get<ESM::ItemLevList>()->mBase);
std::string id = MWMechanics::getLevelledItem(ref.getPtr().get<ESM::ItemLevList>()->mBase, false);
if (id.empty())
return;
addInitialItem(id, owner, faction, count, false);

@ -27,6 +27,7 @@
#include "../mwmechanics/movement.hpp"
#include "../mwmechanics/npcstats.hpp"
#include "../mwmechanics/spellcasting.hpp"
#include "../mwmechanics/levelledlist.hpp"
#include "../mwrender/sky.hpp"
@ -1538,23 +1539,28 @@ namespace MWWorld
}
Ptr World::copyObjectToCell(const Ptr &object, CellStore &cell, const ESM::Position &pos, bool adjustPos)
Ptr World::copyObjectToCell(const Ptr &object, CellStore &cell, ESM::Position pos, bool adjustPos)
{
/// \todo add searching correct cell for position specified
MWWorld::Ptr dropped =
MWWorld::Class::get(object).copyToCell(object, cell, pos);
if (object.getClass().isActor() || adjustPos)
{
Ogre::Vector3 min, max;
if (mPhysics->getObjectAABB(object, min, max)) {
float *pos = dropped.getRefData().getPosition().pos;
pos[0] -= (min.x + max.x) / 2;
pos[1] -= (min.y + max.y) / 2;
pos[2] -= min.z;
pos.pos[0] -= (min.x + max.x) / 2;
pos.pos[1] -= (min.y + max.y) / 2;
pos.pos[2] -= min.z;
}
}
if (cell.isExterior())
{
int cellX, cellY;
positionToIndex(pos.pos[0], pos.pos[1], cellX, cellY);
cell = *mCells.getExterior(cellX, cellY);
}
MWWorld::Ptr dropped =
MWWorld::Class::get(object).copyToCell(object, cell, pos);
if (mWorldScene->isCellActive(cell)) {
if (dropped.getRefData().isEnabled()) {
mWorldScene->addObjectToScene(dropped);
@ -2571,4 +2577,37 @@ namespace MWWorld
MWBase::Environment::get().getWindowManager()->messageBox(message, buttons);
}
}
void World::spawnRandomCreature(const std::string &creatureList)
{
const ESM::CreatureLevList* list = getStore().get<ESM::CreatureLevList>().find(creatureList);
int iNumberCreatures = getStore().get<ESM::GameSetting>().find("iNumberCreatures")->getInt();
int numCreatures = 1 + std::rand()/ (static_cast<double> (RAND_MAX) + 1) * iNumberCreatures; // [1, iNumberCreatures]
for (int i=0; i<numCreatures; ++i)
{
std::string selectedCreature = MWMechanics::getLevelledItem(list, true);
if (selectedCreature.empty())
return;
ESM::Position ipos = mPlayer->getPlayer().getRefData().getPosition();
Ogre::Vector3 pos(ipos.pos);
Ogre::Quaternion rot(Ogre::Radian(-ipos.rot[2]), Ogre::Vector3::UNIT_Z);
const float distance = 50;
pos = pos + distance*rot.yAxis();
ipos.pos[0] = pos.x;
ipos.pos[1] = pos.y;
ipos.pos[2] = pos.z;
ipos.rot[0] = 0;
ipos.rot[1] = 0;
ipos.rot[2] = 0;
MWWorld::CellStore* cell = mPlayer->getPlayer().getCell();
MWWorld::ManualRef ref(getStore(), selectedCreature, 1);
ref.getPtr().getCellRef().mPos = ipos;
safePlaceObject(ref.getPtr(),*cell,ipos);
}
}
}

@ -114,7 +114,7 @@ namespace MWWorld
bool moveObjectImp (const Ptr& ptr, float x, float y, float z);
///< @return true if the active cell (cell player is in) changed
Ptr copyObjectToCell(const Ptr &ptr, CellStore &cell, const ESM::Position &pos, bool adjustPos=true);
Ptr copyObjectToCell(const Ptr &ptr, CellStore &cell, ESM::Position pos, bool adjustPos=true);
void updateWindowManager ();
void performUpdateSceneQueries ();
@ -546,6 +546,9 @@ namespace MWWorld
virtual void confiscateStolenItems(const MWWorld::Ptr& ptr);
virtual void goToJail ();
/// Spawn a random creature from a levelled list next to the player
virtual void spawnRandomCreature(const std::string& creatureList);
};
}

@ -20,20 +20,6 @@ class ESMWriter;
struct LeveledListBase
{
enum Flags
{
Each = 0x01, // Select a new item each time this
// list is instantiated, instead of
// giving several identical items
// (used when a container has more
// than one instance of one leveled
// list.)
AllLevels = 0x02 // Calculate from all levels <= player
// level, not just the closest below
// player.
};
int mFlags;
unsigned char mChanceNone; // Chance that none are selected (0-100)
std::string mId;
@ -61,6 +47,14 @@ struct CreatureLevList: LeveledListBase
{
static unsigned int sRecordId;
enum Flags
{
AllLevels = 0x01 // Calculate from all levels <= player
// level, not just the closest below
// player.
};
CreatureLevList()
{
mRecName = "CNAM";
@ -71,6 +65,20 @@ struct ItemLevList: LeveledListBase
{
static unsigned int sRecordId;
enum Flags
{
Each = 0x01, // Select a new item each time this
// list is instantiated, instead of
// giving several identical items
// (used when a container has more
// than one instance of one leveled
// list.)
AllLevels = 0x02 // Calculate from all levels <= player
// level, not just the closest below
// player.
};
ItemLevList()
{
mRecName = "INAM";

Loading…
Cancel
Save