Merge remote-tracking branch 'scrawl/master'

pull/472/head
Marc Zinnschlag 10 years ago
commit 6c4920c58e

@ -1,7 +1,7 @@
OpenMW
======
[![Build Status](https://img.shields.io/travis/OpenMW/openmw.svg)](https://travis-ci.org/OpenMW/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740)
[![Build Status](https://img.shields.io/travis/OpenMW/openmw.svg?style=plastic)](https://travis-ci.org/OpenMW/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740)
OpenMW is an attempt at recreating the engine for the popular role-playing game
Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work.
@ -68,7 +68,10 @@ Command line options
of the blacklist is enabled)
--script-blacklist-use [=arg(=1)] (=1)
enable script blacklisting
--load-savegame arg load a save game file on game startup
--load-savegame arg load a save game file on game startup
(specify an absolute filename or a
filename relative to the current
working directory)
--skip-menu [=arg(=1)] (=0) skip main menu on game startup
--new-game [=arg(=1)] (=0) run new game sequence (ignored if
skip-menu=0)

@ -535,10 +535,10 @@ void Record<ESM::Class>::print()
std::cout << " Specialization: " << specializationLabel(mData.mData.mSpecialization)
<< " (" << mData.mData.mSpecialization << ")" << std::endl;
for (int i = 0; i != 5; i++)
std::cout << " Major Skill: " << skillLabel(mData.mData.mSkills[i][0])
std::cout << " Minor Skill: " << skillLabel(mData.mData.mSkills[i][0])
<< " (" << mData.mData.mSkills[i][0] << ")" << std::endl;
for (int i = 0; i != 5; i++)
std::cout << " Minor Skill: " << skillLabel(mData.mData.mSkills[i][1])
std::cout << " Major Skill: " << skillLabel(mData.mData.mSkills[i][1])
<< " (" << mData.mData.mSkills[i][1] << ")" << std::endl;
}
@ -837,7 +837,7 @@ void Record<ESM::CreatureLevList>::print()
std::cout << " Chance for None: " << (int)mData.mChanceNone << std::endl;
std::cout << " Flags: " << creatureListFlags(mData.mFlags) << std::endl;
std::cout << " Number of items: " << mData.mList.size() << std::endl;
std::vector<ESM::LeveledListBase::LevelItem>::iterator iit;
std::vector<ESM::LevelledListBase::LevelItem>::iterator iit;
for (iit = mData.mList.begin(); iit != mData.mList.end(); ++iit)
std::cout << " Creature: Level: " << iit->mLevel
<< " Creature: " << iit->mId << std::endl;
@ -849,7 +849,7 @@ void Record<ESM::ItemLevList>::print()
std::cout << " Chance for None: " << (int)mData.mChanceNone << std::endl;
std::cout << " Flags: " << itemListFlags(mData.mFlags) << std::endl;
std::cout << " Number of items: " << mData.mList.size() << std::endl;
std::vector<ESM::LeveledListBase::LevelItem>::iterator iit;
std::vector<ESM::LevelledListBase::LevelItem>::iterator iit;
for (iit = mData.mList.begin(); iit != mData.mList.end(); ++iit)
std::cout << " Inventory: Level: " << iit->mLevel
<< " Item: " << iit->mId << std::endl;

@ -18,6 +18,7 @@
#include <components/esm/weatherstate.hpp>
#include <components/esm/globalscript.hpp>
#include <components/esm/queststate.hpp>
#include <components/esm/stolenitems.hpp>
#include "importcrec.hpp"
#include "importcntc.hpp"
@ -387,24 +388,50 @@ public:
virtual void read(ESM::ESMReader &esm)
{
std::string itemid = esm.getHNString("NAME");
Misc::StringUtils::toLower(itemid);
while (esm.isNextSub("FNAM") || esm.isNextSub("ONAM"))
{
if (esm.retSubName().toString() == "FNAM")
{
std::string factionid = esm.getHString();
mFactionStolenItems.insert(std::make_pair(itemid, factionid));
mStolenItems[itemid].insert(std::make_pair(Misc::StringUtils::lowerCase(factionid), true));
}
else
{
std::string ownerid = esm.getHString();
mStolenItems.insert(std::make_pair(itemid, ownerid));
mStolenItems[itemid].insert(std::make_pair(Misc::StringUtils::lowerCase(ownerid), false));
}
}
}
virtual void write(ESM::ESMWriter &esm)
{
ESM::StolenItems items;
for (std::map<std::string, std::set<Owner> >::const_iterator it = mStolenItems.begin(); it != mStolenItems.end(); ++it)
{
std::map<std::pair<std::string, bool>, int> owners;
for (std::set<Owner>::const_iterator ownerIt = it->second.begin(); ownerIt != it->second.end(); ++ownerIt)
{
owners.insert(std::make_pair(std::make_pair(ownerIt->first, ownerIt->second)
// Since OpenMW doesn't suffer from the owner contamination bug,
// it needs a count argument. But for legacy savegames, we don't know
// this count, so must assume all items of that ID are stolen,
// like vanilla MW did.
,std::numeric_limits<int>::max()));
}
items.mStolenItems.insert(std::make_pair(it->first, owners));
}
esm.startRecord(ESM::REC_STLN);
items.write(esm);
esm.endRecord(ESM::REC_STLN);
}
private:
std::multimap<std::string, std::string> mStolenItems;
std::multimap<std::string, std::string> mFactionStolenItems;
typedef std::pair<std::string, bool> Owner; // <owner id, bool isFaction>
std::map<std::string, std::set<Owner> > mStolenItems;
};
/// Seen responses for a dialogue topic?

@ -17,6 +17,8 @@ namespace ESSImport
}
for (int i=0; i<8; ++i)
out.mObject.mNpcStats.mSkillIncrease[i] = pcdt.mPNAM.mSkillIncreases[i];
for (int i=0; i<27; ++i)
out.mObject.mNpcStats.mSkills[i].mRegular.mProgress = pcdt.mPNAM.mSkillProgress[i];
out.mObject.mNpcStats.mLevelProgress = pcdt.mPNAM.mLevelProgress;
if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Weapon)
@ -24,9 +26,6 @@ namespace ESSImport
if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Spell)
out.mObject.mCreatureStats.mDrawState = 2;
// TODO: convert PNAM.mSkillProgress, needs to be converted to uniform scale
// (or change openmw to accept non-uniform skill progress)
firstPersonCam = (pcdt.mPNAM.mCameraState == PCDT::CameraState_FirstPerson);
for (std::vector<std::string>::const_iterator it = pcdt.mKnownDialogueTopics.begin();

@ -61,7 +61,7 @@ namespace ESSImport
bool mHasACSC;
ACSC mACSC;
int mSkills[27][2];
int mSkills[27][2]; // skills, base and modified
// creature combat stats, base and modified
// I think these can be ignored in the conversion, because it is not possible

@ -22,7 +22,7 @@ namespace ESSImport
ActorData::load(esm);
if (esm.isNextSub("LVCR"))
{
// occurs on leveled creature spawner references
// occurs on levelled creature spawner references
// probably some identifier for the creature that has been spawned?
unsigned char lvcr;
esm.getHT(lvcr);
@ -32,7 +32,7 @@ namespace ESSImport
mEnabled = true;
esm.getHNOT(mEnabled, "ZNAM");
// DATA should occur for all references, except leveled creature spawners
// DATA should occur for all references, except levelled creature spawners
// I've seen DATA *twice* on a creature record, and with the exact same content too! weird
// alarmvoi0000.ess
esm.getHNOT(mPos, "DATA", 24);

@ -10,7 +10,7 @@
#define MAC_OS_X_VERSION_MIN_REQUIRED __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
#endif // MAC_OS_X_VERSION_MIN_REQUIRED
#include <SDL.h>
#include <SDL_video.h>
#include <OgreRoot.h>
#include <OgreRenderSystem.h>

@ -1,4 +1,5 @@
#include <iostream>
#include <csignal>
#include <QApplication>
#include <QTextCodec>
@ -26,6 +27,8 @@ int main(int argc, char *argv[])
qDebug() << "SDL_Init failed: " << QString::fromStdString(SDL_GetError());
return 0;
}
signal(SIGINT, SIG_DFL); // We don't want to use the SDL event loop in the launcher,
// so reset SIGINT which SDL wants to redirect to an SDL_Quit event.
QApplication app(argc, argv);

@ -170,7 +170,6 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
: mOgre (0)
, mFpsLevel(0)
, mVerboseScripts (false)
, mSkipMenu (false)
, mUseSound (true)
@ -292,16 +291,10 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings)
else
throw std::runtime_error ("No default settings file found! Make sure the file \"settings-default.cfg\" was properly installed.");
// load user settings if they exist, otherwise just load the default settings as user settings
// load user settings if they exist
const std::string settingspath = mCfgMgr.getUserConfigPath().string() + "/settings.cfg";
if (boost::filesystem::exists(settingspath))
settings.loadUser(settingspath);
else if (boost::filesystem::exists(localdefault))
settings.loadUser(localdefault);
else if (boost::filesystem::exists(globaldefault))
settings.loadUser(globaldefault);
mFpsLevel = settings.getInt("fps", "HUD");
// load nif overrides
NifOverrides::Overrides nifOverrides;
@ -377,7 +370,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
mEnvironment.setInputManager (input);
MWGui::WindowManager* window = new MWGui::WindowManager(
mExtensions, mFpsLevel, mOgre, mCfgMgr.getLogPath().string() + std::string("/"),
mExtensions, mOgre, mCfgMgr.getLogPath().string() + std::string("/"),
mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap);
mEnvironment.setWindowManager (window);
@ -578,11 +571,6 @@ void OMW::Engine::setSoundUsage(bool soundUsage)
mUseSound = soundUsage;
}
void OMW::Engine::showFPS(int level)
{
mFpsLevel = level;
}
void OMW::Engine::setEncoding(const ToUTF8::FromType& encoding)
{
mEncoding = encoding;

@ -71,7 +71,6 @@ namespace OMW
OEngine::Render::OgreRenderer *mOgre;
std::string mCellName;
std::vector<std::string> mContentFiles;
int mFpsLevel;
bool mVerboseScripts;
bool mSkipMenu;
bool mUseSound;
@ -151,9 +150,6 @@ namespace OMW
*/
void addContentFile(const std::string& file);
/// Enable fps counter
void showFPS(int level);
/// Enable or disable verbose script output
void setScriptsVerbosity(bool scriptsVerbosity);

@ -153,7 +153,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
->default_value(true), "enable script blacklisting")
("load-savegame", bpo::value<std::string>()->default_value(""),
"load a save game file on game startup")
"load a save game file on game startup (specify an absolute filename or a filename relative to the current working directory)")
("skip-menu", bpo::value<bool>()->implicit_value(true)
->default_value(false), "skip main menu on game startup")

@ -1,5 +1,5 @@
#ifndef GAME_BASE_INVIRONMENT_H
#define GAME_BASE_INVIRONMENT_H
#ifndef GAME_BASE_ENVIRONMENT_H
#define GAME_BASE_ENVIRONMENT_H
namespace MWBase
{

@ -2,8 +2,8 @@
#define GAME_MWBASE_INPUTMANAGER_H
#include <string>
#include <components/settings/settings.hpp>
#include <set>
#include <vector>
namespace MWBase
{
@ -29,7 +29,7 @@ namespace MWBase
virtual void changeInputMode(bool guiMode) = 0;
virtual void processChangedSettings(const Settings::CategorySettingVector& changed) = 0;
virtual void processChangedSettings(const std::set< std::pair<std::string, std::string> >& changed) = 0;
virtual void setDragDrop(bool dragDrop) = 0;

@ -129,16 +129,15 @@ namespace MWBase
/// @return false if the attack was considered a "friendly hit" and forgiven
virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0;
/// Utility to check if taking this item is illegal and calling commitCrime if so
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, int count) = 0;
/// @param container The container the item is in; may be empty for an item in the world
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container,
int count) = 0;
/// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so
virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item) = 0;
/// Attempt sleeping in a bed. If this is illegal, call commitCrime.
/// @return was it illegal, and someone saw you doing it?
virtual bool sleepInBed (const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed) = 0;
/// @return is \a ptr allowed to take/use \a item or is it a crime?
virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, MWWorld::Ptr& victim) = 0;
enum PersuasionType
{
PT_Admire,
@ -203,6 +202,15 @@ namespace MWBase
virtual void keepPlayerAlive() = 0;
virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const = 0;
virtual void confiscateStolenItems (const MWWorld::Ptr& player, const MWWorld::Ptr& targetContainer) = 0;
/// List the owners that the player has stolen this item from (the owner can be an NPC or a faction).
/// <Owner, item count>
virtual std::vector<std::pair<std::string, int> > getStolenItemOwners(const std::string& itemid) = 0;
/// Has the player stolen this item from the given owner?
virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid) = 0;
};
}

@ -2,11 +2,9 @@
#define GAME_MWBASE_SOUNDMANAGER_H
#include <string>
#include <set>
#include <boost/shared_ptr.hpp>
#include <components/settings/settings.hpp>
#include "../mwworld/ptr.hpp"
namespace Ogre
@ -74,7 +72,7 @@ namespace MWBase
virtual ~SoundManager() {}
virtual void processChangedSettings(const Settings::CategorySettingVector& settings) = 0;
virtual void processChangedSettings(const std::set< std::pair<std::string, std::string> >& settings) = 0;
virtual void stopMusic() = 0;
///< Stops music if it's playing

@ -5,16 +5,20 @@
#include <vector>
#include <map>
#include <components/settings/settings.hpp>
#include <components/translation/translation.hpp>
#include <components/loadinglistener/loadinglistener.hpp>
#include "../mwmechanics/stat.hpp"
#include "../mwgui/mode.hpp"
namespace Loading
{
class Listener;
}
namespace Translation
{
class Storage;
}
namespace MyGUI
{
class Gui;
@ -267,7 +271,7 @@ namespace MWBase
*/
virtual std::string getGameSettingString(const std::string &id, const std::string &default_) = 0;
virtual void processChangedSettings(const Settings::CategorySettingVector& changed) = 0;
virtual void processChangedSettings(const std::set< std::pair<std::string, std::string> >& changed) = 0;
virtual void windowResized(int x, int y) = 0;

@ -3,26 +3,23 @@
#include <vector>
#include <map>
#include <components/settings/settings.hpp>
#include <set>
#include <components/esm/cellid.hpp>
#include "../mwworld/globals.hpp"
#include "../mwworld/ptr.hpp"
namespace Ogre
{
class Vector2;
class Vector3;
class Quaternion;
class Image;
}
namespace OEngine
namespace Loading
{
namespace Physic
{
class PhysicEngine;
}
class Listener;
}
namespace ESM
@ -390,7 +387,7 @@ namespace MWBase
virtual bool canPlaceObject (float cursorX, float cursorY) = 0;
///< @return true if it is possible to place on object at specified cursor location
virtual void processChangedSettings (const Settings::CategorySettingVector& settings) = 0;
virtual void processChangedSettings (const std::set< std::pair<std::string, std::string> >& settings) = 0;
virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0;
virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const = 0;

@ -59,8 +59,10 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Container> *ref =
ptr.get<ESM::Container>();
// setting ownership not needed, since taking items from a container inherits the
// container's owner automatically
data->mContainerStore.fill(
ref->mBase->mInventory, ptr.getCellRef().getOwner(), ptr.getCellRef().getFaction(), ptr.getCellRef().getFactionRank(), MWBase::Environment::get().getWorld()->getStore());
ref->mBase->mInventory, "");
// store
ptr.getRefData().setCustomData (data.release());
@ -82,7 +84,10 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Container> *ref = ptr.get<ESM::Container>();
const ESM::InventoryList& list = ref->mBase->mInventory;
MWWorld::ContainerStore& store = getContainerStore(ptr);
store.restock(list, ptr, ptr.getCellRef().getOwner(), ptr.getCellRef().getFaction(), ptr.getCellRef().getFactionRank());
// setting ownership not needed, since taking items from a container inherits the
// container's owner automatically
store.restock(list, ptr, "");
}
void Container::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const

@ -139,8 +139,7 @@ namespace MWClass
// store
ptr.getRefData().setCustomData(data.release());
getContainerStore(ptr).fill(ref->mBase->mInventory, getId(ptr), "", -1,
MWBase::Environment::get().getWorld()->getStore());
getContainerStore(ptr).fill(ref->mBase->mInventory, getId(ptr));
if (ref->mBase->mFlags & ESM::Creature::Weapon)
getInventoryStore(ptr).autoEquip(ptr);
@ -886,7 +885,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
const ESM::InventoryList& list = ref->mBase->mInventory;
MWWorld::ContainerStore& store = getContainerStore(ptr);
store.restock(list, ptr, ptr.getCellRef().getRefId(), "", -1);
store.restock(list, ptr, ptr.getCellRef().getRefId());
}
int Creature::getBaseFightRating(const MWWorld::Ptr &ptr) const

@ -384,8 +384,8 @@ namespace MWClass
}
// inventory
data->mInventoryStore.fill(ref->mBase->mInventory, getId(ptr), "", -1,
MWBase::Environment::get().getWorld()->getStore());
// setting ownership is used to make the NPC auto-equip his initial equipment only, and not bartered items
data->mInventoryStore.fill(ref->mBase->mInventory, getId(ptr));
data->mNpcStats.setGoldPool(gold);
@ -1328,7 +1328,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::NPC> *ref = ptr.get<ESM::NPC>();
const ESM::InventoryList& list = ref->mBase->mInventory;
MWWorld::ContainerStore& store = getContainerStore(ptr);
store.restock(list, ptr, ptr.getCellRef().getRefId(), "", -1);
store.restock(list, ptr, ptr.getCellRef().getRefId());
}
int Npc::getBaseFightRating (const MWWorld::Ptr& ptr) const

@ -1,5 +1,7 @@
#include "scripttest.hpp"
#include <iostream>
#include "../mwworld/manualref.hpp"
#include "../mwworld/class.hpp"

@ -285,7 +285,7 @@ namespace MWGui
if (mPtr.getClass().isActor() && mPtr.getClass().getCreatureStats(mPtr).isDead())
return true;
else
MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item.mBase, count);
MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item.mBase, mPtr, count);
}
return true;
}

@ -339,7 +339,8 @@ namespace MWGui
for (int i=0; i<2; ++i)
{
MWWorld::Ptr item = (i == 0) ? mEnchanting.getOldItem() : mEnchanting.getGem();
if (Misc::StringUtils::ciEqual(item.getCellRef().getOwner(), mPtr.getCellRef().getRefId()))
if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(item.getCellRef().getRefId(),
mPtr.getCellRef().getRefId()))
{
std::string msg = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sNotifyMessage49")->getString();
if (msg.find("%s") != std::string::npos)

@ -10,6 +10,7 @@
#include <MyGUI_ScrollView.h>
#include <components/misc/resourcehelpers.hpp>
#include <components/settings/settings.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/soundmanager.hpp"

@ -65,16 +65,7 @@ MWWorld::Ptr InventoryItemModel::moveItem(const ItemStack &item, size_t count, I
if (item.mFlags & ItemStack::Flag_Bound)
return MWWorld::Ptr();
bool setNewOwner = false;
// Are you dead? Then you wont need that anymore
if (mActor.getClass().isActor() && mActor.getClass().getCreatureStats(mActor).isDead()
// Make sure that the item is actually owned by the dead actor
// Prevents a potential exploit for resetting the owner of any item, by placing the item in a corpse
&& Misc::StringUtils::ciEqual(item.mBase.getCellRef().getOwner(), mActor.getCellRef().getRefId()))
setNewOwner = true;
MWWorld::Ptr ret = otherModel->copyItem(item, count, setNewOwner);
MWWorld::Ptr ret = otherModel->copyItem(item, count, false);
removeItem(item, count);
return ret;
}

@ -8,6 +8,8 @@
#include <MyGUI_InputManager.h>
#include <MyGUI_Button.h>
#include <components/settings/settings.hpp>
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/soundmanager.hpp"
@ -622,7 +624,7 @@ namespace MWGui
throw std::runtime_error("Added item not found");
mDragAndDrop->startDrag(i, mSortModel, mTradeModel, mItemView, count);
MWBase::Environment::get().getMechanicsManager()->itemTaken(player, newObject, count);
MWBase::Environment::get().getMechanicsManager()->itemTaken(player, newObject, MWWorld::Ptr(), count);
if (MWBase::Environment::get().getWindowManager()->getSpellWindow())
MWBase::Environment::get().getWindowManager()->getSpellWindow()->updateSpells();

@ -1,5 +1,7 @@
#include "itemmodel.hpp"
#include <set>
#include "../mwworld/class.hpp"
#include "../mwworld/containerstore.hpp"
#include "../mwworld/store.hpp"

@ -46,20 +46,27 @@ namespace MWGui
ItemModel();
virtual ~ItemModel() {}
typedef int ModelIndex;
typedef int ModelIndex; // -1 means invalid index
/// Throws for invalid index or out of range index
virtual ItemStack getItem (ModelIndex index) = 0;
///< throws for invalid index
/// The number of items in the model, this specifies the range of indices you can pass to
/// the getItem function (but this range is only valid until the next call to update())
virtual size_t getItemCount() = 0;
/// Returns an invalid index if the item was not found
virtual ModelIndex getIndex (ItemStack item) = 0;
/// Rebuild the item model, this will invalidate existing model indices
virtual void update() = 0;
/// Move items from this model to \a otherModel.
/// @note Derived implementations may return an empty Ptr if the move was unsuccessful.
virtual MWWorld::Ptr moveItem (const ItemStack& item, size_t count, ItemModel* otherModel);
/// @param setNewOwner Set the copied item's owner to the actor we are copying to, or keep the original owner?
/// @param setNewOwner If true, set the copied item's owner to the actor we are copying to,
/// otherwise reset owner to ""
virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false) = 0;
virtual void removeItem (const ItemStack& item, size_t count) = 0;

@ -8,6 +8,8 @@
#include <components/misc/utf8stream.hpp>
#include <components/translation/translation.hpp>
#include "../mwbase/world.hpp"
#include "../mwbase/journal.hpp"
#include "../mwbase/environment.hpp"

@ -139,7 +139,6 @@ namespace MWGui
if(world->getStore().get<ESM::Class>().isDynamic(cls->mId))
{
// Vanilla uses thief.dds for custom classes.
// Choosing Stealth specialization and Speed/Agility as attributes, if possible. Otherwise fall back to first class found.
MWWorld::SharedIterator<ESM::Class> it = world->getStore().get<ESM::Class>().begin();
for(; it != world->getStore().get<ESM::Class>().end(); ++it)
@ -173,14 +172,17 @@ namespace MWGui
if (pcStats.getAttribute(i).getBase() < 100)
{
mAttributes[i]->setEnabled(true);
mAttributeValues[i]->setEnabled(true);
availableAttributes++;
int mult = pcStats.getLevelupAttributeMultiplier (i);
mult = std::min(mult, 100-pcStats.getAttribute(i).getBase());
text->setCaption(mult <= 1 ? "" : "x" + MyGUI::utility::toString(mult));
}
else
{
mAttributes[i]->setEnabled(false);
mAttributeValues[i]->setEnabled(false);
text->setCaption("");
}

@ -15,6 +15,8 @@
#include <MyGUI_Gui.h>
#include <MyGUI_TextBox.h>
#include <components/settings/settings.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/statemanager.hpp"

@ -9,6 +9,7 @@
#include <components/version/version.hpp>
#include <components/widgets/imagebutton.hpp>
#include <components/settings/settings.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp"

@ -13,6 +13,7 @@
#include <MyGUI_FactoryManager.h>
#include <components/esm/globalmap.hpp>
#include <components/settings/settings.hpp>
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp"

@ -15,6 +15,7 @@
#include <SDL_video.h>
#include <components/widgets/sharedstatebutton.hpp>
#include <components/settings/settings.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"

@ -376,18 +376,26 @@ namespace MWGui
for (SkillList::const_iterator it = skills.begin(); it != end; ++it)
{
int skillId = *it;
if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes
if (skillId < 0 || skillId >= ESM::Skill::Length) // Skip unknown skill indexes
continue;
assert(skillId >= 0 && skillId < ESM::Skill::Length);
const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId];
const MWMechanics::SkillValue &stat = mSkillValues.find(skillId)->second;
int base = stat.getBase();
int modified = stat.getModified();
int progressPercent = stat.getProgress() * 100;
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
const MWWorld::ESMStore &esmStore =
MWBase::Environment::get().getWorld()->getStore();
float progressRequirement = player.getClass().getNpcStats(player).getSkillProgressRequirement(skillId,
*esmStore.get<ESM::Class>().find(player.get<ESM::NPC>()->mBase->mClass));
// This is how vanilla MW displays the progress bar (I think). Note it's slightly inaccurate,
// due to the int casting in the skill levelup logic. Also the progress label could in rare cases
// reach 100% without the skill levelling up.
// Leaving the original display logic for now, for consistency with ess-imported savegames.
int progressPercent = int(float(stat.getProgress()) / float(progressRequirement) * 100.f + 0.5f);
const ESM::Skill* skill = esmStore.get<ESM::Skill>().find(skillId);
std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId];

@ -8,10 +8,12 @@
#include <MyGUI_ImageBox.h>
#include <components/misc/resourcehelpers.hpp>
#include <components/settings/settings.hpp>
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/esmstore.hpp"
@ -585,6 +587,15 @@ namespace MWGui
ret += getMiscString(cellref.getFaction(), "Faction");
if (cellref.getFactionRank() > 0)
ret += getValueString(cellref.getFactionRank(), "Rank");
std::vector<std::pair<std::string, int> > itemOwners =
MWBase::Environment::get().getMechanicsManager()->getStolenItemOwners(cellref.getRefId());
for (std::vector<std::pair<std::string, int> >::const_iterator it = itemOwners.begin(); it != itemOwners.end(); ++it)
{
ret += std::string("\nStolen from ") + it->first;
}
ret += getMiscString(cellref.getGlobalVariable(), "Global");
return ret;
}

@ -135,11 +135,9 @@ namespace MWGui
if (i == sourceModel->getItemCount())
throw std::runtime_error("The borrowed item disappeared");
// reset owner while copying, but only for items bought by the player
bool setNewOwner = (mMerchant.isEmpty());
const ItemStack& item = sourceModel->getItem(i);
// copy the borrowed items to our model
copyItem(item, it->mCount, setNewOwner);
copyItem(item, it->mCount);
// then remove them from the source model
sourceModel->removeItem(item, it->mCount);
}

@ -300,7 +300,8 @@ namespace MWGui
// check if the player is attempting to sell back an item stolen from this actor
for (std::vector<ItemStack>::iterator it = merchantBought.begin(); it != merchantBought.end(); ++it)
{
if (Misc::StringUtils::ciEqual(it->mBase.getCellRef().getOwner(), mPtr.getCellRef().getRefId()))
if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(it->mBase.getCellRef().getRefId(),
mPtr.getCellRef().getRefId()))
{
std::string msg = gmst.find("sNotifyMessage49")->getString();
if (msg.find("%s") != std::string::npos)
@ -315,6 +316,8 @@ namespace MWGui
}
}
// TODO: move to mwmechanics
// Is the player buying?
bool buying = (mCurrentMerchantOffer < 0);

@ -3,6 +3,7 @@
#include <MyGUI_ProgressBar.h>
#include <components/widgets/box.hpp>
#include <components/settings/settings.hpp>
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp"

@ -2,6 +2,8 @@
#include <MyGUI_InputManager.h>
#include <components/settings/settings.hpp>
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/environment.hpp"

@ -19,6 +19,9 @@
#include <MyGUI_ClipboardManager.h>
#include <MyGUI_RenderManager.h>
#include <SDL_keyboard.h>
#include <SDL_clipboard.h>
#include <openengine/ogre/renderer.hpp>
#include <openengine/gui/manager.hpp>
@ -26,6 +29,8 @@
#include <components/fontloader/fontloader.hpp>
#include <components/translation/translation.hpp>
#include <components/widgets/widgets.hpp>
#include <components/widgets/tags.hpp>
@ -91,7 +96,7 @@ namespace MWGui
{
WindowManager::WindowManager(
const Compiler::Extensions& extensions, int fpsLevel, OEngine::Render::OgreRenderer *ogre,
const Compiler::Extensions& extensions, OEngine::Render::OgreRenderer *ogre,
const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts,
Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map<std::string, std::string>& fallbackMap)
: mConsoleOnlyScripts(consoleOnlyScripts)
@ -162,7 +167,6 @@ namespace MWGui
, mForceHidden(GW_None)
, mAllowed(GW_ALL)
, mRestAllowed(true)
, mShowFPSLevel(fpsLevel)
, mFPS(0.0f)
, mTriangleCount(0)
, mBatchCount(0)
@ -264,7 +268,7 @@ namespace MWGui
trackWindow(mDialogueWindow, "dialogue");
mContainerWindow = new ContainerWindow(mDragAndDrop);
trackWindow(mContainerWindow, "container");
mHud = new HUD(mCustomMarkers, mShowFPSLevel, mDragAndDrop);
mHud = new HUD(mCustomMarkers, Settings::Manager::getInt("fps", "HUD"), mDragAndDrop);
mToolTips = new ToolTips();
mScrollWindow = new ScrollWindow();
mBookWindow = new BookWindow();

@ -5,13 +5,14 @@
This class owns and controls all the MW specific windows in the
GUI. It can enable/disable Gui mode, and is responsible for sending
and retrieving information from the Gui.
MyGUI should be initialized separately before creating instances of
this class.
**/
#include <stack>
#include "../mwbase/windowmanager.hpp"
#include <components/settings/settings.hpp>
#include "mapwindow.hpp"
#include <MyGUI_KeyCode.h>
@ -96,7 +97,7 @@ namespace MWGui
typedef std::pair<std::string, int> Faction;
typedef std::vector<Faction> FactionList;
WindowManager(const Compiler::Extensions& extensions, int fpsLevel,
WindowManager(const Compiler::Extensions& extensions,
OEngine::Render::OgreRenderer *mOgre, const std::string& logpath,
const std::string& cacheDir, bool consoleOnlyScripts,
Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map<std::string,std::string>& fallbackMap);
@ -450,7 +451,6 @@ namespace MWGui
void updateVisible(); // Update visibility of all windows based on mode, shown and allowed settings
int mShowFPSLevel;
float mFPS;
unsigned int mTriangleCount;
unsigned int mBatchCount;

@ -5,6 +5,7 @@
#include <vector>
#include <string>
#include <map>
#include <list>
#include "movement.hpp"
#include "../mwbase/world.hpp"

@ -27,6 +27,8 @@
#include "creaturestats.hpp"
#include "security.hpp"
#include <components/settings/settings.hpp>
#include "../mwrender/animation.hpp"
#include "../mwbase/environment.hpp"

@ -12,9 +12,9 @@ namespace MWMechanics
{
/// @return ID of resulting item, or empty if none
inline std::string getLevelledItem (const ESM::LeveledListBase* levItem, bool creature, unsigned char failChance=0)
inline std::string getLevelledItem (const ESM::LevelledListBase* levItem, bool creature, unsigned char failChance=0)
{
const std::vector<ESM::LeveledListBase::LevelItem>& items = levItem->mList;
const std::vector<ESM::LevelledListBase::LevelItem>& items = levItem->mList;
const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr();
int playerLevel = player.getClass().getCreatureStats(player).getLevel();
@ -27,7 +27,7 @@ namespace MWMechanics
std::vector<std::string> candidates;
int highestLevel = 0;
for (std::vector<ESM::LeveledListBase::LevelItem>::const_iterator it = items.begin(); it != items.end(); ++it)
for (std::vector<ESM::LevelledListBase::LevelItem>::const_iterator it = items.begin(); it != items.end(); ++it)
{
if (it->mLevel > highestLevel && it->mLevel <= playerLevel)
highestLevel = it->mLevel;
@ -39,7 +39,7 @@ namespace MWMechanics
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)
for (std::vector<ESM::LevelledListBase::LevelItem>::const_iterator it = items.begin(); it != items.end(); ++it)
{
if (playerLevel >= it->mLevel
&& (allLevels || it->mLevel == highestLevel))

@ -2,6 +2,8 @@
#include "mechanicsmanagerimp.hpp"
#include "npcstats.hpp"
#include <components/esm/stolenitems.hpp>
#include "../mwworld/esmstore.hpp"
#include "../mwworld/inventorystore.hpp"
@ -873,31 +875,31 @@ namespace MWMechanics
mAI = true;
}
bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, MWWorld::Ptr& victim)
bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim)
{
const std::string& owner = item.getCellRef().getOwner();
const std::string& owner = cellref.getOwner();
bool isOwned = !owner.empty() && owner != "player";
const std::string& faction = item.getCellRef().getFaction();
const std::string& faction = cellref.getFaction();
bool isFactionOwned = false;
if (!faction.empty() && ptr.getClass().isNpc())
{
const std::map<std::string, int>& factions = ptr.getClass().getNpcStats(ptr).getFactionRanks();
std::map<std::string, int>::const_iterator found = factions.find(Misc::StringUtils::lowerCase(faction));
if (found == factions.end()
|| found->second < item.getCellRef().getFactionRank())
|| found->second < cellref.getFactionRank())
isFactionOwned = true;
}
const std::string& globalVariable = item.getCellRef().getGlobalVariable();
const std::string& globalVariable = cellref.getGlobalVariable();
if (!globalVariable.empty() && MWBase::Environment::get().getWorld()->getGlobalInt(Misc::StringUtils::lowerCase(globalVariable)) == 1)
{
isOwned = false;
isFactionOwned = false;
}
if (!item.getCellRef().getOwner().empty())
victim = MWBase::Environment::get().getWorld()->searchPtr(item.getCellRef().getOwner(), true);
if (!cellref.getOwner().empty())
victim = MWBase::Environment::get().getWorld()->searchPtr(cellref.getOwner(), true);
return (!isOwned && !isFactionOwned);
}
@ -916,7 +918,7 @@ namespace MWMechanics
}
MWWorld::Ptr victim;
if (isAllowedToUse(ptr, bed, victim))
if (isAllowedToUse(ptr, bed.getCellRef(), victim))
return false;
if(commitCrime(ptr, victim, OT_SleepingInOwnedBed))
@ -931,16 +933,103 @@ namespace MWMechanics
void MechanicsManager::objectOpened(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item)
{
MWWorld::Ptr victim;
if (isAllowedToUse(ptr, item, victim))
if (isAllowedToUse(ptr, item.getCellRef(), victim))
return;
commitCrime(ptr, victim, OT_Trespassing);
}
void MechanicsManager::itemTaken(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item, int count)
std::vector<std::pair<std::string, int> > MechanicsManager::getStolenItemOwners(const std::string& itemid)
{
std::vector<std::pair<std::string, int> > result;
StolenItemsMap::const_iterator it = mStolenItems.find(Misc::StringUtils::lowerCase(itemid));
if (it == mStolenItems.end())
return result;
else
{
const OwnerMap& owners = it->second;
for (OwnerMap::const_iterator ownerIt = owners.begin(); ownerIt != owners.end(); ++ownerIt)
result.push_back(std::make_pair(ownerIt->first.first, ownerIt->second));
return result;
}
}
bool MechanicsManager::isItemStolenFrom(const std::string &itemid, const std::string &ownerid)
{
StolenItemsMap::const_iterator it = mStolenItems.find(Misc::StringUtils::lowerCase(itemid));
if (it == mStolenItems.end())
return false;
const OwnerMap& owners = it->second;
OwnerMap::const_iterator ownerFound = owners.find(std::make_pair(Misc::StringUtils::lowerCase(ownerid), false));
return ownerFound != owners.end();
}
void MechanicsManager::confiscateStolenItems(const MWWorld::Ptr &player, const MWWorld::Ptr &targetContainer)
{
MWWorld::ContainerStore& store = player.getClass().getContainerStore(player);
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
{
StolenItemsMap::iterator stolenIt = mStolenItems.find(Misc::StringUtils::lowerCase(it->getClass().getId(*it)));
if (stolenIt == mStolenItems.end())
continue;
OwnerMap& owners = stolenIt->second;
int itemCount = it->getRefData().getCount();
for (OwnerMap::iterator ownerIt = owners.begin(); ownerIt != owners.end();)
{
int toRemove = std::min(itemCount, ownerIt->second);
itemCount -= toRemove;
ownerIt->second -= toRemove;
if (ownerIt->second == 0)
owners.erase(ownerIt++);
else
++ownerIt;
}
int toMove = it->getRefData().getCount() - itemCount;
targetContainer.getClass().getContainerStore(targetContainer).add(*it, toMove, targetContainer);
store.remove(*it, toMove, player);
}
// TODO: unhardcode the locklevel
targetContainer.getClass().lock(targetContainer,50);
}
void MechanicsManager::itemTaken(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item, const MWWorld::Ptr& container,
int count)
{
if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr())
return;
MWWorld::Ptr victim;
if (isAllowedToUse(ptr, item, victim))
const MWWorld::CellRef* ownerCellRef = &item.getCellRef();
if (!container.isEmpty())
{
// Inherit the owner of the container
ownerCellRef = &container.getCellRef();
}
else
{
if (!item.getCellRef().hasContentFile())
{
// this is a manually placed item, which means it was already stolen
return;
}
}
if (isAllowedToUse(ptr, *ownerCellRef, victim))
return;
Owner owner;
owner.first = ownerCellRef->getOwner();
owner.second = false;
if (owner.first.empty())
{
owner.first = ownerCellRef->getFaction();
owner.second = true;
}
Misc::StringUtils::toLower(owner.first);
mStolenItems[Misc::StringUtils::lowerCase(item.getClass().getId(item))][owner] += count;
commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count);
}
@ -949,7 +1038,7 @@ namespace MWMechanics
// NOTE: victim may be empty
// Only player can commit crime
if (player.getRefData().getHandle() != "player")
if (player != MWBase::Environment::get().getWorld()->getPlayerPtr())
return false;
// Find all the actors within the alarm radius
@ -1351,22 +1440,37 @@ namespace MWMechanics
int MechanicsManager::countSavedGameRecords() const
{
return 1; // Death counter
return 1 // Death counter
+1; // Stolen items
}
void MechanicsManager::write(ESM::ESMWriter &writer, Loading::Listener &listener) const
{
mActors.write(writer, listener);
ESM::StolenItems items;
items.mStolenItems = mStolenItems;
writer.startRecord(ESM::REC_STLN);
items.write(writer);
writer.endRecord(ESM::REC_STLN);
}
void MechanicsManager::readRecord(ESM::ESMReader &reader, uint32_t type)
{
mActors.readRecord(reader, type);
if (type == ESM::REC_STLN)
{
ESM::StolenItems items;
items.load(reader);
mStolenItems = items.mStolenItems;
}
else
mActors.readRecord(reader, type);
}
void MechanicsManager::clear()
{
mActors.clear();
mStolenItems.clear();
}
bool MechanicsManager::isAggressive(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target)

@ -35,6 +35,11 @@ namespace MWMechanics
Objects mObjects;
Actors mActors;
typedef std::pair<std::string, bool> Owner; // < Owner id, bool isFaction >
typedef std::map<Owner, int> OwnerMap; // < Owner, number of stolen items with this id from this owner >
typedef std::map<std::string, OwnerMap> StolenItemsMap;
StolenItemsMap mStolenItems;
public:
void buildPlayer();
@ -121,16 +126,15 @@ namespace MWMechanics
/// @return false if the attack was considered a "friendly hit" and forgiven
virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker);
/// Utility to check if taking this item is illegal and calling commitCrime if so
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, int count);
/// @param container The container the item is in; may be empty for an item in the world
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container,
int count);
/// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so
virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item);
/// Attempt sleeping in a bed. If this is illegal, call commitCrime.
/// @return was it illegal, and someone saw you doing it? Also returns fail when enemies are nearby
virtual bool sleepInBed (const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed);
/// @return is \a ptr allowed to take/use \a item or is it a crime?
virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, MWWorld::Ptr& victim);
virtual void forceStateUpdate(const MWWorld::Ptr &ptr);
virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number);
@ -168,9 +172,21 @@ namespace MWMechanics
virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const;
virtual void confiscateStolenItems (const MWWorld::Ptr& player, const MWWorld::Ptr& targetContainer);
/// List the owners that the player has stolen this item from (the owner can be an NPC or a faction).
/// <Owner, item count>
virtual std::vector<std::pair<std::string, int> > getStolenItemOwners(const std::string& itemid);
/// Has the player stolen this item from the given owner?
virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid);
private:
void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim,
OffenseType type, int arg=0);
/// @return is \a ptr allowed to take/use \a cellref or is it a crime?
virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim);
};
}

@ -125,32 +125,9 @@ bool MWMechanics::NpcStats::isInFaction (const std::string& faction) const
return (mFactionRank.find(Misc::StringUtils::lowerCase(faction)) != mFactionRank.end());
}
float MWMechanics::NpcStats::getSkillGain (int skillIndex, const ESM::Class& class_, int usageType,
int level, float extraFactor) const
float MWMechanics::NpcStats::getSkillProgressRequirement (int skillIndex, const ESM::Class& class_) const
{
if (level<0)
level = static_cast<int> (getSkill (skillIndex).getBase());
const ESM::Skill *skill =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Skill>().find (skillIndex);
float skillFactor = 1;
if (usageType>=4)
throw std::runtime_error ("skill usage type out of range");
if (usageType>=0)
{
skillFactor = skill->mData.mUseValue[usageType];
if (skillFactor<0)
throw std::runtime_error ("invalid skill gain factor");
if (skillFactor==0)
return 0;
}
skillFactor *= extraFactor;
float progressRequirement = 1 + getSkill (skillIndex).getBase();
const MWWorld::Store<ESM::GameSetting> &gmst =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
@ -173,11 +150,15 @@ float MWMechanics::NpcStats::getSkillGain (int skillIndex, const ESM::Class& cla
break;
}
progressRequirement *= typeFactor;
if (typeFactor<=0)
throw std::runtime_error ("invalid skill type factor");
float specialisationFactor = 1;
const ESM::Skill *skill =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Skill>().find (skillIndex);
if (skill->mData.mSpecialization==class_.mData.mSpecialization)
{
specialisationFactor = gmst.find ("fSpecialSkillBonus")->getFloat();
@ -185,7 +166,9 @@ float MWMechanics::NpcStats::getSkillGain (int skillIndex, const ESM::Class& cla
if (specialisationFactor<=0)
throw std::runtime_error ("invalid skill specialisation factor");
}
return 1.0 / ((level+1) * (1.0/skillFactor) * typeFactor * specialisationFactor);
progressRequirement *= specialisationFactor;
return progressRequirement;
}
void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_, int usageType, float extraFactor)
@ -194,13 +177,26 @@ void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_,
if(mIsWerewolf)
return;
const ESM::Skill *skill =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Skill>().find (skillIndex);
float skillGain = 1;
if (usageType>=4)
throw std::runtime_error ("skill usage type out of range");
if (usageType>=0)
{
skillGain = skill->mData.mUseValue[usageType];
if (skillGain<0)
throw std::runtime_error ("invalid skill gain factor");
}
skillGain *= extraFactor;
MWMechanics::SkillValue& value = getSkill (skillIndex);
value.setProgress(value.getProgress() + getSkillGain (skillIndex, class_, usageType, -1, extraFactor));
value.setProgress(value.getProgress() + skillGain);
if (value.getProgress()>=1)
if (int(value.getProgress())>=int(getSkillProgressRequirement(skillIndex, class_)))
{
// skill leveled up
// skill levelled up
increaseSkill(skillIndex, class_, false);
}
}
@ -256,7 +252,7 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas
MWBase::Environment::get().getWindowManager ()->messageBox ("#{sLevelUpMsg}", MWGui::ShowInDialogueMode_Never);
}
getSkill (skillIndex).setBase (base);
getSkill(skillIndex).setBase (base);
if (!preserveProgress)
getSkill(skillIndex).setProgress(0);
}
@ -268,13 +264,15 @@ int MWMechanics::NpcStats::getLevelProgress () const
void MWMechanics::NpcStats::levelUp()
{
mLevelProgress -= 10;
for (int i=0; i<ESM::Attribute::Length; ++i)
mSkillIncreases[i] = 0;
const MWWorld::Store<ESM::GameSetting> &gmst =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
mLevelProgress -= gmst.find("iLevelUpTotal")->getInt();
mLevelProgress = std::max(0, mLevelProgress); // might be necessary when levelup was invoked via console
for (int i=0; i<ESM::Attribute::Length; ++i)
mSkillIncreases[i] = 0;
const int endurance = getAttribute(ESM::Attribute::Endurance).getBase();
// "When you gain a level, in addition to increasing three primary attributes, your Health

@ -23,7 +23,7 @@ namespace MWMechanics
class NpcStats : public CreatureStats
{
int mDisposition;
SkillValue mSkill[ESM::Skill::Length];
SkillValue mSkill[ESM::Skill::Length]; // SkillValue.mProgress used by the player only
SkillValue mWerewolfSkill[ESM::Skill::Length];
int mReputation;
int mCrimeId;
@ -74,11 +74,7 @@ namespace MWMechanics
bool isInFaction (const std::string& faction) const;
float getSkillGain (int skillIndex, const ESM::Class& class_, int usageType = -1,
int level = -1, float extraFactor=1.f) const;
///< \param usageType: Usage specific factor, specified in the respective skill record;
/// -1: use a factor of 1.0 instead.
/// \param level Level to base calculation on; -1: use current level.
float getSkillProgressRequirement (int skillIndex, const ESM::Class& class_) const;
void useSkill (int skillIndex, const ESM::Class& class_, int usageType = -1, float extraFactor=1.f);
///< Increase skill by usage.

@ -18,6 +18,7 @@
#include <components/esm/loadench.hpp>
#include <components/esm/loadstat.hpp>
#include <components/misc/resourcehelpers.hpp>
#include <components/settings/settings.hpp>
#include <libs/openengine/ogre/lights.hpp>

@ -11,6 +11,7 @@
#include <OgreHardwarePixelBuffer.h>
#include <components/loadinglistener/loadinglistener.hpp>
#include <components/settings/settings.hpp>
#include <components/esm/globalmap.hpp>

@ -2,6 +2,7 @@
#include "animationextensions.hpp"
#include <stdexcept>
#include <limits>
#include <components/compiler/extensions.hpp>
#include <components/compiler/opcodes.hpp>

@ -34,24 +34,24 @@
namespace
{
void addToLevList(ESM::LeveledListBase* list, const std::string& itemId, int level)
void addToLevList(ESM::LevelledListBase* list, const std::string& itemId, int level)
{
for (std::vector<ESM::LeveledListBase::LevelItem>::iterator it = list->mList.begin(); it != list->mList.end();)
for (std::vector<ESM::LevelledListBase::LevelItem>::iterator it = list->mList.begin(); it != list->mList.end();)
{
if (it->mLevel == level && itemId == it->mId)
return;
}
ESM::LeveledListBase::LevelItem item;
ESM::LevelledListBase::LevelItem item;
item.mId = itemId;
item.mLevel = level;
list->mList.push_back(item);
}
void removeFromLevList(ESM::LeveledListBase* list, const std::string& itemId, int level)
void removeFromLevList(ESM::LevelledListBase* list, const std::string& itemId, int level)
{
// level of -1 removes all items with that itemId
for (std::vector<ESM::LeveledListBase::LevelItem>::iterator it = list->mList.begin(); it != list->mList.end();)
for (std::vector<ESM::LevelledListBase::LevelItem>::iterator it = list->mList.begin(); it != list->mList.end();)
{
if (level != -1 && it->mLevel != level)
{

@ -348,29 +348,12 @@ namespace MWScript
MWMechanics::NpcStats& stats = ptr.getClass().getNpcStats (ptr);
MWWorld::LiveCellRef<ESM::NPC> *ref = ptr.get<ESM::NPC>();
assert (ref);
const ESM::Class& class_ =
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Class>().find (ref->mBase->mClass);
float level = stats.getSkill(mIndex).getBase();
float progress = stats.getSkill(mIndex).getProgress();
int newLevel = value - (stats.getSkill(mIndex).getModified() - stats.getSkill(mIndex).getBase());
if (newLevel<0)
newLevel = 0;
progress = (progress / stats.getSkillGain (mIndex, class_, -1, level))
* stats.getSkillGain (mIndex, class_, -1, newLevel);
if (progress>=1)
progress = 0.999999999;
stats.getSkill (mIndex).setBase (newLevel);
stats.getSkill (mIndex).setProgress(progress);
}
};

@ -691,10 +691,10 @@ namespace MWScript
if (!ptr.getRefData().getBaseNode())
return;
Ogre::Vector3 worldPos = ptr.getRefData().getBaseNode()->convertLocalToWorldPosition(posChange);
dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext()).updatePtr(
MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x, worldPos.y, worldPos.z));
Ogre::Vector3 diff = ptr.getRefData().getBaseNode()->getOrientation() * posChange;
Ogre::Vector3 worldPos(ptr.getRefData().getPosition().pos);
worldPos += diff;
MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x, worldPos.y, worldPos.z);
}
};

@ -13,6 +13,7 @@
#include <OgreImage.h>
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/operations.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
@ -420,6 +421,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str
break;
case ESM::REC_DCOU:
case ESM::REC_STLN:
MWBase::Environment::get().getMechanicsManager()->readRecord(reader, n.val);
break;

@ -16,7 +16,7 @@ namespace MWWorld
void ActionTake::executeImp (const Ptr& actor)
{
MWBase::Environment::get().getMechanicsManager()->itemTaken(
actor, getTarget(), getTarget().getRefData().getCount());
actor, getTarget(), MWWorld::Ptr(), getTarget().getRefData().getCount());
actor.getClass().getContainerStore (actor).add (getTarget(), getTarget().getRefData().getCount(), actor);
MWBase::Environment::get().getWorld()->deleteObject (getTarget());
}

@ -117,6 +117,15 @@ namespace MWWorld
return mCellRef.mGlobalVariable;
}
void CellRef::resetGlobalVariable()
{
if (!mCellRef.mGlobalVariable.empty())
{
mChanged = true;
mCellRef.mGlobalVariable.erase();
}
}
void CellRef::setFactionRank(int factionRank)
{
if (factionRank != mCellRef.mFactionRank)

@ -75,6 +75,8 @@ namespace MWWorld
// Used by bed rent scripts to allow the player to use the bed for the duration of the rent.
std::string getGlobalVariable() const;
void resetGlobalVariable();
// ID of creature trapped in this soul gem
std::string getSoul() const;
void setSoul(const std::string& soul);

@ -80,6 +80,8 @@ namespace MWWorld
virtual std::string getId (const Ptr& ptr) const;
///< Return ID of \a ptr or throw an exception, if class does not support ID retrieval
/// (default implementation: throw an exception)
/// @note This function is currently redundant; the same ID can be retrieved by CellRef::getRefId.
/// Leaving it here for now in case we want to optimize later.
virtual void insertObjectRendering (const Ptr& ptr, const std::string& mesh, MWRender::RenderingInterface& renderingInterface) const;
virtual void insertObject(const Ptr& ptr, const std::string& mesh, MWWorld::PhysicsSystem& physics) const;

@ -222,29 +222,22 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr
MWWorld::ContainerStoreIterator it = end();
if (setOwner && actorPtr.getClass().isActor())
// HACK: Set owner on the original item, then reset it after we have copied it
// If we set the owner on the copied item, it would not stack correctly...
std::string oldOwner = itemPtr.getCellRef().getOwner();
if (!setOwner || actorPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) // No point in setting owner to the player - NPCs will not respect this anyway
{
// HACK: Set owner on the original item, then reset it after we have copied it
// If we set the owner on the copied item, it would not stack correctly...
std::string oldOwner = itemPtr.getCellRef().getOwner();
if (actorPtr == player)
{
// No point in setting owner to the player - NPCs will not respect this anyway
// Additionally, setting it to "player" would make those items not stack with items that don't have an owner
itemPtr.getCellRef().setOwner("");
}
else
itemPtr.getCellRef().setOwner(actorPtr.getCellRef().getRefId());
it = addImp(itemPtr, count);
itemPtr.getCellRef().setOwner(oldOwner);
itemPtr.getCellRef().setOwner("");
}
else
{
it = addImp(itemPtr, count);
itemPtr.getCellRef().setOwner(actorPtr.getCellRef().getRefId());
}
it = addImp(itemPtr, count);
itemPtr.getCellRef().setOwner(oldOwner);
// The copy of the original item we just made
MWWorld::Ptr item = *it;
@ -258,6 +251,14 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr
pos.pos[1] = 0;
pos.pos[2] = 0;
item.getCellRef().setPosition(pos);
// reset ownership stuff, owner was already handled above
item.getCellRef().resetGlobalVariable();
item.getCellRef().setFaction("");
item.getCellRef().setFactionRank(-1);
// must reset the RefNum on the copied item, so that the RefNum on the original item stays unique
// maybe we should do this in the copy constructor instead?
item.getCellRef().unsetRefNum(); // destroy link to content file
std::string script = item.getClass().getScript(item);
@ -399,19 +400,19 @@ int MWWorld::ContainerStore::remove(const Ptr& item, int count, const Ptr& actor
return count - toRemove;
}
void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std::string& owner, const std::string& faction, int factionRank, const MWWorld::ESMStore& store)
void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std::string& owner)
{
for (std::vector<ESM::ContItem>::const_iterator iter (items.mList.begin()); iter!=items.mList.end();
++iter)
{
std::string id = Misc::StringUtils::lowerCase(iter->mItem.toString());
addInitialItem(id, owner, faction, factionRank, iter->mCount);
addInitialItem(id, owner, iter->mCount);
}
flagAsModified();
}
void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, int factionRank,
void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner,
int count, bool topLevel, const std::string& levItem)
{
ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count);
@ -423,7 +424,7 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::
if (topLevel && std::abs(count) > 1 && levItem->mFlags & ESM::ItemLevList::Each)
{
for (int i=0; i<std::abs(count); ++i)
addInitialItem(id, owner, faction, factionRank, count > 0 ? 1 : -1, true, levItem->mId);
addInitialItem(id, owner, count > 0 ? 1 : -1, true, levItem->mId);
return;
}
else
@ -431,7 +432,7 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::
std::string id = MWMechanics::getLevelledItem(ref.getPtr().get<ESM::ItemLevList>()->mBase, false);
if (id.empty())
return;
addInitialItem(id, owner, faction, factionRank, count, false, levItem->mId);
addInitialItem(id, owner, count, false, levItem->mId);
}
}
else
@ -447,13 +448,11 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::
count = std::abs(count);
ref.getPtr().getCellRef().setOwner(owner);
ref.getPtr().getCellRef().setFaction(faction);
ref.getPtr().getCellRef().setFactionRank(factionRank);
addImp (ref.getPtr(), count);
}
}
void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner, const std::string& faction, int factionRank)
void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner)
{
// Remove the items already spawned by levelled items that will restock
for (std::map<std::string, int>::iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it)
@ -472,13 +471,13 @@ void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MW
if (MWBase::Environment::get().getWorld()->getStore().get<ESM::ItemLevList>().search(it->mItem.toString()))
{
addInitialItem(item, owner, faction, factionRank, it->mCount, true);
addInitialItem(item, owner, it->mCount, true);
}
else
{
int currentCount = count(item);
if (currentCount < std::abs(it->mCount))
addInitialItem(item, owner, faction, factionRank, std::abs(it->mCount) - currentCount, true);
addInitialItem(item, owner, std::abs(it->mCount) - currentCount, true);
}
}
flagAsModified();

@ -75,7 +75,7 @@ namespace MWWorld
mutable float mCachedWeight;
mutable bool mWeightUpToDate;
ContainerStoreIterator addImp (const Ptr& ptr, int count);
void addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, int factionRank, int count, bool topLevel=true, const std::string& levItem = "");
void addInitialItem (const std::string& id, const std::string& owner, int count, bool topLevel=true, const std::string& levItem = "");
template<typename T>
ContainerStoreIterator getState (CellRefList<T>& collection,
@ -112,7 +112,7 @@ namespace MWWorld
/// \attention Do not add items to an existing stack by increasing the count instead of
/// calling this function!
///
/// @param setOwner Set the owner of the added item to \a actorPtr?
/// @param setOwner Set the owner of the added item to \a actorPtr? If false, the owner is reset to "".
///
/// @return if stacking happened, return iterator to the item that was stacked against, otherwise iterator to the newly inserted item.
@ -151,10 +151,10 @@ namespace MWWorld
virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2);
///< @return true if the two specified objects can stack with each other
void fill (const ESM::InventoryList& items, const std::string& owner, const std::string& faction, int factionRank, const MWWorld::ESMStore& store);
void fill (const ESM::InventoryList& items, const std::string& owner);
///< Insert items into *this.
void restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner, const std::string& faction, int factionRank);
void restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner);
virtual void clear();
///< Empty container.

@ -133,12 +133,11 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::add(const Ptr& itemPtr,
const MWWorld::ContainerStoreIterator& retVal = MWWorld::ContainerStore::add(itemPtr, count, actorPtr, setOwner);
// Auto-equip items if an armor/clothing or weapon item is added, but not for the player nor werewolves
if ((actorPtr.getRefData().getHandle() != "player")
&& !(actorPtr.getClass().isNpc() && actorPtr.getClass().getNpcStats(actorPtr).isWerewolf())
&& !actorPtr.getClass().getCreatureStats(actorPtr).isDead())
if (actorPtr.getRefData().getHandle() != "player"
&& !(actorPtr.getClass().isNpc() && actorPtr.getClass().getNpcStats(actorPtr).isWerewolf()))
{
std::string type = itemPtr.getTypeName();
if ((type == typeid(ESM::Armor).name()) || (type == typeid(ESM::Clothing).name()) || (type == typeid(ESM::Weapon).name()))
if (type == typeid(ESM::Armor).name() || type == typeid(ESM::Clothing).name())
autoEquip(actorPtr);
}
@ -234,7 +233,9 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor)
// ...unless this is a companion, he should always equip items given to him.
if (!Misc::StringUtils::ciEqual(test.getCellRef().getOwner(), actor.getCellRef().getRefId()) &&
(actor.getClass().getScript(actor).empty() ||
!actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion")))
!actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion"))
&& !actor.getClass().getCreatureStats(actor).isDead() // Corpses can be dressed up by the player as desired
)
{
continue;
}
@ -506,8 +507,7 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor
&& !(actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()))
{
std::string type = item.getTypeName();
if (((type == typeid(ESM::Armor).name()) || (type == typeid(ESM::Clothing).name()))
&& !actor.getClass().getCreatureStats(actor).isDead())
if (type == typeid(ESM::Armor).name() || type == typeid(ESM::Clothing).name())
autoEquip(actor);
}

@ -1,6 +1,7 @@
#include "livecellref.hpp"
#include <iostream>
#include <components/esm/objectstate.hpp>
#include "../mwbase/environment.hpp"

@ -260,9 +260,20 @@ namespace MWWorld
mCellStore = world.getExterior(0,0);
}
if (!player.mBirthsign.empty() &&
!world.getStore().get<ESM::BirthSign>().search (player.mBirthsign))
throw std::runtime_error ("invalid player state record (birthsign)");
if (!player.mBirthsign.empty())
{
const ESM::BirthSign* sign = world.getStore().get<ESM::BirthSign>().search (player.mBirthsign);
if (!sign)
throw std::runtime_error ("invalid player state record (birthsign does not exist)");
// To handle the case where a birth sign was edited in between play sessions (does not yet handle removing the old spells)
// Also needed for ess-imported savegames which do not specify the birtsign spells in the player's spell list.
for (std::vector<std::string>::const_iterator iter (sign->mPowers.mList.begin());
iter!=sign->mPowers.mList.end(); ++iter)
{
getPlayer().getClass().getCreatureStats(getPlayer()).getSpells().add (*iter);
}
}
mCurrentCrimeId = player.mCurrentCrimeId;
mPaidCrimeId = player.mPaidCrimeId;

@ -2988,18 +2988,10 @@ namespace MWWorld
if (!closestChest.isEmpty()) //Found a close chest
{
ContainerStore& store = ptr.getClass().getContainerStore(ptr);
for (ContainerStoreIterator it = store.begin(); it != store.end(); ++it) //Move all stolen stuff into chest
{
MWWorld::Ptr dummy;
if (!MWBase::Environment::get().getMechanicsManager()->isAllowedToUse(getPlayerPtr(), *it, dummy))
{
closestChest.getClass().getContainerStore(closestChest).add(*it, it->getRefData().getCount(), closestChest);
store.remove(*it, it->getRefData().getCount(), ptr);
}
}
closestChest.getClass().lock(closestChest,50);
MWBase::Environment::get().getMechanicsManager()->confiscateStolenItems(ptr, closestChest);
}
else
std::cerr << "Failed to confiscate items: no stolen_goods container found" << std::endl;
}
void World::goToJail()

@ -63,7 +63,7 @@ add_component_dir (esm
loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter
savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap inventorystate containerstate npcstate creaturestate dialoguestate statstate
npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile
aisequence magiceffects util custommarkerstate
aisequence magiceffects util custommarkerstate stolenitems
)
add_component_dir (esmterrain

@ -15,8 +15,7 @@ ContentSelectorModel::ContentModel::ContentModel(QObject *parent, QIcon warningI
mMimeType ("application/omwcontent"),
mMimeTypes (QStringList() << mMimeType),
mColumnCount (1),
mDragDropFlags (Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled),
mDropActions (Qt::CopyAction | Qt::MoveAction)
mDropActions (Qt::MoveAction)
{
setEncoding ("win1252");
uncheckAll();
@ -104,7 +103,7 @@ QModelIndex ContentSelectorModel::ContentModel::indexFromItem(const EsmFile *ite
Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return Qt::NoItemFlags;
return Qt::ItemIsDropEnabled;
const EsmFile *file = item(index.row());
@ -152,7 +151,7 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index
if (gamefileChecked)
{
if (allDependenciesFound)
returnFlags = returnFlags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | mDragDropFlags;
returnFlags = returnFlags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled;
else
returnFlags = Qt::ItemIsSelectable;
}
@ -443,11 +442,6 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path)
filters << "*.esp" << "*.esm" << "*.omwgame" << "*.omwaddon";
dir.setNameFilters(filters);
QTextCodec *codec = QTextCodec::codecForName("UTF8");
// Create a decoder for non-latin characters in esx metadata
QTextDecoder *decoder = codec->makeDecoder();
foreach (const QString &path, dir.entryList())
{
QFileInfo info(dir.absoluteFilePath(path));
@ -467,11 +461,11 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path)
foreach (const ESM::Header::MasterData &item, fileReader.getGameFiles())
file->addGameFile(QString::fromStdString(item.name));
file->setAuthor (decoder->toUnicode(fileReader.getAuthor().c_str()));
file->setAuthor (QString::fromUtf8(fileReader.getAuthor().c_str()));
file->setDate (info.lastModified());
file->setFormat (fileReader.getFormat());
file->setFilePath (info.absoluteFilePath());
file->setDescription(decoder->toUnicode(fileReader.getDesc().c_str()));
file->setDescription(QString::fromUtf8(fileReader.getDesc().c_str()));
// Put the file in the table
addFile(file);
@ -484,8 +478,6 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path)
}
delete decoder;
sortFiles();
}

@ -89,7 +89,6 @@ namespace ContentSelectorModel
QString mMimeType;
QStringList mMimeTypes;
int mColumnCount;
Qt::ItemFlags mDragDropFlags;
Qt::DropActions mDropActions;
};
}

@ -15,7 +15,8 @@
ContentSelectorView::ContentSelector::ContentSelector(QWidget *parent) :
QObject(parent)
{
ui.setupUi (parent);
ui.setupUi(parent);
ui.addonView->setDragDropMode(QAbstractItemView::InternalMove);
buildContentModel();
buildGameFileView();

@ -117,6 +117,7 @@ enum RecNameInts
REC_MARK = FourCC<'M','A','R','K'>::value,
REC_ENAB = FourCC<'E','N','A','B'>::value,
REC_CAM_ = FourCC<'C','A','M','_'>::value,
REC_STLN = FourCC<'S','T','L','N'>::value,
// format 1
REC_FILT = FourCC<'F','I','L','T'>::value,

@ -7,7 +7,7 @@
namespace ESM
{
void LeveledListBase::load(ESMReader &esm)
void LevelledListBase::load(ESMReader &esm)
{
esm.getHNT(mFlags, "DATA");
esm.getHNT(mChanceNone, "NNAM");
@ -19,13 +19,17 @@ void LeveledListBase::load(ESMReader &esm)
mList.resize(len);
}
else
{
esm.skipRecord();
return;
}
// TODO: Merge with an existing lists here. This can be done
// simply by adding the lists together, making sure that they are
// sorted by level. A better way might be to exclude repeated
// items. Also, some times we don't want to merge lists, just
// overwrite. Figure out a way to give the user this option.
// If this levelled list was already loaded by a previous content file,
// we overwrite the list. Merging lists should probably be left to external tools,
// with the limited amount of information there is in the records, all merging methods
// will be flawed in some way. For a proper fix the ESM format would have to be changed
// to actually track list changes instead of including the whole list for every file
// that does something with that list.
for (size_t i = 0; i < mList.size(); i++)
{
@ -34,7 +38,7 @@ void LeveledListBase::load(ESMReader &esm)
esm.getHNT(li.mLevel, "INTV");
}
}
void LeveledListBase::save(ESMWriter &esm) const
void LevelledListBase::save(ESMWriter &esm) const
{
esm.writeHNT("DATA", mFlags);
esm.writeHNT("NNAM", mChanceNone);
@ -47,7 +51,7 @@ void LeveledListBase::save(ESMWriter &esm) const
}
}
void LeveledListBase::blank()
void LevelledListBase::blank()
{
mFlags = 0;
mChanceNone = 0;

@ -11,14 +11,14 @@ class ESMReader;
class ESMWriter;
/*
* Leveled lists. Since these have identical layout, I only bothered
* Levelled lists. Since these have identical layout, I only bothered
* to implement it once.
*
* We should later implement the ability to merge leveled lists from
* We should later implement the ability to merge levelled lists from
* several files.
*/
struct LeveledListBase
struct LevelledListBase
{
int mFlags;
unsigned char mChanceNone; // Chance that none are selected (0-100)
@ -43,7 +43,7 @@ struct LeveledListBase
///< Set record to default state (does not touch the ID).
};
struct CreatureLevList: LeveledListBase
struct CreatureLevList: LevelledListBase
{
static unsigned int sRecordId;
@ -61,7 +61,7 @@ struct CreatureLevList: LeveledListBase
}
};
struct ItemLevList: LeveledListBase
struct ItemLevList: LevelledListBase
{
static unsigned int sRecordId;
@ -72,7 +72,7 @@ struct ItemLevList: LeveledListBase
// list is instantiated, instead of
// giving several identical items
// (used when a container has more
// than one instance of one leveled
// than one instance of one levelled
// list.)
AllLevels = 0x02 // Calculate from all levels <= player
// level, not just the closest below

@ -0,0 +1,47 @@
#include "stolenitems.hpp"
#include <components/esm/esmreader.hpp>
#include <components/esm/esmwriter.hpp>
namespace ESM
{
void StolenItems::write(ESMWriter &esm) const
{
for (StolenItemsMap::const_iterator it = mStolenItems.begin(); it != mStolenItems.end(); ++it)
{
esm.writeHNString("NAME", it->first);
for (std::map<std::pair<std::string, bool>, int>::const_iterator ownerIt = it->second.begin();
ownerIt != it->second.end(); ++ownerIt)
{
if (ownerIt->first.second)
esm.writeHNString("FNAM", ownerIt->first.first);
else
esm.writeHNString("ONAM", ownerIt->first.first);
esm.writeHNT("COUN", ownerIt->second);
}
}
}
void StolenItems::load(ESMReader &esm)
{
while (esm.isNextSub("NAME"))
{
std::string itemid = esm.getHString();
std::map<std::pair<std::string, bool>, int> ownerMap;
while (esm.isNextSub("FNAM") || esm.isNextSub("ONAM"))
{
std::string subname = esm.retSubName().toString();
std::string owner = esm.getHString();
bool isFaction = (subname == "FNAM");
int count;
esm.getHNT(count, "COUN");
ownerMap.insert(std::make_pair(std::make_pair(owner, isFaction), count));
}
mStolenItems[itemid] = ownerMap;
}
}
}

@ -0,0 +1,24 @@
#ifndef OPENMW_COMPONENTS_ESM_STOLENITEMS_H
#define OPENMW_COMPONENTS_ESM_STOLENITEMS_H
#include <map>
#include <string>
namespace ESM
{
class ESMReader;
class ESMWriter;
// format 0, saved games only
struct StolenItems
{
typedef std::map<std::string, std::map<std::pair<std::string, bool>, int> > StolenItemsMap;
StolenItemsMap mStolenItems;
void load(ESM::ESMReader& esm);
void write(ESM::ESMWriter& esm) const;
};
}
#endif

@ -1,95 +1,144 @@
#include "settings.hpp"
#include <stdexcept>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/fstream.hpp>
#include <OgreResourceGroupManager.h>
#include <OgreStringConverter.h>
#include <OgreDataStream.h>
#include <components/files/constrainedfiledatastream.hpp>
using namespace Settings;
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/algorithm/string.hpp>
namespace bfs = boost::filesystem;
namespace Settings
{
Ogre::ConfigFile Manager::mFile = Ogre::ConfigFile();
Ogre::ConfigFile Manager::mDefaultFile = Ogre::ConfigFile();
CategorySettingValueMap Manager::mDefaultSettings = CategorySettingValueMap();
CategorySettingValueMap Manager::mUserSettings = CategorySettingValueMap();
CategorySettingVector Manager::mChangedSettings = CategorySettingVector();
CategorySettingValueMap Manager::mNewSettings = CategorySettingValueMap();
void Manager::loadUser (const std::string& file)
{
Ogre::DataStreamPtr stream = openConstrainedFileDataStream(file.c_str());
mFile.load(stream);
}
void Manager::loadDefault (const std::string& file)
{
Ogre::DataStreamPtr stream = openConstrainedFileDataStream(file.c_str());
mDefaultFile.load(stream);
}
void Manager::saveUser(const std::string& file)
class SettingsFileParser
{
bfs::ofstream fout((bfs::path(file)));
public:
SettingsFileParser() : mLine(0) {}
Ogre::ConfigFile::SectionIterator seci = mFile.getSectionIterator();
while (seci.hasMoreElements())
void loadSettingsFile (const std::string& file, CategorySettingValueMap& settings)
{
Ogre::String sectionName = seci.peekNextKey();
mFile = file;
boost::filesystem::ifstream stream;
stream.open(boost::filesystem::path(file));
std::string currentCategory;
mLine = 0;
while (!stream.eof() && !stream.fail())
{
++mLine;
std::string line;
std::getline( stream, line );
if (sectionName.length() > 0)
fout << '\n' << '[' << seci.peekNextKey() << ']' << '\n';
size_t i = 0;
if (!skipWhiteSpace(i, line))
continue;
Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
Ogre::ConfigFile::SettingsMultiMap::iterator i;
for (i = settings->begin(); i != settings->end(); ++i)
{
fout << i->first.c_str() << " = " << i->second.c_str() << '\n';
}
if (line[i] == '#') // skip comment
continue;
CategorySettingValueMap::iterator it = mNewSettings.begin();
while (it != mNewSettings.end())
{
if (it->first.first == sectionName)
if (line[i] == '[')
{
fout << it->first.second << " = " << it->second << '\n';
mNewSettings.erase(it++);
size_t end = line.find(']', i);
if (end == std::string::npos)
fail("unterminated category");
currentCategory = line.substr(i+1, end - (i+1));
boost::algorithm::trim(currentCategory);
i = end+1;
}
else
++it;
if (!skipWhiteSpace(i, line))
continue;
if (currentCategory.empty())
fail("empty category name");
size_t settingEnd = line.find('=', i);
if (settingEnd == std::string::npos)
fail("unterminated setting name");
std::string setting = line.substr(i, (settingEnd-i));
boost::algorithm::trim(setting);
size_t valueBegin = settingEnd+1;
std::string value = line.substr(valueBegin);
boost::algorithm::trim(value);
if (settings.insert(std::make_pair(std::make_pair(currentCategory, setting), value)).second == false)
fail(std::string("duplicate setting: [" + currentCategory + "] " + setting));
}
}
std::string category = "";
for (CategorySettingValueMap::iterator it = mNewSettings.begin();
it != mNewSettings.end(); ++it)
private:
/// Increment i until it longer points to a whitespace character
/// in the string or has reached the end of the string.
/// @return false if we have reached the end of the string
bool skipWhiteSpace(size_t& i, std::string& str)
{
if (category != it->first.first)
while (i < str.size() && std::isspace(str[i], std::locale::classic()))
{
category = it->first.first;
fout << '\n' << '[' << category << ']' << '\n';
++i;
}
fout << it->first.second << " = " << it->second << '\n';
return i < str.size();
}
fout.close();
void fail(const std::string& message)
{
std::stringstream error;
error << "Error on line " << mLine << " in " << mFile << ":\n" << message;
throw std::runtime_error(error.str());
}
std::string mFile;
int mLine;
};
void Manager::loadDefault(const std::string &file)
{
SettingsFileParser parser;
parser.loadSettingsFile(file, mDefaultSettings);
}
std::string Manager::getString (const std::string& setting, const std::string& category)
void Manager::loadUser(const std::string &file)
{
if (mNewSettings.find(std::make_pair(category, setting)) != mNewSettings.end())
return mNewSettings[std::make_pair(category, setting)];
SettingsFileParser parser;
parser.loadSettingsFile(file, mUserSettings);
}
void Manager::saveUser(const std::string &file)
{
boost::filesystem::ofstream stream;
stream.open(boost::filesystem::path(file));
std::string currentCategory;
for (CategorySettingValueMap::iterator it = mUserSettings.begin(); it != mUserSettings.end(); ++it)
{
if (it->first.first != currentCategory)
{
currentCategory = it->first.first;
stream << "\n[" << currentCategory << "]\n";
}
stream << it->first.second << " = " << it->second << "\n";
}
}
std::string Manager::getString(const std::string &setting, const std::string &category)
{
CategorySettingValueMap::key_type key = std::make_pair(category, setting);
CategorySettingValueMap::iterator it = mUserSettings.find(key);
if (it != mUserSettings.end())
return it->second;
std::string defaultval = mDefaultFile.getSetting(setting, category, "NOTFOUND");
std::string val = mFile.getSetting(setting, category, defaultval);
it = mDefaultSettings.find(key);
if (it != mDefaultSettings.end())
return it->second;
if (val == "NOTFOUND")
throw std::runtime_error("Trying to retrieve a non-existing setting: " + setting + " Make sure the settings-default.cfg file was properly installed.");
return val;
throw std::runtime_error(std::string("Trying to retrieve a non-existing setting: ") + setting
+ ".\nMake sure the settings-default.cfg file file was properly installed.");
}
float Manager::getFloat (const std::string& setting, const std::string& category)
@ -107,51 +156,20 @@ bool Manager::getBool (const std::string& setting, const std::string& category)
return Ogre::StringConverter::parseBool( getString(setting, category) );
}
void Manager::setString (const std::string& setting, const std::string& category, const std::string& value)
void Manager::setString(const std::string &setting, const std::string &category, const std::string &value)
{
CategorySetting s = std::make_pair(category, setting);
CategorySettingValueMap::key_type key = std::make_pair(category, setting);
bool found=false;
try
CategorySettingValueMap::iterator found = mUserSettings.find(key);
if (found != mUserSettings.end())
{
Ogre::ConfigFile::SettingsIterator it = mFile.getSettingsIterator(category);
while (it.hasMoreElements())
{
Ogre::ConfigFile::SettingsMultiMap::iterator i = it.current();
if ((*i).first == setting)
{
if ((*i).second != value)
{
mChangedSettings.push_back(std::make_pair(category, setting));
(*i).second = value;
}
found = true;
}
it.getNext();
}
if (found->second == value)
return;
}
catch (Ogre::Exception&)
{}
if (!found)
{
if (mNewSettings.find(s) != mNewSettings.end())
{
if (mNewSettings[s] != value)
{
mChangedSettings.push_back(std::make_pair(category, setting));
mNewSettings[s] = value;
}
}
else
{
if (mDefaultFile.getSetting(setting, category) != value)
mChangedSettings.push_back(std::make_pair(category, setting));
mNewSettings[s] = value;
}
}
mUserSettings[key] = value;
mChangedSettings.insert(key);
}
void Manager::setInt (const std::string& setting, const std::string& category, const int value)
@ -159,12 +177,12 @@ void Manager::setInt (const std::string& setting, const std::string& category, c
setString(setting, category, Ogre::StringConverter::toString(value));
}
void Manager::setFloat (const std::string& setting, const std::string& category, const float value)
void Manager::setFloat (const std::string &setting, const std::string &category, const float value)
{
setString(setting, category, Ogre::StringConverter::toString(value));
}
void Manager::setBool (const std::string& setting, const std::string& category, const bool value)
void Manager::setBool(const std::string &setting, const std::string &category, const bool value)
{
setString(setting, category, Ogre::StringConverter::toString(value));
}
@ -175,3 +193,5 @@ const CategorySettingVector Manager::apply()
mChangedSettings.clear();
return vec;
}
}

@ -1,12 +1,14 @@
#ifndef COMPONENTS_SETTINGS_H
#define COMPONENTS_SETTINGS_H
#include <OgreConfigFile.h>
#include <set>
#include <map>
#include <string>
namespace Settings
{
typedef std::pair < std::string, std::string > CategorySetting;
typedef std::vector< std::pair<std::string, std::string> > CategorySettingVector;
typedef std::set< std::pair<std::string, std::string> > CategorySettingVector;
typedef std::map < CategorySetting, std::string > CategorySettingValueMap;
///
@ -15,15 +17,12 @@ namespace Settings
class Manager
{
public:
static Ogre::ConfigFile mFile;
static Ogre::ConfigFile mDefaultFile;
static CategorySettingValueMap mDefaultSettings;
static CategorySettingValueMap mUserSettings;
static CategorySettingVector mChangedSettings;
///< tracks all the settings that were changed since the last apply() call
static CategorySettingValueMap mNewSettings;
///< tracks all the settings that are in the default file, but not in user file yet
void loadDefault (const std::string& file);
///< load file as the default settings (can be overridden by user settings)

@ -98,7 +98,6 @@ namespace Terrain
DefaultWorld* getTerrain() { return mTerrain; }
/// Adjust LODs for the given camera position, possibly splitting up chunks or merging them.
/// @param force Always choose to render this node, even if not the perfect LOD.
/// @return Did we (or all of our children) choose to render?
bool update (const Ogre::Vector3& cameraPos);
@ -124,7 +123,6 @@ namespace Terrain
/// call this method on their children.
/// @note Do not call this before World::areLayersLoaded() == true
/// @param area area in image space to put the quad
/// @param quads collect quads here so they can be deleted later
void prepareForCompositeMap(Ogre::TRect<float> area);
/// Create a chunk for this node from the given data.

@ -1,8 +1,8 @@
#ifndef _SFO_EVENTS_H
#define _SFO_EVENTS_H
#include <SDL.h>
#include <SDL_types.h>
#include <SDL_events.h>
////////////
// Events //
@ -65,7 +65,7 @@ public:
virtual ~WindowListener() {}
/** @remarks The window's visibility changed */
virtual void windowVisibilityChange( bool visible ) {};
virtual void windowVisibilityChange( bool visible ) {}
/** @remarks The window got / lost input focus */
virtual void windowFocusChange( bool have_focus ) {}

@ -4,6 +4,9 @@
#include <OgreTextureManager.h>
#include <OgreRoot.h>
#include <SDL_mouse.h>
#include <SDL_endian.h>
#include <openengine/ogre/imagerotate.hpp>
namespace SFO

@ -1,11 +1,12 @@
#ifndef SDL4OGRE_CURSORMANAGER_H
#define SDL4OGRE_CURSORMANAGER_H
#include <SDL.h>
#include "cursormanager.hpp"
#include <map>
struct SDL_Cursor;
struct SDL_Surface;
namespace SFO
{
class SDLCursorManager :

@ -50,7 +50,7 @@
<UserString key="ImageTexture_AttributeImage" value="icons\k\attribute_strength.dds"/>
<Property key="Caption" value="#{sAttributeStrength}"/>
</Widget>
<Widget type="AutoSizedTextBox" skin="SandText" name="AttribVal1">
<Widget type="AutoSizedTextBox" skin="SandTextButton" name="AttribVal1">
</Widget>
</Widget>
@ -64,7 +64,7 @@
<UserString key="ImageTexture_AttributeImage" value="icons\k\attribute_int.dds"/>
<Property key="Caption" value="#{sAttributeIntelligence}"/>
</Widget>
<Widget type="AutoSizedTextBox" skin="SandText" name="AttribVal2">
<Widget type="AutoSizedTextBox" skin="SandTextButton" name="AttribVal2">
</Widget>
</Widget>
@ -78,7 +78,7 @@
<UserString key="ImageTexture_AttributeImage" value="icons\k\attribute_wilpower.dds"/>
<Property key="Caption" value="#{sAttributeWillpower}"/>
</Widget>
<Widget type="AutoSizedTextBox" skin="SandText" name="AttribVal3">
<Widget type="AutoSizedTextBox" skin="SandTextButton" name="AttribVal3">
</Widget>
</Widget>
@ -92,7 +92,7 @@
<UserString key="ImageTexture_AttributeImage" value="icons\k\attribute_agility.dds"/>
<Property key="Caption" value="#{sAttributeAgility}"/>
</Widget>
<Widget type="AutoSizedTextBox" skin="SandText" name="AttribVal4">
<Widget type="AutoSizedTextBox" skin="SandTextButton" name="AttribVal4">
</Widget>
</Widget>
@ -107,7 +107,7 @@
<UserString key="ImageTexture_AttributeImage" value="icons\k\attribute_speed.dds"/>
<Property key="Caption" value="#{sAttributeSpeed}"/>
</Widget>
<Widget type="AutoSizedTextBox" skin="SandText" name="AttribVal5">
<Widget type="AutoSizedTextBox" skin="SandTextButton" name="AttribVal5">
</Widget>
</Widget>
@ -121,7 +121,7 @@
<UserString key="ImageTexture_AttributeImage" value="icons\k\attribute_endurance.dds"/>
<Property key="Caption" value="#{sAttributeEndurance}"/>
</Widget>
<Widget type="AutoSizedTextBox" skin="SandText" name="AttribVal6">
<Widget type="AutoSizedTextBox" skin="SandTextButton" name="AttribVal6">
</Widget>
</Widget>
@ -135,7 +135,7 @@
<UserString key="ImageTexture_AttributeImage" value="icons\k\attribute_personality.dds"/>
<Property key="Caption" value="#{sAttributePersonality}"/>
</Widget>
<Widget type="AutoSizedTextBox" skin="SandText" name="AttribVal7">
<Widget type="AutoSizedTextBox" skin="SandTextButton" name="AttribVal7">
</Widget>
</Widget>
@ -149,7 +149,7 @@
<UserString key="ImageTexture_AttributeImage" value="icons\k\attribute_luck.dds"/>
<Property key="Caption" value="#{sAttributeLuck}"/>
</Widget>
<Widget type="AutoSizedTextBox" skin="SandText" name="AttribVal8">
<Widget type="AutoSizedTextBox" skin="SandTextButton" name="AttribVal8">
</Widget>
</Widget>
</Widget>

Loading…
Cancel
Save