1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-19 21:53:51 +00:00

Merge remote-tracking branch 'upstream/master'

Conflicts:
	apps/openmw/mwmechanics/aipursue.hpp
	apps/openmw/mwmechanics/aisequence.hpp
This commit is contained in:
Thomas 2014-05-04 02:06:43 -04:00
commit dbf06d8c8b
49 changed files with 542 additions and 285 deletions

View file

@ -434,7 +434,6 @@ IF(NOT WIN32 AND NOT APPLE)
# Install licenses # Install licenses
INSTALL(FILES "DejaVu Font License.txt" DESTINATION "${LICDIR}" ) INSTALL(FILES "DejaVu Font License.txt" DESTINATION "${LICDIR}" )
INSTALL(FILES "OFL.txt" DESTINATION "${LICDIR}" )
INSTALL(FILES "extern/shiny/License.txt" DESTINATION "${LICDIR}" RENAME "Shiny License.txt" ) INSTALL(FILES "extern/shiny/License.txt" DESTINATION "${LICDIR}" RENAME "Shiny License.txt" )
ENDIF (DPKG_PROGRAM) ENDIF (DPKG_PROGRAM)

View file

@ -195,13 +195,13 @@ CSMSettings::UserSettings::~UserSettings()
void CSMSettings::UserSettings::loadSettings (const QString &fileName) void CSMSettings::UserSettings::loadSettings (const QString &fileName)
{ {
mUserFilePath = QString::fromUtf8 mUserFilePath = QString::fromUtf8
(mCfgMgr.getUserConfigPath().c_str()) + fileName.toUtf8(); (mCfgMgr.getUserConfigPath().string().c_str()) + fileName.toUtf8();
QString global = QString::fromUtf8 QString global = QString::fromUtf8
(mCfgMgr.getGlobalPath().c_str()) + fileName.toUtf8(); (mCfgMgr.getGlobalPath().string().c_str()) + fileName.toUtf8();
QString local = QString::fromUtf8 QString local = QString::fromUtf8
(mCfgMgr.getLocalPath().c_str()) + fileName.toUtf8(); (mCfgMgr.getLocalPath().string().c_str()) + fileName.toUtf8();
//open user and global streams //open user and global streams
QTextStream *userStream = openFilestream (mUserFilePath, true); QTextStream *userStream = openFilestream (mUserFilePath, true);

View file

@ -183,7 +183,7 @@ CSVWorld::CommandDelegate* CSVWorld::DialogueDelegateDispatcher::makeDelegate(CS
{ {
delegate = CommandDelegateFactoryCollection::get().makeDelegate ( delegate = CommandDelegateFactoryCollection::get().makeDelegate (
display, mUndoStack, mParent); display, mUndoStack, mParent);
mDelegates.insert(std::make_pair<int, CommandDelegate*>(display, delegate)); mDelegates.insert(std::make_pair(display, delegate));
} else } else
{ {
delegate = delegateIt->second; delegate = delegateIt->second;

View file

@ -67,7 +67,7 @@ add_openmw_dir (mwclass
add_openmw_dir (mwmechanics add_openmw_dir (mwmechanics
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
drawstate spells activespells npcstats aipackage aisequence aipersue alchemy aiwander aitravel aifollow drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow
aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting
disease pickpocket levelledlist combat steering obstacle disease pickpocket levelledlist combat steering obstacle
) )

View file

@ -305,6 +305,10 @@ namespace MWBase
virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) = 0; virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) = 0;
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
virtual int countSavedGameRecords() const = 0;
/// Does the current stack of GUI-windows permit saving?
virtual bool isSavingAllowed() const = 0;
}; };
} }

View file

@ -624,6 +624,8 @@ namespace MWClass
if (!attacker.isEmpty() && ptr.getClass().isNpc() && ptr.getClass().getCreatureStats(ptr).getAiSetting(MWMechanics::CreatureStats::AI_Fight).getModified() <= 30) if (!attacker.isEmpty() && ptr.getClass().isNpc() && ptr.getClass().getCreatureStats(ptr).getAiSetting(MWMechanics::CreatureStats::AI_Fight).getModified() <= 30)
MWBase::Environment::get().getMechanicsManager()->commitCrime(attacker, ptr, MWBase::MechanicsManager::OT_Assault); MWBase::Environment::get().getMechanicsManager()->commitCrime(attacker, ptr, MWBase::MechanicsManager::OT_Assault);
getCreatureStats(ptr).setAttacked(true);
if(!successful) if(!successful)
{ {
// TODO: Handle HitAttemptOnMe script function // TODO: Handle HitAttemptOnMe script function
@ -659,7 +661,6 @@ namespace MWClass
{ {
MWBase::Environment::get().getDialogueManager()->say(ptr, "hit"); MWBase::Environment::get().getDialogueManager()->say(ptr, "hit");
} }
getCreatureStats(ptr).setAttacked(true);
// Check for knockdown // Check for knockdown
float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * fKnockDownMult->getFloat(); float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * fKnockDownMult->getFloat();

View file

@ -215,16 +215,22 @@ namespace MWGui
{ {
std::vector<std::string> matches; std::vector<std::string> matches;
listNames(); listNames();
mCommandLine->setCaption(complete( mCommandLine->getOnlyText(), matches )); std::string oldCaption = mCommandLine->getCaption();
#if 0 std::string newCaption = complete( mCommandLine->getOnlyText(), matches );
int i = 0; mCommandLine->setCaption(newCaption);
for(std::vector<std::string>::iterator it=matches.begin(); it < matches.end(); ++it,++i )
// List candidates if repeatedly pressing tab
if (oldCaption == newCaption && matches.size())
{ {
printOK( *it ); int i = 0;
if( i == 50 ) printOK("");
break; for(std::vector<std::string>::iterator it=matches.begin(); it < matches.end(); ++it,++i )
{
printOK( *it );
if( i == 50 )
break;
}
} }
#endif
} }
if(mCommandHistory.empty()) return; if(mCommandHistory.empty()) return;

View file

@ -196,6 +196,16 @@ namespace MWGui
bitmapFile->read(&textureData[0], width*height*4); bitmapFile->read(&textureData[0], width*height*4);
bitmapFile->close(); bitmapFile->close();
std::string resourceName;
if (name.size() >= 5 && Misc::StringUtils::ciEqual(name.substr(0, 5), "magic"))
resourceName = "Magic Cards";
else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "century"))
resourceName = "Century Gothic";
else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "daedric"))
resourceName = "Daedric";
else
return; // no point in loading it, since there is no way of using additional fonts
std::string textureName = name; std::string textureName = name;
Ogre::Image image; Ogre::Image image;
image.loadDynamicImage(&textureData[0], width, height, Ogre::PF_BYTE_RGBA); image.loadDynamicImage(&textureData[0], width, height, Ogre::PF_BYTE_RGBA);
@ -208,18 +218,11 @@ namespace MWGui
// Register the font with MyGUI // Register the font with MyGUI
MyGUI::ResourceManualFont* font = static_cast<MyGUI::ResourceManualFont*>( MyGUI::ResourceManualFont* font = static_cast<MyGUI::ResourceManualFont*>(
MyGUI::FactoryManager::getInstance().createObject("Resource", "ResourceManualFont")); MyGUI::FactoryManager::getInstance().createObject("Resource", "ResourceManualFont"));
// We need to emulate loading from XML because the data members are private as of mygui 3.2.0 // We need to emulate loading from XML because the data members are private as of mygui 3.2.0
MyGUI::xml::Document xmlDocument; MyGUI::xml::Document xmlDocument;
MyGUI::xml::ElementPtr root = xmlDocument.createRoot("ResourceManualFont"); MyGUI::xml::ElementPtr root = xmlDocument.createRoot("ResourceManualFont");
root->addAttribute("name", resourceName);
if (name.size() >= 5 && Misc::StringUtils::ciEqual(name.substr(0, 5), "magic"))
root->addAttribute("name", "Magic Cards");
else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "century"))
root->addAttribute("name", "Century Gothic");
else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "daedric"))
root->addAttribute("name", "Daedric");
else
return; // no point in loading it, since there is no way of using additional fonts
MyGUI::xml::ElementPtr defaultHeight = root->createChild("Property"); MyGUI::xml::ElementPtr defaultHeight = root->createChild("Property");
defaultHeight->addAttribute("key", "DefaultHeight"); defaultHeight->addAttribute("key", "DefaultHeight");
@ -285,6 +288,7 @@ namespace MWGui
font->deserialization(root, MyGUI::Version(3,2,0)); font->deserialization(root, MyGUI::Version(3,2,0));
MyGUI::ResourceManager::getInstance().removeByName(font->getResourceName());
MyGUI::ResourceManager::getInstance().addResource(font); MyGUI::ResourceManager::getInstance().addResource(font);
} }

View file

@ -35,7 +35,7 @@ namespace MWGui
, mTrading(false) , mTrading(false)
, mLastXSize(0) , mLastXSize(0)
, mLastYSize(0) , mLastYSize(0)
, mPreview(MWBase::Environment::get().getWorld ()->getPlayerPtr()) , mPreview(new MWRender::InventoryPreview(MWBase::Environment::get().getWorld ()->getPlayerPtr()))
, mPreviewDirty(true) , mPreviewDirty(true)
, mDragAndDrop(dragAndDrop) , mDragAndDrop(dragAndDrop)
, mSelectedItem(-1) , mSelectedItem(-1)
@ -91,8 +91,8 @@ namespace MWGui
mTradeModel = new TradeItemModel(new InventoryItemModel(mPtr), MWWorld::Ptr()); mTradeModel = new TradeItemModel(new InventoryItemModel(mPtr), MWWorld::Ptr());
mSortModel = new SortFilterItemModel(mTradeModel); mSortModel = new SortFilterItemModel(mTradeModel);
mItemView->setModel(mSortModel); mItemView->setModel(mSortModel);
mPreview = MWRender::InventoryPreview(mPtr); mPreview.reset(new MWRender::InventoryPreview(mPtr));
mPreview.setup(); mPreview->setup();
} }
void InventoryWindow::setGuiMode(GuiMode mode) void InventoryWindow::setGuiMode(GuiMode mode)
@ -444,7 +444,7 @@ namespace MWGui
MWWorld::Ptr InventoryWindow::getAvatarSelectedItem(int x, int y) MWWorld::Ptr InventoryWindow::getAvatarSelectedItem(int x, int y)
{ {
int slot = mPreview.getSlotSelected (x, y); int slot = mPreview->getSlotSelected (x, y);
if (slot == -1) if (slot == -1)
return MWWorld::Ptr(); return MWWorld::Ptr();
@ -493,7 +493,7 @@ namespace MWGui
mPreviewDirty = false; mPreviewDirty = false;
MyGUI::IntSize size = mAvatarImage->getSize(); MyGUI::IntSize size = mAvatarImage->getSize();
mPreview.update (size.width, size.height); mPreview->update (size.width, size.height);
mAvatarImage->setImageTexture("CharacterPreview"); mAvatarImage->setImageTexture("CharacterPreview");
mAvatarImage->setImageCoord(MyGUI::IntCoord(0, 0, std::min(512, size.width), std::min(1024, size.height))); mAvatarImage->setImageCoord(MyGUI::IntCoord(0, 0, std::min(512, size.width), std::min(1024, size.height)));

View file

@ -34,7 +34,7 @@ namespace MWGui
MWWorld::Ptr getAvatarSelectedItem(int x, int y); MWWorld::Ptr getAvatarSelectedItem(int x, int y);
void rebuildAvatar() { void rebuildAvatar() {
mPreview.rebuild(); mPreview->rebuild();
} }
TradeItemModel* getTradeModel(); TradeItemModel* getTradeModel();
@ -81,7 +81,7 @@ namespace MWGui
int mLastXSize; int mLastXSize;
int mLastYSize; int mLastYSize;
MWRender::InventoryPreview mPreview; std::auto_ptr<MWRender::InventoryPreview> mPreview;
bool mTrading; bool mTrading;

View file

@ -170,7 +170,8 @@ namespace MWGui
buttons.push_back("loadgame"); buttons.push_back("loadgame");
if (state==MWBase::StateManager::State_Running && if (state==MWBase::StateManager::State_Running &&
MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1) MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1 &&
MWBase::Environment::get().getWindowManager()->isSavingAllowed())
buttons.push_back("savegame"); buttons.push_back("savegame");
buttons.push_back("options"); buttons.push_back("options");

View file

@ -2,6 +2,8 @@
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <components/esm/quickkeys.hpp>
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
@ -55,6 +57,14 @@ namespace MWGui
} }
} }
void QuickKeysMenu::clear()
{
for (int i=0; i<10; ++i)
{
unassign(mQuickKeyButtons[i], i);
}
}
QuickKeysMenu::~QuickKeysMenu() QuickKeysMenu::~QuickKeysMenu()
{ {
delete mAssignDialog; delete mAssignDialog;
@ -154,8 +164,6 @@ namespace MWGui
frame->setUserString ("ToolTipType", "ItemPtr"); frame->setUserString ("ToolTipType", "ItemPtr");
frame->setUserData(item); frame->setUserData(item);
frame->eventMouseButtonClick += MyGUI::newDelegate(this, &QuickKeysMenu::onQuickKeyButtonClicked); frame->eventMouseButtonClick += MyGUI::newDelegate(this, &QuickKeysMenu::onQuickKeyButtonClicked);
MyGUI::ImageBox* image = frame->createWidget<MyGUI::ImageBox>("ImageBox", MyGUI::IntCoord(5, 5, 32, 32), MyGUI::Align::Default); MyGUI::ImageBox* image = frame->createWidget<MyGUI::ImageBox>("ImageBox", MyGUI::IntCoord(5, 5, 32, 32), MyGUI::Align::Default);
std::string path = std::string("icons\\"); std::string path = std::string("icons\\");
path += MWWorld::Class::get(item).getInventoryIcon(item); path += MWWorld::Class::get(item).getInventoryIcon(item);
@ -165,7 +173,8 @@ namespace MWGui
image->setImageTexture (path); image->setImageTexture (path);
image->setNeedMouseFocus (false); image->setNeedMouseFocus (false);
mItemSelectionDialog->setVisible(false); if (mItemSelectionDialog)
mItemSelectionDialog->setVisible(false);
} }
void QuickKeysMenu::onAssignItemCancel() void QuickKeysMenu::onAssignItemCancel()
@ -198,7 +207,8 @@ namespace MWGui
image->setImageTexture (path); image->setImageTexture (path);
image->setNeedMouseFocus (false); image->setNeedMouseFocus (false);
mMagicSelectionDialog->setVisible(false); if (mMagicSelectionDialog)
mMagicSelectionDialog->setVisible(false);
} }
void QuickKeysMenu::onAssignMagic (const std::string& spellId) void QuickKeysMenu::onAssignMagic (const std::string& spellId)
@ -239,7 +249,8 @@ namespace MWGui
image->setImageTexture (path); image->setImageTexture (path);
image->setNeedMouseFocus (false); image->setNeedMouseFocus (false);
mMagicSelectionDialog->setVisible(false); if (mMagicSelectionDialog)
mMagicSelectionDialog->setVisible(false);
} }
void QuickKeysMenu::onAssignMagicCancel () void QuickKeysMenu::onAssignMagicCancel ()
@ -374,6 +385,110 @@ namespace MWGui
center(); center();
} }
void QuickKeysMenu::write(ESM::ESMWriter &writer)
{
writer.startRecord(ESM::REC_KEYS);
ESM::QuickKeys keys;
for (int i=0; i<10; ++i)
{
MyGUI::Button* button = mQuickKeyButtons[i];
int type = *button->getUserData<QuickKeyType>();
ESM::QuickKeys::QuickKey key;
key.mType = type;
switch (type)
{
case Type_Unassigned:
break;
case Type_Item:
case Type_MagicItem:
{
MWWorld::Ptr item = *button->getChildAt(0)->getUserData<MWWorld::Ptr>();
key.mId = item.getCellRef().mRefID;
break;
}
case Type_Magic:
std::string spellId = button->getChildAt(0)->getUserString("Spell");
key.mId = spellId;
break;
}
keys.mKeys.push_back(key);
}
keys.save(writer);
writer.endRecord(ESM::REC_KEYS);
}
void QuickKeysMenu::readRecord(ESM::ESMReader &reader, int32_t type)
{
if (type != ESM::REC_KEYS)
return;
ESM::QuickKeys keys;
keys.load(reader);
int i=0;
for (std::vector<ESM::QuickKeys::QuickKey>::const_iterator it = keys.mKeys.begin(); it != keys.mKeys.end(); ++it)
{
if (i >= 10)
return;
mSelectedIndex = i;
int keyType = it->mType;
std::string id = it->mId;
MyGUI::Button* button = mQuickKeyButtons[i];
switch (keyType)
{
case Type_Magic:
onAssignMagic(id);
break;
case Type_Item:
case Type_MagicItem:
{
// Find the item by id
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player);
MWWorld::Ptr item;
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
{
if (Misc::StringUtils::ciEqual(it->getCellRef().mRefID, id))
{
if (item.isEmpty() ||
// Prefer the stack with the lowest remaining uses
(it->getCellRef().mCharge != -1 && (item.getCellRef().mCharge == -1 || it->getCellRef().mCharge < item.getCellRef().mCharge) ))
{
item = *it;
}
}
}
if (item.isEmpty())
unassign(button, i);
else
{
if (keyType == Type_Item)
onAssignItem(item);
else if (keyType == Type_MagicItem)
onAssignMagicItem(item);
}
break;
}
case Type_Unassigned:
unassign(button, i);
break;
}
++i;
}
}
// --------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------

View file

@ -41,6 +41,11 @@ namespace MWGui
}; };
void write (ESM::ESMWriter& writer);
void readRecord (ESM::ESMReader& reader, int32_t type);
void clear();
private: private:
MyGUI::EditBox* mInstructionLabel; MyGUI::EditBox* mInstructionLabel;
MyGUI::Button* mOkButton; MyGUI::Button* mOkButton;

View file

@ -17,6 +17,8 @@ namespace MWGui
void checkReferenceAvailable(); ///< closes the window, if the MW-reference has become unavailable void checkReferenceAvailable(); ///< closes the window, if the MW-reference has become unavailable
void resetReference() { mPtr = MWWorld::Ptr(); mCurrentPlayerCell = NULL; }
protected: protected:
virtual void onReferenceUnavailable() = 0; ///< called when reference has become unavailable virtual void onReferenceUnavailable() = 0; ///< called when reference has become unavailable

View file

@ -53,7 +53,7 @@ namespace MWGui
{ {
onSlotSelected(sender, pos); onSlotSelected(sender, pos);
if (MyGUI::InputManager::getInstance().isShiftPressed()) if (pos != MyGUI::ITEM_NONE && MyGUI::InputManager::getInstance().isShiftPressed())
{ {
ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog();
dialog->open("#{sMessage3}"); dialog->open("#{sMessage3}");
@ -206,6 +206,13 @@ namespace MWGui
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage65}"); MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage65}");
return; return;
} }
}
setVisible(false);
MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_MainMenu);
if (mSaving)
{
MWBase::Environment::get().getStateManager()->saveGame (mSaveNameEdit->getCaption(), mCurrentSlot); MWBase::Environment::get().getStateManager()->saveGame (mSaveNameEdit->getCaption(), mCurrentSlot);
} }
else else
@ -213,12 +220,9 @@ namespace MWGui
if (mCurrentCharacter && mCurrentSlot) if (mCurrentCharacter && mCurrentSlot)
{ {
MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, mCurrentSlot); MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, mCurrentSlot);
MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_MainMenu);
} }
} }
setVisible(false);
if (MWBase::Environment::get().getStateManager()->getState()== if (MWBase::Environment::get().getStateManager()->getState()==
MWBase::StateManager::State_NoGame) MWBase::StateManager::State_NoGame)
{ {

View file

@ -475,7 +475,7 @@ namespace MWGui
text += std::string("#DDC79E") + faction->mName; text += std::string("#DDC79E") + faction->mName;
if (expelled.find(it->first) != expelled.end()) if (expelled.find(it->first) != expelled.end())
text += "\n#{sExpelled}"; text += "\n#BF9959#{sExpelled}";
else else
{ {
text += std::string("\n#BF9959") + faction->mRanks[it->second]; text += std::string("\n#BF9959") + faction->mRanks[it->second];

View file

@ -1405,16 +1405,49 @@ namespace MWGui
void WindowManager::clear() void WindowManager::clear()
{ {
mMap->clear(); mMap->clear();
mQuickKeysMenu->clear();
mTrainingWindow->resetReference();
mDialogueWindow->resetReference();
mTradeWindow->resetReference();
mSpellBuyingWindow->resetReference();
mSpellCreationDialog->resetReference();
mEnchantingDialog->resetReference();
mContainerWindow->resetReference();
mCompanionWindow->resetReference();
mConsole->resetReference();
mGuiModes.clear();
updateVisible();
} }
void WindowManager::write(ESM::ESMWriter &writer, Loading::Listener& progress) void WindowManager::write(ESM::ESMWriter &writer, Loading::Listener& progress)
{ {
mMap->write(writer, progress); mMap->write(writer, progress);
mQuickKeysMenu->write(writer);
progress.increaseProgress();
} }
void WindowManager::readRecord(ESM::ESMReader &reader, int32_t type) void WindowManager::readRecord(ESM::ESMReader &reader, int32_t type)
{ {
mMap->readRecord(reader, type); if (type == ESM::REC_GMAP)
mMap->readRecord(reader, type);
else if (type == ESM::REC_KEYS)
mQuickKeysMenu->readRecord(reader, type);
}
int WindowManager::countSavedGameRecords() const
{
return 1 // Global map
+ 1; // QuickKeysMenu
}
bool WindowManager::isSavingAllowed() const
{
return !MyGUI::InputManager::getInstance().isModalAny()
// TODO: remove this, once we have properly serialized the state of open windows
&& (!isGuiMode() || (mGuiModes.size() == 1 && getMode() == GM_MainMenu));
} }
void WindowManager::playVideo(const std::string &name, bool allowSkipping) void WindowManager::playVideo(const std::string &name, bool allowSkipping)

View file

@ -293,6 +293,10 @@ namespace MWGui
virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress); virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress);
virtual void readRecord (ESM::ESMReader& reader, int32_t type); virtual void readRecord (ESM::ESMReader& reader, int32_t type);
virtual int countSavedGameRecords() const;
/// Does the current stack of GUI-windows permit saving?
virtual bool isSavingAllowed() const;
private: private:
bool mConsoleOnlyScripts; bool mConsoleOnlyScripts;

View file

@ -29,7 +29,7 @@
#include "aicombat.hpp" #include "aicombat.hpp"
#include "aifollow.hpp" #include "aifollow.hpp"
#include "aipersue.hpp" #include "aipursue.hpp"
namespace namespace
{ {
@ -719,34 +719,33 @@ namespace MWMechanics
CreatureStats& creatureStats = MWWorld::Class::get(ptr).getCreatureStats(ptr); CreatureStats& creatureStats = MWWorld::Class::get(ptr).getCreatureStats(ptr);
NpcStats& npcStats = MWWorld::Class::get(ptr).getNpcStats(ptr); NpcStats& npcStats = MWWorld::Class::get(ptr).getNpcStats(ptr);
// If I'm a guard and I'm not hostile if (ptr.getClass().isClass(ptr, "Guard") && creatureStats.getAiSequence().getTypeId() != AiPackage::TypeIdPursue && !creatureStats.isHostile())
if (ptr.getClass().isClass(ptr, "Guard") && !creatureStats.isHostile())
{ {
/// \todo Move me! I shouldn't be here... /// \todo Move me! I shouldn't be here...
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
float cutoff = float(esmStore.get<ESM::GameSetting>().find("iCrimeThreshold")->getInt()) * float cutoff = float(esmStore.get<ESM::GameSetting>().find("iCrimeThreshold")->getInt());
float(esmStore.get<ESM::GameSetting>().find("iCrimeThresholdMultiplier")->getInt()) * // Force dialogue on sight if bounty is greater than the cutoff
esmStore.get<ESM::GameSetting>().find("fCrimeGoldDiscountMult")->getFloat(); // In vanilla morrowind, the greeting dialogue is scripted to either arrest the player (< 5000 bounty) or attack (>= 5000 bounty)
// Attack on sight if bounty is greater than the cutoff
if ( player.getClass().getNpcStats(player).getBounty() >= cutoff if ( player.getClass().getNpcStats(player).getBounty() >= cutoff
// TODO: do not run these two every frame. keep an Aware state for each actor and update it every 0.2 s or so?
&& MWBase::Environment::get().getWorld()->getLOS(ptr, player) && MWBase::Environment::get().getWorld()->getLOS(ptr, player)
&& MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, ptr)) && MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, ptr))
{ {
creatureStats.getAiSequence().stack(AiCombat(player), ptr); creatureStats.getAiSequence().stack(AiPursue(player.getClass().getId(player)), ptr);
creatureStats.setHostile(true); creatureStats.setAlarmed(true);
npcStats.setCrimeId( MWBase::Environment::get().getWorld()->getPlayer().getCrimeId() ); npcStats.setCrimeId(MWBase::Environment::get().getWorld()->getPlayer().getNewCrimeId());
} }
} }
// if I was a witness to a crime // if I was a witness to a crime
if (npcStats.getCrimeId() != -1) if (npcStats.getCrimeId() != -1)
{ {
// if you've payed for your crimes and I havent noticed // if you've paid for your crimes and I havent noticed
if( npcStats.getCrimeId() <= MWBase::Environment::get().getWorld()->getPlayer().getCrimeId() ) if( npcStats.getCrimeId() <= MWBase::Environment::get().getWorld()->getPlayer().getCrimeId() )
{ {
// Calm witness down // Calm witness down
if (ptr.getClass().isClass(ptr, "Guard")) if (ptr.getClass().isClass(ptr, "Guard"))
creatureStats.getAiSequence().stopPersue(); creatureStats.getAiSequence().stopPursuit();
creatureStats.getAiSequence().stopCombat(); creatureStats.getAiSequence().stopCombat();
// Reset factors to attack // Reset factors to attack
@ -761,13 +760,12 @@ namespace MWMechanics
else if (!creatureStats.isHostile()) else if (!creatureStats.isHostile())
{ {
if (ptr.getClass().isClass(ptr, "Guard")) if (ptr.getClass().isClass(ptr, "Guard"))
creatureStats.getAiSequence().stack(AiPersue(player.getClass().getId(player)), ptr); creatureStats.getAiSequence().stack(AiPursue(player.getClass().getId(player)), ptr);
else else
creatureStats.getAiSequence().stack(AiCombat(player), ptr); creatureStats.getAiSequence().stack(AiCombat(player), ptr);
creatureStats.setHostile(true); creatureStats.setHostile(true);
} }
} }
// if I didn't report a crime was I attacked? // if I didn't report a crime was I attacked?
else if (creatureStats.getAttacked() && !creatureStats.isHostile()) else if (creatureStats.getAttacked() && !creatureStats.isHostile())
{ {

View file

@ -392,7 +392,7 @@ namespace MWMechanics
else // remote pathfinding else // remote pathfinding
{ {
bool preferShortcut = false; bool preferShortcut = false;
bool inLOS; bool inLOS = MWBase::Environment::get().getWorld()->getLOS(actor, mTarget);
if(mReadyToAttack) isStuck = false; if(mReadyToAttack) isStuck = false;
@ -400,7 +400,7 @@ namespace MWMechanics
if(!isStuck if(!isStuck
&& (!mForceNoShortcut && (!mForceNoShortcut
|| (Ogre::Vector3(mShortcutFailPos.pos) - vActorPos).length() >= PATHFIND_SHORTCUT_RETRY_DIST) || (Ogre::Vector3(mShortcutFailPos.pos) - vActorPos).length() >= PATHFIND_SHORTCUT_RETRY_DIST)
&& (inLOS = MWBase::Environment::get().getWorld()->getLOS(actor, mTarget))) && inLOS)
{ {
if(speed == 0.0f) speed = actorCls.getSpeed(actor); if(speed == 0.0f) speed = actorCls.getSpeed(actor);
// maximum dist before pit/obstacle for actor to avoid them depending on his speed // maximum dist before pit/obstacle for actor to avoid them depending on his speed
@ -437,7 +437,7 @@ namespace MWMechanics
if(inLOS && mPathFinder.getPath().size() > 1) if(inLOS && mPathFinder.getPath().size() > 1)
{ {
// get point just before target // get point just before target
std::list<ESM::Pathgrid::Point>::iterator pntIter = --mPathFinder.getPath().end(); std::list<ESM::Pathgrid::Point>::const_iterator pntIter = --mPathFinder.getPath().end();
--pntIter; --pntIter;
Ogre::Vector3 vBeforeTarget = Ogre::Vector3(pntIter->mX, pntIter->mY, pntIter->mZ); Ogre::Vector3 vBeforeTarget = Ogre::Vector3(pntIter->mX, pntIter->mY, pntIter->mZ);

View file

@ -21,7 +21,7 @@ namespace MWMechanics
TypeIdFollow = 3, TypeIdFollow = 3,
TypeIdActivate = 4, TypeIdActivate = 4,
TypeIdCombat = 5, TypeIdCombat = 5,
TypeIdPersue = 6 TypeIdPursue = 6
}; };
///Default Deconstructor ///Default Deconstructor

View file

@ -1,4 +1,4 @@
#include "aipersue.hpp" #include "aipursue.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
@ -11,15 +11,15 @@
#include "movement.hpp" #include "movement.hpp"
#include "creaturestats.hpp" #include "creaturestats.hpp"
MWMechanics::AiPersue::AiPersue(const std::string &objectId) MWMechanics::AiPursue::AiPursue(const std::string &objectId)
: mObjectId(objectId) : mObjectId(objectId)
{ {
} }
MWMechanics::AiPersue *MWMechanics::AiPersue::clone() const MWMechanics::AiPursue *MWMechanics::AiPursue::clone() const
{ {
return new AiPersue(*this); return new AiPursue(*this);
} }
bool MWMechanics::AiPersue::execute (const MWWorld::Ptr& actor, float duration) bool MWMechanics::AiPursue::execute (const MWWorld::Ptr& actor, float duration)
{ {
MWBase::World *world = MWBase::Environment::get().getWorld(); MWBase::World *world = MWBase::Environment::get().getWorld();
ESM::Position pos = actor.getRefData().getPosition(); ESM::Position pos = actor.getRefData().getPosition();
@ -52,11 +52,13 @@ bool MWMechanics::AiPersue::execute (const MWWorld::Ptr& actor, float duration)
} }
} }
// Big TODO: Sync this with current AiFollow. Move common code to a shared base class or helpers (applies to all AI packages, way too much duplicated code)
MWWorld::Ptr target = world->getPtr(mObjectId,false); MWWorld::Ptr target = world->getPtr(mObjectId,false);
ESM::Position targetPos = target.getRefData().getPosition(); ESM::Position targetPos = target.getRefData().getPosition();
bool cellChange = cell->mData.mX != mCellX || cell->mData.mY != mCellY; bool cellChange = cell->mData.mX != mCellX || cell->mData.mY != mCellY;
if(!mPathFinder.isPathConstructed() || cellChange) if(!mPathFinder.isPathConstructed() || cellChange || mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
{ {
mCellX = cell->mData.mX; mCellX = cell->mData.mX;
mCellY = cell->mData.mY; mCellY = cell->mData.mY;
@ -76,15 +78,7 @@ bool MWMechanics::AiPersue::execute (const MWWorld::Ptr& actor, float duration)
if((pos.pos[0]-targetPos.pos[0])*(pos.pos[0]-targetPos.pos[0])+ if((pos.pos[0]-targetPos.pos[0])*(pos.pos[0]-targetPos.pos[0])+
(pos.pos[1]-targetPos.pos[1])*(pos.pos[1]-targetPos.pos[1])+ (pos.pos[1]-targetPos.pos[1])*(pos.pos[1]-targetPos.pos[1])+
(pos.pos[2]-targetPos.pos[2])*(pos.pos[2]-targetPos.pos[2]) < 200*200) (pos.pos[2]-targetPos.pos[2])*(pos.pos[2]-targetPos.pos[2]) < 100*100)
{
movement.mPosition[1] = 0;
MWWorld::Ptr target = world->getPtr(mObjectId,false);
MWWorld::Class::get(target).activate(target,actor).get()->execute(actor);
return true;
}
if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
{ {
movement.mPosition[1] = 0; movement.mPosition[1] = 0;
MWWorld::Ptr target = world->getPtr(mObjectId,false); MWWorld::Ptr target = world->getPtr(mObjectId,false);
@ -100,7 +94,7 @@ bool MWMechanics::AiPersue::execute (const MWWorld::Ptr& actor, float duration)
return false; return false;
} }
int MWMechanics::AiPersue::getTypeId() const int MWMechanics::AiPursue::getTypeId() const
{ {
return TypeIdPersue; return TypeIdPursue;
} }

View file

@ -1,5 +1,5 @@
#ifndef GAME_MWMECHANICS_AIPERSUE_H #ifndef GAME_MWMECHANICS_AIPURSUE_H
#define GAME_MWMECHANICS_AIPERSUE_H #define GAME_MWMECHANICS_AIPURSUE_H
#include "aipackage.hpp" #include "aipackage.hpp"
#include <string> #include <string>
@ -17,6 +17,12 @@ namespace MWMechanics
/** \param objectId Actor to pursue **/ /** \param objectId Actor to pursue **/
AiPersue(const std::string &objectId); AiPersue(const std::string &objectId);
virtual AiPersue *clone() const; virtual AiPersue *clone() const;
class AiPursue : public AiPackage
{
public:
AiPursue(const std::string &objectId);
virtual AiPursue *clone() const;
virtual bool execute (const MWWorld::Ptr& actor,float duration); virtual bool execute (const MWWorld::Ptr& actor,float duration);
virtual int getTypeId() const; virtual int getTypeId() const;

View file

@ -73,9 +73,9 @@ void MWMechanics::AiSequence::stopCombat()
} }
} }
void MWMechanics::AiSequence::stopPersue() void MWMechanics::AiSequence::stopPursuit()
{ {
while (getTypeId() == AiPackage::TypeIdPersue) while (getTypeId() == AiPackage::TypeIdPursue)
{ {
delete *mPackages.begin(); delete *mPackages.begin();
mPackages.erase (mPackages.begin()); mPackages.erase (mPackages.begin());
@ -93,11 +93,16 @@ void MWMechanics::AiSequence::execute (const MWWorld::Ptr& actor,float duration)
{ {
if (!mPackages.empty()) if (!mPackages.empty())
{ {
mLastAiPackage = mPackages.front()->getTypeId(); MWMechanics::AiPackage* package = mPackages.front();
if (mPackages.front()->execute (actor,duration)) mLastAiPackage = package->getTypeId();
if (package->execute (actor,duration))
{ {
delete *mPackages.begin(); // To account for the rare case where AiPackage::execute() queued another AI package
mPackages.erase (mPackages.begin()); // (e.g. AiPursue executing a dialogue script that uses startCombat)
std::list<MWMechanics::AiPackage*>::iterator toRemove =
std::find(mPackages.begin(), mPackages.end(), package);
mPackages.erase(toRemove);
delete package;
mDone = true; mDone = true;
} }
else else
@ -118,7 +123,7 @@ void MWMechanics::AiSequence::clear()
void MWMechanics::AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor) void MWMechanics::AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor)
{ {
if (package.getTypeId() == AiPackage::TypeIdCombat || package.getTypeId() == AiPackage::TypeIdPersue) if (package.getTypeId() == AiPackage::TypeIdCombat || package.getTypeId() == AiPackage::TypeIdPursue)
{ {
// Notify AiWander of our current position so we can return to it after combat finished // Notify AiWander of our current position so we can return to it after combat finished
for (std::list<AiPackage *>::const_iterator iter (mPackages.begin()); iter!=mPackages.end(); ++iter) for (std::list<AiPackage *>::const_iterator iter (mPackages.begin()); iter!=mPackages.end(); ++iter)

View file

@ -65,6 +65,9 @@ namespace MWMechanics
/// Has a package been completed during the last update? /// Has a package been completed during the last update?
bool isPackageDone() const; bool isPackageDone() const;
/// Removes all pursue packages until first non-pursue or stack empty.
void stopPursuit();
/// Execute current package, switching if needed. /// Execute current package, switching if needed.
void execute (const MWWorld::Ptr& actor,float duration); void execute (const MWWorld::Ptr& actor,float duration);

View file

@ -489,12 +489,13 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
mIdleState = CharState_Idle; mIdleState = CharState_Idle;
} }
refreshCurrentAnims(mIdleState, mMovementState, true);
if(mDeathState != CharState_None) if(mDeathState != CharState_None)
{ {
playRandomDeath(1.0f); playRandomDeath(1.0f);
} }
else
refreshCurrentAnims(mIdleState, mMovementState, true);
} }
CharacterController::~CharacterController() CharacterController::~CharacterController()

View file

@ -21,194 +21,199 @@ namespace MWRender
namespace MWMechanics namespace MWMechanics
{ {
class Movement; class Movement;
class CreatureStats; class CreatureStats;
enum Priority { ///Priority of actions
Priority_Default, enum Priority {
Priority_Jump, Priority_Default,
Priority_Movement, Priority_Jump,
Priority_Hit, Priority_Movement,
Priority_Weapon, Priority_Hit,
Priority_Knockdown, Priority_Weapon,
Priority_Torch, Priority_Knockdown,
Priority_Torch,
Priority_Death, Priority_Death,
Num_Priorities Num_Priorities
}; };
enum CharacterState { /// Current action of the character
CharState_None, enum CharacterState {
CharState_None,
CharState_SpecialIdle, CharState_SpecialIdle,
CharState_Idle, CharState_Idle,
CharState_Idle2, CharState_Idle2,
CharState_Idle3, CharState_Idle3,
CharState_Idle4, CharState_Idle4,
CharState_Idle5, CharState_Idle5,
CharState_Idle6, CharState_Idle6,
CharState_Idle7, CharState_Idle7,
CharState_Idle8, CharState_Idle8,
CharState_Idle9, CharState_Idle9,
CharState_IdleSwim, CharState_IdleSwim,
CharState_IdleSneak, CharState_IdleSneak,
CharState_WalkForward, CharState_WalkForward,
CharState_WalkBack, CharState_WalkBack,
CharState_WalkLeft, CharState_WalkLeft,
CharState_WalkRight, CharState_WalkRight,
CharState_SwimWalkForward, CharState_SwimWalkForward,
CharState_SwimWalkBack, CharState_SwimWalkBack,
CharState_SwimWalkLeft, CharState_SwimWalkLeft,
CharState_SwimWalkRight, CharState_SwimWalkRight,
CharState_RunForward, CharState_RunForward,
CharState_RunBack, CharState_RunBack,
CharState_RunLeft, CharState_RunLeft,
CharState_RunRight, CharState_RunRight,
CharState_SwimRunForward, CharState_SwimRunForward,
CharState_SwimRunBack, CharState_SwimRunBack,
CharState_SwimRunLeft, CharState_SwimRunLeft,
CharState_SwimRunRight, CharState_SwimRunRight,
CharState_SneakForward, CharState_SneakForward,
CharState_SneakBack, CharState_SneakBack,
CharState_SneakLeft, CharState_SneakLeft,
CharState_SneakRight, CharState_SneakRight,
CharState_TurnLeft, CharState_TurnLeft,
CharState_TurnRight, CharState_TurnRight,
CharState_Jump, CharState_Jump,
CharState_Death1, CharState_Death1,
CharState_Death2, CharState_Death2,
CharState_Death3, CharState_Death3,
CharState_Death4, CharState_Death4,
CharState_Death5, CharState_Death5,
CharState_SwimDeath, CharState_SwimDeath,
CharState_DeathKnockDown, CharState_DeathKnockDown,
CharState_DeathKnockOut, CharState_DeathKnockOut,
CharState_Hit, CharState_Hit,
CharState_KnockDown, CharState_KnockDown,
CharState_KnockOut, CharState_KnockOut,
CharState_Block CharState_Block
}; };
enum WeaponType { ///Weapon type
WeapType_None, enum WeaponType {
WeapType_None,
WeapType_HandToHand, WeapType_HandToHand,
WeapType_OneHand, WeapType_OneHand,
WeapType_TwoHand, WeapType_TwoHand,
WeapType_TwoWide, WeapType_TwoWide,
WeapType_BowAndArrow, WeapType_BowAndArrow,
WeapType_Crossbow, WeapType_Crossbow,
WeapType_Thrown, WeapType_Thrown,
WeapType_PickProbe, WeapType_PickProbe,
WeapType_Spell WeapType_Spell
}; };
enum UpperBodyCharacterState { ///Specific, weapon based state of the character
UpperCharState_Nothing, enum UpperBodyCharacterState {
UpperCharState_EquipingWeap, UpperCharState_Nothing,
UpperCharState_UnEquipingWeap, UpperCharState_EquipingWeap,
UpperCharState_WeapEquiped, UpperCharState_UnEquipingWeap,
UpperCharState_StartToMinAttack, UpperCharState_WeapEquiped,
UpperCharState_MinAttackToMaxAttack, UpperCharState_StartToMinAttack,
UpperCharState_MaxAttackToMinHit, UpperCharState_MinAttackToMaxAttack,
UpperCharState_MinHitToHit, UpperCharState_MaxAttackToMinHit,
UpperCharState_FollowStartToFollowStop, UpperCharState_MinHitToHit,
UpperCharState_CastingSpell UpperCharState_FollowStartToFollowStop,
}; UpperCharState_CastingSpell
};
enum JumpingState { ///Current jumping state
JumpState_None, enum JumpingState {
JumpState_Falling, JumpState_None,
JumpState_Landing JumpState_Falling,
}; JumpState_Landing
};
class CharacterController class CharacterController
{ {
MWWorld::Ptr mPtr; MWWorld::Ptr mPtr;
MWRender::Animation *mAnimation; MWRender::Animation *mAnimation;
typedef std::deque<std::pair<std::string,size_t> > AnimationQueue; typedef std::deque<std::pair<std::string,size_t> > AnimationQueue;
AnimationQueue mAnimQueue; AnimationQueue mAnimQueue;
CharacterState mIdleState; CharacterState mIdleState;
std::string mCurrentIdle; std::string mCurrentIdle;
CharacterState mMovementState; CharacterState mMovementState;
std::string mCurrentMovement; std::string mCurrentMovement;
float mMovementSpeed; float mMovementSpeed;
float mMovementAnimVelocity; float mMovementAnimVelocity;
CharacterState mDeathState; CharacterState mDeathState;
std::string mCurrentDeath; std::string mCurrentDeath;
CharacterState mHitState; CharacterState mHitState;
std::string mCurrentHit; std::string mCurrentHit;
UpperBodyCharacterState mUpperBodyState; UpperBodyCharacterState mUpperBodyState;
JumpingState mJumpState; JumpingState mJumpState;
std::string mCurrentJump; std::string mCurrentJump;
WeaponType mWeaponType; WeaponType mWeaponType;
std::string mCurrentWeapon; std::string mCurrentWeapon;
bool mSkipAnim; bool mSkipAnim;
// counted for skill increase // counted for skill increase
float mSecondsOfSwimming; float mSecondsOfSwimming;
float mSecondsOfRunning; float mSecondsOfRunning;
std::string mAttackType; // slash, chop or thrust std::string mAttackType; // slash, chop or thrust
void determineAttackType(); void determineAttackType();
void refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force=false); void refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force=false);
void clearAnimQueue(); void clearAnimQueue();
bool updateWeaponState(); bool updateWeaponState();
bool updateCreatureState(); bool updateCreatureState();
void updateVisibility(); void updateVisibility();
void playRandomDeath(float startpoint = 0.0f); void playRandomDeath(float startpoint = 0.0f);
/// choose a random animation group with \a prefix and numeric suffix /// choose a random animation group with \a prefix and numeric suffix
/// @param num if non-NULL, the chosen animation number will be written here /// @param num if non-NULL, the chosen animation number will be written here
std::string chooseRandomGroup (const std::string& prefix, int* num = NULL); std::string chooseRandomGroup (const std::string& prefix, int* num = NULL);
public: public:
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim); CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim);
virtual ~CharacterController(); virtual ~CharacterController();
// Be careful when to call this, see comment in Actors // Be careful when to call this, see comment in Actors
void updateContinuousVfx(); void updateContinuousVfx();
void updatePtr(const MWWorld::Ptr &ptr); void updatePtr(const MWWorld::Ptr &ptr);
void update(float duration); void update(float duration);
void playGroup(const std::string &groupname, int mode, int count); void playGroup(const std::string &groupname, int mode, int count);
void skipAnim(); void skipAnim();
bool isAnimPlaying(const std::string &groupName); bool isAnimPlaying(const std::string &groupName);
bool kill(); bool kill();
void resurrect(); void resurrect();
bool isDead() const bool isDead() const
{ return mDeathState != CharState_None; } { return mDeathState != CharState_None; }
void forceStateUpdate(); void forceStateUpdate();
}; };
void getWeaponGroup(WeaponType weaptype, std::string &group); void getWeaponGroup(WeaponType weaptype, std::string &group);
MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, MWWorld::InventoryStore &inv, WeaponType *weaptype); MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, MWWorld::InventoryStore &inv, WeaponType *weaptype);

View file

@ -57,7 +57,7 @@ namespace MWMechanics
return mPath.size(); return mPath.size();
} }
std::list<ESM::Pathgrid::Point> getPath() const const std::list<ESM::Pathgrid::Point>& getPath() const
{ {
return mPath; return mPath;
} }

View file

@ -34,6 +34,10 @@ namespace MWRender
virtual void rebuild(); virtual void rebuild();
private:
CharacterPreview(const CharacterPreview&);
CharacterPreview& operator=(const CharacterPreview&);
protected: protected:
virtual bool renderHeadOnly() { return false; } virtual bool renderHeadOnly() { return false; }

View file

@ -563,7 +563,8 @@ void RenderingManager::configureAmbient(MWWorld::CellStore &mCell)
Ogre::ColourValue colour; Ogre::ColourValue colour;
colour.setAsABGR (mCell.getCell()->mAmbi.mSunlight); colour.setAsABGR (mCell.getCell()->mAmbi.mSunlight);
mSun->setDiffuseColour (colour); mSun->setDiffuseColour (colour);
mSun->setDirection(0,-1,0); mSun->setDirection(1,-1,-1);
sunEnable(false);
} }
} }
// Switch through lighting modes. // Switch through lighting modes.

View file

@ -28,7 +28,9 @@ RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager)
mRippleAreaLength(1000), mRippleAreaLength(1000),
mImpulseSize(20), mImpulseSize(20),
mTexelOffset(0,0), mTexelOffset(0,0),
mFirstUpdate(true) mFirstUpdate(true),
mRectangle(NULL),
mImpulse(NULL)
{ {
Ogre::AxisAlignedBox aabInf; Ogre::AxisAlignedBox aabInf;
aabInf.setInfinite(); aabInf.setInfinite();
@ -105,6 +107,7 @@ RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager)
RippleSimulation::~RippleSimulation() RippleSimulation::~RippleSimulation()
{ {
delete mRectangle; delete mRectangle;
delete mImpulse;
Ogre::Root::getSingleton().destroySceneManager(mSceneMgr); Ogre::Root::getSingleton().destroySceneManager(mSceneMgr);
} }

View file

@ -201,7 +201,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
+MWBase::Environment::get().getWorld()->countSavedGameRecords() +MWBase::Environment::get().getWorld()->countSavedGameRecords()
+MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords() +MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords()
+MWBase::Environment::get().getDialogueManager()->countSavedGameRecords() +MWBase::Environment::get().getDialogueManager()->countSavedGameRecords()
+1; // global map +MWBase::Environment::get().getWindowManager()->countSavedGameRecords();
writer.setRecordCount (recordCount); writer.setRecordCount (recordCount);
writer.save (stream); writer.save (stream);
@ -235,8 +235,9 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
void MWState::StateManager::quickSave (std::string name) void MWState::StateManager::quickSave (std::string name)
{ {
if (mState!=State_Running || if (!(mState==State_Running &&
MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")!=-1) // char gen MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1 // char gen
&& MWBase::Environment::get().getWindowManager()->isSavingAllowed()))
{ {
//You can not save your game right now //You can not save your game right now
MWBase::Environment::get().getWindowManager()->messageBox("#{sSaveGameDenied}"); MWBase::Environment::get().getWindowManager()->messageBox("#{sSaveGameDenied}");
@ -323,7 +324,7 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl
break; break;
case ESM::REC_GMAP: case ESM::REC_GMAP:
case ESM::REC_KEYS:
MWBase::Environment::get().getWindowManager()->readRecord(reader, n.val); MWBase::Environment::get().getWindowManager()->readRecord(reader, n.val);
break; break;

View file

@ -231,6 +231,8 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr
{ {
CellStore *cell; CellStore *cell;
MWBase::Environment::get().getWorld()->getLocalScripts().add(script, item);
if(&(MWWorld::Class::get (player).getContainerStore (player)) == this) if(&(MWWorld::Class::get (player).getContainerStore (player)) == this)
{ {
cell = 0; // Items in player's inventory have cell set to 0, so their scripts will never be removed cell = 0; // Items in player's inventory have cell set to 0, so their scripts will never be removed
@ -243,7 +245,6 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr
item.mCell = cell; item.mCell = cell;
item.mContainerStore = 0; item.mContainerStore = 0;
MWBase::Environment::get().getWorld()->getLocalScripts().add(script, item);
} }
return it; return it;

View file

@ -227,10 +227,6 @@ namespace MWWorld
Ogre::Vector3 inertia(0.0f); Ogre::Vector3 inertia(0.0f);
Ogre::Vector3 velocity; Ogre::Vector3 velocity;
bool canWalk = ptr.getClass().canWalk(ptr);
bool isBipedal = ptr.getClass().isBipedal(ptr);
bool isNpc = ptr.getClass().isNpc();
if(position.z < waterlevel || isFlying) // under water by 3/4 or can fly if(position.z < waterlevel || isFlying) // under water by 3/4 or can fly
{ {
// TODO: Shouldn't water have higher drag in calculating velocity? // TODO: Shouldn't water have higher drag in calculating velocity?
@ -277,14 +273,11 @@ namespace MWWorld
// NOTE: velocity is either z axis only or x & z axis // NOTE: velocity is either z axis only or x & z axis
Ogre::Vector3 nextpos = newPosition + velocity * remainingTime; Ogre::Vector3 nextpos = newPosition + velocity * remainingTime;
// If not able to fly, walk or bipedal don't allow to move out of water // If not able to fly, don't allow to swim up into the air
// TODO: this if condition may not work for large creatures or situations // TODO: this if condition may not work for large creatures or situations
// where the creature gets above the waterline for some reason // where the creature gets above the waterline for some reason
if(newPosition.z < waterlevel && // started 3/4 under water if(newPosition.z < waterlevel && // started 3/4 under water
!isFlying && // can't fly !isFlying && // can't fly
!canWalk && // can't walk
!isBipedal && // not bipedal (assume bipedals can walk)
!isNpc && // FIXME: shouldn't really need this
nextpos.z > waterlevel && // but about to go above water nextpos.z > waterlevel && // but about to go above water
newPosition.z <= waterlevel) newPosition.z <= waterlevel)
{ {

View file

@ -37,7 +37,7 @@ namespace MWWorld
mTeleported(false), mTeleported(false),
mMarkedCell(NULL), mMarkedCell(NULL),
mCurrentCrimeId(-1), mCurrentCrimeId(-1),
mPayedCrimeId(-1) mPaidCrimeId(-1)
{ {
mPlayer.mBase = player; mPlayer.mBase = player;
mPlayer.mRef.mRefID = "player"; mPlayer.mRef.mRefID = "player";
@ -223,7 +223,7 @@ namespace MWWorld
player.mCellId = mCellStore->getCell()->getCellId(); player.mCellId = mCellStore->getCell()->getCellId();
player.mCurrentCrimeId = mCurrentCrimeId; player.mCurrentCrimeId = mCurrentCrimeId;
player.mPayedCrimeId = mPayedCrimeId; player.mPaidCrimeId = mPaidCrimeId;
player.mBirthsign = mSign; player.mBirthsign = mSign;
@ -273,7 +273,7 @@ namespace MWWorld
throw std::runtime_error ("invalid player state record (birthsign)"); throw std::runtime_error ("invalid player state record (birthsign)");
mCurrentCrimeId = player.mCurrentCrimeId; mCurrentCrimeId = player.mCurrentCrimeId;
mPayedCrimeId = player.mPayedCrimeId; mPaidCrimeId = player.mPaidCrimeId;
mSign = player.mBirthsign; mSign = player.mBirthsign;
@ -318,11 +318,11 @@ namespace MWWorld
void Player::recordCrimeId() void Player::recordCrimeId()
{ {
mPayedCrimeId = mCurrentCrimeId; mPaidCrimeId = mCurrentCrimeId;
} }
int Player::getCrimeId() const int Player::getCrimeId() const
{ {
return mPayedCrimeId; return mPaidCrimeId;
} }
} }

View file

@ -48,7 +48,7 @@ namespace MWWorld
bool mTeleported; bool mTeleported;
int mCurrentCrimeId; // the id assigned witnesses int mCurrentCrimeId; // the id assigned witnesses
int mPayedCrimeId; // the last id payed off (0 bounty) int mPaidCrimeId; // the last id paid off (0 bounty)
public: public:
@ -105,8 +105,8 @@ namespace MWWorld
bool readRecord (ESM::ESMReader& reader, int32_t type); bool readRecord (ESM::ESMReader& reader, int32_t type);
int getNewCrimeId(); // get new id for witnesses int getNewCrimeId(); // get new id for witnesses
void recordCrimeId(); // record the payed crime id when bounty is 0 void recordCrimeId(); // record the paid crime id when bounty is 0
int getCrimeId() const; // get the last payed crime id int getCrimeId() const; // get the last paid crime id
}; };
} }
#endif #endif

View file

@ -329,7 +329,6 @@ void WeatherManager::update(float duration)
const bool exterior = (world->isCellExterior() || world->isCellQuasiExterior()); const bool exterior = (world->isCellExterior() || world->isCellQuasiExterior());
if (!exterior) if (!exterior)
{ {
mRendering->sunDisable(false);
mRendering->skyDisable(); mRendering->skyDisable();
mRendering->getSkyManager()->setLightningStrength(0.f); mRendering->getSkyManager()->setLightningStrength(0.f);
stopSounds(true); stopSounds(true);

View file

@ -45,7 +45,7 @@ add_component_dir (esm
loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat
loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter
savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate npcstate creaturestate dialoguestate statstate savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate npcstate creaturestate dialoguestate statstate
npcstats creaturestats weatherstate npcstats creaturestats weatherstate quickkeys
) )
add_component_dir (misc add_component_dir (misc

View file

@ -34,6 +34,12 @@ struct Position
}; };
#pragma pack(pop) #pragma pack(pop)
template <int a, int b, int c, int d>
struct FourCC
{
static const unsigned int value = (((((d << 8) | c) << 8) | b) << 8) | a;
};
enum RecNameInts enum RecNameInts
{ {
// format 0 / legacy // format 0 / legacy
@ -93,6 +99,7 @@ enum RecNameInts
REC_GMAP = 0x50414d47, REC_GMAP = 0x50414d47,
REC_DIAS = 0x53414944, REC_DIAS = 0x53414944,
REC_WTHR = 0x52485457, REC_WTHR = 0x52485457,
REC_KEYS = FourCC<'K','E','Y','S'>::value,
// format 1 // format 1
REC_FILT = 0x544C4946 REC_FILT = 0x544C4946

View file

@ -33,7 +33,7 @@ struct Creature
Respawn = 0x002, Respawn = 0x002,
Weapon = 0x004, // Has weapon and shield Weapon = 0x004, // Has weapon and shield
None = 0x008, // ?? None = 0x008, // ?? This flag appears set for every creature in Morrowind.esm
Essential = 0x080, Essential = 0x080,
// Blood types // Blood types

View file

@ -28,8 +28,8 @@ void ESM::Player::load (ESMReader &esm)
mCurrentCrimeId = -1; mCurrentCrimeId = -1;
esm.getHNOT (mCurrentCrimeId, "CURD"); esm.getHNOT (mCurrentCrimeId, "CURD");
mPayedCrimeId = -1; mPaidCrimeId = -1;
esm.getHNOT (mPayedCrimeId, "PAYD"); esm.getHNOT (mPaidCrimeId, "PAYD");
} }
void ESM::Player::save (ESMWriter &esm) const void ESM::Player::save (ESMWriter &esm) const
@ -52,5 +52,5 @@ void ESM::Player::save (ESMWriter &esm) const
esm.writeHNString ("SIGN", mBirthsign); esm.writeHNString ("SIGN", mBirthsign);
esm.writeHNT ("CURD", mCurrentCrimeId); esm.writeHNT ("CURD", mCurrentCrimeId);
esm.writeHNT ("PAYD", mPayedCrimeId); esm.writeHNT ("PAYD", mPaidCrimeId);
} }

View file

@ -26,11 +26,11 @@ namespace ESM
std::string mBirthsign; std::string mBirthsign;
int mCurrentCrimeId; int mCurrentCrimeId;
int mPayedCrimeId; int mPaidCrimeId;
void load (ESMReader &esm); void load (ESMReader &esm);
void save (ESMWriter &esm) const; void save (ESMWriter &esm) const;
}; };
} }
#endif #endif

View file

@ -0,0 +1,43 @@
#include "quickkeys.hpp"
#include "esmwriter.hpp"
#include "esmreader.hpp"
namespace ESM
{
void QuickKeys::load(ESMReader &esm)
{
while (esm.isNextSub("KEY_"))
{
esm.getSubHeader();
int keyType;
esm.getHNT(keyType, "TYPE");
std::string id;
id = esm.getHNString("ID__");
QuickKey key;
key.mType = keyType;
key.mId = id;
mKeys.push_back(key);
}
}
void QuickKeys::save(ESMWriter &esm) const
{
const std::string recKey = "KEY_";
for (std::vector<QuickKey>::const_iterator it = mKeys.begin(); it != mKeys.end(); ++it)
{
esm.startSubRecord(recKey);
esm.writeHNT("TYPE", it->mType);
esm.writeHNString("ID__", it->mId);
esm.endRecord(recKey);
}
}
}

View file

@ -0,0 +1,28 @@
#ifndef OPENMW_COMPONENTS_ESM_QUICKKEYS_H
#define OPENMW_COMPONENTS_ESM_QUICKKEYS_H
#include <vector>
#include <string>
namespace ESM
{
class ESMReader;
class ESMWriter;
struct QuickKeys
{
struct QuickKey
{
int mType;
std::string mId; // Spell or Item ID
};
std::vector<QuickKey> mKeys;
void load (ESMReader &esm);
void save (ESMWriter &esm) const;
};
}
#endif

View file

@ -62,6 +62,7 @@ namespace OgreInit
OgreInit::~OgreInit() OgreInit::~OgreInit()
{ {
delete mRoot; delete mRoot;
delete Ogre::LogManager::getSingletonPtr();
std::vector<Ogre::ParticleEmitterFactory*>::iterator ei; std::vector<Ogre::ParticleEmitterFactory*>::iterator ei;
for(ei = mEmitterFactories.begin();ei != mEmitterFactories.end();++ei) for(ei = mEmitterFactories.begin();ei != mEmitterFactories.end();++ei)

View file

@ -337,6 +337,8 @@ namespace Terrain
it->mTarget->loadLayers(*it); it->mTarget->loadLayers(*it);
} }
delete data;
mRootNode->loadMaterials(); mRootNode->loadMaterials();
mLayerLoadPending = false; mLayerLoadPending = false;

View file

@ -115,7 +115,7 @@ namespace SFO
mWindowListener->windowClosed(); mWindowListener->windowClosed();
break; break;
default: default:
std::cerr << "Unhandled SDL event of type " << evt.type << std::endl; std::cerr << "Unhandled SDL event of type 0x" << std::hex << evt.type << std::endl;
break; break;
} }
} }
@ -241,8 +241,8 @@ namespace SFO
//eep, wrap the pointer manually if the input driver doesn't support //eep, wrap the pointer manually if the input driver doesn't support
//relative positioning natively //relative positioning natively
int success = SDL_SetRelativeMouseMode(relative ? SDL_TRUE : SDL_FALSE); bool success = SDL_SetRelativeMouseMode(relative ? SDL_TRUE : SDL_FALSE) == 0;
if(relative && success != 0) if(relative && !success)
mWrapPointer = true; mWrapPointer = true;
//now remove all mouse events using the old setting from the queue //now remove all mouse events using the old setting from the queue

View file

@ -49,22 +49,6 @@
<BasisSkin type="SimpleText" offset="0 0 16 16" align="Stretch"/> <BasisSkin type="SimpleText" offset="0 0 16 16" align="Stretch"/>
</Skin> </Skin>
<Skin name="DaedricText" size="16 16">
<Property key="FontName" value="daedric36"/>
<Property key="FontHeight" value="36"/>
<Property key="TextAlign" value="Default"/>
<Property key="TextColour" value="1 1 1"/>
<BasisSkin type="SimpleText" offset="0 0 16 16" align="Stretch"/>
</Skin>
<Skin name="DaedricText_orig" size="16 16">
<Property key="FontName" value="daedric_orig36"/>
<Property key="FontHeight" value="36"/>
<Property key="TextAlign" value="Default"/>
<Property key="TextColour" value="1 1 1"/>
<BasisSkin type="SimpleText" offset="0 0 16 16" align="Stretch"/>
</Skin>
<Skin name="MW_StatNameC" size="200 18"> <Skin name="MW_StatNameC" size="200 18">
<Child type="TextBoxC" skin="SandText" offset="0 0 200 18" align="Left HStretch" name="StatName"/> <Child type="TextBoxC" skin="SandText" offset="0 0 200 18" align="Left HStretch" name="StatName"/>
</Skin> </Skin>

View file

@ -133,9 +133,9 @@ distant land = false
shader = true shader = true
[Water] [Water]
shader = true shader = false
refraction = true refraction = false
rtt size = 512 rtt size = 512
reflect terrain = true reflect terrain = true