mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 22:53:50 +00:00
Merged pull request #1931
This commit is contained in:
commit
9dd0d641bc
19 changed files with 258 additions and 73 deletions
|
@ -233,6 +233,10 @@ namespace MWBase
|
||||||
|
|
||||||
virtual void castSpell(const MWWorld::Ptr& ptr, const std::string spellId, bool manualSpell) = 0;
|
virtual void castSpell(const MWWorld::Ptr& ptr, const std::string spellId, bool manualSpell) = 0;
|
||||||
|
|
||||||
|
virtual void processChangedSettings (const std::set< std::pair<std::string, std::string> >& settings) = 0;
|
||||||
|
|
||||||
|
virtual float getActorsProcessingRange() const = 0;
|
||||||
|
|
||||||
/// Check if the target actor was detected by an observer
|
/// Check if the target actor was detected by an observer
|
||||||
/// If the observer is a non-NPC, check all actors in AI processing distance as observers
|
/// If the observer is a non-NPC, check all actors in AI processing distance as observers
|
||||||
virtual bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer) = 0;
|
virtual bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer) = 0;
|
||||||
|
|
|
@ -302,6 +302,9 @@ namespace MWBase
|
||||||
|
|
||||||
virtual bool castRay (float x1, float y1, float z1, float x2, float y2, float z2) = 0;
|
virtual bool castRay (float x1, float y1, float z1, float x2, float y2, float z2) = 0;
|
||||||
|
|
||||||
|
virtual void setActorCollisionMode(const MWWorld::Ptr& ptr, bool enabled) = 0;
|
||||||
|
virtual bool isActorCollisionEnabled(const MWWorld::Ptr& ptr) = 0;
|
||||||
|
|
||||||
virtual bool toggleCollisionMode() = 0;
|
virtual bool toggleCollisionMode() = 0;
|
||||||
///< Toggle collision mode for player. If disabled player object should ignore
|
///< Toggle collision mode for player. If disabled player object should ignore
|
||||||
/// collisions and gravity.
|
/// collisions and gravity.
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/soundmanager.hpp"
|
#include "../mwbase/soundmanager.hpp"
|
||||||
#include "../mwbase/inputmanager.hpp"
|
#include "../mwbase/inputmanager.hpp"
|
||||||
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
|
||||||
#include "confirmationdialog.hpp"
|
#include "confirmationdialog.hpp"
|
||||||
|
@ -437,6 +438,7 @@ namespace MWGui
|
||||||
MWBase::Environment::get().getSoundManager()->processChangedSettings(changed);
|
MWBase::Environment::get().getSoundManager()->processChangedSettings(changed);
|
||||||
MWBase::Environment::get().getWindowManager()->processChangedSettings(changed);
|
MWBase::Environment::get().getWindowManager()->processChangedSettings(changed);
|
||||||
MWBase::Environment::get().getInputManager()->processChangedSettings(changed);
|
MWBase::Environment::get().getInputManager()->processChangedSettings(changed);
|
||||||
|
MWBase::Environment::get().getMechanicsManager()->processChangedSettings(changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsWindow::onKeyboardSwitchClicked(MyGUI::Widget* _sender)
|
void SettingsWindow::onKeyboardSwitchClicked(MyGUI::Widget* _sender)
|
||||||
|
|
|
@ -147,9 +147,6 @@ void getRestorationPerHourOfSleep (const MWWorld::Ptr& ptr, float& health, float
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
const float aiProcessingDistance = 7168;
|
|
||||||
const float sqrAiProcessingDistance = aiProcessingDistance*aiProcessingDistance;
|
|
||||||
|
|
||||||
class SoulTrap : public MWMechanics::EffectSourceVisitor
|
class SoulTrap : public MWMechanics::EffectSourceVisitor
|
||||||
{
|
{
|
||||||
MWWorld::Ptr mCreature;
|
MWWorld::Ptr mCreature;
|
||||||
|
@ -364,7 +361,8 @@ namespace MWMechanics
|
||||||
const ESM::Position& actor1Pos = actor1.getRefData().getPosition();
|
const ESM::Position& actor1Pos = actor1.getRefData().getPosition();
|
||||||
const ESM::Position& actor2Pos = actor2.getRefData().getPosition();
|
const ESM::Position& actor2Pos = actor2.getRefData().getPosition();
|
||||||
float sqrDist = (actor1Pos.asVec3() - actor2Pos.asVec3()).length2();
|
float sqrDist = (actor1Pos.asVec3() - actor2Pos.asVec3()).length2();
|
||||||
if (sqrDist > sqrAiProcessingDistance)
|
|
||||||
|
if (sqrDist > mActorsProcessingRange*mActorsProcessingRange)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// No combat for totally static creatures
|
// No combat for totally static creatures
|
||||||
|
@ -1130,8 +1128,11 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Actors::Actors() {
|
Actors::Actors()
|
||||||
|
{
|
||||||
mTimerDisposeSummonsCorpses = 0.2f; // We should add a delay between summoned creature death and its corpse despawning
|
mTimerDisposeSummonsCorpses = 0.2f; // We should add a delay between summoned creature death and its corpse despawning
|
||||||
|
|
||||||
|
updateProcessingRange();
|
||||||
}
|
}
|
||||||
|
|
||||||
Actors::~Actors()
|
Actors::~Actors()
|
||||||
|
@ -1139,6 +1140,23 @@ namespace MWMechanics
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Actors::getProcessingRange() const
|
||||||
|
{
|
||||||
|
return mActorsProcessingRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Actors::updateProcessingRange()
|
||||||
|
{
|
||||||
|
// We have to cap it since using high values (larger than 7168) will make some quests harder or impossible to complete (bug #1876)
|
||||||
|
static const float maxProcessingRange = 7168.f;
|
||||||
|
static const float minProcessingRange = maxProcessingRange / 2.f;
|
||||||
|
|
||||||
|
float actorsProcessingRange = Settings::Manager::getFloat("actors processing range", "Game");
|
||||||
|
actorsProcessingRange = std::min(actorsProcessingRange, maxProcessingRange);
|
||||||
|
actorsProcessingRange = std::max(actorsProcessingRange, minProcessingRange);
|
||||||
|
mActorsProcessingRange = actorsProcessingRange;
|
||||||
|
}
|
||||||
|
|
||||||
void Actors::addActor (const MWWorld::Ptr& ptr, bool updateImmediately)
|
void Actors::addActor (const MWWorld::Ptr& ptr, bool updateImmediately)
|
||||||
{
|
{
|
||||||
removeActor(ptr);
|
removeActor(ptr);
|
||||||
|
@ -1184,7 +1202,7 @@ namespace MWMechanics
|
||||||
// Otherwise check if any actor in AI processing range sees the target actor
|
// Otherwise check if any actor in AI processing range sees the target actor
|
||||||
std::vector<MWWorld::Ptr> actors;
|
std::vector<MWWorld::Ptr> actors;
|
||||||
osg::Vec3f position (actor.getRefData().getPosition().asVec3());
|
osg::Vec3f position (actor.getRefData().getPosition().asVec3());
|
||||||
getObjectsInRange(position, aiProcessingDistance, actors);
|
getObjectsInRange(position, mActorsProcessingRange, actors);
|
||||||
for(std::vector<MWWorld::Ptr>::iterator it = actors.begin(); it != actors.end(); ++it)
|
for(std::vector<MWWorld::Ptr>::iterator it = actors.begin(); it != actors.end(); ++it)
|
||||||
{
|
{
|
||||||
if (*it == actor)
|
if (*it == actor)
|
||||||
|
@ -1242,7 +1260,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
if (iter->first == player) continue;
|
if (iter->first == player) continue;
|
||||||
|
|
||||||
bool inProcessingRange = (playerPos - iter->first.getRefData().getPosition().asVec3()).length2() <= sqrAiProcessingDistance;
|
bool inProcessingRange = (playerPos - iter->first.getRefData().getPosition().asVec3()).length2() <= mActorsProcessingRange*mActorsProcessingRange;
|
||||||
if (inProcessingRange)
|
if (inProcessingRange)
|
||||||
{
|
{
|
||||||
MWMechanics::CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first);
|
MWMechanics::CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first);
|
||||||
|
@ -1288,7 +1306,8 @@ namespace MWMechanics
|
||||||
if (timerUpdateEquippedLight >= updateEquippedLightInterval) timerUpdateEquippedLight = 0;
|
if (timerUpdateEquippedLight >= updateEquippedLightInterval) timerUpdateEquippedLight = 0;
|
||||||
|
|
||||||
// show torches only when there are darkness and no precipitations
|
// show torches only when there are darkness and no precipitations
|
||||||
bool showTorches = MWBase::Environment::get().getWorld()->useTorches();
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
|
bool showTorches = world->useTorches();
|
||||||
|
|
||||||
MWWorld::Ptr player = getPlayer();
|
MWWorld::Ptr player = getPlayer();
|
||||||
const osg::Vec3f playerPos = player.getRefData().getPosition().asVec3();
|
const osg::Vec3f playerPos = player.getRefData().getPosition().asVec3();
|
||||||
|
@ -1301,7 +1320,7 @@ namespace MWMechanics
|
||||||
int attackedByPlayerId = player.getClass().getCreatureStats(player).getHitAttemptActorId();
|
int attackedByPlayerId = player.getClass().getCreatureStats(player).getHitAttemptActorId();
|
||||||
if (attackedByPlayerId != -1)
|
if (attackedByPlayerId != -1)
|
||||||
{
|
{
|
||||||
const MWWorld::Ptr playerHitAttemptActor = MWBase::Environment::get().getWorld()->searchPtrViaActorId(attackedByPlayerId);
|
const MWWorld::Ptr playerHitAttemptActor = world->searchPtrViaActorId(attackedByPlayerId);
|
||||||
|
|
||||||
if (!playerHitAttemptActor.isInCell())
|
if (!playerHitAttemptActor.isInCell())
|
||||||
player.getClass().getCreatureStats(player).setHitAttemptActorId(-1);
|
player.getClass().getCreatureStats(player).setHitAttemptActorId(-1);
|
||||||
|
@ -1314,14 +1333,11 @@ namespace MWMechanics
|
||||||
CharacterController* ctrl = iter->second->getCharacterController();
|
CharacterController* ctrl = iter->second->getCharacterController();
|
||||||
|
|
||||||
float distSqr = (playerPos - iter->first.getRefData().getPosition().asVec3()).length2();
|
float distSqr = (playerPos - iter->first.getRefData().getPosition().asVec3()).length2();
|
||||||
// AI processing is only done within distance of 7168 units to the player. Note the "AI distance" slider doesn't affect this
|
// AI processing is only done within given distance to the player.
|
||||||
// (it only does some throttling for targets beyond the "AI distance", so doesn't give any guarantees as to whether AI will be enabled or not)
|
bool inProcessingRange = distSqr <= mActorsProcessingRange*mActorsProcessingRange;
|
||||||
// This distance could be made configurable later, but the setting must be marked with a big warning:
|
|
||||||
// using higher values will make a quest in Bloodmoon harder or impossible to complete (bug #1876)
|
|
||||||
bool inProcessingRange = distSqr <= sqrAiProcessingDistance;
|
|
||||||
|
|
||||||
if (isPlayer)
|
if (isPlayer)
|
||||||
ctrl->setAttackingOrSpell(MWBase::Environment::get().getWorld()->getPlayer().getAttackingOrSpell());
|
ctrl->setAttackingOrSpell(world->getPlayer().getAttackingOrSpell());
|
||||||
|
|
||||||
// If dead or no longer in combat, no longer store any actors who attempted to hit us. Also remove for the player.
|
// If dead or no longer in combat, no longer store any actors who attempted to hit us. Also remove for the player.
|
||||||
if (iter->first != player && (iter->first.getClass().getCreatureStats(iter->first).isDead()
|
if (iter->first != player && (iter->first.getClass().getCreatureStats(iter->first).isDead()
|
||||||
|
@ -1335,10 +1351,10 @@ namespace MWMechanics
|
||||||
|
|
||||||
if (!iter->first.getClass().getCreatureStats(iter->first).isDead())
|
if (!iter->first.getClass().getCreatureStats(iter->first).isDead())
|
||||||
{
|
{
|
||||||
bool cellChanged = MWBase::Environment::get().getWorld()->hasCellChanged();
|
bool cellChanged = world->hasCellChanged();
|
||||||
MWWorld::Ptr actor = iter->first; // make a copy of the map key to avoid it being invalidated when the player teleports
|
MWWorld::Ptr actor = iter->first; // make a copy of the map key to avoid it being invalidated when the player teleports
|
||||||
updateActor(actor, duration);
|
updateActor(actor, duration);
|
||||||
if (!cellChanged && MWBase::Environment::get().getWorld()->hasCellChanged())
|
if (!cellChanged && world->hasCellChanged())
|
||||||
{
|
{
|
||||||
return; // for now abort update of the old cell when cell changes by teleportation magic effect
|
return; // for now abort update of the old cell when cell changes by teleportation magic effect
|
||||||
// a better solution might be to apply cell changes at the end of the frame
|
// a better solution might be to apply cell changes at the end of the frame
|
||||||
|
@ -1363,7 +1379,7 @@ namespace MWMechanics
|
||||||
MWWorld::Ptr headTrackTarget;
|
MWWorld::Ptr headTrackTarget;
|
||||||
|
|
||||||
MWMechanics::CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first);
|
MWMechanics::CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first);
|
||||||
bool firstPersonPlayer = isPlayer && MWBase::Environment::get().getWorld()->isFirstPerson();
|
bool firstPersonPlayer = isPlayer && world->isFirstPerson();
|
||||||
|
|
||||||
// 1. Unconsious actor can not track target
|
// 1. Unconsious actor can not track target
|
||||||
// 2. Actors in combat and pursue mode do not bother to headtrack
|
// 2. Actors in combat and pursue mode do not bother to headtrack
|
||||||
|
@ -1423,27 +1439,25 @@ namespace MWMechanics
|
||||||
CharacterController* playerCharacter = nullptr;
|
CharacterController* playerCharacter = nullptr;
|
||||||
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||||
{
|
{
|
||||||
const float animationDistance = aiProcessingDistance + 400; // Slightly larger than AI distance so there is time to switch back to the idle animation.
|
const float dist = (playerPos - iter->first.getRefData().getPosition().asVec3()).length();
|
||||||
const float distSqr = (playerPos - iter->first.getRefData().getPosition().asVec3()).length2();
|
|
||||||
bool isPlayer = iter->first == player;
|
bool isPlayer = iter->first == player;
|
||||||
bool inAnimationRange = isPlayer || (animationDistance == 0 || distSqr <= animationDistance*animationDistance);
|
bool inRange = isPlayer || dist <= mActorsProcessingRange;
|
||||||
int activeFlag = 1; // Can be changed back to '2' to keep updating bounding boxes off screen (more accurate, but slower)
|
int activeFlag = 1; // Can be changed back to '2' to keep updating bounding boxes off screen (more accurate, but slower)
|
||||||
if (isPlayer)
|
if (isPlayer)
|
||||||
activeFlag = 2;
|
activeFlag = 2;
|
||||||
int active = inAnimationRange ? activeFlag : 0;
|
int active = inRange ? activeFlag : 0;
|
||||||
bool canFly = iter->first.getClass().canFly(iter->first);
|
|
||||||
if (canFly)
|
|
||||||
{
|
|
||||||
// Keep animating flying creatures so they don't just hover in-air
|
|
||||||
inAnimationRange = true;
|
|
||||||
active = std::max(1, active);
|
|
||||||
}
|
|
||||||
|
|
||||||
CharacterController* ctrl = iter->second->getCharacterController();
|
CharacterController* ctrl = iter->second->getCharacterController();
|
||||||
ctrl->setActive(active);
|
ctrl->setActive(active);
|
||||||
|
|
||||||
if (!inAnimationRange)
|
if (!inRange)
|
||||||
|
{
|
||||||
|
iter->first.getRefData().getBaseNode()->setNodeMask(0);
|
||||||
|
world->setActorCollisionMode(iter->first, false);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
else if (!isPlayer)
|
||||||
|
iter->first.getRefData().getBaseNode()->setNodeMask(1<<3);
|
||||||
|
|
||||||
if (iter->first.getClass().getCreatureStats(iter->first).isParalyzed())
|
if (iter->first.getClass().getCreatureStats(iter->first).isParalyzed())
|
||||||
ctrl->skipAnim();
|
ctrl->skipAnim();
|
||||||
|
@ -1455,11 +1469,28 @@ namespace MWMechanics
|
||||||
playerCharacter = ctrl;
|
playerCharacter = ctrl;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
world->setActorCollisionMode(iter->first, true);
|
||||||
ctrl->update(duration);
|
ctrl->update(duration);
|
||||||
|
|
||||||
|
// Fade away actors on large distance (>90% of actor's processing distance)
|
||||||
|
float visibilityRatio = 1.0;
|
||||||
|
float fadeStartDistance = mActorsProcessingRange*0.9f;
|
||||||
|
float fadeEndDistance = mActorsProcessingRange;
|
||||||
|
float fadeRatio = (dist - fadeStartDistance)/(fadeEndDistance - fadeStartDistance);
|
||||||
|
if (fadeRatio > 0)
|
||||||
|
visibilityRatio -= std::max(0.f, fadeRatio);
|
||||||
|
|
||||||
|
visibilityRatio = std::min(1.f, visibilityRatio);
|
||||||
|
|
||||||
|
ctrl->setVisibility(visibilityRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (playerCharacter)
|
if (playerCharacter)
|
||||||
|
{
|
||||||
playerCharacter->update(duration);
|
playerCharacter->update(duration);
|
||||||
|
playerCharacter->setVisibility(1.f);
|
||||||
|
}
|
||||||
|
|
||||||
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||||
{
|
{
|
||||||
|
@ -1671,7 +1702,7 @@ namespace MWMechanics
|
||||||
restoreDynamicStats(iter->first, sleep);
|
restoreDynamicStats(iter->first, sleep);
|
||||||
|
|
||||||
if ((!iter->first.getRefData().getBaseNode()) ||
|
if ((!iter->first.getRefData().getBaseNode()) ||
|
||||||
(playerPos - iter->first.getRefData().getPosition().asVec3()).length2() > sqrAiProcessingDistance)
|
(playerPos - iter->first.getRefData().getPosition().asVec3()).length2() > mActorsProcessingRange*mActorsProcessingRange)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
adjustMagicEffects (iter->first);
|
adjustMagicEffects (iter->first);
|
||||||
|
@ -1915,7 +1946,7 @@ namespace MWMechanics
|
||||||
std::list<MWWorld::Ptr> list;
|
std::list<MWWorld::Ptr> list;
|
||||||
std::vector<MWWorld::Ptr> neighbors;
|
std::vector<MWWorld::Ptr> neighbors;
|
||||||
osg::Vec3f position (actor.getRefData().getPosition().asVec3());
|
osg::Vec3f position (actor.getRefData().getPosition().asVec3());
|
||||||
getObjectsInRange(position, aiProcessingDistance, neighbors);
|
getObjectsInRange(position, mActorsProcessingRange, neighbors);
|
||||||
for(auto neighbor = neighbors.begin(); neighbor != neighbors.end(); ++neighbor)
|
for(auto neighbor = neighbors.begin(); neighbor != neighbors.end(); ++neighbor)
|
||||||
{
|
{
|
||||||
if (*neighbor == actor)
|
if (*neighbor == actor)
|
||||||
|
@ -1936,7 +1967,7 @@ namespace MWMechanics
|
||||||
std::list<MWWorld::Ptr> list;
|
std::list<MWWorld::Ptr> list;
|
||||||
std::vector<MWWorld::Ptr> neighbors;
|
std::vector<MWWorld::Ptr> neighbors;
|
||||||
osg::Vec3f position (actor.getRefData().getPosition().asVec3());
|
osg::Vec3f position (actor.getRefData().getPosition().asVec3());
|
||||||
getObjectsInRange(position, aiProcessingDistance, neighbors);
|
getObjectsInRange(position, mActorsProcessingRange, neighbors);
|
||||||
|
|
||||||
std::set<MWWorld::Ptr> followers;
|
std::set<MWWorld::Ptr> followers;
|
||||||
getActorsFollowing(actor, followers);
|
getActorsFollowing(actor, followers);
|
||||||
|
|
|
@ -65,6 +65,9 @@ namespace MWMechanics
|
||||||
/// paused we may want to do it manually (after equipping permanent enchantment)
|
/// paused we may want to do it manually (after equipping permanent enchantment)
|
||||||
void updateMagicEffects (const MWWorld::Ptr& ptr);
|
void updateMagicEffects (const MWWorld::Ptr& ptr);
|
||||||
|
|
||||||
|
void updateProcessingRange();
|
||||||
|
float getProcessingRange() const;
|
||||||
|
|
||||||
void addActor (const MWWorld::Ptr& ptr, bool updateImmediately=false);
|
void addActor (const MWWorld::Ptr& ptr, bool updateImmediately=false);
|
||||||
///< Register an actor for stats management
|
///< Register an actor for stats management
|
||||||
///
|
///
|
||||||
|
@ -168,6 +171,7 @@ namespace MWMechanics
|
||||||
private:
|
private:
|
||||||
PtrActorMap mActors;
|
PtrActorMap mActors;
|
||||||
float mTimerDisposeSummonsCorpses;
|
float mTimerDisposeSummonsCorpses;
|
||||||
|
float mActorsProcessingRange;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,7 +103,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const ESM::Pathgr
|
||||||
ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
|
ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
|
||||||
|
|
||||||
/// Stops the actor when it gets too close to a unloaded cell
|
/// Stops the actor when it gets too close to a unloaded cell
|
||||||
//... At current time, this test is unnecessary. AI shuts down when actor is more than 7168
|
//... At current time, this test is unnecessary. AI shuts down when actor is more than "actors processing range" setting value
|
||||||
//... units from player, and exterior cells are 8192 units long and wide.
|
//... units from player, and exterior cells are 8192 units long and wide.
|
||||||
//... But AI processing distance may increase in the future.
|
//... But AI processing distance may increase in the future.
|
||||||
if (isNearInactiveCell(pos))
|
if (isNearInactiveCell(pos))
|
||||||
|
@ -354,7 +354,7 @@ bool MWMechanics::AiPackage::isNearInactiveCell(const ESM::Position& actorPos)
|
||||||
|
|
||||||
// currently assumes 3 x 3 grid for exterior cells, with player at center cell.
|
// currently assumes 3 x 3 grid for exterior cells, with player at center cell.
|
||||||
// ToDo: (Maybe) use "exterior cell load distance" setting to get count of actual active cells
|
// ToDo: (Maybe) use "exterior cell load distance" setting to get count of actual active cells
|
||||||
// While AI Process distance is 7168, AI shuts down actors before they reach edges of 3 x 3 grid.
|
// AI shuts down actors before they reach edges of 3 x 3 grid.
|
||||||
const float distanceFromEdge = 200.0;
|
const float distanceFromEdge = 200.0;
|
||||||
float minThreshold = (-1.0f * ESM::Land::REAL_SIZE) + distanceFromEdge;
|
float minThreshold = (-1.0f * ESM::Land::REAL_SIZE) + distanceFromEdge;
|
||||||
float maxThreshold = (2.0f * ESM::Land::REAL_SIZE) - distanceFromEdge;
|
float maxThreshold = (2.0f * ESM::Land::REAL_SIZE) - distanceFromEdge;
|
||||||
|
|
|
@ -3,8 +3,9 @@
|
||||||
#include <components/esm/aisequence.hpp>
|
#include <components/esm/aisequence.hpp>
|
||||||
#include <components/esm/loadcell.hpp>
|
#include <components/esm/loadcell.hpp>
|
||||||
|
|
||||||
#include "../mwbase/world.hpp"
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/cellstore.hpp"
|
#include "../mwworld/cellstore.hpp"
|
||||||
|
@ -21,7 +22,8 @@ bool isWithinMaxRange(const osg::Vec3f& pos1, const osg::Vec3f& pos2)
|
||||||
// Maximum travel distance for vanilla compatibility.
|
// Maximum travel distance for vanilla compatibility.
|
||||||
// Was likely meant to prevent NPCs walking into non-loaded exterior cells, but for some reason is used in interior cells as well.
|
// Was likely meant to prevent NPCs walking into non-loaded exterior cells, but for some reason is used in interior cells as well.
|
||||||
// We can make this configurable at some point, but the default *must* be the below value. Anything else will break shoddily-written content (*cough* MW *cough*) in bizarre ways.
|
// We can make this configurable at some point, but the default *must* be the below value. Anything else will break shoddily-written content (*cough* MW *cough*) in bizarre ways.
|
||||||
return (pos1 - pos2).length2() <= 7168*7168;
|
bool aiDistance = MWBase::Environment::get().getMechanicsManager()->getActorsProcessingRange();
|
||||||
|
return (pos1 - pos2).length2() <= aiDistance*aiDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "../mwrender/animation.hpp"
|
#include "../mwrender/animation.hpp"
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/soundmanager.hpp"
|
#include "../mwbase/soundmanager.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
@ -1849,7 +1850,7 @@ void CharacterController::updateAnimQueue()
|
||||||
mAnimation->setLoopingEnabled(mAnimQueue.front().mGroup, mAnimQueue.size() <= 1);
|
mAnimation->setLoopingEnabled(mAnimQueue.front().mGroup, mAnimQueue.size() <= 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterController::update(float duration)
|
void CharacterController::update(float duration, bool animationOnly)
|
||||||
{
|
{
|
||||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
const MWWorld::Class &cls = mPtr.getClass();
|
const MWWorld::Class &cls = mPtr.getClass();
|
||||||
|
@ -2235,10 +2236,10 @@ void CharacterController::update(float duration)
|
||||||
world->rotateObject(mPtr, rot.x(), rot.y(), 0.0f, true);
|
world->rotateObject(mPtr, rot.x(), rot.y(), 0.0f, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mMovementAnimationControlled)
|
if (!animationOnly && !mMovementAnimationControlled)
|
||||||
world->queueMovement(mPtr, vec);
|
world->queueMovement(mPtr, vec);
|
||||||
}
|
}
|
||||||
else
|
else if (!animationOnly)
|
||||||
// We must always queue movement, even if there is none, to apply gravity.
|
// We must always queue movement, even if there is none, to apply gravity.
|
||||||
world->queueMovement(mPtr, osg::Vec3f(0.f, 0.f, 0.f));
|
world->queueMovement(mPtr, osg::Vec3f(0.f, 0.f, 0.f));
|
||||||
|
|
||||||
|
@ -2261,7 +2262,8 @@ void CharacterController::update(float duration)
|
||||||
playDeath(1.f, mDeathState);
|
playDeath(1.f, mDeathState);
|
||||||
}
|
}
|
||||||
// We must always queue movement, even if there is none, to apply gravity.
|
// We must always queue movement, even if there is none, to apply gravity.
|
||||||
world->queueMovement(mPtr, osg::Vec3f(0.f, 0.f, 0.f));
|
if (!animationOnly)
|
||||||
|
world->queueMovement(mPtr, osg::Vec3f(0.f, 0.f, 0.f));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isPersist = isPersistentAnimPlaying();
|
bool isPersist = isPersistentAnimPlaying();
|
||||||
|
@ -2295,7 +2297,7 @@ void CharacterController::update(float duration)
|
||||||
moved.z() = 1.0;
|
moved.z() = 1.0;
|
||||||
|
|
||||||
// Update movement
|
// Update movement
|
||||||
if(mMovementAnimationControlled && mPtr.getClass().isActor())
|
if(!animationOnly && mMovementAnimationControlled && mPtr.getClass().isActor())
|
||||||
world->queueMovement(mPtr, moved);
|
world->queueMovement(mPtr, moved);
|
||||||
|
|
||||||
mSkipAnim = false;
|
mSkipAnim = false;
|
||||||
|
@ -2544,20 +2546,6 @@ void CharacterController::updateMagicEffects()
|
||||||
{
|
{
|
||||||
if (!mPtr.getClass().isActor())
|
if (!mPtr.getClass().isActor())
|
||||||
return;
|
return;
|
||||||
float alpha = 1.f;
|
|
||||||
if (mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Invisibility).getModifier()) // Ignore base magnitude (see bug #3555).
|
|
||||||
{
|
|
||||||
if (mPtr == getPlayer())
|
|
||||||
alpha = 0.4f;
|
|
||||||
else
|
|
||||||
alpha = 0.f;
|
|
||||||
}
|
|
||||||
float chameleon = mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Chameleon).getMagnitude();
|
|
||||||
if (chameleon)
|
|
||||||
{
|
|
||||||
alpha *= std::max(0.2f, (100.f - chameleon)/100.f);
|
|
||||||
}
|
|
||||||
mAnimation->setAlpha(alpha);
|
|
||||||
|
|
||||||
bool vampire = mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Vampirism).getMagnitude() > 0.0f;
|
bool vampire = mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Vampirism).getMagnitude() > 0.0f;
|
||||||
mAnimation->setVampire(vampire);
|
mAnimation->setVampire(vampire);
|
||||||
|
@ -2566,6 +2554,32 @@ void CharacterController::updateMagicEffects()
|
||||||
mAnimation->setLightEffect(light);
|
mAnimation->setLightEffect(light);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CharacterController::setVisibility(float visibility)
|
||||||
|
{
|
||||||
|
// We should take actor's invisibility in account
|
||||||
|
if (mPtr.getClass().isActor())
|
||||||
|
{
|
||||||
|
float alpha = 1.f;
|
||||||
|
if (mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Invisibility).getModifier()) // Ignore base magnitude (see bug #3555).
|
||||||
|
{
|
||||||
|
if (mPtr == getPlayer())
|
||||||
|
alpha = 0.4f;
|
||||||
|
else
|
||||||
|
alpha = 0.f;
|
||||||
|
}
|
||||||
|
float chameleon = mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Chameleon).getMagnitude();
|
||||||
|
if (chameleon)
|
||||||
|
{
|
||||||
|
alpha *= std::max(0.2f, (100.f - chameleon)/100.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
visibility = std::min(visibility, alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: implement a dithering shader rather than just change object transparency.
|
||||||
|
mAnimation->setAlpha(visibility);
|
||||||
|
}
|
||||||
|
|
||||||
void CharacterController::setAttackTypeBasedOnMovement()
|
void CharacterController::setAttackTypeBasedOnMovement()
|
||||||
{
|
{
|
||||||
float *move = mPtr.getClass().getMovementSettings(mPtr).mPosition;
|
float *move = mPtr.getClass().getMovementSettings(mPtr).mPosition;
|
||||||
|
|
|
@ -257,7 +257,7 @@ public:
|
||||||
|
|
||||||
void updatePtr(const MWWorld::Ptr &ptr);
|
void updatePtr(const MWWorld::Ptr &ptr);
|
||||||
|
|
||||||
void update(float duration);
|
void update(float duration, bool animationOnly=false);
|
||||||
|
|
||||||
void persistAnimationState();
|
void persistAnimationState();
|
||||||
void unpersistAnimationState();
|
void unpersistAnimationState();
|
||||||
|
@ -292,6 +292,7 @@ public:
|
||||||
bool isTurning() const;
|
bool isTurning() const;
|
||||||
bool isAttackingOrSpell() const;
|
bool isAttackingOrSpell() const;
|
||||||
|
|
||||||
|
void setVisibility(float visibility);
|
||||||
void setAttackingOrSpell(bool attackingOrSpell);
|
void setAttackingOrSpell(bool attackingOrSpell);
|
||||||
void castSpell(const std::string spellId, bool manualSpell=false);
|
void castSpell(const std::string spellId, bool manualSpell=false);
|
||||||
void setAIAttackType(const std::string& attackType);
|
void setAIAttackType(const std::string& attackType);
|
||||||
|
|
|
@ -431,6 +431,25 @@ namespace MWMechanics
|
||||||
mObjects.update(duration, paused);
|
mObjects.update(duration, paused);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MechanicsManager::processChangedSettings(const Settings::CategorySettingVector &changed)
|
||||||
|
{
|
||||||
|
for (Settings::CategorySettingVector::const_iterator it = changed.begin(); it != changed.end(); ++it)
|
||||||
|
{
|
||||||
|
if (it->first == "Game" && it->second == "actors processing range")
|
||||||
|
{
|
||||||
|
mActors.updateProcessingRange();
|
||||||
|
|
||||||
|
// Update mechanics for new processing range immediately
|
||||||
|
update(0.f, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float MechanicsManager::getActorsProcessingRange() const
|
||||||
|
{
|
||||||
|
return mActors.getProcessingRange();
|
||||||
|
}
|
||||||
|
|
||||||
bool MechanicsManager::isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer)
|
bool MechanicsManager::isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer)
|
||||||
{
|
{
|
||||||
return mActors.isActorDetected(actor, observer);
|
return mActors.isActorDetected(actor, observer);
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef GAME_MWMECHANICS_MECHANICSMANAGERIMP_H
|
#ifndef GAME_MWMECHANICS_MECHANICSMANAGERIMP_H
|
||||||
#define GAME_MWMECHANICS_MECHANICSMANAGERIMP_H
|
#define GAME_MWMECHANICS_MECHANICSMANAGERIMP_H
|
||||||
|
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
|
@ -206,6 +208,10 @@ namespace MWMechanics
|
||||||
|
|
||||||
virtual void castSpell(const MWWorld::Ptr& ptr, const std::string spellId, bool manualSpell=false);
|
virtual void castSpell(const MWWorld::Ptr& ptr, const std::string spellId, bool manualSpell=false);
|
||||||
|
|
||||||
|
void processChangedSettings(const Settings::CategorySettingVector& settings) override;
|
||||||
|
|
||||||
|
virtual float getActorsProcessingRange() const;
|
||||||
|
|
||||||
/// Check if the target actor was detected by an observer
|
/// Check if the target actor was detected by an observer
|
||||||
/// If the observer is a non-NPC, check all actors in AI processing distance as observers
|
/// If the observer is a non-NPC, check all actors in AI processing distance as observers
|
||||||
virtual bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer);
|
virtual bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer);
|
||||||
|
|
|
@ -1366,6 +1366,33 @@ namespace MWPhysics
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PhysicsSystem::setActorCollisionMode(const MWWorld::Ptr& ptr, bool enabled)
|
||||||
|
{
|
||||||
|
ActorMap::iterator found = mActors.find(ptr);
|
||||||
|
if (found != mActors.end())
|
||||||
|
{
|
||||||
|
bool cmode = found->second->getCollisionMode();
|
||||||
|
if (cmode == enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cmode = enabled;
|
||||||
|
found->second->enableCollisionMode(cmode);
|
||||||
|
found->second->enableCollisionBody(cmode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PhysicsSystem::isActorCollisionEnabled(const MWWorld::Ptr& ptr)
|
||||||
|
{
|
||||||
|
ActorMap::iterator found = mActors.find(ptr);
|
||||||
|
if (found != mActors.end())
|
||||||
|
{
|
||||||
|
bool cmode = found->second->getCollisionMode();
|
||||||
|
return cmode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void PhysicsSystem::queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &movement)
|
void PhysicsSystem::queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &movement)
|
||||||
{
|
{
|
||||||
PtrVelocityList::iterator iter = mMovementQueue.begin();
|
PtrVelocityList::iterator iter = mMovementQueue.begin();
|
||||||
|
|
|
@ -86,6 +86,8 @@ namespace MWPhysics
|
||||||
void removeHeightField (int x, int y);
|
void removeHeightField (int x, int y);
|
||||||
|
|
||||||
bool toggleCollisionMode();
|
bool toggleCollisionMode();
|
||||||
|
bool isActorCollisionEnabled(const MWWorld::Ptr& ptr);
|
||||||
|
void setActorCollisionMode(const MWWorld::Ptr& ptr, bool enabled);
|
||||||
|
|
||||||
void stepSimulation(float dt);
|
void stepSimulation(float dt);
|
||||||
void debugDraw();
|
void debugDraw();
|
||||||
|
|
|
@ -1739,21 +1739,31 @@ namespace MWRender
|
||||||
|
|
||||||
if (alpha != 1.f)
|
if (alpha != 1.f)
|
||||||
{
|
{
|
||||||
osg::StateSet* stateset (new osg::StateSet);
|
// If we have an existing material for alpha transparency, just override alpha level
|
||||||
|
osg::StateSet* stateset = mObjectRoot->getOrCreateStateSet();
|
||||||
|
osg::Material* material = static_cast<osg::Material*>(stateset->getAttribute(osg::StateAttribute::MATERIAL));
|
||||||
|
if (material)
|
||||||
|
{
|
||||||
|
material->setAlpha(osg::Material::FRONT_AND_BACK, alpha);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
osg::StateSet* stateset (new osg::StateSet);
|
||||||
|
|
||||||
osg::BlendFunc* blendfunc (new osg::BlendFunc);
|
osg::BlendFunc* blendfunc (new osg::BlendFunc);
|
||||||
stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
|
stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
|
||||||
|
|
||||||
// FIXME: overriding diffuse/ambient/emissive colors
|
// FIXME: overriding diffuse/ambient/emissive colors
|
||||||
osg::Material* material (new osg::Material);
|
material = new osg::Material;
|
||||||
material->setColorMode(osg::Material::OFF);
|
material->setColorMode(osg::Material::OFF);
|
||||||
material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,alpha));
|
material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,alpha));
|
||||||
material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1));
|
material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1));
|
||||||
stateset->setAttributeAndModes(material, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
|
stateset->setAttributeAndModes(material, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
|
||||||
|
|
||||||
mObjectRoot->setStateSet(stateset);
|
mObjectRoot->setStateSet(stateset);
|
||||||
|
|
||||||
mResourceSystem->getSceneManager()->recreateShaders(mObjectRoot);
|
mResourceSystem->getSceneManager()->recreateShaders(mObjectRoot);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -1583,6 +1583,16 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void World::setActorCollisionMode(const MWWorld::Ptr& ptr, bool enabled)
|
||||||
|
{
|
||||||
|
mPhysics->setActorCollisionMode(ptr, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool World::isActorCollisionEnabled(const MWWorld::Ptr& ptr)
|
||||||
|
{
|
||||||
|
return mPhysics->isActorCollisionEnabled(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
bool World::toggleCollisionMode()
|
bool World::toggleCollisionMode()
|
||||||
{
|
{
|
||||||
if (mPhysics->toggleCollisionMode())
|
if (mPhysics->toggleCollisionMode())
|
||||||
|
@ -3560,7 +3570,13 @@ namespace MWWorld
|
||||||
MWBase::Environment::get().getMechanicsManager()->getObjectsInRange(
|
MWBase::Environment::get().getMechanicsManager()->getObjectsInRange(
|
||||||
origin, feetToGameUnits(static_cast<float>(effectIt->mArea)), objects);
|
origin, feetToGameUnits(static_cast<float>(effectIt->mArea)), objects);
|
||||||
for (std::vector<MWWorld::Ptr>::iterator affected = objects.begin(); affected != objects.end(); ++affected)
|
for (std::vector<MWWorld::Ptr>::iterator affected = objects.begin(); affected != objects.end(); ++affected)
|
||||||
|
{
|
||||||
|
// Ignore actors without collisions here, otherwise it will be possible to hit actors outside processing range.
|
||||||
|
if (affected->getClass().isActor() && !isActorCollisionEnabled(*affected))
|
||||||
|
continue;
|
||||||
|
|
||||||
toApply[*affected].push_back(*effectIt);
|
toApply[*affected].push_back(*effectIt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now apply the appropriate effects to each actor in range
|
// Now apply the appropriate effects to each actor in range
|
||||||
|
|
|
@ -407,6 +407,9 @@ namespace MWWorld
|
||||||
|
|
||||||
bool castRay (float x1, float y1, float z1, float x2, float y2, float z2) override;
|
bool castRay (float x1, float y1, float z1, float x2, float y2, float z2) override;
|
||||||
|
|
||||||
|
void setActorCollisionMode(const Ptr& ptr, bool enabled) override;
|
||||||
|
bool isActorCollisionEnabled(const Ptr& ptr) override;
|
||||||
|
|
||||||
bool toggleCollisionMode() override;
|
bool toggleCollisionMode() override;
|
||||||
///< Toggle collision mode for player. If disabled player object should ignore
|
///< Toggle collision mode for player. If disabled player object should ignore
|
||||||
/// collisions and gravity.
|
/// collisions and gravity.
|
||||||
|
|
|
@ -97,8 +97,21 @@ and values above 500 will result in the player inflicting no damage.
|
||||||
|
|
||||||
This setting can be controlled in game with the Difficulty slider in the Prefs panel of the Options menu.
|
This setting can be controlled in game with the Difficulty slider in the Prefs panel of the Options menu.
|
||||||
|
|
||||||
|
actors processing range
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
:Type: integer
|
||||||
|
:Range: 3584 to 7168
|
||||||
|
:Default: 7168
|
||||||
|
|
||||||
|
This setting allows to specify a distance from player in game units, in which OpenMW updates actor's state.
|
||||||
|
Actor state update includes AI, animations, and physics processing.
|
||||||
|
Actors near that border start softly fade out instead of just appearing/disapperaing.
|
||||||
|
|
||||||
|
This setting can be controlled in game with the "Actors processing range slider" in the Prefs panel of the Options menu.
|
||||||
|
|
||||||
classic reflected absorb spells behavior
|
classic reflected absorb spells behavior
|
||||||
-----------------------------------------
|
----------------------------------------
|
||||||
|
|
||||||
:Type: boolean
|
:Type: boolean
|
||||||
:Range: True/False
|
:Range: True/False
|
||||||
|
|
|
@ -73,7 +73,32 @@
|
||||||
<Property key="TextAlign" value="Right"/>
|
<Property key="TextAlign" value="Right"/>
|
||||||
</Widget>
|
</Widget>
|
||||||
</Widget>
|
</Widget>
|
||||||
<Widget type="HBox" skin="" position="4 200 260 24">
|
<Widget type="Widget" skin="" position="4 184 352 54" align="Left Top HStretch">
|
||||||
|
<Widget type="TextBox" skin="NormalText" position="0 0 352 16" align="Left Top" name="ActorProcessingText">
|
||||||
|
<Property key="Caption" value="Actors processing range"/>
|
||||||
|
</Widget>
|
||||||
|
<Widget type="MWScrollBar" skin="MW_HScroll" position="0 20 352 14" align="Left Top HStretch">
|
||||||
|
<Property key="Range" value="3584"/>
|
||||||
|
<Property key="Page" value="300"/>
|
||||||
|
<UserString key="SettingType" value="Slider"/>
|
||||||
|
<UserString key="SettingCategory" value="Game"/>
|
||||||
|
<UserString key="SettingName" value="actors processing range"/>
|
||||||
|
<UserString key="SettingValueType" value="Float"/>
|
||||||
|
<UserString key="SettingMin" value="3584"/>
|
||||||
|
<UserString key="SettingMax" value="7168"/>
|
||||||
|
<UserString key="SettingLabelWidget" value="ActorProcessingText"/>
|
||||||
|
<UserString key="SettingLabelCaption" value="Actors processing range"/>
|
||||||
|
</Widget>
|
||||||
|
<Widget type="TextBox" skin="SandText" position="0 38 352 16" align="Left Top">
|
||||||
|
<Property key="Caption" value="#{sLow}"/>
|
||||||
|
<Property key="TextAlign" value="Left"/>
|
||||||
|
</Widget>
|
||||||
|
<Widget type="TextBox" skin="SandText" position="0 38 352 16" align="Right Top">
|
||||||
|
<Property key="Caption" value="#{sHigh}"/>
|
||||||
|
<Property key="TextAlign" value="Right"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
<Widget type="HBox" skin="" position="4 250 260 24">
|
||||||
<Widget type="AutoSizedButton" skin="MW_Button" position="0 0 24 24" align="Left Top">
|
<Widget type="AutoSizedButton" skin="MW_Button" position="0 0 24 24" align="Left Top">
|
||||||
<UserString key="SettingCategory" value="Saves"/>
|
<UserString key="SettingCategory" value="Saves"/>
|
||||||
<UserString key="SettingName" value="autosave"/>
|
<UserString key="SettingName" value="autosave"/>
|
||||||
|
@ -83,7 +108,7 @@
|
||||||
<Property key="Caption" value="#{sQuick_Save}"/>
|
<Property key="Caption" value="#{sQuick_Save}"/>
|
||||||
</Widget>
|
</Widget>
|
||||||
</Widget>
|
</Widget>
|
||||||
<Widget type="HBox" skin="" position="4 230 260 24">
|
<Widget type="HBox" skin="" position="4 280 260 24">
|
||||||
<Widget type="AutoSizedButton" skin="MW_Button" position="0 0 24 24" align="Left Top">
|
<Widget type="AutoSizedButton" skin="MW_Button" position="0 0 24 24" align="Left Top">
|
||||||
<UserString key="SettingCategory" value="Game"/>
|
<UserString key="SettingCategory" value="Game"/>
|
||||||
<UserString key="SettingName" value="best attack"/>
|
<UserString key="SettingName" value="best attack"/>
|
||||||
|
@ -93,7 +118,7 @@
|
||||||
<Property key="Caption" value="#{sBestAttack}"/>
|
<Property key="Caption" value="#{sBestAttack}"/>
|
||||||
</Widget>
|
</Widget>
|
||||||
</Widget>
|
</Widget>
|
||||||
<Widget type="HBox" skin="" position="4 260 260 24">
|
<Widget type="HBox" skin="" position="4 310 260 24">
|
||||||
<Widget type="AutoSizedButton" skin="MW_Button" position="0 0 24 24" align="Left Top">
|
<Widget type="AutoSizedButton" skin="MW_Button" position="0 0 24 24" align="Left Top">
|
||||||
<UserString key="SettingCategory" value="GUI"/>
|
<UserString key="SettingCategory" value="GUI"/>
|
||||||
<UserString key="SettingName" value="subtitles"/>
|
<UserString key="SettingName" value="subtitles"/>
|
||||||
|
@ -103,7 +128,7 @@
|
||||||
<Property key="Caption" value="#{sSubtitles}"/>
|
<Property key="Caption" value="#{sSubtitles}"/>
|
||||||
</Widget>
|
</Widget>
|
||||||
</Widget>
|
</Widget>
|
||||||
<Widget type="HBox" skin="" position="4 290 260 24">
|
<Widget type="HBox" skin="" position="4 340 260 24">
|
||||||
<Widget type="AutoSizedButton" skin="MW_Button" position="0 0 24 24" align="Left Top">
|
<Widget type="AutoSizedButton" skin="MW_Button" position="0 0 24 24" align="Left Top">
|
||||||
<UserString key="SettingCategory" value="HUD"/>
|
<UserString key="SettingCategory" value="HUD"/>
|
||||||
<UserString key="SettingName" value="crosshair"/>
|
<UserString key="SettingName" value="crosshair"/>
|
||||||
|
|
|
@ -200,6 +200,9 @@ best attack = false
|
||||||
# Difficulty. Expressed as damage dealt and received. (e.g. -100 to 100).
|
# Difficulty. Expressed as damage dealt and received. (e.g. -100 to 100).
|
||||||
difficulty = 0
|
difficulty = 0
|
||||||
|
|
||||||
|
# The maximum range of actor AI, animations and physics updates.
|
||||||
|
actors processing range = 7168
|
||||||
|
|
||||||
# Make reflected Absorb spells have no practical effect, like in Morrowind.
|
# Make reflected Absorb spells have no practical effect, like in Morrowind.
|
||||||
classic reflected absorb spells behavior = true
|
classic reflected absorb spells behavior = true
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue