Merge pull request #258 from OpenMW/master while resolving conflicts

# Conflicts:
#	.travis.yml
#	README.md
0.6.1
David Cernat 7 years ago
commit 721b218cc2

@ -12,8 +12,10 @@ branches:
- /openmw-.*$/
env:
global:
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
# via the "travis encrypt" command using the project repo's public key
- secure: NZmvVuA0O9NJXVQ12tXQZHDJC2mbFgYNFcsicw0DgW1It2Nk5hxIkF0pfu4/Z59mhQuOPgRVjl5b0FKy2Axh0gkWc1DJEXGwNaiW5lpTMNWR1LJG5rxa8LrDUpFkycpbzfAFuTUZu5z3iYVv64XzELvBuqNGhPMu1LeBnrlech0jFNjkR9p5qtJGWb8zYcPMCC57rig8a9g1ABoVYS6UXjrKpx0946ZLRsE5ukc9pXsypGwPmOMyfzZkxxzIqFaxoE5JIEdaJTWba/6Za315ozYYIi/N35ROI1YAv5GHRe/Iw9XAa4vQpbDzjM7ZSsZdTvvQsSU598gD2xC6jFUKSrpW6GZKwM2x236fZLGnOk5Uw7DUbG+AwpcEmxBwoy9PjBl9ZF3tJykI0gROewCy8MODhdsVMKr1HGIMVBIJySm/RnNqtoDbYV8mYnSl5b8rwJiCajoiR8Zuv4CIfGneeH1a3DOQDPH/qkDsU6ilzF4ANsBlMUUpgY653KBMBmTlNuVZSH527tnD7Fg6JgHVuSQkTbRa1vSkR7Zcre604RZcAoaEdbX3bhVDasPPghU/I742L0RH3oQNlR09pPBDZ8kG7ydl4aPHwpCWnvXNM1vgxtGvnYLztwrse7IoaRXRYiMFmrso78WhMWUDKgvY4wV9aeUu0DtnMezZVIQwCKg=
- macos_qt_formula=qt@5.7
- macos_qt_formula=qt
addons:
apt:
sources:

@ -50,6 +50,7 @@ Programmers
Edmondo Tommasina (edmondo)
Eduard Cot (trombonecot)
Eli2
elsid
Emanuel Guével (potatoesmaster)
eroen
escondida
@ -145,6 +146,7 @@ Programmers
t6
terrorfisch
Thomas Luppi (Digmaster)
Will Herrmann (Thunderforge)
Tom Mason (wheybags)
Torben Leif Carrington (TorbenC)
viadanna

@ -1,3 +1,82 @@
0.42.0
------
Bug #1956: Duplicate objects after loading the game, when a mod was edited
Bug #2100: Falling leaves in Vurt's Leafy West Gash II not rendered correctly
Bug #2116: Cant fit through some doorways pressed against staircases
Bug #2289: Some modal dialogs are not centered on the screen when the window resizes
Bug #2409: Softlock when pressing weapon/magic switch keys during chargen, afterwards switches weapons even though a text field is selected
Bug #2483: Previous/Next Weapon hotkeys triggered while typing the name of game save
Bug #2629: centeroncell, coc causes death / fall damage time to time when teleporting from high
Bug #2645: Cycling weapons is possible while console/pause menu is open
Bug #2678: Combat with water creatures do not end upon exiting water
Bug #2759: Light Problems in Therana's Chamber in Tel Branora
Bug #2771: unhandled sdl event of type 0x302
Bug #2777: (constant/on cast) disintegrate armor/weapon on self is seemingly not working
Bug #2838: Editor: '.' in a record name should be allowed
Bug #2909: NPCs appear floating when standing on a slope
Bug #3093: Controller movement cannot be used while mouse is moving
Bug #3134: Crash possible when using console with open container
Bug #3254: AI enemies hit between them.
Bug #3344: Editor: Verification results sorting by Type is not alphabetical.
Bug #3345: Editor: Cloned and added pathgrids are lost after reopen of saved omwgame file
Bug #3355: [MGSO] Physics maxing out in south cornerclub Balmora
Bug #3484: Editor: camera position is not set when changing cell via drag&drop
Bug #3508: Slowfall kills Jump momentum
Bug #3580: Crash: Error ElementBufferObject::remove BufferData<0> out of range
Bug #3581: NPCs wander too much
Bug #3601: Menu Titles not centered vertically
Bug #3607: [Mac OS] Beginning of NPC speech cut off (same issue as closed bug #3453)
Bug #3613: Can not map "next weapon" or "next spell" to controller
Bug #3617: Enchanted arrows don't explode when hitting the ground
Bug #3645: Unable to use steps in Vivec, Palace of Vivec
Bug #3650: Tamriel Rebuilt 16.09.1 Hist Cuirass GND nif is rendered inside a Pink Box
Bug #3652: Item icon shadows get stuck in the alchemy GUI
Bug #3653: Incorrect swish sounds
Bug #3666: NPC collision should not be disabled until death animation has finished
Bug #3669: Editor: Text field was missing from book object editing dialogue
Bug #3670: Unhandled SDL event of type 0x304
Bug #3671: Incorrect local variable value after picking up bittercup
Bug #3686: Travelling followers doesn't increase travel fee
Bug #3689: Problematic greetings from Antares Big Mod that override the appropriate ones.
Bug #3690: Certain summoned creatures do not engage in combat with underwater creatures
Bug #3691: Enemies do not initiate combat with player followers on sight
Bug #3695: [Regression] Dispel does not always dispel spell effects in 0.41
Bug #3699: Crash on MWWorld::ProjectileManager::moveMagicBolts
Bug #3700: Climbing on rocks and mountains
Bug #3704: Creatures don't auto-equip their shields on creation
Bug #3705: AI combat engagement logic differs from vanilla
Bug #3707: Animation playing does some very odd things if pc comes in contact with the animated mesh
Bug #3712: [Mod] Freeze upon entering Adanumuran with mod Adanumuran Reclaimed
Bug #3713: [Regression] Cancelling dialogue or using travel with creatures throws a (possibly game-breaking) exception
Bug #3719: Dropped identification papers can't be picked up again
Bug #3722: Command spell doesn't bring enemies out of combat
Bug #3727: Using "Activate" mid-script-execution invalidates interpreter context
Bug #3746: Editor: Book records show attribute IDs instead of skill IDs for teached skills entry.
Bug #3755: Followers stop following after loading from savegame
Bug #3772: ModStat lowers attribute to 100 if it was greater
Bug #3781: Guns in Clean Hunter Rifles mod use crossbow sounds
Bug #3797: NPC and creature names don't show up in combat when RMB windows are displayed
Bug #3800: Wrong tooltip maximum width
Bug #3801: Drowning widget is bugged
Bug #3802: BarterOffer shouldn't limit pcMercantile
Bug #3813: Some fatal error
Bug #3816: Expression parser thinks the -> token is unexpected when a given explicit refID clashes with a journal ID
Bug #3822: Custom added creatures are not animated
Feature #451: Water sounds
Feature #2691: Light particles sometimes not shown in inventory character preview
Feature #3523: Light source on magic projectiles
Feature #3644: Nif NiSphericalCollider Unknown Record Type
Feature #3675: ess-Importer: convert mark location
Feature #3693: ess-Importer: convert last known exterior cell
Feature #3748: Editor: Replace "Scroll" check box in Book records with "Book Type" combo box.
Feature #3751: Editor: Replace "Xyz Blood" check boxes in NPC and Creature records with "Blood Type" combo box
Feature #3752: Editor: Replace emitter check boxes in Light records with "Emitter Type" combo box
Feature #3756: Editor: Replace "Female" check box in NPC records with "Gender" combo box
Feature #3757: Editor: Replace "Female" check box in BodyPart records with "Gender" combo box
Task #3092: const version of ContainerStoreIterator
Task #3795: /deps folder not in .gitignore
0.41.0
------

@ -6,4 +6,4 @@ DATE=`date +'%d%m%Y'`
SHORT_COMMIT=`git rev-parse --short ${TRAVIS_COMMIT}`
TARGET_FILENAME="OpenMW-${DATE}-${SHORT_COMMIT}.dmg"
curl --ssl --ftp-create-dirs -T *.dmg -u $OSX_FTP_USER:$OSX_FTP_PASSWORD "ftp://s3.mydevil.net:21/nightly/${TARGET_FILENAME}"
curl --ssl --ftp-create-dirs -T *.dmg -u $OSX_FTP_USER:$OSX_FTP_PASSWORD "${OSX_FTP_URL}${TARGET_FILENAME}"

@ -25,7 +25,7 @@ endif()
message(STATUS "Configuring OpenMW...")
set(OPENMW_VERSION_MAJOR 0)
set(OPENMW_VERSION_MINOR 41)
set(OPENMW_VERSION_MINOR 42)
set(OPENMW_VERSION_RELEASE 0)
set(OPENMW_VERSION_COMMITHASH "")
@ -436,7 +436,7 @@ IF(NOT WIN32 AND NOT APPLE)
# Install icon and desktop file
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "openmw")
INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "${ICONDIR}" COMPONENT "openmw")
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.appdata.xml" DESTINATION "${DATAROOTDIR}/appdata" COMPONENT "openmw")
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.appdata.xml" DESTINATION "${DATAROOTDIR}/metainfo" COMPONENT "openmw")
IF(BUILD_OPENCS)
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "opencs")
INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/opencs/openmw-cs.png" DESTINATION "${ICONDIR}" COMPONENT "opencs")
@ -768,17 +768,19 @@ if (WIN32)
endif()
# Apple bundling
if (APPLE AND DESIRED_QT_VERSION MATCHES 5)
if (OPENMW_OSX_DEPLOYMENT AND APPLE AND DESIRED_QT_VERSION MATCHES 5)
get_property(QT_COCOA_PLUGIN_PATH TARGET Qt5::QCocoaIntegrationPlugin PROPERTY LOCATION_RELEASE)
get_filename_component(QT_COCOA_PLUGIN_DIR "${QT_COCOA_PLUGIN_PATH}" DIRECTORY)
get_filename_component(QT_COCOA_PLUGIN_GROUP "${QT_COCOA_PLUGIN_DIR}" NAME)
get_filename_component(QT_COCOA_PLUGIN_NAME "${QT_COCOA_PLUGIN_PATH}" NAME)
configure_file("${QT_COCOA_PLUGIN_PATH}" "${APP_BUNDLE_DIR}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}" COPYONLY)
configure_file("${QT_COCOA_PLUGIN_PATH}" "${APP_BUNDLE_DIR}/Contents/PlugIns/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}" COPYONLY)
configure_file("${OpenMW_SOURCE_DIR}/files/mac/qt.conf" "${APP_BUNDLE_DIR}/Contents/Resources/qt.conf" COPYONLY)
if (BUILD_OPENCS)
get_property(OPENCS_BUNDLE_NAME_TMP TARGET openmw-cs PROPERTY OUTPUT_NAME)
set(OPENCS_BUNDLE_NAME "${OPENCS_BUNDLE_NAME_TMP}.app")
configure_file("${QT_COCOA_PLUGIN_PATH}" "${OPENCS_BUNDLE_NAME}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}" COPYONLY)
configure_file("${QT_COCOA_PLUGIN_PATH}" "${OPENCS_BUNDLE_NAME}/Contents/PlugIns/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}" COPYONLY)
configure_file("${OpenMW_SOURCE_DIR}/files/mac/qt.conf" "${OPENCS_BUNDLE_NAME}/Contents/Resources/qt.conf" COPYONLY)
endif ()
install(DIRECTORY "${APP_BUNDLE_DIR}" USE_SOURCE_PERMISSIONS DESTINATION "." COMPONENT Runtime)
@ -837,8 +839,8 @@ if (APPLE AND DESIRED_QT_VERSION MATCHES 5)
install_plugins_for_bundle("${APP_BUNDLE_NAME}" PLUGINS)
install_plugins_for_bundle("${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS)
set(PLUGINS ${PLUGINS} "${INSTALLED_OPENMW_APP}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}")
set(OPENCS_PLUGINS ${OPENCS_PLUGINS} "${INSTALLED_OPENCS_APP}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}")
set(PLUGINS ${PLUGINS} "${INSTALLED_OPENMW_APP}/Contents/PlugIns/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}")
set(OPENCS_PLUGINS ${OPENCS_PLUGINS} "${INSTALLED_OPENCS_APP}/Contents/PlugIns/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}")
install(CODE "
function(gp_item_default_embedded_path_override item default_embedded_path_var)
@ -848,12 +850,11 @@ if (APPLE AND DESIRED_QT_VERSION MATCHES 5)
endif()
endfunction()
cmake_policy(SET CMP0009 OLD)
fixup_bundle(\"${INSTALLED_OPENMW_APP}\" \"${PLUGINS}\" \"\")
fixup_bundle(\"${INSTALLED_OPENCS_APP}\" \"${OPENCS_PLUGINS}\" \"\")
" COMPONENT Runtime)
include(CPack)
endif (APPLE AND DESIRED_QT_VERSION MATCHES 5)
endif ()
# Doxygen Target -- simply run 'make doc' or 'make doc_pages'
# output directory for 'make doc' is "${OpenMW_BINARY_DIR}/docs/Doxygen"

@ -33,3 +33,38 @@ Furthermore, we advise to:
* Feel free to submit incomplete pull requests. Even if the work can not be merged yet, pull requests are a great place to collect early feedback. Just make sure to mark it as *[Incomplete]* or *[Do not merge yet]* in the title.
* If you plan on contributing often, please read the [Developer Reference](https://wiki.openmw.org/index.php?title=Developer_Reference) on our wiki, especially the [Policies and Standards](https://wiki.openmw.org/index.php?title=Policies_and_Standards).
* Make sure each of your changes has a clear objective. Unnecessary changes may lead to merge conflicts, clutter the commit history and slow down review. Code formatting 'fixes' should be avoided, unless you were already changing that particular line anyway.
Guidelines for original engine "fixes"
=================================
From time to time you may be tempted to "fix" what you think was a "bug" in the original game engine.
Unfortunately, the definition of what is a "bug" is not so clear. Consider that your "bug" is actually a feature unless proven otherwise:
* We have no way of knowing what the original developers really intended (short of asking them, good luck with that).
* What may seem like an illogical mechanic can actually be part of an attempt to balance the game.
* Many people will actually <i>like</i> these "bugs" because that is what they remember the game for.
* Exploits may be part of the fun of an open-world game - they reward knowledge with power. There are too many of them to plug them all, anyway.
OpenMW, in its default configuration, is meant to be a faithful reimplementation of Morrowind, minus things like crash bugs, stability issues and design errors. However, we try to avoid touching anything that affects the core gameplay, the balancing of the game or introduces incompatibilities with existing mod content.
That said, we may sometimes evaluate such issues on an individual basis. Common exceptions to the above would be:
* Issues so glaring that they would severely limit the capabilities of the engine in the future (for example, the scripting engine not being allowed to access objects in remote cells)
* Bugs where the intent is very obvious, and that have little to no balancing impact (e.g. the bug were being tired made it easier to repair items, instead of harder)
* Bugs that were fixed in an official patch for Morrowind
Feature additions policy
=====================
We get it, you have waited so long for feature XYZ to be available in Morrowind and now that OpenMW is here you can not wait to implement your ingenious idea and share it with the world.
Unfortunately, since maintaining features comes at a cost and our resources are limited, we have to be a little selective in what features we allow into the main repository. Generally:
- Features should be as generic and non-redundant as possible.
- Any feature that is also possible with modding should be done as a mod instead.
- In the future, OpenMW plans to expand the scope of what is possible with modding, e.g. by moving certain game logic into editable scripts.
- Currently, modders can edit OpenMW's GUI skins and layout XML files, although there are still a few missing hooks (e.g. scripting support) in order to make this into a powerful way of modding.
- If a feature introduces new game UI strings, that reduces its chance of being accepted because we do not currently have any way of localizing these to the user's Morrowind installation language.
If you are in doubt of your feature being within our scope, it is probably best to start a forum discussion first. See the [settings documentation](https://openmw.readthedocs.io/en/stable/reference/modding/settings/index.html) and [Features list](https://wiki.openmw.org/index.php?title=Features) for some examples of features that were deemed acceptable.

@ -81,10 +81,10 @@ add_openmw_dir (mwclass
add_openmw_dir (mwmechanics
mechanicsmanagerimp stat creaturestats magiceffects movement actorutil
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aibreathe
aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting
disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning
character actors objects aistate coordinateconverter trading aiface
character actors objects aistate coordinateconverter trading aiface weaponpriority spellpriority
)
add_openmw_dir (mwstate

@ -334,7 +334,7 @@ namespace MWGui
{
ensureSelectedItemUnequipped(count);
const ItemStack& item = mTradeModel->getItem(mSelectedItem);
std::string sound = item.mBase.getClass().getDownSoundId(item.mBase);
std::string sound = item.mBase.getClass().getUpSoundId(item.mBase);
MWBase::Environment::get().getWindowManager()->playSound(sound);
if (item.mType == ItemStack::Type_Barter)

@ -58,6 +58,7 @@ namespace
Book mTopicIndexBook;
bool mQuestMode;
bool mOptionsMode;
bool mTopicsMode;
bool mAllQuests;
template <typename T>
@ -196,6 +197,7 @@ namespace
mQuestMode = false;
mAllQuests = false;
mOptionsMode = false;
mTopicsMode = false;
}
void adjustButton (char const * name)
@ -259,6 +261,7 @@ namespace
void setBookMode ()
{
mOptionsMode = false;
mTopicsMode = false;
setVisible (OptionsBTN, true);
setVisible (OptionsOverlay, false);
@ -269,6 +272,7 @@ namespace
void setOptionsMode ()
{
mOptionsMode = true;
mTopicsMode = false;
setVisible (OptionsBTN, false);
setVisible (OptionsOverlay, true);
@ -292,6 +296,8 @@ namespace
// If in quest mode, ensure the quest list is updated
if (mQuestMode)
notifyQuests(getWidget<MyGUI::Widget>(QuestsList));
else
notifyTopics(getWidget<MyGUI::Widget>(TopicsList));
}
void pushBook (Book book, unsigned int page)
@ -370,6 +376,9 @@ namespace
setVisible (JournalBTN, true);
mOptionsMode = false;
mTopicsMode = false;
MWBase::Environment::get().getWindowManager()->playSound("book page");
}
void notifyTopicSelected (const std::string& topic, int id)
@ -399,6 +408,8 @@ namespace
setVisible (JournalBTN, true);
mOptionsMode = false;
MWBase::Environment::get().getWindowManager()->playSound("book page");
}
void notifyOptions(MyGUI::Widget* _sender)
@ -416,6 +427,8 @@ namespace
{
assert (mStates.size () > 1);
popBook ();
MWBase::Environment::get().getWindowManager()->playSound("book page");
}
void notifyIndexLinkClicked (MWGui::TypesetBook::InteractiveId character)
@ -424,6 +437,8 @@ namespace
setVisible (RightTopicIndex, false);
setVisible (TopicsList, true);
mTopicsMode = true;
Gui::MWList* list = getWidget<Gui::MWList>(TopicsList);
list->clear();
@ -432,17 +447,22 @@ namespace
mModel->visitTopicNamesStartingWith((char) character, add);
list->adjustSize();
MWBase::Environment::get().getWindowManager()->playSound("book page");
}
void notifyTopics(MyGUI::Widget* _sender)
{
mQuestMode = false;
mTopicsMode = false;
setVisible (LeftTopicIndex, true);
setVisible (RightTopicIndex, true);
setVisible (TopicsList, false);
setVisible (QuestsList, false);
setVisible (ShowAllBTN, false);
setVisible (ShowActiveBTN, false);
MWBase::Environment::get().getWindowManager()->playSound("book page");
}
struct AddNamesToList
@ -494,6 +514,8 @@ namespace
SetNamesInactive setInactive(list);
mModel->visitQuestNames(!mAllQuests, setInactive);
}
MWBase::Environment::get().getWindowManager()->playSound("book page");
}
void notifyShowAll(MyGUI::Widget* _sender)
@ -510,7 +532,16 @@ namespace
void notifyCancel(MyGUI::Widget* _sender)
{
setBookMode ();
if (mTopicsMode)
{
notifyTopics(_sender);
}
else
{
setBookMode();
MWBase::Environment::get().getWindowManager()->playSound("book page");
}
}
void notifyClose(MyGUI::Widget* _sender)
@ -539,6 +570,8 @@ namespace
if (page+2 < book->pageCount())
{
MWBase::Environment::get().getWindowManager()->playSound("book page");
page += 2;
updateShowingPages ();
}
@ -555,6 +588,8 @@ namespace
if(page >= 2)
{
MWBase::Environment::get().getWindowManager()->playSound("book page");
page -= 2;
updateShowingPages ();
}

@ -33,7 +33,6 @@ namespace MWGui
SpellBuyingWindow::SpellBuyingWindow() :
WindowBase("openmw_spell_buying_window.layout")
, mLastPos(0)
, mCurrentY(0)
{
getWidget(mCancelButton, "CancelButton");
@ -48,13 +47,20 @@ namespace MWGui
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_SpellBuying);
}
void SpellBuyingWindow::addSpell(const std::string& spellId)
bool SpellBuyingWindow::sortSpells (const ESM::Spell* left, const ESM::Spell* right)
{
std::string leftName = Misc::StringUtils::lowerCase(left->mName);
std::string rightName = Misc::StringUtils::lowerCase(right->mName);
return leftName.compare(rightName) < 0;
}
void SpellBuyingWindow::addSpell(const ESM::Spell& spell)
{
const MWWorld::ESMStore &store =
MWBase::Environment::get().getWorld()->getStore();
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(spellId);
int price = static_cast<int>(spell->mData.mCost*store.get<ESM::GameSetting>().find("fSpellValueMult")->getFloat());
int price = static_cast<int>(spell.mData.mCost*store.get<ESM::GameSetting>().find("fSpellValueMult")->getFloat());
price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true);
MWWorld::Ptr player = MWMechanics::getPlayer();
@ -75,13 +81,13 @@ namespace MWGui
mCurrentY += sLineHeight;
toAdd->setUserData(price);
toAdd->setCaptionWithReplacing(spell->mName+" - "+MyGUI::utility::toString(price)+"#{sgp}");
toAdd->setCaptionWithReplacing(spell.mName+" - "+MyGUI::utility::toString(price)+"#{sgp}");
toAdd->setSize(mSpellsView->getWidth(),sLineHeight);
toAdd->eventMouseWheel += MyGUI::newDelegate(this, &SpellBuyingWindow::onMouseWheel);
toAdd->setUserString("ToolTipType", "Spell");
toAdd->setUserString("Spell", spellId);
toAdd->setUserString("Spell", spell.mId);
toAdd->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellBuyingWindow::onSpellButtonClick);
mSpellsWidgetMap.insert(std::make_pair (toAdd, spellId));
mSpellsWidgetMap.insert(std::make_pair (toAdd, spell.mId));
}
void SpellBuyingWindow::clearSpells()
@ -93,7 +99,7 @@ namespace MWGui
mSpellsWidgetMap.clear();
}
void SpellBuyingWindow::startSpellBuying(const MWWorld::Ptr& actor)
void SpellBuyingWindow::startSpellBuying(const MWWorld::Ptr& actor, int startOffset)
{
center();
mPtr = actor;
@ -101,6 +107,8 @@ namespace MWGui
MWMechanics::Spells& merchantSpells = actor.getClass().getCreatureStats (actor).getSpells();
std::vector<const ESM::Spell*> spellsToSort;
for (MWMechanics::Spells::TIterator iter = merchantSpells.begin(); iter!=merchantSpells.end(); ++iter)
{
const ESM::Spell* spell = iter->first;
@ -120,15 +128,25 @@ namespace MWGui
if (playerHasSpell(iter->first->mId))
continue;
addSpell (iter->first->mId);
spellsToSort.push_back(iter->first);
}
std::stable_sort(spellsToSort.begin(), spellsToSort.end(), sortSpells);
for (std::vector<const ESM::Spell*>::iterator it = spellsToSort.begin() ; it != spellsToSort.end(); ++it)
{
addSpell(**it);
}
spellsToSort.clear();
updateLabels();
// Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden
mSpellsView->setVisibleVScroll(false);
mSpellsView->setCanvasSize (MyGUI::IntSize(mSpellsView->getWidth(), std::max(mSpellsView->getHeight(), mCurrentY)));
mSpellsView->setVisibleVScroll(true);
mSpellsView->setViewOffset(MyGUI::IntPoint(0, startOffset));
}
bool SpellBuyingWindow::playerHasSpell(const std::string &id)
@ -165,7 +183,7 @@ namespace MWGui
MWMechanics::CreatureStats& npcStats = mPtr.getClass().getCreatureStats(mPtr);
npcStats.setGoldPool(npcStats.getGoldPool() + price);
startSpellBuying(mPtr);
startSpellBuying(mPtr, mSpellsView->getViewOffset().top);
MWBase::Environment::get().getWindowManager()->playSound("Item Gold Up");
}

@ -4,6 +4,8 @@
#include "windowbase.hpp"
#include "referenceinterface.hpp"
#include "../mwworld/esmstore.hpp"
namespace MyGUI
{
class Gui;
@ -23,7 +25,7 @@ namespace MWGui
public:
SpellBuyingWindow();
void startSpellBuying(const MWWorld::Ptr& actor);
void startSpellBuying(const MWWorld::Ptr& actor, int startOffset);
virtual void exit();
@ -38,7 +40,7 @@ namespace MWGui
void onCancelButtonClicked(MyGUI::Widget* _sender);
void onSpellButtonClick(MyGUI::Widget* _sender);
void onMouseWheel(MyGUI::Widget* _sender, int _rel);
void addSpell(const std::string& spellID);
void addSpell(const ESM::Spell& spell);
void clearSpells();
int mLastPos,mCurrentY;
@ -49,6 +51,9 @@ namespace MWGui
virtual void onReferenceUnavailable();
bool playerHasSpell (const std::string& id);
private:
static bool sortSpells (const ESM::Spell* left, const ESM::Spell* right);
};
}

@ -473,22 +473,11 @@ namespace MWGui
for (std::vector<ESM::ENAMstruct>::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it)
{
float x = 0.5f * (it->mMagnMin + it->mMagnMax);
const ESM::ENAMstruct& effect = *it;
const ESM::MagicEffect* effect =
store.get<ESM::MagicEffect>().find(it->mEffectID);
y += std::max(1.f, MWMechanics::calcEffectCost(effect));
x *= 0.1f * effect->mData.mBaseCost;
x *= 1 + it->mDuration;
x += 0.05f * std::max(1, it->mArea) * effect->mData.mBaseCost;
float fEffectCostMult =
store.get<ESM::GameSetting>().find("fEffectCostMult")->getFloat();
y += x * fEffectCostMult;
y = std::max(1.f,y);
if (it->mRange == ESM::RT_Target)
if (effect.mRange == ESM::RT_Target)
y *= 1.5;
}
@ -508,8 +497,10 @@ namespace MWGui
mPriceLabel->setCaption(MyGUI::utility::toString(int(price)));
float chance = MWMechanics::getSpellSuccessChance(&mSpell, MWMechanics::getPlayer());
mSuccessChance->setCaption(MyGUI::utility::toString(int(chance)));
float chance = MWMechanics::calcSpellBaseSuccessChance(&mSpell, MWMechanics::getPlayer(), NULL);
int intChance = std::min(100, int(chance));
mSuccessChance->setCaption(MyGUI::utility::toString(intChance));
}
// ------------------------------------------------------------------------------------------------

@ -122,8 +122,6 @@ namespace MWGui
mCurrentBalance = 0;
mCurrentMerchantOffer = 0;
restock();
std::vector<MWWorld::Ptr> itemSources;
MWBase::Environment::get().getWorld()->getContainersOwnedBy(actor, itemSources);
@ -209,7 +207,7 @@ namespace MWGui
void TradeWindow::sellItem(MyGUI::Widget* sender, int count)
{
const ItemStack& item = mTradeModel->getItem(mItemToSell);
std::string sound = item.mBase.getClass().getDownSoundId(item.mBase);
std::string sound = item.mBase.getClass().getUpSoundId(item.mBase);
MWBase::Environment::get().getWindowManager()->playSound(sound);
TradeItemModel* playerTradeModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getTradeModel();
@ -357,6 +355,8 @@ namespace MWGui
MWBase::Environment::get().getWindowManager()->playSound("Item Gold Up");
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter);
restock();
}
void TradeWindow::onCancelButtonClicked(MyGUI::Widget* _sender)

@ -2072,7 +2072,7 @@ namespace MWGui
void WindowManager::startSpellBuying(const MWWorld::Ptr &actor)
{
pushGuiMode(GM_SpellBuying);
mSpellBuyingWindow->startSpellBuying(actor);
mSpellBuyingWindow->startSpellBuying(actor, 0);
}
void WindowManager::startTrade(const MWWorld::Ptr &actor)

@ -42,6 +42,8 @@
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/statemanager.hpp"
#include "../mwmechanics/aibreathe.hpp"
#include "spellcasting.hpp"
#include "npcstats.hpp"
#include "creaturestats.hpp"
@ -863,6 +865,15 @@ namespace MWMechanics
if (stats.getTimeToStartDrowning() == -1.f)
stats.setTimeToStartDrowning(fHoldBreathTime);
if (ptr.getClass().isNpc() && stats.getTimeToStartDrowning() < fHoldBreathTime / 2)
{
if(ptr != MWMechanics::getPlayer() ) {
MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence();
if(seq.getTypeId() != MWMechanics::AiPackage::TypeIdBreathe) //Only add it once
seq.stack(MWMechanics::AiBreathe(), ptr);
}
}
MWBase::World *world = MWBase::Environment::get().getWorld();
bool knockedOutUnderwater = (ctrl->isKnockedOut() && world->isUnderwater(ptr.getCell(), osg::Vec3f(ptr.getRefData().getPosition().asVec3())));
if((world->isSubmerged(ptr) || knockedOutUnderwater)
@ -1625,6 +1636,11 @@ namespace MWMechanics
calculateCreatureStatModifiers (iter->first, duration);
if (iter->first.getClass().isNpc())
calculateNpcStatModifiers(iter->first, duration);
MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(iter->first);
if (animation)
animation->updateEffects(duration);
}
fastForwardAi();

@ -0,0 +1,54 @@
#include "aibreathe.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/esmstore.hpp"
#include "npcstats.hpp"
#include "movement.hpp"
#include "steering.hpp"
MWMechanics::AiBreathe::AiBreathe()
: AiPackage()
{
}
bool MWMechanics::AiBreathe::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
{
static const float fHoldBreathTime = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fHoldBreathTime")->getFloat();
const MWWorld::Class& actorClass = actor.getClass();
if (actorClass.isNpc())
{
if (actorClass.getNpcStats(actor).getTimeToStartDrowning() < fHoldBreathTime / 2)
{
actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
smoothTurn(actor, -180, 0);
return false;
}
}
return true;
}
MWMechanics::AiBreathe *MWMechanics::AiBreathe::clone() const
{
return new AiBreathe(*this);
}
int MWMechanics::AiBreathe::getTypeId() const
{
return TypeIdBreathe;
}
unsigned int MWMechanics::AiBreathe::getPriority() const
{
return 2;
}

@ -0,0 +1,28 @@
#ifndef GAME_MWMECHANICS_AIBREATHE_H
#define GAME_MWMECHANICS_AIBREATHE_H
#include "aipackage.hpp"
namespace MWMechanics
{
/// \brief AiPackage to have an actor resurface to breathe
// The AI will go up if lesser than half breath left
class AiBreathe : public AiPackage
{
public:
AiBreathe();
virtual AiBreathe *clone() const;
virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration);
virtual int getTypeId() const;
virtual unsigned int getPriority() const;
virtual bool canCancel() const { return false; }
virtual bool shouldCancelPreviousAi() const { return false; }
};
}
#endif

@ -603,6 +603,10 @@ namespace MWMechanics
// opponent's weapon range, or not backing up if opponent is also using a ranged weapon
if (isDistantCombat && distToTarget < rangeAttack / 4)
{
// actor should not back up into water
if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(actor), 0.5f))
return;
mMovement.mPosition[1] = -1;
}
}

@ -16,607 +16,25 @@
#include "npcstats.hpp"
#include "spellcasting.hpp"
#include "combat.hpp"
namespace
{
// RangeTypes using bitflags to allow multiple range types, as can be the case with spells having multiple effects.
enum RangeTypes
{
Self = 0x1,
Touch = 0x10,
Target = 0x100
};
int getRangeTypes (const ESM::EffectList& effects)
{
int types = 0;
for (std::vector<ESM::ENAMstruct>::const_iterator it = effects.mList.begin(); it != effects.mList.end(); ++it)
{
if (it->mRange == ESM::RT_Self)
types |= Self;
else if (it->mRange == ESM::RT_Touch)
types |= Touch;
else if (it->mRange == ESM::RT_Target)
types |= Target;
}
return types;
}
float suggestCombatRange(int rangeTypes)
{
static const float fCombatDistance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fCombatDistance")->getFloat();
static float fHandToHandReach = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fHandToHandReach")->getFloat();
// This distance is a possible distance of melee attack
static float distance = fCombatDistance * std::max(2.f, fHandToHandReach);
if (rangeTypes & Touch)
{
return fCombatDistance;
}
return distance * 4;
}
int numEffectsToDispel (const MWWorld::Ptr& actor, int effectFilter=-1, bool negative = true)
{
int toCure=0;
const MWMechanics::ActiveSpells& activeSpells = actor.getClass().getCreatureStats(actor).getActiveSpells();
for (MWMechanics::ActiveSpells::TIterator it = activeSpells.begin(); it != activeSpells.end(); ++it)
{
const MWMechanics::ActiveSpells::ActiveSpellParams& params = it->second;
for (std::vector<MWMechanics::ActiveSpells::ActiveEffect>::const_iterator effectIt = params.mEffects.begin();
effectIt != params.mEffects.end(); ++effectIt)
{
int effectId = effectIt->mEffectId;
if (effectFilter != -1 && effectId != effectFilter)
continue;
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effectId);
if (effectIt->mDuration <= 3) // Don't attempt to dispel if effect runs out shortly anyway
continue;
if (negative && magicEffect->mData.mFlags & ESM::MagicEffect::Harmful)
++toCure;
if (!negative && !(magicEffect->mData.mFlags & ESM::MagicEffect::Harmful))
++toCure;
}
}
return toCure;
}
}
#include "weaponpriority.hpp"
#include "spellpriority.hpp"
namespace MWMechanics
{
float ratePotion (const MWWorld::Ptr &item, const MWWorld::Ptr& actor)
float suggestCombatRange(int rangeTypes)
{
if (item.getTypeName() != typeid(ESM::Potion).name())
return 0.f;
const ESM::Potion* potion = item.get<ESM::Potion>()->mBase;
return rateEffects(potion->mEffects, actor, MWWorld::Ptr());
}
float rateWeapon (const MWWorld::Ptr &item, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy, int type,
float arrowRating, float boltRating)
{
if (item.getTypeName() != typeid(ESM::Weapon).name())
return 0.f;
const ESM::Weapon* weapon = item.get<ESM::Weapon>()->mBase;
if (type != -1 && weapon->mData.mType != type)
return 0.f;
float rating=0.f;
float bonus=0.f;
if (weapon->mData.mType >= ESM::Weapon::MarksmanBow && weapon->mData.mType <= ESM::Weapon::MarksmanThrown)
bonus+=1.5f;
if (weapon->mData.mType >= ESM::Weapon::MarksmanBow)
{
rating = (weapon->mData.mChop[0] + weapon->mData.mChop[1]) / 2.f;
}
else
{
for (int i=0; i<2; ++i)
{
rating += weapon->mData.mSlash[i];
rating += weapon->mData.mThrust[i];
rating += weapon->mData.mChop[i];
}
rating /= 6.f;
}
if (item.getClass().hasItemHealth(item))
{
if (item.getClass().getItemHealth(item) == 0)
return 0.f;
rating *= item.getClass().getItemHealth(item) / float(item.getClass().getItemMaxHealth(item));
}
if (weapon->mData.mType == ESM::Weapon::MarksmanBow)
{
if (arrowRating <= 0.f)
rating = 0.f;
else
rating += arrowRating;
}
else if (weapon->mData.mType == ESM::Weapon::MarksmanCrossbow)
{
if (boltRating <= 0.f)
rating = 0.f;
else
rating += boltRating;
}
if (!weapon->mEnchant.empty())
{
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find(weapon->mEnchant);
if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes
&& (item.getCellRef().getEnchantmentCharge() == -1
|| item.getCellRef().getEnchantmentCharge() >= enchantment->mData.mCost))
rating += rateEffects(enchantment->mEffects, actor, enemy);
}
int skill = item.getClass().getEquipmentSkill(item);
if (skill != -1)
rating *= actor.getClass().getSkill(actor, skill) / 100.f;
return rating + bonus;
}
float rateSpell(const ESM::Spell *spell, const MWWorld::Ptr &actor, const MWWorld::Ptr& enemy)
{
const CreatureStats& stats = actor.getClass().getCreatureStats(actor);
float successChance = MWMechanics::getSpellSuccessChance(spell, actor);
if (successChance == 0.f)
return 0.f;
if (spell->mData.mType != ESM::Spell::ST_Spell)
return 0.f;
// Don't make use of racial bonus spells, like MW. Can be made optional later
if (actor.getClass().isNpc())
{
std::string raceid = actor.get<ESM::NPC>()->mBase->mRace;
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(raceid);
if (race->mPowers.exists(spell->mId))
return 0.f;
}
if (spell->mData.mCost > stats.getMagicka().getCurrent())
return 0.f;
// Spells don't stack, so early out if the spell is still active on the target
int types = getRangeTypes(spell->mEffects);
if ((types & Self) && stats.getActiveSpells().isSpellActive(spell->mId))
return 0.f;
if ( ((types & Touch) || (types & Target)) && enemy.getClass().getCreatureStats(enemy).getActiveSpells().isSpellActive(spell->mId))
return 0.f;
return rateEffects(spell->mEffects, actor, enemy) * (successChance / 100.f);
}
float rateMagicItem(const MWWorld::Ptr &ptr, const MWWorld::Ptr &actor, const MWWorld::Ptr& enemy)
{
if (ptr.getClass().getEnchantment(ptr).empty())
return 0.f;
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find(ptr.getClass().getEnchantment(ptr));
if (enchantment->mData.mType == ESM::Enchantment::CastOnce)
{
return rateEffects(enchantment->mEffects, actor, enemy);
}
else
{
//if (!ptr.getClass().canBeEquipped(ptr, actor))
return 0.f;
}
}
float rateEffect(const ESM::ENAMstruct &effect, const MWWorld::Ptr &actor, const MWWorld::Ptr &enemy)
{
// NOTE: enemy may be empty
float rating = 1;
switch (effect.mEffectID)
{
case ESM::MagicEffect::Soultrap:
case ESM::MagicEffect::AlmsiviIntervention:
case ESM::MagicEffect::DivineIntervention:
case ESM::MagicEffect::CalmHumanoid:
case ESM::MagicEffect::CalmCreature:
case ESM::MagicEffect::FrenzyHumanoid:
case ESM::MagicEffect::FrenzyCreature:
case ESM::MagicEffect::DemoralizeHumanoid:
case ESM::MagicEffect::DemoralizeCreature:
case ESM::MagicEffect::RallyHumanoid:
case ESM::MagicEffect::RallyCreature:
case ESM::MagicEffect::Charm:
case ESM::MagicEffect::DetectAnimal:
case ESM::MagicEffect::DetectEnchantment:
case ESM::MagicEffect::DetectKey:
case ESM::MagicEffect::Telekinesis:
case ESM::MagicEffect::Mark:
case ESM::MagicEffect::Recall:
case ESM::MagicEffect::Jump:
case ESM::MagicEffect::WaterBreathing:
case ESM::MagicEffect::SwiftSwim:
case ESM::MagicEffect::WaterWalking:
case ESM::MagicEffect::SlowFall:
case ESM::MagicEffect::Light:
case ESM::MagicEffect::Lock:
case ESM::MagicEffect::Open:
case ESM::MagicEffect::TurnUndead:
case ESM::MagicEffect::WeaknessToCommonDisease:
case ESM::MagicEffect::WeaknessToBlightDisease:
case ESM::MagicEffect::WeaknessToCorprusDisease:
case ESM::MagicEffect::CureCommonDisease:
case ESM::MagicEffect::CureBlightDisease:
case ESM::MagicEffect::CureCorprusDisease:
case ESM::MagicEffect::ResistBlightDisease:
case ESM::MagicEffect::ResistCommonDisease:
case ESM::MagicEffect::ResistCorprusDisease:
case ESM::MagicEffect::Invisibility:
case ESM::MagicEffect::Chameleon:
case ESM::MagicEffect::NightEye:
case ESM::MagicEffect::Vampirism:
case ESM::MagicEffect::StuntedMagicka:
case ESM::MagicEffect::ExtraSpell:
case ESM::MagicEffect::RemoveCurse:
case ESM::MagicEffect::CommandCreature:
case ESM::MagicEffect::CommandHumanoid:
return 0.f;
case ESM::MagicEffect::Sound:
{
if (enemy.isEmpty())
return 0.f;
// there is no need to cast sound if enemy is not able to cast spells
CreatureStats& stats = enemy.getClass().getCreatureStats(enemy);
if (stats.getMagicEffects().get(ESM::MagicEffect::Silence).getMagnitude() > 0)
return 0.f;
if (stats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0)
return 0.f;
break;
}
case ESM::MagicEffect::RestoreAttribute:
return 0.f; // TODO: implement based on attribute damage
case ESM::MagicEffect::RestoreSkill:
return 0.f; // TODO: implement based on skill damage
case ESM::MagicEffect::ResistFire:
case ESM::MagicEffect::ResistFrost:
case ESM::MagicEffect::ResistMagicka:
case ESM::MagicEffect::ResistNormalWeapons:
case ESM::MagicEffect::ResistParalysis:
case ESM::MagicEffect::ResistPoison:
case ESM::MagicEffect::ResistShock:
case ESM::MagicEffect::SpellAbsorption:
case ESM::MagicEffect::Reflect:
return 0.f; // probably useless since we don't know in advance what the enemy will cast
// don't cast these for now as they would make the NPC cast the same effect over and over again, especially when they have potions
case ESM::MagicEffect::FortifyAttribute:
case ESM::MagicEffect::FortifyHealth:
case ESM::MagicEffect::FortifyMagicka:
case ESM::MagicEffect::FortifyFatigue:
case ESM::MagicEffect::FortifySkill:
case ESM::MagicEffect::FortifyMaximumMagicka:
case ESM::MagicEffect::FortifyAttack:
return 0.f;
case ESM::MagicEffect::Burden:
{
if (enemy.isEmpty())
return 0.f;
// Ignore enemy without inventory
if (!enemy.getClass().hasInventoryStore(enemy))
return 0.f;
// burden makes sense only to overburden an enemy
float burden = enemy.getClass().getEncumbrance(enemy) - enemy.getClass().getCapacity(enemy);
if (burden > 0)
return 0.f;
if ((effect.mMagnMin + effect.mMagnMax)/2.f > -burden)
rating *= 3;
else
return 0.f;
break;
}
case ESM::MagicEffect::Feather:
{
// Ignore actors without inventory
if (!actor.getClass().hasInventoryStore(actor))
return 0.f;
// feather makes sense only for overburden actors
float burden = actor.getClass().getEncumbrance(actor) - actor.getClass().getCapacity(actor);
if (burden <= 0)
return 0.f;
if ((effect.mMagnMin + effect.mMagnMax)/2.f >= burden)
rating *= 3;
else
return 0.f;
break;
}
case ESM::MagicEffect::Levitate:
return 0.f; // AI isn't designed to take advantage of this, and could be perceived as unfair anyway
case ESM::MagicEffect::BoundBoots:
case ESM::MagicEffect::BoundHelm:
if (actor.getClass().isNpc())
{
// Beast races can't wear helmets or boots
std::string raceid = actor.get<ESM::NPC>()->mBase->mRace;
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(raceid);
if (race->mData.mFlags & ESM::Race::Beast)
return 0.f;
}
// Intended fall-through
// Creatures can not wear armor
case ESM::MagicEffect::BoundCuirass:
case ESM::MagicEffect::BoundGloves:
if (!actor.getClass().isNpc())
return 0.f;
break;
case ESM::MagicEffect::RestoreHealth:
case ESM::MagicEffect::RestoreMagicka:
case ESM::MagicEffect::RestoreFatigue:
if (effect.mRange == ESM::RT_Self)
{
int priority = 1;
if (effect.mEffectID == ESM::MagicEffect::RestoreHealth)
priority = 10;
const DynamicStat<float>& current = actor.getClass().getCreatureStats(actor).
getDynamic(effect.mEffectID - ESM::MagicEffect::RestoreHealth);
float toHeal = (effect.mMagnMin + effect.mMagnMax)/2.f * effect.mDuration;
// Effect doesn't heal more than we need, *or* we are below 1/2 health
if (current.getModified() - current.getCurrent() > toHeal
|| current.getCurrent() < current.getModified()*0.5)
{
return 10000.f * priority
- (toHeal - (current.getModified()-current.getCurrent())); // prefer the most fitting potion
}
else
return -10000.f * priority; // Save for later
}
break;
case ESM::MagicEffect::Dispel:
{
int numPositive = 0;
int numNegative = 0;
int diff = 0;
if (effect.mRange == ESM::RT_Self)
{
numPositive = numEffectsToDispel(actor, -1, false);
numNegative = numEffectsToDispel(actor);
diff = numNegative - numPositive;
}
else
{
if (enemy.isEmpty())
return 0.f;
numPositive = numEffectsToDispel(enemy, -1, false);
numNegative = numEffectsToDispel(enemy);
diff = numPositive - numNegative;
// if rating < 0 here, the spell will be considered as negative later
rating *= -1;
}
if (diff <= 0)
return 0.f;
rating *= (diff) / 5.f;
break;
}
// Prefer Cure effects over Dispel, because Dispel also removes positive effects
case ESM::MagicEffect::CureParalyzation:
return 1001.f * numEffectsToDispel(actor, ESM::MagicEffect::Paralyze);
case ESM::MagicEffect::CurePoison:
return 1001.f * numEffectsToDispel(actor, ESM::MagicEffect::Poison);
case ESM::MagicEffect::DisintegrateArmor:
{
if (enemy.isEmpty())
return 0.f;
// Ignore enemy without inventory
if (!enemy.getClass().hasInventoryStore(enemy))
return 0.f;
MWWorld::InventoryStore& inv = enemy.getClass().getInventoryStore(enemy);
// According to UESP
static const int armorSlots[] = {
MWWorld::InventoryStore::Slot_CarriedLeft,
MWWorld::InventoryStore::Slot_Cuirass,
MWWorld::InventoryStore::Slot_LeftPauldron,
MWWorld::InventoryStore::Slot_RightPauldron,
MWWorld::InventoryStore::Slot_LeftGauntlet,
MWWorld::InventoryStore::Slot_RightGauntlet,
MWWorld::InventoryStore::Slot_Helmet,
MWWorld::InventoryStore::Slot_Greaves,
MWWorld::InventoryStore::Slot_Boots
};
bool enemyHasArmor = false;
// Ignore enemy without armor
for (unsigned int i=0; i<sizeof(armorSlots)/sizeof(int); ++i)
{
MWWorld::ContainerStoreIterator item = inv.getSlot(armorSlots[i]);
if (item != inv.end() && (item.getType() == MWWorld::ContainerStore::Type_Armor))
{
enemyHasArmor = true;
break;
}
}
if (!enemyHasArmor)
return 0.f;
break;
}
case ESM::MagicEffect::DisintegrateWeapon:
{
if (enemy.isEmpty())
return 0.f;
// Ignore enemy without inventory
if (!enemy.getClass().hasInventoryStore(enemy))
return 0.f;
MWWorld::InventoryStore& inv = enemy.getClass().getInventoryStore(enemy);
MWWorld::ContainerStoreIterator item = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
// Ignore enemy without weapons
if (item == inv.end() || (item.getType() != MWWorld::ContainerStore::Type_Weapon))
return 0.f;
break;
}
case ESM::MagicEffect::DamageAttribute:
case ESM::MagicEffect::DrainAttribute:
if (!enemy.isEmpty() && enemy.getClass().getCreatureStats(enemy).getAttribute(effect.mAttribute).getModified() <= 0)
return 0.f;
{
if (effect.mAttribute >= 0 && effect.mAttribute < ESM::Attribute::Length)
{
const float attributePriorities[ESM::Attribute::Length] = {
1.0f, // Strength
0.5f, // Intelligence
0.6f, // Willpower
0.7f, // Agility
0.5f, // Speed
0.8f, // Endurance
0.7f, // Personality
0.3f // Luck
};
rating *= attributePriorities[effect.mAttribute];
}
}
break;
case ESM::MagicEffect::DamageSkill:
case ESM::MagicEffect::DrainSkill:
if (enemy.isEmpty() || !enemy.getClass().isNpc())
return 0.f;
if (enemy.getClass().getNpcStats(enemy).getSkill(effect.mSkill).getModified() <= 0)
return 0.f;
break;
default:
break;
}
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effect.mEffectID);
// Underwater casting not possible
if (effect.mRange == ESM::RT_Target)
{
if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(actor), 0.75f))
return 0.f;
if (enemy.isEmpty())
return 0.f;
if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(enemy), 0.75f))
return 0.f;
}
rating *= magicEffect->mData.mBaseCost;
if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful)
{
rating *= -1.f;
if (enemy.isEmpty())
return 0.f;
// Check resistance for harmful effects
CreatureStats& stats = enemy.getClass().getCreatureStats(enemy);
float resistance = MWMechanics::getEffectResistanceAttribute(effect.mEffectID, &stats.getMagicEffects());
rating *= (1.f - std::min(resistance, 100.f) / 100.f);
}
// for harmful no-magnitude effects (e.g. silence) check if enemy is already has them
// for non-harmful no-magnitude effects (e.g. bound items) check if actor is already has them
if (magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude)
{
if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful)
{
CreatureStats& stats = enemy.getClass().getCreatureStats(enemy);
static const float fCombatDistance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fCombatDistance")->getFloat();
static float fHandToHandReach = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fHandToHandReach")->getFloat();
if (stats.getMagicEffects().get(effect.mEffectID).getMagnitude() > 0)
return 0.f;
}
else
{
CreatureStats& stats = actor.getClass().getCreatureStats(actor);
// This distance is a possible distance of melee attack
static float distance = fCombatDistance * std::max(2.f, fHandToHandReach);
if (stats.getMagicEffects().get(effect.mEffectID).getMagnitude() > 0)
return 0.f;
}
}
else
if (rangeTypes & RangeTypes::Touch)
{
rating *= (effect.mMagnMin + effect.mMagnMax)/2.f;
return fCombatDistance;
}
if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration))
rating *= effect.mDuration;
// Currently treating all "on target" or "on touch" effects to target the enemy actor.
// Combat AI is egoistic, so doesn't consider applying positive effects to friendly actors.
if (effect.mRange != ESM::RT_Self)
rating *= -1.f;
return rating;
}
float rateEffects(const ESM::EffectList &list, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy)
{
// NOTE: enemy may be empty
float rating = 0.f;
for (std::vector<ESM::ENAMstruct>::const_iterator it = list.mList.begin(); it != list.mList.end(); ++it)
{
rating += rateEffect(*it, actor, enemy);
}
return rating;
return distance * 4;
}
void ActionSpell::prepare(const MWWorld::Ptr &actor)
@ -638,7 +56,7 @@ namespace MWMechanics
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(mSpellId);
int types = getRangeTypes(spell->mEffects);
isRanged = (types & Target) | (types & Self);
isRanged = (types & RangeTypes::Target) | (types & RangeTypes::Self);
return suggestCombatRange(types);
}
@ -832,6 +250,79 @@ namespace MWMechanics
return bestAction;
}
float getBestActionRating(const MWWorld::Ptr &actor, const MWWorld::Ptr &enemy)
{
Spells& spells = actor.getClass().getCreatureStats(actor).getSpells();
float bestActionRating = 0.f;
// Default to hand-to-hand combat
if (actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())
{
return bestActionRating;
}
if (actor.getClass().hasInventoryStore(actor))
{
MWWorld::InventoryStore& store = actor.getClass().getInventoryStore(actor);
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
{
float rating = rateMagicItem(*it, actor, enemy);
if (rating > bestActionRating)
{
bestActionRating = rating;
}
}
float bestArrowRating = 0;
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
{
float rating = rateWeapon(*it, actor, enemy, ESM::Weapon::Arrow);
if (rating > bestArrowRating)
{
bestArrowRating = rating;
}
}
float bestBoltRating = 0;
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
{
float rating = rateWeapon(*it, actor, enemy, ESM::Weapon::Bolt);
if (rating > bestBoltRating)
{
bestBoltRating = rating;
}
}
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
{
std::vector<int> equipmentSlots = it->getClass().getEquipmentSlots(*it).first;
if (std::find(equipmentSlots.begin(), equipmentSlots.end(), (int)MWWorld::InventoryStore::Slot_CarriedRight)
== equipmentSlots.end())
continue;
float rating = rateWeapon(*it, actor, enemy, -1, bestArrowRating, bestBoltRating);
if (rating > bestActionRating)
{
bestActionRating = rating;
}
}
}
for (Spells::TIterator it = spells.begin(); it != spells.end(); ++it)
{
const ESM::Spell* spell = it->first;
float rating = rateSpell(spell, actor, enemy);
if (rating > bestActionRating)
{
bestActionRating = rating;
}
}
return bestActionRating;
}
float getDistanceMinusHalfExtents(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, bool minusZDist)
{
@ -1016,67 +507,6 @@ namespace MWMechanics
return true;
}
float vanillaRateSpell(const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy)
{
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
static const float fAIMagicSpellMult = gmst.find("fAIMagicSpellMult")->getFloat();
static const float fAIRangeMagicSpellMult = gmst.find("fAIRangeMagicSpellMult")->getFloat();
float mult = fAIMagicSpellMult;
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt =
spell->mEffects.mList.begin(); effectIt != spell->mEffects.mList.end(); ++effectIt)
{
if (effectIt->mRange == ESM::RT_Target)
{
if (!MWBase::Environment::get().getWorld()->isSwimming(enemy))
mult = fAIRangeMagicSpellMult;
else
mult = 0.0f;
break;
}
}
return MWMechanics::getSpellSuccessChance(spell, actor) * mult;
}
float vanillaRateWeaponAndAmmo(const MWWorld::Ptr& weapon, const MWWorld::Ptr& ammo, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy)
{
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
static const float fAIMeleeWeaponMult = gmst.find("fAIMeleeWeaponMult")->getFloat();
static const float fAIMeleeArmorMult = gmst.find("fAIMeleeArmorMult")->getFloat();
static const float fAIRangeMeleeWeaponMult = gmst.find("fAIRangeMeleeWeaponMult")->getFloat();
if (weapon.isEmpty())
return 0.f;
float skillMult = actor.getClass().getSkill(actor, weapon.getClass().getEquipmentSkill(weapon)) * 0.01f;
float chopMult = fAIMeleeWeaponMult;
float bonusDamage = 0.f;
const ESM::Weapon* esmWeap = weapon.get<ESM::Weapon>()->mBase;
if (esmWeap->mData.mType >= ESM::Weapon::MarksmanBow)
{
if (!ammo.isEmpty() && !MWBase::Environment::get().getWorld()->isSwimming(enemy))
{
bonusDamage = ammo.get<ESM::Weapon>()->mBase->mData.mChop[1];
chopMult = fAIRangeMeleeWeaponMult;
}
else
chopMult = 0.f;
}
float chopRating = (esmWeap->mData.mChop[1] + bonusDamage) * skillMult * chopMult;
float slashRating = esmWeap->mData.mSlash[1] * skillMult * fAIMeleeWeaponMult;
float thrustRating = esmWeap->mData.mThrust[1] * skillMult * fAIMeleeWeaponMult;
return actor.getClass().getArmorRating(actor) * fAIMeleeArmorMult
+ std::max(std::max(chopRating, slashRating), thrustRating);
}
float vanillaRateFlee(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy)
{
const CreatureStats& stats = actor.getClass().getCreatureStats(actor);
@ -1122,5 +552,4 @@ namespace MWMechanics
return false;
}
}

@ -10,7 +10,6 @@
namespace MWMechanics
{
class Action
{
public:
@ -88,26 +87,13 @@ namespace MWMechanics
virtual const ESM::Weapon* getWeapon() const;
};
float rateSpell (const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
float rateMagicItem (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
float ratePotion (const MWWorld::Ptr& item, const MWWorld::Ptr &actor);
/// @param type Skip all weapons that are not of this type (i.e. return rating 0)
float rateWeapon (const MWWorld::Ptr& item, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy,
int type=-1, float arrowRating=0.f, float boltRating=0.f);
/// @note target may be empty
float rateEffect (const ESM::ENAMstruct& effect, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
/// @note target may be empty
float rateEffects (const ESM::EffectList& list, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
std::shared_ptr<Action> prepareNextAction (const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
float getBestActionRating(const MWWorld::Ptr &actor, const MWWorld::Ptr &enemy);
float getDistanceMinusHalfExtents(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy, bool minusZDist=false);
float getMaxAttackDistance(const MWWorld::Ptr& actor);
bool canFight(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
float vanillaRateSpell(const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
float vanillaRateWeaponAndAmmo(const MWWorld::Ptr& weapon, const MWWorld::Ptr& ammo, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
float vanillaRateFlee(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
bool makeFleeDecision(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy, float antiFleeRating);
}

@ -176,7 +176,9 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float dur
if (!mObstacleCheck.check(actor, duration)) return;
// first check if obstacle is a door
MWWorld::Ptr door = getNearbyDoor(actor); // NOTE: checks interior cells only
static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance();
MWWorld::Ptr door = getNearbyDoor(actor, distance);
if (door != MWWorld::Ptr())
{
// note: AiWander currently does not open doors

@ -41,12 +41,13 @@ namespace MWMechanics
TypeIdFollow = 3,
TypeIdActivate = 4,
// These 4 are not really handled as Ai Packages in the MW engine
// These 5 are not really handled as Ai Packages in the MW engine
// For compatibility do *not* return these in the getCurrentAiPackage script function..
TypeIdCombat = 5,
TypeIdPursue = 6,
TypeIdAvoidDoor = 7,
TypeIdFace = 8
TypeIdFace = 8,
TypeIdBreathe = 9
};
///Default constructor

@ -16,6 +16,7 @@
#include "aifollow.hpp"
#include "aiactivate.hpp"
#include "aicombat.hpp"
#include "aicombataction.hpp"
#include "aipursue.hpp"
#include "actorutil.hpp"
@ -182,7 +183,8 @@ bool isActualAiPackage(int packageTypeId)
return (packageTypeId != AiPackage::TypeIdCombat
&& packageTypeId != AiPackage::TypeIdPursue
&& packageTypeId != AiPackage::TypeIdAvoidDoor
&& packageTypeId != AiPackage::TypeIdFace);
&& packageTypeId != AiPackage::TypeIdFace
&& packageTypeId != AiPackage::TypeIdBreathe);
}
void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
@ -208,6 +210,8 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac
float nearestDist = std::numeric_limits<float>::max();
osg::Vec3f vActorPos = actor.getRefData().getPosition().asVec3();
float bestRating = 0.f;
for(std::list<AiPackage *>::iterator it = mPackages.begin(); it != mPackages.end();)
{
if ((*it)->getTypeId() != AiPackage::TypeIdCombat) break;
@ -222,6 +226,8 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac
}
else
{
float rating = MWMechanics::getBestActionRating(actor, target);
const ESM::Position &targetPos = target.getRefData().getPosition();
float distTo = (targetPos.asVec3() - vActorPos).length();
@ -230,10 +236,12 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac
if (it == mPackages.begin())
distTo = std::max(0.f, distTo - 50.f);
if (distTo < nearestDist)
// if a target has higher priority than current target or has same priority but closer
if (rating > bestRating || ((distTo < nearestDist) && rating == bestRating))
{
nearestDist = distTo;
itActualCombat = it;
bestRating = rating;
}
++it;
}

@ -449,11 +449,14 @@ namespace MWMechanics
{
// Check if an idle actor is too close to a door - if so start walking
storage.mDoorCheckDuration += duration;
static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance();
if (storage.mDoorCheckDuration >= DOOR_CHECK_INTERVAL)
{
storage.mDoorCheckDuration = 0; // restart timer
if (mDistance && // actor is not intended to be stationary
proximityToDoor(actor, MIN_DIST_TO_DOOR_SQUARED*1.6f*1.6f)) // NOTE: checks interior cells only
proximityToDoor(actor, distance*1.6f))
{
storage.setState(Wander_MoveNow);
storage.mTrimCurrentNode = false; // just in case
@ -486,7 +489,7 @@ namespace MWMechanics
float duration, AiWanderStorage& storage, ESM::Position& pos)
{
// Is there no destination or are we there yet?
if ((!mPathFinder.isPathConstructed()) || pathTo(actor, mPathFinder.getPath().back(), duration, DESTINATION_TOLERANCE))
if ((!mPathFinder.isPathConstructed()) || pathTo(actor, ESM::Pathgrid::Point(mPathFinder.getPath().back()), duration, DESTINATION_TOLERANCE))
{
stopWalking(actor, storage);
storage.setState(Wander_ChooseAction);
@ -527,10 +530,12 @@ namespace MWMechanics
void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration, ESM::Position& pos)
{
static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance();
if (mObstacleCheck.isEvading())
{
// first check if we're walking into a door
if (proximityToDoor(actor)) // NOTE: checks interior cells only
if (proximityToDoor(actor, distance))
{
// remove allowed points then select another random destination
storage.mTrimCurrentNode = true;

@ -1,4 +1,5 @@
#include "autocalcspell.hpp"
#include "spellcasting.hpp"
#include <climits>
#include <limits>
@ -255,27 +256,39 @@ namespace MWMechanics
void calcWeakestSchool (const ESM::Spell* spell, const int* actorSkills, int& effectiveSchool, float& skillTerm)
{
// Morrowind for some reason uses a formula slightly different from magicka cost calculation
float minChance = std::numeric_limits<float>::max();
const ESM::EffectList& effects = spell->mEffects;
for (std::vector<ESM::ENAMstruct>::const_iterator it = effects.mList.begin(); it != effects.mList.end(); ++it)
{
const ESM::ENAMstruct& effect = *it;
float x = static_cast<float>(effect.mDuration);
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effect.mEffectID);
if (!(magicEffect->mData.mFlags & ESM::MagicEffect::UncappedDamage))
x = std::max(1.f, x);
x *= 0.1f * magicEffect->mData.mBaseCost;
x *= 0.5f * (effect.mMagnMin + effect.mMagnMax);
x += effect.mArea * 0.05f * magicEffect->mData.mBaseCost;
if (effect.mRange == ESM::RT_Target)
x *= 1.5f;
int minMagn = 1;
int maxMagn = 1;
if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude))
{
minMagn = effect.mMagnMin;
maxMagn = effect.mMagnMax;
}
static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fEffectCostMult")->getFloat();
int duration = 0;
if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration))
duration = effect.mDuration;
static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore()
.get<ESM::GameSetting>().find("fEffectCostMult")->getFloat();
float x = 0.5 * (std::max(1, minMagn) + std::max(1, maxMagn));
x *= 0.1 * magicEffect->mData.mBaseCost;
x *= 1 + duration;
x += 0.05 * std::max(1, effect.mArea) * magicEffect->mData.mBaseCost;
x *= fEffectCostMult;
if (effect.mRange == ESM::RT_Target)
x *= 1.5f;
float s = 2.f * actorSkills[mapSchoolToSkill(magicEffect->mData.mSchool)];
if (s - x < minChance)
{

@ -2164,13 +2164,13 @@ bool CharacterController::playGroup(const std::string &groupname, int mode, int
}
else
{
// If the given animation is a looped animation, is already playing
// and has not yet reached its Loop Stop key, make it the only animation
// in the queue, and retain the loop count from the animation that was
// already playing. This emulates observed behavior from the original
// engine and allows banners to animate correctly.
// If this animation is a looped animation (has a "loop start" key) that is already playing
// and has not yet reached the end of the loop, allow it to continue animating with its existing loop count
// and remove any other animations that were queued.
// This emulates observed behavior from the original allows the script "OutsideBanner" to animate banners correctly.
if (!mAnimQueue.empty() && mAnimQueue.front().mGroup == groupname &&
mAnimation->getTextKeyTime(mAnimQueue.front().mGroup+": loop start") >= 0)
mAnimation->getTextKeyTime(mAnimQueue.front().mGroup + ": loop start") >= 0 &&
mAnimation->isPlaying(groupname))
{
float endOfLoop = mAnimation->getTextKeyTime(mAnimQueue.front().mGroup+": loop stop");
@ -2179,8 +2179,7 @@ bool CharacterController::playGroup(const std::string &groupname, int mode, int
if (endOfLoop > 0 && (mAnimation->getCurrentTime(mAnimQueue.front().mGroup) < endOfLoop))
{
mAnimation->setLoopingEnabled(mAnimQueue.front().mGroup, true);
mAnimQueue.resize(1);
mAnimQueue.resize(1);
return true;
}
}

@ -1547,7 +1547,7 @@ namespace MWMechanics
{
int disposition = 50;
if (ptr.getClass().isNpc())
disposition = getDerivedDisposition(ptr, false);
disposition = getDerivedDisposition(ptr, true);
int fight = std::max(0, ptr.getClass().getCreatureStats(ptr).getAiSetting(CreatureStats::AI_Fight).getModified()
+ static_cast<int>(getFightDistanceBias(ptr, target) + getFightDispositionBias(static_cast<float>(disposition))));

@ -1,6 +1,7 @@
#include "obstacle.hpp"
#include <components/esm/loadcell.hpp>
#include <components/sceneutil/positionattitudetransform.hpp>
#include "../mwbase/world.hpp"
#include "../mwworld/class.hpp"
@ -23,50 +24,48 @@ namespace MWMechanics
{ -1.0f, -1.0f } // move to side and backwards
};
// Proximity check function for interior doors. Given that most interior cells
// do not have many doors performance shouldn't be too much of an issue.
//
// Limitation: there can be false detections, and does not test whether the
// actor is facing the door.
bool proximityToDoor(const MWWorld::Ptr& actor, float minSqr)
bool proximityToDoor(const MWWorld::Ptr& actor, float minDist)
{
if(getNearbyDoor(actor, minSqr)!=MWWorld::Ptr())
if(getNearbyDoor(actor, minDist)!=MWWorld::Ptr())
return true;
else
return false;
}
MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minSqr)
MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minDist)
{
MWWorld::CellStore *cell = actor.getCell();
if(cell->getCell()->isExterior())
return MWWorld::Ptr(); // check interior cells only
// Check all the doors in this cell
const MWWorld::CellRefList<ESM::Door>& doors = cell->getReadOnlyDoors();
const MWWorld::CellRefList<ESM::Door>::List& refList = doors.mList;
MWWorld::CellRefList<ESM::Door>::List::const_iterator it = refList.begin();
osg::Vec3f pos(actor.getRefData().getPosition().asVec3());
pos.z() = 0;
/// TODO: How to check whether the actor is facing a door? Below code is for
/// the player, perhaps it can be adapted.
//MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getFacedObject();
//if(!ptr.isEmpty())
//std::cout << "faced door " << ptr.getClass().getName(ptr) << std::endl;
osg::Vec3f actorDir = (actor.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0,1,0));
/// TODO: The in-game observation of rot[2] value seems to be the
/// opposite of the code in World::activateDoor() ::confused::
for (; it != refList.end(); ++it)
{
const MWWorld::LiveCellRef<ESM::Door>& ref = *it;
if((pos - ref.mData.getPosition().asVec3()).length2() < minSqr
&& ref.mData.getPosition().rot[2] == ref.mRef.getPosition().rot[2])
{
// FIXME cast
return MWWorld::Ptr(&const_cast<MWWorld::LiveCellRef<ESM::Door> &>(ref), actor.getCell()); // found, stop searching
}
osg::Vec3f doorPos(ref.mData.getPosition().asVec3());
doorPos.z() = 0;
float angle = std::acos(actorDir * (doorPos - pos) / (actorDir.length() * (doorPos - pos).length()));
// Allow 60 degrees angle between actor and door
if (angle < -osg::PI / 3 || angle > osg::PI / 3)
continue;
// Door is not close enough
if ((pos - doorPos).length2() > minDist*minDist)
continue;
// FIXME cast
return MWWorld::Ptr(&const_cast<MWWorld::LiveCellRef<ESM::Door> &>(ref), actor.getCell()); // found, stop searching
}
return MWWorld::Ptr(); // none found
}

@ -10,19 +10,14 @@ namespace MWMechanics
{
struct Movement;
/// NOTE: determined empirically based on in-game behaviour
static const float MIN_DIST_TO_DOOR_SQUARED = 128*128;
static const int NUM_EVADE_DIRECTIONS = 4;
/// tests actor's proximity to a closed door by default
bool proximityToDoor(const MWWorld::Ptr& actor,
float minSqr = MIN_DIST_TO_DOOR_SQUARED);
bool proximityToDoor(const MWWorld::Ptr& actor, float minDist);
/// Returns door pointer within range. No guarantee is given as to which one
/** \return Pointer to the door, or NULL if none exists **/
MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor,
float minSqr = MIN_DIST_TO_DOOR_SQUARED);
MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minDist);
class ObstacleCheck
{

@ -60,8 +60,36 @@ namespace MWMechanics
return schoolSkillMap[school];
}
float getSpellSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool, bool cap)
float calcEffectCost(const ESM::ENAMstruct& effect)
{
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effect.mEffectID);
int minMagn = 1;
int maxMagn = 1;
if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude))
{
minMagn = effect.mMagnMin;
maxMagn = effect.mMagnMax;
}
int duration = 0;
if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration))
duration = effect.mDuration;
static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore()
.get<ESM::GameSetting>().find("fEffectCostMult")->getFloat();
float x = 0.5 * (std::max(1, minMagn) + std::max(1, maxMagn));
x *= 0.1 * magicEffect->mData.mBaseCost;
x *= 1 + duration;
x += 0.05 * std::max(1, effect.mArea) * magicEffect->mData.mBaseCost;
return x * fEffectCostMult;
}
float calcSpellBaseSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool)
{
// Morrowind for some reason uses a formula slightly different from magicka cost calculation
float y = std::numeric_limits<float>::max();
float lowestSkill = 0;
@ -70,8 +98,10 @@ namespace MWMechanics
float x = static_cast<float>(it->mDuration);
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(
it->mEffectID);
if (!(magicEffect->mData.mFlags & ESM::MagicEffect::UncappedDamage))
x = std::max(1.f, x);
x *= 0.1f * magicEffect->mData.mBaseCost;
x *= 0.5f * (it->mMagnMin + it->mMagnMax);
x *= it->mArea * 0.05f * magicEffect->mData.mBaseCost;
@ -91,6 +121,18 @@ namespace MWMechanics
}
}
CreatureStats& stats = actor.getClass().getCreatureStats(actor);
int actorWillpower = stats.getAttribute(ESM::Attribute::Willpower).getModified();
int actorLuck = stats.getAttribute(ESM::Attribute::Luck).getModified();
float castChance = (lowestSkill - spell->mData.mCost + 0.2f * actorWillpower + 0.1f * actorLuck);
return castChance;
}
float getSpellSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool, bool cap)
{
bool godmode = actor == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState();
CreatureStats& stats = actor.getClass().getCreatureStats(actor);
@ -114,10 +156,8 @@ namespace MWMechanics
float castBonus = -stats.getMagicEffects().get(ESM::MagicEffect::Sound).getMagnitude();
int actorWillpower = stats.getAttribute(ESM::Attribute::Willpower).getModified();
int actorLuck = stats.getAttribute(ESM::Attribute::Luck).getModified();
float castChance = (lowestSkill - spell->mData.mCost + castBonus + 0.2f * actorWillpower + 0.1f * actorLuck) * stats.getFatigueTerm();
float castChance = calcSpellBaseSuccessChance(spell, actor, effectiveSchool) + castBonus;
castChance *= stats.getFatigueTerm();
if (!cap)
return std::max(0.f, castChance);
@ -1165,6 +1205,9 @@ namespace MWMechanics
receivedMagicDamage = true;
adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::DamageHealth, -magnitude);
}
break;
case ESM::MagicEffect::DamageMagicka:
case ESM::MagicEffect::DamageFatigue:
if (!godmode)
@ -1181,6 +1224,9 @@ namespace MWMechanics
receivedMagicDamage = true;
adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::AbsorbHealth, -magnitude);
}
break;
case ESM::MagicEffect::AbsorbMagicka:
case ESM::MagicEffect::AbsorbFatigue:
if (!godmode)

@ -1,6 +1,7 @@
#ifndef MWMECHANICS_SPELLSUCCESS_H
#define MWMECHANICS_SPELLSUCCESS_H
#include <components/esm/effectlist.hpp>
#include <components/esm/loadskil.hpp>
#include "../mwworld/ptr.hpp"
@ -21,6 +22,8 @@ namespace MWMechanics
ESM::Skill::SkillEnum spellSchoolToSkill(int school);
float calcEffectCost(const ESM::ENAMstruct& effect);
bool isSummoningEffect(int effectId);
/**
@ -62,6 +65,7 @@ namespace MWMechanics
bool checkEffectTarget (int effectId, const MWWorld::Ptr& target, const MWWorld::Ptr& caster, bool castByPlayer);
int getEffectiveEnchantmentCastCost (float castCost, const MWWorld::Ptr& actor);
float calcSpellBaseSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool);
/// Apply a magic effect that is applied in tick intervals until its remaining time ends or it is removed
/// @return Was the effect a tickable effect with a magnitude?

@ -0,0 +1,545 @@
#include "spellpriority.hpp"
#include <components/esm/loadench.hpp>
#include <components/esm/loadmgef.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwworld/inventorystore.hpp"
#include "../mwworld/actionequip.hpp"
#include "../mwworld/cellstore.hpp"
#include "npcstats.hpp"
#include "spellcasting.hpp"
#include "combat.hpp"
namespace
{
int numEffectsToDispel (const MWWorld::Ptr& actor, int effectFilter=-1, bool negative = true)
{
int toCure=0;
const MWMechanics::ActiveSpells& activeSpells = actor.getClass().getCreatureStats(actor).getActiveSpells();
for (MWMechanics::ActiveSpells::TIterator it = activeSpells.begin(); it != activeSpells.end(); ++it)
{
const MWMechanics::ActiveSpells::ActiveSpellParams& params = it->second;
for (std::vector<MWMechanics::ActiveSpells::ActiveEffect>::const_iterator effectIt = params.mEffects.begin();
effectIt != params.mEffects.end(); ++effectIt)
{
int effectId = effectIt->mEffectId;
if (effectFilter != -1 && effectId != effectFilter)
continue;
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effectId);
if (effectIt->mDuration <= 3) // Don't attempt to dispel if effect runs out shortly anyway
continue;
if (negative && magicEffect->mData.mFlags & ESM::MagicEffect::Harmful)
++toCure;
if (!negative && !(magicEffect->mData.mFlags & ESM::MagicEffect::Harmful))
++toCure;
}
}
return toCure;
}
}
namespace MWMechanics
{
int getRangeTypes (const ESM::EffectList& effects)
{
int types = 0;
for (std::vector<ESM::ENAMstruct>::const_iterator it = effects.mList.begin(); it != effects.mList.end(); ++it)
{
if (it->mRange == ESM::RT_Self)
types |= RangeTypes::Self;
else if (it->mRange == ESM::RT_Touch)
types |= RangeTypes::Touch;
else if (it->mRange == ESM::RT_Target)
types |= RangeTypes::Target;
}
return types;
}
float ratePotion (const MWWorld::Ptr &item, const MWWorld::Ptr& actor)
{
if (item.getTypeName() != typeid(ESM::Potion).name())
return 0.f;
const ESM::Potion* potion = item.get<ESM::Potion>()->mBase;
return rateEffects(potion->mEffects, actor, MWWorld::Ptr());
}
float rateSpell(const ESM::Spell *spell, const MWWorld::Ptr &actor, const MWWorld::Ptr& enemy)
{
const CreatureStats& stats = actor.getClass().getCreatureStats(actor);
float successChance = MWMechanics::getSpellSuccessChance(spell, actor);
if (successChance == 0.f)
return 0.f;
if (spell->mData.mType != ESM::Spell::ST_Spell)
return 0.f;
// Don't make use of racial bonus spells, like MW. Can be made optional later
if (actor.getClass().isNpc())
{
std::string raceid = actor.get<ESM::NPC>()->mBase->mRace;
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(raceid);
if (race->mPowers.exists(spell->mId))
return 0.f;
}
if (spell->mData.mCost > stats.getMagicka().getCurrent())
return 0.f;
// Spells don't stack, so early out if the spell is still active on the target
int types = getRangeTypes(spell->mEffects);
if ((types & Self) && stats.getActiveSpells().isSpellActive(spell->mId))
return 0.f;
if ( ((types & Touch) || (types & Target)) && enemy.getClass().getCreatureStats(enemy).getActiveSpells().isSpellActive(spell->mId))
return 0.f;
return rateEffects(spell->mEffects, actor, enemy) * (successChance / 100.f);
}
float rateMagicItem(const MWWorld::Ptr &ptr, const MWWorld::Ptr &actor, const MWWorld::Ptr& enemy)
{
if (ptr.getClass().getEnchantment(ptr).empty())
return 0.f;
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find(ptr.getClass().getEnchantment(ptr));
if (enchantment->mData.mType == ESM::Enchantment::CastOnce)
{
return rateEffects(enchantment->mEffects, actor, enemy);
}
else
{
//if (!ptr.getClass().canBeEquipped(ptr, actor))
return 0.f;
}
}
float rateEffect(const ESM::ENAMstruct &effect, const MWWorld::Ptr &actor, const MWWorld::Ptr &enemy)
{
// NOTE: enemy may be empty
float rating = 1;
switch (effect.mEffectID)
{
case ESM::MagicEffect::Soultrap:
case ESM::MagicEffect::AlmsiviIntervention:
case ESM::MagicEffect::DivineIntervention:
case ESM::MagicEffect::CalmHumanoid:
case ESM::MagicEffect::CalmCreature:
case ESM::MagicEffect::FrenzyHumanoid:
case ESM::MagicEffect::FrenzyCreature:
case ESM::MagicEffect::DemoralizeHumanoid:
case ESM::MagicEffect::DemoralizeCreature:
case ESM::MagicEffect::RallyHumanoid:
case ESM::MagicEffect::RallyCreature:
case ESM::MagicEffect::Charm:
case ESM::MagicEffect::DetectAnimal:
case ESM::MagicEffect::DetectEnchantment:
case ESM::MagicEffect::DetectKey:
case ESM::MagicEffect::Telekinesis:
case ESM::MagicEffect::Mark:
case ESM::MagicEffect::Recall:
case ESM::MagicEffect::Jump:
case ESM::MagicEffect::WaterBreathing:
case ESM::MagicEffect::SwiftSwim:
case ESM::MagicEffect::WaterWalking:
case ESM::MagicEffect::SlowFall:
case ESM::MagicEffect::Light:
case ESM::MagicEffect::Lock:
case ESM::MagicEffect::Open:
case ESM::MagicEffect::TurnUndead:
case ESM::MagicEffect::WeaknessToCommonDisease:
case ESM::MagicEffect::WeaknessToBlightDisease:
case ESM::MagicEffect::WeaknessToCorprusDisease:
case ESM::MagicEffect::CureCommonDisease:
case ESM::MagicEffect::CureBlightDisease:
case ESM::MagicEffect::CureCorprusDisease:
case ESM::MagicEffect::ResistBlightDisease:
case ESM::MagicEffect::ResistCommonDisease:
case ESM::MagicEffect::ResistCorprusDisease:
case ESM::MagicEffect::Invisibility:
case ESM::MagicEffect::Chameleon:
case ESM::MagicEffect::NightEye:
case ESM::MagicEffect::Vampirism:
case ESM::MagicEffect::StuntedMagicka:
case ESM::MagicEffect::ExtraSpell:
case ESM::MagicEffect::RemoveCurse:
case ESM::MagicEffect::CommandCreature:
case ESM::MagicEffect::CommandHumanoid:
return 0.f;
case ESM::MagicEffect::Sound:
{
if (enemy.isEmpty())
return 0.f;
// there is no need to cast sound if enemy is not able to cast spells
CreatureStats& stats = enemy.getClass().getCreatureStats(enemy);
if (stats.getMagicEffects().get(ESM::MagicEffect::Silence).getMagnitude() > 0)
return 0.f;
if (stats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0)
return 0.f;
break;
}
case ESM::MagicEffect::RestoreAttribute:
return 0.f; // TODO: implement based on attribute damage
case ESM::MagicEffect::RestoreSkill:
return 0.f; // TODO: implement based on skill damage
case ESM::MagicEffect::ResistFire:
case ESM::MagicEffect::ResistFrost:
case ESM::MagicEffect::ResistMagicka:
case ESM::MagicEffect::ResistNormalWeapons:
case ESM::MagicEffect::ResistParalysis:
case ESM::MagicEffect::ResistPoison:
case ESM::MagicEffect::ResistShock:
case ESM::MagicEffect::SpellAbsorption:
case ESM::MagicEffect::Reflect:
return 0.f; // probably useless since we don't know in advance what the enemy will cast
// don't cast these for now as they would make the NPC cast the same effect over and over again, especially when they have potions
case ESM::MagicEffect::FortifyAttribute:
case ESM::MagicEffect::FortifyHealth:
case ESM::MagicEffect::FortifyMagicka:
case ESM::MagicEffect::FortifyFatigue:
case ESM::MagicEffect::FortifySkill:
case ESM::MagicEffect::FortifyMaximumMagicka:
case ESM::MagicEffect::FortifyAttack:
return 0.f;
case ESM::MagicEffect::Burden:
{
if (enemy.isEmpty())
return 0.f;
// Ignore enemy without inventory
if (!enemy.getClass().hasInventoryStore(enemy))
return 0.f;
// burden makes sense only to overburden an enemy
float burden = enemy.getClass().getEncumbrance(enemy) - enemy.getClass().getCapacity(enemy);
if (burden > 0)
return 0.f;
if ((effect.mMagnMin + effect.mMagnMax)/2.f > -burden)
rating *= 3;
else
return 0.f;
break;
}
case ESM::MagicEffect::Feather:
{
// Ignore actors without inventory
if (!actor.getClass().hasInventoryStore(actor))
return 0.f;
// feather makes sense only for overburden actors
float burden = actor.getClass().getEncumbrance(actor) - actor.getClass().getCapacity(actor);
if (burden <= 0)
return 0.f;
if ((effect.mMagnMin + effect.mMagnMax)/2.f >= burden)
rating *= 3;
else
return 0.f;
break;
}
case ESM::MagicEffect::Levitate:
return 0.f; // AI isn't designed to take advantage of this, and could be perceived as unfair anyway
case ESM::MagicEffect::BoundBoots:
case ESM::MagicEffect::BoundHelm:
if (actor.getClass().isNpc())
{
// Beast races can't wear helmets or boots
std::string raceid = actor.get<ESM::NPC>()->mBase->mRace;
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(raceid);
if (race->mData.mFlags & ESM::Race::Beast)
return 0.f;
}
// Intended fall-through
// Creatures can not wear armor
case ESM::MagicEffect::BoundCuirass:
case ESM::MagicEffect::BoundGloves:
if (!actor.getClass().isNpc())
return 0.f;
break;
case ESM::MagicEffect::RestoreHealth:
case ESM::MagicEffect::RestoreMagicka:
case ESM::MagicEffect::RestoreFatigue:
if (effect.mRange == ESM::RT_Self)
{
int priority = 1;
if (effect.mEffectID == ESM::MagicEffect::RestoreHealth)
priority = 10;
const DynamicStat<float>& current = actor.getClass().getCreatureStats(actor).
getDynamic(effect.mEffectID - ESM::MagicEffect::RestoreHealth);
float toHeal = (effect.mMagnMin + effect.mMagnMax)/2.f * effect.mDuration;
// Effect doesn't heal more than we need, *or* we are below 1/2 health
if (current.getModified() - current.getCurrent() > toHeal
|| current.getCurrent() < current.getModified()*0.5)
{
return 10000.f * priority
- (toHeal - (current.getModified()-current.getCurrent())); // prefer the most fitting potion
}
else
return -10000.f * priority; // Save for later
}
break;
case ESM::MagicEffect::Dispel:
{
int numPositive = 0;
int numNegative = 0;
int diff = 0;
if (effect.mRange == ESM::RT_Self)
{
numPositive = numEffectsToDispel(actor, -1, false);
numNegative = numEffectsToDispel(actor);
diff = numNegative - numPositive;
}
else
{
if (enemy.isEmpty())
return 0.f;
numPositive = numEffectsToDispel(enemy, -1, false);
numNegative = numEffectsToDispel(enemy);
diff = numPositive - numNegative;
// if rating < 0 here, the spell will be considered as negative later
rating *= -1;
}
if (diff <= 0)
return 0.f;
rating *= (diff) / 5.f;
break;
}
// Prefer Cure effects over Dispel, because Dispel also removes positive effects
case ESM::MagicEffect::CureParalyzation:
return 1001.f * numEffectsToDispel(actor, ESM::MagicEffect::Paralyze);
case ESM::MagicEffect::CurePoison:
return 1001.f * numEffectsToDispel(actor, ESM::MagicEffect::Poison);
case ESM::MagicEffect::DisintegrateArmor:
{
if (enemy.isEmpty())
return 0.f;
// Ignore enemy without inventory
if (!enemy.getClass().hasInventoryStore(enemy))
return 0.f;
MWWorld::InventoryStore& inv = enemy.getClass().getInventoryStore(enemy);
// According to UESP
static const int armorSlots[] = {
MWWorld::InventoryStore::Slot_CarriedLeft,
MWWorld::InventoryStore::Slot_Cuirass,
MWWorld::InventoryStore::Slot_LeftPauldron,
MWWorld::InventoryStore::Slot_RightPauldron,
MWWorld::InventoryStore::Slot_LeftGauntlet,
MWWorld::InventoryStore::Slot_RightGauntlet,
MWWorld::InventoryStore::Slot_Helmet,
MWWorld::InventoryStore::Slot_Greaves,
MWWorld::InventoryStore::Slot_Boots
};
bool enemyHasArmor = false;
// Ignore enemy without armor
for (unsigned int i=0; i<sizeof(armorSlots)/sizeof(int); ++i)
{
MWWorld::ContainerStoreIterator item = inv.getSlot(armorSlots[i]);
if (item != inv.end() && (item.getType() == MWWorld::ContainerStore::Type_Armor))
{
enemyHasArmor = true;
break;
}
}
if (!enemyHasArmor)
return 0.f;
break;
}
case ESM::MagicEffect::DisintegrateWeapon:
{
if (enemy.isEmpty())
return 0.f;
// Ignore enemy without inventory
if (!enemy.getClass().hasInventoryStore(enemy))
return 0.f;
MWWorld::InventoryStore& inv = enemy.getClass().getInventoryStore(enemy);
MWWorld::ContainerStoreIterator item = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
// Ignore enemy without weapons
if (item == inv.end() || (item.getType() != MWWorld::ContainerStore::Type_Weapon))
return 0.f;
break;
}
case ESM::MagicEffect::DamageAttribute:
case ESM::MagicEffect::DrainAttribute:
if (!enemy.isEmpty() && enemy.getClass().getCreatureStats(enemy).getAttribute(effect.mAttribute).getModified() <= 0)
return 0.f;
{
if (effect.mAttribute >= 0 && effect.mAttribute < ESM::Attribute::Length)
{
const float attributePriorities[ESM::Attribute::Length] = {
1.0f, // Strength
0.5f, // Intelligence
0.6f, // Willpower
0.7f, // Agility
0.5f, // Speed
0.8f, // Endurance
0.7f, // Personality
0.3f // Luck
};
rating *= attributePriorities[effect.mAttribute];
}
}
break;
case ESM::MagicEffect::DamageSkill:
case ESM::MagicEffect::DrainSkill:
if (enemy.isEmpty() || !enemy.getClass().isNpc())
return 0.f;
if (enemy.getClass().getNpcStats(enemy).getSkill(effect.mSkill).getModified() <= 0)
return 0.f;
break;
default:
break;
}
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effect.mEffectID);
// Underwater casting not possible
if (effect.mRange == ESM::RT_Target)
{
if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(actor), 0.75f))
return 0.f;
if (enemy.isEmpty())
return 0.f;
if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(enemy), 0.75f))
return 0.f;
}
if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful)
{
rating *= -1.f;
if (enemy.isEmpty())
return 0.f;
// Check resistance for harmful effects
CreatureStats& stats = enemy.getClass().getCreatureStats(enemy);
float resistance = MWMechanics::getEffectResistanceAttribute(effect.mEffectID, &stats.getMagicEffects());
rating *= (1.f - std::min(resistance, 100.f) / 100.f);
}
// for harmful no-magnitude effects (e.g. silence) check if enemy is already has them
// for non-harmful no-magnitude effects (e.g. bound items) check if actor is already has them
if (magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude)
{
if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful)
{
CreatureStats& stats = enemy.getClass().getCreatureStats(enemy);
if (stats.getMagicEffects().get(effect.mEffectID).getMagnitude() > 0)
return 0.f;
}
else
{
CreatureStats& stats = actor.getClass().getCreatureStats(actor);
if (stats.getMagicEffects().get(effect.mEffectID).getMagnitude() > 0)
return 0.f;
}
}
rating *= calcEffectCost(effect);
// Currently treating all "on target" or "on touch" effects to target the enemy actor.
// Combat AI is egoistic, so doesn't consider applying positive effects to friendly actors.
if (effect.mRange != ESM::RT_Self)
rating *= -1.f;
return rating;
}
float rateEffects(const ESM::EffectList &list, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy)
{
// NOTE: enemy may be empty
float rating = 0.f;
for (std::vector<ESM::ENAMstruct>::const_iterator it = list.mList.begin(); it != list.mList.end(); ++it)
{
rating += rateEffect(*it, actor, enemy);
if (it->mRange == ESM::RT_Target)
rating *= 1.5f;
}
return rating;
}
float vanillaRateSpell(const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy)
{
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
static const float fAIMagicSpellMult = gmst.find("fAIMagicSpellMult")->getFloat();
static const float fAIRangeMagicSpellMult = gmst.find("fAIRangeMagicSpellMult")->getFloat();
float mult = fAIMagicSpellMult;
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt =
spell->mEffects.mList.begin(); effectIt != spell->mEffects.mList.end(); ++effectIt)
{
if (effectIt->mRange == ESM::RT_Target)
{
if (!MWBase::Environment::get().getWorld()->isSwimming(enemy))
mult = fAIRangeMagicSpellMult;
else
mult = 0.0f;
break;
}
}
return MWMechanics::getSpellSuccessChance(spell, actor) * mult;
}
}

@ -0,0 +1,32 @@
#ifndef OPENMW_SPELL_PRIORITY_H
#define OPENMW_SPELL_PRIORITY_H
#include <components/esm/loadspel.hpp>
#include "../mwworld/ptr.hpp"
namespace MWMechanics
{
// RangeTypes using bitflags to allow multiple range types, as can be the case with spells having multiple effects.
enum RangeTypes
{
Self = 0x1,
Touch = 0x10,
Target = 0x100
};
int getRangeTypes (const ESM::EffectList& effects);
float rateSpell (const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
float rateMagicItem (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
float ratePotion (const MWWorld::Ptr& item, const MWWorld::Ptr &actor);
/// @note target may be empty
float rateEffect (const ESM::ENAMstruct& effect, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
/// @note target may be empty
float rateEffects (const ESM::EffectList& list, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
float vanillaRateSpell(const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
}
#endif

@ -0,0 +1,146 @@
#include "weaponpriority.hpp"
#include <components/esm/loadench.hpp>
#include <components/esm/loadmgef.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/esmstore.hpp"
#include "npcstats.hpp"
#include "combat.hpp"
#include "aicombataction.hpp"
#include "spellpriority.hpp"
namespace MWMechanics
{
float rateWeapon (const MWWorld::Ptr &item, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy, int type,
float arrowRating, float boltRating)
{
if (item.getTypeName() != typeid(ESM::Weapon).name())
return 0.f;
const ESM::Weapon* weapon = item.get<ESM::Weapon>()->mBase;
if (type != -1 && weapon->mData.mType != type)
return 0.f;
float rating=0.f;
float bonus=0.f;
if (weapon->mData.mType >= ESM::Weapon::MarksmanBow && weapon->mData.mType <= ESM::Weapon::MarksmanThrown)
{
// Range weapon is useless under water
if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(actor), 0.75f))
return 0.f;
if (enemy.isEmpty())
return 0.f;
if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(enemy), 0.75f))
return 0.f;
bonus+=1.5f;
}
if (weapon->mData.mType >= ESM::Weapon::MarksmanBow)
{
rating = (weapon->mData.mChop[0] + weapon->mData.mChop[1]) / 2.f;
if (weapon->mData.mType >= ESM::Weapon::MarksmanThrown)
MWMechanics::resistNormalWeapon(enemy, actor, item, rating);
}
else
{
for (int i=0; i<2; ++i)
{
rating += weapon->mData.mSlash[i];
rating += weapon->mData.mThrust[i];
rating += weapon->mData.mChop[i];
}
rating /= 6.f;
MWMechanics::resistNormalWeapon(enemy, actor, item, rating);
}
if (item.getClass().hasItemHealth(item))
{
if (item.getClass().getItemHealth(item) == 0)
return 0.f;
rating *= item.getClass().getItemHealth(item) / float(item.getClass().getItemMaxHealth(item));
}
if (weapon->mData.mType == ESM::Weapon::MarksmanBow)
{
if (arrowRating <= 0.f)
rating = 0.f;
else
rating += arrowRating;
}
else if (weapon->mData.mType == ESM::Weapon::MarksmanCrossbow)
{
if (boltRating <= 0.f)
rating = 0.f;
else
rating += boltRating;
}
if (!weapon->mEnchant.empty())
{
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find(weapon->mEnchant);
if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes
&& (item.getCellRef().getEnchantmentCharge() == -1
|| item.getCellRef().getEnchantmentCharge() >= enchantment->mData.mCost))
rating += rateEffects(enchantment->mEffects, actor, enemy);
}
int skill = item.getClass().getEquipmentSkill(item);
if (skill != -1)
rating *= actor.getClass().getSkill(actor, skill) / 100.f;
// There is no need to apply bonus if weapon rating == 0
if (rating == 0.f)
return 0.f;
return rating + bonus;
}
float vanillaRateWeaponAndAmmo(const MWWorld::Ptr& weapon, const MWWorld::Ptr& ammo, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy)
{
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
static const float fAIMeleeWeaponMult = gmst.find("fAIMeleeWeaponMult")->getFloat();
static const float fAIMeleeArmorMult = gmst.find("fAIMeleeArmorMult")->getFloat();
static const float fAIRangeMeleeWeaponMult = gmst.find("fAIRangeMeleeWeaponMult")->getFloat();
if (weapon.isEmpty())
return 0.f;
float skillMult = actor.getClass().getSkill(actor, weapon.getClass().getEquipmentSkill(weapon)) * 0.01f;
float chopMult = fAIMeleeWeaponMult;
float bonusDamage = 0.f;
const ESM::Weapon* esmWeap = weapon.get<ESM::Weapon>()->mBase;
if (esmWeap->mData.mType >= ESM::Weapon::MarksmanBow)
{
if (!ammo.isEmpty() && !MWBase::Environment::get().getWorld()->isSwimming(enemy))
{
bonusDamage = ammo.get<ESM::Weapon>()->mBase->mData.mChop[1];
chopMult = fAIRangeMeleeWeaponMult;
}
else
chopMult = 0.f;
}
float chopRating = (esmWeap->mData.mChop[1] + bonusDamage) * skillMult * chopMult;
float slashRating = esmWeap->mData.mSlash[1] * skillMult * fAIMeleeWeaponMult;
float thrustRating = esmWeap->mData.mThrust[1] * skillMult * fAIMeleeWeaponMult;
return actor.getClass().getArmorRating(actor) * fAIMeleeArmorMult
+ std::max(std::max(chopRating, slashRating), thrustRating);
}
}

@ -0,0 +1,14 @@
#ifndef OPENMW_WEAPON_PRIORITY_H
#define OPENMW_WEAPON_PRIORITY_H
#include "../mwworld/ptr.hpp"
namespace MWMechanics
{
float rateWeapon (const MWWorld::Ptr& item, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy,
int type=-1, float arrowRating=0.f, float boltRating=0.f);
float vanillaRateWeaponAndAmmo(const MWWorld::Ptr& weapon, const MWWorld::Ptr& ammo, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
}
#endif

@ -38,6 +38,8 @@ Objects::~Objects()
void Objects::insertBegin(const MWWorld::Ptr& ptr)
{
assert(mObjects.find(ptr) == mObjects.end());
osg::ref_ptr<osg::Group> cellnode;
CellMap::iterator found = mCellSceneNodes.find(ptr.getCell());
@ -90,9 +92,8 @@ void Objects::insertCreature(const MWWorld::Ptr &ptr, const std::string &mesh, b
else
anim = new CreatureAnimation(ptr, mesh, mResourceSystem);
ptr.getClass().getContainerStore(ptr).setContListener(static_cast<ActorAnimation*>(anim.get()));
mObjects.insert(std::make_pair(ptr, anim));
if (mObjects.insert(std::make_pair(ptr, anim)).second)
ptr.getClass().getContainerStore(ptr).setContListener(static_cast<ActorAnimation*>(anim.get()));
}
void Objects::insertNPC(const MWWorld::Ptr &ptr)
@ -102,10 +103,11 @@ void Objects::insertNPC(const MWWorld::Ptr &ptr)
osg::ref_ptr<NpcAnimation> anim (new NpcAnimation(ptr, osg::ref_ptr<osg::Group>(ptr.getRefData().getBaseNode()), mResourceSystem));
ptr.getClass().getInventoryStore(ptr).setInvListener(anim.get(), ptr);
ptr.getClass().getInventoryStore(ptr).setContListener(anim.get());
mObjects.insert(std::make_pair(ptr, anim));
if (mObjects.insert(std::make_pair(ptr, anim)).second)
{
ptr.getClass().getInventoryStore(ptr).setInvListener(anim.get(), ptr);
ptr.getClass().getInventoryStore(ptr).setContListener(anim.get());
}
}
bool Objects::removeObject (const MWWorld::Ptr& ptr)

@ -65,6 +65,12 @@ namespace
void addObject(const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics,
MWRender::RenderingManager& rendering)
{
if (ptr.getRefData().getBaseNode() || physics.getActor(ptr))
{
std::cerr << "Warning: Tried to add " << ptr.getCellRef().getRefId() << " to the scene twice" << std::endl;
return;
}
bool useAnim = ptr.getClass().useAnim();
std::string model = ptr.getClass().getModel(ptr);
if (useAnim)

@ -856,7 +856,10 @@ namespace MWWorld
mWeatherManager->advanceTime (hours, incremental);
if (!incremental)
{
mRendering->notifyWorldSpaceChanged();
mProjectileManager->clear();
}
hours += mGameHour->getFloat();
@ -1552,6 +1555,7 @@ namespace MWWorld
{
osg::Vec3f a(x1,y1,z1);
osg::Vec3f b(x2,y2,z2);
MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(a, b, MWWorld::Ptr(), std::vector<MWWorld::Ptr>(), MWPhysics::CollisionType_World|MWPhysics::CollisionType_Door);
return result.mHit;
}

@ -49,17 +49,42 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr<osgViewer::Viewer> v
SDL_PumpEvents();
SDL_Event evt;
SDL_Event event;
if (windowEventsOnly)
{
// During loading, just handle window events, and keep others for later
while (SDL_PeepEvents(&evt, 1, SDL_GETEVENT, SDL_WINDOWEVENT, SDL_WINDOWEVENT))
handleWindowEvent(evt);
while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_WINDOWEVENT, SDL_WINDOWEVENT))
handleWindowEvent(event);
return;
}
while(SDL_PollEvent(&evt))
// Merge redundant events to avoid unnecessary listener calls
std::vector<SDL_Event> events;
while(SDL_PollEvent(&event)) {
if (events.empty() || events.back().type != event.type)
{
events.emplace_back(event);
continue;
}
SDL_Event& previousEvent = events.back();
switch (event.type)
{
case SDL_MOUSEMOTION:
previousEvent.motion.x = event.motion.x;
previousEvent.motion.y = event.motion.y;
previousEvent.motion.xrel += event.motion.xrel;
previousEvent.motion.yrel += event.motion.yrel;
break;
default:
events.emplace_back(event);
}
}
for (const SDL_Event& evt : events)
{
switch(evt.type)
{

@ -422,4 +422,10 @@ namespace Gui
align();
}
Spacer::Spacer()
{
setUserString("HStretch", "true");
setUserString("VStretch", "true");
}
}

@ -81,6 +81,15 @@ namespace Gui
bool mAutoResize; // auto resize the box so that it exactly fits all elements
};
class Spacer : public AutoSizedWidget, public MyGUI::Widget
{
MYGUI_RTTI_DERIVED( Spacer )
public:
Spacer();
virtual MyGUI::IntSize getRequestedSize() { return MyGUI::IntSize(0,0); }
};
class HBox : public Box, public MyGUI::Widget
{
MYGUI_RTTI_DERIVED( HBox )

@ -16,6 +16,7 @@ namespace Gui
{
MyGUI::FactoryManager::getInstance().registerFactory<Gui::MWList>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<Gui::HBox>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<Gui::Spacer>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<Gui::VBox>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<Gui::AutoSizedTextBox>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<Gui::AutoSizedEditBox>("Widget");

@ -1,3 +1,2 @@
breathe
parse_cmake
sphinx

@ -11,7 +11,6 @@
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import glob
import os
import sys
@ -21,12 +20,6 @@ import sys
project_root = os.path.abspath('../../')
sys.path.insert(0, project_root)
def insensitive_glob(pattern):
def either(c):
return '[%s%s]' % (c.lower(), c.upper()) if c.isalpha() else c
return glob.glob(''.join(map(either, pattern)))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
@ -43,37 +36,6 @@ extensions = [
'sphinx.ext.viewcode',
]
try:
import breathe
extensions.append('breathe')
except ImportError:
print("WARNING: Unable to import breathe, code documentation won't be generated.")
# Where breathe can find the source files
openmw_path = os.path.join(project_root, "apps", "openmw")
openmw_sub_dirs = os.walk(openmw_path).next()[1]
openmw_headers = insensitive_glob(os.path.join(openmw_path, "*.hpp"))
for dir in openmw_sub_dirs:
openmw_headers += insensitive_glob(os.path.join(openmw_path, dir, "*.hpp"))
# massage the headers to get the relative path needed
openmw_headers = [os.path.relpath(x, openmw_path) for x in openmw_headers]
opencs_path = os.path.join(project_root, "apps", "opencs")
opencs_sub_dirs = os.walk(opencs_path).next()[1]
opencs_headers = insensitive_glob(os.path.join(opencs_path, "*.hpp"))
opencs_sub_sub_dirs = []
for dir in opencs_sub_dirs:
opencs_headers += insensitive_glob(os.path.join(opencs_path, dir, "*.hpp"))
opencs_sub_sub_dirs += os.walk(os.path.join(opencs_path, dir)).next()[1]
for sub_dir in opencs_sub_sub_dirs:
opencs_headers += insensitive_glob(os.path.join(opencs_path, dir, sub_dir, "*.hpp"))
opencs_headers = [os.path.relpath(x, opencs_path) for x in opencs_headers]
breathe_projects_source = {
"openmw": (openmw_path, openmw_headers),
"opencs": (opencs_path, opencs_headers),
}
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
@ -88,7 +50,7 @@ master_doc = 'index'
# General information about the project.
project = u'OpenMW'
copyright = u'2016, OpenMW Team'
copyright = u'2017, OpenMW Team'
# The version info for the project you're documenting, acts as replacement for

@ -5,16 +5,7 @@ Sections
--------
.. toctree::
:maxdepth: 2
:maxdepth: 3
manuals/index
reference/index
source/index
Indices and Tables
==================
* :ref:`genindex`
* :ref:`search`

@ -1,8 +0,0 @@
Project Source Documentation
============================
.. toctree::
:maxdepth: 2
openmw/index
opencs/index

@ -1,11 +0,0 @@
OpenMW-CS Source Documentation
##############################
.. toctree::
:maxdepth: 2
model/index
view/index
.. autodoxygenfile:: editor.hpp
:project: opencs

@ -1,358 +0,0 @@
./opencs/model
##############
doc
---
.. autodoxygenfile:: model/doc/blacklist.hpp
:project: opencs
.. autodoxygenfile:: model/doc/document.hpp
:project: opencs
.. autodoxygenfile:: model/doc/documentmanager.hpp
:project: opencs
.. autodoxygenfile:: model/doc/loader.hpp
:project: opencs
.. autodoxygenfile:: model/doc/messages.hpp
:project: opencs
.. autodoxygenfile:: model/doc/operationholder.hpp
:project: opencs
.. autodoxygenfile:: model/doc/operation.hpp
:project: opencs
.. autodoxygenfile:: model/doc/runner.hpp
:project: opencs
.. autodoxygenfile:: model/doc/saving.hpp
:project: opencs
.. autodoxygenfile:: model/doc/savingstages.hpp
:project: opencs
.. autodoxygenfile:: model/doc/savingstate.hpp
:project: opencs
.. autodoxygenfile:: model/doc/stage.hpp
:project: opencs
.. autodoxygenfile:: model/doc/state.hpp
:project: opencs
filter
------
.. autodoxygenfile:: model/filter/andnode.hpp
:project: opencs
.. autodoxygenfile:: model/filter/booleannode.hpp
:project: opencs
.. autodoxygenfile:: model/filter/leafnode.hpp
:project: opencs
.. autodoxygenfile:: model/filter/narynode.hpp
:project: opencs
.. autodoxygenfile:: model/filter/node.hpp
:project: opencs
.. autodoxygenfile:: model/filter/notnode.hpp
:project: opencs
.. autodoxygenfile:: model/filter/ornode.hpp
:project: opencs
.. autodoxygenfile:: model/filter/parser.hpp
:project: opencs
.. autodoxygenfile:: model/filter/textnode.hpp
:project: opencs
.. autodoxygenfile:: model/filter/unarynode.hpp
:project: opencs
.. autodoxygenfile:: model/filter/valuenode.hpp
:project: opencs
prefs
-----
.. autodoxygenfile:: model/prefs/boolsetting.hpp
:project: opencs
.. autodoxygenfile:: model/prefs/category.hpp
:project: opencs
.. autodoxygenfile:: model/prefs/coloursetting.hpp
:project: opencs
.. autodoxygenfile:: model/prefs/doublesetting.hpp
:project: opencs
.. autodoxygenfile:: model/prefs/enumsetting.hpp
:project: opencs
.. autodoxygenfile:: model/prefs/intsetting.hpp
:project: opencs
.. autodoxygenfile:: model/prefs/modifiersetting.hpp
:project: opencs
.. autodoxygenfile:: model/prefs/setting.hpp
:project: opencs
.. autodoxygenfile:: model/prefs/shortcuteventhandler.hpp
:project: opencs
.. autodoxygenfile:: model/prefs/shortcut.hpp
:project: opencs
.. autodoxygenfile:: model/prefs/shortcutmanager.hpp
:project: opencs
.. autodoxygenfile:: model/prefs/shortcutsetting.hpp
:project: opencs
.. autodoxygenfile:: model/prefs/state.hpp
:project: opencs
tools
-----
.. autodoxygenfile:: model/tools/birthsigncheck.hpp
:project: opencs
.. autodoxygenfile:: model/tools/bodypartcheck.hpp
:project: opencs
.. autodoxygenfile:: model/tools/classcheck.hpp
:project: opencs
.. autodoxygenfile:: model/tools/factioncheck.hpp
:project: opencs
.. autodoxygenfile:: model/tools/gmstcheck.hpp
:project: opencs
.. autodoxygenfile:: model/tools/journalcheck.hpp
:project: opencs
.. autodoxygenfile:: model/tools/magiceffectcheck.hpp
:project: opencs
.. autodoxygenfile:: model/tools/mandatoryid.hpp
:project: opencs
.. autodoxygenfile:: model/tools/mergeoperation.hpp
:project: opencs
.. autodoxygenfile:: model/tools/mergestages.hpp
:project: opencs
.. autodoxygenfile:: model/tools/mergestate.hpp
:project: opencs
.. autodoxygenfile:: model/tools/pathgridcheck.hpp
:project: opencs
.. autodoxygenfile:: model/tools/racecheck.hpp
:project: opencs
.. autodoxygenfile:: model/tools/referenceablecheck.hpp
:project: opencs
.. autodoxygenfile:: model/tools/referencecheck.hpp
:project: opencs
.. autodoxygenfile:: model/tools/regioncheck.hpp
:project: opencs
.. autodoxygenfile:: model/tools/reportmodel.hpp
:project: opencs
.. autodoxygenfile:: model/tools/scriptcheck.hpp
:project: opencs
.. autodoxygenfile:: model/tools/search.hpp
:project: opencs
.. autodoxygenfile:: model/tools/searchoperation.hpp
:project: opencs
.. autodoxygenfile:: model/tools/searchstage.hpp
:project: opencs
.. autodoxygenfile:: model/tools/skillcheck.hpp
:project: opencs
.. autodoxygenfile:: model/tools/soundcheck.hpp
:project: opencs
.. autodoxygenfile:: model/tools/soundgencheck.hpp
:project: opencs
.. autodoxygenfile:: model/tools/spellcheck.hpp
:project: opencs
.. autodoxygenfile:: model/tools/startscriptcheck.hpp
:project: opencs
.. autodoxygenfile:: model/tools/tools.hpp
:project: opencs
.. autodoxygenfile:: model/tools/topicinfocheck.hpp
:project: opencs
world
-----
.. autodoxygenfile:: model/world/cellcoordinates.hpp
:project: opencs
.. autodoxygenfile:: model/world/cell.hpp
:project: opencs
.. autodoxygenfile:: model/world/cellselection.hpp
:project: opencs
.. autodoxygenfile:: model/world/collectionbase.hpp
:project: opencs
.. autodoxygenfile:: model/world/collection.hpp
:project: opencs
.. autodoxygenfile:: model/world/columnbase.hpp
:project: opencs
.. autodoxygenfile:: model/world/columnimp.hpp
:project: opencs
.. autodoxygenfile:: model/world/columns.hpp
:project: opencs
.. autodoxygenfile:: model/world/commanddispatcher.hpp
:project: opencs
.. autodoxygenfile:: model/world/commandmacro.hpp
:project: opencs
.. autodoxygenfile:: model/world/commands.hpp
:project: opencs
.. autodoxygenfile:: model/world/data.hpp
:project: opencs
.. autodoxygenfile:: model/world/defaultgmsts.hpp
:project: opencs
.. autodoxygenfile:: model/world/idcollection.hpp
:project: opencs
.. autodoxygenfile:: model/world/idcompletionmanager.hpp
:project: opencs
.. autodoxygenfile:: model/world/idtablebase.hpp
:project: opencs
.. autodoxygenfile:: model/world/idtable.hpp
:project: opencs
.. autodoxygenfile:: model/world/idtableproxymodel.hpp
:project: opencs
.. autodoxygenfile:: model/world/idtree.hpp
:project: opencs
.. autodoxygenfile:: model/world/infocollection.hpp
:project: opencs
.. autodoxygenfile:: model/world/info.hpp
:project: opencs
.. autodoxygenfile:: model/world/infoselectwrapper.hpp
:project: opencs
.. autodoxygenfile:: model/world/infotableproxymodel.hpp
:project: opencs
.. autodoxygenfile:: model/world/land.hpp
:project: opencs
.. autodoxygenfile:: model/world/landtexture.hpp
:project: opencs
.. autodoxygenfile:: model/world/metadata.hpp
:project: opencs
.. autodoxygenfile:: model/world/nestedcoladapterimp.hpp
:project: opencs
.. autodoxygenfile:: model/world/nestedcollection.hpp
:project: opencs
.. autodoxygenfile:: model/world/nestedcolumnadapter.hpp
:project: opencs
.. autodoxygenfile:: model/world/nestedidcollection.hpp
:project: opencs
.. autodoxygenfile:: model/world/nestedinfocollection.hpp
:project: opencs
.. autodoxygenfile:: model/world/nestedtableproxymodel.hpp
:project: opencs
.. autodoxygenfile:: model/world/nestedtablewrapper.hpp
:project: opencs
.. autodoxygenfile:: model/world/pathgrid.hpp
:project: opencs
.. autodoxygenfile:: model/world/record.hpp
:project: opencs
.. autodoxygenfile:: model/world/refcollection.hpp
:project: opencs
.. autodoxygenfile:: model/world/ref.hpp
:project: opencs
.. autodoxygenfile:: model/world/refidadapter.hpp
:project: opencs
.. autodoxygenfile:: model/world/refidadapterimp.hpp
:project: opencs
.. autodoxygenfile:: model/world/refidcollection.hpp
:project: opencs
.. autodoxygenfile:: model/world/refiddata.hpp
:project: opencs
.. autodoxygenfile:: model/world/regionmap.hpp
:project: opencs
.. autodoxygenfile:: model/world/resources.hpp
:project: opencs
.. autodoxygenfile:: model/world/resourcesmanager.hpp
:project: opencs
.. autodoxygenfile:: model/world/resourcetable.hpp
:project: opencs
.. autodoxygenfile:: model/world/scope.hpp
:project: opencs
.. autodoxygenfile:: model/world/scriptcontext.hpp
:project: opencs
.. autodoxygenfile:: model/world/subcellcollection.hpp
:project: opencs
.. autodoxygenfile:: model/world/tablemimedata.hpp
:project: opencs
.. autodoxygenfile:: model/world/universalid.hpp
:project: opencs

@ -1,340 +0,0 @@
./opencs/view
#############
doc
---
.. autodoxygenfile:: view/doc/adjusterwidget.hpp
:project: opencs
.. autodoxygenfile:: view/doc/filedialog.hpp
:project: opencs
.. autodoxygenfile:: view/doc/filewidget.hpp
:project: opencs
.. autodoxygenfile:: view/doc/globaldebugprofilemenu.hpp
:project: opencs
.. autodoxygenfile:: view/doc/loader.hpp
:project: opencs
.. autodoxygenfile:: view/doc/newgame.hpp
:project: opencs
.. autodoxygenfile:: view/doc/operation.hpp
:project: opencs
.. autodoxygenfile:: view/doc/operations.hpp
:project: opencs
.. autodoxygenfile:: view/doc/runlogsubview.hpp
:project: opencs
.. autodoxygenfile:: view/doc/sizehint.hpp
:project: opencs
.. autodoxygenfile:: view/doc/startup.hpp
:project: opencs
.. autodoxygenfile:: view/doc/subviewfactory.hpp
:project: opencs
.. autodoxygenfile:: view/doc/subviewfactoryimp.hpp
:project: opencs
.. autodoxygenfile:: view/doc/subview.hpp
:project: opencs
.. autodoxygenfile:: view/doc/view.hpp
:project: opencs
.. autodoxygenfile:: view/doc/viewmanager.hpp
:project: opencs
filter
------
.. autodoxygenfile:: view/filter/editwidget.hpp
:project: opencs
.. autodoxygenfile:: view/filter/filterbox.hpp
:project: opencs
.. autodoxygenfile:: view/filter/recordfilterbox.hpp
:project: opencs
prefs
-----
.. autodoxygenfile:: view/prefs/dialogue.hpp
:project: opencs
.. autodoxygenfile:: view/prefs/keybindingpage.hpp
:project: opencs
.. autodoxygenfile:: view/prefs/pagebase.hpp
:project: opencs
.. autodoxygenfile:: view/prefs/page.hpp
:project: opencs
render
------
.. autodoxygenfile:: view/render/cameracontroller.hpp
:project: opencs
.. autodoxygenfile:: view/render/cellarrow.hpp
:project: opencs
.. autodoxygenfile:: view/render/cellborder.hpp
:project: opencs
.. autodoxygenfile:: view/render/cell.hpp
:project: opencs
.. autodoxygenfile:: view/render/cellmarker.hpp
:project: opencs
.. autodoxygenfile:: view/render/cellwater.hpp
:project: opencs
.. autodoxygenfile:: view/render/editmode.hpp
:project: opencs
.. autodoxygenfile:: view/render/instancemode.hpp
:project: opencs
.. autodoxygenfile:: view/render/instancemovemode.hpp
:project: opencs
.. autodoxygenfile:: view/render/instanceselectionmode.hpp
:project: opencs
.. autodoxygenfile:: view/render/lightingbright.hpp
:project: opencs
.. autodoxygenfile:: view/render/lightingday.hpp
:project: opencs
.. autodoxygenfile:: view/render/lighting.hpp
:project: opencs
.. autodoxygenfile:: view/render/lightingnight.hpp
:project: opencs
.. autodoxygenfile:: view/render/mask.hpp
:project: opencs
.. autodoxygenfile:: view/render/object.hpp
:project: opencs
.. autodoxygenfile:: view/render/orbitcameramode.hpp
:project: opencs
.. autodoxygenfile:: view/render/pagedworldspacewidget.hpp
:project: opencs
.. autodoxygenfile:: view/render/pathgrid.hpp
:project: opencs
.. autodoxygenfile:: view/render/pathgridmode.hpp
:project: opencs
.. autodoxygenfile:: view/render/pathgridselectionmode.hpp
:project: opencs
.. autodoxygenfile:: view/render/previewwidget.hpp
:project: opencs
.. autodoxygenfile:: view/render/scenewidget.hpp
:project: opencs
.. autodoxygenfile:: view/render/selectionmode.hpp
:project: opencs
.. autodoxygenfile:: view/render/tagbase.hpp
:project: opencs
.. autodoxygenfile:: view/render/terrainstorage.hpp
:project: opencs
.. autodoxygenfile:: view/render/unpagedworldspacewidget.hpp
:project: opencs
.. autodoxygenfile:: view/render/worldspacewidget.hpp
:project: opencs
tools
-----
.. autodoxygenfile:: view/tools/merge.hpp
:project: opencs
.. autodoxygenfile:: view/tools/reportsubview.hpp
:project: opencs
.. autodoxygenfile:: view/tools/reporttable.hpp
:project: opencs
.. autodoxygenfile:: view/tools/searchbox.hpp
:project: opencs
.. autodoxygenfile:: view/tools/searchsubview.hpp
:project: opencs
.. autodoxygenfile:: view/tools/subviews.hpp
:project: opencs
widget
------
.. autodoxygenfile:: view/widget/coloreditor.hpp
:project: opencs
.. autodoxygenfile:: view/widget/colorpickerpopup.hpp
:project: opencs
.. autodoxygenfile:: view/widget/completerpopup.hpp
:project: opencs
.. autodoxygenfile:: view/widget/droplineedit.hpp
:project: opencs
.. autodoxygenfile:: view/widget/modebutton.hpp
:project: opencs
.. autodoxygenfile:: view/widget/pushbutton.hpp
:project: opencs
.. autodoxygenfile:: view/widget/scenetoolbar.hpp
:project: opencs
.. autodoxygenfile:: view/widget/scenetool.hpp
:project: opencs
.. autodoxygenfile:: view/widget/scenetoolmode.hpp
:project: opencs
.. autodoxygenfile:: view/widget/scenetoolrun.hpp
:project: opencs
.. autodoxygenfile:: view/widget/scenetooltoggle2.hpp
:project: opencs
.. autodoxygenfile:: view/widget/scenetooltoggle.hpp
:project: opencs
world
-----
.. autodoxygenfile:: view/world/cellcreator.hpp
:project: opencs
.. autodoxygenfile:: view/world/colordelegate.hpp
:project: opencs
.. autodoxygenfile:: view/world/creator.hpp
:project: opencs
.. autodoxygenfile:: view/world/datadisplaydelegate.hpp
:project: opencs
.. autodoxygenfile:: view/world/dialoguecreator.hpp
:project: opencs
.. autodoxygenfile:: view/world/dialoguespinbox.hpp
:project: opencs
.. autodoxygenfile:: view/world/dialoguesubview.hpp
:project: opencs
.. autodoxygenfile:: view/world/dragdroputils.hpp
:project: opencs
.. autodoxygenfile:: view/world/dragrecordtable.hpp
:project: opencs
.. autodoxygenfile:: view/world/enumdelegate.hpp
:project: opencs
.. autodoxygenfile:: view/world/extendedcommandconfigurator.hpp
:project: opencs
.. autodoxygenfile:: view/world/genericcreator.hpp
:project: opencs
.. autodoxygenfile:: view/world/globalcreator.hpp
:project: opencs
.. autodoxygenfile:: view/world/idcompletiondelegate.hpp
:project: opencs
.. autodoxygenfile:: view/world/idtypedelegate.hpp
:project: opencs
.. autodoxygenfile:: view/world/idvalidator.hpp
:project: opencs
.. autodoxygenfile:: view/world/infocreator.hpp
:project: opencs
.. autodoxygenfile:: view/world/nestedtable.hpp
:project: opencs
.. autodoxygenfile:: view/world/pathgridcreator.hpp
:project: opencs
.. autodoxygenfile:: view/world/previewsubview.hpp
:project: opencs
.. autodoxygenfile:: view/world/recordbuttonbar.hpp
:project: opencs
.. autodoxygenfile:: view/world/recordstatusdelegate.hpp
:project: opencs
.. autodoxygenfile:: view/world/referenceablecreator.hpp
:project: opencs
.. autodoxygenfile:: view/world/referencecreator.hpp
:project: opencs
.. autodoxygenfile:: view/world/regionmap.hpp
:project: opencs
.. autodoxygenfile:: view/world/regionmapsubview.hpp
:project: opencs
.. autodoxygenfile:: view/world/scenesubview.hpp
:project: opencs
.. autodoxygenfile:: view/world/scriptedit.hpp
:project: opencs
.. autodoxygenfile:: view/world/scripterrortable.hpp
:project: opencs
.. autodoxygenfile:: view/world/scripthighlighter.hpp
:project: opencs
.. autodoxygenfile:: view/world/scriptsubview.hpp
:project: opencs
.. autodoxygenfile:: view/world/startscriptcreator.hpp
:project: opencs
.. autodoxygenfile:: view/world/subviews.hpp
:project: opencs
.. autodoxygenfile:: view/world/tablebottombox.hpp
:project: opencs
.. autodoxygenfile:: view/world/tableeditidaction.hpp
:project: opencs
.. autodoxygenfile:: view/world/table.hpp
:project: opencs
.. autodoxygenfile:: view/world/tablesubview.hpp
:project: opencs
.. autodoxygenfile:: view/world/util.hpp
:project: opencs
.. autodoxygenfile:: view/world/vartypedelegate.hpp
:project: opencs

@ -1,24 +0,0 @@
OpenMW Source Documentation
###########################
.. toctree::
:maxdepth: 2
mwbase
mwclass
mwdialogue
mwgui
mwinput
mwmechanics
mwphysics
mwrender
mwscript
mwsound
mwstate
mwworld
.. autodoxygenfile:: engine.hpp
:project: openmw
.. autodoxygenfile:: doc.hpp
:project: openmw

@ -1,32 +0,0 @@
./mwbase
########
.. autodoxygenfile:: mwbase/dialoguemanager.hpp
:project: openmw
.. autodoxygenfile:: mwbase/environment.hpp
:project: openmw
.. autodoxygenfile:: mwbase/inputmanager.hpp
:project: openmw
.. autodoxygenfile:: mwbase/journal.hpp
:project: openmw
.. autodoxygenfile:: mwbase/mechanicsmanager.hpp
:project: openmw
.. autodoxygenfile:: mwbase/scriptmanager.hpp
:project: openmw
.. autodoxygenfile:: mwbase/soundmanager.hpp
:project: openmw
.. autodoxygenfile:: mwbase/statemanager.hpp
:project: openmw
.. autodoxygenfile:: mwbase/windowmanager.hpp
:project: openmw
.. autodoxygenfile:: mwbase/world.hpp
:project: openmw

@ -1,68 +0,0 @@
./mwclass
#########
.. autodoxygenfile:: mwclass/activator.hpp
:project: openmw
.. autodoxygenfile:: mwclass/actor.hpp
:project: openmw
.. autodoxygenfile:: mwclass/apparatus.hpp
:project: openmw
.. autodoxygenfile:: mwclass/armor.hpp
:project: openmw
.. autodoxygenfile:: mwclass/bodypart.hpp
:project: openmw
.. autodoxygenfile:: mwclass/book.hpp
:project: openmw
.. autodoxygenfile:: mwclass/classes.hpp
:project: openmw
.. autodoxygenfile:: mwclass/clothing.hpp
:project: openmw
.. autodoxygenfile:: mwclass/container.hpp
:project: openmw
.. autodoxygenfile:: mwclass/creature.hpp
:project: openmw
.. autodoxygenfile:: mwclass/creaturelevlist.hpp
:project: openmw
.. autodoxygenfile:: mwclass/ingredient.hpp
:project: openmw
.. autodoxygenfile:: mwclass/itemlevlist.hpp
:project: openmw
.. autodoxygenfile:: mwclass/light.hpp
:project: openmw
.. autodoxygenfile:: mwclass/lockpick.hpp
:project: openmw
.. autodoxygenfile:: mwclass/misc.hpp
:project: openmw
.. autodoxygenfile:: mwclass/npc.hpp
:project: openmw
.. autodoxygenfile:: mwclass/potion.hpp
:project: openmw
.. autodoxygenfile:: mwclass/probe.hpp
:project: openmw
.. autodoxygenfile:: mwclass/repair.hpp
:project: openmw
.. autodoxygenfile:: mwclass/static.hpp
:project: openmw
.. autodoxygenfile:: mwclass/weapon.hpp
:project: openmw

@ -1,32 +0,0 @@
./mwdialogue
############
.. autodoxygenfile:: mwdialogue/dialoguemanagerimp.hpp
:project: openmw
.. autodoxygenfile:: mwdialogue/filter.hpp
:project: openmw
.. autodoxygenfile:: mwdialogue/hypertextparser.hpp
:project: openmw
.. autodoxygenfile:: mwdialogue/journalentry.hpp
:project: openmw
.. autodoxygenfile:: mwdialogue/journalimp.hpp
:project: openmw
.. autodoxygenfile:: mwdialogue/keywordsearch.hpp
:project: openmw
.. autodoxygenfile:: mwdialogue/quest.hpp
:project: openmw
.. autodoxygenfile:: mwdialogue/scripttest.hpp
:project: openmw
.. autodoxygenfile:: mwdialogue/selectwrapper.hpp
:project: openmw
.. autodoxygenfile:: mwdialogue/topic.hpp
:project: openmw

@ -1,227 +0,0 @@
./mwgui
#######
.. autodoxygenfile:: mwgui/alchemywindow.hpp
:project: openmw
.. autodoxygenfile:: mwgui/backgroundimage.hpp
:project: openmw
.. autodoxygenfile:: mwgui/birth.hpp
:project: openmw
.. autodoxygenfile:: mwgui/bookpage.hpp
:project: openmw
.. autodoxygenfile:: mwgui/bookwindow.hpp
:project: openmw
.. autodoxygenfile:: mwgui/charactercreation.hpp
:project: openmw
.. autodoxygenfile:: mwgui/class.hpp
:project: openmw
.. autodoxygenfile:: mwgui/companionitemmodel.hpp
:project: openmw
.. autodoxygenfile:: mwgui/companionwindow.hpp
:project: openmw
.. autodoxygenfile:: mwgui/confirmationdialog.hpp
:project: openmw
.. autodoxygenfile:: mwgui/console.hpp
:project: openmw
.. autodoxygenfile:: mwgui/container.hpp
:project: openmw
.. autodoxygenfile:: mwgui/containeritemmodel.hpp
:project: openmw
.. autodoxygenfile:: mwgui/controllers.hpp
:project: openmw
.. autodoxygenfile:: mwgui/countdialog.hpp
:project: openmw
.. autodoxygenfile:: mwgui/cursor.hpp
:project: openmw
.. autodoxygenfile:: mwgui/debugwindow.hpp
:project: openmw
.. autodoxygenfile:: mwgui/dialogue.hpp
:project: openmw
.. autodoxygenfile:: mwgui/draganddrop.hpp
:project: openmw
.. autodoxygenfile:: mwgui/enchantingdialog.hpp
:project: openmw
.. autodoxygenfile:: mwgui/exposedwindow.hpp
:project: openmw
.. autodoxygenfile:: mwgui/formatting.hpp
:project: openmw
.. autodoxygenfile:: mwgui/hud.hpp
:project: openmw
.. autodoxygenfile:: mwgui/inventoryitemmodel.hpp
:project: openmw
.. autodoxygenfile:: mwgui/inventorywindow.hpp
:project: openmw
.. autodoxygenfile:: mwgui/itemchargeview.hpp
:project: openmw
.. autodoxygenfile:: mwgui/itemmodel.hpp
:project: openmw
.. autodoxygenfile:: mwgui/itemselection.hpp
:project: openmw
.. autodoxygenfile:: mwgui/itemview.hpp
:project: openmw
.. autodoxygenfile:: mwgui/itemwidget.hpp
:project: openmw
.. autodoxygenfile:: mwgui/jailscreen.hpp
:project: openmw
.. autodoxygenfile:: mwgui/journalbooks.hpp
:project: openmw
.. autodoxygenfile:: mwgui/journalviewmodel.hpp
:project: openmw
.. autodoxygenfile:: mwgui/journalwindow.hpp
:project: openmw
.. autodoxygenfile:: mwgui/layout.hpp
:project: openmw
.. autodoxygenfile:: mwgui/levelupdialog.hpp
:project: openmw
.. autodoxygenfile:: mwgui/loadingscreen.hpp
:project: openmw
.. autodoxygenfile:: mwgui/mainmenu.hpp
:project: openmw
.. autodoxygenfile:: mwgui/mapwindow.hpp
:project: openmw
.. autodoxygenfile:: mwgui/merchantrepair.hpp
:project: openmw
.. autodoxygenfile:: mwgui/messagebox.hpp
:project: openmw
.. autodoxygenfile:: mwgui/mode.hpp
:project: openmw
.. autodoxygenfile:: mwgui/pickpocketitemmodel.hpp
:project: openmw
.. autodoxygenfile:: mwgui/quickkeysmenu.hpp
:project: openmw
.. autodoxygenfile:: mwgui/race.hpp
:project: openmw
.. autodoxygenfile:: mwgui/recharge.hpp
:project: openmw
.. autodoxygenfile:: mwgui/referenceinterface.hpp
:project: openmw
.. autodoxygenfile:: mwgui/repair.hpp
:project: openmw
.. autodoxygenfile:: mwgui/review.hpp
:project: openmw
.. autodoxygenfile:: mwgui/savegamedialog.hpp
:project: openmw
.. autodoxygenfile:: mwgui/screenfader.hpp
:project: openmw
.. autodoxygenfile:: mwgui/scrollwindow.hpp
:project: openmw
.. autodoxygenfile:: mwgui/settingswindow.hpp
:project: openmw
.. autodoxygenfile:: mwgui/sortfilteritemmodel.hpp
:project: openmw
.. autodoxygenfile:: mwgui/soulgemdialog.hpp
:project: openmw
.. autodoxygenfile:: mwgui/spellbuyingwindow.hpp
:project: openmw
.. autodoxygenfile:: mwgui/spellcreationdialog.hpp
:project: openmw
.. autodoxygenfile:: mwgui/spellicons.hpp
:project: openmw
.. autodoxygenfile:: mwgui/spellmodel.hpp
:project: openmw
.. autodoxygenfile:: mwgui/spellview.hpp
:project: openmw
.. autodoxygenfile:: mwgui/spellwindow.hpp
:project: openmw
.. autodoxygenfile:: mwgui/statswindow.hpp
:project: openmw
.. autodoxygenfile:: mwgui/textinput.hpp
:project: openmw
.. autodoxygenfile:: mwgui/timeadvancer.hpp
:project: openmw
.. autodoxygenfile:: mwgui/tooltips.hpp
:project: openmw
.. autodoxygenfile:: mwgui/tradeitemmodel.hpp
:project: openmw
.. autodoxygenfile:: mwgui/tradewindow.hpp
:project: openmw
.. autodoxygenfile:: mwgui/trainingwindow.hpp
:project: openmw
.. autodoxygenfile:: mwgui/travelwindow.hpp
:project: openmw
.. autodoxygenfile:: mwgui/videowidget.hpp
:project: openmw
.. autodoxygenfile:: mwgui/waitdialog.hpp
:project: openmw
.. autodoxygenfile:: mwgui/widgets.hpp
:project: openmw
.. autodoxygenfile:: mwgui/windowbase.hpp
:project: openmw
.. autodoxygenfile:: mwgui/windowmanagerimp.hpp
:project: openmw
.. autodoxygenfile:: mwgui/windowpinnablebase.hpp
:project: openmw

@ -1,5 +0,0 @@
./mwinput
#########
.. autodoxygenfile:: mwinput/inputmanagerimp.hpp
:project: openmw

@ -1,137 +0,0 @@
./mwmechanics
#############
.. autodoxygenfile:: mwmechanics/activespells.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/actor.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/actors.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/actorutil.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/aiactivate.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/aiavoiddoor.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/aicombataction.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/aicombat.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/aiescort.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/aiface.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/aifollow.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/aipackage.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/aipursue.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/aisequence.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/aistate.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/aitravel.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/aiwander.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/alchemy.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/autocalcspell.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/character.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/combat.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/coordinateconverter.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/creaturestats.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/difficultyscaling.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/disease.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/drawstate.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/enchanting.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/levelledlist.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/magiceffects.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/mechanicsmanagerimp.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/movement.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/npcstats.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/objects.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/obstacle.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/pathfinding.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/pathgrid.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/pickpocket.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/repair.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/security.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/spellcasting.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/spells.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/stat.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/steering.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/summoning.hpp
:project: openmw
.. autodoxygenfile:: mwmechanics/trading.hpp
:project: openmw

@ -1,15 +0,0 @@
./mwphysics
###########
.. autodoxygenfile:: mwphysics/actor.hpp
:project: openmw
.. autodoxygenfile:: mwphysics/collisiontype.hpp
:project: openmw
.. autodoxygenfile:: mwphysics/convert.hpp
:project: openmw
.. autodoxygenfile:: mwphysics/physicssystem.hpp
:project: openmw

@ -1,77 +0,0 @@
./mwrender
##########
.. autodoxygenfile:: mwrender/actoranimation.hpp
:project: openmw
.. autodoxygenfile:: mwrender/animation.hpp
:project: openmw
.. autodoxygenfile:: mwrender/bulletdebugdraw.hpp
:project: openmw
.. autodoxygenfile:: mwrender/camera.hpp
:project: openmw
.. autodoxygenfile:: mwrender/cell.hpp
:project: openmw
.. autodoxygenfile:: mwrender/characterpreview.hpp
:project: openmw
.. autodoxygenfile:: mwrender/creatureanimation.hpp
:project: openmw
.. autodoxygenfile:: mwrender/effectmanager.hpp
:project: openmw
.. autodoxygenfile:: mwrender/globalmap.hpp
:project: openmw
.. autodoxygenfile:: mwrender/localmap.hpp
:project: openmw
.. autodoxygenfile:: mwrender/npcanimation.hpp
:project: openmw
.. autodoxygenfile:: mwrender/objects.hpp
:project: openmw
.. autodoxygenfile:: mwrender/pathgrid.hpp
:project: openmw
.. autodoxygenfile:: mwrender/renderbin.hpp
:project: openmw
.. autodoxygenfile:: mwrender/renderinginterface.hpp
:project: openmw
.. autodoxygenfile:: mwrender/renderingmanager.hpp
:project: openmw
.. autodoxygenfile:: mwrender/rendermode.hpp
:project: openmw
.. autodoxygenfile:: mwrender/ripplesimulation.hpp
:project: openmw
.. autodoxygenfile:: mwrender/rotatecontroller.hpp
:project: openmw
.. autodoxygenfile:: mwrender/sky.hpp
:project: openmw
.. autodoxygenfile:: mwrender/terrainstorage.hpp
:project: openmw
.. autodoxygenfile:: mwrender/util.hpp
:project: openmw
.. autodoxygenfile:: mwrender/vismask.hpp
:project: openmw
.. autodoxygenfile:: mwrender/water.hpp
:project: openmw
.. autodoxygenfile:: mwrender/weaponanimation.hpp
:project: openmw

@ -1,65 +0,0 @@
./mwscript
##########
.. autodoxygenfile:: mwscript/aiextensions.hpp
:project: openmw
.. autodoxygenfile:: mwscript/animationextensions.hpp
:project: openmw
.. autodoxygenfile:: mwscript/cellextensions.hpp
:project: openmw
.. autodoxygenfile:: mwscript/compilercontext.hpp
:project: openmw
.. autodoxygenfile:: mwscript/consoleextensions.hpp
:project: openmw
.. autodoxygenfile:: mwscript/containerextensions.hpp
:project: openmw
.. autodoxygenfile:: mwscript/controlextensions.hpp
:project: openmw
.. autodoxygenfile:: mwscript/dialogueextensions.hpp
:project: openmw
.. autodoxygenfile:: mwscript/extensions.hpp
:project: openmw
.. autodoxygenfile:: mwscript/globalscripts.hpp
:project: openmw
.. autodoxygenfile:: mwscript/guiextensions.hpp
:project: openmw
.. autodoxygenfile:: mwscript/interpretercontext.hpp
:project: openmw
.. autodoxygenfile:: mwscript/locals.hpp
:project: openmw
.. autodoxygenfile:: mwscript/miscextensions.hpp
:project: openmw
.. autodoxygenfile:: mwscript/ref.hpp
:project: openmw
.. autodoxygenfile:: mwscript/scriptmanagerimp.hpp
:project: openmw
.. autodoxygenfile:: mwscript/skyextensions.hpp
:project: openmw
.. autodoxygenfile:: mwscript/soundextensions.hpp
:project: openmw
.. autodoxygenfile:: mwscript/statsextensions.hpp
:project: openmw
.. autodoxygenfile:: mwscript/transformationextensions.hpp
:project: openmw
.. autodoxygenfile:: mwscript/userextensions.hpp
:project: openmw

@ -1,29 +0,0 @@
./mwsound
#########
.. autodoxygenfile:: mwsound/ffmpeg_decoder.hpp
:project: openmw
.. autodoxygenfile:: mwsound/loudness.hpp
:project: openmw
.. autodoxygenfile:: mwsound/movieaudiofactory.hpp
:project: openmw
.. autodoxygenfile:: mwsound/openal_output.hpp
:project: openmw
.. autodoxygenfile:: mwsound/sound_buffer.hpp
:project: openmw
.. autodoxygenfile:: mwsound/sound_decoder.hpp
:project: openmw
.. autodoxygenfile:: mwsound/sound.hpp
:project: openmw
.. autodoxygenfile:: mwsound/soundmanagerimp.hpp
:project: openmw
.. autodoxygenfile:: mwsound/sound_output.hpp
:project: openmw

@ -1,11 +0,0 @@
./mwstate
#########
.. autodoxygenfile:: mwstate/character.hpp
:project: openmw
.. autodoxygenfile:: mwstate/charactermanager.hpp
:project: openmw
.. autodoxygenfile:: mwstate/statemanagerimp.hpp
:project: openmw

@ -1,132 +0,0 @@
./mwworld
#########
.. autodoxygenfile:: mwworld/actionalchemy.hpp
:project: openmw
.. autodoxygenfile:: mwworld/actionapply.hpp
:project: openmw
.. autodoxygenfile:: mwworld/actiondoor.hpp
:project: openmw
.. autodoxygenfile:: mwworld/actioneat.hpp
:project: openmw
.. autodoxygenfile:: mwworld/actionequip.hpp
:project: openmw
.. autodoxygenfile:: mwworld/action.hpp
:project: openmw
.. autodoxygenfile:: mwworld/actionopen.hpp
:project: openmw
.. autodoxygenfile:: mwworld/actionread.hpp
:project: openmw
.. autodoxygenfile:: mwworld/actionrepair.hpp
:project: openmw
.. autodoxygenfile:: mwworld/actionsoulgem.hpp
:project: openmw
.. autodoxygenfile:: mwworld/actiontake.hpp
:project: openmw
.. autodoxygenfile:: mwworld/actiontalk.hpp
:project: openmw
.. autodoxygenfile:: mwworld/actionteleport.hpp
:project: openmw
.. autodoxygenfile:: mwworld/actiontrap.hpp
:project: openmw
.. autodoxygenfile:: mwworld/cellpreloader.hpp
:project: openmw
.. autodoxygenfile:: mwworld/cellref.hpp
:project: openmw
.. autodoxygenfile:: mwworld/cellreflist.hpp
:project: openmw
.. autodoxygenfile:: mwworld/cells.hpp
:project: openmw
.. autodoxygenfile:: mwworld/cellstore.hpp
:project: openmw
.. autodoxygenfile:: mwworld/cellvisitors.hpp
:project: openmw
.. autodoxygenfile:: mwworld/class.hpp
:project: openmw
.. autodoxygenfile:: mwworld/containerstore.hpp
:project: openmw
.. autodoxygenfile:: mwworld/contentloader.hpp
:project: openmw
.. autodoxygenfile:: mwworld/customdata.hpp
:project: openmw
.. autodoxygenfile:: mwworld/esmloader.hpp
:project: openmw
.. autodoxygenfile:: mwworld/esmstore.hpp
:project: openmw
.. autodoxygenfile:: mwworld/failedaction.hpp
:project: openmw
.. autodoxygenfile:: mwworld/globals.hpp
:project: openmw
.. autodoxygenfile:: mwworld/inventorystore.hpp
:project: openmw
.. autodoxygenfile:: mwworld/livecellref.hpp
:project: openmw
.. autodoxygenfile:: mwworld/localscripts.hpp
:project: openmw
.. autodoxygenfile:: mwworld/manualref.hpp
:project: openmw
.. autodoxygenfile:: mwworld/nullaction.hpp
:project: openmw
.. autodoxygenfile:: mwworld/player.hpp
:project: openmw
.. autodoxygenfile:: mwworld/projectilemanager.hpp
:project: openmw
.. autodoxygenfile:: mwworld/ptr.hpp
:project: openmw
.. autodoxygenfile:: mwworld/recordcmp.hpp
:project: openmw
.. autodoxygenfile:: mwworld/refdata.hpp
:project: openmw
.. autodoxygenfile:: mwworld/scene.hpp
:project: openmw
.. autodoxygenfile:: mwworld/store.hpp
:project: openmw
.. autodoxygenfile:: mwworld/timestamp.hpp
:project: openmw
.. autodoxygenfile:: mwworld/weather.hpp
:project: openmw
.. autodoxygenfile:: mwworld/worldimp.hpp
:project: openmw

@ -0,0 +1,2 @@
[Paths]
Plugins = PlugIns

@ -10,9 +10,7 @@
</Widget>
<Widget type="HBox" position="0 235 580 24" align="Right Bottom">
<Widget type="Widget">
<UserString key="HStretch" value="true"/>
</Widget>
<Widget type="Spacer"/>
<Widget type="AutoSizedButton" skin="MW_Button" name="DisposeCorpseButton" align="Right Bottom">
<Property key="Caption" value="#{sDisposeofCorpse}"/>
<Property key="Visible" value="false"/>

@ -16,13 +16,15 @@
<Property key="Page" value="1"/>
<Property key="WheelPage" value="1"/>
</Widget>
<Widget type="HBox" skin="" position="0 91 140 24" align="Center Bottom">
<Widget type="AutoSizedButton" skin="MW_Button" position="0 0 53 24" align="Center Top" name="OkButton">
<Widget type="HBox" skin="" position="0 91 592 24" align="Center Bottom HStretch">
<Widget type="Spacer" />
<Widget type="AutoSizedButton" skin="MW_Button" position="0 0 53 24" align="Left Top" name="OkButton">
<Property key="Caption" value="#{sOk}"/>
</Widget>
<Widget type="AutoSizedButton" skin="MW_Button" position="0 0 86 24" align="Center Top" name="CancelButton">
<Widget type="AutoSizedButton" skin="MW_Button" position="0 0 86 24" align="Right Top" name="CancelButton">
<Property key="Caption" value="#{sCancel}"/>
</Widget>
<Widget type="Spacer" />
</Widget>
</Widget>
<CodeGeneratorSettings/>

@ -3,6 +3,7 @@
<MyGUI type="Layout">
<Widget type="Window" skin="" layer="JournalBooks" align="Left|Top" position="0 0 565 390" name="_Main">
<Property key="NeedKey" value="false"/>
<!-- pages -->
<Widget type="ImageBox" skin="ImageBox" position="-70 0 705 390" align="Top|Right" name="JImage">
<Property key="ImageTexture" value="textures\tx_menubook.dds"/>

@ -7,13 +7,13 @@
<x>0</x>
<y>0</y>
<width>635</width>
<height>575</height>
<height>565</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>635</width>
<height>535</height>
<height>565</height>
</size>
</property>
<property name="windowTitle">
@ -57,6 +57,18 @@
<string/>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QStackedWidget" name="pagesWidget"/>
</item>

@ -53,7 +53,7 @@
</property>
<layout class="QGridLayout" name="gridLayout_3" columnstretch="1,1">
<item row="1" column="1">
<spacer name="horizontalSpacer">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@ -115,7 +115,7 @@
<item>
<layout class="QGridLayout" name="gridLayout_4" columnstretch="1,1">
<item row="2" column="1">
<spacer name="horizontalSpacer_2">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@ -134,15 +134,18 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QProgressBar" name="progressBar">
<property name="maximum">
<number>4</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QProgressBar" name="progressBar">
<property name="maximum">
<number>4</number>
</property>
<property name="textVisible">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>

Loading…
Cancel
Save