forked from mirror/openmw-tes3mp
Merge remote-tracking branch 'upstream/master' into bugfix-3617
This commit is contained in:
commit
e82d542d89
66 changed files with 1722 additions and 282 deletions
|
@ -1,7 +1,7 @@
|
|||
os:
|
||||
- linux
|
||||
# - osx
|
||||
osx_image: xcode7.2
|
||||
- osx
|
||||
osx_image: xcode8.2
|
||||
language: cpp
|
||||
sudo: required
|
||||
dist: trusty
|
||||
|
@ -15,6 +15,7 @@ env:
|
|||
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||
# via the "travis encrypt" command using the project repo's public key
|
||||
- secure: "jybGzAdUbqt9vWR/GEnRd96BgAi/7Zd1+2HK68j/i/8+/1YH2XxLOy4Jv/DUBhBlJIkxs/Xv8dRcUlFOclZDHX1d/9Qnsqd3oUVkD7k1y7cTOWy9TBQaE/v/kZo3LpzA3xPwwthrb0BvqIbOfIELi5fS5s8ba85WFRg3AX70wWE="
|
||||
- macos_qt_formula=qt@5.5
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
|
@ -62,9 +63,9 @@ script:
|
|||
- if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi
|
||||
- if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi
|
||||
notifications:
|
||||
recipients:
|
||||
- corrmage+travis-ci@gmail.com
|
||||
email:
|
||||
recipients:
|
||||
- corrmage+travis-ci@gmail.com
|
||||
on_success: change
|
||||
on_failure: always
|
||||
irc:
|
||||
|
|
|
@ -71,6 +71,7 @@ Programmers
|
|||
John Blomberg (fstp)
|
||||
Jordan Ayers
|
||||
Jordan Milne
|
||||
Jules Blok (Armada651)
|
||||
Julien Voisin (jvoisin/ap0)
|
||||
Karl-Felix Glatzer (k1ll)
|
||||
Kevin Poitra (PuppyKevin)
|
||||
|
@ -80,6 +81,7 @@ Programmers
|
|||
lazydev
|
||||
Leon Krieg (lkrieg)
|
||||
Leon Saunders (emoose)
|
||||
logzero
|
||||
lohikaarme
|
||||
Lukasz Gromanowski (lgro)
|
||||
Manuel Edelmann (vorenon)
|
||||
|
|
75
CHANGELOG.md
75
CHANGELOG.md
|
@ -1,3 +1,78 @@
|
|||
0.41.0
|
||||
------
|
||||
|
||||
Bug #1138: Casting water walking doesn't move the player out of the water
|
||||
Bug #1931: Rocks from blocked passage in Bamz-Amschend, Radacs Forge can reset and cant be removed again.
|
||||
Bug #2048: Almvisi and Divine Intervention display wrong spell effect
|
||||
Bug #2054: Show effect-indicator for "instant effect" spells and potions
|
||||
Bug #2150: Clockwork City door animation problem
|
||||
Bug #2288: Playback of weapon idle animation not correct
|
||||
Bug #2410: Stat-review window doesn't display starting spells, powers, or abilities
|
||||
Bug #2493: Repairing occasionally very slow
|
||||
Bug #2716: [OSG] Water surface is too transparent from some angles
|
||||
Bug #2859: [MAC OS X] Cannot exit fullscreen once enabled
|
||||
Bug #3091: Editor: will not save addon if global variable value type is null
|
||||
Bug #3277: Editor: Non-functional nested tables in subviews need to be hidden instead of being disabled
|
||||
Bug #3348: Disabled map markers show on minimap
|
||||
Bug #3350: Extending selection to instances with same object results in duplicates.
|
||||
Bug #3353: [Mod] Romance version 3.7 script failed
|
||||
Bug #3376: [Mod] Vampire Embrace script fails to execute
|
||||
Bug #3385: Banners don't animate in stormy weather as they do in the original game
|
||||
Bug #3393: Akulakhan re-enabled after main quest
|
||||
Bug #3427: Editor: OpenMW-CS instances won´t get deleted
|
||||
Bug #3451: Feril Salmyn corpse isn't where it is supposed to be
|
||||
Bug #3497: Zero-weight armor is displayed as "heavy" in inventory tooltip
|
||||
Bug #3499: Idle animations don't always loop
|
||||
Bug #3500: Spark showers at Sotha Sil do not appear until you look at the ceiling
|
||||
Bug #3515: Editor: Moved objects in interior cells are teleported to exterior cells.
|
||||
Bug #3520: Editor: OpenMW-CS cannot find project file when launching the game
|
||||
Bug #3521: Armed NPCs don't use correct melee attacks
|
||||
Bug #3535: Changing cell immediately after dying causes character to freeze.
|
||||
Bug #3542: Unable to rest if unalerted slaughterfish are in the cell with you
|
||||
Bug #3549: Blood effects occur even when a hit is resisted
|
||||
Bug #3551: NPC Todwendy in german version can't interact
|
||||
Bug #3552: Opening the journal when fonts are missing results in a crash
|
||||
Bug #3555: SetInvisible command should not apply graphic effect
|
||||
Bug #3561: Editor: changes from omwaddon are not loaded in [New Addon] mode
|
||||
Bug #3562: Non-hostile NPCs can be disarmed by stealing their weapons via sneaking
|
||||
Bug #3564: Editor: openmw-cs verification results
|
||||
Bug #3568: Items that should be invisible are shown in the inventory
|
||||
Bug #3574: Alchemy: Alembics and retorts are used in reverse
|
||||
Bug #3575: Diaglog choices don't work in mw 0.40
|
||||
Bug #3576: Minor differences in AI reaction to hostile spell effects
|
||||
Bug #3577: not local nolore dialog test
|
||||
Bug #3578: Animation Replacer hangs after one cicle/step
|
||||
Bug #3579: Bound Armor skillups and sounds
|
||||
Bug #3583: Targetted GetCurrentAiPackage returns 0
|
||||
Bug #3584: Persuasion bug
|
||||
Bug #3590: Vendor, Ilen Faveran, auto equips items from stock
|
||||
Bug #3594: Weather doesn't seem to update correctly in Mournhold
|
||||
Bug #3598: Saving doesn't save status of objects
|
||||
Bug #3600: Screen goes black when trying to travel to Sadrith Mora
|
||||
Bug #3608: Water ripples aren't created when walking on water
|
||||
Bug #3626: Argonian NPCs swim like khajiits
|
||||
Bug #3627: Cannot delete "Blessed touch" spell from spellbook
|
||||
Bug #3634: An enchanted throwing weapon consumes charges from the stack in your inventory. (0.40.0)
|
||||
Bug #3635: Levelled items in merchants are "re-rolled" (not bug 2952, see inside)
|
||||
Feature #1118: AI combat: flee
|
||||
Feature #1596: Editor: Render water
|
||||
Feature #2042: Adding a non-portable Light to the inventory should cause the player to glow
|
||||
Feature #3166: Editor: Instance editing mode - rotate sub mode
|
||||
Feature #3167: Editor: Instance editing mode - scale sub mode
|
||||
Feature #3420: ess-Importer: player control flags
|
||||
Feature #3489: You shouldn't be be able to re-cast a bound equipment spell
|
||||
Feature #3496: Zero-weight boots should play light boot footsteps
|
||||
Feature #3516: Water Walking should give a "can't cast" message and fail when you are too deep
|
||||
Feature #3519: Play audio and visual effects for all effects in a spell
|
||||
Feature #3527: Double spell explosion scaling
|
||||
Feature #3534: Play particle textures for spell effects
|
||||
Feature #3539: Make NPCs use opponent's weapon range to decide whether to dodge
|
||||
Feature #3540: Allow dodging for creatures with "biped" flag
|
||||
Feature #3545: Drop shadow for items in menu
|
||||
Feature #3558: Implement same spell range for "on touch" spells as original engine
|
||||
Feature #3560: Allow using telekinesis with touch spells on objects
|
||||
Task #3585: Some objects added by Morrowind Rebirth do not display properly their texture
|
||||
|
||||
0.40.0
|
||||
------
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ brew update
|
|||
brew rm cmake || true
|
||||
brew rm pkgconfig || true
|
||||
brew rm qt5 || true
|
||||
brew install cmake pkgconfig qt55
|
||||
brew install cmake pkgconfig $macos_qt_formula
|
||||
|
||||
curl http://downloads.openmw.org/osx/dependencies/openmw-deps-263d4a8.zip -o ~/openmw-deps.zip
|
||||
curl https://downloads.openmw.org/osx/dependencies/openmw-deps-0ecece4.zip -o ~/openmw-deps.zip
|
||||
unzip ~/openmw-deps.zip -d /private/tmp/openmw-deps > /dev/null
|
||||
|
|
|
@ -4,7 +4,7 @@ export CXX=clang++
|
|||
export CC=clang
|
||||
|
||||
DEPENDENCIES_ROOT="/private/tmp/openmw-deps/openmw-deps"
|
||||
QT_PATH="/usr/local/opt/qt55"
|
||||
QT_PATH=`brew --prefix $macos_qt_formula`
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
|
@ -12,7 +12,7 @@ cd build
|
|||
cmake \
|
||||
-D CMAKE_PREFIX_PATH="$DEPENDENCIES_ROOT;$QT_PATH" \
|
||||
-D CMAKE_OSX_DEPLOYMENT_TARGET="10.8" \
|
||||
-D CMAKE_OSX_SYSROOT="macosx10.11" \
|
||||
-D CMAKE_OSX_SYSROOT="macosx10.12" \
|
||||
-D CMAKE_BUILD_TYPE=Debug \
|
||||
-D OPENMW_OSX_DEPLOYMENT=TRUE \
|
||||
-D DESIRED_QT_VERSION=5 \
|
||||
|
|
|
@ -25,7 +25,7 @@ endif()
|
|||
message(STATUS "Configuring OpenMW...")
|
||||
|
||||
set(OPENMW_VERSION_MAJOR 0)
|
||||
set(OPENMW_VERSION_MINOR 40)
|
||||
set(OPENMW_VERSION_MINOR 41)
|
||||
set(OPENMW_VERSION_RELEASE 0)
|
||||
|
||||
set(OPENMW_VERSION_COMMITHASH "")
|
||||
|
|
|
@ -7,7 +7,7 @@ OpenMW is a recreation of the engine for the popular role-playing game Morrowind
|
|||
|
||||
OpenMW also comes with OpenMW-CS, a replacement for Morrowind's TES Construction Set.
|
||||
|
||||
* Version: 0.40.0
|
||||
* Version: 0.41.0
|
||||
* License: GPLv3 (see [docs/license/GPL3.txt](https://github.com/OpenMW/openmw/blob/master/docs/license/GPL3.txt) for more information)
|
||||
* Website: http://www.openmw.org
|
||||
* IRC: #openmw on irc.freenode.net
|
||||
|
|
|
@ -47,6 +47,42 @@ namespace ESSImport
|
|||
controls.mVanityModeDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_VanityModeDisabled;
|
||||
controls.mWeaponDrawingDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_WeaponDrawingDisabled;
|
||||
controls.mSpellDrawingDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_SpellDrawingDisabled;
|
||||
|
||||
if (pcdt.mHasMark)
|
||||
{
|
||||
out.mHasMark = 1;
|
||||
|
||||
const PCDT::PNAM::MarkLocation& mark = pcdt.mPNAM.mMarkLocation;
|
||||
|
||||
ESM::CellId cell;
|
||||
cell.mWorldspace = ESM::CellId::sDefaultWorldspace;
|
||||
cell.mPaged = true;
|
||||
|
||||
cell.mIndex.mX = mark.mCellX;
|
||||
cell.mIndex.mY = mark.mCellY;
|
||||
|
||||
// TODO: Figure out a better way to detect interiors. (0, 0) is a valid exterior cell.
|
||||
if (mark.mCellX == 0 && mark.mCellY == 0)
|
||||
{
|
||||
cell.mWorldspace = pcdt.mMNAM;
|
||||
cell.mPaged = false;
|
||||
}
|
||||
|
||||
out.mMarkedCell = cell;
|
||||
out.mMarkedPosition.pos[0] = mark.mX;
|
||||
out.mMarkedPosition.pos[1] = mark.mY;
|
||||
out.mMarkedPosition.pos[2] = mark.mZ;
|
||||
out.mMarkedPosition.rot[0] = out.mMarkedPosition.rot[1] = 0.0f;
|
||||
out.mMarkedPosition.rot[2] = mark.mRotZ;
|
||||
}
|
||||
|
||||
if (pcdt.mHasENAM)
|
||||
{
|
||||
const int cellSize = 8192;
|
||||
out.mLastKnownExteriorPosition[0] = (pcdt.mENAM.mCellX + 0.5f) * cellSize;
|
||||
out.mLastKnownExteriorPosition[1] = (pcdt.mENAM.mCellY + 0.5f) * cellSize;
|
||||
out.mLastKnownExteriorPosition[2] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -62,8 +62,11 @@ namespace ESSImport
|
|||
playerCellId.mPaged = true;
|
||||
playerCellId.mIndex.mX = playerCellId.mIndex.mY = 0;
|
||||
mPlayer.mCellId = playerCellId;
|
||||
//mPlayer.mLastKnownExteriorPosition
|
||||
mPlayer.mHasMark = 0; // TODO
|
||||
mPlayer.mLastKnownExteriorPosition[0]
|
||||
= mPlayer.mLastKnownExteriorPosition[1]
|
||||
= mPlayer.mLastKnownExteriorPosition[2]
|
||||
= 0.0f;
|
||||
mPlayer.mHasMark = 0;
|
||||
mPlayer.mCurrentCrimeId = 0; // TODO
|
||||
mPlayer.mObject.blank();
|
||||
mPlayer.mObject.mRef.mRefID = "player"; // REFR.mRefID would be PlayerSaveGame
|
||||
|
|
|
@ -23,9 +23,12 @@ namespace ESSImport
|
|||
mKnownDialogueTopics.push_back(esm.getHString());
|
||||
}
|
||||
|
||||
mHasMark = false;
|
||||
if (esm.isNextSub("MNAM"))
|
||||
esm.skipHSub(); // If this field is here it seems to specify the interior cell the player is in,
|
||||
// but it's not always here, so it's kinda useless
|
||||
{
|
||||
mHasMark = true;
|
||||
mMNAM = esm.getHString();
|
||||
}
|
||||
|
||||
esm.getHNT(mPNAM, "PNAM");
|
||||
|
||||
|
@ -34,6 +37,14 @@ namespace ESSImport
|
|||
if (esm.isNextSub("NAM9"))
|
||||
esm.skipHSub();
|
||||
|
||||
// Rest state. You shouldn't even be able to save during rest, but skip just in case.
|
||||
if (esm.isNextSub("RNAM"))
|
||||
/*
|
||||
int hoursLeft;
|
||||
float x, y, z; // resting position
|
||||
*/
|
||||
esm.skipHSub(); // 16 bytes
|
||||
|
||||
mBounty = 0;
|
||||
esm.getHNOT(mBounty, "CNAM");
|
||||
|
||||
|
@ -50,8 +61,12 @@ namespace ESSImport
|
|||
if (esm.isNextSub("NAM3"))
|
||||
esm.skipHSub();
|
||||
|
||||
mHasENAM = false;
|
||||
if (esm.isNextSub("ENAM"))
|
||||
esm.skipHSub();
|
||||
{
|
||||
mHasENAM = true;
|
||||
esm.getHT(mENAM);
|
||||
}
|
||||
|
||||
if (esm.isNextSub("LNAM"))
|
||||
esm.skipHSub();
|
||||
|
@ -63,12 +78,19 @@ namespace ESSImport
|
|||
mFactions.push_back(fnam);
|
||||
}
|
||||
|
||||
if (esm.isNextSub("AADT"))
|
||||
esm.skipHSub(); // 44 bytes, no clue
|
||||
mHasAADT = false;
|
||||
if (esm.isNextSub("AADT")) // Attack animation data?
|
||||
{
|
||||
mHasAADT = true;
|
||||
esm.getHT(mAADT);
|
||||
}
|
||||
|
||||
if (esm.isNextSub("KNAM"))
|
||||
esm.skipHSub(); // assigned Quick Keys, I think
|
||||
|
||||
if (esm.isNextSub("ANIS"))
|
||||
esm.skipHSub(); // 16 bytes
|
||||
|
||||
if (esm.isNextSub("WERE"))
|
||||
{
|
||||
// some werewolf data, 152 bytes
|
||||
|
@ -76,10 +98,6 @@ namespace ESSImport
|
|||
esm.getSubHeader();
|
||||
esm.skip(152);
|
||||
}
|
||||
|
||||
// unsure if before or after WERE
|
||||
if (esm.isNextSub("ANIS"))
|
||||
esm.skipHSub();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -42,8 +42,11 @@ struct PCDT
|
|||
{
|
||||
PlayerFlags_ViewSwitchDisabled = 0x1,
|
||||
PlayerFlags_ControlsDisabled = 0x4,
|
||||
PlayerFlags_Sleeping = 0x10,
|
||||
PlayerFlags_Waiting = 0x40,
|
||||
PlayerFlags_WeaponDrawn = 0x80,
|
||||
PlayerFlags_SpellDrawn = 0x100,
|
||||
PlayerFlags_InJail = 0x200,
|
||||
PlayerFlags_JumpingDisabled = 0x1000,
|
||||
PlayerFlags_LookingDisabled = 0x2000,
|
||||
PlayerFlags_VanityModeDisabled = 0x4000,
|
||||
|
@ -68,19 +71,53 @@ struct PCDT
|
|||
|
||||
struct PNAM
|
||||
{
|
||||
struct MarkLocation
|
||||
{
|
||||
float mX, mY, mZ; // worldspace position
|
||||
float mRotZ; // Z angle in radians
|
||||
int mCellX, mCellY; // grid coordinates; for interior cells this is always (0, 0)
|
||||
};
|
||||
|
||||
int mPlayerFlags; // controls, camera and draw state
|
||||
unsigned int mLevelProgress;
|
||||
float mSkillProgress[27]; // skill progress, non-uniform scaled
|
||||
unsigned char mSkillIncreases[8]; // number of skill increases for each attribute
|
||||
unsigned char mUnknown3[84];
|
||||
int mTelekinesisRangeBonus; // in units; seems redundant
|
||||
float mVisionBonus; // range: <0.0, 1.0>; affected by light spells and Get/Mod/SetPCVisionBonus
|
||||
int mDetectKeyMagnitude; // seems redundant
|
||||
int mDetectEnchantmentMagnitude; // seems redundant
|
||||
int mDetectAnimalMagnitude; // seems redundant
|
||||
MarkLocation mMarkLocation;
|
||||
unsigned char mUnknown3[40];
|
||||
unsigned char mSpecIncreases[3]; // number of skill increases for each specialization
|
||||
unsigned char mUnknown4;
|
||||
};
|
||||
|
||||
struct ENAM
|
||||
{
|
||||
int mCellX;
|
||||
int mCellY;
|
||||
};
|
||||
|
||||
struct AADT // 44 bytes
|
||||
{
|
||||
int animGroupIndex; // See convertANIS() for the mapping.
|
||||
unsigned char mUnknown5[40];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
std::vector<FNAM> mFactions;
|
||||
PNAM mPNAM;
|
||||
|
||||
bool mHasMark;
|
||||
std::string mMNAM; // mark cell name; can also be sDefaultCellname or region name
|
||||
|
||||
bool mHasENAM;
|
||||
ENAM mENAM; // last exterior cell
|
||||
|
||||
bool mHasAADT;
|
||||
AADT mAADT;
|
||||
|
||||
void load(ESM::ESMReader& esm);
|
||||
};
|
||||
|
||||
|
|
|
@ -215,7 +215,6 @@ if (MSVC)
|
|||
if (CMAKE_CL_64)
|
||||
set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj")
|
||||
endif (CMAKE_CL_64)
|
||||
add_definitions("-D_USE_MATH_DEFINES")
|
||||
endif (MSVC)
|
||||
|
||||
if (WIN32)
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace osg
|
||||
|
@ -200,6 +201,10 @@ namespace MWBase
|
|||
|
||||
virtual std::list<MWWorld::Ptr> getEnemiesNearby(const MWWorld::Ptr& actor) = 0;
|
||||
|
||||
/// Recursive versions of above methods
|
||||
virtual void getActorsFollowing(const MWWorld::Ptr& actor, std::set<MWWorld::Ptr>& out) = 0;
|
||||
virtual void getActorsSidingWith(const MWWorld::Ptr& actor, std::set<MWWorld::Ptr>& out) = 0;
|
||||
|
||||
virtual void playerLoaded() = 0;
|
||||
|
||||
virtual int countSavedGameRecords() const = 0;
|
||||
|
|
|
@ -164,7 +164,7 @@ namespace MWClass
|
|||
getContainerStore(ptr).fill(ref->mBase->mInventory, ptr.getCellRef().getRefId());
|
||||
|
||||
if (hasInventory)
|
||||
getInventoryStore(ptr).autoEquip(ptr);
|
||||
getInventoryStore(ptr).autoEquipShield(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -448,14 +448,14 @@ namespace MWDialogue
|
|||
{
|
||||
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue);
|
||||
|
||||
// Clamp permanent disposition change so that final disposition doesn't go below 0 (could happen with intimidate)
|
||||
float curDisp = static_cast<float>(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor, false));
|
||||
if (curDisp + mPermanentDispositionChange < 0)
|
||||
mPermanentDispositionChange = -curDisp;
|
||||
|
||||
// Apply disposition change to NPC's base disposition
|
||||
if (mActor.getClass().isNpc())
|
||||
{
|
||||
// Clamp permanent disposition change so that final disposition doesn't go below 0 (could happen with intimidate)
|
||||
float curDisp = static_cast<float>(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor, false));
|
||||
if (curDisp + mPermanentDispositionChange < 0)
|
||||
mPermanentDispositionChange = -curDisp;
|
||||
|
||||
MWMechanics::NpcStats& npcStats = mActor.getClass().getNpcStats(mActor);
|
||||
npcStats.setBaseDisposition(static_cast<int>(npcStats.getBaseDisposition() + mPermanentDispositionChange));
|
||||
}
|
||||
|
|
|
@ -107,11 +107,11 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const
|
|||
bool MWDialogue::Filter::testPlayer (const ESM::DialInfo& info) const
|
||||
{
|
||||
const MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||
MWMechanics::NpcStats& stats = player.getClass().getNpcStats (player);
|
||||
|
||||
// check player faction
|
||||
// check player faction and rank
|
||||
if (!info.mPcFaction.empty())
|
||||
{
|
||||
MWMechanics::NpcStats& stats = player.getClass().getNpcStats (player);
|
||||
std::map<std::string,int>::const_iterator iter = stats.getFactionRanks().find (Misc::StringUtils::lowerCase (info.mPcFaction));
|
||||
|
||||
if(iter==stats.getFactionRanks().end())
|
||||
|
@ -121,6 +121,18 @@ bool MWDialogue::Filter::testPlayer (const ESM::DialInfo& info) const
|
|||
if (iter->second < info.mData.mPCrank)
|
||||
return false;
|
||||
}
|
||||
else if (info.mData.mPCrank != -1)
|
||||
{
|
||||
// required PC faction is not specified but PC rank is; use speaker's faction
|
||||
std::map<std::string,int>::const_iterator iter = stats.getFactionRanks().find (Misc::StringUtils::lowerCase (mActor.getClass().getPrimaryFaction(mActor)));
|
||||
|
||||
if(iter==stats.getFactionRanks().end())
|
||||
return false;
|
||||
|
||||
// check rank
|
||||
if (iter->second < info.mData.mPCrank)
|
||||
return false;
|
||||
}
|
||||
|
||||
// check cell
|
||||
if (!info.mCell.empty())
|
||||
|
|
|
@ -428,7 +428,9 @@ namespace MWGui
|
|||
{
|
||||
// split lines
|
||||
const int lineHeight = currentFontHeight();
|
||||
unsigned int lastLine = (mPaginator.getStartTop() + mPaginator.getPageHeight() - mPaginator.getCurrentTop()) / lineHeight;
|
||||
unsigned int lastLine = (mPaginator.getStartTop() + mPaginator.getPageHeight() - mPaginator.getCurrentTop());
|
||||
if (lineHeight > 0)
|
||||
lastLine /= lineHeight;
|
||||
int ret = mPaginator.getCurrentTop() + lastLine * lineHeight;
|
||||
|
||||
// first empty lines that would go to the next page should be ignored
|
||||
|
|
|
@ -55,7 +55,7 @@ namespace MWGui
|
|||
|
||||
void TravelWindow::addDestination(const std::string& name,ESM::Position pos,bool interior)
|
||||
{
|
||||
int price = 0;
|
||||
int price;
|
||||
|
||||
const MWWorld::Store<ESM::GameSetting> &gmst =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||
|
@ -70,14 +70,21 @@ namespace MWGui
|
|||
else
|
||||
{
|
||||
ESM::Position PlayerPos = player.getRefData().getPosition();
|
||||
float d = sqrt( pow(pos.pos[0] - PlayerPos.pos[0],2) + pow(pos.pos[1] - PlayerPos.pos[1],2) + pow(pos.pos[2] - PlayerPos.pos[2],2) );
|
||||
float d = sqrt(pow(pos.pos[0] - PlayerPos.pos[0], 2) + pow(pos.pos[1] - PlayerPos.pos[1], 2) + pow(pos.pos[2] - PlayerPos.pos[2], 2));
|
||||
price = static_cast<int>(d / gmst.find("fTravelMult")->getFloat());
|
||||
}
|
||||
|
||||
price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true);
|
||||
price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, price, true);
|
||||
|
||||
// Add price for the travelling followers
|
||||
std::set<MWWorld::Ptr> followers;
|
||||
MWWorld::ActionTeleport::getFollowersToTeleport(player, followers);
|
||||
|
||||
// Apply followers cost, in vanilla one follower travels for free
|
||||
price *= std::max(1, static_cast<int>(followers.size()));
|
||||
|
||||
MyGUI::Button* toAdd = mDestinationsView->createWidget<MyGUI::Button>("SandTextButton", 0, mCurrentY, 200, sLineHeight, MyGUI::Align::Default);
|
||||
toAdd->setEnabled(price<=playerGold);
|
||||
toAdd->setEnabled(price <= playerGold);
|
||||
mCurrentY += sLineHeight;
|
||||
if(interior)
|
||||
toAdd->setUserString("interior","y");
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "movement.hpp"
|
||||
#include "character.hpp"
|
||||
#include "aicombat.hpp"
|
||||
#include "aicombataction.hpp"
|
||||
#include "aifollow.hpp"
|
||||
#include "aipursue.hpp"
|
||||
#include "actor.hpp"
|
||||
|
@ -83,15 +84,14 @@ public:
|
|||
const std::string& sourceName, const std::string& sourceId, int casterActorId,
|
||||
float magnitude, float remainingTime = -1, float totalTime = -1)
|
||||
{
|
||||
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||
if ( ((key.mId == ESM::MagicEffect::CommandHumanoid && mActor.getClass().isNpc())
|
||||
|| (key.mId == ESM::MagicEffect::CommandCreature && mActor.getTypeName() == typeid(ESM::Creature).name()))
|
||||
&& casterActorId == player.getClass().getCreatureStats(player).getActorId()
|
||||
if (((key.mId == ESM::MagicEffect::CommandHumanoid && mActor.getClass().isNpc())
|
||||
|| (key.mId == ESM::MagicEffect::CommandCreature && mActor.getTypeName() == typeid(ESM::Creature).name()))
|
||||
&& magnitude >= mActor.getClass().getCreatureStats(mActor).getLevel())
|
||||
mCommanded = true;
|
||||
}
|
||||
};
|
||||
|
||||
// Check for command effects having ended and remove package if necessary
|
||||
void adjustCommandedActor (const MWWorld::Ptr& actor)
|
||||
{
|
||||
CheckActorCommanded check(actor);
|
||||
|
@ -111,13 +111,7 @@ void adjustCommandedActor (const MWWorld::Ptr& actor)
|
|||
}
|
||||
}
|
||||
|
||||
if (check.mCommanded && !hasCommandPackage)
|
||||
{
|
||||
// FIXME: don't use refid string
|
||||
MWMechanics::AiFollow package("player", true);
|
||||
stats.getAiSequence().stack(package, actor);
|
||||
}
|
||||
else if (!check.mCommanded && hasCommandPackage)
|
||||
if (!check.mCommanded && hasCommandPackage)
|
||||
{
|
||||
stats.getAiSequence().erase(it);
|
||||
}
|
||||
|
@ -286,10 +280,12 @@ namespace MWMechanics
|
|||
|
||||
void Actors::engageCombat (const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, bool againstPlayer)
|
||||
{
|
||||
CreatureStats& creatureStats = actor1.getClass().getCreatureStats(actor1);
|
||||
const CreatureStats& creatureStats1 = actor1.getClass().getCreatureStats(actor1);
|
||||
if (creatureStats1.getAiSequence().isInCombat(actor2))
|
||||
return;
|
||||
|
||||
if (actor2.getClass().getCreatureStats(actor2).isDead()
|
||||
|| actor1.getClass().getCreatureStats(actor1).isDead())
|
||||
const CreatureStats& creatureStats2 = actor2.getClass().getCreatureStats(actor2);
|
||||
if (creatureStats1.isDead() || creatureStats2.isDead())
|
||||
return;
|
||||
|
||||
const ESM::Position& actor1Pos = actor1.getRefData().getPosition();
|
||||
|
@ -298,55 +294,26 @@ namespace MWMechanics
|
|||
if (sqrDist > sqrAiProcessingDistance)
|
||||
return;
|
||||
|
||||
// pure water creatures won't try to fight with the target on the ground
|
||||
// except that creature is already hostile
|
||||
if ((againstPlayer || !creatureStats.getAiSequence().isInCombat())
|
||||
&& !MWMechanics::isEnvironmentCompatible(actor1, actor2)) // creature can't swim to target
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// no combat for totally static creatures (they have no movement or attack animations anyway)
|
||||
// No combat for totally static creatures
|
||||
if (!actor1.getClass().isMobile(actor1))
|
||||
return;
|
||||
|
||||
bool aggressive;
|
||||
|
||||
if (againstPlayer)
|
||||
// Start combat if target actor is in combat with one of our followers or escorters
|
||||
const std::list<MWWorld::Ptr>& followersAndEscorters = getActorsSidingWith(actor1);
|
||||
for (std::list<MWWorld::Ptr>::const_iterator it = followersAndEscorters.begin(); it != followersAndEscorters.end(); ++it)
|
||||
{
|
||||
// followers with high fight should not engage in combat with the player (e.g. bm_bear_black_summon)
|
||||
const std::list<MWWorld::Ptr>& followers = getActorsSidingWith(actor2);
|
||||
if (std::find(followers.begin(), followers.end(), actor1) != followers.end())
|
||||
return;
|
||||
|
||||
aggressive = MWBase::Environment::get().getMechanicsManager()->isAggressive(actor1, actor2);
|
||||
}
|
||||
else
|
||||
{
|
||||
aggressive = false;
|
||||
|
||||
// Make guards fight aggressive creatures
|
||||
if (!actor1.getClass().isNpc() && actor2.getClass().isClass(actor2, "Guard"))
|
||||
// Need to check both ways since player doesn't use AI packages
|
||||
if ((creatureStats2.getAiSequence().isInCombat(*it)
|
||||
|| it->getClass().getCreatureStats(*it).getAiSequence().isInCombat(actor2))
|
||||
&& !creatureStats1.getAiSequence().isInCombat(*it))
|
||||
{
|
||||
if (creatureStats.getAiSequence().isInCombat() && MWBase::Environment::get().getMechanicsManager()->isAggressive(actor1, actor2))
|
||||
aggressive = true;
|
||||
MWBase::Environment::get().getMechanicsManager()->startCombat(actor1, actor2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// start combat if target actor is in combat with one of our followers
|
||||
const std::list<MWWorld::Ptr>& followers = getActorsSidingWith(actor1);
|
||||
const CreatureStats& creatureStats2 = actor2.getClass().getCreatureStats(actor2);
|
||||
for (std::list<MWWorld::Ptr>::const_iterator it = followers.begin(); it != followers.end(); ++it)
|
||||
{
|
||||
// need to check both ways since player doesn't use AI packages
|
||||
if ((creatureStats2.getAiSequence().isInCombat(*it)
|
||||
|| it->getClass().getCreatureStats(*it).getAiSequence().isInCombat(actor2))
|
||||
&& !creatureStats.getAiSequence().isInCombat(*it))
|
||||
aggressive = true;
|
||||
}
|
||||
|
||||
// start combat if target actor is in combat with someone we are following
|
||||
for (std::list<MWMechanics::AiPackage*>::const_iterator it = creatureStats.getAiSequence().begin(); it != creatureStats.getAiSequence().end(); ++it)
|
||||
// Start combat if target actor is in combat with someone we are following through a follow package
|
||||
for (std::list<MWMechanics::AiPackage*>::const_iterator it = creatureStats1.getAiSequence().begin(); it != creatureStats1.getAiSequence().end(); ++it)
|
||||
{
|
||||
if (!(*it)->sideWithTarget())
|
||||
continue;
|
||||
|
@ -356,20 +323,63 @@ namespace MWMechanics
|
|||
if (followTarget.isEmpty())
|
||||
continue;
|
||||
|
||||
if (creatureStats.getAiSequence().isInCombat(followTarget))
|
||||
if (creatureStats1.getAiSequence().isInCombat(followTarget))
|
||||
continue;
|
||||
|
||||
// need to check both ways since player doesn't use AI packages
|
||||
// Need to check both ways since player doesn't use AI packages
|
||||
if (creatureStats2.getAiSequence().isInCombat(followTarget)
|
||||
|| followTarget.getClass().getCreatureStats(followTarget).getAiSequence().isInCombat(actor2))
|
||||
aggressive = true;
|
||||
{
|
||||
MWBase::Environment::get().getMechanicsManager()->startCombat(actor1, actor2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Start combat with the player if we are already in combat with a player follower or escorter
|
||||
const std::list<MWWorld::Ptr>& playerFollowersAndEscorters = getActorsSidingWith(getPlayer());
|
||||
if (againstPlayer)
|
||||
{
|
||||
for (std::list<MWWorld::Ptr>::const_iterator it = playerFollowersAndEscorters.begin(); it != playerFollowersAndEscorters.end(); ++it)
|
||||
{
|
||||
if (creatureStats1.getAiSequence().isInCombat(*it))
|
||||
{
|
||||
MWBase::Environment::get().getMechanicsManager()->startCombat(actor1, actor2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(aggressive)
|
||||
// Otherwise, don't initiate combat with an unreachable target
|
||||
if (!MWMechanics::canFight(actor1,actor2))
|
||||
return;
|
||||
|
||||
bool aggressive = false;
|
||||
|
||||
if (againstPlayer || std::find(playerFollowersAndEscorters.begin(), playerFollowersAndEscorters.end(), actor2) != playerFollowersAndEscorters.end())
|
||||
{
|
||||
// Player followers and escorters with high fight should not initiate combat here with the player or with
|
||||
// other player followers or escorters
|
||||
if (std::find(playerFollowersAndEscorters.begin(), playerFollowersAndEscorters.end(), actor1) != playerFollowersAndEscorters.end())
|
||||
return;
|
||||
|
||||
aggressive = MWBase::Environment::get().getMechanicsManager()->isAggressive(actor1, actor2);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make guards fight aggressive creatures
|
||||
if (!actor1.getClass().isNpc() && actor2.getClass().isClass(actor2, "Guard"))
|
||||
{
|
||||
if (creatureStats1.getAiSequence().isInCombat() && MWBase::Environment::get().getMechanicsManager()->isAggressive(actor1, actor2))
|
||||
aggressive = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (aggressive)
|
||||
{
|
||||
bool LOS = MWBase::Environment::get().getWorld()->getLOS(actor1, actor2);
|
||||
|
||||
if (againstPlayer) LOS &= MWBase::Environment::get().getMechanicsManager()->awarenessCheck(actor2, actor1);
|
||||
if (againstPlayer || std::find(playerFollowersAndEscorters.begin(), playerFollowersAndEscorters.end(), actor2) != playerFollowersAndEscorters.end())
|
||||
LOS &= MWBase::Environment::get().getMechanicsManager()->awarenessCheck(actor2, actor1);
|
||||
|
||||
if (LOS)
|
||||
{
|
||||
|
@ -1482,6 +1492,20 @@ namespace MWMechanics
|
|||
return list;
|
||||
}
|
||||
|
||||
void Actors::getActorsFollowing(const MWWorld::Ptr &actor, std::set<MWWorld::Ptr>& out) {
|
||||
std::list<MWWorld::Ptr> followers = getActorsFollowing(actor);
|
||||
for(std::list<MWWorld::Ptr>::iterator it = followers.begin();it != followers.end();++it)
|
||||
if (out.insert(*it).second)
|
||||
getActorsFollowing(*it, out);
|
||||
}
|
||||
|
||||
void Actors::getActorsSidingWith(const MWWorld::Ptr &actor, std::set<MWWorld::Ptr>& out) {
|
||||
std::list<MWWorld::Ptr> followers = getActorsSidingWith(actor);
|
||||
for(std::list<MWWorld::Ptr>::iterator it = followers.begin();it != followers.end();++it)
|
||||
if (out.insert(*it).second)
|
||||
getActorsSidingWith(*it, out);
|
||||
}
|
||||
|
||||
std::list<int> Actors::getActorsFollowingIndices(const MWWorld::Ptr &actor)
|
||||
{
|
||||
std::list<int> list;
|
||||
|
|
|
@ -123,6 +123,11 @@ namespace MWMechanics
|
|||
std::list<MWWorld::Ptr> getActorsSidingWith(const MWWorld::Ptr& actor);
|
||||
std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor);
|
||||
|
||||
/// Recursive version of getActorsFollowing
|
||||
void getActorsFollowing(const MWWorld::Ptr &actor, std::set<MWWorld::Ptr>& out);
|
||||
/// Recursive version of getActorsSidingWith
|
||||
void getActorsSidingWith(const MWWorld::Ptr &actor, std::set<MWWorld::Ptr>& out);
|
||||
|
||||
/// Get the list of AiFollow::mFollowIndex for all actors following this target
|
||||
std::list<int> getActorsFollowingIndices(const MWWorld::Ptr& actor);
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "aicombataction.hpp"
|
||||
#include "combat.hpp"
|
||||
#include "coordinateconverter.hpp"
|
||||
#include "actorutil.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -210,13 +211,14 @@ namespace MWMechanics
|
|||
else
|
||||
{
|
||||
timerReact = 0;
|
||||
attack(actor, target, storage, characterController);
|
||||
if (attack(actor, target, storage, characterController))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void AiCombat::attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController)
|
||||
bool AiCombat::attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController)
|
||||
{
|
||||
const MWWorld::CellStore*& currentCell = storage.mCell;
|
||||
bool cellChange = currentCell && (actor.getCell() != currentCell);
|
||||
|
@ -231,7 +233,10 @@ namespace MWMechanics
|
|||
storage.stopAttack();
|
||||
characterController.setAttackingOrSpell(false);
|
||||
storage.mActionCooldown = 0.f;
|
||||
forceFlee = true;
|
||||
if (target == MWMechanics::getPlayer())
|
||||
forceFlee = true;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
const MWWorld::Class& actorClass = actor.getClass();
|
||||
|
@ -243,7 +248,7 @@ namespace MWMechanics
|
|||
if (!forceFlee)
|
||||
{
|
||||
if (actionCooldown > 0)
|
||||
return;
|
||||
return false;
|
||||
|
||||
if (characterController.readyToPrepareAttack())
|
||||
{
|
||||
|
@ -258,7 +263,7 @@ namespace MWMechanics
|
|||
}
|
||||
|
||||
if (!currentAction)
|
||||
return;
|
||||
return false;
|
||||
|
||||
if (storage.isFleeing() != currentAction->isFleeing())
|
||||
{
|
||||
|
@ -266,7 +271,7 @@ namespace MWMechanics
|
|||
{
|
||||
storage.startFleeing();
|
||||
MWBase::Environment::get().getDialogueManager()->say(actor, "flee");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
storage.stopFleeing();
|
||||
|
@ -311,6 +316,7 @@ namespace MWMechanics
|
|||
storage.mMovement.mRotation[2] = getZAngleToDir((vTargetPos-vActorPos)); // using vAimDir results in spastic movements since the head is animated
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MWMechanics::AiCombat::updateLOS(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, MWMechanics::AiCombatStorage& storage)
|
||||
|
|
|
@ -59,7 +59,8 @@ namespace MWMechanics
|
|||
|
||||
int mTargetActorId;
|
||||
|
||||
void attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController);
|
||||
/// Returns true if combat should end
|
||||
bool attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController);
|
||||
|
||||
void updateLOS(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, AiCombatStorage& storage);
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ namespace MWMechanics
|
|||
MWWorld::Ptr getTarget() const;
|
||||
virtual bool sideWithTarget() const { return true; }
|
||||
virtual bool followTargetThroughDoors() const { return true; }
|
||||
virtual bool shouldCancelPreviousAi() const { return !mCommanded; }
|
||||
|
||||
virtual AiFollow *clone() const;
|
||||
|
||||
|
|
|
@ -281,6 +281,10 @@ void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor)
|
|||
}
|
||||
}
|
||||
|
||||
// Stop combat when a non-combat AI package is added
|
||||
if (isActualAiPackage(package.getTypeId()))
|
||||
stopCombat();
|
||||
|
||||
// remove previous packages if required
|
||||
if (package.shouldCancelPreviousAi())
|
||||
{
|
||||
|
|
|
@ -473,8 +473,8 @@ namespace MWMechanics
|
|||
void AiWander::onWalkingStatePerFrameActions(const MWWorld::Ptr& actor,
|
||||
float duration, AiWanderStorage& storage, ESM::Position& pos)
|
||||
{
|
||||
// Are we there yet?
|
||||
if (pathTo(actor, mPathFinder.getPath().back(), duration, DESTINATION_TOLERANCE))
|
||||
// Is there no destination or are we there yet?
|
||||
if ((!mPathFinder.isPathConstructed()) || pathTo(actor, mPathFinder.getPath().back(), duration, DESTINATION_TOLERANCE))
|
||||
{
|
||||
stopWalking(actor, storage);
|
||||
storage.setState(Wander_ChooseAction);
|
||||
|
|
|
@ -70,12 +70,14 @@ std::string getBestAttack (const ESM::Weapon* weapon)
|
|||
int slash = (weapon->mData.mSlash[0] + weapon->mData.mSlash[1])/2;
|
||||
int chop = (weapon->mData.mChop[0] + weapon->mData.mChop[1])/2;
|
||||
int thrust = (weapon->mData.mThrust[0] + weapon->mData.mThrust[1])/2;
|
||||
if (slash >= chop && slash >= thrust)
|
||||
if (slash == chop && slash == thrust)
|
||||
return "slash";
|
||||
else if (chop >= slash && chop >= thrust)
|
||||
return "chop";
|
||||
else
|
||||
else if (thrust >= chop && thrust >= slash)
|
||||
return "thrust";
|
||||
else if (slash >= chop && slash >= thrust)
|
||||
return "slash";
|
||||
else
|
||||
return "chop";
|
||||
}
|
||||
|
||||
// Converts a movement Run state to its equivalent Walk state.
|
||||
|
|
|
@ -978,18 +978,6 @@ namespace MWMechanics
|
|||
}
|
||||
|
||||
|
||||
void getFollowers (const MWWorld::Ptr& actor, std::set<MWWorld::Ptr>& out)
|
||||
{
|
||||
std::list<MWWorld::Ptr> followers = MWBase::Environment::get().getMechanicsManager()->getActorsSidingWith(actor);
|
||||
for(std::list<MWWorld::Ptr>::iterator it = followers.begin();it != followers.end();++it)
|
||||
{
|
||||
if (out.insert(*it).second)
|
||||
{
|
||||
getFollowers(*it, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool MechanicsManager::commitCrime(const MWWorld::Ptr &player, const MWWorld::Ptr &victim, OffenseType type, int arg, bool victimAware)
|
||||
{
|
||||
// NOTE: victim may be empty
|
||||
|
@ -1013,7 +1001,7 @@ namespace MWMechanics
|
|||
|
||||
// get the player's followers / allies (works recursively) that will not report crimes
|
||||
std::set<MWWorld::Ptr> playerFollowers;
|
||||
getFollowers(player, playerFollowers);
|
||||
getActorsSidingWith(player, playerFollowers);
|
||||
|
||||
// Did anyone see it?
|
||||
bool crimeSeen = false;
|
||||
|
@ -1437,6 +1425,14 @@ namespace MWMechanics
|
|||
return mActors.getEnemiesNearby(actor);
|
||||
}
|
||||
|
||||
void MechanicsManager::getActorsFollowing(const MWWorld::Ptr& actor, std::set<MWWorld::Ptr>& out) {
|
||||
mActors.getActorsFollowing(actor, out);
|
||||
}
|
||||
|
||||
void MechanicsManager::getActorsSidingWith(const MWWorld::Ptr& actor, std::set<MWWorld::Ptr>& out) {
|
||||
mActors.getActorsSidingWith(actor, out);
|
||||
}
|
||||
|
||||
int MechanicsManager::countSavedGameRecords() const
|
||||
{
|
||||
return 1 // Death counter
|
||||
|
|
|
@ -165,6 +165,11 @@ namespace MWMechanics
|
|||
virtual std::list<MWWorld::Ptr> getActorsFighting(const MWWorld::Ptr& actor);
|
||||
virtual std::list<MWWorld::Ptr> getEnemiesNearby(const MWWorld::Ptr& actor);
|
||||
|
||||
/// Recursive version of getActorsFollowing
|
||||
virtual void getActorsFollowing(const MWWorld::Ptr& actor, std::set<MWWorld::Ptr>& out);
|
||||
/// Recursive version of getActorsSidingWith
|
||||
virtual void getActorsSidingWith(const MWWorld::Ptr& actor, std::set<MWWorld::Ptr>& out);
|
||||
|
||||
virtual bool toggleAI();
|
||||
virtual bool isAIActive();
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "magiceffects.hpp"
|
||||
#include "npcstats.hpp"
|
||||
#include "actorutil.hpp"
|
||||
#include "aifollow.hpp"
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
|
@ -491,6 +492,15 @@ namespace MWMechanics
|
|||
|
||||
appliedLastingEffects.push_back(effect);
|
||||
|
||||
// Command spells should have their effect, including taking the target out of combat, each time the spell successfully affects the target
|
||||
if (((effectIt->mEffectID == ESM::MagicEffect::CommandHumanoid && target.getClass().isNpc())
|
||||
|| (effectIt->mEffectID == ESM::MagicEffect::CommandCreature && target.getTypeName() == typeid(ESM::Creature).name()))
|
||||
&& !caster.isEmpty() && caster.getClass().isActor() && target != getPlayer() && magnitude >= target.getClass().getCreatureStats(target).getLevel())
|
||||
{
|
||||
MWMechanics::AiFollow package(caster.getCellRef().getRefId(), true);
|
||||
target.getClass().getCreatureStats(target).getAiSequence().stack(package, target);
|
||||
}
|
||||
|
||||
// For absorb effects, also apply the effect to the caster - but with a negative
|
||||
// magnitude, since we're transferring stats from the target to the caster
|
||||
if (!caster.isEmpty() && caster.getClass().isActor())
|
||||
|
@ -616,6 +626,11 @@ namespace MWMechanics
|
|||
return true;
|
||||
}
|
||||
}
|
||||
else if (target.getClass().isActor() && effectId == ESM::MagicEffect::Dispel)
|
||||
{
|
||||
target.getClass().getCreatureStats(target).getActiveSpells().purgeAll(magnitude);
|
||||
return true;
|
||||
}
|
||||
else if (target.getClass().isActor() && target == getPlayer())
|
||||
{
|
||||
MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(mCaster);
|
||||
|
@ -1148,9 +1163,6 @@ namespace MWMechanics
|
|||
case ESM::MagicEffect::CureCorprusDisease:
|
||||
actor.getClass().getCreatureStats(actor).getSpells().purgeCorprusDisease();
|
||||
break;
|
||||
case ESM::MagicEffect::Dispel:
|
||||
actor.getClass().getCreatureStats(actor).getActiveSpells().purgeAll(magnitude);
|
||||
break;
|
||||
case ESM::MagicEffect::RemoveCurse:
|
||||
actor.getClass().getCreatureStats(actor).getSpells().purgeCurses();
|
||||
break;
|
||||
|
|
|
@ -55,29 +55,46 @@ namespace MWPhysics
|
|||
static const float sMaxSlope = 49.0f;
|
||||
static const float sStepSizeUp = 34.0f;
|
||||
static const float sStepSizeDown = 62.0f;
|
||||
static const float sMinStep = 10.f;
|
||||
|
||||
// Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared.
|
||||
static const int sMaxIterations = 8;
|
||||
|
||||
// FIXME: move to a separate file
|
||||
class MovementSolver
|
||||
static bool isActor(const btCollisionObject *obj)
|
||||
{
|
||||
assert(obj);
|
||||
return obj->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor;
|
||||
}
|
||||
|
||||
template <class Vec3>
|
||||
static bool isWalkableSlope(const Vec3 &normal)
|
||||
{
|
||||
static const float sMaxSlopeCos = std::cos(osg::DegreesToRadians(sMaxSlope));
|
||||
return (normal.z() > sMaxSlopeCos);
|
||||
}
|
||||
|
||||
static bool canStepDown(const ActorTracer &stepper)
|
||||
{
|
||||
return stepper.mHitObject && isWalkableSlope(stepper.mPlaneNormal) && !isActor(stepper.mHitObject);
|
||||
}
|
||||
|
||||
class Stepper
|
||||
{
|
||||
private:
|
||||
static float getSlope(osg::Vec3f normal)
|
||||
{
|
||||
normal.normalize();
|
||||
return osg::RadiansToDegrees(std::acos(normal * osg::Vec3f(0.f, 0.f, 1.f)));
|
||||
}
|
||||
const btCollisionWorld *mColWorld;
|
||||
const btCollisionObject *mColObj;
|
||||
|
||||
enum StepMoveResult
|
||||
{
|
||||
Result_Blocked, // unable to move over obstacle
|
||||
Result_MaxSlope, // unable to end movement on this slope
|
||||
Result_Success
|
||||
};
|
||||
ActorTracer mTracer, mUpStepper, mDownStepper;
|
||||
bool mHaveMoved;
|
||||
|
||||
static StepMoveResult stepMove(const btCollisionObject *colobj, osg::Vec3f &position,
|
||||
const osg::Vec3f &toMove, float &remainingTime, const btCollisionWorld* collisionWorld)
|
||||
public:
|
||||
Stepper(const btCollisionWorld *colWorld, const btCollisionObject *colObj)
|
||||
: mColWorld(colWorld)
|
||||
, mColObj(colObj)
|
||||
, mHaveMoved(true)
|
||||
{}
|
||||
|
||||
bool step(osg::Vec3f &position, const osg::Vec3f &toMove, float &remainingTime)
|
||||
{
|
||||
/*
|
||||
* Slide up an incline or set of stairs. Should be called only after a
|
||||
|
@ -123,12 +140,14 @@ namespace MWPhysics
|
|||
* +--+ +--------
|
||||
* ==============================================
|
||||
*/
|
||||
ActorTracer tracer, stepper;
|
||||
|
||||
stepper.doTrace(colobj, position, position+osg::Vec3f(0.0f,0.0f,sStepSizeUp), collisionWorld);
|
||||
if(stepper.mFraction < std::numeric_limits<float>::epsilon())
|
||||
return Result_Blocked; // didn't even move the smallest representable amount
|
||||
// (TODO: shouldn't this be larger? Why bother with such a small amount?)
|
||||
if (mHaveMoved)
|
||||
{
|
||||
mHaveMoved = false;
|
||||
mUpStepper.doTrace(mColObj, position, position+osg::Vec3f(0.0f,0.0f,sStepSizeUp), mColWorld);
|
||||
if(mUpStepper.mFraction < std::numeric_limits<float>::epsilon())
|
||||
return false; // didn't even move the smallest representable amount
|
||||
// (TODO: shouldn't this be larger? Why bother with such a small amount?)
|
||||
}
|
||||
|
||||
/*
|
||||
* Try moving from the elevated position using tracer.
|
||||
|
@ -143,9 +162,10 @@ namespace MWPhysics
|
|||
* +--+
|
||||
* ==============================================
|
||||
*/
|
||||
tracer.doTrace(colobj, stepper.mEndPos, stepper.mEndPos + toMove, collisionWorld);
|
||||
if(tracer.mFraction < std::numeric_limits<float>::epsilon())
|
||||
return Result_Blocked; // didn't even move the smallest representable amount
|
||||
osg::Vec3f tracerPos = mUpStepper.mEndPos;
|
||||
mTracer.doTrace(mColObj, tracerPos, tracerPos + toMove, mColWorld);
|
||||
if(mTracer.mFraction < std::numeric_limits<float>::epsilon())
|
||||
return false; // didn't even move the smallest representable amount
|
||||
|
||||
/*
|
||||
* Try moving back down sStepSizeDown using stepper.
|
||||
|
@ -162,26 +182,40 @@ namespace MWPhysics
|
|||
* +--+ +--+
|
||||
* ==============================================
|
||||
*/
|
||||
stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), collisionWorld);
|
||||
if (getSlope(stepper.mPlaneNormal) > sMaxSlope)
|
||||
return Result_MaxSlope;
|
||||
if(stepper.mFraction < 1.0f)
|
||||
mDownStepper.doTrace(mColObj, mTracer.mEndPos, mTracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), mColWorld);
|
||||
if (!canStepDown(mDownStepper))
|
||||
{
|
||||
// Try again with increased step length
|
||||
if (mTracer.mFraction < 1.0f || toMove.length2() > sMinStep*sMinStep)
|
||||
return false;
|
||||
|
||||
osg::Vec3f direction = toMove;
|
||||
direction.normalize();
|
||||
mTracer.doTrace(mColObj, tracerPos, tracerPos + direction*sMinStep, mColWorld);
|
||||
if (mTracer.mFraction < 0.001f)
|
||||
return false;
|
||||
|
||||
mDownStepper.doTrace(mColObj, mTracer.mEndPos, mTracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), mColWorld);
|
||||
if (!canStepDown(mDownStepper))
|
||||
return false;
|
||||
}
|
||||
if (mDownStepper.mFraction < 1.0f)
|
||||
{
|
||||
// don't allow stepping up other actors
|
||||
if (stepper.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor)
|
||||
return Result_Blocked;
|
||||
// only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall.
|
||||
// TODO: stepper.mPlaneNormal does not appear to be reliable - needs more testing
|
||||
// NOTE: caller's variables 'position' & 'remainingTime' are modified here
|
||||
position = stepper.mEndPos;
|
||||
remainingTime *= (1.0f-tracer.mFraction); // remaining time is proportional to remaining distance
|
||||
return Result_Success;
|
||||
position = mDownStepper.mEndPos;
|
||||
remainingTime *= (1.0f-mTracer.mFraction); // remaining time is proportional to remaining distance
|
||||
mHaveMoved = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return Result_Blocked;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class MovementSolver
|
||||
{
|
||||
private:
|
||||
///Project a vector u on another vector v
|
||||
static inline osg::Vec3f project(const osg::Vec3f& u, const osg::Vec3f &v)
|
||||
{
|
||||
|
@ -229,14 +263,14 @@ namespace MWPhysics
|
|||
collisionWorld->rayTest(from, to, resultCallback1);
|
||||
|
||||
if (resultCallback1.hasHit() &&
|
||||
( (toOsg(resultCallback1.m_hitPointWorld) - tracer.mEndPos).length() > 35
|
||||
|| getSlope(tracer.mPlaneNormal) > sMaxSlope))
|
||||
( (toOsg(resultCallback1.m_hitPointWorld) - tracer.mEndPos).length2() > 35*35
|
||||
|| !isWalkableSlope(tracer.mPlaneNormal)))
|
||||
{
|
||||
actor->setOnGround(getSlope(toOsg(resultCallback1.m_hitNormalWorld)) <= sMaxSlope);
|
||||
actor->setOnGround(isWalkableSlope(resultCallback1.m_hitNormalWorld));
|
||||
return toOsg(resultCallback1.m_hitPointWorld) + osg::Vec3f(0.f, 0.f, 1.f);
|
||||
}
|
||||
|
||||
actor->setOnGround(getSlope(tracer.mPlaneNormal) <= sMaxSlope);
|
||||
actor->setOnGround(isWalkableSlope(tracer.mPlaneNormal));
|
||||
|
||||
return tracer.mEndPos;
|
||||
}
|
||||
|
@ -312,8 +346,8 @@ namespace MWPhysics
|
|||
velocity *= 1.f-(fStromWalkMult * (angleDegrees/180.f));
|
||||
}
|
||||
|
||||
Stepper stepper(collisionWorld, colobj);
|
||||
osg::Vec3f origVelocity = velocity;
|
||||
|
||||
osg::Vec3f newPosition = position;
|
||||
/*
|
||||
* A loop to find newPosition using tracer, if successful different from the starting position.
|
||||
|
@ -332,10 +366,7 @@ namespace MWPhysics
|
|||
newPosition.z() <= swimlevel)
|
||||
{
|
||||
const osg::Vec3f down(0,0,-1);
|
||||
float movelen = velocity.normalize();
|
||||
osg::Vec3f reflectdir = reflect(velocity, down);
|
||||
reflectdir.normalize();
|
||||
velocity = slide(reflectdir, down)*movelen;
|
||||
velocity = slide(velocity, down);
|
||||
// NOTE: remainingTime is unchanged before the loop continues
|
||||
continue; // velocity updated, calculate nextpos again
|
||||
}
|
||||
|
@ -364,19 +395,25 @@ namespace MWPhysics
|
|||
break;
|
||||
}
|
||||
|
||||
|
||||
osg::Vec3f oldPosition = newPosition;
|
||||
// We hit something. Try to step up onto it. (NOTE: stepMove does not allow stepping over)
|
||||
// NOTE: stepMove modifies newPosition if successful
|
||||
const float minStep = 10.f;
|
||||
StepMoveResult result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, collisionWorld);
|
||||
if (result == Result_MaxSlope && (velocity*remainingTime).length() < minStep) // to make sure the maximum stepping distance isn't framerate-dependent or movement-speed dependent
|
||||
// We are touching something.
|
||||
if (tracer.mFraction < 1E-9f)
|
||||
{
|
||||
osg::Vec3f normalizedVelocity = velocity;
|
||||
normalizedVelocity.normalize();
|
||||
result = stepMove(colobj, newPosition, normalizedVelocity*minStep, remainingTime, collisionWorld);
|
||||
// Try to separate by backing off slighly to unstuck the solver
|
||||
const osg::Vec3f backOff = (newPosition - tracer.mHitPoint) * 1E-3f;
|
||||
newPosition += backOff;
|
||||
}
|
||||
if(result == Result_Success)
|
||||
|
||||
// We hit something. Check if we can step up.
|
||||
float hitHeight = tracer.mHitPoint.z() - tracer.mEndPos.z() + halfExtents.z();
|
||||
osg::Vec3f oldPosition = newPosition;
|
||||
bool result = false;
|
||||
if (hitHeight < sStepSizeUp && !isActor(tracer.mHitObject))
|
||||
{
|
||||
// Try to step up onto it.
|
||||
// NOTE: stepMove does not allow stepping over, modifies newPosition if successful
|
||||
result = stepper.step(newPosition, velocity*remainingTime, remainingTime);
|
||||
}
|
||||
if (result)
|
||||
{
|
||||
// don't let pure water creatures move out of water after stepMove
|
||||
if (ptr.getClass().isPureWaterCreature(ptr)
|
||||
|
@ -386,23 +423,19 @@ namespace MWPhysics
|
|||
else
|
||||
{
|
||||
// Can't move this way, try to find another spot along the plane
|
||||
osg::Vec3f direction = velocity;
|
||||
float movelen = direction.normalize();
|
||||
osg::Vec3f reflectdir = reflect(velocity, tracer.mPlaneNormal);
|
||||
reflectdir.normalize();
|
||||
osg::Vec3f newVelocity = slide(velocity, tracer.mPlaneNormal);
|
||||
|
||||
// Do not allow sliding upward if there is gravity.
|
||||
// Stepping will have taken care of that.
|
||||
if(!(newPosition.z() < swimlevel || isFlying))
|
||||
newVelocity.z() = std::min(newVelocity.z(), 0.0f);
|
||||
|
||||
osg::Vec3f newVelocity = slide(reflectdir, tracer.mPlaneNormal)*movelen;
|
||||
if ((newVelocity-velocity).length2() < 0.01)
|
||||
break;
|
||||
if ((velocity * origVelocity) <= 0.f)
|
||||
if ((newVelocity * origVelocity) <= 0.f)
|
||||
break; // ^ dot product
|
||||
|
||||
velocity = newVelocity;
|
||||
|
||||
// Do not allow sliding upward if there is gravity. Stepping will have taken
|
||||
// care of that.
|
||||
if(!(newPosition.z() < swimlevel || isFlying))
|
||||
velocity.z() = std::min(velocity.z(), 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -413,7 +446,7 @@ namespace MWPhysics
|
|||
osg::Vec3f to = newPosition - (physicActor->getOnGround() ?
|
||||
osg::Vec3f(0,0,sStepSizeDown+2.f) : osg::Vec3f(0,0,2.f));
|
||||
tracer.doTrace(colobj, from, to, collisionWorld);
|
||||
if(tracer.mFraction < 1.0f && getSlope(tracer.mPlaneNormal) <= sMaxSlope
|
||||
if(tracer.mFraction < 1.0f && isWalkableSlope(tracer.mPlaneNormal)
|
||||
&& tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup != CollisionType_Actor)
|
||||
{
|
||||
const btCollisionObject* standingOn = tracer.mHitObject;
|
||||
|
@ -996,6 +1029,8 @@ namespace MWPhysics
|
|||
bool PhysicsSystem::canMoveToWaterSurface(const MWWorld::ConstPtr &actor, const float waterlevel)
|
||||
{
|
||||
const Actor* physicActor = getActor(actor);
|
||||
if (!physicActor)
|
||||
return false;
|
||||
const float halfZ = physicActor->getHalfExtents().z();
|
||||
const osg::Vec3f actorPosition = physicActor->getPosition();
|
||||
const osg::Vec3f startingPosition(actorPosition.x(), actorPosition.y(), actorPosition.z() + halfZ);
|
||||
|
@ -1349,7 +1384,8 @@ namespace MWPhysics
|
|||
else if (physicActor->getCollisionMode() && canMoveToWaterSurface(iter->first, waterlevel))
|
||||
{
|
||||
const osg::Vec3f actorPosition = physicActor->getPosition();
|
||||
physicActor->setPosition(osg::Vec3f(actorPosition.x(), actorPosition.y(), waterlevel));
|
||||
physicActor->setPosition(osg::Vec3f(actorPosition.x(), actorPosition.y(), waterlevel));
|
||||
waterCollision = true;
|
||||
}
|
||||
}
|
||||
physicActor->setCanWaterWalk(waterCollision);
|
||||
|
|
|
@ -78,6 +78,7 @@ void ActorTracer::doTrace(const btCollisionObject *actor, const osg::Vec3f& star
|
|||
mFraction = newTraceCallback.m_closestHitFraction;
|
||||
mPlaneNormal = osg::Vec3f(tracehitnormal.x(), tracehitnormal.y(), tracehitnormal.z());
|
||||
mEndPos = (end-start)*mFraction + start;
|
||||
mHitPoint = toOsg(newTraceCallback.m_hitPointWorld);
|
||||
mHitObject = newTraceCallback.m_hitCollisionObject;
|
||||
}
|
||||
else
|
||||
|
@ -85,6 +86,7 @@ void ActorTracer::doTrace(const btCollisionObject *actor, const osg::Vec3f& star
|
|||
mEndPos = end;
|
||||
mPlaneNormal = osg::Vec3f(0.0f, 0.0f, 1.0f);
|
||||
mFraction = 1.0f;
|
||||
mHitPoint = end;
|
||||
mHitObject = NULL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace MWPhysics
|
|||
{
|
||||
osg::Vec3f mEndPos;
|
||||
osg::Vec3f mPlaneNormal;
|
||||
osg::Vec3f mHitPoint;
|
||||
const btCollisionObject* mHitObject;
|
||||
|
||||
float mFraction;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <osg/Group>
|
||||
#include <osg/Geometry>
|
||||
#include <osg/Depth>
|
||||
#include <osg/TexEnvCombine>
|
||||
|
||||
#include <osgDB/WriteFile>
|
||||
|
||||
|
@ -144,6 +145,10 @@ namespace MWRender
|
|||
image->allocateImage(mWidth, mHeight, 1, GL_RGB, GL_UNSIGNED_BYTE);
|
||||
unsigned char* data = image->data();
|
||||
|
||||
osg::ref_ptr<osg::Image> alphaImage = new osg::Image;
|
||||
alphaImage->allocateImage(mWidth, mHeight, 1, GL_ALPHA, GL_UNSIGNED_BYTE);
|
||||
unsigned char* alphaData = alphaImage->data();
|
||||
|
||||
for (int x = mMinX; x <= mMaxX; ++x)
|
||||
{
|
||||
for (int y = mMinY; y <= mMaxY; ++y)
|
||||
|
@ -208,6 +213,8 @@ namespace MWRender
|
|||
data[texelY * mWidth * 3 + texelX * 3] = r;
|
||||
data[texelY * mWidth * 3 + texelX * 3+1] = g;
|
||||
data[texelY * mWidth * 3 + texelX * 3+2] = b;
|
||||
|
||||
alphaData[texelY * mWidth+ texelX] = (y2 < 0) ? static_cast<unsigned char>(0) : static_cast<unsigned char>(255);
|
||||
}
|
||||
}
|
||||
loadingListener->increaseProgress();
|
||||
|
@ -224,6 +231,14 @@ namespace MWRender
|
|||
mBaseTexture->setImage(image);
|
||||
mBaseTexture->setResizeNonPowerOfTwoHint(false);
|
||||
|
||||
mAlphaTexture = new osg::Texture2D;
|
||||
mAlphaTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
|
||||
mAlphaTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
|
||||
mAlphaTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
|
||||
mAlphaTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
|
||||
mAlphaTexture->setImage(alphaImage);
|
||||
mAlphaTexture->setResizeNonPowerOfTwoHint(false);
|
||||
|
||||
clear();
|
||||
|
||||
loadingListener->loadingOff();
|
||||
|
@ -299,6 +314,28 @@ namespace MWRender
|
|||
stateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
|
||||
stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||
stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
|
||||
|
||||
if (mAlphaTexture)
|
||||
{
|
||||
osg::ref_ptr<osg::Vec2Array> texcoords = new osg::Vec2Array;
|
||||
|
||||
float x1 = x / static_cast<float>(mWidth);
|
||||
float x2 = (x + width) / static_cast<float>(mWidth);
|
||||
float y1 = y / static_cast<float>(mHeight);
|
||||
float y2 = (y + height) / static_cast<float>(mHeight);
|
||||
texcoords->push_back(osg::Vec2f(x1, y1));
|
||||
texcoords->push_back(osg::Vec2f(x1, y2));
|
||||
texcoords->push_back(osg::Vec2f(x2, y2));
|
||||
texcoords->push_back(osg::Vec2f(x2, y1));
|
||||
geom->setTexCoordArray(1, texcoords, osg::Array::BIND_PER_VERTEX);
|
||||
|
||||
stateset->setTextureAttributeAndModes(1, mAlphaTexture, osg::StateAttribute::ON);
|
||||
osg::ref_ptr<osg::TexEnvCombine> texEnvCombine = new osg::TexEnvCombine;
|
||||
texEnvCombine->setCombine_RGB(osg::TexEnvCombine::REPLACE);
|
||||
texEnvCombine->setSource0_RGB(osg::TexEnvCombine::PREVIOUS);
|
||||
stateset->setTextureAttributeAndModes(1, texEnvCombine);
|
||||
}
|
||||
|
||||
camera->addChild(geom);
|
||||
}
|
||||
|
||||
|
|
|
@ -107,6 +107,7 @@ namespace MWRender
|
|||
std::vector< std::pair<int,int> > mExploredCells;
|
||||
|
||||
osg::ref_ptr<osg::Texture2D> mBaseTexture;
|
||||
osg::ref_ptr<osg::Texture2D> mAlphaTexture;
|
||||
|
||||
// GPU copy of overlay
|
||||
// Note, uploads are pushed through a Camera, instead of through mOverlayImage
|
||||
|
|
|
@ -943,8 +943,8 @@ public:
|
|||
|
||||
void setState(const MoonState& state)
|
||||
{
|
||||
float radsX = ((state.mRotationFromHorizon) * M_PI) / 180.0f;
|
||||
float radsZ = ((state.mRotationFromNorth) * M_PI) / 180.0f;
|
||||
float radsX = ((state.mRotationFromHorizon) * static_cast<float>(osg::PI)) / 180.0f;
|
||||
float radsZ = ((state.mRotationFromNorth) * static_cast<float>(osg::PI)) / 180.0f;
|
||||
|
||||
osg::Quat rotX(radsX, osg::Vec3f(1.0f, 0.0f, 0.0f));
|
||||
osg::Quat rotZ(radsZ, osg::Vec3f(0.0f, 0.0f, 1.0f));
|
||||
|
@ -954,7 +954,7 @@ public:
|
|||
|
||||
// The moon quad is initially oriented facing down, so we need to offset its X-axis
|
||||
// rotation to rotate it to face the camera when sitting at the horizon.
|
||||
osg::Quat attX((-M_PI / 2.0f) + radsX, osg::Vec3f(1.0f, 0.0f, 0.0f));
|
||||
osg::Quat attX((-static_cast<float>(osg::PI) / 2.0f) + radsX, osg::Vec3f(1.0f, 0.0f, 0.0f));
|
||||
mTransform->setAttitude(attX * rotZ);
|
||||
|
||||
setPhase(state.mPhase);
|
||||
|
|
|
@ -437,7 +437,9 @@ bool OpenAL_SoundStream::process()
|
|||
alGetSourcei(mSource, AL_SOURCE_STATE, &state);
|
||||
if(state != AL_PLAYING && state != AL_PAUSED)
|
||||
{
|
||||
// Ensure all processed buffers are removed so we don't replay them.
|
||||
refillQueue();
|
||||
|
||||
alSourcePlay(mSource);
|
||||
}
|
||||
}
|
||||
|
@ -906,7 +908,10 @@ void OpenAL_Output::finishSound(MWBase::SoundPtr sound)
|
|||
ALuint source = GET_PTRID(sound->mHandle);
|
||||
sound->mHandle = 0;
|
||||
|
||||
alSourceStop(source);
|
||||
// Rewind the stream instead of stopping it, this puts the source into an AL_INITIAL state,
|
||||
// which works around a bug in the MacOS OpenAL implementation which would otherwise think
|
||||
// the initial queue already played when it hasn't.
|
||||
alSourceRewind(source);
|
||||
alSourcei(source, AL_BUFFER, 0);
|
||||
|
||||
mFreeSources.push_back(source);
|
||||
|
@ -1006,7 +1011,10 @@ void OpenAL_Output::finishStream(MWBase::SoundStreamPtr sound)
|
|||
sound->mHandle = 0;
|
||||
mStreamThread->remove(stream);
|
||||
|
||||
alSourceStop(source);
|
||||
// Rewind the stream instead of stopping it, this puts the source into an AL_INITIAL state,
|
||||
// which works around a bug in the MacOS OpenAL implementation which would otherwise think
|
||||
// the initial queue already played when it hasn't.
|
||||
alSourceRewind(source);
|
||||
alSourcei(source, AL_BUFFER, 0);
|
||||
|
||||
mFreeSources.push_back(source);
|
||||
|
|
|
@ -8,23 +8,6 @@
|
|||
|
||||
#include "player.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
void getFollowers (const MWWorld::Ptr& actor, std::set<MWWorld::Ptr>& out)
|
||||
{
|
||||
std::list<MWWorld::Ptr> followers = MWBase::Environment::get().getMechanicsManager()->getActorsFollowing(actor);
|
||||
for(std::list<MWWorld::Ptr>::iterator it = followers.begin();it != followers.end();++it)
|
||||
{
|
||||
if (out.insert(*it).second)
|
||||
{
|
||||
getFollowers(*it, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
ActionTeleport::ActionTeleport (const std::string& cellName,
|
||||
|
@ -37,21 +20,12 @@ namespace MWWorld
|
|||
{
|
||||
if (mTeleportFollowers)
|
||||
{
|
||||
//find any NPC that is following the actor and teleport him too
|
||||
// Find any NPCs that are following the actor and teleport them with him
|
||||
std::set<MWWorld::Ptr> followers;
|
||||
getFollowers(actor, followers);
|
||||
for(std::set<MWWorld::Ptr>::iterator it = followers.begin();it != followers.end();++it)
|
||||
{
|
||||
MWWorld::Ptr follower = *it;
|
||||
getFollowersToTeleport(actor, followers);
|
||||
|
||||
std::string script = follower.getClass().getScript(follower);
|
||||
if (!script.empty() && follower.getRefData().getLocals().getIntVar(script, "stayoutside") == 1)
|
||||
continue;
|
||||
|
||||
if ((follower.getRefData().getPosition().asVec3() - actor.getRefData().getPosition().asVec3()).length2()
|
||||
<= 800*800)
|
||||
teleport(*it);
|
||||
}
|
||||
for (std::set<MWWorld::Ptr>::iterator it = followers.begin(); it != followers.end(); ++it)
|
||||
teleport(*it);
|
||||
}
|
||||
|
||||
teleport(actor);
|
||||
|
@ -82,4 +56,21 @@ namespace MWWorld
|
|||
world->moveObject(actor,world->getInterior(mCellName),mPosition.pos[0],mPosition.pos[1],mPosition.pos[2]);
|
||||
}
|
||||
}
|
||||
|
||||
void ActionTeleport::getFollowersToTeleport(const MWWorld::Ptr& actor, std::set<MWWorld::Ptr>& out) {
|
||||
std::set<MWWorld::Ptr> followers;
|
||||
MWBase::Environment::get().getMechanicsManager()->getActorsFollowing(actor, followers);
|
||||
|
||||
for(std::set<MWWorld::Ptr>::iterator it = followers.begin();it != followers.end();++it)
|
||||
{
|
||||
MWWorld::Ptr follower = *it;
|
||||
|
||||
std::string script = follower.getClass().getScript(follower);
|
||||
if (!script.empty() && follower.getRefData().getLocals().getIntVar(script, "stayoutside") == 1)
|
||||
continue;
|
||||
|
||||
if ((follower.getRefData().getPosition().asVec3() - actor.getRefData().getPosition().asVec3()).length2() <= 800*800)
|
||||
out.insert(follower);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef GAME_MWWORLD_ACTIONTELEPORT_H
|
||||
#define GAME_MWWORLD_ACTIONTELEPORT_H
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include <components/esm/defs.hpp>
|
||||
|
@ -23,9 +24,12 @@ namespace MWWorld
|
|||
|
||||
public:
|
||||
|
||||
ActionTeleport (const std::string& cellName, const ESM::Position& position, bool teleportFollowers);
|
||||
///< If cellName is empty, an exterior cell is assumed.
|
||||
/// If cellName is empty, an exterior cell is assumed.
|
||||
/// @param teleportFollowers Whether to teleport any following actors of the target actor as well.
|
||||
ActionTeleport (const std::string& cellName, const ESM::Position& position, bool teleportFollowers);
|
||||
|
||||
/// Outputs every actor follower who is in teleport range and wasn't ordered to not enter interiors
|
||||
static void getFollowersToTeleport(const MWWorld::Ptr& actor, std::set<MWWorld::Ptr>& out);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -137,6 +137,9 @@ namespace
|
|||
iter->load (state);
|
||||
return;
|
||||
}
|
||||
|
||||
std::cerr << "Dropping reference to " << state.mRef.mRefID << " (invalid content file link)" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// new reference
|
||||
|
|
|
@ -139,7 +139,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::add(const Ptr& itemPtr,
|
|||
|
||||
// Auto-equip items if an armor/clothing or weapon item is added, but not for the player nor werewolves
|
||||
if (actorPtr != MWMechanics::getPlayer()
|
||||
&& !(actorPtr.getClass().isNpc() && actorPtr.getClass().getNpcStats(actorPtr).isWerewolf()))
|
||||
&& actorPtr.getClass().isNpc() && !actorPtr.getClass().getNpcStats(actorPtr).isWerewolf())
|
||||
{
|
||||
std::string type = itemPtr.getTypeName();
|
||||
if (type == typeid(ESM::Armor).name() || type == typeid(ESM::Clothing).name())
|
||||
|
@ -237,10 +237,6 @@ bool MWWorld::InventoryStore::canActorAutoEquip(const MWWorld::Ptr& actor, const
|
|||
|
||||
void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor)
|
||||
{
|
||||
if (!actor.getClass().isNpc())
|
||||
// autoEquip is no-op for creatures
|
||||
return;
|
||||
|
||||
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
const MWWorld::Store<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>();
|
||||
MWMechanics::NpcStats& stats = actor.getClass().getNpcStats(actor);
|
||||
|
@ -402,8 +398,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor)
|
|||
std::pair<std::vector<int>, bool> itemsSlots =
|
||||
weapon->getClass().getEquipmentSlots (*weapon);
|
||||
|
||||
for (std::vector<int>::const_iterator slot (itemsSlots.first.begin());
|
||||
slot!=itemsSlots.first.end(); ++slot)
|
||||
if (!itemsSlots.first.empty())
|
||||
{
|
||||
if (!itemsSlots.second)
|
||||
{
|
||||
|
@ -413,8 +408,8 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor)
|
|||
}
|
||||
}
|
||||
|
||||
slots_[*slot] = weapon;
|
||||
break;
|
||||
int slot = itemsSlots.first.front();
|
||||
slots_[slot] = weapon;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -444,6 +439,50 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor)
|
|||
}
|
||||
}
|
||||
|
||||
void MWWorld::InventoryStore::autoEquipShield(const MWWorld::Ptr& actor)
|
||||
{
|
||||
bool updated = false;
|
||||
|
||||
mUpdatesEnabled = false;
|
||||
for (ContainerStoreIterator iter(begin(ContainerStore::Type_Armor)); iter != end(); ++iter)
|
||||
{
|
||||
if (iter->get<ESM::Armor>()->mBase->mData.mType != ESM::Armor::Shield)
|
||||
continue;
|
||||
|
||||
if (iter->getClass().canBeEquipped(*iter, actor).first != 1)
|
||||
continue;
|
||||
|
||||
if (iter->getClass().getItemHealth(*iter) <= 0)
|
||||
continue;
|
||||
|
||||
std::pair<std::vector<int>, bool> shieldSlots =
|
||||
iter->getClass().getEquipmentSlots(*iter);
|
||||
|
||||
if (shieldSlots.first.empty())
|
||||
continue;
|
||||
|
||||
int slot = shieldSlots.first[0];
|
||||
const ContainerStoreIterator& shield = mSlots[slot];
|
||||
|
||||
if (shield != end()
|
||||
&& shield.getType() == Type_Armor && shield->get<ESM::Armor>()->mBase->mData.mType == ESM::Armor::Shield)
|
||||
{
|
||||
if (shield->getClass().getItemHealth(*shield) >= iter->getClass().getItemHealth(*iter))
|
||||
continue;
|
||||
}
|
||||
|
||||
equip(slot, iter, actor);
|
||||
updated = true;
|
||||
}
|
||||
mUpdatesEnabled = true;
|
||||
|
||||
if (updated)
|
||||
{
|
||||
fireEquipmentChangedEvent(actor);
|
||||
updateMagicEffects(actor);
|
||||
}
|
||||
}
|
||||
|
||||
const MWMechanics::MagicEffects& MWWorld::InventoryStore::getMagicEffects() const
|
||||
{
|
||||
return mMagicEffects;
|
||||
|
@ -623,7 +662,7 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor
|
|||
// If an armor/clothing item is removed, try to find a replacement,
|
||||
// but not for the player nor werewolves.
|
||||
if (wasEquipped && (actor != MWMechanics::getPlayer())
|
||||
&& !(actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()))
|
||||
&& actor.getClass().isNpc() && !actor.getClass().getNpcStats(actor).isWerewolf())
|
||||
{
|
||||
std::string type = item.getTypeName();
|
||||
if (type == typeid(ESM::Armor).name() || type == typeid(ESM::Clothing).name())
|
||||
|
|
|
@ -162,6 +162,9 @@ namespace MWWorld
|
|||
void autoEquip (const MWWorld::Ptr& actor);
|
||||
///< Auto equip items according to stats and item value.
|
||||
|
||||
void autoEquipShield(const MWWorld::Ptr& actor);
|
||||
///< Auto-equip the shield with most health.
|
||||
|
||||
const MWMechanics::MagicEffects& getMagicEffects() const;
|
||||
///< Return magic effects from worn items.
|
||||
|
||||
|
|
|
@ -280,7 +280,9 @@ namespace MWWorld
|
|||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||
for (size_t it = 0; it != state.mSoundIds.size(); it++)
|
||||
{
|
||||
state.mSounds.push_back(sndMgr->playSound3D(pos, state.mSoundIds.at(it), 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop));
|
||||
MWBase::SoundPtr sound = sndMgr->playSound3D(pos, state.mSoundIds.at(it), 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop);
|
||||
if (sound)
|
||||
state.mSounds.push_back(sound);
|
||||
}
|
||||
|
||||
mMagicBolts.push_back(state);
|
||||
|
@ -568,8 +570,10 @@ namespace MWWorld
|
|||
|
||||
for (size_t soundIter = 0; soundIter != state.mSoundIds.size(); soundIter++)
|
||||
{
|
||||
state.mSounds.push_back(sndMgr->playSound3D(esm.mPosition, state.mSoundIds.at(soundIter), 1.0f, 1.0f,
|
||||
MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop));
|
||||
MWBase::SoundPtr sound = sndMgr->playSound3D(esm.mPosition, state.mSoundIds.at(soundIter), 1.0f, 1.0f,
|
||||
MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop);
|
||||
if (sound)
|
||||
state.mSounds.push_back(sound);
|
||||
}
|
||||
|
||||
mMagicBolts.push_back(state);
|
||||
|
|
|
@ -13,7 +13,8 @@ namespace
|
|||
enum RefDataFlags
|
||||
{
|
||||
Flag_SuppressActivate = 1, // If set, activation will be suppressed and redirected to the OnActivate flag, which can then be handled by a script.
|
||||
Flag_OnActivate = 2
|
||||
Flag_OnActivate = 2,
|
||||
Flag_ActivationBuffered = 4
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -83,6 +84,7 @@ namespace MWWorld
|
|||
try
|
||||
{
|
||||
copy (refData);
|
||||
mFlags &= ~(Flag_SuppressActivate|Flag_OnActivate|Flag_ActivationBuffered);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
@ -241,38 +243,32 @@ namespace MWWorld
|
|||
return mChanged || !mAnimationState.empty();
|
||||
}
|
||||
|
||||
bool RefData::activateByScript()
|
||||
{
|
||||
bool ret = (mFlags & Flag_ActivationBuffered);
|
||||
mFlags &= ~(Flag_SuppressActivate|Flag_OnActivate);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool RefData::activate()
|
||||
{
|
||||
if (!(mFlags & Flag_SuppressActivate))
|
||||
return true;
|
||||
if (mFlags & Flag_SuppressActivate)
|
||||
{
|
||||
mFlags |= Flag_OnActivate|Flag_ActivationBuffered;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
mFlags |= Flag_OnActivate;
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool RefData::onActivate()
|
||||
{
|
||||
bool ret = mFlags & Flag_OnActivate;
|
||||
mFlags |= Flag_SuppressActivate;
|
||||
|
||||
if (mFlags & Flag_OnActivate)
|
||||
{
|
||||
mFlags &= (~Flag_OnActivate);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RefData::activateByScript()
|
||||
{
|
||||
if (mFlags & Flag_SuppressActivate)
|
||||
{
|
||||
mFlags &= (~Flag_SuppressActivate);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
mFlags &= (~Flag_OnActivate);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const ESM::AnimationState& RefData::getAnimationState() const
|
||||
|
|
|
@ -695,9 +695,9 @@ void WeatherManager::update(float duration, bool paused)
|
|||
|
||||
double theta;
|
||||
if ( !is_night ) {
|
||||
theta = M_PI * (adjustedHour - mSunriseTime) / dayDuration;
|
||||
theta = static_cast<float>(osg::PI) * (adjustedHour - mSunriseTime) / dayDuration;
|
||||
} else {
|
||||
theta = M_PI * (1.f - (adjustedHour - adjustedNightStart) / nightDuration);
|
||||
theta = static_cast<float>(osg::PI) * (1.f - (adjustedHour - adjustedNightStart) / nightDuration);
|
||||
}
|
||||
|
||||
osg::Vec3f final(
|
||||
|
|
|
@ -320,11 +320,14 @@ void RigGeometry::updateBounds(osg::NodeVisitor *nv)
|
|||
box.expandBy(bs);
|
||||
}
|
||||
|
||||
_boundingBox = box;
|
||||
_boundingSphere = osg::BoundingSphere(_boundingBox);
|
||||
_boundingSphereComputed = true;
|
||||
for (unsigned int i=0; i<getNumParents(); ++i)
|
||||
getParent(i)->dirtyBound();
|
||||
if (box != _boundingBox)
|
||||
{
|
||||
_boundingBox = box;
|
||||
_boundingSphere = osg::BoundingSphere(_boundingBox);
|
||||
_boundingSphereComputed = true;
|
||||
for (unsigned int i=0; i<getNumParents(); ++i)
|
||||
getParent(i)->dirtyBound();
|
||||
}
|
||||
}
|
||||
|
||||
void RigGeometry::updateGeomToSkelMatrix(const osg::NodePath& nodePath)
|
||||
|
|
|
@ -108,6 +108,11 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr<osgViewer::Viewer> v
|
|||
case SDL_TEXTINPUT:
|
||||
mKeyboardListener->textInput(evt.text);
|
||||
break;
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 4)
|
||||
case SDL_KEYMAPCHANGED:
|
||||
break;
|
||||
#endif
|
||||
case SDL_JOYHATMOTION: //As we manage everything with GameController, don't even bother with these.
|
||||
case SDL_JOYAXISMOTION:
|
||||
case SDL_JOYBUTTONDOWN:
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <osg/ref_ptr>
|
||||
|
||||
#include <SDL_events.h>
|
||||
#include <SDL_version.h>
|
||||
|
||||
#include "OISCompat.hpp"
|
||||
#include "events.hpp"
|
||||
|
|
|
@ -19,9 +19,9 @@ The largest difference between OpenMW and Morrowind in terms of data structure i
|
|||
|
||||
To install mods via this new feature:
|
||||
|
||||
#. Open ``openmw.cfg`` with your preffered text editor. It is located as described in https://wiki.openmw.org/index.php?title=Paths and *not* in your OpenMW root directory.
|
||||
#. Open ``openmw.cfg`` with your preffered text editor. It is located as described in :doc:`paths` and *not* in your OpenMW root directory.
|
||||
#. Find or search for ``data=``. This is located very near the bottom of the file.
|
||||
#. Add a new line below this line and make a new entry of the format ``data=path/to/your/mod``
|
||||
#. Add a new line below this line and make a new entry of the format ``data="path/to/your/mod"``
|
||||
#. Make as many of these entries as you need for each mod folder you want to include.
|
||||
#. Save ``openmw.cfg``
|
||||
|
||||
|
|
77
docs/source/openmw-mods/font.rst
Normal file
77
docs/source/openmw-mods/font.rst
Normal file
|
@ -0,0 +1,77 @@
|
|||
Fonts
|
||||
#####
|
||||
|
||||
Morrowind .fnt fonts
|
||||
--------------------
|
||||
|
||||
Morrowind uses a custom ``.fnt`` file format. It is not compatible with the Windows Font File ``.fnt`` format, nor compatible with ``.fnt`` formats from any other Bethesda games. To our knowledge, the format is undocumented and no tools for viewing or editing these fonts exist.
|
||||
|
||||
OpenMW can load this format and convert it on the fly into something usable (see font loader `source code <https://github.com/OpenMW/openmw/blob/master/components/fontloader/fontloader.cpp#L210>`_). In OpenMW 0.32, an --export-fonts command line option was added to write the converted font (a PNG image and an XML file describing the position of each glyph in the image) to the current directory.
|
||||
|
||||
TrueType fonts
|
||||
--------------
|
||||
|
||||
Unlike vanilla Morrowind, OpenMW directly supports TrueType (``.ttf``) fonts. This is the recommended way to create new fonts.
|
||||
|
||||
- To replace the primary "Magic Cards" font:
|
||||
|
||||
#. Download `Pelagiad <http://isaskar.github.io/Pelagiad/>`_ by Isak Larborn (aka Isaskar).
|
||||
#. Install the ``openmw_font.xml`` file into ``resources/mygui/openmw_font.xml`` in your OpenMW installation.
|
||||
#. Copy ``Pelagiad.ttf`` into ``resources/mygui/`` as well.
|
||||
#. If desired, you can now delete the original ``Magic_Cards.*`` files from your Data Files/Fonts directory.
|
||||
- You can also replace the Daedric font:
|
||||
|
||||
#. Download `Ayembedt <https://github.com/georgd/OpenMW-Fonts>`_ by Georg Duffner.
|
||||
#. Install ``OMWAyembedt.otf`` into ``/resources/mygui/`` folder in your OpenMW installation.
|
||||
#. Add the following lines to openmw_font.xml::
|
||||
|
||||
<Resource type="ResourceTrueTypeFont" name="Daedric">
|
||||
<Property key="Source" value="OMWAyembedt.otf"/>
|
||||
<Property key="Size" value="24"/>
|
||||
<Property key="Resolution" value="50"/>
|
||||
<Property key="Antialias" value="false"/>
|
||||
<Property key="TabWidth" value="8"/>
|
||||
<Property key="OffsetHeight" value="0"/>
|
||||
<Codes>
|
||||
<Code range="32"/>
|
||||
<Code range="65 90"/>
|
||||
<Code range="97 122"/>
|
||||
</Codes>
|
||||
</Resource>
|
||||
|
||||
#. This font is missing a few glyphs (mostly punctuation), but is complete in the primary glyphs. If desired, you can now delete the original ``daedric.*`` files from your Data Files/Fonts directory.
|
||||
|
||||
- Another replacement for the Daedric font is `Oblivion <http://www.uesp.net/wiki/File:Obliviontt.zip>`_ by Dongle.
|
||||
|
||||
#. Install the ``Oblivion.ttf`` file resources/mygui/.
|
||||
#. The openmw_fonts.xml entry is::
|
||||
|
||||
<Resource type="ResourceTrueTypeFont" name="Daedric">
|
||||
<Property key="Source" value="Oblivion.ttf"/>
|
||||
<Property key="Size" value="30"/>
|
||||
<Property key="Resolution" value="50"/>
|
||||
<Property key="Antialias" value="false"/>
|
||||
<Property key="TabWidth" value="8"/>
|
||||
<Property key="OffsetHeight" value="0"/>
|
||||
<Codes>
|
||||
<Code range="32 34"/>
|
||||
<Code range="39"/>
|
||||
<Code range="44 46"/>
|
||||
<Code range="48 59"/>
|
||||
<Code range="63"/>
|
||||
<Code range="65 90"/>
|
||||
<Code range="97 122"/>
|
||||
<Code range="172 173"/>
|
||||
<Code range="255"/>
|
||||
<Code range="376"/>
|
||||
<Code range="894"/>
|
||||
<Code range="8211 8212"/>
|
||||
<Code range="8216 8217"/>
|
||||
<Code range="8220 8221"/>
|
||||
</Codes>
|
||||
</Resource>
|
||||
|
||||
Bitmap fonts
|
||||
------------
|
||||
|
||||
Morrowind ``.fnt`` files are essentially a bitmap font, but using them is discouraged because of no Unicode support. MyGUI has its own format for bitmap fonts. An example can be seen by using the --export-fonts command line option (see above), which converts Morrowind ``.fnt`` to a MyGUI bitmap font. This is the recommended format to use if you wish to edit Morrowind's bitmap font or create a new bitmap font.
|
|
@ -14,4 +14,7 @@ The following document is the complete reference guide to modifying, or modding,
|
|||
foreword
|
||||
differences
|
||||
mod-install
|
||||
settings/index
|
||||
fonts
|
||||
convert_bump_mapped_mods
|
||||
paths
|
|
@ -8,13 +8,20 @@ Install
|
|||
|
||||
#. Your mod probably comes in some kind of archive, such as ``.zip``, ``.rar``, ``.7z``, or something along those lines. Unpack this archive into its own folder.
|
||||
#. Ensure the structure of this folder is correct.
|
||||
|
||||
#. Locate the plugin files, ``.esp`` or ``.omwaddon``. The folder containing the plugin files we will call your *data folder*
|
||||
#. Check that all resource folders (``Meshes``, ``Textures``, etc.) containing additional resource files (the actual meshes, textures, etc.) are in the *data folder*.
|
||||
.. note::
|
||||
There may be multiple levels of folders, but the location of the plugins must be the same as the resource folders.
|
||||
#. Open your ``openmw.cfg`` file in your preferred plain text editor. It is located as described in https://wiki.openmw.org/index.php?title=Paths and *not* in your OpenMW root directory.
|
||||
|
||||
.. note::
|
||||
There may be multiple levels of folders, but the location of the plugins must be the same as the resource folders.
|
||||
|
||||
#. Open your ``openmw.cfg`` file in your preferred plain text editor. It is located as described in :doc:`paths` and *not* in your OpenMW root directory.
|
||||
#. Find or search for ``data=``. This is located very near the bottom of the file. If you are using Morrowind, this first entry should already point to your Morrowind data directory, ``Data Files``; otherwise it will point to your game file, ``.omwgame``.
|
||||
#. Create a new line underneath and type: ``data="path/to/your/data folder"`` Remember, the *data folder* is where your mod's plugin files are. The double quotes around this path name are *required*.
|
||||
|
||||
.. note::
|
||||
Some text editors, such as TextEdit on Mac, will autocorrect your double quotes to typographical "curly" quotes instead of leaving them as the propper neutral vertical quotes ``""``.
|
||||
|
||||
#. Save your ``openmw.cfg`` file.
|
||||
|
||||
You have now installed your mod. Any simple replacer mods that only contain resource files such as meshes or textures will now automatically be loaded in the order of their ``data=*`` entry. This is important to note because replacer mods that replace the same resource will overwrite previous ones as you go down the list.
|
||||
|
@ -22,6 +29,15 @@ You have now installed your mod. Any simple replacer mods that only contain reso
|
|||
Enable
|
||||
------
|
||||
|
||||
Any mods that have plugin files must be enabled to work.
|
||||
Any mods that have plugin files must be enabled to work. Master game files and plugin files can only be enabled if they have been properly installed within a *data folder* as described above.
|
||||
|
||||
#.
|
||||
#. Open the OpenMW Launcher.
|
||||
#. Click on the Data Files tab.
|
||||
#. In the Content List box, select the content list you wish to modify in the dropdown menu, or make a new one by:
|
||||
|
||||
#. Click the New Content List button and enter the name of your content list, then click OK. New lists are useful for keeping track of the mods used for different characters or for different games if you play more than one game using OpenMW.
|
||||
#. In the Content box, select your game file (``.esm`` or ``.omwgame``) from the dropdown menu.
|
||||
|
||||
#. Now you must activate the plugins you wish to use by checking the box next to their entry in the Content box list.
|
||||
#. Load order can be changed simply by dragging the entries around within the list. Mods are loaded from the top down, so if one plugin depends on another, it must be lower on the list.
|
||||
#. Click Play to run OpenMW with your game and enabled mods!
|
||||
|
|
28
docs/source/openmw-mods/paths.rst
Normal file
28
docs/source/openmw-mods/paths.rst
Normal file
|
@ -0,0 +1,28 @@
|
|||
Paths
|
||||
#####
|
||||
|
||||
The following describes the locations for the various OpenMW file paths for different types of files on different operating systems.
|
||||
|
||||
.. note::
|
||||
Actual location depends on your computer's setup. Username, harddrive, and language may vary.
|
||||
|
||||
Configuration files and log files
|
||||
---------------------------------
|
||||
|
||||
:Linux: ``$HOME/.config/openmw``
|
||||
:Mac: ``$HOME/Library/Preferences/openmw``
|
||||
:Windows: ``C:\Users\Username\Documents\my games\openmw``
|
||||
|
||||
Savegames
|
||||
---------
|
||||
|
||||
:Linux: ``$HOME/.local/share/openmw/saves``
|
||||
:Mac: ``$HOME/Library/Application Support/openmw/saves``
|
||||
:Windows: ``C:\Users\Username\Documents\my games\openmw\saves``
|
||||
|
||||
Screenshots
|
||||
-----------
|
||||
|
||||
:Linux: ``$HOME/.local/share/openmw``
|
||||
:Mac: ``$HOME/Library/Application Support/openmw``
|
||||
:Windows: ``C:\Users\Username\Documents\my games\openmw``
|
104
docs/source/openmw-mods/settings/GUI.rst
Normal file
104
docs/source/openmw-mods/settings/GUI.rst
Normal file
|
@ -0,0 +1,104 @@
|
|||
GUI Settings
|
||||
############
|
||||
|
||||
scaling factor
|
||||
--------------
|
||||
|
||||
:Type: floating point
|
||||
:Range: > 0.0
|
||||
:Default: 1.0
|
||||
|
||||
This floating point setting scales the GUI interface windows. The value must be greater than 0.0. A value of 1.0 results in the normal scale. Values much larger than 2.0 may result in user interface components being inaccessible. Until a gamepad interface is created, increasing this setting is helpful for simulating the larger interface used in console games.
|
||||
|
||||
The default value is 1.0. This setting can only be configured by editing the settings configuration file.
|
||||
|
||||
menu transparency
|
||||
-----------------
|
||||
|
||||
:Type: floating point
|
||||
:Range: 0.0 (transparent) to 1.0 (opaque)
|
||||
:Default: 0.84
|
||||
|
||||
This floating point setting controls the transparency of the GUI windows. The value should be between 0.0 (transparent) and 1.0 (opaque).
|
||||
The default value is 0.84. This setting can be adjusted in game with the Menu Transparency slider in the Prefs panel of the Options menu.
|
||||
|
||||
tooltip delay
|
||||
-------------
|
||||
|
||||
:Type: floating point
|
||||
:Range: > 0.0
|
||||
:Default: 0.0
|
||||
|
||||
This floating point value determines the number of seconds between when you begin hovering over an item and when its tooltip appears. This setting only affects the tooltip delay for objects under the crosshair in GUI mode windows. There does not appear to be a setting to control the tool tip delay in outside of GUI mode.
|
||||
|
||||
The tooltip displays context sensitive information on the selected GUI element, such as weight, value, damage, armor rating, magical effects, and detailed description.
|
||||
|
||||
The default value is 0.0. This setting can be adjusted between 0.0 and 1.0 in game with the Menu Help Delay slider in the Prefs panel of the Options menu.
|
||||
|
||||
stretch menu background
|
||||
-----------------------
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: False
|
||||
|
||||
Stretch or shrink the main menu screen, loading splash screens, introductory movie, and cut scenes to fill the specified video resolution, distorting their aspect ratio. The Bethesda provided assets have a 4:3 aspect ratio, but other assets are permitted to have other aspect ratios. If this setting is false, the assets will be centered in their correct aspect ratio, with black bars filling the remainder of the screen.
|
||||
|
||||
The default value is false. This setting can only be configured by editing the settings configuration file.
|
||||
|
||||
subtitles
|
||||
---------
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: False
|
||||
|
||||
Enable or disable subtitles for NPC spoken dialog (and some sound effects). Subtitles will appear in a tool tip box in the lower center of the screen.
|
||||
|
||||
The default value is false. This setting can be toggled in game with the Subtitles button in the Prefs panel of Options menu.
|
||||
|
||||
hit fader
|
||||
---------
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: True
|
||||
|
||||
This boolean setting enables or disables the "red flash" overlay that provides a visual clue when the character has taken damage.
|
||||
|
||||
If this setting is disabled, the player will "bleed" like NPCs do.
|
||||
|
||||
The default value is true. This setting can only be configured by editing the settings configuration file.
|
||||
|
||||
werewolf overlay
|
||||
----------------
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: True
|
||||
|
||||
Enable or disable the werewolf overlay.
|
||||
|
||||
The default value is true. This setting can only be configured by editing the settings configuration file.
|
||||
|
||||
color background owned
|
||||
----------------------
|
||||
|
||||
:Type: RGBA floating point
|
||||
:Range: 0.0 to 1.0
|
||||
:Default: 0.15 0.0 0.0 1.0
|
||||
|
||||
The following two settings determine the background color of the tool tip and the crosshair when hovering over an item owned by an NPC. The color definitions are composed of four floating point values between 0.0 and 1.0 inclusive, representing the red, green, blue and alpha channels. The alpha value is currently ignored. The crosshair color will have no effect if the crosshair setting in the HUD section is disabled.
|
||||
|
||||
The default value is "0.15 0.0 0.0 1.0", which is a dark red color. This setting can only be configured by editing the settings configuration file. This setting has no effect if the show owned setting in the Game Settings Section is false.
|
||||
|
||||
color crosshair owned
|
||||
---------------------
|
||||
|
||||
:Type: RGBA floating point
|
||||
:Range: 0.0 to 1.0
|
||||
:Default: 1.0 0.15 0.15 1.0
|
||||
|
||||
This setting sets the color of the crosshair when hovering over an item owned by an NPC. The value is composed of four floating point values representing the red, green, blue and alpha channels. The alpha value is currently ignored.
|
||||
|
||||
The default value is "1.0 0.15 0.15 1.0" which is a bright red color. This setting can only be configured by editing the settings configuration file. This setting has no effect if the crosshair setting in the HUD Settings Section is false. This setting has no effect if the show owned setting in the Game Settings Section is false.
|
13
docs/source/openmw-mods/settings/HUD.rst
Normal file
13
docs/source/openmw-mods/settings/HUD.rst
Normal file
|
@ -0,0 +1,13 @@
|
|||
HUD Settings
|
||||
############
|
||||
|
||||
crosshair
|
||||
---------
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: True
|
||||
|
||||
This boolean setting determines whether the crosshair or reticle is displayed. Some players perceive that disabling the crosshair provides a more immersive experience. Another common use is to disable the crosshair for screen shots. Enabling the crosshair provides more immediate feedback about which object that is currently the focus of actions.
|
||||
|
||||
The default value is true. This setting can be toggled with the Crosshair button in the Prefs panel of the Options menu.
|
75
docs/source/openmw-mods/settings/camera.rst
Normal file
75
docs/source/openmw-mods/settings/camera.rst
Normal file
|
@ -0,0 +1,75 @@
|
|||
Camera Settings
|
||||
###############
|
||||
|
||||
near clip
|
||||
---------
|
||||
|
||||
:Type: floating point
|
||||
:Range: > 0
|
||||
:Default: 1.0
|
||||
|
||||
This floating point setting controls the distance to the near clipping plane. The value must be greater than zero. Values greater than approximately 18.0 will occasionally clip objects in the world in front of the character. Values greater than approximately 8.0 will clip the character's hands in first person view and/or the back of their head in third person view.
|
||||
|
||||
The default value is 1.0. This setting can only be configured by editing the settings configuration file. The value must be greater than 0.0, but it's unclear if the engine enforces this limitation.
|
||||
|
||||
small feature culling
|
||||
---------------------
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: True
|
||||
|
||||
This boolean setting determines whether objects that render to a few pixels or smaller will be culled (not drawn). It generally improves performance to enable this feature, and by definition the culled objects will be very small on screen. It appears that the default definition of "small" in OpenSceneGraph is 2x2 pixels.
|
||||
|
||||
The default value is true. This setting can only be configured by editing the settings configuration file.
|
||||
|
||||
viewing distance
|
||||
----------------
|
||||
|
||||
:Type: floating point
|
||||
:Range: > 0
|
||||
:Default: 6666.0
|
||||
|
||||
This floating point values controls the maximum visible distance (also called the far clipping plane). Larger values significantly improve rendering in exterior spaces, but also increase the amount of rendered geometry and significantly reduce the frame rate. This value interacts with the exterior cell load distance setting in that it's probably undesired for this value to provide visibility into cells that have not yet been loaded. When cells are visible before loading, the geometry will "pop-in" suddenly, creating a jarring visual effect. To prevent this effect, this value must be less than::
|
||||
|
||||
(8192 * exterior cell load distance - 1024) * 0.93
|
||||
|
||||
The constant 8192 is the size of a cell, and 1024 is the threshold distance for loading a new cell. Additionally, the field of view setting also interacts with this setting because the view frustrum end is a plane, so you can see further at the edges of the screen than you should be able to. This can be observed in game by looking at distant objects and rotating the camera so the objects are near the edge of the screen. As a result, this setting should further be reduced by a factor that depends on the field of view setting. In the default configuration this reduction is 7%, hence the factor of 0.93 above. Using this factor, approximate values recommended for other exterior cell load distance settings are:
|
||||
|
||||
======= ========
|
||||
Cells Viewing
|
||||
Distance
|
||||
======= ========
|
||||
2 14285
|
||||
3 21903
|
||||
4 29522
|
||||
5 35924
|
||||
======= ========
|
||||
|
||||
Reductions of up to 25% or more can be required to completely eliminate pop-in for wide fields of view and long viewing distances near the edges of the screen, but such situations are unusual and probably not worth the performance penalty introduced by loading geometry obscured by fog in the center of the screen. See RenderingManager::configureFog for the relevant source code.
|
||||
|
||||
Enabling the distant land setting is an alternative to increasing exterior cell load distance. Note that the distant land setting does not include rendering of distant static objects, so the resulting visual effect is not the same.
|
||||
|
||||
The default value is 6666.0. This setting can be adjusted in game from the ridiculously low value of 2000.0 to a maximum of 6666.0, using the View Distance slider in the Detail tab of the Video panel of the Options menu.
|
||||
|
||||
field of view
|
||||
-------------
|
||||
|
||||
:Type: floating point
|
||||
:Range: 0-360
|
||||
:Default: 55.0
|
||||
|
||||
Sets the camera field of view in degrees. Recommended values range from 30 degrees to 110 degrees. Small values provide a very narrow field of view that creates a "zoomed in" effect, while large values cause distortion at the edges of the screen. The "field of view" setting interacts with aspect ratio of your video resolution in that more square aspect ratios (e.g. 4:3) need a wider field of view to more resemble the same field of view on a widescreen (e.g. 16:9) monitor.
|
||||
|
||||
The default value is 55.0. This setting can be changed in game using the Field of View slider from the Video tab of the Video panel of the Options menu.
|
||||
|
||||
first person field of view
|
||||
--------------------------
|
||||
|
||||
:Type: floating point
|
||||
:Range: 0-360
|
||||
:Default: 55.0
|
||||
|
||||
The floating point setting controls the field of view for first person meshes such as the player's hands and held objects. It is not recommended to change this value from its default value because the Bethesda provided Morrowind assets do not adapt well to large values, while small values can result in the hands not being visible.
|
||||
|
||||
The default value is 55.0. This setting can only be configured by editing the settings configuration file.
|
17
docs/source/openmw-mods/settings/cells.rst
Normal file
17
docs/source/openmw-mods/settings/cells.rst
Normal file
|
@ -0,0 +1,17 @@
|
|||
Cells Settings
|
||||
##############
|
||||
|
||||
exterior cell load distance
|
||||
---------------------------
|
||||
|
||||
:Type: integer
|
||||
:Range: >= 1
|
||||
:Default: 1
|
||||
|
||||
This integer setting determines the number of exterior cells adjacent to the character that will be loaded for rendering. Values greater than one may significantly affect loading times when exiting interior spaces or loading additional exterior cells. Caution is advised when increasing this setting.
|
||||
|
||||
This setting interacts with viewing distance and field of view settings.
|
||||
|
||||
It is generally very wasteful for this value to load geometry than will almost never be visible due to viewing distance and fog. For low frame rate screen shots of scenic vistas, this setting should be set high, and viewing distances adjusted accordingly.
|
||||
|
||||
The default value is 1. This value must be greater than or equal to 1. This setting can only be configured by editing the settings configuration file.
|
46
docs/source/openmw-mods/settings/game.rst
Normal file
46
docs/source/openmw-mods/settings/game.rst
Normal file
|
@ -0,0 +1,46 @@
|
|||
Game Settings
|
||||
#############
|
||||
|
||||
show owned
|
||||
----------
|
||||
|
||||
:Type: integer
|
||||
:Range: 0, 1, 2, 3
|
||||
:Default: 0
|
||||
|
||||
Enable visual clues for items owned by NPCs when the crosshair is on the object. If the setting is 0, no clues are provided which is the default Morrowind behavior. If the setting is 1, the background of the tool tip for the object is highlight in the color specified by the color background owned setting in the GUI Settings Section. If the setting is 2, the crosshair is the color of the color crosshair owned setting in the GUI Settings section. If the setting is 3, both the tool tip background and the crosshair are colored. The crosshair is not visible if crosshair is false.
|
||||
|
||||
The default value is 0 (no clues). This setting can only be configured by editing the settings configuration file.
|
||||
|
||||
best attack
|
||||
-----------
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: False
|
||||
|
||||
If this boolean setting is true, the player character will always use the most powerful attack when striking with a weapon (chop, slash or thrust). If this setting is false, the type of attack is determined by the direction that the character is moving at the time the attack begins.
|
||||
|
||||
The default value is false. This setting can be toggled with the Always Use Best Attack button in the Prefs panel of the Options menu.
|
||||
|
||||
difficulty
|
||||
----------
|
||||
|
||||
:Type: integer
|
||||
:Range: -500 to 500
|
||||
:Default: 0
|
||||
|
||||
This integer setting adjusts the difficulty of the game and is intended to be in the range -100 to 100 inclusive. Given the default game setting for fDifficultyMult of 5.0, a value of -100 results in the player taking 80% of the usual damage, doing 6 times the normal damage. A value of 100 results in the player taking 6 times as much damage, but inflicting only 80% of the usual damage. Values less than -500 will result in the player receiving no damage, and values greater than 500 will result in the player inflicting no damage.
|
||||
|
||||
The default value is 0. This setting can be controlled in game with the Difficulty slider in the Prefs panel of the Options menu.
|
||||
|
||||
show effect duration
|
||||
--------------------
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: False
|
||||
|
||||
Show the remaining duration of magic effects and lights if this boolean setting is true. The remaining duration is displayed in the tooltip by hovering over the magical effect.
|
||||
|
||||
The default value is false. This setting can only be configured by editing the settings configuration file.
|
35
docs/source/openmw-mods/settings/general.rst
Normal file
35
docs/source/openmw-mods/settings/general.rst
Normal file
|
@ -0,0 +1,35 @@
|
|||
General Settings
|
||||
################
|
||||
|
||||
anisotropy
|
||||
----------
|
||||
|
||||
:Type: integer
|
||||
:Range: 0 to 16
|
||||
:Default: 4
|
||||
|
||||
Set the maximum anisotropic filtering on textures. Anisotropic filtering is a method of enhancing the image quality of textures on surfaces that are at oblique viewing angles with respect to the camera. Valid values range from 0 to 16. Modern video cards can often perform 8 or 16 anisotropic filtering with a minimal performance impact. This effect of this setting can be seen in the Video panel of the Options menu by finding a location with straight lines (striped rugs and Balmora cobblestones work well) radiating into the distance, and adjusting the anisotropy slider.
|
||||
|
||||
The default value is 4. This setting can be changed in game using the Anisotropy slider in the Detail tab of the Video panel of the Options menu.
|
||||
|
||||
screenshot format
|
||||
-----------------
|
||||
|
||||
:Type: string
|
||||
:Range: jpg, png, tga
|
||||
:Default: png
|
||||
|
||||
Specify the format for screen shots taken by pressing the screen shot key (bound to F12 by default). This setting should be the file extension commonly associated with the desired format. The formats supported will be determined at compilation, but "jpg", "png", and "tga" should be allowed.
|
||||
|
||||
The default value is "png". This setting can only be configured by editing the settings configuration file.
|
||||
|
||||
texture filtering
|
||||
-----------------
|
||||
|
||||
:Type: string
|
||||
:Range: bilinear, trilinear
|
||||
:Default: trilinear
|
||||
|
||||
Set the isotropic texture filtering mode to bilinear or trilinear. Bilinear filtering is a texture filtering method used to smooth textures when displayed larger or smaller than they actually are. Bilinear filtering is reasonably accurate until the scaling of the texture gets below half or above double the original size of the texture. Trilinear filtering is an extension of the bilinear texture filtering method, which also performs linear interpolation between mipmaps. Both methods use mipmaps in OpenMW, and the corresponding OpenGL modes are LINEAR_MIPMAP_NEAREST and LINEAR_MIPMAP_LINEAR. Trilinear filtering produces better texturing at a minimal cost on modern video cards.
|
||||
|
||||
The default value is trilinear. This setting can be changed in game using the Texture filtering pull down in the Detail tab of the Video panel of the Options menu.
|
28
docs/source/openmw-mods/settings/index.rst
Normal file
28
docs/source/openmw-mods/settings/index.rst
Normal file
|
@ -0,0 +1,28 @@
|
|||
###############################
|
||||
Advanced Settings Configuration
|
||||
###############################
|
||||
|
||||
This part of the guide will cover how to make modifications to the more arcane settings in OpenMW, most of which are not available from in-game menus, to optimize or customize your OpenMW experience. If you are familiar with ``.ini`` tweaks in Morrowind or the other games, this will be quite similar. All settings described in this section are changed in ``settings.cfg``, located in your OpenMW user directory. See :doc:`paths` for this location.
|
||||
|
||||
Although this guide attempts to be comprehensive and up to date. You will always be able to find the full list of settings available and their default values in ``settings-default.cfg`` in your main OpenMW installation directory. The ranges I have included with each setting are the physically possible ranges, not recommendations.
|
||||
|
||||
.. warning::
|
||||
As the title suggests, these are advanced settings. If digging around plain text files and manually editing settings sounds scary to you, you may want to stear clear of altering these files. That being said, this guide should be plenty clear enough that you can find the setting you want to change and safely edit it.
|
||||
|
||||
.. toctree::
|
||||
:caption: Table of Contents
|
||||
:maxdepth: 2
|
||||
|
||||
camera
|
||||
cells
|
||||
map
|
||||
GUI
|
||||
HUD
|
||||
game
|
||||
general
|
||||
input
|
||||
saves
|
||||
sound
|
||||
video
|
||||
water
|
||||
windows
|
83
docs/source/openmw-mods/settings/input.rst
Normal file
83
docs/source/openmw-mods/settings/input.rst
Normal file
|
@ -0,0 +1,83 @@
|
|||
Input Settings
|
||||
##############
|
||||
|
||||
grab cursor
|
||||
-----------
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: True
|
||||
|
||||
OpenMW will capture control of the cursor if this boolean setting is true.
|
||||
|
||||
In "look mode", OpenMW will center the cursor regardless of the value of this setting (since the cursor/crosshair is always centered in the OpenMW window). However, in GUI mode, this setting determines the behavior when the cursor is moved outside the OpenMW window. If true, the cursor movement stops at the edge of the window preventing access to other applications. If false, the cursor is allowed to move freely on the desktop.
|
||||
|
||||
This setting does not apply to the screen where escape has been pressed, where the cursor is never captured. Regardless of this setting "Alt-Tab" or some other operating system dependent key sequence can be used to allow the operating system to regain control of the mouse cursor. This setting interacts with the minimize on focus loss setting by affecting what counts as a focus loss. Specifically on a two-screen configuration it may be more convenient to access the second screen with setting disabled.
|
||||
|
||||
Note for developers: it's desirable to have this setting disabled when running the game in a debugger, to prevent the mouse cursor from becoming unusable when the game pauses on a breakpoint.
|
||||
|
||||
The default value is true. This setting can only be configured by editing the settings configuration file.
|
||||
|
||||
toggle sneak
|
||||
------------
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: False
|
||||
|
||||
This boolean setting causes the behavior of the sneak key (bound to Ctrl by default) to toggle sneaking on and off rather than requiring the key to be held down while sneaking. Players that spend significant time sneaking may find the character easier to control with this option enabled.
|
||||
|
||||
The default value is false. This setting can only be configured by editing the settings configuration file.
|
||||
|
||||
always run
|
||||
----------
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: False
|
||||
|
||||
If this boolean setting is true, the character is running by default, otherwise the character is walking by default. The shift key will temporarily invert this setting, and the caps lock key will invert this setting while it's "locked". This setting is updated every time you exit the game, based on whether the caps lock key was on or off at the time you exited.
|
||||
|
||||
The default value is false. This settings can be toggled in game by pressing the CapsLock key and exiting.
|
||||
|
||||
allow third person zoom
|
||||
-----------------------
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: False
|
||||
|
||||
Allow zooming in and out using the middle mouse wheel in third person view. This feature may not work correctly if the mouse wheel is bound to other actions, and may be triggered accidentally in some cases, so is disabled by default. This setting can only be configured by editing the settings configuration file.
|
||||
|
||||
camera sensitivity
|
||||
------------------
|
||||
|
||||
:Type: floating point
|
||||
:Range: > 0
|
||||
:Default: 1.0
|
||||
|
||||
This floating point setting controls the overall camera/mouse sensitivity when not in GUI mode. The default sensitivity is 1.0, with smaller values requiring more mouse movement, and larger values requiring less. This setting is multiplicative in magnitude. This setting does not affect mouse speed in GUI mode, which is instead controlled by your operating system mouse speed setting.
|
||||
|
||||
The default value is 1.0. This setting can be changed with the Camera Sensitivity slider in the Controls panel of the Options menu.
|
||||
|
||||
camera y multiplier
|
||||
-------------------
|
||||
|
||||
:Type: floating point
|
||||
:Range: > 0
|
||||
:Default: 1.0
|
||||
|
||||
This floating point setting controls the vertical camera/mouse sensitivity relative to the horizontal sensitivity (see camera sensitivity above). It is multiplicative with the previous setting, meaning that it should remain set at 1.0 unless the player desires to have different sensitivities in the two axes.
|
||||
|
||||
The default value is 1.0. This setting can only be configured by editing the settings configuration file.
|
||||
|
||||
invert y axis
|
||||
-------------
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: False
|
||||
|
||||
Invert the vertical axis while not in GUI mode. If this setting is true, moving the mouse away from the player will look down, while moving it towards the player will look up. This setting does not affect cursor movement in GUI mode.
|
||||
|
||||
The default value is false. This setting can be toggled in game with the Invert Y Axis button in the Controls panel of the Options menu.
|
53
docs/source/openmw-mods/settings/map.rst
Normal file
53
docs/source/openmw-mods/settings/map.rst
Normal file
|
@ -0,0 +1,53 @@
|
|||
Map Settings
|
||||
############
|
||||
|
||||
global map size
|
||||
---------------
|
||||
|
||||
:Type: integer
|
||||
:Range: >= 1
|
||||
:Default: 18
|
||||
|
||||
This integer setting adjusts the scale of the world map in the GUI mode map window. The value is the width in pixels of each cell in the map, so larger values result in larger more detailed world maps, while smaller values result in smaller less detailed world maps. However, the native resolution of the map source material appears to be 9 pixels per unexplored cell and approximately 18 pixels per explored cell, so values larger than 36 don't produce much additional detail. Similarly, the size of place markers is currently fixed at 12 pixels, so values smaller than this result in overlapping place markers. Values from 12 to 36 are recommended. For reference, Vvardenfell is approximately 41x36 cells.
|
||||
|
||||
Warning: Changing this setting affects saved games. The currently explored area is stored as an image in the save file that's overlayed on the default world map in game. When you increase the resolution of the map, the overlay of earlier saved games will be scaled up on load, and appear blurry. When you visit the cell again, the overlay for that cell is regenerated at the new resolution, so the blurry areas can be corrected by revisiting all the cells you've already visited.
|
||||
|
||||
The default value for this setting is 18. This setting can not be configured except by editing the settings configuration file.
|
||||
|
||||
local map hud widget size
|
||||
-------------------------
|
||||
|
||||
:Type: integer
|
||||
:Range: >= 1
|
||||
:Default: 256
|
||||
|
||||
This integer setting controls the zoom level for the HUD map widget (the map in the lower right corner of the window). A value of 64 results in the HUD map widget displaying one entire exterior cell. Since the GUI mode map displays 3x3 cells, a value of approximately 21 displays the same area as the GUI mode map. Larger values increase the level of zoom, while smaller values are wasteful since there's no map data to display beyond the 3x3 cell grid.
|
||||
|
||||
Note that the actual size of the widget is always the same on the screen unless the scaling factor setting in the "GUI" section is changed. Increasing both the scaling factor of the GUI and this setting does result in a higher resolution HUD map, but unfortunately with a scaled direction pointer on top of it.
|
||||
|
||||
The default value for this setting is 256. This setting can not be configured except by editing the settings configuration file.
|
||||
|
||||
local map resolution
|
||||
--------------------
|
||||
|
||||
:Type: integer
|
||||
:Range: >= 1
|
||||
:Default: 256
|
||||
|
||||
This integer setting controls the resolution of the GUI mode local map window. Larger values generally increase the visible detail in map. If this setting is half the local map widget size or smaller, the map will generally be be fairly blurry. Setting both options to the same value results in a map with good detail. Values that exceed the local map widget size setting by more than a factor of two are unlikely to provide much of an improvement in detail since they're subsequently scaled back to the approximately the map widget size before display. The video resolution settings interacts with this setting in that regard.
|
||||
|
||||
.. warning::
|
||||
Increasing this setting can increase cell load times, because the map is rendered on demand each time you enter a new cell. Large values may exceed video card limits or exhaust VRAM.
|
||||
|
||||
The default value for this setting is 256. This setting can not be configured except by editing the settings configuration file.
|
||||
|
||||
local map widget size
|
||||
---------------------
|
||||
|
||||
:Type: integer
|
||||
:Range: >= 1
|
||||
:Default: 512
|
||||
|
||||
This integer setting controls the canvas size of the GUI mode local map window. Larger values result in a larger physical map size on screen, and typically require more panning to see all available portions of the map. This larger size also enables an overall greater level of detail if the local map resolution setting is also increased.
|
||||
|
||||
The default value for this setting is 512. This setting can not be configured except by editing the settings configuration file.
|
35
docs/source/openmw-mods/settings/saves.rst
Normal file
35
docs/source/openmw-mods/settings/saves.rst
Normal file
|
@ -0,0 +1,35 @@
|
|||
Saves Settings
|
||||
##############
|
||||
|
||||
character
|
||||
---------
|
||||
|
||||
:Type: string
|
||||
:Range:
|
||||
:Default: ""
|
||||
|
||||
This string setting contains the default character name for loading saved games.
|
||||
|
||||
The default value is the empty string, which results in no character being selected by default. This setting is automatically updated from the Load menu when a different character is selected.
|
||||
|
||||
autosave
|
||||
--------
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: True
|
||||
|
||||
This boolean setting determines whether the game will be automatically saved when the character rests.
|
||||
|
||||
The default value is true. This setting can be toggled in game with the Auto-Save when Rest button in the Prefs panel of the Options menu.
|
||||
|
||||
timeplayed
|
||||
----------
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: False
|
||||
|
||||
This boolean setting determines whether the amount of the time the player has spent playing will be displayed for each saved game in the Load menu.
|
||||
|
||||
The default value is false. This setting can only be configured by editing the settings configuration file. This setting was added in OpenMW 0.37.
|
113
docs/source/openmw-mods/settings/sound.rst
Normal file
113
docs/source/openmw-mods/settings/sound.rst
Normal file
|
@ -0,0 +1,113 @@
|
|||
Sound Settings
|
||||
##############
|
||||
|
||||
device
|
||||
------
|
||||
|
||||
:Type: string
|
||||
:Range:
|
||||
:Default: ""
|
||||
|
||||
This string setting determines which audio device to use. A blank or missing setting means to use the default device, which should usually be sufficient, but if you need to explicitly specify a device use this setting.
|
||||
|
||||
The names of detected devices can be found in the openmw.log file in your configuration directory.
|
||||
|
||||
The default value is the empty string. This setting can only be configured by editing the settings configuration file.
|
||||
|
||||
master volume
|
||||
-------------
|
||||
|
||||
:Type: floating point
|
||||
:Range: 0.0 to 1.0
|
||||
:Default: 1.0
|
||||
|
||||
This floating point setting controls the overall volume. The master volume is multiplied with all other volume settings to determine the final volume.
|
||||
|
||||
The default value is 1.0. Valid values range from 0.0 (silent) to 1.0 (maximum volume). This setting can be changed in game using the Master slider from the Audio panel of the Options menu.
|
||||
|
||||
footsteps volume
|
||||
----------------
|
||||
|
||||
:Type: floating point
|
||||
:Range: 0.0 to 1.0
|
||||
:Default: 0.2
|
||||
|
||||
This floating point setting controls the volume of footsteps from the character and other actors.
|
||||
|
||||
The default value is 0.2. Valid values range from 0.0 (silent) to 1.0 (maximum volume). This setting can be changed in game using the Footsteps slider from the Audio panel of the Options menu.
|
||||
|
||||
music volume
|
||||
------------
|
||||
|
||||
:Type: floating point
|
||||
:Range: 0.0 to 1.0
|
||||
:Default: 0.5
|
||||
|
||||
This floating point setting controls the volume for music tracks.
|
||||
|
||||
The default value is 0.5. Valid values range from 0.0 (silent) to 1.0 (maximum volume). This setting can be changed in game using the Music slider from the Audio panel of the Options menu.
|
||||
|
||||
sfx volume
|
||||
----------
|
||||
|
||||
:Type: floating point
|
||||
:Range: 0.0 to 1.0
|
||||
:Default: 1.0
|
||||
|
||||
This floating point setting controls the volume for special sound effects such as combat noises.
|
||||
|
||||
The default value is 1.0. Valid values range from 0.0 (silent) to 1.0 (maximum volume). This setting can be changed in game using the Effects slider from the Audio panel of the Options menu.
|
||||
|
||||
voice volume
|
||||
------------
|
||||
|
||||
:Type: floating point
|
||||
:Range: 0.0 to 1.0
|
||||
:Default: 0.8
|
||||
|
||||
This floating point setting controls the volume for spoken dialog from NPCs.
|
||||
|
||||
The default value is 0.8. Valid values range from 0.0 (silent) to 1.0 (maximum volume). This setting can be changed in game using the Voice slider from the Audio panel of the Options menu.
|
||||
|
||||
buffer cache min
|
||||
----------------
|
||||
|
||||
:Type: integer
|
||||
:Range: > 0
|
||||
:Default: 14
|
||||
|
||||
This integer setting determines the minimum size of the sound buffer cache in megabytes. When the cache reaches the size specified by the buffer cache max setting, old buffers will be unloaded until it's using no more memory than specified by this setting. This setting must be less than or equal to the buffer cache max setting.
|
||||
|
||||
The default value is 14. This setting can only be configured by editing the settings configuration file. This setting was added in OpenMW version 0.38.
|
||||
|
||||
buffer cache max
|
||||
----------------
|
||||
|
||||
:Type: integer
|
||||
:Range: > 0
|
||||
:Default: 16
|
||||
|
||||
This integer setting determines the maximum size of the sound buffer cache in megabytes. When the cache reaches this size, old buffers will be unloaded until it reaches the size specified by the buffer cache min setting. This setting must be greater than or equal to the buffer cache min setting.
|
||||
|
||||
The default value is 16. This setting can only be configured by editing the settings configuration file. This setting was added in OpenMW version 0.38.
|
||||
|
||||
hrtf enable
|
||||
-----------
|
||||
|
||||
:Type: integer
|
||||
:Range: -1, 0, 1
|
||||
:Default: -1
|
||||
|
||||
This integer setting determines whether to enable head-related transfer function (HRTF) audio processing. HRTF audio processing creates the perception of sounds occurring in a three dimensional space when wearing headphones. Enabling HRTF may also require an OpenAL Soft version greater than 1.17.0, and possibly some operating system configuration. A value of 0 disables HRTF processing, while a value of 1 explicitly enables HRTF processing.
|
||||
The default value is -1, which should enable the feature automatically for most users when possible. This setting can only be configured by editing the settings configuration file. This setting was added in OpenMW version 0.38.
|
||||
|
||||
hrtf
|
||||
----
|
||||
|
||||
:Type: string
|
||||
:Range:
|
||||
:Default: ""
|
||||
|
||||
This string setting specifies which HRTF profile to use when HRTF is enabled. Blank means use the default. This setting has no effect if HRTF is not enabled based on the hrtf enable setting. Allowed values for this field are enumerated in openmw.log file is an HRTF enabled ausio system is installed.
|
||||
|
||||
The default value is the empty string, which uses the default profile. This setting can only be configured by editing the settings configuration file. This setting was added in OpenMW version 0.38.
|
135
docs/source/openmw-mods/settings/video.rst
Normal file
135
docs/source/openmw-mods/settings/video.rst
Normal file
|
@ -0,0 +1,135 @@
|
|||
Video Settings
|
||||
##############
|
||||
|
||||
resolution x
|
||||
------------
|
||||
|
||||
:Type: integer
|
||||
:Range: > 0
|
||||
:Default: 800
|
||||
|
||||
This setting determines the horizontal resolution of the OpenMW game window. Larger values produce more detailed images within the constraints of your graphics hardware but also significantly reduce the frame rate.
|
||||
|
||||
The default value is 800. The window resolution can be selected from a menu of common screen sizes in the Video tab of the Video Panel of the Options menu, or in the Graphics tab of the OpenMW Launcher. The horizontal resolution can also be set to a custom value in the Graphics tab of the OpenMW Launcher.
|
||||
|
||||
resolution y
|
||||
------------
|
||||
|
||||
:Type: integer
|
||||
:Range: > 0
|
||||
:Default: 600
|
||||
|
||||
This setting determines the vertical resolution of the OpenMW game window. Larger values produce more detailed images within the constraints of your graphics hardware but also significantly reduce the frame rate.
|
||||
|
||||
The default value is 600. The window resolution can be selected from a menu of common screen sizes in the Video tab of the Video Panel of the Options menu, or in the Graphics tab of the OpenMW Launcher. The vertical resolution can also be set to a custom value in the Graphics tab of the OpenMW Launcher.
|
||||
|
||||
fullscreen
|
||||
----------
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: False
|
||||
|
||||
This boolean setting determines whether the entire screen is used for the specified resolution.
|
||||
|
||||
The default value is false. This setting can be toggled in game using the Fullscreen button in the Video tab of the Video panel in the Options menu. It can also be toggled with the Full Screen check box in the Graphics tab of the OpenMW Launcher.
|
||||
|
||||
screen
|
||||
------
|
||||
|
||||
:Type: integer
|
||||
:Range: >= 0
|
||||
:Default: 0
|
||||
|
||||
This integer setting determines which screen the game will open on in multi-monitor configurations. This setting is particularly important when the fullscreen setting is true, since this is the only way to control which screen is used, but it can also be used to control which screen a normal window or a borderless window opens on as well. The screens are numbered in increasing order, beginning with 0.
|
||||
|
||||
The default value is 0. This setting can be selected from a pull down menu in the Graphics tab of the OpenMW Launcher, but cannot be changed during game play.
|
||||
|
||||
minimize on focus loss
|
||||
----------------------
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: False
|
||||
|
||||
Minimize the OpenMW window if it loses cursor focus. This setting is primarily useful for single screen configurations, so that the OpenMW screen in full screen mode can be minimized when the operating system regains control of the mouse and keyboard. On multiple screen configurations, disabling this option makes it easier to switch between screens while playing OpenMW.
|
||||
|
||||
Note that a minimized game window consumes less system resources and produces less heat, since the game does not need to render in minimized state. It is therefore advisable to minimize the game during pauses (either via use of this setting, or by minimizing the window manually).
|
||||
|
||||
This setting has no effect if the fullscreen setting is false.
|
||||
|
||||
Developer note: corresponds to SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS.
|
||||
|
||||
The default value is true. This setting can only be configured by editing the settings configuration file.
|
||||
|
||||
window border
|
||||
-------------
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: True
|
||||
|
||||
This boolean setting determines whether there's an operating system border drawn around the OpenMW window. If this setting is true, the window can be moved and resized with the operating system window controls. If this setting is false, the window has no operating system border.
|
||||
|
||||
This setting has no effect if the fullscreen setting is true.
|
||||
|
||||
The default value is true. This setting can be toggled in game using the Window Border button in the Video tab of the Video panel in the Options menu. It can also be toggled with the Window Border check box in the OpenMW Launcher.
|
||||
|
||||
antialiasing
|
||||
------------
|
||||
|
||||
:Type: integer
|
||||
:Range: 0, 2, 4, 8, 16
|
||||
:Default: 0
|
||||
|
||||
This integer setting controls anti-aliasing. Anti-aliasing is a technique designed to improve the appearance of polygon edges, so they do not appear to be "jagged". Anti-aliasing can smooth these edges at the cost of a minor reduction in the frame rate. A value of 0 disables anti-aliasing. Other powers of two (e.g. 2, 4, 8, 16) are supported according to the capabilities of your graphics hardware. Higher values do a better job of smoothing out the image but have a greater impact on frame rate.
|
||||
|
||||
This setting can be configured from a list of valid choices in the Graphics panel of the OpenMW Launcher, but cannot be changed during game play - due to a technical limitation that may be addressed in a future version of OpenMW.
|
||||
|
||||
vsync
|
||||
-----
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: False
|
||||
|
||||
This boolean setting determines whether frame draws are synchronized with the vertical refresh rate of your monitor. Enabling this setting can reduce screen tearing, a visual defect caused by updating the image buffer in the middle of a screen draw. Enabling this option typically implies limiting the framerate to 60 frames per second, but may also introduce additional delays caused by having to wait until the appropriate time (the vertical blanking interval) to draw a frame.
|
||||
|
||||
The default value is false. This setting can be adjusted in game using the VSync button in the Video tab of the Video panel in the Options menu. It can also be changed by toggling the Vertical Sync check box in the Graphics tab of the OpenMW Launcher.
|
||||
|
||||
framerate limit
|
||||
---------------
|
||||
|
||||
:Type: floating point
|
||||
:Range: >= 0.0
|
||||
:Default: 0.0
|
||||
|
||||
This floating point setting determines the maximum frame rate in frames per second. If this setting is 0.0, the frame rate is unlimited.
|
||||
|
||||
There are several reasons to consider capping your frame rate, especially if you're already experiencing a relatively high frame rate (greater than 60 frames per second). Lower frame rates will consume less power and generate less heat and noise. Frame rates above 60 frames per second rarely produce perceptible improvements in visual quality, but may improve input responsiveness. Capping the frame rate may in some situations reduce the perception of choppiness (highly variable frame rates during game play) by lowering the peak frame rates.
|
||||
|
||||
This setting interacts with the vsync setting in the Video section in the sense that enabling vertical sync limits the frame rate to the refresh rate of your monitor (often 60 frames per second). Choosing to limit the frame rate using this setting instead of vsync may reduce input lag due to the game not having to wait for the vertical blanking interval.
|
||||
|
||||
The default value is 0.0. This setting can only be configured by editing the settings configuration file. This setting was added in OpenMW 0.37.
|
||||
|
||||
contrast
|
||||
--------
|
||||
|
||||
:Type: floating point
|
||||
:Range: > 0.0
|
||||
:Default: 1.0
|
||||
|
||||
This floating point setting controls the contrast correction for all video in the game.
|
||||
|
||||
The default value is 1.0. This setting can only be configured by editing the settings configuration file. This setting does not currently work under Linux.
|
||||
|
||||
gamma
|
||||
-----
|
||||
|
||||
:Type: floating point
|
||||
:Range: > 0.0
|
||||
:Default: 1.0
|
||||
|
||||
This floating point setting controls the gamma correction for all video in the game. Gamma is an exponent that makes colors brighter if greater than 1.0 and darker if less than 1.0.
|
||||
|
||||
The default value is 1.0. This setting can be changed in the Detail tab of the Video panel of the Options menu. This setting does not currently work under Linux, and the in-game setting in the Options menu has been disabled.
|
43
docs/source/openmw-mods/settings/water.rst
Normal file
43
docs/source/openmw-mods/settings/water.rst
Normal file
|
@ -0,0 +1,43 @@
|
|||
Water Settings
|
||||
############
|
||||
|
||||
.. note::
|
||||
The settings for the water shader are difficult to describe, but can be seen immediately in the Water tab of the Video panel in the Options menu. Changes there will be saved to these settings. It is suggested to stand on the shore of a moderately broad body of water with trees or other objects on the far shore to test reflection textures, underwater plants in shallow water near by to test refraction textures, and some deep water visible from your location to test deep water visibility.
|
||||
|
||||
shader
|
||||
------
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: False
|
||||
|
||||
This boolean setting enables or disables the water shader, which results in much more realistic looking water surfaces, including reflected objects and a more detailed wavy surface.
|
||||
|
||||
The default value is false. This setting can be toggled with the Shader button in the Water tab of the Video panel of the Options menu.
|
||||
|
||||
rtt size
|
||||
--------
|
||||
|
||||
:Type: integer
|
||||
:Range: > 0
|
||||
:Default: 512
|
||||
|
||||
The integer setting determines the size of the texture used for reflection and refraction (if enabled). For reflection, the texture size determines the detail of reflected images on the surface of the water. For refraction, the texture size determines the detail of the objects on the other side of the plane of water (which have a wavy appearance caused by the refraction). RTT is an acronym for Render to Texture which allows rendering of the scene to be saved as a texture.
|
||||
Higher values produces better visuals and result in a marginally lower frame rate depending on your graphics hardware.
|
||||
|
||||
In the Water tab of the Video panel of the Options menu, the choices are Low (512), Medium (1024) and High (2048). This setting has no effect if the shader setting is false. It is recommended to use values that are a power of two because this results in more efficient use of video hardware.
|
||||
|
||||
This setting has no effect if the shader setting is false.
|
||||
|
||||
refraction
|
||||
----------
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: False
|
||||
|
||||
This boolean setting enables the refraction rendering feature of the water shader. Refraction causes deep water to be more opaque and objects seen through the plane of the water to have a wavy appearance. Enabling this feature results in better visuals, and a marginally lower frame rate depending on your graphics hardware.
|
||||
|
||||
This setting has no effect if the shader setting is false.
|
||||
|
||||
The default setting is false. This setting can be toggled with the Refraction button in the Water tab of the Video panel of the Options menu.
|
149
docs/source/openmw-mods/settings/windows.rst
Normal file
149
docs/source/openmw-mods/settings/windows.rst
Normal file
|
@ -0,0 +1,149 @@
|
|||
Windows Settings
|
||||
############
|
||||
|
||||
:Type: floating point
|
||||
:Range: 0.0 to 1.0
|
||||
|
||||
This section controls the location and size of each window in GUI mode. Each setting is a floating point number representing a *fraction* of the resolution x or resolution y setting in the Video Settings Section. The X and Y values locate the top left corner of the window, while the W value determines the width of the window and the H value determines the height of the window.
|
||||
|
||||
Unlike the documentation for most sections which lists the exact setting name, this page instead lists the names of the windows. For example, to configure the alchemy window, the actual settings would be::
|
||||
|
||||
alchemy x = 0.25
|
||||
alchemy y = 0.25
|
||||
alchemy h = 0.5
|
||||
alchemy w = 0.5
|
||||
|
||||
Each window in the GUI mode remembers it's previous location when exiting the game. By far the easiest way to configure these settings is to simply move the windows around in game. Hand editing the configuration file might result in some fine tuning for alignment, but the settings will be overwritten if a window is moved.
|
||||
|
||||
.. note::
|
||||
To scale the windows, making the widgets proportionally larger, see the scaling factor setting instead.
|
||||
|
||||
stats
|
||||
-----
|
||||
|
||||
:Default: x = 0.0
|
||||
y = 0.0
|
||||
h = 0.375
|
||||
w = 0.4275
|
||||
|
||||
The stats window, displaying level, race, class, skills and stats. Activated by clicking on any of the three bars in the lower left corner of the HUD.
|
||||
|
||||
spells
|
||||
------
|
||||
|
||||
:Default: x = 0.625
|
||||
y = 0.5725
|
||||
h = 0.375
|
||||
w = 0.4275
|
||||
|
||||
The spells window, displaying powers, spells, and magical items. Activated by clicking on the spells widget (third from left) in the bottom left corner of the HUD.
|
||||
|
||||
map
|
||||
---
|
||||
|
||||
:Default: x = 0.625
|
||||
y = 0.0
|
||||
h = 0.375
|
||||
w = 0.5725
|
||||
|
||||
The local and world map window. Activated by clicking on the map widget in the bottom right corner of the HUD.
|
||||
|
||||
dialogue
|
||||
--------
|
||||
|
||||
:Default: x = 0.095
|
||||
y = 0.095
|
||||
h = 0.810
|
||||
w = 0.810
|
||||
|
||||
The dialog window, for talking with NPCs. Activated by clicking on a NPC.
|
||||
|
||||
alchemy
|
||||
-------
|
||||
|
||||
:Default: x = 0.25
|
||||
y = 0.25
|
||||
h = 0.5
|
||||
w = 0.5
|
||||
|
||||
The alchemy window, for crafting potions. Activated by dragging an alchemy tool on to the rag doll. Unlike most other windows, this window hides all other windows when opened.
|
||||
|
||||
console
|
||||
-------
|
||||
|
||||
:Default: x = 0.0
|
||||
y = 0.0
|
||||
h = 1.0
|
||||
w = 0.5
|
||||
|
||||
The console command window. Activated by pressing the tilde (~) key.
|
||||
|
||||
inventory
|
||||
---------
|
||||
|
||||
:Default: x = 0.0
|
||||
y = 0.4275
|
||||
h = 0.6225
|
||||
w = 0.5725
|
||||
|
||||
The inventory window, displaying the paper doll and possessions, when activated by clicking on the inventory widget (second from left) in the bottom left corner of the HUD.
|
||||
|
||||
inventory container
|
||||
-------------------
|
||||
|
||||
:Default: x = 0.0
|
||||
y = 0.4275
|
||||
h = 0.6225
|
||||
w = 0.5725
|
||||
|
||||
The player's inventory window while searching a container, showing the contents of the character's inventory. Activated by clicking on a container. The same window is used for searching dead bodies, and pickpocketing people.
|
||||
|
||||
inventory barter
|
||||
----------------
|
||||
|
||||
:Default: x = 0.0
|
||||
y = 0.4275
|
||||
h = 0.6225
|
||||
w = 0.5725
|
||||
|
||||
The player's inventory window while bartering. It displays goods owned by the character while bartering. Activated by clicking on the Barter choice in the dialog window for an NPC.
|
||||
|
||||
inventory companion
|
||||
-------------------
|
||||
|
||||
:Default: x = 0.0
|
||||
y = 0.4275
|
||||
h = 0.6225
|
||||
w = 0.5725
|
||||
|
||||
The player's inventory window while interacting with a companion. The companion windows were added in the Tribunal expansion, but are available everywhere in the OpenMW engine.
|
||||
|
||||
container
|
||||
---------
|
||||
|
||||
:Default: x = 0.25
|
||||
y = 0.0
|
||||
h = 0.75
|
||||
w = 0.375
|
||||
|
||||
The container window, showing the contents of the container. Activated by clicking on a container. The same window is used for searching dead bodies, and pickpocketing people.
|
||||
|
||||
barter
|
||||
------
|
||||
|
||||
:Default: x = 0.25
|
||||
y = 0.0
|
||||
h = 0.75
|
||||
w = 0.375
|
||||
|
||||
The NPC bartering window, displaying goods owned by the shopkeeper while bartering. Activated by clicking on the Barter choice in the dialog window for an NPC.
|
||||
|
||||
companion
|
||||
---------
|
||||
|
||||
:Default: x = 0.25
|
||||
y = 0.0
|
||||
h = 0.75
|
||||
w = 0.375
|
||||
|
||||
The NPC's inventory window while interacting with a companion. The companion windows were added in the Tribunal expansion, but are available everywhere in the OpenMW engine.
|
Loading…
Reference in a new issue