diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 4051480c73..6be3f0e3e3 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -90,7 +90,7 @@ QT4_WRAP_UI(UI_HDRS ${LAUNCHER_UI}) include(${QT_USE_FILE}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) if(NOT WIN32) - include_directories(${LIBUNSHIELD_INCLUDE}) + include_directories(${LIBUNSHIELD_INCLUDE_DIR}) endif(NOT WIN32) # Main executable diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index ce53dcf5cb..e864e4ed26 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -358,7 +358,7 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, setAcceptDrops(true); - mDoubleClickActions.insert (std::make_pair (0, Action_InPlaceEdit)); + mDoubleClickActions.insert (std::make_pair (Qt::NoModifier, Action_InPlaceEdit)); mDoubleClickActions.insert (std::make_pair (Qt::ShiftModifier, Action_EditRecord)); mDoubleClickActions.insert (std::make_pair (Qt::ControlModifier, Action_View)); mDoubleClickActions.insert (std::make_pair (Qt::ShiftModifier | Qt::ControlModifier, Action_EditRecordAndClose)); diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index c755814883..ce213b316a 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -138,6 +138,9 @@ namespace MWBase /// @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, diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 7753dc5689..5910c471b3 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -537,15 +537,14 @@ namespace MWClass const MWBase::World *world = MWBase::Environment::get().getWorld(); const MWMechanics::MagicEffects &mageffects = stats.getMagicEffects(); - const float normalizedEncumbrance = getNormalizedEncumbrance(ptr); - bool running = ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run); // The Run speed difference for creatures comes from the animation speed difference (see runStateToWalkState in character.cpp) float runSpeed = walkSpeed; float moveSpeed; - if(normalizedEncumbrance >= 1.0f) + + if(getEncumbrance(ptr) > getCapacity(ptr)) moveSpeed = 0.0f; else if(canFly(ptr) || (mageffects.get(ESM::MagicEffect::Levitate).getMagnitude() > 0 && world->isLevitationEnabled())) @@ -553,6 +552,7 @@ namespace MWClass float flySpeed = 0.01f*(stats.getAttribute(ESM::Attribute::Speed).getModified() + mageffects.get(ESM::MagicEffect::Levitate).getMagnitude()); flySpeed = gmst.fMinFlySpeed->getFloat() + flySpeed*(gmst.fMaxFlySpeed->getFloat() - gmst.fMinFlySpeed->getFloat()); + const float normalizedEncumbrance = getNormalizedEncumbrance(ptr); flySpeed *= 1.0f - gmst.fEncumberedMoveEffect->getFloat() * normalizedEncumbrance; flySpeed = std::max(0.0f, flySpeed); moveSpeed = flySpeed; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index ef03d285ca..f7949f1ece 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -23,39 +23,6 @@ #include -namespace -{ - /// @return is \a ptr allowed to take/use \a item or is it a crime? - bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, MWWorld::Ptr& victim) - { - const std::string& owner = item.getCellRef().getOwner(); - bool isOwned = !owner.empty() && owner != "player"; - - const std::string& faction = item.getCellRef().getFaction(); - bool isFactionOwned = false; - if (!faction.empty() && ptr.getClass().isNpc()) - { - const std::map& factions = ptr.getClass().getNpcStats(ptr).getFactionRanks(); - std::map::const_iterator found = factions.find(Misc::StringUtils::lowerCase(faction)); - if (found == factions.end() - || found->second < item.getCellRef().getFactionRank()) - isFactionOwned = true; - } - - const std::string& globalVariable = item.getCellRef().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); - - return (!isOwned && !isFactionOwned); - } -} - namespace MWMechanics { void MechanicsManager::buildPlayer() @@ -879,6 +846,35 @@ namespace MWMechanics mAI = true; } + bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, MWWorld::Ptr& victim) + { + const std::string& owner = item.getCellRef().getOwner(); + bool isOwned = !owner.empty() && owner != "player"; + + const std::string& faction = item.getCellRef().getFaction(); + bool isFactionOwned = false; + if (!faction.empty() && ptr.getClass().isNpc()) + { + const std::map& factions = ptr.getClass().getNpcStats(ptr).getFactionRanks(); + std::map::const_iterator found = factions.find(Misc::StringUtils::lowerCase(faction)); + if (found == factions.end() + || found->second < item.getCellRef().getFactionRank()) + isFactionOwned = true; + } + + const std::string& globalVariable = item.getCellRef().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); + + return (!isOwned && !isFactionOwned); + } + bool MechanicsManager::sleepInBed(const MWWorld::Ptr &ptr, const MWWorld::Ptr &bed) { if (ptr.getClass().getNpcStats(ptr).isWerewolf()) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index dc5479ecd8..9f9e85c5af 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -130,6 +130,9 @@ namespace MWMechanics /// @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); diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index ecaf4253e8..a88c5a1015 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -41,7 +41,8 @@ namespace MWScript } catch (...) { - MWBase::Environment::get().getJournal()->setJournalIndex(quest, index); + if (MWBase::Environment::get().getJournal()->getJournalIndex(quest) < index) + MWBase::Environment::get().getJournal()->setJournalIndex(quest, index); } } }; diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index 8270c4e6b2..d9778c053e 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -90,13 +90,32 @@ namespace MWScript void GlobalScripts::addStartup() { - addScript ("main"); + // make list of global scripts to be added + std::vector scripts; + + scripts.push_back ("main"); for (MWWorld::Store::iterator iter = mStore.get().begin(); iter != mStore.get().end(); ++iter) { - addScript (iter->mScript); + scripts.push_back (iter->mScript); + } + + // add scripts + for (std::vector::const_iterator iter (scripts.begin()); + iter!=scripts.end(); ++iter) + { + try + { + addScript (*iter); + } + catch (const std::exception& exception) + { + std::cerr + << "Failed to add start script " << *iter << " because an exception has " + << "been thrown: " << exception.what() << std::endl; + } } } diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 52021839d9..d8d13a9211 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -311,6 +311,9 @@ namespace MWScript std::string InterpreterContext::getNPCRank() const { + if (getReferenceImp().getClass().getNpcStats(getReferenceImp()).getFactionRanks().empty()) + throw std::runtime_error("getNPCRank(): NPC is not in a faction"); + const std::map& ranks = getReferenceImp().getClass().getNpcStats (getReferenceImp()).getFactionRanks(); std::map::const_iterator it = ranks.begin(); @@ -347,6 +350,9 @@ namespace MWScript MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayerPtr(); + if (getReferenceImp().getClass().getNpcStats(getReferenceImp()).getFactionRanks().empty()) + throw std::runtime_error("getPCRank(): NPC is not in a faction"); + std::string factionId = getReferenceImp().getClass().getNpcStats (getReferenceImp()).getFactionRanks().begin()->first; const std::map& ranks = player.getClass().getNpcStats (player).getFactionRanks(); @@ -374,6 +380,9 @@ namespace MWScript MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayerPtr(); + if (getReferenceImp().getClass().getNpcStats(getReferenceImp()).getFactionRanks().empty()) + throw std::runtime_error("getPCNextRank(): NPC is not in a faction"); + std::string factionId = getReferenceImp().getClass().getNpcStats (getReferenceImp()).getFactionRanks().begin()->first; const std::map& ranks = player.getClass().getNpcStats (player).getFactionRanks(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5d07a26a09..4c2bd669b6 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1294,7 +1294,7 @@ namespace MWWorld if (force || !isFlying(ptr)) { - Ogre::Vector3 traced = mPhysics->traceDown(ptr, 300); + Ogre::Vector3 traced = mPhysics->traceDown(ptr, 500); if (traced.z < pos.pos[2]) pos.pos[2] = traced.z; } @@ -2879,7 +2879,8 @@ namespace MWWorld ContainerStore& store = ptr.getClass().getContainerStore(ptr); for (ContainerStoreIterator it = store.begin(); it != store.end(); ++it) //Move all stolen stuff into chest { - if (!it->getCellRef().getOwner().empty() && it->getCellRef().getOwner() != "player") //Not owned by no one/player? + 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); diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index 019bf41611..0020669815 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -85,6 +85,11 @@ struct Land char mColours[3 * LAND_NUM_VERTS]; int mDataTypes; + // WNAM appears to contain the global map image for this cell. Probably a palette-based format, + // since there's only 1 byte for each pixel. + // Currently unused (global map is drawn on the fly in OpenMW, takes ~1/2 second at startup for Morrowind.esm). + // The problem with using the original data is that we would need to exactly replicate the TES CS's algorithm + // for drawing the global map in OpenCS, in order to get seamless edges when creating landmass mods. uint8_t mWnam[81]; short mUnk1; uint8_t mUnk2; diff --git a/components/interpreter/defines.cpp b/components/interpreter/defines.cpp index 6f3b5bb5aa..94916ee851 100644 --- a/components/interpreter/defines.cpp +++ b/components/interpreter/defines.cpp @@ -4,10 +4,12 @@ #include #include #include +#include namespace Interpreter{ - bool Check(const std::string& str, const std::string& escword, unsigned int* i, unsigned int* start){ + bool check(const std::string& str, const std::string& escword, unsigned int* i, unsigned int* start) + { bool retval = str.find(escword) == 0; if(retval){ (*i) += escword.length(); @@ -18,170 +20,181 @@ namespace Interpreter{ std::vector globals; - bool longerStr(const std::string& a, const std::string& b){ + bool longerStr(const std::string& a, const std::string& b) + { return a.length() > b.length(); } - std::string fixDefinesReal(std::string text, char eschar, bool isBook, Context& context){ + std::string fixDefinesReal(std::string text, char eschar, bool isBook, Context& context) + { unsigned int start = 0; std::ostringstream retval; - for(unsigned int i = 0; i < text.length(); i++){ - if(text[i] == eschar){ + for(unsigned int i = 0; i < text.length(); i++) + { + if(text[i] == eschar) + { retval << text.substr(start, i - start); std::string temp = text.substr(i+1, 100); transform(temp.begin(), temp.end(), temp.begin(), ::tolower); - bool found; - - if( (found = Check(temp, "actionslideright", &i, &start))){ - retval << context.getActionBinding("#{sRight}"); - } - else if((found = Check(temp, "actionreadymagic", &i, &start))){ - retval << context.getActionBinding("#{sReady_Magic}"); - } - else if((found = Check(temp, "actionprevweapon", &i, &start))){ - retval << "PLACEHOLDER_ACTION_PREV_WEAPON"; - } - else if((found = Check(temp, "actionnextweapon", &i, &start))){ - retval << "PLACEHOLDER_ACTION_PREV_WEAPON"; - } - else if((found = Check(temp, "actiontogglerun", &i, &start))){ - retval << context.getActionBinding("#{sAuto_Run}"); - } - else if((found = Check(temp, "actionslideleft", &i, &start))){ - retval << context.getActionBinding("#{sLeft}"); - } - else if((found = Check(temp, "actionreadyitem", &i, &start))){ - retval << context.getActionBinding("#{sReady_Weapon}"); - } - else if((found = Check(temp, "actionprevspell", &i, &start))){ - retval << "PLACEHOLDER_ACTION_PREV_SPELL"; - } - else if((found = Check(temp, "actionnextspell", &i, &start))){ - retval << "PLACEHOLDER_ACTION_NEXT_SPELL"; - } - else if((found = Check(temp, "actionrestmenu", &i, &start))){ - retval << context.getActionBinding("#{sRestKey}"); - } - else if((found = Check(temp, "actionmenumode", &i, &start))){ - retval << context.getActionBinding("#{sInventory}"); - } - else if((found = Check(temp, "actionactivate", &i, &start))){ - retval << context.getActionBinding("#{sActivate}"); - } - else if((found = Check(temp, "actionjournal", &i, &start))){ - retval << context.getActionBinding("#{sJournal}"); - } - else if((found = Check(temp, "actionforward", &i, &start))){ - retval << context.getActionBinding("#{sForward}"); - } - else if((found = Check(temp, "pccrimelevel", &i, &start))){ - retval << context.getPCBounty(); - } - else if((found = Check(temp, "actioncrouch", &i, &start))){ - retval << context.getActionBinding("#{sCrouch_Sneak}"); - } - else if((found = Check(temp, "actionjump", &i, &start))){ - retval << context.getActionBinding("#{sJump}"); - } - else if((found = Check(temp, "actionback", &i, &start))){ - retval << context.getActionBinding("#{sBack}"); - } - else if((found = Check(temp, "actionuse", &i, &start))){ - retval << context.getActionBinding("#{sUse}"); - } - else if((found = Check(temp, "actionrun", &i, &start))){ - retval << context.getActionBinding("#{sRun}"); - } - else if((found = Check(temp, "pcclass", &i, &start))){ - retval << context.getPCClass(); - } - else if((found = Check(temp, "pcrace", &i, &start))){ - retval << context.getPCRace(); - } - else if((found = Check(temp, "pcname", &i, &start))){ - retval << context.getPCName(); - } - else if((found = Check(temp, "cell", &i, &start))){ - retval << context.getCurrentCellName(); - } - - else if(eschar == '%' && !isBook) { // In Dialogue, not messagebox - if( (found = Check(temp, "faction", &i, &start))){ - retval << context.getNPCFaction(); + bool found = false; + try + { + if( (found = check(temp, "actionslideright", &i, &start))){ + retval << context.getActionBinding("#{sRight}"); } - else if((found = Check(temp, "nextpcrank", &i, &start))){ - retval << context.getPCNextRank(); + else if((found = check(temp, "actionreadymagic", &i, &start))){ + retval << context.getActionBinding("#{sReady_Magic}"); } - else if((found = Check(temp, "pcnextrank", &i, &start))){ - retval << context.getPCNextRank(); + else if((found = check(temp, "actionprevweapon", &i, &start))){ + retval << "PLACEHOLDER_ACTION_PREV_WEAPON"; } - else if((found = Check(temp, "pcrank", &i, &start))){ - retval << context.getPCRank(); + else if((found = check(temp, "actionnextweapon", &i, &start))){ + retval << "PLACEHOLDER_ACTION_PREV_WEAPON"; } - else if((found = Check(temp, "rank", &i, &start))){ - retval << context.getNPCRank(); + else if((found = check(temp, "actiontogglerun", &i, &start))){ + retval << context.getActionBinding("#{sAuto_Run}"); } - - else if((found = Check(temp, "class", &i, &start))){ - retval << context.getNPCClass(); + else if((found = check(temp, "actionslideleft", &i, &start))){ + retval << context.getActionBinding("#{sLeft}"); } - else if((found = Check(temp, "race", &i, &start))){ - retval << context.getNPCRace(); + else if((found = check(temp, "actionreadyitem", &i, &start))){ + retval << context.getActionBinding("#{sReady_Weapon}"); } - else if((found = Check(temp, "name", &i, &start))){ - retval << context.getNPCName(); + else if((found = check(temp, "actionprevspell", &i, &start))){ + retval << "PLACEHOLDER_ACTION_PREV_SPELL"; } - } - else { // In messagebox or book, not dialogue - - /* empty outside dialogue */ - if( (found = Check(temp, "faction", &i, &start))); - else if((found = Check(temp, "nextpcrank", &i, &start))); - else if((found = Check(temp, "pcnextrank", &i, &start))); - else if((found = Check(temp, "pcrank", &i, &start))); - else if((found = Check(temp, "rank", &i, &start))); - - /* uses pc in messageboxes */ - else if((found = Check(temp, "class", &i, &start))){ + else if((found = check(temp, "actionnextspell", &i, &start))){ + retval << "PLACEHOLDER_ACTION_NEXT_SPELL"; + } + else if((found = check(temp, "actionrestmenu", &i, &start))){ + retval << context.getActionBinding("#{sRestKey}"); + } + else if((found = check(temp, "actionmenumode", &i, &start))){ + retval << context.getActionBinding("#{sInventory}"); + } + else if((found = check(temp, "actionactivate", &i, &start))){ + retval << context.getActionBinding("#{sActivate}"); + } + else if((found = check(temp, "actionjournal", &i, &start))){ + retval << context.getActionBinding("#{sJournal}"); + } + else if((found = check(temp, "actionforward", &i, &start))){ + retval << context.getActionBinding("#{sForward}"); + } + else if((found = check(temp, "pccrimelevel", &i, &start))){ + retval << context.getPCBounty(); + } + else if((found = check(temp, "actioncrouch", &i, &start))){ + retval << context.getActionBinding("#{sCrouch_Sneak}"); + } + else if((found = check(temp, "actionjump", &i, &start))){ + retval << context.getActionBinding("#{sJump}"); + } + else if((found = check(temp, "actionback", &i, &start))){ + retval << context.getActionBinding("#{sBack}"); + } + else if((found = check(temp, "actionuse", &i, &start))){ + retval << context.getActionBinding("#{sUse}"); + } + else if((found = check(temp, "actionrun", &i, &start))){ + retval << context.getActionBinding("#{sRun}"); + } + else if((found = check(temp, "pcclass", &i, &start))){ retval << context.getPCClass(); } - else if((found = Check(temp, "race", &i, &start))){ + else if((found = check(temp, "pcrace", &i, &start))){ retval << context.getPCRace(); } - else if((found = Check(temp, "name", &i, &start))){ + else if((found = check(temp, "pcname", &i, &start))){ retval << context.getPCName(); } - } - - /* Not a builtin, try global variables */ - if(!found){ - /* if list of globals is empty, grab it and sort it by descending string length */ - if(globals.empty()){ - globals = context.getGlobals(); - sort(globals.begin(), globals.end(), longerStr); + else if((found = check(temp, "cell", &i, &start))){ + retval << context.getCurrentCellName(); } - for(unsigned int j = 0; j < globals.size(); j++){ - if(globals[j].length() > temp.length()){ // Just in case there's a global with a huuuge name - std::string temp = text.substr(i+1, globals[j].length()); - transform(temp.begin(), temp.end(), temp.begin(), ::tolower); + else if(eschar == '%' && !isBook) { // In Dialogue, not messagebox + if( (found = check(temp, "faction", &i, &start))){ + retval << context.getNPCFaction(); + } + else if((found = check(temp, "nextpcrank", &i, &start))){ + retval << context.getPCNextRank(); + } + else if((found = check(temp, "pcnextrank", &i, &start))){ + retval << context.getPCNextRank(); + } + else if((found = check(temp, "pcrank", &i, &start))){ + retval << context.getPCRank(); + } + else if((found = check(temp, "rank", &i, &start))){ + retval << context.getNPCRank(); } - if((found = Check(temp, globals[j], &i, &start))){ - char type = context.getGlobalType(globals[j]); + else if((found = check(temp, "class", &i, &start))){ + retval << context.getNPCClass(); + } + else if((found = check(temp, "race", &i, &start))){ + retval << context.getNPCRace(); + } + else if((found = check(temp, "name", &i, &start))){ + retval << context.getNPCName(); + } + } + else { // In messagebox or book, not dialogue - switch(type){ - case 's': retval << context.getGlobalShort(globals[j]); break; - case 'l': retval << context.getGlobalLong(globals[j]); break; - case 'f': retval << context.getGlobalFloat(globals[j]); break; + /* empty outside dialogue */ + if( (found = check(temp, "faction", &i, &start))); + else if((found = check(temp, "nextpcrank", &i, &start))); + else if((found = check(temp, "pcnextrank", &i, &start))); + else if((found = check(temp, "pcrank", &i, &start))); + else if((found = check(temp, "rank", &i, &start))); + + /* uses pc in messageboxes */ + else if((found = check(temp, "class", &i, &start))){ + retval << context.getPCClass(); + } + else if((found = check(temp, "race", &i, &start))){ + retval << context.getPCRace(); + } + else if((found = check(temp, "name", &i, &start))){ + retval << context.getPCName(); + } + } + + /* Not a builtin, try global variables */ + if(!found){ + /* if list of globals is empty, grab it and sort it by descending string length */ + if(globals.empty()){ + globals = context.getGlobals(); + sort(globals.begin(), globals.end(), longerStr); + } + + for(unsigned int j = 0; j < globals.size(); j++){ + if(globals[j].length() > temp.length()){ // Just in case there's a global with a huuuge name + std::string temp = text.substr(i+1, globals[j].length()); + transform(temp.begin(), temp.end(), temp.begin(), ::tolower); + } + + if((found = check(temp, globals[j], &i, &start))){ + char type = context.getGlobalType(globals[j]); + + switch(type){ + case 's': retval << context.getGlobalShort(globals[j]); break; + case 'l': retval << context.getGlobalLong(globals[j]); break; + case 'f': retval << context.getGlobalFloat(globals[j]); break; + } + break; } - break; } } } - - /* Not found */ + catch (std::exception& e) + { + std::cerr << "Failed to replace escape character, with the following error: " << e.what() << std::endl; + std::cerr << "Full text below: " << std::endl << text << std::endl; + } + + // Not found, or error if(!found){ /* leave unmodified */ i += 1; diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 5efd0d6c99..f3b5a27f8f 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -272,7 +272,7 @@ class NiSkinData : public Record public: struct BoneTrafo { - Ogre::Matrix3 rotation; // Rotation offset from bone? + Ogre::Matrix3 rotationScale; // Rotation offset from bone, non-uniform scale Ogre::Vector3 trans; // Translation float scale; // Probably scale (always 1) }; @@ -295,7 +295,7 @@ public: void read(NIFStream *nif) { - trafo.rotation = nif->getMatrix3(); + trafo.rotationScale = nif->getMatrix3(); trafo.trans = nif->getVector3(); trafo.scale = nif->getFloat(); @@ -307,7 +307,7 @@ public: { BoneInfo &bi = bones[i]; - bi.trafo.rotation = nif->getMatrix3(); + bi.trafo.rotationScale = nif->getMatrix3(); bi.trafo.trans = nif->getVector3(); bi.trafo.scale = nif->getFloat(); bi.unknown = nif->getVector4(); diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index e62193a24e..c1b169ac88 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -133,7 +133,7 @@ public: { Transformation t; t.pos = getVector3(); - t.rotation = getMatrix3(); + t.rotationScale = getMatrix3(); t.scale = getFloat(); return t; } diff --git a/components/nif/niftypes.hpp b/components/nif/niftypes.hpp index 786c48b65e..f9235ec45d 100644 --- a/components/nif/niftypes.hpp +++ b/components/nif/niftypes.hpp @@ -35,7 +35,7 @@ namespace Nif struct Transformation { Ogre::Vector3 pos; - Ogre::Matrix3 rotation; + Ogre::Matrix3 rotationScale; float scale; static const Transformation& getIdentity() diff --git a/components/nif/node.cpp b/components/nif/node.cpp index b7ca981133..7529e602d9 100644 --- a/components/nif/node.cpp +++ b/components/nif/node.cpp @@ -42,8 +42,9 @@ void Node::getProperties(const Nif::NiTexturingProperty *&texprop, Ogre::Matrix4 Node::getLocalTransform() const { - Ogre::Matrix4 mat4 = Ogre::Matrix4(Ogre::Matrix4::IDENTITY); - mat4.makeTransform(trafo.pos, Ogre::Vector3(trafo.scale), Ogre::Quaternion(trafo.rotation)); + Ogre::Matrix4 mat4 = Ogre::Matrix4(trafo.rotationScale); + mat4.setTrans(trafo.pos); + mat4.setScale(Ogre::Vector3(trafo.rotationScale[0][0], trafo.rotationScale[1][1], trafo.rotationScale[2][2]) * trafo.scale); return mat4; } diff --git a/components/nifogre/mesh.cpp b/components/nifogre/mesh.cpp index af73df637d..c952e664db 100644 --- a/components/nifogre/mesh.cpp +++ b/components/nifogre/mesh.cpp @@ -138,9 +138,10 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape const Nif::NodeList &bones = skin->bones; for(size_t b = 0;b < bones.length();b++) { - Ogre::Matrix4 mat; - mat.makeTransform(data->bones[b].trafo.trans, Ogre::Vector3(data->bones[b].trafo.scale), - Ogre::Quaternion(data->bones[b].trafo.rotation)); + const Ogre::Matrix3& rotationScale = data->bones[b].trafo.rotationScale; + Ogre::Matrix4 mat (rotationScale); + mat.setTrans(data->bones[b].trafo.trans); + mat.setScale(Ogre::Vector3(rotationScale[0][0], rotationScale[1][1], rotationScale[2][2]) * data->bones[b].trafo.scale); mat = bones[b]->getWorldTransform() * mat; const std::vector &weights = data->bones[b].weights; diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index 9e12eec905..4f6921d89d 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -36,9 +36,17 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, if(parent) parent->addChild(bone); mNifToOgreHandleMap[node->recIndex] = bone->getHandle(); - bone->setOrientation(node->trafo.rotation); - bone->setPosition(node->trafo.pos); - bone->setScale(Ogre::Vector3(node->trafo.scale)); + // decompose the local transform into position, scale and orientation. + // this is required for cases where the rotationScale matrix includes scaling, which the NIF format allows :( + // the code would look a bit nicer if Ogre allowed setting the transform matrix of a Bone directly, but we can't do that. + Ogre::Matrix4 mat(node->getLocalTransform()); + Ogre::Vector3 position, scale; + Ogre::Quaternion orientation; + mat.decomposition(position, scale, orientation); + bone->setOrientation(orientation); + bone->setPosition(position); + bone->setScale(scale); + bone->setBindingPose(); if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index fe322a6bfe..6a66ac3d7c 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -142,10 +142,8 @@ void TerrainGrid::setVisible(bool visible) Ogre::AxisAlignedBox TerrainGrid::getWorldBoundingBox (const Ogre::Vector2& center) { - float cellSize = getStorage()->getCellWorldSize(); - - int cellX = std::floor(center.x/cellSize); - int cellY = std::floor(center.y/cellSize); + int cellX = std::floor(center.x); + int cellY = std::floor(center.y); Grid::iterator it = mGrid.find(std::make_pair(cellX, cellY)); if (it == mGrid.end())