worldimp.cpp 91.2 KB
Newer Older
1
#include "worldimp.hpp"
2 3 4 5 6 7 8
#ifdef _WIN32
#include <boost/tr1/tr1/unordered_map>
#elif defined HAVE_UNORDERED_MAP
#include <unordered_map>
#else
#include <tr1/unordered_map>
#endif
9

scrawl's avatar
scrawl committed
10 11
#include <OgreSceneNode.h>

12 13
#include <libs/openengine/bullet/physic.hpp>

14
#include <components/bsa/bsa_archive.hpp>
15
#include <components/files/collections.hpp>
16
#include <components/compiler/locals.hpp>
17

18 19
#include <boost/math/special_functions/sign.hpp>

20
#include "../mwbase/environment.hpp"
21
#include "../mwbase/soundmanager.hpp"
22
#include "../mwbase/mechanicsmanager.hpp"
23
#include "../mwbase/windowmanager.hpp"
24
#include "../mwbase/scriptmanager.hpp"
25

26
#include "../mwmechanics/creaturestats.hpp"
27
#include "../mwmechanics/movement.hpp"
28
#include "../mwmechanics/npcstats.hpp"
scrawl's avatar
scrawl committed
29
#include "../mwmechanics/spellcasting.hpp"
30
#include "../mwmechanics/levelledlist.hpp"
31

32

33
#include "../mwrender/sky.hpp"
34
#include "../mwrender/animation.hpp"
35

lazydev's avatar
lazydev committed
36 37
#include "../mwclass/door.hpp"

38
#include "player.hpp"
39
#include "manualref.hpp"
40
#include "cellfunctors.hpp"
Chris Robinson's avatar
Chris Robinson committed
41
#include "containerstore.hpp"
42
#include "inventorystore.hpp"
43
#include "actionteleport.hpp"
44

45 46 47 48
#include "contentloader.hpp"
#include "esmloader.hpp"
#include "omwloader.hpp"

49 50
using namespace Ogre;

51 52
namespace
{
53 54 55
/*  // NOTE this code is never instantiated (proper copy in localscripts.cpp),
    //      so this commented out to not produce syntactic errors

56
    template<typename T>
Artem Kotsynyak's avatar
Artem Kotsynyak committed
57
    void listCellScripts (const MWWorld::ESMStore& store,
58
        MWWorld::CellRefList<T>& cellRefList, MWWorld::LocalScripts& localScripts,
59
        MWWorld::Ptr::CellStore *cell)
60
    {
61
        for (typename MWWorld::CellRefList<T>::List::iterator iter (
62 63
            cellRefList.mList.begin());
            iter!=cellRefList.mList.end(); ++iter)
64
        {
65
            if (!iter->mBase->mScript.empty() && iter->mData.getCount())
Marc Zinnschlag's avatar
Marc Zinnschlag committed
66
            {
67
                if (const ESM::Script *script = store.get<ESM::Script>().find (iter->mBase->mScript))
68
                {
Marc Zinnschlag's avatar
Marc Zinnschlag committed
69
                    iter->mData.setLocals (*script);
70

71
                    localScripts.add (iter->mBase->mScript, MWWorld::Ptr (&*iter, cell));
Marc Zinnschlag's avatar
Marc Zinnschlag committed
72 73
                }
            }
74 75
        }
    }
76
*/
77
    template<typename T>
78 79
    MWWorld::LiveCellRef<T> *searchViaHandle (const std::string& handle,
        MWWorld::CellRefList<T>& refList)
80
    {
81
        typedef typename MWWorld::CellRefList<T>::List::iterator iterator;
82

83
        for (iterator iter (refList.mList.begin()); iter!=refList.mList.end(); ++iter)
84
        {
85
            if (iter->mData.getCount() > 0 && iter->mData.getBaseNode()){
86 87 88 89
            if (iter->mData.getHandle()==handle)
            {
                return &*iter;
            }
Jason Hooks's avatar
Jason Hooks committed
90
            }
91
        }
92 93
        return 0;
    }
94 95
}

Marc Zinnschlag's avatar
Marc Zinnschlag committed
96
namespace MWWorld
97
{
98 99 100 101 102 103 104 105 106 107 108 109 110 111
    struct GameContentLoader : public ContentLoader
    {
        GameContentLoader(Loading::Listener& listener)
          : ContentLoader(listener)
        {
        }

        bool addLoader(const std::string& extension, ContentLoader* loader)
        {
            return mLoaders.insert(std::make_pair(extension, loader)).second;
        }

        void load(const boost::filesystem::path& filepath, int& index)
        {
112
            LoadersContainer::iterator it(mLoaders.find(Misc::StringUtils::lowerCase(filepath.extension().string())));
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
            if (it != mLoaders.end())
            {
                it->second->load(filepath, index);
            }
            else
            {
              std::string msg("Cannot load file: ");
              msg += filepath.string();
              throw std::runtime_error(msg.c_str());
            }
        }

        private:
          typedef std::tr1::unordered_map<std::string, ContentLoader*> LoadersContainer;
          LoadersContainer mLoaders;
    };

130 131
    Ptr World::getPtrViaHandle (const std::string& handle, Ptr::CellStore& cell)
    {
132
        if (MWWorld::LiveCellRef<ESM::Activator> *ref =
133
            searchViaHandle (handle, cell.mActivators))
134
            return Ptr (ref, &cell);
135
        if (MWWorld::LiveCellRef<ESM::Potion> *ref = searchViaHandle (handle, cell.mPotions))
136
            return Ptr (ref, &cell);
137
        if (MWWorld::LiveCellRef<ESM::Apparatus> *ref = searchViaHandle (handle, cell.mAppas))
138
            return Ptr (ref, &cell);
139
        if (MWWorld::LiveCellRef<ESM::Armor> *ref = searchViaHandle (handle, cell.mArmors))
140
            return Ptr (ref, &cell);
141
        if (MWWorld::LiveCellRef<ESM::Book> *ref = searchViaHandle (handle, cell.mBooks))
142
            return Ptr (ref, &cell);
143
        if (MWWorld::LiveCellRef<ESM::Clothing> *ref = searchViaHandle (handle, cell.mClothes))
144
            return Ptr (ref, &cell);
145
        if (MWWorld::LiveCellRef<ESM::Container> *ref =
146
            searchViaHandle (handle, cell.mContainers))
147
            return Ptr (ref, &cell);
148
        if (MWWorld::LiveCellRef<ESM::Creature> *ref =
149
            searchViaHandle (handle, cell.mCreatures))
150
            return Ptr (ref, &cell);
151
        if (MWWorld::LiveCellRef<ESM::Door> *ref = searchViaHandle (handle, cell.mDoors))
152
            return Ptr (ref, &cell);
153
        if (MWWorld::LiveCellRef<ESM::Ingredient> *ref =
154
            searchViaHandle (handle, cell.mIngreds))
155
            return Ptr (ref, &cell);
156
        if (MWWorld::LiveCellRef<ESM::Light> *ref = searchViaHandle (handle, cell.mLights))
157
            return Ptr (ref, &cell);
scrawl's avatar
scrawl committed
158
        if (MWWorld::LiveCellRef<ESM::Lockpick> *ref = searchViaHandle (handle, cell.mLockpicks))
159
            return Ptr (ref, &cell);
160
        if (MWWorld::LiveCellRef<ESM::Miscellaneous> *ref = searchViaHandle (handle, cell.mMiscItems))
161
            return Ptr (ref, &cell);
162
        if (MWWorld::LiveCellRef<ESM::NPC> *ref = searchViaHandle (handle, cell.mNpcs))
163
            return Ptr (ref, &cell);
164
        if (MWWorld::LiveCellRef<ESM::Probe> *ref = searchViaHandle (handle, cell.mProbes))
165
            return Ptr (ref, &cell);
166
        if (MWWorld::LiveCellRef<ESM::Repair> *ref = searchViaHandle (handle, cell.mRepairs))
167
            return Ptr (ref, &cell);
168
        if (MWWorld::LiveCellRef<ESM::Static> *ref = searchViaHandle (handle, cell.mStatics))
169
            return Ptr (ref, &cell);
170
        if (MWWorld::LiveCellRef<ESM::Weapon> *ref = searchViaHandle (handle, cell.mWeapons))
171 172 173 174 175
            return Ptr (ref, &cell);
        return Ptr();
    }


176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
    int World::getDaysPerMonth (int month) const
    {
        switch (month)
        {
            case 0: return 31;
            case 1: return 28;
            case 2: return 31;
            case 3: return 30;
            case 4: return 31;
            case 5: return 30;
            case 6: return 31;
            case 7: return 31;
            case 8: return 30;
            case 9: return 31;
            case 10: return 30;
            case 11: return 31;
        }
193

194 195
        throw std::runtime_error ("month out of range");
    }
196

Marc Zinnschlag's avatar
Marc Zinnschlag committed
197 198
    void World::adjustSky()
    {
scrawl's avatar
scrawl committed
199
        if (mSky && (isCellExterior() || isCellQuasiExterior()))
Marc Zinnschlag's avatar
Marc Zinnschlag committed
200
        {
201 202 203
            mRendering->skySetHour (mGlobalVariables->getFloat ("gamehour"));
            mRendering->skySetDate (mGlobalVariables->getInt ("day"),
                mGlobalVariables->getInt ("month"));
scrawl's avatar
scrawl committed
204

205
            mRendering->skyEnable();
Marc Zinnschlag's avatar
Marc Zinnschlag committed
206
        }
scrawl's avatar
scrawl committed
207
        else
208
            mRendering->skyDisable();
Marc Zinnschlag's avatar
Marc Zinnschlag committed
209 210
    }

211
    World::World (OEngine::Render::OgreRenderer& renderer,
212
        const Files::Collections& fileCollections,
213
        const std::vector<std::string>& contentFiles,
scrawl's avatar
scrawl committed
214
        const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir,
Marc Zinnschlag's avatar
Marc Zinnschlag committed
215
        ToUTF8::Utf8Encoder* encoder, const std::map<std::string,std::string>& fallbackMap, int mActivationDistanceOverride)
216
    : mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0),
scrawl's avatar
scrawl committed
217
      mSky (true), mCells (mStore, mEsm),
scrawl's avatar
scrawl committed
218
      mActivationDistanceOverride (mActivationDistanceOverride),
219
      mFallback(fallbackMap), mPlayIntro(0), mTeleportEnabled(true), mLevitationEnabled(false),
scrawl's avatar
scrawl committed
220
      mFacedDistance(FLT_MAX), mGodMode(false), mGoToJail(false)
221
    {
222
        mPhysics = new PhysicsSystem(renderer);
223
        mPhysEngine = mPhysics->getEngine();
224

225
        mRendering = new MWRender::RenderingManager(renderer, resDir, cacheDir, mPhysEngine,&mFallback);
226

scrawl's avatar
scrawl committed
227 228
        mPhysEngine->setSceneManager(renderer.getScene());

229
        mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback);
230

231
        // NOTE: We might need to reserve one more for the running game / save.
232
        mEsm.resize(contentFiles.size());
scrawl's avatar
scrawl committed
233 234
        Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
        listener->loadingOn();
235

236 237 238
        GameContentLoader gameContentLoader(*listener);
        EsmLoader esmLoader(mStore, mEsm, encoder, *listener);
        OmwLoader omwLoader(*listener);
239

240 241 242 243
        gameContentLoader.addLoader(".esm", &esmLoader);
        gameContentLoader.addLoader(".esp", &esmLoader);
        gameContentLoader.addLoader(".omwgame", &omwLoader);
        gameContentLoader.addLoader(".omwaddon", &omwLoader);
244

245
        loadContentFiles(fileCollections, contentFiles, gameContentLoader);
246

scrawl's avatar
scrawl committed
247
        listener->loadingOff();
248

249 250 251 252
        // insert records that may not be present in all versions of MW
        if (mEsm[0].getFormat() == 0)
            ensureNeededRecords();

253
        mStore.setUp();
254
        mStore.movePlayerRecord();
255

256
        mGlobalVariables = new Globals (mStore);
257

scrawl's avatar
scrawl committed
258 259 260 261 262
        mWorldScene = new Scene(*mRendering, mPhysics);
    }

    void World::startNewGame()
    {
scrawl's avatar
scrawl committed
263 264 265
        mGoToJail = false;
        mLevitationEnabled = true;
        mTeleportEnabled = true;
scrawl's avatar
scrawl committed
266 267 268 269 270 271 272 273 274
        mWorldScene->changeToVoid();

        mStore.clearDynamic();
        mStore.setUp();

        mCells.clear();

        // Rebuild player
        setupPlayer();
275
        mPlayer->setCell(NULL);
scrawl's avatar
scrawl committed
276 277 278 279 280
        MWWorld::Ptr player = mPlayer->getPlayer();

        // removes NpcStats, ContainerStore etc
        player.getRefData().setCustomData(NULL);

281 282 283
        renderPlayer();
        mRendering->resetCamera();

scrawl's avatar
scrawl committed
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
        // make sure to do this so that local scripts from items that were in the players inventory are removed
        mLocalScripts.clear();

        MWBase::Environment::get().getWindowManager()->updatePlayer();

        ESM::Position pos;
        const int cellSize = 8192;
        pos.pos[0] = cellSize/2;
        pos.pos[1] = cellSize/2;
        pos.pos[2] = 0;
        pos.rot[0] = 0;
        pos.rot[1] = 0;
        pos.rot[2] = 0;
        mWorldScene->changeToExteriorCell(pos);


        // enable collision
        if(!mPhysics->toggleCollisionMode())
            mPhysics->toggleCollisionMode();

        // FIXME: should be set to 1, but the sound manager won't pause newly started sounds
        mPlayIntro = 2;

        // global variables
        delete mGlobalVariables;
        mGlobalVariables = new Globals (mStore);
310

scrawl's avatar
scrawl committed
311 312
        // set new game mark
        mGlobalVariables->setInt ("chargenstate", 1);
313 314
        mGlobalVariables->setInt ("pcrace", 3);

scrawl's avatar
scrawl committed
315 316 317
        // we don't want old weather to persist on a new game
        delete mWeatherManager;
        mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback);
Sebastian Wick's avatar
Sebastian Wick committed
318

scrawl's avatar
scrawl committed
319
        MWBase::Environment::get().getScriptManager()->resetGlobalScripts();
320
    }
321

Jason Hooks's avatar
Jason Hooks committed
322

323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
    void World::ensureNeededRecords()
    {
        if (!mStore.get<ESM::GameSetting>().search("sCompanionShare"))
        {
            ESM::GameSetting sCompanionShare;
            sCompanionShare.mId = "sCompanionShare";
            ESM::Variant value;
            value.setType(ESM::VT_String);
            value.setString("Companion Share");
            sCompanionShare.mValue = value;
            mStore.insertStatic(sCompanionShare);
        }
        if (!mStore.get<ESM::Global>().search("dayspassed"))
        {
            // vanilla Morrowind does not define dayspassed.
            ESM::Global dayspassed;
            dayspassed.mId = "dayspassed";
            ESM::Variant value;
            value.setType(ESM::VT_Long);
            value.setInteger(1); // but the addons start counting at 1 :(
            dayspassed.mValue = value;
            mStore.insertStatic(dayspassed);
        }
        if (!mStore.get<ESM::GameSetting>().search("fWereWolfRunMult"))
        {
            ESM::GameSetting fWereWolfRunMult;
            fWereWolfRunMult.mId = "fWereWolfRunMult";
            ESM::Variant value;
            value.setType(ESM::VT_Float);
            value.setFloat(1.f);
            fWereWolfRunMult.mValue = value;
            mStore.insertStatic(fWereWolfRunMult);
        }
    }

358 359
    World::~World()
    {
360
        delete mWeatherManager;
Marc Zinnschlag's avatar
Marc Zinnschlag committed
361
        delete mWorldScene;
362
        delete mGlobalVariables;
363
        delete mRendering;
Sebastian Wick's avatar
Sebastian Wick committed
364
        delete mPhysics;
365 366

        delete mPlayer;
367
    }
Sebastian Wick's avatar
Sebastian Wick committed
368 369 370 371

    const ESM::Cell *World::getExterior (const std::string& cellName) const
    {
        // first try named cells
372 373
        const ESM::Cell *cell = mStore.get<ESM::Cell>().searchExtByName (cellName);
        if (cell != 0) {
Sebastian Wick's avatar
Sebastian Wick committed
374
            return cell;
375
        }
Sebastian Wick's avatar
Sebastian Wick committed
376 377

        // didn't work -> now check for regions
378 379 380
        const MWWorld::Store<ESM::Region> &regions = mStore.get<ESM::Region>();
        MWWorld::Store<ESM::Region>::iterator it = regions.begin();
        for (; it != regions.end(); ++it)
Sebastian Wick's avatar
Sebastian Wick committed
381
        {
lazydev's avatar
lazydev committed
382
            if (Misc::StringUtils::ciEqual(cellName, it->mName))
Sebastian Wick's avatar
Sebastian Wick committed
383
            {
384
                return mStore.get<ESM::Cell>().searchExtByRegion(it->mId);
Sebastian Wick's avatar
Sebastian Wick committed
385 386 387 388 389
            }
        }

        return 0;
    }
Marc Zinnschlag's avatar
Marc Zinnschlag committed
390

Marc Zinnschlag's avatar
Marc Zinnschlag committed
391
    const MWWorld::Fallback *World::getFallback() const
392 393 394 395
    {
        return &mFallback;
    }

396 397
    Ptr::CellStore *World::getExterior (int x, int y)
    {
398
        return mCells.getExterior (x, y);
399
    }
Marc Zinnschlag's avatar
Marc Zinnschlag committed
400

401
    Ptr::CellStore *World::getInterior (const std::string& name)
402
    {
403
        return mCells.getInterior (name);
404
    }
405

406
    MWWorld::Player& World::getPlayer()
407
    {
408
        return *mPlayer;
409
    }
410

Artem Kotsynyak's avatar
Artem Kotsynyak committed
411
    const MWWorld::ESMStore& World::getStore() const
412 413 414
    {
        return mStore;
    }
Marc Zinnschlag's avatar
Marc Zinnschlag committed
415

416
    std::vector<ESM::ESMReader>& World::getEsmReader()
417 418 419
    {
        return mEsm;
    }
420

421
    LocalScripts& World::getLocalScripts()
422 423 424
    {
        return mLocalScripts;
    }
425

426 427
    bool World::hasCellChanged() const
    {
428
        return mWorldScene->hasCellChanged();
429
    }
430

431
    Globals::Data& World::getGlobalVariable (const std::string& name)
432
    {
433
        return (*mGlobalVariables)[name];
434
    }
435

Marc Zinnschlag's avatar
Marc Zinnschlag committed
436 437 438 439 440
    Globals::Data World::getGlobalVariable (const std::string& name) const
    {
        return (*mGlobalVariables)[name];
    }

441 442 443
    char World::getGlobalVariableType (const std::string& name) const
    {
        return mGlobalVariables->getType (name);
444 445
    }

446 447 448 449
    std::vector<std::string> World::getGlobals () const
    {
        return mGlobalVariables->getGlobals();
    }
450

451 452 453 454 455 456
    std::string World::getCurrentCellName () const
    {
        std::string name;

        Ptr::CellStore *cell = mWorldScene->getCurrentCell();
        if (cell->mCell->isExterior())
457
        {
458
            if (cell->mCell->mName != "")
459
            {
460
                name = cell->mCell->mName;
461 462 463
            }
            else
            {
464 465 466 467 468
                const ESM::Region* region =
                    MWBase::Environment::get().getWorld()->getStore().get<ESM::Region>().search(cell->mCell->mRegion);
                if (region)
                    name = region->mName;
                else
469
                {
470 471 472
                    const ESM::GameSetting *setting =
                        MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().search("sDefaultCellname");

473 474
                    if (setting && setting->mValue.getType()==ESM::VT_String)
                        name = setting->mValue.getString();
475 476
                }

477 478 479 480
            }
        }
        else
        {
481
            name = cell->mCell->mName;
482 483
        }

484 485
        return name;
    }
486

487 488 489 490 491
    void World::removeRefScript (MWWorld::RefData *ref)
    {
        mLocalScripts.remove (ref);
    }

492
    Ptr World::searchPtr (const std::string& name, bool activeOnly)
493
    {
494
        Ptr ret;
495 496 497
        // the player is always in an active cell.
        if (name=="player")
        {
498
            return mPlayer->getPlayer();
499
        }
500

501 502 503 504 505 506
        Ptr ptr = Class::get (mPlayer->getPlayer()).
            getContainerStore (mPlayer->getPlayer()).search (name);

        if (!ptr.isEmpty())
            return ptr;

507 508
        std::string lowerCaseName = Misc::StringUtils::lowerCase(name);

509
        // active cells
510
        for (Scene::CellStoreCollection::const_iterator iter (mWorldScene->getActiveCells().begin());
511
            iter!=mWorldScene->getActiveCells().end(); ++iter)
512
        {
513
            Ptr::CellStore* cellstore = *iter;
514
            Ptr ptr = mCells.getPtr (lowerCaseName, *cellstore, true);
515

516
            if (!ptr.isEmpty())
517
                return ptr;
518
        }
519

520 521
        if (!activeOnly)
        {
522
            ret = mCells.getPtr (lowerCaseName);
523
        }
524 525
        return ret;
    }
526

527 528 529 530 531
    Ptr World::getPtr (const std::string& name, bool activeOnly)
    {
        Ptr ret = searchPtr(name, activeOnly);
        if (!ret.isEmpty())
            return ret;
532 533
        throw std::runtime_error ("unknown ID: " + name);
    }
534 535

    Ptr World::getPtrViaHandle (const std::string& handle)
scrawl's avatar
scrawl committed
536 537 538 539 540 541 542 543
    {
        Ptr res = searchPtrViaHandle (handle);
        if (res.isEmpty ())
            throw std::runtime_error ("unknown Ogre handle: " + handle);
        return res;
    }

    Ptr World::searchPtrViaHandle (const std::string& handle)
544
    {
545 546
        if (mPlayer->getPlayer().getRefData().getHandle()==handle)
            return mPlayer->getPlayer();
547
        for (Scene::CellStoreCollection::const_iterator iter (mWorldScene->getActiveCells().begin());
548
            iter!=mWorldScene->getActiveCells().end(); ++iter)
549
        {
550 551
            Ptr::CellStore* cellstore = *iter;
            Ptr ptr = getPtrViaHandle (handle, *cellstore);
552 553 554 555 556

            if (!ptr.isEmpty())
                return ptr;
        }

557
        return MWWorld::Ptr();
558 559
    }

560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
    void World::addContainerScripts(const Ptr& reference, Ptr::CellStore * cell)
    {
        if( reference.getTypeName()==typeid (ESM::Container).name() ||
            reference.getTypeName()==typeid (ESM::NPC).name() ||
            reference.getTypeName()==typeid (ESM::Creature).name())
        {
            MWWorld::ContainerStore& container = MWWorld::Class::get(reference).getContainerStore(reference);
            for(MWWorld::ContainerStoreIterator it = container.begin(); it != container.end(); ++it)
            {
                std::string script = MWWorld::Class::get(*it).getScript(*it);
                if(script != "")
                {
                    MWWorld::Ptr item = *it;
                    item.mCell = cell;
                    mLocalScripts.add (script, item);
                }
            }
        }
    }

580
    void World::enable (const Ptr& reference)
581
    {
582
        if (!reference.getRefData().isEnabled())
583
        {
584
            reference.getRefData().enable();
585

586 587
            if(mWorldScene->getActiveCells().find (reference.getCell()) != mWorldScene->getActiveCells().end() && reference.getRefData().getCount())
                mWorldScene->addObjectToScene (reference);
588 589
        }
    }
590

591 592 593 594 595 596 597 598
    void World::removeContainerScripts(const Ptr& reference)
    {
        if( reference.getTypeName()==typeid (ESM::Container).name() ||
            reference.getTypeName()==typeid (ESM::NPC).name() ||
            reference.getTypeName()==typeid (ESM::Creature).name())
        {
            MWWorld::ContainerStore& container = MWWorld::Class::get(reference).getContainerStore(reference);
            for(MWWorld::ContainerStoreIterator it = container.begin(); it != container.end(); ++it)
599
            {
600 601
                std::string script = MWWorld::Class::get(*it).getScript(*it);
                if(script != "")
602
                {
603 604
                    MWWorld::Ptr item = *it;
                    mLocalScripts.remove (item);
605 606
                }
            }
607 608
        }
    }
609

610
    void World::disable (const Ptr& reference)
611
    {
612
        if (reference.getRefData().isEnabled())
613
        {
614
            reference.getRefData().disable();
615

616 617
            if(mWorldScene->getActiveCells().find (reference.getCell())!=mWorldScene->getActiveCells().end() && reference.getRefData().getCount())
                mWorldScene->removeObjectFromScene (reference);
618
        }
619
    }
620

Marc Zinnschlag's avatar
Marc Zinnschlag committed
621 622
    void World::advanceTime (double hours)
    {
623 624
        MWBase::Environment::get().getMechanicsManager()->advanceTime(hours*3600);

625 626
        mWeatherManager->advanceTime (hours);

Marc Zinnschlag's avatar
Marc Zinnschlag committed
627
        hours += mGlobalVariables->getFloat ("gamehour");
628

Marc Zinnschlag's avatar
Marc Zinnschlag committed
629
        setHour (hours);
630

631
        int days = hours / 24;
632

633 634
        if (days>0)
            mGlobalVariables->setInt ("dayspassed", days + mGlobalVariables->getInt ("dayspassed"));
Marc Zinnschlag's avatar
Marc Zinnschlag committed
635
    }
636

Marc Zinnschlag's avatar
Marc Zinnschlag committed
637 638 639 640
    void World::setHour (double hour)
    {
        if (hour<0)
            hour = 0;
641

Marc Zinnschlag's avatar
Marc Zinnschlag committed
642
        int days = hour / 24;
643

Marc Zinnschlag's avatar
Marc Zinnschlag committed
644
        hour = std::fmod (hour, 24);
645

Marc Zinnschlag's avatar
Marc Zinnschlag committed
646
        mGlobalVariables->setFloat ("gamehour", hour);
647

648
        mRendering->skySetHour (hour);
649

scrawl's avatar
scrawl committed
650
        mWeatherManager->setHour (hour);
651

Marc Zinnschlag's avatar
Marc Zinnschlag committed
652
        if (days>0)
653
            setDay (days + mGlobalVariables->getInt ("day"));
Marc Zinnschlag's avatar
Marc Zinnschlag committed
654
    }
655

Marc Zinnschlag's avatar
Marc Zinnschlag committed
656 657
    void World::setDay (int day)
    {
658 659
        if (day<1)
            day = 1;
660 661

        int month = mGlobalVariables->getInt ("month");
662

663
        while (true)
Marc Zinnschlag's avatar
Marc Zinnschlag committed
664
        {
665
            int days = getDaysPerMonth (month);
666
            if (day<=days)
667
                break;
668

669 670 671 672 673 674 675 676 677
            if (month<11)
            {
                ++month;
            }
            else
            {
                month = 0;
                mGlobalVariables->setInt ("year", mGlobalVariables->getInt ("year")+1);
            }
678

679
            day -= days;
680 681 682
        }

        mGlobalVariables->setInt ("day", day);
683 684
        mGlobalVariables->setInt ("month", month);

685
        mRendering->skySetDate (day, month);
686

scrawl's avatar
scrawl committed
687
        mWeatherManager->setDate (day, month);
688 689
    }

690 691 692 693
    void World::setMonth (int month)
    {
        if (month<0)
            month = 0;
694

695 696
        int years = month / 12;
        month = month % 12;
697

698
        int days = getDaysPerMonth (month);
699

700 701
        if (mGlobalVariables->getInt ("day")>days)
            mGlobalVariables->setInt ("day", days);
702

703
        mGlobalVariables->setInt ("month", month);
704

705 706 707
        if (years>0)
            mGlobalVariables->setInt ("year", years+mGlobalVariables->getInt ("year"));

708
        mRendering->skySetDate (mGlobalVariables->getInt ("day"), month);
709
    }
710

scrawl's avatar
scrawl committed
711 712 713 714 715 716 717 718 719 720
    int World::getDay()
    {
        return mGlobalVariables->getInt("day");
    }

    int World::getMonth()
    {
        return mGlobalVariables->getInt("month");
    }

721 722 723 724 725 726
    TimeStamp World::getTimeStamp() const
    {
        return TimeStamp (mGlobalVariables->getFloat ("gamehour"),
            mGlobalVariables->getInt ("dayspassed"));
    }

727
    bool World::toggleSky()
728 729 730 731
    {
        if (mSky)
        {
            mSky = false;
732
            mRendering->skyDisable();
733
            return false;
734 735 736 737
        }
        else
        {
            mSky = true;
738
            mRendering->skyEnable();
739
            return true;
740 741
        }
    }
742

743 744
    int World::getMasserPhase() const
    {
745
        return mRendering->skyGetMasserPhase();
746
    }
747

748 749
    int World::getSecundaPhase() const
    {
750
        return mRendering->skyGetSecundaPhase();
751
    }
752

753 754
    void World::setMoonColour (bool red)
    {
755
        mRendering->skySetMoonColour (red);
756
    }
757

758 759
    float World::getTimeScaleFactor()