mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-20 04:53:53 +00:00
improves animation-controlled velocity check
This commit is contained in:
commit
a6be72673c
230 changed files with 6274 additions and 1752 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -40,6 +40,7 @@ resources
|
|||
|
||||
## generated objects
|
||||
apps/openmw/config.hpp
|
||||
components/version/version.hpp
|
||||
Docs/mainpage.hpp
|
||||
moc_*.cxx
|
||||
*.cxx_parameters
|
||||
|
|
|
@ -14,15 +14,30 @@ endif (APPLE)
|
|||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/)
|
||||
|
||||
include (OpenMWMacros)
|
||||
include(OpenMWMacros)
|
||||
|
||||
# Version
|
||||
|
||||
set (OPENMW_VERSION_MAJOR 0)
|
||||
set (OPENMW_VERSION_MINOR 27)
|
||||
set (OPENMW_VERSION_RELEASE 0)
|
||||
include(GetGitRevisionDescription)
|
||||
|
||||
set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")
|
||||
get_git_tag_revision(TAGHASH --tags --max-count=1)
|
||||
get_git_head_revision(REFSPEC COMMITHASH)
|
||||
git_describe(VERSION --tags ${TAGHASH})
|
||||
|
||||
string(REGEX MATCH "^openmw-[^0-9]*[0-9]+\\.[0-9]+\\.[0-9]+.*" MATCH "${VERSION}")
|
||||
if (MATCH)
|
||||
string(REGEX REPLACE "^openmw-([0-9]+)\\..*" "\\1" OPENMW_VERSION_MAJOR "${VERSION}")
|
||||
string(REGEX REPLACE "^openmw-[0-9]+\\.([0-9]+).*" "\\1" OPENMW_VERSION_MINOR "${VERSION}")
|
||||
string(REGEX REPLACE "^openmw-[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" OPENMW_VERSION_RELEASE "${VERSION}")
|
||||
|
||||
set(OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")
|
||||
set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}")
|
||||
set(OPENMW_VERSION_TAGHASH "${TAGHASH}")
|
||||
|
||||
message(STATUS "Configuring OpenMW ${OPENMW_VERSION}...")
|
||||
else (MATCH)
|
||||
message(FATAL_ERROR "Failed to get valid version information from Git")
|
||||
endif (MATCH)
|
||||
|
||||
# doxygen main page
|
||||
|
||||
|
@ -319,7 +334,7 @@ configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
|
|||
|
||||
configure_file(${OpenMW_SOURCE_DIR}/files/opencs.cfg
|
||||
"${OpenMW_BINARY_DIR}/opencs.cfg")
|
||||
|
||||
|
||||
configure_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters
|
||||
"${OpenMW_BINARY_DIR}/resources/defaultfilters" COPYONLY)
|
||||
|
||||
|
|
|
@ -236,7 +236,9 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info)
|
|||
// Loop through all the references
|
||||
ESM::CellRef ref;
|
||||
if(!quiet) std::cout << " References:\n";
|
||||
while(cell.getNextRef(esm, ref))
|
||||
|
||||
bool deleted = false;
|
||||
while(cell.getNextRef(esm, ref, deleted))
|
||||
{
|
||||
if (save) {
|
||||
info.data.mCellRefs[&cell].push_back(ref);
|
||||
|
@ -244,13 +246,14 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info)
|
|||
|
||||
if(quiet) continue;
|
||||
|
||||
std::cout << " Refnum: " << ref.mRefnum << std::endl;
|
||||
std::cout << " Refnum: " << ref.mRefNum.mIndex << std::endl;
|
||||
std::cout << " ID: '" << ref.mRefID << "'\n";
|
||||
std::cout << " Owner: '" << ref.mOwner << "'\n";
|
||||
std::cout << " Enchantment charge: '" << ref.mEnchantmentCharge << "'\n";
|
||||
std::cout << " Uses/health: '" << ref.mCharge << "'\n";
|
||||
std::cout << " Gold value: '" << ref.mGoldValue << "'\n";
|
||||
std::cout << " Blocked: '" << static_cast<int>(ref.mReferenceBlocked) << "'" << std::endl;
|
||||
std::cout << " Deleted: " << deleted << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
#include "maindialog.hpp"
|
||||
|
||||
#include <components/version/version.hpp>
|
||||
|
||||
#include <QLabel>
|
||||
#include <QDate>
|
||||
#include <QTime>
|
||||
#include <QPushButton>
|
||||
#include <QFontDatabase>
|
||||
#include <QInputDialog>
|
||||
|
@ -67,6 +72,22 @@ Launcher::MainDialog::MainDialog(QWidget *parent)
|
|||
// Remove what's this? button
|
||||
setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
// Add version information to bottom of the window
|
||||
QString revision(OPENMW_VERSION_COMMITHASH);
|
||||
QString tag(OPENMW_VERSION_TAGHASH);
|
||||
|
||||
if (revision == tag) {
|
||||
versionLabel->setText(tr("OpenMW %0 release").arg(OPENMW_VERSION));
|
||||
} else {
|
||||
versionLabel->setText(tr("OpenMW development (%0)").arg(revision.left(10)));
|
||||
}
|
||||
|
||||
// Add the compile date and time
|
||||
versionLabel->setToolTip(tr("Compiled on %0 %1").arg(QLocale(QLocale::C).toDate(QString(__DATE__).simplified(),
|
||||
QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate),
|
||||
QLocale(QLocale::C).toTime(QString(__TIME__).simplified(),
|
||||
QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate)));
|
||||
|
||||
createIcons();
|
||||
}
|
||||
|
||||
|
|
|
@ -133,16 +133,10 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, std::vector<std::
|
|||
state==CSMWorld::RecordBase::State_ModifiedOnly ||
|
||||
infoModified)
|
||||
{
|
||||
// always write the topic record
|
||||
std::string type;
|
||||
for (int i=0; i<4; ++i)
|
||||
/// \todo make endianess agnostic (change ESMWriter interface?)
|
||||
type += reinterpret_cast<const char *> (&topic.mModified.sRecordId)[i];
|
||||
|
||||
mState.getWriter().startRecord (type);
|
||||
mState.getWriter().startRecord (topic.mModified.sRecordId);
|
||||
mState.getWriter().writeHNCString ("NAME", topic.mModified.mId);
|
||||
topic.mModified.save (mState.getWriter());
|
||||
mState.getWriter().endRecord (type);
|
||||
mState.getWriter().endRecord (topic.mModified.sRecordId);
|
||||
|
||||
// write modified selected info records
|
||||
for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second;
|
||||
|
@ -178,15 +172,10 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, std::vector<std::
|
|||
next->mModified.mId.substr (next->mModified.mId.find_last_of ('#')+1);
|
||||
}
|
||||
|
||||
std::string type;
|
||||
for (int i=0; i<4; ++i)
|
||||
/// \todo make endianess agnostic (change ESMWriter interface?)
|
||||
type += reinterpret_cast<const char *> (&info.sRecordId)[i];
|
||||
|
||||
mState.getWriter().startRecord (type);
|
||||
mState.getWriter().startRecord (info.sRecordId);
|
||||
mState.getWriter().writeHNCString ("INAM", info.mId);
|
||||
info.save (mState.getWriter());
|
||||
mState.getWriter().endRecord (type);
|
||||
mState.getWriter().endRecord (info.sRecordId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,10 +104,10 @@ namespace CSMDoc
|
|||
/// \todo make endianess agnostic (change ESMWriter interface?)
|
||||
type += reinterpret_cast<const char *> (&mCollection.getRecord (stage).mModified.sRecordId)[i];
|
||||
|
||||
mState.getWriter().startRecord (type);
|
||||
mState.getWriter().startRecord (mCollection.getRecord (stage).mModified.sRecordId);
|
||||
mState.getWriter().writeHNCString ("NAME", mCollection.getId (stage));
|
||||
mCollection.getRecord (stage).mModified.save (mState.getWriter());
|
||||
mState.getWriter().endRecord (type);
|
||||
mState.getWriter().endRecord (mCollection.getRecord (stage).mModified.sRecordId);
|
||||
}
|
||||
else if (state==CSMWorld::RecordBase::State_Deleted)
|
||||
{
|
||||
|
|
|
@ -8,6 +8,5 @@ void CSMWorld::CellRef::load (ESM::ESMReader &esm, Cell& cell, const std::string
|
|||
mId = id;
|
||||
mCell = cell.mId;
|
||||
|
||||
if (!mDeleted)
|
||||
cell.addRef (mId);
|
||||
cell.addRef (mId);
|
||||
}
|
|
@ -16,7 +16,8 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
|
|||
|
||||
CellRef ref;
|
||||
|
||||
while (cell2.getNextRef (reader, ref))
|
||||
bool deleted = false;
|
||||
while (cell2.getNextRef (reader, ref, deleted))
|
||||
{
|
||||
/// \todo handle deleted and moved references
|
||||
ref.load (reader, cell2, getNewId());
|
||||
|
|
|
@ -147,15 +147,10 @@ namespace CSMWorld
|
|||
if (state==CSMWorld::RecordBase::State_Modified ||
|
||||
state==CSMWorld::RecordBase::State_ModifiedOnly)
|
||||
{
|
||||
std::string type;
|
||||
for (int i=0; i<4; ++i)
|
||||
/// \todo make endianess agnostic (change ESMWriter interface?)
|
||||
type += reinterpret_cast<const char *> (&mContainer.at (index).mModified.sRecordId)[i];
|
||||
|
||||
writer.startRecord (type);
|
||||
writer.startRecord (mContainer.at (index).mModified.sRecordId);
|
||||
writer.writeHNCString ("NAME", getId (index));
|
||||
mContainer.at (index).mModified.save (writer);
|
||||
writer.endRecord (type);
|
||||
writer.endRecord (mContainer.at (index).mModified.sRecordId);
|
||||
}
|
||||
else if (state==CSMWorld::RecordBase::State_Deleted)
|
||||
{
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
|
||||
# config file
|
||||
configure_file ("${CMAKE_CURRENT_SOURCE_DIR}/config.hpp.cmake" "${CMAKE_CURRENT_SOURCE_DIR}/config.hpp")
|
||||
|
||||
# local files
|
||||
set(GAME
|
||||
main.cpp
|
||||
|
@ -12,7 +8,6 @@ if(NOT WIN32)
|
|||
endif()
|
||||
set(GAME_HEADER
|
||||
engine.hpp
|
||||
config.hpp
|
||||
)
|
||||
source_group(game FILES ${GAME} ${GAME_HEADER})
|
||||
|
||||
|
@ -74,12 +69,16 @@ add_openmw_dir (mwmechanics
|
|||
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
|
||||
drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow
|
||||
aiescort aiactivate aicombat repair enchanting pathfinding security spellsuccess spellcasting
|
||||
disease pickpocket levelledlist combat
|
||||
disease pickpocket levelledlist combat steering
|
||||
)
|
||||
|
||||
add_openmw_dir (mwstate
|
||||
statemanagerimp charactermanager character
|
||||
)
|
||||
|
||||
add_openmw_dir (mwbase
|
||||
environment world scriptmanager dialoguemanager journal soundmanager mechanicsmanager
|
||||
inputmanager windowmanager
|
||||
inputmanager windowmanager statemanager
|
||||
)
|
||||
|
||||
# Main executable
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include <MyGUI_WidgetManager.h>
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include <components/compiler/extensions0.hpp>
|
||||
|
||||
#include <components/bsa/bsa_archive.hpp>
|
||||
|
@ -41,8 +43,7 @@
|
|||
|
||||
#include "mwmechanics/mechanicsmanagerimp.hpp"
|
||||
|
||||
|
||||
#include <SDL.h>
|
||||
#include "mwstate/statemanagerimp.hpp"
|
||||
|
||||
void OMW::Engine::executeLocalScripts()
|
||||
{
|
||||
|
@ -88,31 +89,47 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
|
|||
if (mUseSound)
|
||||
MWBase::Environment::get().getSoundManager()->update(frametime);
|
||||
|
||||
// global scripts
|
||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().run();
|
||||
bool paused = MWBase::Environment::get().getWindowManager()->isGuiMode();
|
||||
|
||||
bool changed = MWBase::Environment::get().getWorld()->hasCellChanged();
|
||||
// update game state
|
||||
MWBase::Environment::get().getStateManager()->update (frametime);
|
||||
|
||||
// local scripts
|
||||
executeLocalScripts(); // This does not handle the case where a global script causes a cell
|
||||
// change, followed by a cell change in a local script during the same
|
||||
// frame.
|
||||
if (MWBase::Environment::get().getStateManager()->getState()==
|
||||
MWBase::StateManager::State_Running)
|
||||
{
|
||||
// global scripts
|
||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().run();
|
||||
|
||||
// passing of time
|
||||
if (!MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||
MWBase::Environment::get().getWorld()->advanceTime(
|
||||
frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600);
|
||||
bool changed = MWBase::Environment::get().getWorld()->hasCellChanged();
|
||||
|
||||
// local scripts
|
||||
executeLocalScripts(); // This does not handle the case where a global script causes a
|
||||
// cell change, followed by a cell change in a local script during
|
||||
// the same frame.
|
||||
|
||||
if (changed) // keep change flag for another frame, if cell changed happened in local script
|
||||
MWBase::Environment::get().getWorld()->markCellAsUnchanged();
|
||||
|
||||
if (!paused)
|
||||
MWBase::Environment::get().getWorld()->advanceTime(
|
||||
frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600);
|
||||
}
|
||||
|
||||
if (changed) // keep change flag for another frame, if cell changed happend in local script
|
||||
MWBase::Environment::get().getWorld()->markCellAsUnchanged();
|
||||
|
||||
// update actors
|
||||
MWBase::Environment::get().getMechanicsManager()->update(frametime,
|
||||
MWBase::Environment::get().getWindowManager()->isGuiMode());
|
||||
paused);
|
||||
|
||||
if (MWBase::Environment::get().getStateManager()->getState()==
|
||||
MWBase::StateManager::State_Running)
|
||||
{
|
||||
MWWorld::Ptr player = mEnvironment.getWorld()->getPlayerPtr();
|
||||
if(!paused && player.getClass().getCreatureStats(player).isDead())
|
||||
MWBase::Environment::get().getStateManager()->endGame();
|
||||
}
|
||||
|
||||
// update world
|
||||
MWBase::Environment::get().getWorld()->update(frametime, MWBase::Environment::get().getWindowManager()->isGuiMode());
|
||||
MWBase::Environment::get().getWorld()->update(frametime, paused);
|
||||
|
||||
// update GUI
|
||||
Ogre::RenderWindow* window = mOgre->getWindow();
|
||||
|
@ -135,7 +152,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
|
|||
: mOgre (0)
|
||||
, mFpsLevel(0)
|
||||
, mVerboseScripts (false)
|
||||
, mNewGame (false)
|
||||
, mSkipMenu (false)
|
||||
, mUseSound (true)
|
||||
, mCompileAll (false)
|
||||
, mScriptContext (0)
|
||||
|
@ -265,12 +282,7 @@ void OMW::Engine::setCell (const std::string& cellName)
|
|||
|
||||
void OMW::Engine::addContentFile(const std::string& file)
|
||||
{
|
||||
if (file.find_last_of(".") == std::string::npos)
|
||||
{
|
||||
throw std::runtime_error("Missing extension in content file!");
|
||||
}
|
||||
|
||||
mContentFiles.push_back(file);
|
||||
mContentFiles.push_back(file);
|
||||
}
|
||||
|
||||
void OMW::Engine::setScriptsVerbosity(bool scriptsVerbosity)
|
||||
|
@ -278,9 +290,9 @@ void OMW::Engine::setScriptsVerbosity(bool scriptsVerbosity)
|
|||
mVerboseScripts = scriptsVerbosity;
|
||||
}
|
||||
|
||||
void OMW::Engine::setNewGame(bool newGame)
|
||||
void OMW::Engine::setSkipMenu (bool skipMenu)
|
||||
{
|
||||
mNewGame = newGame;
|
||||
mSkipMenu = skipMenu;
|
||||
}
|
||||
|
||||
std::string OMW::Engine::loadSettings (Settings::Manager & settings)
|
||||
|
@ -326,6 +338,9 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings)
|
|||
|
||||
void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||
{
|
||||
mEnvironment.setStateManager (
|
||||
new MWState::StateManager (mCfgMgr.getUserDataPath() / "saves", mContentFiles.at (0)));
|
||||
|
||||
Nif::NIFFile::CacheLock cachelock;
|
||||
|
||||
std::string renderSystem = settings.getString("render system", "Video");
|
||||
|
@ -392,10 +407,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
input->setPlayer(&mEnvironment.getWorld()->getPlayer());
|
||||
|
||||
window->initUI();
|
||||
if (mNewGame)
|
||||
// still redundant work here: recreate CharacterCreation(),
|
||||
// double update visibility etc.
|
||||
window->setNewGame(true);
|
||||
window->renderWorldMap();
|
||||
|
||||
//Load translation data
|
||||
|
@ -403,7 +414,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
for (size_t i = 0; i < mContentFiles.size(); i++)
|
||||
mTranslationDataStorage.loadTranslationData(mFileCollections, mContentFiles[i]);
|
||||
|
||||
Compiler::registerExtensions (mExtensions);
|
||||
Compiler::registerExtensions (mExtensions);
|
||||
|
||||
// Create sound system
|
||||
mEnvironment.setSoundManager (new MWSound::SoundManager(mUseSound));
|
||||
|
@ -427,12 +438,12 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
mechanics->buildPlayer();
|
||||
window->updatePlayer();
|
||||
|
||||
if (!mNewGame)
|
||||
{
|
||||
// load cell
|
||||
ESM::Position pos;
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
// load cell
|
||||
ESM::Position pos;
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
|
||||
if (!mCellName.empty())
|
||||
{
|
||||
if (world->findExteriorPosition(mCellName, pos)) {
|
||||
world->changeToExteriorCell (pos);
|
||||
}
|
||||
|
@ -442,7 +453,11 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
}
|
||||
}
|
||||
else
|
||||
mEnvironment.getWorld()->startNewGame();
|
||||
{
|
||||
pos.pos[0] = pos.pos[1] = pos.pos[2] = 0;
|
||||
pos.rot[0] = pos.rot[1] = pos.pos[2] = 0;
|
||||
world->changeToExteriorCell (pos);
|
||||
}
|
||||
|
||||
Ogre::FrameEvent event;
|
||||
event.timeSinceLastEvent = 0;
|
||||
|
@ -468,7 +483,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
|
||||
void OMW::Engine::go()
|
||||
{
|
||||
assert (!mCellName.empty());
|
||||
assert (!mContentFiles.empty());
|
||||
assert (!mOgre);
|
||||
|
||||
|
@ -489,8 +503,14 @@ void OMW::Engine::go()
|
|||
if (!mStartupScript.empty())
|
||||
MWBase::Environment::get().getWindowManager()->executeInConsole (mStartupScript);
|
||||
|
||||
// start in main menu
|
||||
if (!mSkipMenu)
|
||||
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
|
||||
else
|
||||
MWBase::Environment::get().getStateManager()->newGame (true);
|
||||
|
||||
// Start the main rendering loop
|
||||
while (!mEnvironment.getRequestExit())
|
||||
while (!mEnvironment.get().getStateManager()->hasQuitRequest())
|
||||
Ogre::Root::getSingleton().renderOneFrame();
|
||||
|
||||
// Save user settings
|
||||
|
|
|
@ -71,7 +71,7 @@ namespace OMW
|
|||
std::vector<std::string> mContentFiles;
|
||||
int mFpsLevel;
|
||||
bool mVerboseScripts;
|
||||
bool mNewGame;
|
||||
bool mSkipMenu;
|
||||
bool mUseSound;
|
||||
bool mCompileAll;
|
||||
std::string mFocusName;
|
||||
|
@ -151,8 +151,7 @@ namespace OMW
|
|||
/// Disable or enable all sounds
|
||||
void setSoundUsage(bool soundUsage);
|
||||
|
||||
/// Start as a new game.
|
||||
void setNewGame(bool newGame);
|
||||
void setSkipMenu (bool skipMenu);
|
||||
|
||||
void setGrabMouse(bool grab) { mGrab = grab; }
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <iostream>
|
||||
#include <cstdio>
|
||||
|
||||
#include <components/version/version.hpp>
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
|
||||
#include <SDL.h>
|
||||
|
@ -30,8 +31,6 @@ extern int is_debugger_attached(void);
|
|||
#include <OSX/macUtils.h>
|
||||
#endif
|
||||
|
||||
#include "config.hpp"
|
||||
|
||||
#include <boost/version.hpp>
|
||||
/**
|
||||
* Workaround for problems with whitespaces in paths in older versions of Boost library
|
||||
|
@ -116,7 +115,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
|||
("resources", bpo::value<std::string>()->default_value("resources"),
|
||||
"set resources directory")
|
||||
|
||||
("start", bpo::value<std::string>()->default_value("Beshara"),
|
||||
("start", bpo::value<std::string>()->default_value(""),
|
||||
"set initial cell")
|
||||
|
||||
("content", bpo::value<StringsVector>()->default_value(StringsVector(), "")
|
||||
|
@ -137,8 +136,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
|||
("script-run", bpo::value<std::string>()->default_value(""),
|
||||
"select a file containing a list of console commands that is executed on startup")
|
||||
|
||||
("new-game", bpo::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "activate char gen/new game mechanics")
|
||||
("skip-menu", bpo::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "skip main menu on game startup")
|
||||
|
||||
("fs-strict", bpo::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "strict file system handling (no case folding)")
|
||||
|
@ -232,7 +231,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
|||
|
||||
// startup-settings
|
||||
engine.setCell(variables["start"].as<std::string>());
|
||||
engine.setNewGame(variables["new-game"].as<bool>());
|
||||
engine.setSkipMenu (variables["skip-menu"].as<bool>());
|
||||
|
||||
// other settings
|
||||
engine.setSoundUsage(!variables["no-sound"].as<bool>());
|
||||
|
|
|
@ -11,13 +11,14 @@
|
|||
#include "mechanicsmanager.hpp"
|
||||
#include "inputmanager.hpp"
|
||||
#include "windowmanager.hpp"
|
||||
#include "statemanager.hpp"
|
||||
|
||||
MWBase::Environment *MWBase::Environment::sThis = 0;
|
||||
bool MWBase::Environment::sExit = false;
|
||||
|
||||
MWBase::Environment::Environment()
|
||||
: mWorld (0), mSoundManager (0), mScriptManager (0), mWindowManager (0),
|
||||
mMechanicsManager (0), mDialogueManager (0), mJournal (0), mInputManager (0), mFrameDuration (0)
|
||||
mMechanicsManager (0), mDialogueManager (0), mJournal (0), mInputManager (0), mFrameDuration (0),
|
||||
mStateManager (0)
|
||||
{
|
||||
assert (!sThis);
|
||||
sThis = this;
|
||||
|
@ -69,6 +70,11 @@ void MWBase::Environment::setInputManager (InputManager *inputManager)
|
|||
mInputManager = inputManager;
|
||||
}
|
||||
|
||||
void MWBase::Environment::setStateManager (StateManager *stateManager)
|
||||
{
|
||||
mStateManager = stateManager;
|
||||
}
|
||||
|
||||
void MWBase::Environment::setFrameDuration (float duration)
|
||||
{
|
||||
mFrameDuration = duration;
|
||||
|
@ -122,6 +128,12 @@ MWBase::InputManager *MWBase::Environment::getInputManager() const
|
|||
return mInputManager;
|
||||
}
|
||||
|
||||
MWBase::StateManager *MWBase::Environment::getStateManager() const
|
||||
{
|
||||
assert (mStateManager);
|
||||
return mStateManager;
|
||||
}
|
||||
|
||||
float MWBase::Environment::getFrameDuration() const
|
||||
{
|
||||
return mFrameDuration;
|
||||
|
@ -152,6 +164,9 @@ void MWBase::Environment::cleanup()
|
|||
|
||||
delete mInputManager;
|
||||
mInputManager = 0;
|
||||
|
||||
delete mStateManager;
|
||||
mStateManager = 0;
|
||||
}
|
||||
|
||||
const MWBase::Environment& MWBase::Environment::get()
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace MWBase
|
|||
class MechanicsManager;
|
||||
class InputManager;
|
||||
class WindowManager;
|
||||
class StateManager;
|
||||
|
||||
/// \brief Central hub for mw-subsystems
|
||||
///
|
||||
|
@ -30,10 +31,9 @@ namespace MWBase
|
|||
DialogueManager *mDialogueManager;
|
||||
Journal *mJournal;
|
||||
InputManager *mInputManager;
|
||||
StateManager *mStateManager;
|
||||
float mFrameDuration;
|
||||
|
||||
static bool sExit;
|
||||
|
||||
Environment (const Environment&);
|
||||
///< not implemented
|
||||
|
||||
|
@ -46,9 +46,6 @@ namespace MWBase
|
|||
|
||||
~Environment();
|
||||
|
||||
static void setRequestExit () { sExit = true; }
|
||||
static bool getRequestExit () { return sExit; }
|
||||
|
||||
void setWorld (World *world);
|
||||
|
||||
void setSoundManager (SoundManager *soundManager);
|
||||
|
@ -65,6 +62,8 @@ namespace MWBase
|
|||
|
||||
void setInputManager (InputManager *inputManager);
|
||||
|
||||
void setStateManager (StateManager *stateManager);
|
||||
|
||||
void setFrameDuration (float duration);
|
||||
///< Set length of current frame in seconds.
|
||||
|
||||
|
@ -84,6 +83,8 @@ namespace MWBase
|
|||
|
||||
InputManager *getInputManager() const;
|
||||
|
||||
StateManager *getStateManager() const;
|
||||
|
||||
float getFrameDuration() const;
|
||||
|
||||
void cleanup();
|
||||
|
|
|
@ -5,10 +5,18 @@
|
|||
#include <deque>
|
||||
#include <map>
|
||||
|
||||
#include <libs/platform/stdint.h>
|
||||
|
||||
#include "../mwdialogue/journalentry.hpp"
|
||||
#include "../mwdialogue/topic.hpp"
|
||||
#include "../mwdialogue/quest.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
}
|
||||
|
||||
namespace MWBase
|
||||
{
|
||||
/// \brief Interface for the player's journal (implemented in MWDialogue)
|
||||
|
@ -46,7 +54,7 @@ namespace MWBase
|
|||
virtual int getJournalIndex (const std::string& id) const = 0;
|
||||
///< Get the journal index.
|
||||
|
||||
virtual void addTopic (const std::string& topicId, const std::string& infoId) = 0;
|
||||
virtual void addTopic (const std::string& topicId, const std::string& infoId, const std::string& actorName) = 0;
|
||||
|
||||
virtual TEntryIter begin() const = 0;
|
||||
///< Iterator pointing to the begin of the main journal.
|
||||
|
@ -69,6 +77,12 @@ namespace MWBase
|
|||
|
||||
virtual TTopicIter topicEnd() const = 0;
|
||||
///< Iterator pointing past the last topic.
|
||||
|
||||
virtual int countSavedGameRecords() const = 0;
|
||||
|
||||
virtual void write (ESM::ESMWriter& writer) const = 0;
|
||||
|
||||
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -136,33 +136,35 @@ namespace MWBase
|
|||
float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange) = 0;
|
||||
///< Perform a persuasion action on NPC
|
||||
|
||||
virtual void forceStateUpdate(const MWWorld::Ptr &ptr) = 0;
|
||||
///< Forces an object to refresh its animation state.
|
||||
virtual void forceStateUpdate(const MWWorld::Ptr &ptr) = 0;
|
||||
///< Forces an object to refresh its animation state.
|
||||
|
||||
virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number=1) = 0;
|
||||
///< Run animation for a MW-reference. Calls to this function for references that are currently not
|
||||
/// in the scene should be ignored.
|
||||
///
|
||||
/// \param mode 0 normal, 1 immediate start, 2 immediate loop
|
||||
/// \param count How many times the animation should be run
|
||||
virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number=1) = 0;
|
||||
///< Run animation for a MW-reference. Calls to this function for references that are currently not
|
||||
/// in the scene should be ignored.
|
||||
///
|
||||
/// \param mode 0 normal, 1 immediate start, 2 immediate loop
|
||||
/// \param count How many times the animation should be run
|
||||
|
||||
virtual void skipAnimation(const MWWorld::Ptr& ptr) = 0;
|
||||
///< Skip the animation for the given MW-reference for one frame. Calls to this function for
|
||||
/// references that are currently not in the scene should be ignored.
|
||||
virtual void skipAnimation(const MWWorld::Ptr& ptr) = 0;
|
||||
///< Skip the animation for the given MW-reference for one frame. Calls to this function for
|
||||
/// references that are currently not in the scene should be ignored.
|
||||
|
||||
virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName) = 0;
|
||||
virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName) = 0;
|
||||
|
||||
/// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently
|
||||
/// paused we may want to do it manually (after equipping permanent enchantment)
|
||||
virtual void updateMagicEffects (const MWWorld::Ptr& ptr) = 0;
|
||||
/// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently
|
||||
/// paused we may want to do it manually (after equipping permanent enchantment)
|
||||
virtual void updateMagicEffects (const MWWorld::Ptr& ptr) = 0;
|
||||
|
||||
virtual void toggleAI() = 0;
|
||||
virtual bool isAIActive() = 0;
|
||||
virtual void toggleAI() = 0;
|
||||
virtual bool isAIActive() = 0;
|
||||
|
||||
virtual void getObjectsInRange (const Ogre::Vector3& position, float radius, std::vector<MWWorld::Ptr>& objects) = 0;
|
||||
|
||||
///return the list of actors which are following the given actor (ie AiFollow is active and the target is the actor)
|
||||
virtual std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor) = 0;
|
||||
|
||||
virtual void playerLoaded() = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -35,8 +35,6 @@ namespace MWBase
|
|||
|
||||
virtual ~ScriptManager() {}
|
||||
|
||||
virtual void resetGlobalScripts() = 0;
|
||||
|
||||
virtual void run (const std::string& name, Interpreter::Context& interpreterContext) = 0;
|
||||
///< Run the script with the given name (compile first, if not compiled yet)
|
||||
|
||||
|
|
|
@ -149,6 +149,8 @@ namespace MWBase
|
|||
virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up) = 0;
|
||||
|
||||
virtual void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated) = 0;
|
||||
|
||||
virtual void clear() = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
81
apps/openmw/mwbase/statemanager.hpp
Normal file
81
apps/openmw/mwbase/statemanager.hpp
Normal file
|
@ -0,0 +1,81 @@
|
|||
#ifndef GAME_MWSTATE_STATEMANAGER_H
|
||||
#define GAME_MWSTATE_STATEMANAGER_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace MWState
|
||||
{
|
||||
struct Slot;
|
||||
class Character;
|
||||
}
|
||||
|
||||
namespace MWBase
|
||||
{
|
||||
/// \brief Interface for game state manager (implemented in MWState)
|
||||
class StateManager
|
||||
{
|
||||
public:
|
||||
|
||||
enum State
|
||||
{
|
||||
State_NoGame,
|
||||
State_Ended,
|
||||
State_Running
|
||||
};
|
||||
|
||||
typedef std::vector<MWState::Character>::const_iterator CharacterIterator;
|
||||
|
||||
private:
|
||||
|
||||
StateManager (const StateManager&);
|
||||
///< not implemented
|
||||
|
||||
StateManager& operator= (const StateManager&);
|
||||
///< not implemented
|
||||
|
||||
public:
|
||||
|
||||
StateManager() {}
|
||||
|
||||
virtual ~StateManager() {}
|
||||
|
||||
virtual void requestQuit() = 0;
|
||||
|
||||
virtual bool hasQuitRequest() const = 0;
|
||||
|
||||
virtual void askLoadRecent() = 0;
|
||||
|
||||
virtual State getState() const = 0;
|
||||
|
||||
virtual void newGame (bool bypass = false) = 0;
|
||||
///< Start a new game.
|
||||
///
|
||||
/// \param bypass Skip new game mechanics.
|
||||
|
||||
virtual void endGame() = 0;
|
||||
|
||||
virtual void saveGame (const std::string& description, const MWState::Slot *slot = 0) = 0;
|
||||
///< Write a saved game to \a slot or create a new slot if \a slot == 0.
|
||||
///
|
||||
/// \note Slot must belong to the current character.
|
||||
|
||||
virtual void loadGame (const MWState::Character *character, const MWState::Slot *slot) = 0;
|
||||
///< Load a saved game file from \a slot.
|
||||
///
|
||||
/// \note \a slot must belong to \a character.
|
||||
|
||||
virtual MWState::Character *getCurrentCharacter (bool create = true) = 0;
|
||||
///< \param create Create a new character, if there is no current character.
|
||||
|
||||
virtual CharacterIterator characterBegin() = 0;
|
||||
///< Any call to SaveGame and getCurrentCharacter can invalidate the returned
|
||||
/// iterator.
|
||||
|
||||
virtual CharacterIterator characterEnd() = 0;
|
||||
|
||||
virtual void update (float duration) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -33,6 +33,8 @@ namespace OEngine
|
|||
namespace ESM
|
||||
{
|
||||
struct Class;
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
|
@ -279,12 +281,19 @@ namespace MWBase
|
|||
|
||||
virtual const Translation::Storage& getTranslationDataStorage() const = 0;
|
||||
|
||||
/// Warning: do not use MyGUI::InputManager::setKeyFocusWidget directly. Instead use this.
|
||||
virtual void setKeyFocusWidget (MyGUI::Widget* widget) = 0;
|
||||
|
||||
virtual Loading::Listener* getLoadingScreen() = 0;
|
||||
|
||||
/// Should the cursor be visible?
|
||||
virtual bool getCursorVisible() = 0;
|
||||
|
||||
/// Clear all savegame-specific data
|
||||
virtual void clear() = 0;
|
||||
|
||||
virtual void write (ESM::ESMWriter& writer) = 0;
|
||||
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define GAME_MWBASE_WORLD_H
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <components/settings/settings.hpp>
|
||||
|
||||
|
@ -30,12 +31,14 @@ namespace OEngine
|
|||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
struct Position;
|
||||
struct Cell;
|
||||
struct Class;
|
||||
struct Potion;
|
||||
struct Spell;
|
||||
struct NPC;
|
||||
struct CellId;
|
||||
}
|
||||
|
||||
namespace MWRender
|
||||
|
@ -94,13 +97,26 @@ namespace MWBase
|
|||
|
||||
virtual void startNewGame() = 0;
|
||||
|
||||
virtual void clear() = 0;
|
||||
|
||||
virtual int countSavedGameRecords() const = 0;
|
||||
|
||||
virtual void write (ESM::ESMWriter& writer) const = 0;
|
||||
|
||||
virtual void readRecord (ESM::ESMReader& reader, int32_t type,
|
||||
const std::map<int, int>& contentFileMap) = 0;
|
||||
|
||||
virtual OEngine::Render::Fader* getFader() = 0;
|
||||
///< \ŧodo remove this function. Rendering details should not be exposed.
|
||||
///< \todo remove this function. Rendering details should not be exposed.
|
||||
|
||||
virtual MWWorld::CellStore *getExterior (int x, int y) = 0;
|
||||
|
||||
virtual MWWorld::CellStore *getInterior (const std::string& name) = 0;
|
||||
|
||||
virtual MWWorld::CellStore *getCell (const ESM::CellId& id) = 0;
|
||||
|
||||
virtual void useDeathCamera() = 0;
|
||||
|
||||
virtual void setWaterHeight(const float height) = 0;
|
||||
|
||||
virtual void toggleWater() = 0;
|
||||
|
@ -139,16 +155,26 @@ namespace MWBase
|
|||
virtual bool isPositionExplored (float nX, float nY, int x, int y, bool interior) = 0;
|
||||
///< see MWRender::LocalMap::isPositionExplored
|
||||
|
||||
virtual MWWorld::Globals::Data& getGlobalVariable (const std::string& name) = 0;
|
||||
virtual void setGlobalInt (const std::string& name, int value) = 0;
|
||||
///< Set value independently from real type.
|
||||
|
||||
virtual MWWorld::Globals::Data getGlobalVariable (const std::string& name) const = 0;
|
||||
virtual void setGlobalFloat (const std::string& name, float value) = 0;
|
||||
///< Set value independently from real type.
|
||||
|
||||
virtual int getGlobalInt (const std::string& name) const = 0;
|
||||
///< Get value independently from real type.
|
||||
|
||||
virtual float getGlobalFloat (const std::string& name) const = 0;
|
||||
///< Get value independently from real type.
|
||||
|
||||
virtual char getGlobalVariableType (const std::string& name) const = 0;
|
||||
///< Return ' ', if there is no global variable with this name.
|
||||
|
||||
virtual std::vector<std::string> getGlobals () const = 0;
|
||||
|
||||
virtual std::string getCurrentCellName() const = 0;
|
||||
virtual std::string getCellName (const MWWorld::CellStore *cell = 0) const = 0;
|
||||
///< Return name of the cell.
|
||||
///
|
||||
/// \note If cell==0, the cell the player is currently in will be used instead to
|
||||
/// generate a name.
|
||||
|
||||
virtual void removeRefScript (MWWorld::RefData *ref) = 0;
|
||||
//< Remove the script attached to ref from mLocalScripts
|
||||
|
@ -185,8 +211,12 @@ namespace MWBase
|
|||
virtual void setDay (int day) = 0;
|
||||
///< Set in-game time day.
|
||||
|
||||
virtual int getDay() = 0;
|
||||
virtual int getMonth() = 0;
|
||||
virtual int getDay() const = 0;
|
||||
virtual int getMonth() const = 0;
|
||||
virtual int getYear() const = 0;
|
||||
|
||||
virtual std::string getMonthName (int month = -1) const = 0;
|
||||
///< Return name of month (-1: current month)
|
||||
|
||||
virtual MWWorld::TimeStamp getTimeStamp() const = 0;
|
||||
///< Return current in-game time stamp.
|
||||
|
@ -215,6 +245,8 @@ namespace MWBase
|
|||
virtual void changeToExteriorCell (const ESM::Position& position) = 0;
|
||||
///< Move to exterior cell.
|
||||
|
||||
virtual void changeToCell (const ESM::CellId& cellId, const ESM::Position& position) = 0;
|
||||
|
||||
virtual const ESM::Cell *getExterior (const std::string& cellName) const = 0;
|
||||
///< Return a cell matching the given name or a 0-pointer, if there is no such cell.
|
||||
|
||||
|
@ -336,7 +368,7 @@ namespace MWBase
|
|||
virtual bool isSwimming(const MWWorld::Ptr &object) const = 0;
|
||||
///Is the head of the creature underwater?
|
||||
virtual bool isSubmerged(const MWWorld::Ptr &object) const = 0;
|
||||
virtual bool isUnderwater(const MWWorld::Ptr::CellStore* cell, const Ogre::Vector3 &pos) const = 0;
|
||||
virtual bool isUnderwater(const MWWorld::CellStore* cell, const Ogre::Vector3 &pos) const = 0;
|
||||
virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0;
|
||||
|
||||
virtual void togglePOV() = 0;
|
||||
|
@ -384,6 +416,7 @@ namespace MWBase
|
|||
virtual void playVideo(const std::string& name, bool allowSkipping) = 0;
|
||||
virtual void stopVideo() = 0;
|
||||
virtual void frameStarted (float dt, bool paused) = 0;
|
||||
virtual void screenshot (Ogre::Image& image, int w, int h) = 0;
|
||||
|
||||
/// Find default position inside exterior cell specified by name
|
||||
/// \return false if exterior with given name not exists, true otherwise
|
||||
|
@ -428,6 +461,8 @@ namespace MWBase
|
|||
virtual void launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects,
|
||||
const MWWorld::Ptr& actor, const std::string& sourceName) = 0;
|
||||
|
||||
virtual const std::vector<std::string>& getContentFiles() const = 0;
|
||||
|
||||
virtual void breakInvisibility (const MWWorld::Ptr& actor) = 0;
|
||||
|
||||
// Are we in an exterior or pseudo-exterior cell and it's night?
|
||||
|
|
|
@ -366,12 +366,12 @@ namespace MWClass
|
|||
return MWWorld::Ptr(&cell.mArmors.insert(*ref), &cell);
|
||||
}
|
||||
|
||||
float Armor::getEnchantmentPoints (const MWWorld::Ptr& ptr) const
|
||||
int Armor::getEnchantmentPoints (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Armor> *ref =
|
||||
ptr.get<ESM::Armor>();
|
||||
|
||||
return ref->mBase->mData.mEnchant/10.f;
|
||||
return ref->mBase->mData.mEnchant;
|
||||
}
|
||||
|
||||
bool Armor::canSell (const MWWorld::Ptr& item, int npcServices) const
|
||||
|
|
|
@ -79,7 +79,7 @@ namespace MWClass
|
|||
|
||||
virtual std::string getModel(const MWWorld::Ptr &ptr) const;
|
||||
|
||||
virtual float getEnchantmentPoints (const MWWorld::Ptr& ptr) const;
|
||||
virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const;
|
||||
};
|
||||
|
|
|
@ -189,12 +189,12 @@ namespace MWClass
|
|||
return MWWorld::Ptr(&cell.mBooks.insert(*ref), &cell);
|
||||
}
|
||||
|
||||
float Book::getEnchantmentPoints (const MWWorld::Ptr& ptr) const
|
||||
int Book::getEnchantmentPoints (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Book> *ref =
|
||||
ptr.get<ESM::Book>();
|
||||
|
||||
return ref->mBase->mData.mEnchant/10.f;
|
||||
return ref->mBase->mData.mEnchant;
|
||||
}
|
||||
|
||||
bool Book::canSell (const MWWorld::Ptr& item, int npcServices) const
|
||||
|
|
|
@ -58,7 +58,7 @@ namespace MWClass
|
|||
|
||||
virtual std::string getModel(const MWWorld::Ptr &ptr) const;
|
||||
|
||||
virtual float getEnchantmentPoints (const MWWorld::Ptr& ptr) const;
|
||||
virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
virtual float getWeight (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
|
|
|
@ -279,12 +279,12 @@ namespace MWClass
|
|||
return MWWorld::Ptr(&cell.mClothes.insert(*ref), &cell);
|
||||
}
|
||||
|
||||
float Clothing::getEnchantmentPoints (const MWWorld::Ptr& ptr) const
|
||||
int Clothing::getEnchantmentPoints (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Clothing> *ref =
|
||||
ptr.get<ESM::Clothing>();
|
||||
|
||||
return ref->mBase->mData.mEnchant/10.f;
|
||||
return ref->mBase->mData.mEnchant;
|
||||
}
|
||||
|
||||
bool Clothing::canSell (const MWWorld::Ptr& item, int npcServices) const
|
||||
|
|
|
@ -71,7 +71,7 @@ namespace MWClass
|
|||
|
||||
virtual std::string getModel(const MWWorld::Ptr &ptr) const;
|
||||
|
||||
virtual float getEnchantmentPoints (const MWWorld::Ptr& ptr) const;
|
||||
virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
virtual float getWeight (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "container.hpp"
|
||||
|
||||
#include <components/esm/loadcont.hpp>
|
||||
#include <components/esm/containerstate.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
@ -258,4 +259,26 @@ namespace MWClass
|
|||
|
||||
return MWWorld::Ptr(&cell.mContainers.insert(*ref), &cell);
|
||||
}
|
||||
|
||||
void Container::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
const ESM::ContainerState& state2 = dynamic_cast<const ESM::ContainerState&> (state);
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore.
|
||||
readState (state2.mInventory);
|
||||
}
|
||||
|
||||
void Container::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
ESM::ContainerState& state2 = dynamic_cast<ESM::ContainerState&> (state);
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore.
|
||||
writeState (state2.mInventory);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,6 +54,14 @@ namespace MWClass
|
|||
virtual void unlock (const MWWorld::Ptr& ptr) const;
|
||||
///< Unlock object
|
||||
|
||||
virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const;
|
||||
///< Read additional state from \a state into \a ptr.
|
||||
|
||||
virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const;
|
||||
///< Write additional state from \a ptr into \a state.
|
||||
|
||||
static void registerSelf();
|
||||
|
||||
virtual std::string getModel(const MWWorld::Ptr &ptr) const;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "creature.hpp"
|
||||
|
||||
#include <components/esm/loadcrea.hpp>
|
||||
#include <components/esm/creaturestate.hpp>
|
||||
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwmechanics/magiceffects.hpp"
|
||||
|
@ -332,7 +333,7 @@ namespace MWClass
|
|||
if (damage > 0)
|
||||
MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition);
|
||||
|
||||
victim.getClass().onHit(victim, damage, true, MWWorld::Ptr(), ptr, true);
|
||||
victim.getClass().onHit(victim, damage, true, weapon, ptr, true);
|
||||
}
|
||||
|
||||
void Creature::onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const
|
||||
|
@ -528,8 +529,8 @@ namespace MWClass
|
|||
float moveSpeed;
|
||||
if(normalizedEncumbrance >= 1.0f)
|
||||
moveSpeed = 0.0f;
|
||||
else if(mageffects.get(ESM::MagicEffect::Levitate).mMagnitude > 0 &&
|
||||
world->isLevitationEnabled())
|
||||
else if(isFlying(ptr) || (mageffects.get(ESM::MagicEffect::Levitate).mMagnitude > 0 &&
|
||||
world->isLevitationEnabled()))
|
||||
{
|
||||
float flySpeed = 0.01f*(stats.getAttribute(ESM::Attribute::Speed).getModified() +
|
||||
mageffects.get(ESM::MagicEffect::Levitate).mMagnitude);
|
||||
|
@ -758,6 +759,28 @@ namespace MWClass
|
|||
return 0;
|
||||
}
|
||||
|
||||
void Creature::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
const ESM::CreatureState& state2 = dynamic_cast<const ESM::CreatureState&> (state);
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore->
|
||||
readState (state2.mInventory);
|
||||
}
|
||||
|
||||
void Creature::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
ESM::CreatureState& state2 = dynamic_cast<ESM::CreatureState&> (state);
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore->
|
||||
writeState (state2.mInventory);
|
||||
}
|
||||
|
||||
const ESM::GameSetting* Creature::fMinWalkSpeedCreature;
|
||||
const ESM::GameSetting* Creature::fMaxWalkSpeedCreature;
|
||||
const ESM::GameSetting *Creature::fEncumberedMoveEffect;
|
||||
|
|
|
@ -91,7 +91,7 @@ namespace MWClass
|
|||
|
||||
virtual bool isEssential (const MWWorld::Ptr& ptr) const;
|
||||
///< Is \a ptr essential? (i.e. may losing \a ptr make the game unwinnable)
|
||||
|
||||
|
||||
virtual int getServices (const MWWorld::Ptr& actor) const;
|
||||
|
||||
virtual bool isPersistent (const MWWorld::Ptr& ptr) const;
|
||||
|
@ -125,6 +125,14 @@ namespace MWClass
|
|||
|
||||
/// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini)
|
||||
virtual int getBloodTexture (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const;
|
||||
///< Read additional state from \a state into \a ptr.
|
||||
|
||||
virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const;
|
||||
///< Write additional state from \a ptr into \a state.
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "light.hpp"
|
||||
|
||||
#include <components/esm/loadligh.hpp>
|
||||
#include <components/esm/lightstate.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
@ -269,4 +270,24 @@ namespace MWClass
|
|||
}
|
||||
return std::make_pair(1,"");
|
||||
}
|
||||
|
||||
void Light::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
const ESM::LightState& state2 = dynamic_cast<const ESM::LightState&> (state);
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mTime = state2.mTime;
|
||||
}
|
||||
|
||||
void Light::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
ESM::LightState& state2 = dynamic_cast<ESM::LightState&> (state);
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
state2.mTime = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mTime;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,6 +71,14 @@ namespace MWClass
|
|||
virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const;
|
||||
|
||||
std::pair<int, std::string> canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const;
|
||||
|
||||
virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const;
|
||||
///< Read additional state from \a state into \a ptr.
|
||||
|
||||
virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const;
|
||||
///< Write additional state from \a ptr into \a state.
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -155,11 +155,8 @@ namespace MWClass
|
|||
int count = ptr.getRefData().getCount();
|
||||
|
||||
bool gold = isGold(ptr);
|
||||
|
||||
if (gold && ptr.getCellRef().mGoldValue != 1)
|
||||
count = ptr.getCellRef().mGoldValue;
|
||||
else if (gold)
|
||||
count *= ref->mBase->mData.mValue;
|
||||
if (gold)
|
||||
count *= getValue(ptr);
|
||||
|
||||
std::string countString;
|
||||
if (!gold)
|
||||
|
@ -204,7 +201,7 @@ namespace MWClass
|
|||
MWBase::Environment::get().getWorld()->getStore();
|
||||
|
||||
if (isGold(ptr)) {
|
||||
int goldAmount = ptr.getRefData().getCount();
|
||||
int goldAmount = getValue(ptr) * ptr.getRefData().getCount();
|
||||
|
||||
std::string base = "Gold_001";
|
||||
if (goldAmount >= 100)
|
||||
|
@ -223,6 +220,7 @@ namespace MWClass
|
|||
newRef.getPtr().get<ESM::Miscellaneous>();
|
||||
newPtr = MWWorld::Ptr(&cell.mMiscItems.insert(*ref), &cell);
|
||||
newPtr.getCellRef().mGoldValue = goldAmount;
|
||||
newPtr.getRefData().setCount(1);
|
||||
} else {
|
||||
MWWorld::LiveCellRef<ESM::Miscellaneous> *ref =
|
||||
ptr.get<ESM::Miscellaneous>();
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <components/esm/loadmgef.hpp>
|
||||
#include <components/esm/loadnpc.hpp>
|
||||
#include <components/esm/npcstate.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
@ -536,7 +537,7 @@ namespace MWClass
|
|||
weapon.getCellRef().mCharge = weapmaxhealth;
|
||||
damage *= float(weapon.getCellRef().mCharge) / weapmaxhealth;
|
||||
}
|
||||
|
||||
|
||||
if (!MWBase::Environment::get().getWorld()->getGodModeState())
|
||||
weapon.getCellRef().mCharge -= std::min(std::max(1,
|
||||
(int)(damage * gmst.find("fWeaponDamageMult")->getFloat())), weapon.getCellRef().mCharge);
|
||||
|
@ -603,10 +604,7 @@ namespace MWClass
|
|||
{
|
||||
MWMechanics::CastSpell cast(ptr, victim);
|
||||
cast.mHitPosition = hitPosition;
|
||||
bool success = cast.cast(weapon);
|
||||
|
||||
if (ptr.getRefData().getHandle() == "player" && success)
|
||||
skillUsageSucceeded (ptr, ESM::Skill::Enchant, 3);
|
||||
cast.cast(weapon);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -726,6 +724,9 @@ namespace MWClass
|
|||
if (armorref.mCharge == 0)
|
||||
inv.unequipItem(armor, ptr);
|
||||
|
||||
if (ptr.getRefData().getHandle() == "player")
|
||||
skillUsageSucceeded(ptr, get(armor).getEquipmentSkill(armor), 0);
|
||||
|
||||
switch(get(armor).getEquipmentSkill(armor))
|
||||
{
|
||||
case ESM::Skill::LightArmor:
|
||||
|
@ -739,6 +740,8 @@ namespace MWClass
|
|||
break;
|
||||
}
|
||||
}
|
||||
else if(ptr.getRefData().getHandle() == "player")
|
||||
skillUsageSucceeded(ptr, ESM::Skill::Unarmored, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -999,7 +1002,7 @@ namespace MWClass
|
|||
|
||||
return ref->mBase->mFlags & ESM::NPC::Essential;
|
||||
}
|
||||
|
||||
|
||||
void Npc::registerSelf()
|
||||
{
|
||||
boost::shared_ptr<Class> instance (new Npc);
|
||||
|
@ -1268,6 +1271,28 @@ namespace MWClass
|
|||
return 0;
|
||||
}
|
||||
|
||||
void Npc::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
const ESM::NpcState& state2 = dynamic_cast<const ESM::NpcState&> (state);
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mInventoryStore.
|
||||
readState (state2.mInventory);
|
||||
}
|
||||
|
||||
void Npc::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
ESM::NpcState& state2 = dynamic_cast<ESM::NpcState&> (state);
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mInventoryStore.
|
||||
writeState (state2.mInventory);
|
||||
}
|
||||
|
||||
const ESM::GameSetting *Npc::fMinWalkSpeed;
|
||||
const ESM::GameSetting *Npc::fMaxWalkSpeed;
|
||||
const ESM::GameSetting *Npc::fEncumberedMoveEffect;
|
||||
|
|
|
@ -137,7 +137,7 @@ namespace MWClass
|
|||
///< Is \a ptr essential? (i.e. may losing \a ptr make the game unwinnable)
|
||||
|
||||
virtual int getServices (const MWWorld::Ptr& actor) const;
|
||||
|
||||
|
||||
virtual bool isPersistent (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
virtual std::string getSoundIdFromSndGen(const MWWorld::Ptr &ptr, const std::string &name) const;
|
||||
|
@ -158,6 +158,14 @@ namespace MWClass
|
|||
virtual bool isNpc() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const;
|
||||
///< Read additional state from \a state into \a ptr.
|
||||
|
||||
virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const;
|
||||
///< Write additional state from \a ptr into \a state.
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -429,12 +429,12 @@ namespace MWClass
|
|||
return MWWorld::Ptr(&cell.mWeapons.insert(*ref), &cell);
|
||||
}
|
||||
|
||||
float Weapon::getEnchantmentPoints (const MWWorld::Ptr& ptr) const
|
||||
int Weapon::getEnchantmentPoints (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Weapon> *ref =
|
||||
ptr.get<ESM::Weapon>();
|
||||
|
||||
return ref->mBase->mData.mEnchant/10.f;
|
||||
return ref->mBase->mData.mEnchant;
|
||||
}
|
||||
|
||||
bool Weapon::canSell (const MWWorld::Ptr& item, int npcServices) const
|
||||
|
|
|
@ -84,7 +84,7 @@ namespace MWClass
|
|||
|
||||
virtual float getWeight (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
virtual float getEnchantmentPoints (const MWWorld::Ptr& ptr) const;
|
||||
virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -286,7 +286,7 @@ namespace MWDialogue
|
|||
|
||||
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
|
||||
win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext), title);
|
||||
MWBase::Environment::get().getJournal()->addTopic (topic, info->mId);
|
||||
MWBase::Environment::get().getJournal()->addTopic (topic, info->mId, mActor.getClass().getName(mActor));
|
||||
|
||||
executeScript (info->mResultScript);
|
||||
|
||||
|
@ -451,7 +451,7 @@ namespace MWDialogue
|
|||
|
||||
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
|
||||
MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addResponse (Interpreter::fixDefinesDialog(text, interpreterContext));
|
||||
MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId);
|
||||
MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId, mActor.getClass().getName(mActor));
|
||||
executeScript (info->mResultScript);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -171,7 +171,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c
|
|||
|
||||
// internally all globals are float :(
|
||||
return select.selectCompare (
|
||||
MWBase::Environment::get().getWorld()->getGlobalVariable (select.getName()).mFloat);
|
||||
MWBase::Environment::get().getWorld()->getGlobalFloat (select.getName()));
|
||||
|
||||
case SelectWrapper::Function_Local:
|
||||
{
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <components/esm/journalentry.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
|
@ -10,23 +12,55 @@
|
|||
|
||||
namespace MWDialogue
|
||||
{
|
||||
JournalEntry::JournalEntry() {}
|
||||
Entry::Entry() {}
|
||||
|
||||
JournalEntry::JournalEntry (const std::string& topic, const std::string& infoId)
|
||||
: mTopic (topic), mInfoId (infoId)
|
||||
{}
|
||||
|
||||
std::string JournalEntry::getText (const MWWorld::ESMStore& store) const
|
||||
Entry::Entry (const std::string& topic, const std::string& infoId)
|
||||
: mInfoId (infoId)
|
||||
{
|
||||
const ESM::Dialogue *dialogue =
|
||||
store.get<ESM::Dialogue>().find (mTopic);
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>().find (topic);
|
||||
|
||||
for (std::vector<ESM::DialInfo>::const_iterator iter (dialogue->mInfo.begin());
|
||||
iter!=dialogue->mInfo.end(); ++iter)
|
||||
if (iter->mId == mInfoId)
|
||||
return iter->mResponse;
|
||||
{
|
||||
/// \todo text replacement
|
||||
mText = iter->mResponse;
|
||||
return;
|
||||
}
|
||||
|
||||
throw std::runtime_error ("unknown info ID " + mInfoId + " for topic " + mTopic);
|
||||
throw std::runtime_error ("unknown info ID " + mInfoId + " for topic " + topic);
|
||||
}
|
||||
|
||||
Entry::Entry (const ESM::JournalEntry& record) : mInfoId (record.mInfo), mText (record.mText), mActorName(record.mActorName) {}
|
||||
|
||||
std::string Entry::getText() const
|
||||
{
|
||||
return mText;
|
||||
}
|
||||
|
||||
void Entry::write (ESM::JournalEntry& entry) const
|
||||
{
|
||||
entry.mInfo = mInfoId;
|
||||
entry.mText = mText;
|
||||
entry.mActorName = mActorName;
|
||||
}
|
||||
|
||||
|
||||
JournalEntry::JournalEntry() {}
|
||||
|
||||
JournalEntry::JournalEntry (const std::string& topic, const std::string& infoId)
|
||||
: Entry (topic, infoId), mTopic (topic)
|
||||
{}
|
||||
|
||||
JournalEntry::JournalEntry (const ESM::JournalEntry& record)
|
||||
: Entry (record), mTopic (record.mTopic)
|
||||
{}
|
||||
|
||||
void JournalEntry::write (ESM::JournalEntry& entry) const
|
||||
{
|
||||
Entry::write (entry);
|
||||
entry.mTopic = mTopic;
|
||||
}
|
||||
|
||||
JournalEntry JournalEntry::makeFromQuest (const std::string& topic, int index)
|
||||
|
@ -49,6 +83,7 @@ namespace MWDialogue
|
|||
throw std::runtime_error ("unknown journal index for topic " + topic);
|
||||
}
|
||||
|
||||
|
||||
StampedJournalEntry::StampedJournalEntry()
|
||||
: mDay (0), mMonth (0), mDayOfMonth (0)
|
||||
{}
|
||||
|
@ -58,11 +93,24 @@ namespace MWDialogue
|
|||
: JournalEntry (topic, infoId), mDay (day), mMonth (month), mDayOfMonth (dayOfMonth)
|
||||
{}
|
||||
|
||||
StampedJournalEntry::StampedJournalEntry (const ESM::JournalEntry& record)
|
||||
: JournalEntry (record), mDay (record.mDay), mMonth (record.mMonth),
|
||||
mDayOfMonth (record.mDayOfMonth)
|
||||
{}
|
||||
|
||||
void StampedJournalEntry::write (ESM::JournalEntry& entry) const
|
||||
{
|
||||
JournalEntry::write (entry);
|
||||
entry.mDay = mDay;
|
||||
entry.mMonth = mMonth;
|
||||
entry.mDayOfMonth = mDayOfMonth;
|
||||
}
|
||||
|
||||
StampedJournalEntry StampedJournalEntry::makeFromQuest (const std::string& topic, int index)
|
||||
{
|
||||
int day = MWBase::Environment::get().getWorld()->getGlobalVariable ("dayspassed").mLong;
|
||||
int month = MWBase::Environment::get().getWorld()->getGlobalVariable ("month").mLong;
|
||||
int dayOfMonth = MWBase::Environment::get().getWorld()->getGlobalVariable ("day").mLong;
|
||||
int day = MWBase::Environment::get().getWorld()->getGlobalInt ("dayspassed");
|
||||
int month = MWBase::Environment::get().getWorld()->getGlobalInt ("month");
|
||||
int dayOfMonth = MWBase::Environment::get().getWorld()->getGlobalInt ("day");
|
||||
|
||||
return StampedJournalEntry (topic, idFromIndex (topic, index), day, month, dayOfMonth);
|
||||
}
|
||||
|
|
|
@ -3,24 +3,45 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
namespace MWWorld
|
||||
namespace ESM
|
||||
{
|
||||
struct ESMStore;
|
||||
struct JournalEntry;
|
||||
}
|
||||
|
||||
namespace MWDialogue
|
||||
{
|
||||
/// \brief A quest or dialogue entry
|
||||
struct JournalEntry
|
||||
/// \brief Basic quest/dialogue/topic entry
|
||||
struct Entry
|
||||
{
|
||||
std::string mInfoId;
|
||||
std::string mText;
|
||||
std::string mActorName; // optional
|
||||
|
||||
Entry();
|
||||
|
||||
Entry (const std::string& topic, const std::string& infoId);
|
||||
|
||||
Entry (const ESM::JournalEntry& record);
|
||||
|
||||
std::string getText() const;
|
||||
|
||||
void write (ESM::JournalEntry& entry) const;
|
||||
};
|
||||
|
||||
/// \brief A dialogue entry
|
||||
///
|
||||
/// Same as entry, but store TopicID
|
||||
struct JournalEntry : public Entry
|
||||
{
|
||||
std::string mTopic;
|
||||
std::string mInfoId;
|
||||
|
||||
JournalEntry();
|
||||
|
||||
JournalEntry (const std::string& topic, const std::string& infoId);
|
||||
|
||||
std::string getText (const MWWorld::ESMStore& store) const;
|
||||
JournalEntry (const ESM::JournalEntry& record);
|
||||
|
||||
void write (ESM::JournalEntry& entry) const;
|
||||
|
||||
static JournalEntry makeFromQuest (const std::string& topic, int index);
|
||||
|
||||
|
@ -39,6 +60,10 @@ namespace MWDialogue
|
|||
StampedJournalEntry (const std::string& topic, const std::string& infoId,
|
||||
int day, int month, int dayOfMonth);
|
||||
|
||||
StampedJournalEntry (const ESM::JournalEntry& record);
|
||||
|
||||
void write (ESM::JournalEntry& entry) const;
|
||||
|
||||
static StampedJournalEntry makeFromQuest (const std::string& topic, int index);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
|
||||
#include "journalimp.hpp"
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include <components/esm/esmwriter.hpp>
|
||||
#include <components/esm/esmreader.hpp>
|
||||
#include <components/esm/queststate.hpp>
|
||||
#include <components/esm/journalentry.hpp>
|
||||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -26,6 +33,38 @@ namespace MWDialogue
|
|||
return iter->second;
|
||||
}
|
||||
|
||||
Topic& Journal::getTopic (const std::string& id)
|
||||
{
|
||||
TTopicContainer::iterator iter = mTopics.find (id);
|
||||
|
||||
if (iter==mTopics.end())
|
||||
{
|
||||
std::pair<TTopicContainer::iterator, bool> result
|
||||
= mTopics.insert (std::make_pair (id, Topic (id)));
|
||||
|
||||
iter = result.first;
|
||||
}
|
||||
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
bool Journal::isThere (const std::string& topicId, const std::string& infoId) const
|
||||
{
|
||||
if (const ESM::Dialogue *dialogue =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>().search (topicId))
|
||||
{
|
||||
if (infoId.empty())
|
||||
return true;
|
||||
|
||||
for (std::vector<ESM::DialInfo>::const_iterator iter (dialogue->mInfo.begin());
|
||||
iter!=dialogue->mInfo.end(); ++iter)
|
||||
if (iter->mId == infoId)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Journal::Journal()
|
||||
{}
|
||||
|
||||
|
@ -64,19 +103,13 @@ namespace MWDialogue
|
|||
quest.setIndex (index);
|
||||
}
|
||||
|
||||
void Journal::addTopic (const std::string& topicId, const std::string& infoId)
|
||||
void Journal::addTopic (const std::string& topicId, const std::string& infoId, const std::string& actorName)
|
||||
{
|
||||
TTopicContainer::iterator iter = mTopics.find (topicId);
|
||||
Topic& topic = getTopic (topicId);
|
||||
|
||||
if (iter==mTopics.end())
|
||||
{
|
||||
std::pair<TTopicContainer::iterator, bool> result
|
||||
= mTopics.insert (std::make_pair (topicId, Topic (topicId)));
|
||||
|
||||
iter = result.first;
|
||||
}
|
||||
|
||||
iter->second.addEntry (JournalEntry (topicId, infoId));
|
||||
JournalEntry entry(topicId, infoId);
|
||||
entry.mActorName = actorName;
|
||||
topic.addEntry (entry);
|
||||
}
|
||||
|
||||
int Journal::getJournalIndex (const std::string& id) const
|
||||
|
@ -118,4 +151,106 @@ namespace MWDialogue
|
|||
{
|
||||
return mTopics.end();
|
||||
}
|
||||
|
||||
int Journal::countSavedGameRecords() const
|
||||
{
|
||||
int count = static_cast<int> (mQuests.size());
|
||||
|
||||
for (TQuestIter iter (mQuests.begin()); iter!=mQuests.end(); ++iter)
|
||||
count += std::distance (iter->second.begin(), iter->second.end());
|
||||
|
||||
count += std::distance (mJournal.begin(), mJournal.end());
|
||||
|
||||
for (TTopicIter iter (mTopics.begin()); iter!=mTopics.end(); ++iter)
|
||||
count += std::distance (iter->second.begin(), iter->second.end());
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void Journal::write (ESM::ESMWriter& writer) const
|
||||
{
|
||||
for (TQuestIter iter (mQuests.begin()); iter!=mQuests.end(); ++iter)
|
||||
{
|
||||
const Quest& quest = iter->second;
|
||||
|
||||
ESM::QuestState state;
|
||||
quest.write (state);
|
||||
writer.startRecord (ESM::REC_QUES);
|
||||
state.save (writer);
|
||||
writer.endRecord (ESM::REC_QUES);
|
||||
|
||||
for (Topic::TEntryIter iter (quest.begin()); iter!=quest.end(); ++iter)
|
||||
{
|
||||
ESM::JournalEntry entry;
|
||||
entry.mType = ESM::JournalEntry::Type_Quest;
|
||||
entry.mTopic = quest.getTopic();
|
||||
iter->write (entry);
|
||||
writer.startRecord (ESM::REC_JOUR);
|
||||
entry.save (writer);
|
||||
writer.endRecord (ESM::REC_JOUR);
|
||||
}
|
||||
}
|
||||
|
||||
for (TEntryIter iter (mJournal.begin()); iter!=mJournal.end(); ++iter)
|
||||
{
|
||||
ESM::JournalEntry entry;
|
||||
entry.mType = ESM::JournalEntry::Type_Journal;
|
||||
iter->write (entry);
|
||||
writer.startRecord (ESM::REC_JOUR);
|
||||
entry.save (writer);
|
||||
writer.endRecord (ESM::REC_JOUR);
|
||||
}
|
||||
|
||||
for (TTopicIter iter (mTopics.begin()); iter!=mTopics.end(); ++iter)
|
||||
{
|
||||
const Topic& topic = iter->second;
|
||||
|
||||
for (Topic::TEntryIter iter (topic.begin()); iter!=topic.end(); ++iter)
|
||||
{
|
||||
ESM::JournalEntry entry;
|
||||
entry.mType = ESM::JournalEntry::Type_Topic;
|
||||
entry.mTopic = topic.getTopic();
|
||||
iter->write (entry);
|
||||
writer.startRecord (ESM::REC_JOUR);
|
||||
entry.save (writer);
|
||||
writer.endRecord (ESM::REC_JOUR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Journal::readRecord (ESM::ESMReader& reader, int32_t type)
|
||||
{
|
||||
if (type==ESM::REC_JOUR)
|
||||
{
|
||||
ESM::JournalEntry record;
|
||||
record.load (reader);
|
||||
|
||||
if (isThere (record.mTopic, record.mInfo))
|
||||
switch (record.mType)
|
||||
{
|
||||
case ESM::JournalEntry::Type_Quest:
|
||||
|
||||
getQuest (record.mTopic).insertEntry (record);
|
||||
break;
|
||||
|
||||
case ESM::JournalEntry::Type_Journal:
|
||||
|
||||
mJournal.push_back (record);
|
||||
break;
|
||||
|
||||
case ESM::JournalEntry::Type_Topic:
|
||||
|
||||
getTopic (record.mTopic).insertEntry (record);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (type==ESM::REC_QUES)
|
||||
{
|
||||
ESM::QuestState record;
|
||||
record.load (reader);
|
||||
|
||||
if (isThere (record.mTopic))
|
||||
mQuests.insert (std::make_pair (record.mTopic, record));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,14 @@ namespace MWDialogue
|
|||
TQuestContainer mQuests;
|
||||
TTopicContainer mTopics;
|
||||
|
||||
private:
|
||||
|
||||
Quest& getQuest (const std::string& id);
|
||||
|
||||
Topic& getTopic (const std::string& id);
|
||||
|
||||
bool isThere (const std::string& topicId, const std::string& infoId = "") const;
|
||||
|
||||
public:
|
||||
|
||||
Journal();
|
||||
|
@ -32,7 +38,7 @@ namespace MWDialogue
|
|||
virtual int getJournalIndex (const std::string& id) const;
|
||||
///< Get the journal index.
|
||||
|
||||
virtual void addTopic (const std::string& topicId, const std::string& infoId);
|
||||
virtual void addTopic (const std::string& topicId, const std::string& infoId, const std::string& actorName);
|
||||
|
||||
virtual TEntryIter begin() const;
|
||||
///< Iterator pointing to the begin of the main journal.
|
||||
|
@ -55,6 +61,12 @@ namespace MWDialogue
|
|||
|
||||
virtual TTopicIter topicEnd() const;
|
||||
///< Iterator pointing past the last topic.
|
||||
|
||||
virtual int countSavedGameRecords() const;
|
||||
|
||||
virtual void write (ESM::ESMWriter& writer) const;
|
||||
|
||||
virtual void readRecord (ESM::ESMReader& reader, int32_t type);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
|
||||
#include "quest.hpp"
|
||||
|
||||
#include <components/esm/queststate.hpp>
|
||||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -16,7 +18,11 @@ namespace MWDialogue
|
|||
: Topic (topic), mIndex (0), mFinished (false)
|
||||
{}
|
||||
|
||||
const std::string Quest::getName() const
|
||||
Quest::Quest (const ESM::QuestState& state)
|
||||
: Topic (state.mTopic), mIndex (state.mState), mFinished (state.mFinished!=0)
|
||||
{}
|
||||
|
||||
std::string Quest::getName() const
|
||||
{
|
||||
const ESM::Dialogue *dialogue =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>().find (mTopic);
|
||||
|
@ -82,12 +88,20 @@ namespace MWDialogue
|
|||
if (index==-1)
|
||||
throw std::runtime_error ("unknown journal entry for topic " + mTopic);
|
||||
|
||||
setIndex (index);
|
||||
if (index > mIndex)
|
||||
setIndex (index);
|
||||
|
||||
for (TEntryIter iter (mEntries.begin()); iter!=mEntries.end(); ++iter)
|
||||
if (*iter==entry.mInfoId)
|
||||
if (iter->mInfoId==entry.mInfoId)
|
||||
return;
|
||||
|
||||
mEntries.push_back (entry.mInfoId);
|
||||
mEntries.push_back (entry); // we want slicing here
|
||||
}
|
||||
|
||||
void Quest::write (ESM::QuestState& state) const
|
||||
{
|
||||
state.mTopic = getTopic();
|
||||
state.mState = mIndex;
|
||||
state.mFinished = mFinished;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,9 +3,14 @@
|
|||
|
||||
#include "topic.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct QuestState;
|
||||
}
|
||||
|
||||
namespace MWDialogue
|
||||
{
|
||||
/// \brief A quest in progress or a compelted quest
|
||||
/// \brief A quest in progress or a completed quest
|
||||
class Quest : public Topic
|
||||
{
|
||||
int mIndex;
|
||||
|
@ -17,13 +22,15 @@ namespace MWDialogue
|
|||
|
||||
Quest (const std::string& topic);
|
||||
|
||||
const std::string getName() const;
|
||||
Quest (const ESM::QuestState& state);
|
||||
|
||||
virtual std::string getName() const;
|
||||
///< May be an empty string
|
||||
|
||||
int getIndex() const;
|
||||
|
||||
void setIndex (int index);
|
||||
///< Calling this function with a non-existant index while throw an exception.
|
||||
///< Calling this function with a non-existent index will throw an exception.
|
||||
|
||||
bool isFinished() const;
|
||||
|
||||
|
@ -31,6 +38,8 @@ namespace MWDialogue
|
|||
///< Add entry and adjust index accordingly.
|
||||
///
|
||||
/// \note Redundant entries are ignored, but the index is still adjusted.
|
||||
|
||||
void write (ESM::QuestState& state) const;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
|
||||
#include "topic.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
namespace MWDialogue
|
||||
|
@ -9,7 +12,8 @@ namespace MWDialogue
|
|||
{}
|
||||
|
||||
Topic::Topic (const std::string& topic)
|
||||
: mTopic (topic)
|
||||
: mTopic (topic), mName (
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>().find (topic)->mId)
|
||||
{}
|
||||
|
||||
Topic::~Topic()
|
||||
|
@ -20,11 +24,29 @@ namespace MWDialogue
|
|||
if (entry.mTopic!=mTopic)
|
||||
throw std::runtime_error ("topic does not match: " + mTopic);
|
||||
|
||||
for (TEntryIter iter = begin(); iter!=end(); ++iter)
|
||||
if (*iter==entry.mInfoId)
|
||||
// bail out if we already have heard this
|
||||
for (Topic::TEntryIter it = mEntries.begin(); it != mEntries.end(); ++it)
|
||||
{
|
||||
if (it->mInfoId == entry.mInfoId)
|
||||
return;
|
||||
}
|
||||
|
||||
mEntries.push_back (entry.mInfoId);
|
||||
mEntries.push_back (entry); // we want slicing here
|
||||
}
|
||||
|
||||
void Topic::insertEntry (const ESM::JournalEntry& entry)
|
||||
{
|
||||
mEntries.push_back (entry);
|
||||
}
|
||||
|
||||
std::string Topic::getTopic() const
|
||||
{
|
||||
return mTopic;
|
||||
}
|
||||
|
||||
std::string Topic::getName() const
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
Topic::TEntryIter Topic::begin() const
|
||||
|
|
|
@ -6,6 +6,11 @@
|
|||
|
||||
#include "journalentry.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct JournalEntry;
|
||||
}
|
||||
|
||||
namespace MWDialogue
|
||||
{
|
||||
/// \brief Collection of seen responses for a topic
|
||||
|
@ -13,13 +18,14 @@ namespace MWDialogue
|
|||
{
|
||||
public:
|
||||
|
||||
typedef std::vector<std::string> TEntryContainer;
|
||||
typedef std::vector<Entry> TEntryContainer;
|
||||
typedef TEntryContainer::const_iterator TEntryIter;
|
||||
|
||||
protected:
|
||||
|
||||
std::string mTopic;
|
||||
TEntryContainer mEntries; // info-IDs
|
||||
std::string mName;
|
||||
TEntryContainer mEntries;
|
||||
|
||||
public:
|
||||
|
||||
|
@ -34,7 +40,13 @@ namespace MWDialogue
|
|||
///
|
||||
/// \note Redundant entries are ignored.
|
||||
|
||||
std::string const & getName () const { return mTopic; }
|
||||
void insertEntry (const ESM::JournalEntry& entry);
|
||||
///< Add entry without checking for redundant entries or modifying the state of the
|
||||
/// topic otherwise
|
||||
|
||||
std::string getTopic() const;
|
||||
|
||||
virtual std::string getName() const;
|
||||
|
||||
TEntryIter begin() const;
|
||||
///< Iterator pointing to the begin of the journal for this topic.
|
||||
|
|
|
@ -33,8 +33,7 @@ namespace MWGui
|
|||
|
||||
getWidget(mBirthList, "BirthsignList");
|
||||
mBirthList->setScrollVisible(true);
|
||||
mBirthList->eventListSelectAccept += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth);
|
||||
mBirthList->eventListMouseItemActivate += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth);
|
||||
mBirthList->eventListSelectAccept += MyGUI::newDelegate(this, &BirthDialog::onAccept);
|
||||
mBirthList->eventListChangePosition += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth);
|
||||
|
||||
MyGUI::Button* backButton;
|
||||
|
@ -97,6 +96,14 @@ namespace MWGui
|
|||
eventDone(this);
|
||||
}
|
||||
|
||||
void BirthDialog::onAccept(MyGUI::ListBox *_sender, size_t _index)
|
||||
{
|
||||
onSelectBirth(_sender, _index);
|
||||
if(mBirthList->getIndexSelected() == MyGUI::ITEM_NONE)
|
||||
return;
|
||||
eventDone(this);
|
||||
}
|
||||
|
||||
void BirthDialog::onBackClicked(MyGUI::Widget* _sender)
|
||||
{
|
||||
eventBack();
|
||||
|
|
|
@ -38,6 +38,7 @@ namespace MWGui
|
|||
protected:
|
||||
void onSelectBirth(MyGUI::ListBox* _sender, size_t _index);
|
||||
|
||||
void onAccept(MyGUI::ListBox* _sender, size_t index);
|
||||
void onOkClicked(MyGUI::Widget* _sender);
|
||||
void onBackClicked(MyGUI::Widget* _sender);
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwmechanics/npcstats.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/fallback.hpp"
|
||||
|
||||
|
@ -47,9 +47,8 @@ namespace
|
|||
void updatePlayerHealth()
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get(player).getCreatureStats(player);
|
||||
|
||||
creatureStats.updateHealth();
|
||||
MWMechanics::NpcStats& npcStats = MWWorld::Class::get(player).getNpcStats(player);
|
||||
npcStats.updateHealth();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -82,8 +82,7 @@ namespace MWGui
|
|||
|
||||
getWidget(mClassList, "ClassList");
|
||||
mClassList->setScrollVisible(true);
|
||||
mClassList->eventListSelectAccept += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass);
|
||||
mClassList->eventListMouseItemActivate += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass);
|
||||
mClassList->eventListSelectAccept += MyGUI::newDelegate(this, &PickClassDialog::onAccept);
|
||||
mClassList->eventListChangePosition += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass);
|
||||
|
||||
getWidget(mClassImage, "ClassImage");
|
||||
|
@ -152,6 +151,14 @@ namespace MWGui
|
|||
eventBack();
|
||||
}
|
||||
|
||||
void PickClassDialog::onAccept(MyGUI::ListBox* _sender, size_t _index)
|
||||
{
|
||||
onSelectClass(_sender, _index);
|
||||
if(mClassList->getIndexSelected() == MyGUI::ITEM_NONE)
|
||||
return;
|
||||
eventDone(this);
|
||||
}
|
||||
|
||||
void PickClassDialog::onSelectClass(MyGUI::ListBox* _sender, size_t _index)
|
||||
{
|
||||
if (_index == MyGUI::ITEM_NONE)
|
||||
|
|
|
@ -111,6 +111,7 @@ namespace MWGui
|
|||
|
||||
protected:
|
||||
void onSelectClass(MyGUI::ListBox* _sender, size_t _index);
|
||||
void onAccept(MyGUI::ListBox* _sender, size_t _index);
|
||||
|
||||
void onOkClicked(MyGUI::Widget* _sender);
|
||||
void onBackClicked(MyGUI::Widget* _sender);
|
||||
|
|
|
@ -235,7 +235,7 @@ namespace MWGui
|
|||
|
||||
mItemView->setModel (mSortModel);
|
||||
|
||||
MyGUI::InputManager::getInstance().setKeyFocusWidget(mCloseButton);
|
||||
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton);
|
||||
|
||||
// Careful here. setTitle may cause size updates, causing itemview redraw, so make sure to do it last
|
||||
// or we end up using a possibly invalid model.
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include <boost/range/algorithm/copy.hpp>
|
||||
#include <OgreUTFString.h>
|
||||
|
||||
#include <OgreResourceGroupManager.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
int convertFromHex(std::string hex)
|
||||
|
@ -288,6 +290,16 @@ namespace MWGui
|
|||
MyGUI::ImageBox* box = mParent->createWidget<MyGUI::ImageBox> ("ImageBox",
|
||||
MyGUI::IntCoord(0, mHeight, width, height), MyGUI::Align::Left | MyGUI::Align::Top,
|
||||
mParent->getName() + boost::lexical_cast<std::string>(mParent->getChildCount()));
|
||||
|
||||
// Apparently a bug with some morrowind versions, they reference the image without the size suffix.
|
||||
// So if the image isn't found, try appending the size.
|
||||
if (!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup("bookart\\"+image))
|
||||
{
|
||||
std::stringstream str;
|
||||
str << image.substr(0, image.rfind(".")) << "_" << width << "_" << height << image.substr(image.rfind("."));
|
||||
image = str.str();
|
||||
}
|
||||
|
||||
box->setImageTexture("bookart\\" + image);
|
||||
box->setProperty("NeedMouse", "false");
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ namespace MWGui
|
|||
getWidget(mRightPane, "RightPane");
|
||||
getWidget(mArmorRating, "ArmorRating");
|
||||
|
||||
mAvatar->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onAvatarClicked);
|
||||
mAvatarImage->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onAvatarClicked);
|
||||
|
||||
getWidget(mItemView, "ItemView");
|
||||
mItemView->eventItemClicked += MyGUI::newDelegate(this, &InventoryWindow::onItemSelected);
|
||||
|
@ -76,11 +76,12 @@ namespace MWGui
|
|||
|
||||
void InventoryWindow::adjustPanes()
|
||||
{
|
||||
const float aspect = 0.5; // fixed aspect ratio for the left pane
|
||||
mLeftPane->setSize( (mMainWidget->getSize().height-44) * aspect, mMainWidget->getSize().height-44 );
|
||||
mRightPane->setCoord( mLeftPane->getPosition().left + (mMainWidget->getSize().height-44) * aspect + 4,
|
||||
const float aspect = 0.5; // fixed aspect ratio for the avatar image
|
||||
float leftPaneWidth = (mMainWidget->getSize().height-44-mArmorRating->getHeight()) * aspect;
|
||||
mLeftPane->setSize( leftPaneWidth, mMainWidget->getSize().height-44 );
|
||||
mRightPane->setCoord( mLeftPane->getPosition().left + leftPaneWidth + 4,
|
||||
mRightPane->getPosition().top,
|
||||
mMainWidget->getSize().width - 12 - (mMainWidget->getSize().height-44) * aspect - 15,
|
||||
mMainWidget->getSize().width - 12 - leftPaneWidth - 15,
|
||||
mMainWidget->getSize().height-44 );
|
||||
}
|
||||
|
||||
|
@ -418,9 +419,9 @@ namespace MWGui
|
|||
else
|
||||
{
|
||||
MyGUI::IntPoint mousePos = MyGUI::InputManager::getInstance ().getLastPressedPosition (MyGUI::MouseButton::Left);
|
||||
MyGUI::IntPoint relPos = mousePos - mAvatar->getAbsolutePosition ();
|
||||
int realX = int(float(relPos.left) / float(mAvatar->getSize().width) * 512.f );
|
||||
int realY = int(float(relPos.top) / float(mAvatar->getSize().height) * 1024.f );
|
||||
MyGUI::IntPoint relPos = mousePos - mAvatarImage->getAbsolutePosition ();
|
||||
int realX = int(float(relPos.left) / float(mAvatarImage->getSize().width) * 512.f );
|
||||
int realY = int(float(relPos.top) / float(mAvatarImage->getSize().height) * 1024.f );
|
||||
|
||||
MWWorld::Ptr itemSelected = getAvatarSelectedItem (realX, realY);
|
||||
if (itemSelected.isEmpty ())
|
||||
|
@ -487,11 +488,18 @@ namespace MWGui
|
|||
if (mPreviewDirty)
|
||||
{
|
||||
mPreviewDirty = false;
|
||||
MyGUI::IntSize size = mAvatar->getSize();
|
||||
MyGUI::IntSize size = mAvatarImage->getSize();
|
||||
|
||||
mPreview.update (size.width, size.height);
|
||||
mAvatarImage->setSize(MyGUI::IntSize(std::max(mAvatar->getSize().width, 512), std::max(mAvatar->getSize().height, 1024)));
|
||||
|
||||
mAvatarImage->setImageTexture("CharacterPreview");
|
||||
mAvatarImage->setImageCoord(MyGUI::IntCoord(0, 0, std::min(512, size.width), std::min(1024, size.height)));
|
||||
mAvatarImage->setImageTile(MyGUI::IntSize(std::min(512, size.width), std::min(1024, size.height)));
|
||||
|
||||
mArmorRating->setCaptionWithReplacing ("#{sArmor}: "
|
||||
+ boost::lexical_cast<std::string>(static_cast<int>(MWWorld::Class::get(mPtr).getArmorRating(mPtr))));
|
||||
if (mArmorRating->getTextSize().width > mArmorRating->getSize().width)
|
||||
mArmorRating->setCaptionWithReplacing (boost::lexical_cast<std::string>(static_cast<int>(MWWorld::Class::get(mPtr).getArmorRating(mPtr))));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -502,9 +510,6 @@ namespace MWGui
|
|||
MWBase::Environment::get().getWindowManager()->getSpellWindow()->updateSpells();
|
||||
|
||||
mPreviewDirty = true;
|
||||
|
||||
mArmorRating->setCaptionWithReplacing ("#{sArmor}: "
|
||||
+ boost::lexical_cast<std::string>(static_cast<int>(MWWorld::Class::get(mPtr).getArmorRating(mPtr))));
|
||||
}
|
||||
|
||||
void InventoryWindow::pickUpObject (MWWorld::Ptr object)
|
||||
|
@ -551,9 +556,4 @@ namespace MWGui
|
|||
|
||||
MWBase::Environment::get().getMechanicsManager()->itemTaken(player, newObject, count);
|
||||
}
|
||||
|
||||
MyGUI::IntCoord InventoryWindow::getAvatarScreenCoord ()
|
||||
{
|
||||
return mAvatar->getAbsoluteCoord ();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,8 +31,6 @@ namespace MWGui
|
|||
|
||||
void pickUpObject (MWWorld::Ptr object);
|
||||
|
||||
MyGUI::IntCoord getAvatarScreenCoord();
|
||||
|
||||
MWWorld::Ptr getAvatarSelectedItem(int x, int y);
|
||||
|
||||
void rebuildAvatar() {
|
||||
|
|
|
@ -196,34 +196,6 @@ book JournalBooks::createEmptyJournalBook ()
|
|||
typesetter->lineBreak ();
|
||||
typesetter->write (body, to_utf8_span ("You should have gone though the starting quest and got an initial quest."));
|
||||
|
||||
BookTypesetter::Style* big = typesetter->createStyle ("", MyGUI::Colour::Black);
|
||||
BookTypesetter::Style* test = typesetter->createStyle ("MonoFont", MyGUI::Colour::Blue);
|
||||
|
||||
typesetter->sectionBreak (20);
|
||||
typesetter->write (body, to_utf8_span (
|
||||
"The layout engine doesn't currently support aligning fonts to "
|
||||
"their baseline within a single line so the following text looks "
|
||||
"funny. In order to properly implement it, a stupidly simple "
|
||||
"change is needed in MyGUI to report the where the baseline is for "
|
||||
"a particular font"
|
||||
));
|
||||
|
||||
typesetter->sectionBreak (20);
|
||||
typesetter->write (big, to_utf8_span ("big text g"));
|
||||
typesetter->write (body, to_utf8_span (" проверяем только в дебаге"));
|
||||
typesetter->write (body, to_utf8_span (" normal g"));
|
||||
typesetter->write (big, to_utf8_span (" done g"));
|
||||
|
||||
typesetter->sectionBreak (20);
|
||||
typesetter->write (test, to_utf8_span (
|
||||
"int main (int argc,\n"
|
||||
" char ** argv)\n"
|
||||
"{\n"
|
||||
" print (\"hello world!\\n\");\n"
|
||||
" return 0;\n"
|
||||
"}\n"
|
||||
));
|
||||
|
||||
return typesetter->complete ();
|
||||
}
|
||||
|
||||
|
|
|
@ -20,8 +20,6 @@ namespace MWGui {
|
|||
|
||||
struct JournalViewModelImpl;
|
||||
|
||||
static void injectMonthName (std::ostream & os, int month);
|
||||
|
||||
struct JournalViewModelImpl : JournalViewModel
|
||||
{
|
||||
typedef KeywordSearch <std::string, intptr_t> KeywordSearchT;
|
||||
|
@ -237,21 +235,21 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
|
||||
std::string getText () const
|
||||
{
|
||||
return itr->getText(MWBase::Environment::get().getWorld()->getStore());
|
||||
return itr->getText();
|
||||
}
|
||||
|
||||
Utf8Span timestamp () const
|
||||
{
|
||||
if (timestamp_buffer.empty ())
|
||||
{
|
||||
std::string dayStr = MyGUI::LanguageManager::getInstance().replaceTags("#{sDay}");
|
||||
|
||||
std::ostringstream os;
|
||||
|
||||
os << itr->mDayOfMonth << ' ';
|
||||
|
||||
injectMonthName (os, itr->mMonth);
|
||||
|
||||
const std::string& dayStr = MyGUI::LanguageManager::getInstance().replaceTags("#{sDay}");
|
||||
os << " (" << dayStr << " " << (itr->mDay + 1) << ')';
|
||||
os
|
||||
<< itr->mDayOfMonth << ' '
|
||||
<< MWBase::Environment::get().getWorld()->getMonthName (itr->mMonth)
|
||||
<< " (" << dayStr << " " << (itr->mDay + 1) << ')';
|
||||
|
||||
timestamp_buffer = os.str ();
|
||||
}
|
||||
|
@ -272,7 +270,7 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
{
|
||||
for (MWDialogue::Topic::TEntryIter j = quest->begin (); j != quest->end (); ++j)
|
||||
{
|
||||
if (i->mInfoId == *j)
|
||||
if (i->mInfoId == j->mInfoId)
|
||||
visitor (JournalEntryImpl <MWBase::Journal::TEntryIter> (this, i));
|
||||
}
|
||||
}
|
||||
|
@ -292,9 +290,7 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
void visitTopicName (TopicId topicId, boost::function <void (Utf8Span)> visitor) const
|
||||
{
|
||||
MWDialogue::Topic const & topic = * reinterpret_cast <MWDialogue::Topic const *> (topicId);
|
||||
// This is to get the correct case for the topic
|
||||
const std::string& name = MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>().find(topic.getName())->mId;
|
||||
visitor (toUtf8Span (name));
|
||||
visitor (toUtf8Span (topic.getName()));
|
||||
}
|
||||
|
||||
void visitTopicNamesStartingWith (char character, boost::function < void (TopicId , Utf8Span) > visitor) const
|
||||
|
@ -306,10 +302,7 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
if (i->first [0] != std::tolower (character, mLocale))
|
||||
continue;
|
||||
|
||||
// This is to get the correct case for the topic
|
||||
const std::string& name = MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>().find(i->first)->mId;
|
||||
|
||||
visitor (TopicId (&i->second), toUtf8Span (name));
|
||||
visitor (TopicId (&i->second), toUtf8Span (i->second.getName()));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -318,24 +311,18 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
{
|
||||
MWDialogue::Topic const & mTopic;
|
||||
|
||||
mutable std::string source_buffer;
|
||||
|
||||
TopicEntryImpl (JournalViewModelImpl const * model, MWDialogue::Topic const & topic, iterator_t itr) :
|
||||
BaseEntry (model, itr), mTopic (topic)
|
||||
{}
|
||||
|
||||
std::string getText () const
|
||||
{
|
||||
/// \todo defines are not replaced (%PCName etc). should probably be done elsewhere though since we need the actor
|
||||
return mTopic.getEntry (*itr).getText(MWBase::Environment::get().getWorld()->getStore());
|
||||
|
||||
return itr->getText();
|
||||
}
|
||||
|
||||
Utf8Span source () const
|
||||
{
|
||||
if (source_buffer.empty ())
|
||||
source_buffer = "someone";
|
||||
return toUtf8Span (source_buffer);
|
||||
return toUtf8Span (itr->mActorName);
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -351,38 +338,6 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
}
|
||||
};
|
||||
|
||||
static void injectMonthName (std::ostream & os, int month)
|
||||
{
|
||||
MyGUI::LanguageManager& lm = MyGUI::LanguageManager::getInstance();
|
||||
|
||||
if (month == 0)
|
||||
os << lm.replaceTags ("#{sMonthMorningstar}");
|
||||
else if (month == 1)
|
||||
os << lm.replaceTags ("#{sMonthSunsdawn}");
|
||||
else if (month == 2)
|
||||
os << lm.replaceTags ("#{sMonthFirstseed}");
|
||||
else if (month == 3)
|
||||
os << lm.replaceTags ("#{sMonthRainshand}");
|
||||
else if (month == 4)
|
||||
os << lm.replaceTags ("#{sMonthSecondseed}");
|
||||
else if (month == 5)
|
||||
os << lm.replaceTags ("#{sMonthMidyear}");
|
||||
else if (month == 6)
|
||||
os << lm.replaceTags ("#{sMonthSunsheight}");
|
||||
else if (month == 7)
|
||||
os << lm.replaceTags ("#{sMonthLastseed}");
|
||||
else if (month == 8)
|
||||
os << lm.replaceTags ("#{sMonthHeartfire}");
|
||||
else if (month == 9)
|
||||
os << lm.replaceTags ("#{sMonthFrostfall}");
|
||||
else if (month == 10)
|
||||
os << lm.replaceTags ("#{sMonthSunsdusk}");
|
||||
else if (month == 11)
|
||||
os << lm.replaceTags ("#{sMonthEveningstar}");
|
||||
else
|
||||
os << month;
|
||||
}
|
||||
|
||||
JournalViewModel::Ptr JournalViewModel::create ()
|
||||
{
|
||||
return boost::make_shared <JournalViewModelImpl> ();
|
||||
|
|
|
@ -155,7 +155,6 @@ namespace MWGui
|
|||
void LevelupDialog::onOkButtonClicked (MyGUI::Widget* sender)
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
|
||||
MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get(player).getCreatureStats (player);
|
||||
MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player);
|
||||
|
||||
if (mSpentAttributes.size() < 3)
|
||||
|
@ -165,15 +164,14 @@ namespace MWGui
|
|||
// increase attributes
|
||||
for (int i=0; i<3; ++i)
|
||||
{
|
||||
MWMechanics::AttributeValue attribute = creatureStats.getAttribute(mSpentAttributes[i]);
|
||||
MWMechanics::AttributeValue attribute = pcStats.getAttribute(mSpentAttributes[i]);
|
||||
attribute.setBase (attribute.getBase () + pcStats.getLevelupAttributeMultiplier (mSpentAttributes[i]));
|
||||
|
||||
if (attribute.getBase() >= 100)
|
||||
attribute.setBase(100);
|
||||
creatureStats.setAttribute(mSpentAttributes[i], attribute);
|
||||
pcStats.setAttribute(mSpentAttributes[i], attribute);
|
||||
}
|
||||
|
||||
creatureStats.levelUp();
|
||||
pcStats.levelUp ();
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Levelup);
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
#include "mainmenu.hpp"
|
||||
|
||||
#include <OgreRoot.h>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/journal.hpp"
|
||||
#include "../mwbase/dialoguemanager.hpp"
|
||||
#include "../mwbase/statemanager.hpp"
|
||||
|
||||
#include "../mwstate/character.hpp"
|
||||
|
||||
#include "savegamedialog.hpp"
|
||||
|
||||
|
@ -16,90 +17,132 @@ namespace MWGui
|
|||
|
||||
MainMenu::MainMenu(int w, int h)
|
||||
: OEngine::GUI::Layout("openmw_mainmenu.layout")
|
||||
, mButtonBox(0)
|
||||
, mButtonBox(0), mWidth (w), mHeight (h)
|
||||
, mSaveGameDialog(NULL)
|
||||
{
|
||||
onResChange(w,h);
|
||||
updateMenu();
|
||||
}
|
||||
|
||||
MainMenu::~MainMenu()
|
||||
{
|
||||
delete mSaveGameDialog;
|
||||
}
|
||||
|
||||
void MainMenu::onResChange(int w, int h)
|
||||
{
|
||||
setCoord(0,0,w,h);
|
||||
mWidth = w;
|
||||
mHeight = h;
|
||||
|
||||
updateMenu();
|
||||
}
|
||||
|
||||
if (mButtonBox)
|
||||
MyGUI::Gui::getInstance ().destroyWidget(mButtonBox);
|
||||
void MainMenu::setVisible (bool visible)
|
||||
{
|
||||
if (visible)
|
||||
updateMenu();
|
||||
|
||||
mButtonBox = mMainWidget->createWidget<MyGUI::Widget>("", MyGUI::IntCoord(0, 0, 0, 0), MyGUI::Align::Default);
|
||||
int curH = 0;
|
||||
|
||||
std::vector<std::string> buttons;
|
||||
buttons.push_back("return");
|
||||
buttons.push_back("newgame");
|
||||
//buttons.push_back("loadgame");
|
||||
//buttons.push_back("savegame");
|
||||
buttons.push_back("options");
|
||||
//buttons.push_back("credits");
|
||||
buttons.push_back("exitgame");
|
||||
|
||||
int maxwidth = 0;
|
||||
|
||||
mButtons.clear();
|
||||
for (std::vector<std::string>::iterator it = buttons.begin(); it != buttons.end(); ++it)
|
||||
{
|
||||
MWGui::ImageButton* button = mButtonBox->createWidget<MWGui::ImageButton>
|
||||
("ImageBox", MyGUI::IntCoord(0, curH, 0, 0), MyGUI::Align::Default);
|
||||
button->setProperty("ImageHighlighted", "textures\\menu_" + *it + "_over.dds");
|
||||
button->setProperty("ImageNormal", "textures\\menu_" + *it + ".dds");
|
||||
button->setProperty("ImagePushed", "textures\\menu_" + *it + "_pressed.dds");
|
||||
MyGUI::IntSize requested = button->getRequestedSize();
|
||||
button->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::onButtonClicked);
|
||||
mButtons[*it] = button;
|
||||
curH += requested.height;
|
||||
|
||||
if (requested.width > maxwidth)
|
||||
maxwidth = requested.width;
|
||||
}
|
||||
for (std::map<std::string, MWGui::ImageButton*>::iterator it = mButtons.begin(); it != mButtons.end(); ++it)
|
||||
{
|
||||
MyGUI::IntSize requested = it->second->getRequestedSize();
|
||||
it->second->setCoord((maxwidth-requested.width) / 2, it->second->getTop(), requested.width, requested.height);
|
||||
}
|
||||
|
||||
mButtonBox->setCoord (w/2 - maxwidth/2, h/2 - curH/2, maxwidth, curH);
|
||||
OEngine::GUI::Layout::setVisible (visible);
|
||||
}
|
||||
|
||||
void MainMenu::onButtonClicked(MyGUI::Widget *sender)
|
||||
{
|
||||
std::string name = *sender->getUserData<std::string>();
|
||||
MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f);
|
||||
if (sender == mButtons["return"])
|
||||
if (name == "return")
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager ()->resumeSounds (MWBase::SoundManager::Play_TypeSfx);
|
||||
MWBase::Environment::get().getWindowManager ()->removeGuiMode (GM_MainMenu);
|
||||
}
|
||||
else if (sender == mButtons["options"])
|
||||
else if (name == "options")
|
||||
MWBase::Environment::get().getWindowManager ()->pushGuiMode (GM_Settings);
|
||||
else if (sender == mButtons["exitgame"])
|
||||
MWBase::Environment::get().setRequestExit();
|
||||
else if (sender == mButtons["newgame"])
|
||||
else if (name == "exitgame")
|
||||
MWBase::Environment::get().getStateManager()->requestQuit();
|
||||
else if (name == "newgame")
|
||||
{
|
||||
MWBase::Environment::get().getWorld()->startNewGame();
|
||||
MWBase::Environment::get().getWindowManager()->setNewGame(true);
|
||||
MWBase::Environment::get().getDialogueManager()->clear();
|
||||
MWBase::Environment::get().getJournal()->clear();
|
||||
MWBase::Environment::get().getStateManager()->newGame();
|
||||
}
|
||||
|
||||
else if (sender == mButtons["loadgame"])
|
||||
else
|
||||
{
|
||||
MWGui::SaveGameDialog* dialog = new MWGui::SaveGameDialog();
|
||||
dialog->setLoadOrSave(true);
|
||||
dialog->setVisible(true);
|
||||
}
|
||||
else if (sender == mButtons["savegame"])
|
||||
{
|
||||
MWGui::SaveGameDialog* dialog = new MWGui::SaveGameDialog();
|
||||
dialog->setLoadOrSave(false);
|
||||
dialog->setVisible(true);
|
||||
if (!mSaveGameDialog)
|
||||
mSaveGameDialog = new SaveGameDialog();
|
||||
if (name == "loadgame")
|
||||
mSaveGameDialog->setLoadOrSave(true);
|
||||
else if (name == "savegame")
|
||||
mSaveGameDialog->setLoadOrSave(false);
|
||||
mSaveGameDialog->setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
void MainMenu::updateMenu()
|
||||
{
|
||||
setCoord(0,0, mWidth, mHeight);
|
||||
|
||||
|
||||
if (!mButtonBox)
|
||||
mButtonBox = mMainWidget->createWidget<MyGUI::Widget>("", MyGUI::IntCoord(0, 0, 0, 0), MyGUI::Align::Default);
|
||||
|
||||
int curH = 0;
|
||||
|
||||
MWBase::StateManager::State state = MWBase::Environment::get().getStateManager()->getState();
|
||||
|
||||
std::vector<std::string> buttons;
|
||||
|
||||
if (state==MWBase::StateManager::State_Running)
|
||||
buttons.push_back("return");
|
||||
|
||||
buttons.push_back("newgame");
|
||||
|
||||
if (MWBase::Environment::get().getStateManager()->characterBegin()!=
|
||||
MWBase::Environment::get().getStateManager()->characterEnd())
|
||||
buttons.push_back("loadgame");
|
||||
|
||||
if (state==MWBase::StateManager::State_Running &&
|
||||
MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1)
|
||||
buttons.push_back("savegame");
|
||||
|
||||
buttons.push_back("options");
|
||||
//buttons.push_back("credits");
|
||||
buttons.push_back("exitgame");
|
||||
|
||||
// Create new buttons if needed
|
||||
for (std::vector<std::string>::iterator it = buttons.begin(); it != buttons.end(); ++it)
|
||||
{
|
||||
if (mButtons.find(*it) == mButtons.end())
|
||||
{
|
||||
MWGui::ImageButton* button = mButtonBox->createWidget<MWGui::ImageButton>
|
||||
("ImageBox", MyGUI::IntCoord(0, curH, 0, 0), MyGUI::Align::Default);
|
||||
button->setProperty("ImageHighlighted", "textures\\menu_" + *it + "_over.dds");
|
||||
button->setProperty("ImageNormal", "textures\\menu_" + *it + ".dds");
|
||||
button->setProperty("ImagePushed", "textures\\menu_" + *it + "_pressed.dds");
|
||||
button->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::onButtonClicked);
|
||||
button->setUserData(std::string(*it));
|
||||
mButtons[*it] = button;
|
||||
}
|
||||
}
|
||||
|
||||
// Start by hiding all buttons
|
||||
int maxwidth = 0;
|
||||
for (std::map<std::string, MWGui::ImageButton*>::iterator it = mButtons.begin(); it != mButtons.end(); ++it)
|
||||
{
|
||||
it->second->setVisible(false);
|
||||
MyGUI::IntSize requested = it->second->getRequestedSize();
|
||||
if (requested.width > maxwidth)
|
||||
maxwidth = requested.width;
|
||||
}
|
||||
|
||||
// Now show and position the ones we want
|
||||
for (std::vector<std::string>::iterator it = buttons.begin(); it != buttons.end(); ++it)
|
||||
{
|
||||
assert(mButtons.find(*it) != mButtons.end());
|
||||
MWGui::ImageButton* button = mButtons[*it];
|
||||
button->setVisible(true);
|
||||
MyGUI::IntSize requested = button->getRequestedSize();
|
||||
button->setCoord((maxwidth-requested.width) / 2, curH, requested.width, requested.height);
|
||||
curH += requested.height;
|
||||
}
|
||||
|
||||
mButtonBox->setCoord (mWidth/2 - maxwidth/2, mHeight/2 - curH/2, maxwidth, curH);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,19 +5,33 @@
|
|||
namespace MWGui
|
||||
{
|
||||
|
||||
class SaveGameDialog;
|
||||
|
||||
class MainMenu : public OEngine::GUI::Layout
|
||||
{
|
||||
public:
|
||||
MainMenu(int w, int h);
|
||||
int mWidth;
|
||||
int mHeight;
|
||||
|
||||
void onResChange(int w, int h);
|
||||
public:
|
||||
|
||||
private:
|
||||
MyGUI::Widget* mButtonBox;
|
||||
MainMenu(int w, int h);
|
||||
~MainMenu();
|
||||
|
||||
std::map<std::string, MWGui::ImageButton*> mButtons;
|
||||
void onResChange(int w, int h);
|
||||
|
||||
void onButtonClicked (MyGUI::Widget* sender);
|
||||
virtual void setVisible (bool visible);
|
||||
|
||||
private:
|
||||
|
||||
MyGUI::Widget* mButtonBox;
|
||||
|
||||
std::map<std::string, MWGui::ImageButton*> mButtons;
|
||||
|
||||
void onButtonClicked (MyGUI::Widget* sender);
|
||||
|
||||
void updateMenu();
|
||||
|
||||
SaveGameDialog* mSaveGameDialog;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -373,8 +373,9 @@ namespace MWGui
|
|||
|
||||
// ------------------------------------------------------------------------------------------
|
||||
|
||||
MapWindow::MapWindow(const std::string& cacheDir)
|
||||
: MWGui::WindowPinnableBase("openmw_map_window.layout")
|
||||
MapWindow::MapWindow(DragAndDrop* drag, const std::string& cacheDir)
|
||||
: WindowPinnableBase("openmw_map_window.layout")
|
||||
, NoDrop(drag, mMainWidget)
|
||||
, mGlobal(false)
|
||||
, mGlobalMap(0)
|
||||
, mGlobalMapRender(0)
|
||||
|
@ -434,7 +435,7 @@ namespace MWGui
|
|||
|
||||
|
||||
static int _counter=0;
|
||||
MyGUI::Button* markerWidget = mGlobalMapImage->createWidget<MyGUI::Button>("ButtonImage",
|
||||
MyGUI::Button* markerWidget = mGlobalMapOverlay->createWidget<MyGUI::Button>("ButtonImage",
|
||||
widgetCoord, MyGUI::Align::Default, "Door" + boost::lexical_cast<std::string>(_counter));
|
||||
markerWidget->setImageResource("DoorMarker");
|
||||
markerWidget->setUserString("ToolTipType", "Layout");
|
||||
|
@ -499,10 +500,11 @@ namespace MWGui
|
|||
mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight());
|
||||
mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight());
|
||||
|
||||
for (unsigned int i=0; i<mGlobalMapImage->getChildCount (); ++i)
|
||||
// force markers to foreground
|
||||
for (unsigned int i=0; i<mGlobalMapOverlay->getChildCount (); ++i)
|
||||
{
|
||||
if (mGlobalMapImage->getChildAt (i)->getName().substr(0,4) == "Door")
|
||||
mGlobalMapImage->getChildAt (i)->castType<MyGUI::Button>()->setImageResource("DoorMarker");
|
||||
if (mGlobalMapOverlay->getChildAt (i)->getName().substr(0,4) == "Door")
|
||||
mGlobalMapOverlay->getChildAt (i)->castType<MyGUI::Button>()->setImageResource("DoorMarker");
|
||||
}
|
||||
|
||||
globalMapUpdatePlayer();
|
||||
|
@ -573,4 +575,31 @@ namespace MWGui
|
|||
mGlobalMap->setViewOffset(viewoffs);
|
||||
}
|
||||
|
||||
void MapWindow::clear()
|
||||
{
|
||||
mGlobalMapRender->clear();
|
||||
|
||||
while (mEventBoxGlobal->getChildCount())
|
||||
MyGUI::Gui::getInstance().destroyWidget(mEventBoxGlobal->getChildAt(0));
|
||||
while (mGlobalMapOverlay->getChildCount())
|
||||
MyGUI::Gui::getInstance().destroyWidget(mGlobalMapOverlay->getChildAt(0));
|
||||
}
|
||||
|
||||
void MapWindow::write(ESM::ESMWriter &writer)
|
||||
{
|
||||
mGlobalMapRender->write(writer);
|
||||
}
|
||||
|
||||
void MapWindow::readRecord(ESM::ESMReader &reader, int32_t type)
|
||||
{
|
||||
std::vector<std::pair<int, int> > exploredCells;
|
||||
mGlobalMapRender->readRecord(reader, type, exploredCells);
|
||||
|
||||
for (std::vector<std::pair<int, int> >::iterator it = exploredCells.begin(); it != exploredCells.end(); ++it)
|
||||
{
|
||||
const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Cell>().search(it->first, it->second);
|
||||
if (cell && !cell->mName.empty())
|
||||
addVisitedLocation(cell->mName, it->first, it->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef MWGUI_MAPWINDOW_H
|
||||
#define MWGUI_MAPWINDOW_H
|
||||
|
||||
#include <libs/platform/stdint.h>
|
||||
|
||||
#include "windowpinnablebase.hpp"
|
||||
|
||||
namespace MWRender
|
||||
|
@ -8,6 +10,12 @@ namespace MWRender
|
|||
class GlobalMap;
|
||||
}
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
}
|
||||
|
||||
namespace Loading
|
||||
{
|
||||
class Listener;
|
||||
|
@ -75,10 +83,10 @@ namespace MWGui
|
|||
float mLastDirectionY;
|
||||
};
|
||||
|
||||
class MapWindow : public MWGui::WindowPinnableBase, public LocalMapBase
|
||||
class MapWindow : public MWGui::WindowPinnableBase, public LocalMapBase, public NoDrop
|
||||
{
|
||||
public:
|
||||
MapWindow(const std::string& cacheDir);
|
||||
MapWindow(DragAndDrop* drag, const std::string& cacheDir);
|
||||
virtual ~MapWindow();
|
||||
|
||||
void setCellName(const std::string& cellName);
|
||||
|
@ -92,6 +100,14 @@ namespace MWGui
|
|||
|
||||
virtual void open();
|
||||
|
||||
void onFrame(float dt) { NoDrop::onFrame(dt); }
|
||||
|
||||
/// Clear all savegame-specific data
|
||||
void clear();
|
||||
|
||||
void write (ESM::ESMWriter& writer);
|
||||
void readRecord (ESM::ESMReader& reader, int32_t type);
|
||||
|
||||
private:
|
||||
void onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id);
|
||||
void onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id);
|
||||
|
|
|
@ -245,11 +245,11 @@ namespace MWGui
|
|||
}
|
||||
mainWidgetSize.height = textSize.height + textButtonPadding + buttonHeight + buttonMainPadding;
|
||||
|
||||
MyGUI::IntCoord absCoord;
|
||||
absCoord.left = (gameWindowSize.width - mainWidgetSize.width)/2;
|
||||
absCoord.top = (gameWindowSize.height - mainWidgetSize.height)/2;
|
||||
MyGUI::IntPoint absPos;
|
||||
absPos.left = (gameWindowSize.width - mainWidgetSize.width)/2;
|
||||
absPos.top = (gameWindowSize.height - mainWidgetSize.height)/2;
|
||||
|
||||
mMainWidget->setCoord(absCoord);
|
||||
mMainWidget->setPosition(absPos);
|
||||
mMainWidget->setSize(mainWidgetSize);
|
||||
|
||||
MyGUI::IntCoord messageWidgetCoord;
|
||||
|
@ -332,7 +332,7 @@ namespace MWGui
|
|||
{
|
||||
if(Misc::StringUtils::ciEqual((*button)->getCaption(), ok))
|
||||
{
|
||||
MyGUI::InputManager::getInstance().setKeyFocusWidget(*button);
|
||||
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(*button);
|
||||
(*button)->eventKeyButtonPressed += MyGUI::newDelegate(this, &InteractiveMessageBox::onKeyPressed);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -70,8 +70,7 @@ namespace MWGui
|
|||
setText("RaceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu5", "Race"));
|
||||
getWidget(mRaceList, "RaceList");
|
||||
mRaceList->setScrollVisible(true);
|
||||
mRaceList->eventListSelectAccept += MyGUI::newDelegate(this, &RaceDialog::onSelectRace);
|
||||
mRaceList->eventListMouseItemActivate += MyGUI::newDelegate(this, &RaceDialog::onSelectRace);
|
||||
mRaceList->eventListSelectAccept += MyGUI::newDelegate(this, &RaceDialog::onAccept);
|
||||
mRaceList->eventListChangePosition += MyGUI::newDelegate(this, &RaceDialog::onSelectRace);
|
||||
|
||||
setText("SkillsT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sBonusSkillTitle", "Skill Bonus"));
|
||||
|
@ -241,6 +240,14 @@ namespace MWGui
|
|||
updateSpellPowers();
|
||||
}
|
||||
|
||||
void RaceDialog::onAccept(MyGUI::ListBox *_sender, size_t _index)
|
||||
{
|
||||
onSelectRace(_sender, _index);
|
||||
if(mRaceList->getIndexSelected() == MyGUI::ITEM_NONE)
|
||||
return;
|
||||
eventDone(this);
|
||||
}
|
||||
|
||||
void RaceDialog::getBodyParts (int part, std::vector<std::string>& out)
|
||||
{
|
||||
out.clear();
|
||||
|
|
|
@ -67,6 +67,7 @@ namespace MWGui
|
|||
void onSelectNextHair(MyGUI::Widget* _sender);
|
||||
|
||||
void onSelectRace(MyGUI::ListBox* _sender, size_t _index);
|
||||
void onAccept(MyGUI::ListBox* _sender, size_t _index);
|
||||
|
||||
void onOkClicked(MyGUI::Widget* _sender);
|
||||
void onBackClicked(MyGUI::Widget* _sender);
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace MWGui
|
|||
|
||||
void ReferenceInterface::checkReferenceAvailable()
|
||||
{
|
||||
MWWorld::Ptr::CellStore* playerCell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell();
|
||||
MWWorld::CellStore* playerCell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell();
|
||||
|
||||
// check if player has changed cell, or count of the reference has become 0
|
||||
if ((playerCell != mCurrentPlayerCell && mCurrentPlayerCell != NULL)
|
||||
|
|
|
@ -1,12 +1,28 @@
|
|||
#include "savegamedialog.hpp"
|
||||
#include "widgets.hpp"
|
||||
|
||||
#include <OgreImage.h>
|
||||
#include <OgreTextureManager.h>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include <components/settings/settings.hpp>
|
||||
|
||||
#include "../mwbase/statemanager.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
|
||||
#include "../mwstate/character.hpp"
|
||||
|
||||
#include "confirmationdialog.hpp"
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
SaveGameDialog::SaveGameDialog()
|
||||
: WindowModal("openmw_savegame_dialog.layout")
|
||||
, mSaving(true)
|
||||
, mCurrentCharacter(NULL)
|
||||
{
|
||||
getWidget(mScreenshot, "Screenshot");
|
||||
getWidget(mCharacterSelection, "SelectCharacter");
|
||||
|
@ -18,21 +34,89 @@ namespace MWGui
|
|||
getWidget(mSpacer, "Spacer");
|
||||
mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onOkButtonClicked);
|
||||
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onCancelButtonClicked);
|
||||
mCharacterSelection->eventComboChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterSelected);
|
||||
mSaveList->eventListChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onSlotSelected);
|
||||
mSaveList->eventListSelectAccept += MyGUI::newDelegate(this, &SaveGameDialog::onSlotActivated);
|
||||
mSaveNameEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &SaveGameDialog::onEditSelectAccept);
|
||||
mSaveNameEdit->eventEditTextChange += MyGUI::newDelegate(this, &SaveGameDialog::onSaveNameChanged);
|
||||
}
|
||||
|
||||
void SaveGameDialog::onSlotActivated(MyGUI::ListBox *sender, size_t pos)
|
||||
{
|
||||
onSlotSelected(sender, pos);
|
||||
accept();
|
||||
}
|
||||
|
||||
void SaveGameDialog::onSaveNameChanged(MyGUI::EditBox *sender)
|
||||
{
|
||||
// This might have previously been a save slot from the list. If so, that is no longer the case
|
||||
mSaveList->setIndexSelected(MyGUI::ITEM_NONE);
|
||||
onSlotSelected(mSaveList, MyGUI::ITEM_NONE);
|
||||
}
|
||||
|
||||
void SaveGameDialog::onEditSelectAccept(MyGUI::EditBox *sender)
|
||||
{
|
||||
accept();
|
||||
}
|
||||
|
||||
void SaveGameDialog::open()
|
||||
{
|
||||
WindowModal::open();
|
||||
|
||||
mSaveNameEdit->setCaption ("");
|
||||
if (mSaving)
|
||||
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveNameEdit);
|
||||
|
||||
center();
|
||||
|
||||
MWBase::StateManager* mgr = MWBase::Environment::get().getStateManager();
|
||||
if (mgr->characterBegin() == mgr->characterEnd())
|
||||
return;
|
||||
|
||||
mCurrentCharacter = mgr->getCurrentCharacter (false);
|
||||
|
||||
std::string directory =
|
||||
Misc::StringUtils::lowerCase (Settings::Manager::getString ("character", "Saves"));
|
||||
|
||||
mCharacterSelection->removeAllItems();
|
||||
|
||||
for (MWBase::StateManager::CharacterIterator it = mgr->characterBegin(); it != mgr->characterEnd(); ++it)
|
||||
{
|
||||
if (it->begin()!=it->end())
|
||||
{
|
||||
std::stringstream title;
|
||||
title << it->getSignature().mPlayerName;
|
||||
title << " (Level " << it->getSignature().mPlayerLevel << " " << it->getSignature().mPlayerClass << ")";
|
||||
|
||||
mCharacterSelection->addItem (title.str());
|
||||
|
||||
if (mCurrentCharacter == &*it ||
|
||||
(!mCurrentCharacter && !mSaving && directory==Misc::StringUtils::lowerCase (
|
||||
it->begin()->mPath.parent_path().filename().string())))
|
||||
{
|
||||
mCurrentCharacter = &*it;
|
||||
mCharacterSelection->setIndexSelected(mCharacterSelection->getItemCount()-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fillSaveList();
|
||||
|
||||
}
|
||||
|
||||
void SaveGameDialog::setLoadOrSave(bool load)
|
||||
{
|
||||
mSaving = !load;
|
||||
mSaveNameEdit->setVisible(!load);
|
||||
mCharacterSelection->setUserString("Hidden", load ? "false" : "true");
|
||||
mCharacterSelection->setVisible(load);
|
||||
mSpacer->setUserString("Hidden", load ? "false" : "true");
|
||||
|
||||
if (!load)
|
||||
{
|
||||
mCurrentCharacter = MWBase::Environment::get().getStateManager()->getCurrentCharacter (false);
|
||||
}
|
||||
|
||||
center();
|
||||
}
|
||||
|
||||
|
@ -41,9 +125,161 @@ namespace MWGui
|
|||
setVisible(false);
|
||||
}
|
||||
|
||||
void SaveGameDialog::onOkButtonClicked(MyGUI::Widget *sender)
|
||||
void SaveGameDialog::onConfirmationGiven()
|
||||
{
|
||||
setVisible(false);
|
||||
accept(true);
|
||||
}
|
||||
|
||||
void SaveGameDialog::accept(bool reallySure)
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(NULL);
|
||||
|
||||
// Get the selected slot, if any
|
||||
unsigned int i=0;
|
||||
const MWState::Slot* slot = NULL;
|
||||
|
||||
if (mCurrentCharacter)
|
||||
{
|
||||
for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it,++i)
|
||||
{
|
||||
if (i == mSaveList->getIndexSelected())
|
||||
slot = &*it;
|
||||
}
|
||||
}
|
||||
|
||||
if (mSaving)
|
||||
{
|
||||
// If overwriting an existing slot, ask for confirmation first
|
||||
if (slot != NULL && !reallySure)
|
||||
{
|
||||
ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog();
|
||||
dialog->open("#{sMessage4}");
|
||||
dialog->eventOkClicked.clear();
|
||||
dialog->eventOkClicked += MyGUI::newDelegate(this, &SaveGameDialog::onConfirmationGiven);
|
||||
dialog->eventCancelClicked.clear();
|
||||
return;
|
||||
}
|
||||
if (mSaveNameEdit->getCaption().empty())
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage65}");
|
||||
return;
|
||||
}
|
||||
MWBase::Environment::get().getStateManager()->saveGame (mSaveNameEdit->getCaption(), slot);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mCurrentCharacter && slot)
|
||||
MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, slot);
|
||||
}
|
||||
|
||||
setVisible(false);
|
||||
|
||||
if (MWBase::Environment::get().getStateManager()->getState()==
|
||||
MWBase::StateManager::State_NoGame)
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
|
||||
}
|
||||
}
|
||||
|
||||
void SaveGameDialog::onOkButtonClicked(MyGUI::Widget *sender)
|
||||
{
|
||||
accept();
|
||||
}
|
||||
|
||||
void SaveGameDialog::onCharacterSelected(MyGUI::ComboBox *sender, size_t pos)
|
||||
{
|
||||
MWBase::StateManager* mgr = MWBase::Environment::get().getStateManager();
|
||||
|
||||
unsigned int i=0;
|
||||
const MWState::Character* character = NULL;
|
||||
for (MWBase::StateManager::CharacterIterator it = mgr->characterBegin(); it != mgr->characterEnd(); ++it, ++i)
|
||||
{
|
||||
if (i == pos)
|
||||
character = &*it;
|
||||
}
|
||||
assert(character && "Can't find selected character");
|
||||
|
||||
mCurrentCharacter = character;
|
||||
fillSaveList();
|
||||
}
|
||||
|
||||
void SaveGameDialog::fillSaveList()
|
||||
{
|
||||
mSaveList->removeAllItems();
|
||||
if (!mCurrentCharacter)
|
||||
return;
|
||||
for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it)
|
||||
{
|
||||
mSaveList->addItem(it->mProfile.mDescription);
|
||||
}
|
||||
onSlotSelected(mSaveList, MyGUI::ITEM_NONE);
|
||||
}
|
||||
|
||||
void SaveGameDialog::onSlotSelected(MyGUI::ListBox *sender, size_t pos)
|
||||
{
|
||||
if (pos == MyGUI::ITEM_NONE)
|
||||
{
|
||||
mInfoText->setCaption("");
|
||||
mScreenshot->setImageTexture("");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mSaving)
|
||||
mSaveNameEdit->setCaption(sender->getItemNameAt(pos));
|
||||
|
||||
const MWState::Slot* slot = NULL;
|
||||
unsigned int i=0;
|
||||
for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it, ++i)
|
||||
{
|
||||
if (i == pos)
|
||||
slot = &*it;
|
||||
}
|
||||
assert(slot && "Can't find selected slot");
|
||||
|
||||
std::stringstream text;
|
||||
time_t time = slot->mTimeStamp;
|
||||
struct tm* timeinfo;
|
||||
timeinfo = localtime(&time);
|
||||
|
||||
text << asctime(timeinfo) << "\n";
|
||||
text << "Level " << slot->mProfile.mPlayerLevel << "\n";
|
||||
text << slot->mProfile.mPlayerCell << "\n";
|
||||
// text << "Time played: " << slot->mProfile.mTimePlayed << "\n";
|
||||
|
||||
int hour = int(slot->mProfile.mInGameTime.mGameHour);
|
||||
bool pm = hour >= 12;
|
||||
if (hour >= 13) hour -= 12;
|
||||
if (hour == 0) hour = 12;
|
||||
|
||||
text
|
||||
<< slot->mProfile.mInGameTime.mDay << " "
|
||||
<< MWBase::Environment::get().getWorld()->getMonthName(slot->mProfile.mInGameTime.mMonth)
|
||||
<< " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}");
|
||||
|
||||
mInfoText->setCaptionWithReplacing(text.str());
|
||||
|
||||
// Decode screenshot
|
||||
std::vector<char> data = slot->mProfile.mScreenshot; // MemoryDataStream doesn't work with const data :(
|
||||
Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&data[0], data.size()));
|
||||
Ogre::Image image;
|
||||
image.load(stream, "jpg");
|
||||
|
||||
const std::string textureName = "@savegame_screenshot";
|
||||
Ogre::TexturePtr texture;
|
||||
texture = Ogre::TextureManager::getSingleton().getByName(textureName);
|
||||
mScreenshot->setImageTexture("");
|
||||
if (texture.isNull())
|
||||
{
|
||||
texture = Ogre::TextureManager::getSingleton().createManual(textureName,
|
||||
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||
Ogre::TEX_TYPE_2D,
|
||||
image.getWidth(), image.getHeight(), 0, Ogre::PF_BYTE_RGBA, Ogre::TU_DYNAMIC_WRITE_ONLY);
|
||||
}
|
||||
texture->unload();
|
||||
texture->setWidth(image.getWidth());
|
||||
texture->setHeight(image.getHeight());
|
||||
texture->loadImage(image);
|
||||
|
||||
mScreenshot->setImageTexture(textureName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,11 @@
|
|||
|
||||
#include "windowbase.hpp"
|
||||
|
||||
namespace MWState
|
||||
{
|
||||
class Character;
|
||||
}
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
|
@ -15,12 +20,22 @@ namespace MWGui
|
|||
|
||||
void setLoadOrSave(bool load);
|
||||
|
||||
private:
|
||||
void onCancelButtonClicked (MyGUI::Widget* sender);
|
||||
void onOkButtonClicked (MyGUI::Widget* sender);
|
||||
void onCharacterSelected (MyGUI::ComboBox* sender, size_t pos);
|
||||
void onSlotSelected (MyGUI::ListBox* sender, size_t pos);
|
||||
void onSlotActivated (MyGUI::ListBox* sender, size_t pos);
|
||||
void onEditSelectAccept (MyGUI::EditBox* sender);
|
||||
void onSaveNameChanged (MyGUI::EditBox* sender);
|
||||
void onConfirmationGiven();
|
||||
|
||||
void accept(bool reallySure=false);
|
||||
|
||||
void fillSaveList();
|
||||
|
||||
private:
|
||||
MyGUI::ImageBox* mScreenshot;
|
||||
bool mSaving;
|
||||
|
||||
MyGUI::ComboBox* mCharacterSelection;
|
||||
MyGUI::EditBox* mInfoText;
|
||||
|
@ -30,6 +45,8 @@ namespace MWGui
|
|||
MyGUI::EditBox* mSaveNameEdit;
|
||||
MyGUI::Widget* mSpacer;
|
||||
|
||||
const MWState::Character* mCurrentCharacter;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -42,8 +42,9 @@ namespace
|
|||
|
||||
namespace MWGui
|
||||
{
|
||||
SpellWindow::SpellWindow()
|
||||
SpellWindow::SpellWindow(DragAndDrop* drag)
|
||||
: WindowPinnableBase("openmw_spell_window.layout")
|
||||
, NoDrop(drag, mMainWidget)
|
||||
, mHeight(0)
|
||||
, mWidth(0)
|
||||
{
|
||||
|
|
|
@ -7,14 +7,16 @@ namespace MWGui
|
|||
{
|
||||
class SpellIcons;
|
||||
|
||||
class SpellWindow : public WindowPinnableBase
|
||||
class SpellWindow : public WindowPinnableBase, public NoDrop
|
||||
{
|
||||
public:
|
||||
SpellWindow();
|
||||
SpellWindow(DragAndDrop* drag);
|
||||
virtual ~SpellWindow();
|
||||
|
||||
void updateSpells();
|
||||
|
||||
void onFrame(float dt) { NoDrop::onFrame(dt); }
|
||||
|
||||
protected:
|
||||
MyGUI::ScrollView* mSpellView;
|
||||
MyGUI::Widget* mEffectBox;
|
||||
|
|
|
@ -18,8 +18,9 @@ namespace MWGui
|
|||
|
||||
const int StatsWindow::sLineHeight = 18;
|
||||
|
||||
StatsWindow::StatsWindow ()
|
||||
StatsWindow::StatsWindow (DragAndDrop* drag)
|
||||
: WindowPinnableBase("openmw_stats_window.layout")
|
||||
, NoDrop(drag, mMainWidget)
|
||||
, mSkillView(NULL)
|
||||
, mMajorSkills()
|
||||
, mMinorSkills()
|
||||
|
@ -219,11 +220,13 @@ namespace MWGui
|
|||
updateSkillArea();
|
||||
}
|
||||
|
||||
void StatsWindow::onFrame ()
|
||||
void StatsWindow::onFrame (float dt)
|
||||
{
|
||||
if (!mMainWidget->getVisible())
|
||||
return;
|
||||
|
||||
NoDrop::onFrame(dt);
|
||||
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
const MWMechanics::NpcStats &PCstats = MWWorld::Class::get(player).getNpcStats(player);
|
||||
|
||||
|
@ -231,9 +234,12 @@ namespace MWGui
|
|||
MyGUI::Widget* levelWidget;
|
||||
for (int i=0; i<2; ++i)
|
||||
{
|
||||
int max = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("iLevelUpTotal")->getInt();
|
||||
getWidget(levelWidget, i==0 ? "Level_str" : "LevelText");
|
||||
levelWidget->setUserString("RangePosition_LevelProgress", boost::lexical_cast<std::string>(PCstats.getLevelProgress()));
|
||||
levelWidget->setUserString("Caption_LevelProgressText", boost::lexical_cast<std::string>(PCstats.getLevelProgress()) + "/10");
|
||||
levelWidget->setUserString("Range_LevelProgress", boost::lexical_cast<std::string>(max));
|
||||
levelWidget->setUserString("Caption_LevelProgressText", boost::lexical_cast<std::string>(PCstats.getLevelProgress()) + "/"
|
||||
+ boost::lexical_cast<std::string>(max));
|
||||
}
|
||||
|
||||
setFactions(PCstats.getFactionRanks());
|
||||
|
|
|
@ -10,17 +10,17 @@ namespace MWGui
|
|||
{
|
||||
class WindowManager;
|
||||
|
||||
class StatsWindow : public WindowPinnableBase
|
||||
class StatsWindow : public WindowPinnableBase, public NoDrop
|
||||
{
|
||||
public:
|
||||
typedef std::map<std::string, int> FactionList;
|
||||
|
||||
typedef std::vector<int> SkillList;
|
||||
|
||||
StatsWindow();
|
||||
StatsWindow(DragAndDrop* drag);
|
||||
|
||||
/// automatically updates all the data in the stats window, but only if it has changed.
|
||||
void onFrame();
|
||||
void onFrame(float dt);
|
||||
|
||||
void setBar(const std::string& name, const std::string& tname, int val, int max);
|
||||
void setPlayerName(const std::string& playerName);
|
||||
|
|
|
@ -182,7 +182,7 @@ namespace MWGui
|
|||
}
|
||||
else if (type == "AvatarItemSelection")
|
||||
{
|
||||
MyGUI::IntCoord avatarPos = MWBase::Environment::get().getWindowManager()->getInventoryWindow ()->getAvatarScreenCoord ();
|
||||
MyGUI::IntCoord avatarPos = focus->getAbsoluteCoord();
|
||||
MyGUI::IntPoint relMousePos = MyGUI::InputManager::getInstance ().getMousePosition () - MyGUI::IntPoint(avatarPos.left, avatarPos.top);
|
||||
int realX = int(float(relMousePos.left) / float(avatarPos.width) * 512.f );
|
||||
int realY = int(float(relMousePos.top) / float(avatarPos.height) * 1024.f );
|
||||
|
|
|
@ -87,49 +87,7 @@ namespace MWGui
|
|||
onHourSliderChangedPosition(mHourSlider, 0);
|
||||
mHourSlider->setScrollPosition (0);
|
||||
|
||||
// http://www.uesp.net/wiki/Lore:Calendar
|
||||
std::string month;
|
||||
int m = MWBase::Environment::get().getWorld ()->getMonth ();
|
||||
switch (m) {
|
||||
case 0:
|
||||
month = "#{sMonthMorningstar}";
|
||||
break;
|
||||
case 1:
|
||||
month = "#{sMonthSunsdawn}";
|
||||
break;
|
||||
case 2:
|
||||
month = "#{sMonthFirstseed}";
|
||||
break;
|
||||
case 3:
|
||||
month = "#{sMonthRainshand}";
|
||||
break;
|
||||
case 4:
|
||||
month = "#{sMonthSecondseed}";
|
||||
break;
|
||||
case 5:
|
||||
month = "#{sMonthMidyear}";
|
||||
break;
|
||||
case 6:
|
||||
month = "#{sMonthSunsheight}";
|
||||
break;
|
||||
case 7:
|
||||
month = "#{sMonthLastseed}";
|
||||
break;
|
||||
case 8:
|
||||
month = "#{sMonthHeartfire}";
|
||||
break;
|
||||
case 9:
|
||||
month = "#{sMonthFrostfall}";
|
||||
break;
|
||||
case 10:
|
||||
month = "#{sMonthSunsdusk}";
|
||||
break;
|
||||
case 11:
|
||||
month = "#{sMonthEveningstar}";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
std::string month = MWBase::Environment::get().getWorld ()->getMonthName();
|
||||
int hour = MWBase::Environment::get().getWorld ()->getTimeStamp ().getHour ();
|
||||
bool pm = hour >= 12;
|
||||
if (hour >= 13) hour -= 12;
|
||||
|
@ -271,7 +229,9 @@ namespace MWGui
|
|||
const MWMechanics::NpcStats &pcstats = MWWorld::Class::get(player).getNpcStats(player);
|
||||
|
||||
// trigger levelup if possible
|
||||
if (mSleeping && pcstats.getLevelProgress () >= 10)
|
||||
const MWWorld::Store<ESM::GameSetting> &gmst =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||
if (mSleeping && pcstats.getLevelProgress () >= gmst.find("iLevelUpTotal")->getInt())
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->pushGuiMode (GM_Levelup);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "windowbase.hpp"
|
||||
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "container.hpp"
|
||||
|
||||
using namespace MWGui;
|
||||
|
||||
|
@ -50,3 +51,36 @@ void WindowModal::close()
|
|||
{
|
||||
MyGUI::InputManager::getInstance ().removeWidgetModal (mMainWidget);
|
||||
}
|
||||
|
||||
NoDrop::NoDrop(DragAndDrop *drag, MyGUI::Widget *widget)
|
||||
: mDrag(drag), mWidget(widget), mTransparent(false)
|
||||
{
|
||||
}
|
||||
|
||||
void NoDrop::onFrame(float dt)
|
||||
{
|
||||
MyGUI::IntPoint mousePos = MyGUI::InputManager::getInstance().getMousePosition();
|
||||
|
||||
if (mDrag->mIsOnDragAndDrop)
|
||||
{
|
||||
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getMouseFocusWidget();
|
||||
while (focus && focus != mWidget)
|
||||
focus = focus->getParent();
|
||||
|
||||
if (focus == mWidget)
|
||||
mTransparent = true;
|
||||
}
|
||||
if (!mWidget->getAbsoluteCoord().inside(mousePos))
|
||||
mTransparent = false;
|
||||
|
||||
if (mTransparent)
|
||||
{
|
||||
mWidget->setNeedMouseFocus(false); // Allow click-through
|
||||
mWidget->setAlpha(std::max(0.13f, mWidget->getAlpha() - dt*5));
|
||||
}
|
||||
else
|
||||
{
|
||||
mWidget->setNeedMouseFocus(true);
|
||||
mWidget->setAlpha(std::min(1.0f, mWidget->getAlpha() + dt*5));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace MWBase
|
|||
namespace MWGui
|
||||
{
|
||||
class WindowManager;
|
||||
class DragAndDrop;
|
||||
|
||||
class WindowBase: public OEngine::GUI::Layout
|
||||
{
|
||||
|
@ -42,6 +43,21 @@ namespace MWGui
|
|||
virtual void open();
|
||||
virtual void close();
|
||||
};
|
||||
|
||||
/// A window that cannot be the target of a drag&drop action.
|
||||
/// When hovered with a drag item, the window will become transparent and allow click-through.
|
||||
class NoDrop
|
||||
{
|
||||
public:
|
||||
NoDrop(DragAndDrop* drag, MyGUI::Widget* widget);
|
||||
|
||||
void onFrame(float dt);
|
||||
|
||||
private:
|
||||
MyGUI::Widget* mWidget;
|
||||
DragAndDrop* mDrag;
|
||||
bool mTransparent;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <extern/sdl4ogre/sdlcursormanager.hpp>
|
||||
|
||||
#include "../mwbase/inputmanager.hpp"
|
||||
#include "../mwbase/statemanager.hpp"
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/player.hpp"
|
||||
|
@ -200,9 +201,9 @@ namespace MWGui
|
|||
|
||||
mRecharge = new Recharge();
|
||||
mMenu = new MainMenu(w,h);
|
||||
mMap = new MapWindow("");
|
||||
mMap = new MapWindow(mDragAndDrop, "");
|
||||
trackWindow(mMap, "map");
|
||||
mStatsWindow = new StatsWindow();
|
||||
mStatsWindow = new StatsWindow(mDragAndDrop);
|
||||
trackWindow(mStatsWindow, "stats");
|
||||
mConsole = new Console(w,h, mConsoleOnlyScripts);
|
||||
trackWindow(mConsole, "console");
|
||||
|
@ -227,7 +228,7 @@ namespace MWGui
|
|||
mConfirmationDialog = new ConfirmationDialog();
|
||||
mAlchemyWindow = new AlchemyWindow();
|
||||
trackWindow(mAlchemyWindow, "alchemy");
|
||||
mSpellWindow = new SpellWindow();
|
||||
mSpellWindow = new SpellWindow(mDragAndDrop);
|
||||
trackWindow(mSpellWindow, "spells");
|
||||
mQuickKeysMenu = new QuickKeysMenu();
|
||||
mLevelupDialog = new LevelupDialog();
|
||||
|
@ -699,6 +700,10 @@ namespace MWGui
|
|||
|
||||
mToolTips->onFrame(frameDuration);
|
||||
|
||||
if (MWBase::Environment::get().getStateManager()->getState()==
|
||||
MWBase::StateManager::State_NoGame)
|
||||
return;
|
||||
|
||||
if (mDragAndDrop->mIsOnDragAndDrop)
|
||||
{
|
||||
assert(mDragAndDrop->mDraggedWidget);
|
||||
|
@ -709,7 +714,9 @@ namespace MWGui
|
|||
|
||||
mInventoryWindow->onFrame();
|
||||
|
||||
mStatsWindow->onFrame();
|
||||
mStatsWindow->onFrame(frameDuration);
|
||||
mMap->onFrame(frameDuration);
|
||||
mSpellWindow->onFrame(frameDuration);
|
||||
|
||||
mWaitDialog->onFrame(frameDuration);
|
||||
|
||||
|
@ -730,31 +737,20 @@ namespace MWGui
|
|||
mCompanionWindow->onFrame();
|
||||
}
|
||||
|
||||
void WindowManager::changeCell(MWWorld::Ptr::CellStore* cell)
|
||||
void WindowManager::changeCell(MWWorld::CellStore* cell)
|
||||
{
|
||||
std::string name = MWBase::Environment::get().getWorld()->getCellName (cell);
|
||||
|
||||
mMap->setCellName( name );
|
||||
mHud->setCellName( name );
|
||||
|
||||
if (cell->mCell->isExterior())
|
||||
{
|
||||
std::string name;
|
||||
if (cell->mCell->mName != "")
|
||||
{
|
||||
name = cell->mCell->mName;
|
||||
if (!cell->mCell->mName.empty())
|
||||
mMap->addVisitedLocation ("#{sCell=" + name + "}", cell->mCell->getGridX (), cell->mCell->getGridY ());
|
||||
}
|
||||
else
|
||||
{
|
||||
const ESM::Region* region =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Region>().search(cell->mCell->mRegion);
|
||||
if (region)
|
||||
name = region->mName;
|
||||
else
|
||||
name = getGameSettingString("sDefaultCellname", "Wilderness");
|
||||
}
|
||||
|
||||
mMap->cellExplored(cell->mCell->getGridX(), cell->mCell->getGridY());
|
||||
|
||||
mMap->setCellName( name );
|
||||
mHud->setCellName( name );
|
||||
|
||||
mMap->setCellPrefix("Cell");
|
||||
mHud->setCellPrefix("Cell");
|
||||
mMap->setActiveCell( cell->mCell->getGridX(), cell->mCell->getGridY() );
|
||||
|
@ -762,8 +758,6 @@ namespace MWGui
|
|||
}
|
||||
else
|
||||
{
|
||||
mMap->setCellName( cell->mCell->mName );
|
||||
mHud->setCellName( cell->mCell->mName );
|
||||
mMap->setCellPrefix( cell->mCell->mName );
|
||||
mHud->setCellPrefix( cell->mCell->mName );
|
||||
|
||||
|
@ -774,7 +768,6 @@ namespace MWGui
|
|||
MWBase::Environment::get().getWorld()->getPlayer().setLastKnownExteriorPosition(worldPos);
|
||||
mMap->setGlobalMapPlayerPosition(worldPos.x, worldPos.y);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void WindowManager::setInteriorMapTexture(const int x, const int y)
|
||||
|
@ -1237,7 +1230,7 @@ namespace MWGui
|
|||
bool WindowManager::getRestEnabled()
|
||||
{
|
||||
//Enable rest dialogue if character creation finished
|
||||
if(mRestAllowed==false && MWBase::Environment::get().getWorld()->getGlobalVariable ("chargenstate").mFloat==-1)
|
||||
if(mRestAllowed==false && MWBase::Environment::get().getWorld()->getGlobalFloat ("chargenstate")==-1)
|
||||
mRestAllowed=true;
|
||||
return mRestAllowed;
|
||||
}
|
||||
|
@ -1390,4 +1383,19 @@ namespace MWGui
|
|||
Settings::Manager::setFloat(setting + " h", "Windows", h);
|
||||
}
|
||||
|
||||
void WindowManager::clear()
|
||||
{
|
||||
mMap->clear();
|
||||
}
|
||||
|
||||
void WindowManager::write(ESM::ESMWriter &writer)
|
||||
{
|
||||
mMap->write(writer);
|
||||
}
|
||||
|
||||
void WindowManager::readRecord(ESM::ESMReader &reader, int32_t type)
|
||||
{
|
||||
mMap->readRecord(reader, type);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -105,6 +105,7 @@ namespace MWGui
|
|||
*/
|
||||
virtual void update();
|
||||
|
||||
/// Warning: do not use MyGUI::InputManager::setKeyFocusWidget directly. Instead use this.
|
||||
virtual void setKeyFocusWidget (MyGUI::Widget* widget);
|
||||
|
||||
virtual void setNewGame(bool newgame);
|
||||
|
@ -280,6 +281,12 @@ namespace MWGui
|
|||
|
||||
virtual bool getCursorVisible();
|
||||
|
||||
/// Clear all savegame-specific data
|
||||
virtual void clear();
|
||||
|
||||
virtual void write (ESM::ESMWriter& writer);
|
||||
virtual void readRecord (ESM::ESMReader& reader, int32_t type);
|
||||
|
||||
private:
|
||||
bool mConsoleOnlyScripts;
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
#include "../mwbase/statemanager.hpp"
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
|
||||
using namespace ICS;
|
||||
|
@ -167,7 +168,9 @@ namespace MWInput
|
|||
switch (action)
|
||||
{
|
||||
case A_GameMenu:
|
||||
toggleMainMenu ();
|
||||
if(!(MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_Running
|
||||
&& MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_MainMenu))
|
||||
toggleMainMenu ();
|
||||
break;
|
||||
case A_Screenshot:
|
||||
screenshot();
|
||||
|
@ -248,8 +251,6 @@ namespace MWInput
|
|||
|
||||
mInputManager->capture(loading);
|
||||
// inject some fake mouse movement to force updating MyGUI's widget states
|
||||
// this shouldn't do any harm since we're moving back to the original position afterwards
|
||||
MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX+1), int(mMouseY+1), mMouseWheel);
|
||||
MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel);
|
||||
|
||||
// update values of channels (as a result of pressed keys)
|
||||
|
@ -280,7 +281,9 @@ namespace MWInput
|
|||
return;
|
||||
|
||||
// Disable movement in Gui mode
|
||||
if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return;
|
||||
if (MWBase::Environment::get().getWindowManager()->isGuiMode()
|
||||
|| MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_Running)
|
||||
return;
|
||||
|
||||
|
||||
// Configure player movement according to keyboard input. Actual movement will
|
||||
|
@ -574,8 +577,6 @@ namespace MWInput
|
|||
|
||||
double x = arg.xrel * mCameraSensitivity * (1.0f/256.f);
|
||||
double y = arg.yrel * mCameraSensitivity * (1.0f/256.f) * (mInvertY ? -1 : 1) * mCameraYMultiplier;
|
||||
float scale = MWBase::Environment::get().getFrameDuration();
|
||||
if(scale <= 0.0f) scale = 1.0f;
|
||||
|
||||
float rot[3];
|
||||
rot[0] = -y;
|
||||
|
@ -585,8 +586,8 @@ namespace MWInput
|
|||
// Only actually turn player when we're not in vanity mode
|
||||
if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot))
|
||||
{
|
||||
mPlayer->yaw(x/scale);
|
||||
mPlayer->pitch(-y/scale);
|
||||
mPlayer->yaw(x);
|
||||
mPlayer->pitch(-y);
|
||||
}
|
||||
|
||||
if (arg.zrel && mControlSwitch["playerviewswitch"]) //Check to make sure you are allowed to zoomout and there is a change
|
||||
|
@ -615,7 +616,7 @@ namespace MWInput
|
|||
|
||||
void InputManager::windowClosed()
|
||||
{
|
||||
MWBase::Environment::setRequestExit();
|
||||
MWBase::Environment::get().getStateManager()->requestQuit();
|
||||
}
|
||||
|
||||
void InputManager::toggleMainMenu()
|
||||
|
@ -747,7 +748,8 @@ namespace MWInput
|
|||
|
||||
void InputManager::showQuickKeysMenu()
|
||||
{
|
||||
if (!MWBase::Environment::get().getWindowManager()->isGuiMode ())
|
||||
if (!MWBase::Environment::get().getWindowManager()->isGuiMode ()
|
||||
&& MWBase::Environment::get().getWorld()->getGlobalFloat ("chargenstate")==-1)
|
||||
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_QuickKeysMenu);
|
||||
else if (MWBase::Environment::get().getWindowManager()->getMode () == MWGui::GM_QuickKeysMenu)
|
||||
MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_QuickKeysMenu);
|
||||
|
|
|
@ -757,7 +757,7 @@ namespace MWMechanics
|
|||
}
|
||||
}
|
||||
|
||||
void Actors::dropActors (const MWWorld::Ptr::CellStore *cellStore, const MWWorld::Ptr& ignore)
|
||||
void Actors::dropActors (const MWWorld::CellStore *cellStore, const MWWorld::Ptr& ignore)
|
||||
{
|
||||
PtrControllerMap::iterator iter = mActors.begin();
|
||||
while(iter != mActors.end())
|
||||
|
@ -774,23 +774,56 @@ namespace MWMechanics
|
|||
|
||||
void Actors::update (float duration, bool paused)
|
||||
{
|
||||
if (!paused)
|
||||
if(!paused)
|
||||
{
|
||||
// Reset data from previous frame
|
||||
for (PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||
{
|
||||
// Reset last hit object, which is only valid for one frame
|
||||
// Note, the new hit object for this frame may be set by CharacterController::update -> Animation::runAnimation
|
||||
// (below)
|
||||
iter->first.getClass().getCreatureStats(iter->first).setLastHitObject(std::string());
|
||||
}
|
||||
|
||||
// AI and magic effects update
|
||||
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
||||
{
|
||||
if (!iter->first.getClass().getCreatureStats(iter->first).isDead())
|
||||
{
|
||||
updateActor(iter->first, duration);
|
||||
if(iter->first.getTypeName() == typeid(ESM::NPC).name())
|
||||
updateNpc(iter->first, duration, paused);
|
||||
}
|
||||
}
|
||||
|
||||
// Looping magic VFX update
|
||||
// Note: we need to do this before any of the animations are updated.
|
||||
// Reaching the text keys may trigger Hit / Spellcast (and as such, particles),
|
||||
// so updating VFX immediately after that would just remove the particle effects instantly.
|
||||
// There needs to be a magic effect update in between.
|
||||
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
||||
iter->second->updateContinuousVfx();
|
||||
|
||||
// Animation/movement update
|
||||
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
||||
{
|
||||
if (iter->first.getClass().getCreatureStats(iter->first).getMagicEffects().get(
|
||||
ESM::MagicEffect::Paralyze).mMagnitude > 0)
|
||||
iter->second->skipAnim();
|
||||
iter->second->update(duration);
|
||||
}
|
||||
|
||||
// Kill dead actors
|
||||
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();iter++)
|
||||
{
|
||||
const MWWorld::Class &cls = MWWorld::Class::get(iter->first);
|
||||
CreatureStats &stats = cls.getCreatureStats(iter->first);
|
||||
|
||||
stats.setLastHitObject(std::string());
|
||||
if(!stats.isDead())
|
||||
{
|
||||
if(iter->second->isDead())
|
||||
iter->second->resurrect();
|
||||
|
||||
updateActor(iter->first, duration);
|
||||
if(iter->first.getTypeName() == typeid(ESM::NPC).name())
|
||||
updateNpc(iter->first, duration, paused);
|
||||
|
||||
if(!stats.isDead())
|
||||
continue;
|
||||
}
|
||||
|
@ -799,65 +832,47 @@ namespace MWMechanics
|
|||
if(iter->first.getRefData().getHandle()=="player" &&
|
||||
MWBase::Environment::get().getWorld()->getGodModeState())
|
||||
{
|
||||
MWMechanics::DynamicStat<float> stat(stats.getHealth());
|
||||
MWMechanics::DynamicStat<float> stat (stats.getHealth());
|
||||
|
||||
if(stat.getModified()<1)
|
||||
if (stat.getModified()<1)
|
||||
{
|
||||
stat.setModified(1, 0);
|
||||
stats.setHealth(stat);
|
||||
}
|
||||
|
||||
stats.resurrect();
|
||||
continue;
|
||||
}
|
||||
|
||||
if(iter->second->isDead())
|
||||
continue;
|
||||
|
||||
iter->second->kill();
|
||||
|
||||
// Apply soultrap
|
||||
if (iter->first.getTypeName() == typeid(ESM::Creature).name())
|
||||
{
|
||||
SoulTrap soulTrap (iter->first);
|
||||
stats.getActiveSpells().visitEffectSources(soulTrap);
|
||||
}
|
||||
|
||||
// Reset magic effects and recalculate derived effects
|
||||
// One case where we need this is to make sure bound items are removed upon death
|
||||
stats.setMagicEffects(MWMechanics::MagicEffects());
|
||||
calculateCreatureStatModifiers(iter->first, 0);
|
||||
|
||||
// Make sure spell effects with CasterLinked flag are removed
|
||||
// TODO: would be nice not to do this all the time...
|
||||
for(PtrControllerMap::iterator iter2(mActors.begin());iter2 != mActors.end();++iter2)
|
||||
{
|
||||
MWMechanics::ActiveSpells& spells = iter2->first.getClass().getCreatureStats(iter2->first).getActiveSpells();
|
||||
spells.purge(iter->first.getRefData().getHandle());
|
||||
}
|
||||
|
||||
++mDeathCount[cls.getId(iter->first)];
|
||||
// FIXME: see http://bugs.openmw.org/issues/869
|
||||
MWBase::Environment::get().getWorld()->enableActorCollision(iter->first, false);
|
||||
|
||||
if(cls.isEssential(iter->first))
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sKilledEssential}");
|
||||
if (iter->second->kill())
|
||||
{
|
||||
++mDeathCount[cls.getId(iter->first)];
|
||||
|
||||
}
|
||||
}
|
||||
// Apply soultrap
|
||||
if (iter->first.getTypeName() == typeid(ESM::Creature).name())
|
||||
{
|
||||
SoulTrap soulTrap (iter->first);
|
||||
stats.getActiveSpells().visitEffectSources(soulTrap);
|
||||
}
|
||||
|
||||
if(!paused)
|
||||
{
|
||||
// Note: we need to do this before any of the animations are updated.
|
||||
// Reaching the text keys may trigger Hit / Spellcast (and as such, particles),
|
||||
// so updating VFX immediately after that would just remove the particle effects instantly.
|
||||
// There needs to be a magic effect update in between.
|
||||
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
||||
iter->second->updateContinuousVfx();
|
||||
// Reset magic effects and recalculate derived effects
|
||||
// One case where we need this is to make sure bound items are removed upon death
|
||||
stats.setMagicEffects(MWMechanics::MagicEffects());
|
||||
calculateCreatureStatModifiers(iter->first, 0);
|
||||
|
||||
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
||||
{
|
||||
if (iter->first.getClass().getCreatureStats(iter->first).getMagicEffects().get(
|
||||
ESM::MagicEffect::Paralyze).mMagnitude > 0)
|
||||
iter->second->skipAnim();
|
||||
iter->second->update(duration);
|
||||
if(cls.isEssential(iter->first))
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sKilledEssential}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,22 @@
|
|||
#include "aicombat.hpp"
|
||||
#include "aifollow.hpp"
|
||||
|
||||
#include "movement.hpp"
|
||||
#include <OgreMath.h>
|
||||
#include <OgreVector3.h>
|
||||
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/timestamp.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
#include "../mwbase/dialoguemanager.hpp"
|
||||
|
||||
#include "character.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
|
||||
#include "creaturestats.hpp"
|
||||
#include "npcstats.hpp"
|
||||
|
||||
#include <OgreMath.h>
|
||||
#include <OgreVector3.h>
|
||||
#include "steering.hpp"
|
||||
#include "movement.hpp"
|
||||
#include "character.hpp" // fixme: for getActiveWeapon
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -43,7 +42,9 @@ namespace MWMechanics
|
|||
mReadyToAttack(false),
|
||||
mStrike(false),
|
||||
mCombatMove(false),
|
||||
mMovement()
|
||||
mRotate(false),
|
||||
mMovement(),
|
||||
mTargetAngle(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -68,10 +69,16 @@ namespace MWMechanics
|
|||
mCombatMove = false;
|
||||
}
|
||||
}
|
||||
|
||||
actor.getClass().getMovementSettings(actor) = mMovement;
|
||||
|
||||
if (mRotate)
|
||||
{
|
||||
if (zTurn(actor, Ogre::Degree(mTargetAngle)))
|
||||
mRotate = false;
|
||||
}
|
||||
|
||||
|
||||
//actor.getClass().getCreatureStats(actor).setAttackingOrSpell(mReadyToAttack);
|
||||
mTimerAttack -= duration;
|
||||
actor.getClass().getCreatureStats(actor).setAttackingOrSpell(mStrike);
|
||||
|
||||
|
@ -156,17 +163,12 @@ namespace MWMechanics
|
|||
weapRange = 150; //TODO: use true attack range (the same problem in Creature::hit)
|
||||
}
|
||||
|
||||
//MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(false);
|
||||
|
||||
ESM::Position pos = actor.getRefData().getPosition();
|
||||
|
||||
float zAngle;
|
||||
|
||||
|
||||
float rangeMelee;
|
||||
float rangeCloseUp;
|
||||
bool distantCombat = false;
|
||||
if (weaptype==WeapType_BowAndArrow || weaptype==WeapType_Crossbow || weaptype==WeapType_ThowWeapon)
|
||||
if (weaptype==WeapType_BowAndArrow || weaptype==WeapType_Crossbow || weaptype==WeapType_Thrown)
|
||||
{
|
||||
rangeMelee = 1000; // TODO: should depend on archer skill
|
||||
rangeCloseUp = 0; //doesn't needed when attacking from distance
|
||||
|
@ -189,12 +191,8 @@ namespace MWMechanics
|
|||
//Melee and Close-up combat
|
||||
vDir.z = 0;
|
||||
float dirLen = vDir.length();
|
||||
zAngle = Ogre::Radian( Ogre::Math::ACos(vDir.y / dirLen) * sgn(Ogre::Math::ASin(vDir.x / dirLen)) ).valueDegrees();
|
||||
|
||||
// TODO: use movement settings instead of rotating directly
|
||||
MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false);
|
||||
|
||||
//MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
mTargetAngle = Ogre::Radian( Ogre::Math::ACos(vDir.y / dirLen) * sgn(Ogre::Math::ASin(vDir.x / dirLen)) ).valueDegrees();
|
||||
mRotate = true;
|
||||
|
||||
//bool LOS = MWBase::Environment::get().getWorld()->getLOS(actor, mTarget);
|
||||
if (mFollowTarget && distBetween > rangeMelee)
|
||||
|
@ -206,7 +204,10 @@ namespace MWMechanics
|
|||
{
|
||||
//Melee: stop running and attack
|
||||
mMovement.mPosition[1] = 0;
|
||||
chooseBestAttack(weapon, mMovement);
|
||||
|
||||
// When attacking with a weapon, choose between slash, thrust or chop
|
||||
if (actor.getClass().hasInventoryStore(actor))
|
||||
chooseBestAttack(weapon, mMovement);
|
||||
|
||||
if(mMovement.mPosition[0] || mMovement.mPosition[1])
|
||||
{
|
||||
|
@ -237,12 +238,6 @@ namespace MWMechanics
|
|||
else
|
||||
{
|
||||
//target is at far distance: build path to target OR follow target (if previously actor had reached it once)
|
||||
|
||||
/*
|
||||
//apply when AIFOLLOW package implementation will be existent
|
||||
if(mFollowTarget)
|
||||
actor.getClass().getCreatureStats(actor).getAiSequence().stack(AiFollow(mTarget));*/
|
||||
|
||||
mFollowTarget = false;
|
||||
|
||||
buildNewPath(actor);
|
||||
|
@ -252,13 +247,10 @@ namespace MWMechanics
|
|||
|
||||
//try shortcut
|
||||
if(vDir.length() < mPathFinder.getDistToNext(pos.pos[0],pos.pos[1],pos.pos[2]) && MWBase::Environment::get().getWorld()->getLOS(actor, mTarget))
|
||||
zAngle = Ogre::Radian( Ogre::Math::ACos(vDir.y / vDir.length()) * sgn(Ogre::Math::ASin(vDir.x / vDir.length())) ).valueDegrees();
|
||||
mTargetAngle = Ogre::Radian( Ogre::Math::ACos(vDir.y / vDir.length()) * sgn(Ogre::Math::ASin(vDir.x / vDir.length())) ).valueDegrees();
|
||||
else
|
||||
zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
||||
|
||||
// TODO: use movement settings instead of rotating directly
|
||||
MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false);
|
||||
//mMovement.mRotation[2] = 10*(Ogre::Degree(zAngle).valueRadians()-pos.rot[2]);
|
||||
mTargetAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
||||
mRotate = true;
|
||||
|
||||
mMovement.mPosition[1] = 1;
|
||||
mReadyToAttack = false;
|
||||
|
@ -294,6 +286,8 @@ namespace MWMechanics
|
|||
}
|
||||
}
|
||||
|
||||
actor.getClass().getMovementSettings(actor) = mMovement;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -374,7 +368,7 @@ void chooseBestAttack(const ESM::Weapon* weapon, MWMechanics::Movement &movement
|
|||
{
|
||||
if (weapon == NULL)
|
||||
{
|
||||
//hand-to-hand and creatures' attacks deal equal damage for each type
|
||||
//hand-to-hand deal equal damage for each type
|
||||
float roll = static_cast<float>(rand())/RAND_MAX;
|
||||
if(roll <= 0.333f) //side punch
|
||||
{
|
||||
|
|
|
@ -29,16 +29,21 @@ namespace MWMechanics
|
|||
|
||||
private:
|
||||
PathFinder mPathFinder;
|
||||
//controls duration of the actual strike
|
||||
// controls duration of the actual strike
|
||||
float mTimerAttack;
|
||||
float mTimerReact;
|
||||
//controls duration of the sideway & forward moves
|
||||
//when mCombatMove is true
|
||||
// controls duration of the sideway & forward moves
|
||||
// when mCombatMove is true
|
||||
float mTimerCombatMove;
|
||||
|
||||
// the z rotation angle (degrees) we want to reach
|
||||
// used every frame when mRotate is true
|
||||
float mTargetAngle;
|
||||
|
||||
bool mReadyToAttack, mStrike;
|
||||
bool mFollowTarget;
|
||||
bool mCombatMove;
|
||||
bool mRotate;
|
||||
|
||||
MWMechanics::Movement mMovement;
|
||||
MWWorld::Ptr mTarget;
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
|
||||
#include "steering.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
float sgn(float a)
|
||||
|
@ -33,7 +35,7 @@ namespace MWMechanics
|
|||
{
|
||||
mMaxDist = 470;
|
||||
|
||||
// The CS Help File states that if a duration is givin, the AI package will run for that long
|
||||
// The CS Help File states that if a duration is given, the AI package will run for that long
|
||||
// BUT if a location is givin, it "trumps" the duration so it will simply escort to that location.
|
||||
if(mX != 0 || mY != 0 || mZ != 0)
|
||||
mDuration = 0;
|
||||
|
@ -52,7 +54,7 @@ namespace MWMechanics
|
|||
{
|
||||
mMaxDist = 470;
|
||||
|
||||
// The CS Help File states that if a duration is givin, the AI package will run for that long
|
||||
// The CS Help File states that if a duration is given, the AI package will run for that long
|
||||
// BUT if a location is givin, it "trumps" the duration so it will simply escort to that location.
|
||||
if(mX != 0 || mY != 0 || mZ != 0)
|
||||
mDuration = 0;
|
||||
|
@ -89,25 +91,23 @@ namespace MWMechanics
|
|||
if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX)
|
||||
{
|
||||
int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX);
|
||||
// Check if actor is near the border of an inactive cell. If so, disable AiEscort.
|
||||
// FIXME: This *should* pause the AiEscort package instead of terminating it.
|
||||
// Check if actor is near the border of an inactive cell. If so, pause walking.
|
||||
if(sideX * (pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE /
|
||||
2.0 - 200))
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY)
|
||||
{
|
||||
int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY);
|
||||
// Check if actor is near the border of an inactive cell. If so, disable AiEscort.
|
||||
// FIXME: This *should* pause the AiEscort package instead of terminating it.
|
||||
// Check if actor is near the border of an inactive cell. If so, pause walking.
|
||||
if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE /
|
||||
2.0 - 200))
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -151,8 +151,7 @@ namespace MWMechanics
|
|||
if(distanceBetweenResult <= mMaxDist * mMaxDist)
|
||||
{
|
||||
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
||||
// TODO: use movement settings instead of rotating directly
|
||||
MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false);
|
||||
zTurn(actor, Ogre::Degree(zAngle));
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
|
||||
mMaxDist = 470;
|
||||
}
|
||||
|
|
|
@ -6,15 +6,17 @@
|
|||
#include "movement.hpp"
|
||||
|
||||
#include <OgreMath.h>
|
||||
|
||||
|
||||
#include "steering.hpp"
|
||||
|
||||
MWMechanics::AiFollow::AiFollow(const std::string &actorId,float duration, float x, float y, float z)
|
||||
: mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(""), mTimer(0), mStuckTimer(0)
|
||||
{
|
||||
}
|
||||
MWMechanics::AiFollow::AiFollow(const std::string &actorId,const std::string &cellId,float duration, float x, float y, float z)
|
||||
: mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(cellId), mTimer(0), mStuckTimer(0)
|
||||
{
|
||||
}
|
||||
{
|
||||
}
|
||||
MWMechanics::AiFollow::AiFollow(const std::string &actorId,const std::string &cellId,float duration, float x, float y, float z)
|
||||
: mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(cellId), mTimer(0), mStuckTimer(0)
|
||||
{
|
||||
}
|
||||
|
||||
bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
||||
{
|
||||
|
@ -45,14 +47,14 @@ bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
|||
}
|
||||
}
|
||||
|
||||
ESM::Pathgrid::Point dest;
|
||||
dest.mX = target.getRefData().getPosition().pos[0];
|
||||
dest.mY = target.getRefData().getPosition().pos[1];
|
||||
ESM::Pathgrid::Point dest;
|
||||
dest.mX = target.getRefData().getPosition().pos[0];
|
||||
dest.mY = target.getRefData().getPosition().pos[1];
|
||||
dest.mZ = target.getRefData().getPosition().pos[2];
|
||||
|
||||
ESM::Pathgrid::Point start;
|
||||
start.mX = pos.pos[0];
|
||||
start.mY = pos.pos[1];
|
||||
ESM::Pathgrid::Point start;
|
||||
start.mX = pos.pos[0];
|
||||
start.mY = pos.pos[1];
|
||||
start.mZ = pos.pos[2];
|
||||
|
||||
if(mPathFinder.getPath().empty())
|
||||
|
@ -88,18 +90,14 @@ bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
|||
|
||||
if(!mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]))
|
||||
{
|
||||
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
||||
//MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false);
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mRotation[2] = 10*(Ogre::Degree(zAngle).valueRadians()-pos.rot[2]);
|
||||
//std::cout << Ogre::Degree(zAngle).valueDegrees()-Ogre::Radian(actor.getRefData().getPosition().rot[2]).valueDegrees() << " "<< pos.rot[2] << " " << zAngle << "\n";
|
||||
//MWWorld::Class::get(actor).get
|
||||
}
|
||||
|
||||
if((dest.mX - pos.pos[0])*(dest.mX - pos.pos[0])+(dest.mY - pos.pos[1])*(dest.mY - pos.pos[1])+(dest.mZ - pos.pos[2])*(dest.mZ - pos.pos[2])
|
||||
< 100*100)
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])));
|
||||
}
|
||||
|
||||
if((dest.mX - pos.pos[0])*(dest.mX - pos.pos[0])+(dest.mY - pos.pos[1])*(dest.mY - pos.pos[1])+(dest.mZ - pos.pos[2])*(dest.mZ - pos.pos[2])
|
||||
< 100*100)
|
||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
||||
else
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
|
||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -109,12 +107,12 @@ std::string MWMechanics::AiFollow::getFollowedActor()
|
|||
return mActorId;
|
||||
}
|
||||
|
||||
MWMechanics::AiFollow *MWMechanics::AiFollow::clone() const
|
||||
{
|
||||
return new AiFollow(*this);
|
||||
}
|
||||
|
||||
int MWMechanics::AiFollow::getTypeId() const
|
||||
{
|
||||
return TypeIdFollow;
|
||||
MWMechanics::AiFollow *MWMechanics::AiFollow::clone() const
|
||||
{
|
||||
return new AiFollow(*this);
|
||||
}
|
||||
|
||||
int MWMechanics::AiFollow::getTypeId() const
|
||||
{
|
||||
return TypeIdFollow;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ void MWMechanics::AiSequence::copy (const AiSequence& sequence)
|
|||
mPackages.push_back ((*iter)->clone());
|
||||
}
|
||||
|
||||
MWMechanics::AiSequence::AiSequence() : mDone (false) {}
|
||||
MWMechanics::AiSequence::AiSequence() : mDone (false), mLastAiPackage(-1) {}
|
||||
|
||||
MWMechanics::AiSequence::AiSequence (const AiSequence& sequence) : mDone (false)
|
||||
{
|
||||
|
@ -84,6 +84,7 @@ void MWMechanics::AiSequence::execute (const MWWorld::Ptr& actor,float duration)
|
|||
{
|
||||
if (!mPackages.empty())
|
||||
{
|
||||
mLastAiPackage = mPackages.front()->getTypeId();
|
||||
if (mPackages.front()->execute (actor,duration))
|
||||
{
|
||||
delete *mPackages.begin();
|
||||
|
@ -91,7 +92,9 @@ void MWMechanics::AiSequence::execute (const MWWorld::Ptr& actor,float duration)
|
|||
mDone = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mDone = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,9 @@ namespace MWMechanics
|
|||
|
||||
void copy (const AiSequence& sequence);
|
||||
|
||||
// The type of AI package that ran last
|
||||
int mLastAiPackage;
|
||||
|
||||
public:
|
||||
|
||||
AiSequence();
|
||||
|
@ -36,6 +39,10 @@ namespace MWMechanics
|
|||
int getTypeId() const;
|
||||
///< @see enum AiPackage::TypeId
|
||||
|
||||
int getLastRunTypeId() const { return mLastAiPackage; }
|
||||
///< Get the typeid of the Ai package that ran last, NOT the currently "active" Ai package that will be run in the next frame.
|
||||
/// This difference is important when an Ai package has just finished and been removed.
|
||||
|
||||
bool getCombatTarget (std::string &targetActorId) const;
|
||||
///< Return true and assign target if combat package is currently
|
||||
/// active, return false otherwise
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
#include "aitravel.hpp"
|
||||
|
||||
#include "movement.hpp"
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
|
||||
#include "steering.hpp"
|
||||
#include "movement.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
float sgn(float a)
|
||||
|
@ -86,9 +87,7 @@ namespace MWMechanics
|
|||
return true;
|
||||
}
|
||||
|
||||
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
||||
// TODO: use movement settings instead of rotating directly
|
||||
world->rotateObject(actor, 0, 0, zAngle, false);
|
||||
zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])));
|
||||
movement.mPosition[1] = 1;
|
||||
|
||||
return false;
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include "creaturestats.hpp"
|
||||
#include <OgreVector3.h>
|
||||
|
||||
#include "steering.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
float sgn(float a)
|
||||
|
@ -68,6 +70,7 @@ namespace MWMechanics
|
|||
bool AiWander::execute (const MWWorld::Ptr& actor,float duration)
|
||||
{
|
||||
actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing);
|
||||
actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, false);
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
if(mDuration)
|
||||
{
|
||||
|
@ -188,15 +191,18 @@ namespace MWMechanics
|
|||
mIdleNow = true;
|
||||
|
||||
// Play idle voiced dialogue entries randomly
|
||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||
float chance = store.get<ESM::GameSetting>().find("fVoiceIdleOdds")->getFloat();
|
||||
int roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
|
||||
int hello = actor.getClass().getCreatureStats(actor).getAiSetting(CreatureStats::AI_Hello).getModified();
|
||||
if (hello > 0)
|
||||
{
|
||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||
float chance = store.get<ESM::GameSetting>().find("fVoiceIdleOdds")->getFloat();
|
||||
int roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
|
||||
// Don't bother if the player is out of hearing range
|
||||
if (roll < chance && Ogre::Vector3(player.getRefData().getPosition().pos).distance(Ogre::Vector3(actor.getRefData().getPosition().pos)) < 1500)
|
||||
MWBase::Environment::get().getDialogueManager()->say(actor, "idle");
|
||||
// Don't bother if the player is out of hearing range
|
||||
if (roll < chance && Ogre::Vector3(player.getRefData().getPosition().pos).distance(Ogre::Vector3(actor.getRefData().getPosition().pos)) < 1500)
|
||||
MWBase::Environment::get().getDialogueManager()->say(actor, "idle");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -205,7 +211,7 @@ namespace MWMechanics
|
|||
// Play a random voice greeting if the player gets too close
|
||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||
|
||||
float hello = actor.getClass().getCreatureStats(actor).getAiSetting(CreatureStats::AI_Hello).getModified();
|
||||
int hello = actor.getClass().getCreatureStats(actor).getAiSetting(CreatureStats::AI_Hello).getModified();
|
||||
float helloDistance = hello;
|
||||
int iGreetDistanceMultiplier = store.get<ESM::GameSetting>().find("iGreetDistanceMultiplier")->getInt();
|
||||
helloDistance *= iGreetDistanceMultiplier;
|
||||
|
@ -281,11 +287,6 @@ namespace MWMechanics
|
|||
|
||||
if(mWalking)
|
||||
{
|
||||
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
||||
// TODO: use movement settings instead of rotating directly
|
||||
world->rotateObject(actor, 0, 0, zAngle, false);
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
|
||||
|
||||
if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
|
||||
{
|
||||
stopWalking(actor);
|
||||
|
@ -293,6 +294,12 @@ namespace MWMechanics
|
|||
mWalking = false;
|
||||
mChooseAction = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])));
|
||||
|
||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/statemanager.hpp"
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
|
@ -118,7 +119,7 @@ static const struct WeaponInfo {
|
|||
{ WeapType_TwoWide, "2w", "weapontwowide" },
|
||||
{ WeapType_BowAndArrow, "1h", "bowandarrow" },
|
||||
{ WeapType_Crossbow, "crossbow", "crossbow" },
|
||||
{ WeapType_ThowWeapon, "1h", "throwweapon" },
|
||||
{ WeapType_Thrown, "1h", "throwweapon" },
|
||||
{ WeapType_PickProbe, "1h", "pickprobe" },
|
||||
{ WeapType_Spell, "spell", "spellcast" },
|
||||
};
|
||||
|
@ -156,7 +157,14 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
|||
bool block = mPtr.getClass().getCreatureStats(mPtr).getBlock();
|
||||
if(mHitState == CharState_None)
|
||||
{
|
||||
if(knockdown)
|
||||
if (mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() < 0)
|
||||
{
|
||||
mHitState = CharState_KnockOut;
|
||||
mCurrentHit = "knockout";
|
||||
mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::Group_All, false, 1, "start", "stop", 0.0f, ~0ul);
|
||||
mPtr.getClass().getCreatureStats(mPtr).setKnockedDown(true);
|
||||
}
|
||||
else if(knockdown)
|
||||
{
|
||||
mHitState = CharState_KnockDown;
|
||||
mCurrentHit = "knockdown";
|
||||
|
@ -186,6 +194,12 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
|||
mPtr.getClass().getCreatureStats(mPtr).setBlock(false);
|
||||
mHitState = CharState_None;
|
||||
}
|
||||
else if (mHitState == CharState_KnockOut && mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() > 0)
|
||||
{
|
||||
mHitState = CharState_KnockDown;
|
||||
mAnimation->disable(mCurrentHit);
|
||||
mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::Group_All, true, 1, "loop stop", "stop", 0.0f, 0);
|
||||
}
|
||||
}
|
||||
|
||||
const WeaponInfo *weap = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(mWeaponType));
|
||||
|
@ -301,12 +315,24 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
|||
if(!mCurrentMovement.empty())
|
||||
{
|
||||
float vel, speedmult = 1.0f;
|
||||
|
||||
bool isrunning = mPtr.getClass().getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Run);
|
||||
|
||||
if(mMovementSpeed > 0.0f && (vel=mAnimation->getVelocity(mCurrentMovement)) > 1.0f)
|
||||
speedmult = mMovementSpeed / vel;
|
||||
|
||||
else if (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight)
|
||||
speedmult = 1.f; // TODO: should get a speed mult depending on the current turning speed
|
||||
else if (mMovementSpeed > 0.0f)
|
||||
// The first person anims don't have any velocity to calculate a speed multiplier from.
|
||||
// We use the third person velocities instead.
|
||||
// FIXME: should be pulled from the actual animation, but it is not presently loaded.
|
||||
speedmult = mMovementSpeed / (isrunning ? 222.857f : 154.064f);
|
||||
mAnimation->play(mCurrentMovement, Priority_Movement, movegroup, false,
|
||||
speedmult, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul);
|
||||
|
||||
mMovementAnimVelocity = vel;
|
||||
}
|
||||
else mMovementAnimVelocity = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -367,7 +393,7 @@ MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, MWWorld::I
|
|||
*weaptype = WeapType_Crossbow;
|
||||
break;
|
||||
case ESM::Weapon::MarksmanThrown:
|
||||
*weaptype = WeapType_ThowWeapon;
|
||||
*weaptype = WeapType_Thrown;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -403,6 +429,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
|
|||
, mIdleState(CharState_None)
|
||||
, mMovementState(CharState_None)
|
||||
, mMovementSpeed(0.0f)
|
||||
, mMovementAnimVelocity(0.0f)
|
||||
, mDeathState(CharState_None)
|
||||
, mHitState(CharState_None)
|
||||
, mUpperBodyState(UpperCharState_Nothing)
|
||||
|
@ -479,7 +506,14 @@ bool CharacterController::updateCreatureState()
|
|||
{
|
||||
MWBase::Environment::get().getWorld()->breakInvisibility(mPtr);
|
||||
|
||||
determineAttackType();
|
||||
// These are unique animations and not linked to movement type. Just pick one randomly.
|
||||
int roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 3; // [0, 2]
|
||||
if (roll == 0)
|
||||
mCurrentWeapon = "attack1";
|
||||
else if (roll == 1)
|
||||
mCurrentWeapon = "attack2";
|
||||
else
|
||||
mCurrentWeapon = "attack3";
|
||||
|
||||
mAnimation->play(mCurrentWeapon, Priority_Weapon,
|
||||
MWRender::Animation::Group_All, true,
|
||||
|
@ -527,6 +561,7 @@ bool CharacterController::updateWeaponState()
|
|||
{
|
||||
getWeaponGroup(weaptype, weapgroup);
|
||||
mAnimation->showWeapons(false);
|
||||
mAnimation->setWeaponGroup(weapgroup);
|
||||
|
||||
mAnimation->play(weapgroup, Priority_Weapon,
|
||||
MWRender::Animation::Group_UpperBody, true,
|
||||
|
@ -581,6 +616,19 @@ bool CharacterController::updateWeaponState()
|
|||
if(isWeapon)
|
||||
weapSpeed = weapon->get<ESM::Weapon>()->mBase->mData.mSpeed;
|
||||
|
||||
// Cancel attack if we no longer have ammunition
|
||||
bool ammunition = true;
|
||||
MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
||||
if (mWeaponType == WeapType_Crossbow)
|
||||
ammunition = (ammo != inv.end() && ammo->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::Bolt);
|
||||
else if (mWeaponType == WeapType_BowAndArrow)
|
||||
ammunition = (ammo != inv.end() && ammo->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::Arrow);
|
||||
if (!ammunition && mUpperBodyState > UpperCharState_WeapEquiped)
|
||||
{
|
||||
mAnimation->disable(mCurrentWeapon);
|
||||
mUpperBodyState = UpperCharState_WeapEquiped;
|
||||
}
|
||||
|
||||
float complete;
|
||||
bool animPlaying;
|
||||
if(stats.getAttackingOrSpell())
|
||||
|
@ -685,14 +733,15 @@ bool CharacterController::updateWeaponState()
|
|||
if(item.getRefData().getCount())
|
||||
MWBase::Environment::get().getWindowManager()->setSelectedWeapon(item);
|
||||
}
|
||||
else
|
||||
else if (ammunition)
|
||||
{
|
||||
if(mWeaponType == WeapType_Crossbow || mWeaponType == WeapType_BowAndArrow ||
|
||||
mWeaponType == WeapType_ThowWeapon)
|
||||
mWeaponType == WeapType_Thrown)
|
||||
mAttackType = "shoot";
|
||||
else
|
||||
{
|
||||
if(isWeapon && Settings::Manager::getBool("best attack", "Game"))
|
||||
if(isWeapon && mPtr.getRefData().getHandle() == "player" &&
|
||||
Settings::Manager::getBool("best attack", "Game"))
|
||||
mAttackType = getBestAttack(weapon->get<ESM::Weapon>()->mBase);
|
||||
else
|
||||
determineAttackType();
|
||||
|
@ -751,12 +800,59 @@ bool CharacterController::updateWeaponState()
|
|||
}
|
||||
}
|
||||
|
||||
mAnimation->setPitchFactor(0.f);
|
||||
if (mWeaponType == WeapType_BowAndArrow || mWeaponType == WeapType_Thrown)
|
||||
{
|
||||
switch (mUpperBodyState)
|
||||
{
|
||||
case UpperCharState_StartToMinAttack:
|
||||
mAnimation->setPitchFactor(complete);
|
||||
break;
|
||||
case UpperCharState_MinAttackToMaxAttack:
|
||||
case UpperCharState_MaxAttackToMinHit:
|
||||
case UpperCharState_MinHitToHit:
|
||||
mAnimation->setPitchFactor(1.f);
|
||||
break;
|
||||
case UpperCharState_FollowStartToFollowStop:
|
||||
if (animPlaying)
|
||||
mAnimation->setPitchFactor(1.f-complete);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (mWeaponType == WeapType_Crossbow)
|
||||
{
|
||||
switch (mUpperBodyState)
|
||||
{
|
||||
case UpperCharState_EquipingWeap:
|
||||
mAnimation->setPitchFactor(complete);
|
||||
break;
|
||||
case UpperCharState_UnEquipingWeap:
|
||||
mAnimation->setPitchFactor(1.f-complete);
|
||||
break;
|
||||
case UpperCharState_WeapEquiped:
|
||||
case UpperCharState_StartToMinAttack:
|
||||
case UpperCharState_MinAttackToMaxAttack:
|
||||
case UpperCharState_MaxAttackToMinHit:
|
||||
case UpperCharState_MinHitToHit:
|
||||
case UpperCharState_FollowStartToFollowStop:
|
||||
mAnimation->setPitchFactor(1.f);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!animPlaying)
|
||||
{
|
||||
if(mUpperBodyState == UpperCharState_EquipingWeap ||
|
||||
mUpperBodyState == UpperCharState_FollowStartToFollowStop ||
|
||||
mUpperBodyState == UpperCharState_CastingSpell)
|
||||
{
|
||||
if (ammunition && mWeaponType == WeapType_Crossbow)
|
||||
mAnimation->attachArrow();
|
||||
|
||||
mUpperBodyState = UpperCharState_WeapEquiped;
|
||||
//don't allow to continue playing hit animation on UpperBody after actor had attacked during it
|
||||
if(mHitState == CharState_Hit)
|
||||
|
@ -1136,18 +1232,17 @@ void CharacterController::update(float duration)
|
|||
|
||||
if (!mSkipAnim)
|
||||
{
|
||||
if(mHitState != CharState_KnockDown)
|
||||
rot *= Ogre::Math::RadiansToDegrees(1.0f);
|
||||
if(mHitState != CharState_KnockDown && mHitState != CharState_KnockOut)
|
||||
{
|
||||
rot *= duration * Ogre::Math::RadiansToDegrees(1.0f);
|
||||
world->rotateObject(mPtr, rot.x, rot.y, rot.z, true);
|
||||
}
|
||||
else //avoid z-rotating for knockdown
|
||||
world->rotateObject(mPtr, rot.x, rot.y, 0.0f, true);
|
||||
|
||||
// all actual movement in 3rd person controlled by animations, except for jump
|
||||
// !mAnimation->hasAnimation("death1") identifies 1st person mode
|
||||
if(mJumpState != JumpState_None || vec.z > 0
|
||||
|| (mPtr.getRefData().getHandle() == "player" && !mAnimation->hasAnimation("death1")))
|
||||
// always control actual movement by animation unless this:
|
||||
// FIXME: actor falling/landing should be controlled by physics engine
|
||||
if(mMovementAnimVelocity == 0.0f && (vec.length() > 0.0f || mJumpState != JumpState_None))
|
||||
{
|
||||
world->queueMovement(mPtr, vec);
|
||||
}
|
||||
|
@ -1158,7 +1253,6 @@ void CharacterController::update(float duration)
|
|||
}
|
||||
else if(cls.getCreatureStats(mPtr).isDead())
|
||||
{
|
||||
MWBase::Environment::get().getWorld()->enableActorCollision(mPtr, false);
|
||||
world->queueMovement(mPtr, Ogre::Vector3(0.0f));
|
||||
}
|
||||
|
||||
|
@ -1260,10 +1354,17 @@ void CharacterController::forceStateUpdate()
|
|||
}
|
||||
}
|
||||
|
||||
void CharacterController::kill()
|
||||
bool CharacterController::kill()
|
||||
{
|
||||
if(mDeathState != CharState_None)
|
||||
return;
|
||||
if( isDead() )
|
||||
{
|
||||
//player's death animation is over
|
||||
if( mPtr.getRefData().getHandle()=="player" && !isAnimPlaying(mCurrentDeath) )
|
||||
{
|
||||
MWBase::Environment::get().getStateManager()->askLoadRecent();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
playRandomDeath();
|
||||
|
||||
|
@ -1274,6 +1375,8 @@ void CharacterController::kill()
|
|||
|
||||
mIdleState = CharState_None;
|
||||
mCurrentIdle.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CharacterController::resurrect()
|
||||
|
@ -1338,15 +1441,6 @@ void CharacterController::determineAttackType()
|
|||
else
|
||||
mAttackType = "chop";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (move[0] && !move[1]) //sideway
|
||||
mCurrentWeapon = "attack2";
|
||||
else if (move[1]) //forward
|
||||
mCurrentWeapon = "attack3";
|
||||
else
|
||||
mCurrentWeapon = "attack1";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -93,6 +93,7 @@ enum CharacterState {
|
|||
|
||||
CharState_Hit,
|
||||
CharState_KnockDown,
|
||||
CharState_KnockOut,
|
||||
CharState_Block
|
||||
};
|
||||
|
||||
|
@ -105,7 +106,7 @@ enum WeaponType {
|
|||
WeapType_TwoWide,
|
||||
WeapType_BowAndArrow,
|
||||
WeapType_Crossbow,
|
||||
WeapType_ThowWeapon,
|
||||
WeapType_Thrown,
|
||||
WeapType_PickProbe,
|
||||
|
||||
WeapType_Spell
|
||||
|
@ -144,6 +145,7 @@ class CharacterController
|
|||
CharacterState mMovementState;
|
||||
std::string mCurrentMovement;
|
||||
float mMovementSpeed;
|
||||
float mMovementAnimVelocity;
|
||||
|
||||
CharacterState mDeathState;
|
||||
std::string mCurrentDeath;
|
||||
|
@ -198,7 +200,7 @@ public:
|
|||
void skipAnim();
|
||||
bool isAnimPlaying(const std::string &groupName);
|
||||
|
||||
void kill();
|
||||
bool kill();
|
||||
void resurrect();
|
||||
bool isDead() const
|
||||
{ return mDeathState != CharState_None; }
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
namespace MWMechanics
|
||||
{
|
||||
CreatureStats::CreatureStats()
|
||||
: mLevel (0), mLevelHealthBonus(0.f), mDead (false), mDied (false), mFriendlyHits (0),
|
||||
: mLevel (0), mDead (false), mDied (false), mFriendlyHits (0),
|
||||
mTalkedTo (false), mAlarmed (false),
|
||||
mAttacked (false), mHostile (false),
|
||||
mAttackingOrSpell(false),
|
||||
|
@ -22,35 +22,6 @@ namespace MWMechanics
|
|||
mAiSettings[i] = 0;
|
||||
}
|
||||
|
||||
float CreatureStats::getLevelHealthBonus () const
|
||||
{
|
||||
return mLevelHealthBonus;
|
||||
}
|
||||
|
||||
void CreatureStats::levelUp()
|
||||
{
|
||||
const MWWorld::Store<ESM::GameSetting> &gmst =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||
|
||||
const int endurance = getAttribute(ESM::Attribute::Endurance).getBase();
|
||||
|
||||
// "When you gain a level, in addition to increasing three primary attributes, your Health
|
||||
// will automatically increase by 10% of your Endurance attribute. If you increased Endurance this level,
|
||||
// the Health increase is calculated from the increased Endurance"
|
||||
mLevelHealthBonus += endurance * gmst.find("fLevelUpHealthEndMult")->getFloat();
|
||||
updateHealth();
|
||||
|
||||
mLevel++;
|
||||
}
|
||||
|
||||
void CreatureStats::updateHealth()
|
||||
{
|
||||
const int endurance = getAttribute(ESM::Attribute::Endurance).getBase();
|
||||
const int strength = getAttribute(ESM::Attribute::Strength).getBase();
|
||||
|
||||
setHealth(static_cast<int> (0.5 * (strength + endurance)) + mLevelHealthBonus);
|
||||
}
|
||||
|
||||
const AiSequence& CreatureStats::getAiSequence() const
|
||||
{
|
||||
return mAiSequence;
|
||||
|
@ -208,9 +179,6 @@ namespace MWMechanics
|
|||
|
||||
mDynamic[index] = value;
|
||||
|
||||
if (index == 2 && value.getCurrent() < 0)
|
||||
setKnockedDown(true);
|
||||
|
||||
if (index==0 && mDynamic[index].getCurrent()<1)
|
||||
{
|
||||
if (!mDead)
|
||||
|
|
|
@ -22,13 +22,11 @@ namespace MWMechanics
|
|||
DrawState_ mDrawState;
|
||||
AttributeValue mAttributes[8];
|
||||
DynamicStat<float> mDynamic[3]; // health, magicka, fatigue
|
||||
int mLevel;
|
||||
Spells mSpells;
|
||||
ActiveSpells mActiveSpells;
|
||||
MagicEffects mMagicEffects;
|
||||
Stat<int> mAiSettings[4];
|
||||
AiSequence mAiSequence;
|
||||
float mLevelHealthBonus;
|
||||
bool mDead;
|
||||
bool mDied;
|
||||
int mFriendlyHits;
|
||||
|
@ -54,6 +52,7 @@ namespace MWMechanics
|
|||
protected:
|
||||
bool mIsWerewolf;
|
||||
AttributeValue mWerewolfAttributes[8];
|
||||
int mLevel;
|
||||
|
||||
public:
|
||||
CreatureStats();
|
||||
|
@ -142,14 +141,6 @@ namespace MWMechanics
|
|||
float getFatigueTerm() const;
|
||||
///< Return effective fatigue
|
||||
|
||||
float getLevelHealthBonus() const;
|
||||
|
||||
void levelUp();
|
||||
|
||||
void updateHealth();
|
||||
///< Calculate health based on endurance and strength.
|
||||
/// Called at character creation and at level up.
|
||||
|
||||
bool isDead() const;
|
||||
|
||||
bool hasDied() const;
|
||||
|
|
|
@ -250,7 +250,10 @@ namespace MWMechanics
|
|||
{
|
||||
if (itemEmpty())
|
||||
return 0;
|
||||
return MWWorld::Class::get(mOldItemPtr).getEnchantmentPoints(mOldItemPtr);
|
||||
|
||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||
|
||||
return mOldItemPtr.getClass().getEnchantmentPoints(mOldItemPtr) * store.get<ESM::GameSetting>().find("fEnchantmentMult")->getFloat();
|
||||
}
|
||||
bool Enchanting::soulEmpty() const
|
||||
{
|
||||
|
@ -274,22 +277,18 @@ namespace MWMechanics
|
|||
|
||||
float Enchanting::getEnchantChance() const
|
||||
{
|
||||
/*
|
||||
Formula from http://www.uesp.net/wiki/Morrowind:Enchant
|
||||
*/
|
||||
const CreatureStats& creatureStats = MWWorld::Class::get (mEnchanter).getCreatureStats (mEnchanter);
|
||||
const NpcStats& npcStats = MWWorld::Class::get (mEnchanter).getNpcStats (mEnchanter);
|
||||
|
||||
float chance1 = (npcStats.getSkill (ESM::Skill::Enchant).getModified() +
|
||||
(0.25 * creatureStats.getAttribute (ESM::Attribute::Intelligence).getModified())
|
||||
+ (0.125 * creatureStats.getAttribute (ESM::Attribute::Luck).getModified()));
|
||||
(0.25 * npcStats.getAttribute (ESM::Attribute::Intelligence).getModified())
|
||||
+ (0.125 * npcStats.getAttribute (ESM::Attribute::Luck).getModified()));
|
||||
|
||||
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||
|
||||
float chance2 = 7.5 / (gmst.find("fEnchantmentChanceMult")->getFloat() * ((mCastStyle == ESM::Enchantment::ConstantEffect) ?
|
||||
gmst.find("fEnchantmentConstantChanceMult")->getFloat() : 1 ))
|
||||
* getEnchantPoints();
|
||||
|
||||
float chance2 = 2.5 * getEnchantPoints();
|
||||
if(mCastStyle==ESM::Enchantment::ConstantEffect)
|
||||
{
|
||||
float constantChance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("fEnchantmentConstantChanceMult")->getFloat();
|
||||
chance2 /= constantChance;
|
||||
}
|
||||
return (chance1-chance2);
|
||||
}
|
||||
|
||||
|
|
|
@ -760,6 +760,14 @@ namespace MWMechanics
|
|||
return mAI;
|
||||
}
|
||||
|
||||
void MechanicsManager::playerLoaded()
|
||||
{
|
||||
mUpdatePlayer = true;
|
||||
mClassSelected = true;
|
||||
mRaceSelected = true;
|
||||
mAI = true;
|
||||
}
|
||||
|
||||
bool MechanicsManager::sleepInBed(const MWWorld::Ptr &ptr, const MWWorld::Ptr &bed)
|
||||
{
|
||||
MWWorld::Ptr victim;
|
||||
|
|
|
@ -123,22 +123,24 @@ namespace MWMechanics
|
|||
/// @return was it illegal, and someone saw you doing it?
|
||||
virtual bool sleepInBed (const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed);
|
||||
|
||||
virtual void forceStateUpdate(const MWWorld::Ptr &ptr);
|
||||
virtual void forceStateUpdate(const MWWorld::Ptr &ptr);
|
||||
|
||||
virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number);
|
||||
virtual void skipAnimation(const MWWorld::Ptr& ptr);
|
||||
virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string &groupName);
|
||||
virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number);
|
||||
virtual void skipAnimation(const MWWorld::Ptr& ptr);
|
||||
virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string &groupName);
|
||||
|
||||
/// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently
|
||||
/// paused we may want to do it manually (after equipping permanent enchantment)
|
||||
virtual void updateMagicEffects (const MWWorld::Ptr& ptr);
|
||||
|
||||
virtual void toggleAI();
|
||||
virtual bool isAIActive();
|
||||
virtual void getObjectsInRange (const Ogre::Vector3& position, float radius, std::vector<MWWorld::Ptr>& objects);
|
||||
|
||||
virtual void getObjectsInRange (const Ogre::Vector3& position, float radius, std::vector<MWWorld::Ptr>& objects);
|
||||
virtual std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor);
|
||||
|
||||
virtual std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor);
|
||||
virtual void toggleAI();
|
||||
virtual bool isAIActive();
|
||||
|
||||
virtual void playerLoaded();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ MWMechanics::NpcStats::NpcStats()
|
|||
, mProfit(0)
|
||||
, mTimeToStartDrowning(20.0)
|
||||
, mLastDrowningHit(0)
|
||||
, mLevelHealthBonus(0)
|
||||
{
|
||||
mSkillIncreases.resize (ESM::Attribute::Length, 0);
|
||||
}
|
||||
|
@ -189,22 +190,31 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas
|
|||
|
||||
base += 1;
|
||||
|
||||
// if this is a major or minor skill of the class, increase level progress
|
||||
bool levelProgress = false;
|
||||
for (int i=0; i<2; ++i)
|
||||
for (int j=0; j<5; ++j)
|
||||
const MWWorld::Store<ESM::GameSetting> &gmst =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||
|
||||
// is this a minor or major skill?
|
||||
int increase = gmst.find("iLevelupMiscMultAttriubte")->getInt(); // Note: GMST has a typo
|
||||
for (int k=0; k<5; ++k)
|
||||
{
|
||||
if (class_.mData.mSkills[k][0] == skillIndex)
|
||||
{
|
||||
int skill = class_.mData.mSkills[j][i];
|
||||
if (skill == skillIndex)
|
||||
levelProgress = true;
|
||||
mLevelProgress += gmst.find("iLevelUpMinorMult")->getInt();
|
||||
increase = gmst.find("iLevelUpMajorMultAttribute")->getInt();
|
||||
}
|
||||
}
|
||||
for (int k=0; k<5; ++k)
|
||||
{
|
||||
if (class_.mData.mSkills[k][1] == skillIndex)
|
||||
{
|
||||
mLevelProgress += gmst.find("iLevelUpMajorMult")->getInt();
|
||||
increase = gmst.find("iLevelUpMinorMultAttribute")->getInt();
|
||||
}
|
||||
}
|
||||
|
||||
mLevelProgress += levelProgress;
|
||||
|
||||
// check the attribute this skill belongs to
|
||||
const ESM::Skill* skill =
|
||||
MWBase::Environment::get().getWorld ()->getStore ().get<ESM::Skill>().find(skillIndex);
|
||||
++mSkillIncreases[skill->mData.mAttribute];
|
||||
mSkillIncreases[skill->mData.mAttribute] += increase;
|
||||
|
||||
// Play sound & skill progress notification
|
||||
/// \todo check if character is the player, if levelling is ever implemented for NPCs
|
||||
|
@ -216,7 +226,7 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas
|
|||
% static_cast<int> (base);
|
||||
MWBase::Environment::get().getWindowManager ()->messageBox(message.str());
|
||||
|
||||
if (mLevelProgress >= 10)
|
||||
if (mLevelProgress >= gmst.find("iLevelUpTotal")->getInt())
|
||||
{
|
||||
// levelup is possible now
|
||||
MWBase::Environment::get().getWindowManager ()->messageBox ("#{sLevelUpMsg}");
|
||||
|
@ -237,22 +247,43 @@ 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>();
|
||||
|
||||
const int endurance = getAttribute(ESM::Attribute::Endurance).getBase();
|
||||
|
||||
// "When you gain a level, in addition to increasing three primary attributes, your Health
|
||||
// will automatically increase by 10% of your Endurance attribute. If you increased Endurance this level,
|
||||
// the Health increase is calculated from the increased Endurance"
|
||||
mLevelHealthBonus += endurance * gmst.find("fLevelUpHealthEndMult")->getFloat();
|
||||
updateHealth();
|
||||
|
||||
setLevel(getLevel()+1);
|
||||
}
|
||||
|
||||
void MWMechanics::NpcStats::updateHealth()
|
||||
{
|
||||
const int endurance = getAttribute(ESM::Attribute::Endurance).getBase();
|
||||
const int strength = getAttribute(ESM::Attribute::Strength).getBase();
|
||||
|
||||
setHealth(static_cast<int> (0.5 * (strength + endurance)) + mLevelHealthBonus);
|
||||
}
|
||||
|
||||
int MWMechanics::NpcStats::getLevelupAttributeMultiplier(int attribute) const
|
||||
{
|
||||
// Source: http://www.uesp.net/wiki/Morrowind:Level#How_to_Level_Up
|
||||
int num = mSkillIncreases[attribute];
|
||||
if (num <= 1)
|
||||
|
||||
if (num == 0)
|
||||
return 1;
|
||||
else if (num <= 4)
|
||||
return 2;
|
||||
else if (num <= 7)
|
||||
return 3;
|
||||
else if (num <= 9)
|
||||
return 4;
|
||||
else
|
||||
return 5;
|
||||
|
||||
num = std::min(10, num);
|
||||
|
||||
// iLevelUp01Mult - iLevelUp10Mult
|
||||
std::stringstream gmst;
|
||||
gmst << "iLevelUp" << std::setfill('0') << std::setw(2) << num << "Mult";
|
||||
|
||||
return MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(gmst.str())->getInt();
|
||||
}
|
||||
|
||||
void MWMechanics::NpcStats::flagAsUsed (const std::string& id)
|
||||
|
|
|
@ -51,6 +51,8 @@ namespace MWMechanics
|
|||
/// time since last hit from drowning
|
||||
float mLastDrowningHit;
|
||||
|
||||
float mLevelHealthBonus;
|
||||
|
||||
public:
|
||||
|
||||
NpcStats();
|
||||
|
@ -98,6 +100,10 @@ namespace MWMechanics
|
|||
|
||||
void levelUp();
|
||||
|
||||
void updateHealth();
|
||||
///< Calculate health based on endurance and strength.
|
||||
/// Called at character creation and at level up.
|
||||
|
||||
void flagAsUsed (const std::string& id);
|
||||
|
||||
bool hasBeenUsed (const std::string& id) const;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue