1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-02-27 19:39:41 +00:00

Add OpenMW commits up to 19 Nov 2019

# Conflicts:
#	apps/openmw/mwmechanics/aipursue.cpp
#	apps/openmw/mwmechanics/summoning.cpp
This commit is contained in:
David Cernat 2019-11-19 17:16:48 +02:00
commit 0c98c5d09e
39 changed files with 279 additions and 138 deletions

View file

@ -172,6 +172,10 @@
Bug #5186: Equipped item enchantments don't affect creatures
Bug #5190: On-strike enchantments can be applied to and used with non-projectile ranged weapons
Bug #5196: Dwarven ghosts do not use idle animations
Bug #5206: A "class does not have NPC stats" error when player's follower kills an enemy with damage spell
Bug #5209: Spellcasting ignores race height
Bug #5210: AiActivate allows actors to open dialogue and inventory windows
Bug #5211: Screen fades in if the first loaded save is in interior cell
Feature #1774: Handle AvoidNode
Feature #2229: Improve pathfinding AI
Feature #3025: Analogue gamepad movement controls

View file

@ -712,7 +712,7 @@ std::string creatureFlags(int flags)
if (flags & ESM::Creature::Respawn) properties += "Respawn ";
if (flags & ESM::Creature::Weapon) properties += "Weapon ";
if (flags & ESM::Creature::Essential) properties += "Essential ";
int unused = (0xFF ^
int unused = (0xFFFFFFFF ^
(ESM::Creature::Base|
ESM::Creature::Walks|
ESM::Creature::Swims|

View file

@ -135,7 +135,7 @@ bool Launcher::GraphicsPage::loadSettings()
if (mEngineSettings.getBool("player shadows", "Shadows"))
playerShadowsCheckBox->setCheckState(Qt::Checked);
if (mEngineSettings.getBool("terrain shadows", "Shadows"))
objectShadowsCheckBox->setCheckState(Qt::Checked);
terrainShadowsCheckBox->setCheckState(Qt::Checked);
if (mEngineSettings.getBool("object shadows", "Shadows"))
objectShadowsCheckBox->setCheckState(Qt::Checked);
if (mEngineSettings.getBool("enable indoor shadows", "Shadows"))

View file

@ -1038,6 +1038,28 @@ bool CSVRender::TerrainShapeMode::isInCellSelection(int globalSelectionX, int gl
return false;
}
void CSVRender::TerrainShapeMode::handleSelection(int globalSelectionX, int globalSelectionY, std::vector<std::pair<int, int>>* selections)
{
if (isInCellSelection(globalSelectionX, globalSelectionY)) selections->emplace_back(globalSelectionX, globalSelectionY);
else
{
int moduloX = globalSelectionX % (ESM::Land::LAND_SIZE - 1);
int moduloY = globalSelectionY % (ESM::Land::LAND_SIZE - 1);
bool xIsAtCellBorder = moduloX == 0;
bool yIsAtCellBorder = moduloY == 0;
if (!xIsAtCellBorder && !yIsAtCellBorder)
return;
int selectionX = globalSelectionX;
int selectionY = globalSelectionY;
if (xIsAtCellBorder)
selectionX--;
if (yIsAtCellBorder)
selectionY--;
if (isInCellSelection(selectionX, selectionY))
selections->emplace_back(globalSelectionX, globalSelectionY);
}
}
void CSVRender::TerrainShapeMode::selectTerrainShapes(const std::pair<int, int>& vertexCoords, unsigned char selectMode, bool dragOperation)
{
int r = mBrushSize / 2;
@ -1045,7 +1067,7 @@ void CSVRender::TerrainShapeMode::selectTerrainShapes(const std::pair<int, int>&
if (mBrushShape == CSVWidget::BrushShape_Point)
{
if (isInCellSelection(vertexCoords.first, vertexCoords.second)) selections.emplace_back(vertexCoords.first, vertexCoords.second);
handleSelection(vertexCoords.first, vertexCoords.second, &selections);
}
if (mBrushShape == CSVWidget::BrushShape_Square)
@ -1054,7 +1076,7 @@ void CSVRender::TerrainShapeMode::selectTerrainShapes(const std::pair<int, int>&
{
for(int j = vertexCoords.second - r; j <= vertexCoords.second + r; ++j)
{
if (isInCellSelection(i, j)) selections.emplace_back(i, j);
handleSelection(i, j, &selections);
}
}
}
@ -1068,7 +1090,7 @@ void CSVRender::TerrainShapeMode::selectTerrainShapes(const std::pair<int, int>&
int distanceX = abs(i - vertexCoords.first);
int distanceY = abs(j - vertexCoords.second);
int distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2)));
if (isInCellSelection(i, j) && distance <= r) selections.emplace_back(i, j);
if (distance <= r) handleSelection(i, j, &selections);
}
}
}
@ -1080,8 +1102,7 @@ void CSVRender::TerrainShapeMode::selectTerrainShapes(const std::pair<int, int>&
for(auto const& value: mCustomBrushShape)
{
std::pair<int, int> localVertexCoords (vertexCoords.first + value.first, vertexCoords.second + value.second);
std::string cellId (CSMWorld::CellCoordinates::vertexGlobalToCellId(localVertexCoords));
if (isInCellSelection(localVertexCoords.first, localVertexCoords.second)) selections.emplace_back(localVertexCoords);
handleSelection(localVertexCoords.first, localVertexCoords.second, &selections);
}
}
}
@ -1227,7 +1248,7 @@ void CSVRender::TerrainShapeMode::createNewLandData(const CSMWorld::CellCoordina
++averageDivider;
downCellSampleHeight = landDownShapePointer[ESM::Land::LAND_SIZE / 2];
if(paged->getCellAlteredHeight(cellLeftCoords, ESM::Land::LAND_SIZE / 2, 0))
if(paged->getCellAlteredHeight(cellDownCoords, ESM::Land::LAND_SIZE / 2, 0))
downCellSampleHeight += *paged->getCellAlteredHeight(cellDownCoords, ESM::Land::LAND_SIZE / 2, 0);
}
}
@ -1418,8 +1439,12 @@ void CSVRender::TerrainShapeMode::setBrushShape(CSVWidget::BrushShape brushShape
selectionCenterY = selectionCenterY + value.second;
++selectionAmount;
}
selectionCenterX = selectionCenterX / selectionAmount;
selectionCenterY = selectionCenterY / selectionAmount;
if (selectionAmount != 0)
{
selectionCenterX /= selectionAmount;
selectionCenterY /= selectionAmount;
}
mCustomBrushShape.clear();
std::pair<int, int> differentialPos {};

View file

@ -134,6 +134,9 @@ namespace CSVRender
/// Check if global selection coordinate belongs to cell in view
bool isInCellSelection(int globalSelectionX, int globalSelectionY);
/// Select vertex at global selection coordinate
void handleSelection(int globalSelectionX, int globalSelectionY, std::vector<std::pair<int, int>>* selections);
/// Handle brush mechanics for terrain shape selection
void selectTerrainShapes (const std::pair<int, int>& vertexCoords, unsigned char selectMode, bool dragOperation);

View file

@ -730,8 +730,12 @@ void CSVRender::TerrainTextureMode::setBrushShape(int brushShape)
selectionCenterY += value.second;
++selectionAmount;
}
if (selectionAmount != 0)
{
selectionCenterX /= selectionAmount;
selectionCenterY /= selectionAmount;
}
mCustomBrushShape.clear();
for (auto const& value: terrainSelection)

View file

@ -807,6 +807,8 @@ namespace MWBase
/// Return physical half extents of the given actor to be used in pathfinding
virtual osg::Vec3f getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const = 0;
virtual bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const = 0;
};
}

View file

@ -423,6 +423,12 @@ namespace MWGui
MWScript::InterpreterContext interpreterContext (&mPtr.getRefData().getLocals(), mPtr);
MWBase::Environment::get().getScriptManager()->run (script, interpreterContext);
}
// Clean up summoned creatures as well
std::map<MWMechanics::CreatureStats::SummonKey, int>& creatureMap = creatureStats.getSummonedCreatureMap();
for (const auto& creature : creatureMap)
MWBase::Environment::get().getMechanicsManager()->cleanupSummonedCreature(mPtr, creature.second);
creatureMap.clear();
}
MWBase::Environment::get().getWorld()->deleteObject(mPtr);

View file

@ -4,6 +4,7 @@
#include <MyGUI_Button.h>
#include <MyGUI_Gui.h>
#include <MyGUI_ImageBox.h>
#include <MyGUI_RenderManager.h>
#include <components/esm/esmwriter.hpp>
#include <components/esm/quickkeys.hpp>
@ -309,7 +310,12 @@ namespace MWGui
mSelected->id = item.getCellRef().getRefId();
mSelected->name = item.getClass().getName(item);
mSelected->button->setFrame("textures\\menu_icon_select_magic_magic.dds", MyGUI::IntCoord(2, 2, 40, 40));
float scale = 1.f;
MyGUI::ITexture* texture = MyGUI::RenderManager::getInstance().getTexture("textures\\menu_icon_select_magic_magic.dds");
if (texture)
scale = texture->getHeight() / 64.f;
mSelected->button->setFrame("textures\\menu_icon_select_magic_magic.dds", MyGUI::IntCoord(0, 0, 44*scale, 44*scale));
mSelected->button->setIcon(item);
mSelected->button->setUserString("ToolTipType", "ItemPtr");
@ -355,7 +361,12 @@ namespace MWGui
path.insert(slashPos+1, "b_");
path = MWBase::Environment::get().getWindowManager()->correctIconPath(path);
mSelected->button->setFrame("textures\\menu_icon_select_magic.dds", MyGUI::IntCoord(2, 2, 40, 40));
float scale = 1.f;
MyGUI::ITexture* texture = MyGUI::RenderManager::getInstance().getTexture("textures\\menu_icon_select_magic.dds");
if (texture)
scale = texture->getHeight() / 64.f;
mSelected->button->setFrame("textures\\menu_icon_select_magic.dds", MyGUI::IntCoord(0, 0, 44*scale, 44*scale));
mSelected->button->setIcon(path);
if (mMagicSelectionDialog)

View file

@ -149,7 +149,7 @@ float BookWindowBase::adjustButton (char const * name)
Gui::ImageButton* button;
WindowBase::getWidget (button, name);
MyGUI::IntSize requested = button->getRequestedSize();
float scale = requested.height / button->getSize().height;
float scale = float(requested.height) / button->getSize().height;
MyGUI::IntSize newSize = requested;
newSize.width /= scale;
newSize.height /= scale;

View file

@ -1079,7 +1079,7 @@ namespace MWMechanics
if (caster == player || playerFollowers.find(caster) != playerFollowers.end())
{
if (caster.getClass().getNpcStats(caster).isWerewolf())
if (caster.getClass().isNpc() && caster.getClass().getNpcStats(caster).isWerewolf())
caster.getClass().getNpcStats(caster).addWerewolfKill();
MWBase::Environment::get().getMechanicsManager()->actorKilled(ptr, player);
@ -2138,6 +2138,13 @@ namespace MWMechanics
if (fx)
MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel,
"", ptr.getRefData().getPosition().asVec3());
// Remove the summoned creature's summoned creatures as well
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
std::map<CreatureStats::SummonKey, int>& creatureMap = stats.getSummonedCreatureMap();
for (const auto& creature : creatureMap)
cleanupSummonedCreature(stats, creature.second);
creatureMap.clear();
}
else if (creatureActorId != -1)
{

View file

@ -13,6 +13,8 @@
#include "../mwworld/cellstore.hpp"
#include "../mwworld/inventorystore.hpp"
#include "../mwphysics/collisiontype.hpp"
#include "pathgrid.hpp"
#include "creaturestats.hpp"
#include "movement.hpp"
@ -222,8 +224,28 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor)
}
}
namespace
{
bool isDoorOnTheWay(const MWWorld::Ptr& actor, const MWWorld::Ptr& door, const osg::Vec3f& nextPathPoint)
{
const auto world = MWBase::Environment::get().getWorld();
const auto halfExtents = world->getHalfExtents(actor);
const auto position = actor.getRefData().getPosition().asVec3() + osg::Vec3f(0, 0, halfExtents.z());
const auto destination = nextPathPoint + osg::Vec3f(0, 0, halfExtents.z());
return world->hasCollisionWithDoor(door, position, destination);
}
}
void MWMechanics::AiPackage::openDoors(const MWWorld::Ptr& actor)
{
// note: AiWander currently does not open doors
if (getTypeId() == TypeIdWander)
return;
if (mPathFinder.getPathSize() == 0)
return;
MWBase::World* world = MWBase::Environment::get().getWorld();
static float distance = world->getMaxActivationDistance();
@ -231,9 +253,11 @@ void MWMechanics::AiPackage::openDoors(const MWWorld::Ptr& actor)
if (door == MWWorld::Ptr())
return;
// note: AiWander currently does not open doors
if (getTypeId() != TypeIdWander && !door.getCellRef().getTeleport() && door.getClass().getDoorState(door) == MWWorld::DoorState::Idle)
if (!door.getCellRef().getTeleport() && door.getClass().getDoorState(door) == MWWorld::DoorState::Idle)
{
if (!isDoorOnTheWay(actor, door, mPathFinder.getPath().front()))
return;
if ((door.getCellRef().getTrap().empty() && door.getCellRef().getLockLevel() <= 0 ))
{
world->activate(door, actor);

View file

@ -3,6 +3,7 @@
#include <components/esm/aisequence.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/class.hpp"
@ -104,8 +105,7 @@ bool AiPursue::execute (const MWWorld::Ptr& actor, CharacterController& characte
/*
End of tes3mp addition
*/
target.getClass().activate(target,actor).get()->execute(actor); //Arrest player when reached
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue, actor); //Arrest player when reached
return true;
}

View file

@ -1995,6 +1995,17 @@ void CharacterController::update(float duration, bool animationOnly)
bool isPlayer = mPtr == MWMechanics::getPlayer();
bool godmode = isPlayer && MWBase::Environment::get().getWorld()->getGodModeState();
float scale = mPtr.getCellRef().getScale();
static const bool normalizeSpeed = Settings::Manager::getBool("normalise race speed", "Game");
if (!normalizeSpeed && mPtr.getClass().isNpc())
{
const ESM::NPC* npc = mPtr.get<ESM::NPC>()->mBase;
const ESM::Race* race = world->getStore().get<ESM::Race>().find(npc->mRace);
float weight = npc->isMale() ? race->mData.mWeight.mMale : race->mData.mWeight.mFemale;
scale *= weight;
}
if(!cls.isActor())
updateAnimQueue();
else if(!cls.getCreatureStats(mPtr).isDead())
@ -2254,6 +2265,8 @@ void CharacterController::update(float duration, bool animationOnly)
jumpstate = mAnimation->isPlaying(mCurrentJump) ? JumpState_Landing : JumpState_None;
vec.x() *= scale;
vec.y() *= scale;
vec.z() = 0.0f;
inJump = false;
@ -2445,20 +2458,9 @@ void CharacterController::update(float duration, bool animationOnly)
else
moved = osg::Vec3f(0.f, 0.f, 0.f);
float scale = mPtr.getCellRef().getScale();
moved.x() *= scale;
moved.y() *= scale;
static const bool normalizeSpeed = Settings::Manager::getBool("normalise race speed", "Game");
if (mPtr.getClass().isNpc() && !normalizeSpeed)
{
const ESM::NPC* npc = mPtr.get<ESM::NPC>()->mBase;
const ESM::Race* race = world->getStore().get<ESM::Race>().find(npc->mRace);
float weight = npc->isMale() ? race->mData.mWeight.mMale : race->mData.mWeight.mFemale;
moved.x() *= weight;
moved.y() *= weight;
}
// Ensure we're moving in generally the right direction...
if(speed > 0.f)
{

View file

@ -34,6 +34,7 @@ namespace MWMechanics
Enchanting::Enchanting()
: mCastStyle(ESM::Enchantment::CastOnce)
, mSelfEnchanting(false)
, mWeaponType(-1)
{}
void Enchanting::setOldItem(const MWWorld::Ptr& oldItem)

View file

@ -133,10 +133,9 @@ namespace MWMechanics
}
// Update summon effects
bool casterDead = creatureStats.isDead();
for (std::map<CreatureStats::SummonKey, int>::iterator it = creatureMap.begin(); it != creatureMap.end(); )
{
bool found = !casterDead && mActiveEffects.find(it->first) != mActiveEffects.end();
bool found = mActiveEffects.find(it->first) != mActiveEffects.end();
if (!found)
{
// Effect has ended
@ -147,39 +146,11 @@ namespace MWMechanics
++it;
}
std::vector<int>& graveyard = creatureStats.getSummonedCreatureGraveyard();
for (std::vector<int>::iterator it = graveyard.begin(); it != graveyard.end(); )
{
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(*it);
if (!ptr.isEmpty())
{
it = graveyard.erase(it);
std::vector<int> graveyard = creatureStats.getSummonedCreatureGraveyard();
creatureStats.getSummonedCreatureGraveyard().clear();
const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>()
.search("VFX_Summon_End");
if (fx)
MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel,
"", ptr.getRefData().getPosition().asVec3());
MWBase::Environment::get().getWorld()->deleteObject(ptr);
/*
Start of tes3mp addition
Send an ID_OBJECT_DELETE packet every time a summoned creature despawns
*/
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
objectList->reset();
objectList->packetOrigin = mwmp::CLIENT_GAMEPLAY;
objectList->addObjectDelete(ptr);
objectList->sendObjectDelete();
/*
End of tes3mp addition
*/
}
else
++it;
}
for (const int creature : graveyard)
MWBase::Environment::get().getMechanicsManager()->cleanupSummonedCreature(mActor, creature);
if (!cleanup)
return;

View file

@ -113,7 +113,7 @@ bool ActorAnimation::updateCarriedLeftVisible(const int weaptype) const
{
SceneUtil::FindByNameVisitor findVisitor ("Bip01 AttachShield");
mObjectRoot->accept(findVisitor);
if (findVisitor.mFoundNode)
if (findVisitor.mFoundNode || (mPtr == MWMechanics::getPlayer() && mPtr.isInCell() && MWBase::Environment::get().getWorld()->isFirstPerson()))
{
const MWWorld::InventoryStore& inv = cls.getInventoryStore(mPtr);
const MWWorld::ConstContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);

View file

@ -539,7 +539,7 @@ std::string NpcAnimation::getShieldMesh(MWWorld::ConstPtr shield) const
{
const ESM::BodyPart *bodypart = 0;
bodypart = partStore.search(bodypartName);
if (bodypart->mData.mType != ESM::BodyPart::MT_Armor)
if (bodypart == nullptr || bodypart->mData.mType != ESM::BodyPart::MT_Armor)
return "";
else if (!bodypart->mModel.empty())
mesh = "meshes\\" + bodypart->mModel;

View file

@ -527,7 +527,7 @@ void Water::createSimpleWaterStateSet(osg::Node* node, float alpha)
// Add animated textures
std::vector<osg::ref_ptr<osg::Texture2D> > textures;
int frameCount = Fallback::Map::getInt("Water_SurfaceFrameCount");
int frameCount = std::max(0, std::min(Fallback::Map::getInt("Water_SurfaceFrameCount"), 320));
const std::string& texture = Fallback::Map::getString("Water_SurfaceTexture");
for (int i=0; i<frameCount; ++i)
{
@ -643,7 +643,7 @@ Water::~Water()
void Water::listAssetsToPreload(std::vector<std::string> &textures)
{
int frameCount = Fallback::Map::getInt("Water_SurfaceFrameCount");
int frameCount = std::max(0, std::min(Fallback::Map::getInt("Water_SurfaceFrameCount"), 320));
const std::string& texture = Fallback::Map::getString("Water_SurfaceTexture");
for (int i=0; i<frameCount; ++i)
{

View file

@ -18,6 +18,9 @@ namespace MWWorld
if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory))
return;
if (actor != MWMechanics::getPlayer())
return;
if (!MWBase::Environment::get().getMechanicsManager()->onOpen(getTarget()))
return;

View file

@ -3,12 +3,15 @@
#include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwmechanics/actorutil.hpp"
namespace MWWorld
{
ActionTalk::ActionTalk (const Ptr& actor) : Action (false, actor) {}
void ActionTalk::executeImp (const Ptr& actor)
{
if (actor == MWMechanics::getPlayer())
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue, getTarget());
}
}

View file

@ -49,7 +49,7 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener)
std::string fname = mast.name;
int index = ~0;
for (int i = 0; i < esm.getIndex(); i++) {
const std::string &candidate = allPlugins->at(i).getContext().filename;
const std::string candidate = allPlugins->at(i).getContext().filename;
std::string fnamecandidate = boost::filesystem::path(candidate).filename().string();
if (Misc::StringUtils::ciEqual(fname, fnamecandidate)) {
index = i;

View file

@ -262,7 +262,7 @@ namespace MWWorld
{
// Spawn at 0.75 * ActorHeight
// Note: we ignore the collision box offset, this is required to make some flying creatures work as intended.
pos.z() += mPhysics->getHalfExtents(caster).z() * 2 * 0.75;
pos.z() += mPhysics->getRenderingHalfExtents(caster).z() * 2 * 0.75;
}
if (MWBase::Environment::get().getWorld()->isUnderwater(caster.getCell(), pos)) // Underwater casting not possible

View file

@ -751,10 +751,8 @@ namespace MWWorld
void Scene::changeToInteriorCell (const std::string& cellName, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent)
{
CellStore *cell = MWBase::Environment::get().getWorld()->getInterior(cellName);
bool loadcell = (mCurrentCell == nullptr);
if(!loadcell)
loadcell = *mCurrentCell != *cell;
bool useFading = (mCurrentCell != nullptr);
if (useFading)
MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.5);
Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
@ -763,7 +761,7 @@ namespace MWWorld
loadingListener->setLabel(loadingInteriorText, false, messagesCount > 0);
Loading::ScopedLoad load(loadingListener);
if(!loadcell)
if(mCurrentCell != nullptr && *mCurrentCell == *cell)
{
MWBase::World *world = MWBase::Environment::get().getWorld();
world->moveObject(world->getPlayerPtr(), position.pos[0], position.pos[1], position.pos[2]);
@ -817,6 +815,7 @@ namespace MWWorld
if (changeEvent)
mCellChanged = true;
if (useFading)
MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5);
MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell);

View file

@ -36,6 +36,7 @@
#include <components/misc/constants.hpp>
#include <components/misc/resourcehelpers.hpp>
#include <components/misc/rng.hpp>
#include <components/misc/convert.hpp>
#include <components/files/collections.hpp>
@ -4351,4 +4352,23 @@ namespace MWWorld
return getHalfExtents(actor);
}
bool World::hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const
{
const auto object = mPhysics->getObject(door);
if (!object)
return false;
btVector3 aabbMin;
btVector3 aabbMax;
object->getShapeInstance()->getCollisionShape()->getAabb(btTransform::getIdentity(), aabbMin, aabbMax);
const auto toLocal = object->getCollisionObject()->getWorldTransform().inverse();
const auto localFrom = toLocal(Misc::Convert::toBullet(position));
const auto localTo = toLocal(Misc::Convert::toBullet(destination));
btScalar hitDistance = 1;
btVector3 hitNormal;
return btRayAabb(localFrom, localTo, aabbMin, aabbMax, hitDistance, hitNormal);
}
}

View file

@ -898,6 +898,8 @@ namespace MWWorld
/// Return physical half extents of the given actor to be used in pathfinding
osg::Vec3f getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const override;
bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const override;
};
}

View file

@ -347,8 +347,6 @@ namespace Compiler
scanner.putbackName (name, loc);
return false;
}
return Parser::parseName (name, loc, scanner);
}
bool ExprParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)

View file

@ -301,7 +301,7 @@ namespace NifOsg
private:
Vec3Interpolator mData;
TargetColor mTargetColor;
TargetColor mTargetColor = Ambient;
};
class FlipController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller

View file

@ -341,6 +341,7 @@ namespace NifOsg
osg::ref_ptr<osg::Switch> switchNode (new osg::Switch);
switchNode->setName(niSwitchNode->name);
switchNode->setNewChildDefaultValue(false);
switchNode->setSingleChildOn(niSwitchNode->initialIndex);
return switchNode;
}
@ -433,7 +434,7 @@ namespace NifOsg
osg::ref_ptr<osg::Group> node;
osg::Object::DataVariance dataVariance = osg::Object::UNSPECIFIED;
// TODO: it is unclear how to handle transformations of LOD and Switch nodes and controllers for them.
// TODO: it is unclear how to handle transformations of LOD nodes and controllers for them.
switch (nifNode->recType)
{
case Nif::RC_NiLODNode:
@ -444,12 +445,6 @@ namespace NifOsg
break;
}
case Nif::RC_NiSwitchNode:
{
const Nif::NiSwitchNode* niSwitchNode = static_cast<const Nif::NiSwitchNode*>(nifNode);
node = handleSwitchNode(niSwitchNode);
dataVariance = osg::Object::STATIC;
break;
}
case Nif::RC_NiTriShape:
case Nif::RC_NiTriStrips:
case Nif::RC_NiAutoNormalParticles:
@ -625,6 +620,19 @@ namespace NifOsg
&& !nifNode->controller.empty() && node->getDataVariance() == osg::Object::DYNAMIC)
handleNodeControllers(nifNode, static_cast<osg::MatrixTransform*>(node.get()), animflags);
if (nifNode->recType == Nif::RC_NiSwitchNode)
{
const Nif::NiSwitchNode* niSwitchNode = static_cast<const Nif::NiSwitchNode*>(nifNode);
osg::ref_ptr<osg::Switch> switchNode = handleSwitchNode(niSwitchNode);
node->addChild(switchNode);
if (niSwitchNode->name == Constants::NightDayLabel && !SceneUtil::hasUserDescription(rootNode, Constants::NightDayLabel))
rootNode->getOrCreateUserDataContainer()->addDescription(Constants::NightDayLabel);
else if (niSwitchNode->name == Constants::HerbalismLabel && !SceneUtil::hasUserDescription(rootNode, Constants::HerbalismLabel))
rootNode->getOrCreateUserDataContainer()->addDescription(Constants::HerbalismLabel);
node = switchNode;
}
const Nif::NiNode *ninode = dynamic_cast<const Nif::NiNode*>(nifNode);
if(ninode)
{
@ -643,16 +651,6 @@ namespace NifOsg
}
}
if (nifNode->recType == Nif::RC_NiSwitchNode)
{
const Nif::NiSwitchNode* niSwitchNode = static_cast<const Nif::NiSwitchNode*>(nifNode);
node->asSwitch()->setSingleChildOn(niSwitchNode->initialIndex);
if (niSwitchNode->name == Constants::NightDayLabel && !SceneUtil::hasUserDescription(rootNode, Constants::NightDayLabel))
rootNode->getOrCreateUserDataContainer()->addDescription(Constants::NightDayLabel);
else if (niSwitchNode->name == Constants::HerbalismLabel && !SceneUtil::hasUserDescription(rootNode, Constants::HerbalismLabel))
rootNode->getOrCreateUserDataContainer()->addDescription(Constants::HerbalismLabel);
}
return node;
}

View file

@ -24,6 +24,8 @@ namespace SceneUtil
mShadowSettings->setReceivesShadowTraversalMask(~0u);
int numberOfShadowMapsPerLight = Settings::Manager::getInt("number of shadow maps", "Shadows");
numberOfShadowMapsPerLight = std::max(1, std::min(numberOfShadowMapsPerLight, 8));
mShadowSettings->setNumShadowMapsPerLight(numberOfShadowMapsPerLight);
mShadowSettings->setBaseShadowTextureUnit(8 - numberOfShadowMapsPerLight);
@ -66,6 +68,8 @@ namespace SceneUtil
void ShadowManager::disableShadowsForStateSet(osg::ref_ptr<osg::StateSet> stateset)
{
int numberOfShadowMapsPerLight = Settings::Manager::getInt("number of shadow maps", "Shadows");
numberOfShadowMapsPerLight = std::max(1, std::min(numberOfShadowMapsPerLight, 8));
int baseShadowTextureUnit = 8 - numberOfShadowMapsPerLight;
osg::ref_ptr<osg::Image> fakeShadowMapImage = new osg::Image();

View file

@ -36,7 +36,6 @@ namespace Terrain
osg::ref_ptr<osg::Node> getChunk(float size, const osg::Vec2f& center, unsigned char lod, unsigned int lodFlags);
void setCullingActive(bool active) { mCullingActive = active; }
void setCompositeMapSize(unsigned int size) { mCompositeMapSize = size; }
void setCompositeMapLevel(float level) { mCompositeMapLevel = level; }
void setMaxCompositeGeometrySize(float maxCompGeometrySize) { mMaxCompGeometrySize = maxCompGeometrySize; }
@ -65,8 +64,6 @@ namespace Terrain
unsigned int mCompositeMapSize;
float mCompositeMapLevel;
float mMaxCompGeometrySize;
bool mCullingActive;
};
}

View file

@ -14,6 +14,8 @@ namespace Gui
, mMouseFocus(false)
, mMousePress(false)
, mKeyFocus(false)
, mUseWholeTexture(true)
, mTextureRect(MyGUI::IntCoord(0, 0, 0, 0))
{
setNeedKeyFocus(sDefaultNeedKeyFocus);
}
@ -23,6 +25,13 @@ namespace Gui
sDefaultNeedKeyFocus = enabled;
}
void ImageButton::setTextureRect(MyGUI::IntCoord coord)
{
mTextureRect = coord;
mUseWholeTexture = (coord == MyGUI::IntCoord(0, 0, 0, 0));
updateImage();
}
void ImageButton::setPropertyOverride(const std::string &_key, const std::string &_value)
{
if (_key == "ImageHighlighted")
@ -37,6 +46,11 @@ namespace Gui
}
mImageNormal = _value;
}
else if (_key == "TextureRect")
{
mTextureRect = MyGUI::IntCoord::parse(_value);
mUseWholeTexture = (mTextureRect == MyGUI::IntCoord(0, 0, 0, 0));
}
else
ImageBox::setPropertyOverride(_key, _value);
}
@ -66,12 +80,25 @@ namespace Gui
void ImageButton::updateImage()
{
std::string textureName = mImageNormal;
if (mMousePress)
setImageTexture(mImagePushed);
textureName = mImagePushed;
else if (mMouseFocus || mKeyFocus)
setImageTexture(mImageHighlighted);
else
setImageTexture(mImageNormal);
textureName = mImageHighlighted;
if (!mUseWholeTexture)
{
int scale = 1.f;
MyGUI::ITexture* texture = MyGUI::RenderManager::getInstance().getTexture(textureName);
if (texture && getHeight() != 0)
scale = texture->getHeight() / getHeight();
setImageTile(MyGUI::IntSize(mTextureRect.width * scale, mTextureRect.height * scale));
MyGUI::IntCoord scaledSize(mTextureRect.left * scale, mTextureRect.top * scale, mTextureRect.width * scale, mTextureRect.height * scale);
setImageCoord(scaledSize);
}
setImageTexture(textureName);
}
MyGUI::IntSize ImageButton::getRequestedSize()
@ -82,7 +109,11 @@ namespace Gui
Log(Debug::Error) << "ImageButton: can't find image " << mImageNormal;
return MyGUI::IntSize(0,0);
}
return MyGUI::IntSize (texture->getWidth(), texture->getHeight());
if (mUseWholeTexture)
return MyGUI::IntSize(texture->getWidth(), texture->getHeight());
return MyGUI::IntSize(mTextureRect.width, mTextureRect.height);
}
void ImageButton::setImage(const std::string &image)
@ -96,7 +127,7 @@ namespace Gui
mImageHighlighted = imageNoExt + "_over" + ext;
mImagePushed = imageNoExt + "_pressed" + ext;
setImageTexture(mImageNormal);
updateImage();
}
void ImageButton::onMouseButtonReleased(int _left, int _top, MyGUI::MouseButton _id)

View file

@ -23,6 +23,8 @@ namespace Gui
/// Set mImageNormal, mImageHighlighted and mImagePushed based on file convention (image_idle.ext, image_over.ext and image_pressed.ext)
void setImage(const std::string& image);
void setTextureRect(MyGUI::IntCoord coord);
private:
void updateImage();
@ -44,6 +46,9 @@ namespace Gui
bool mMouseFocus;
bool mMousePress;
bool mKeyFocus;
bool mUseWholeTexture;
MyGUI::IntCoord mTextureRect;
};
}

View file

@ -85,11 +85,11 @@ compute tight scene bounds
:Type: boolean
:Range: True/False
:Default: False
:Default: True
With this setting enabled, attempt to better use the shadow map(s) by making them cover a smaller area.
This can be especially helpful when looking downwards with a high viewing distance but will be less useful with the default value.
The performance impact of this may be very large.
May have a minor to major performance impact.
shadow map resolution
---------------------
@ -200,10 +200,10 @@ use front face culling
:Type: boolean
:Range: True/False
:Default: True
:Default: False
Excludes theoretically unnecessary faces from shadow maps, slightly increasing performance.
In practice, Peter Panning can be much less visible with these faces included, so if you have high polygon offset values, disabling this may help minimise the side effects.
In practice, Peter Panning can be much less visible with these faces included, so if you have high polygon offset values, leaving this off may help minimise the side effects.
split point uniform logarithmic ratio
-------------------------------------

View file

@ -68,7 +68,7 @@ composite map level
:Type: integer
:Range: >= -3
:Default: -2
:Default: 0
Controls at which minimum size (in 2^value cell units) terrain chunks will start to use a composite map instead of the high-detail textures.
With value -3 composite maps are used everywhere.
@ -76,7 +76,7 @@ With value -3 composite maps are used everywhere.
A composite map is a pre-rendered texture that contains all the texture layers combined.
Note that resolution of composite maps is currently always fixed at 'composite map resolution',
regardless of the resolution of the underlying terrain textures.
If high-detail texture replacers are used, probably it is worth to increase 'composite map resolution' setting value.
If high resolution texture replacers are used, it is recommended to increase 'composite map resolution' setting value.
composite map resolution
------------------------

View file

@ -97,6 +97,13 @@ namespace ICS
xmlControl = xmlControl->NextSiblingElement("Control");
}
static const size_t channelsCountLimit = 65536;
if (controlChannelCount > channelsCountLimit)
{
ICS_LOG("Warning: requested channels count (" + ToString<size_t>(controlChannelCount) + ") exceeds allowed maximum (" + ToString<size_t>(channelsCountLimit) + "), clamping it");
controlChannelCount = channelsCountLimit;
}
if(controlChannelCount > channelCount)
{
size_t dif = controlChannelCount - channelCount;
@ -116,7 +123,13 @@ namespace ICS
TiXmlElement* xmlChannelFilter = xmlRoot->FirstChildElement("ChannelFilter");
while(xmlChannelFilter)
{
int ch = FromString<int>(xmlChannelFilter->Attribute("number"));
size_t ch = FromString<size_t>(xmlChannelFilter->Attribute("number"));
if(ch >= controlChannelCount)
{
ICS_LOG("ERROR: channel number (ch) is out of range");
xmlChannelFilter = xmlChannelFilter->NextSiblingElement("ChannelFilter");
continue;
}
TiXmlElement* xmlInterval = xmlChannelFilter->FirstChildElement("Interval");
while(xmlInterval)
@ -150,7 +163,6 @@ namespace ICS
xmlInterval = xmlInterval->NextSiblingElement("Interval");
}
xmlChannelFilter = xmlChannelFilter->NextSiblingElement("ChannelFilter");
}
@ -264,7 +276,13 @@ namespace ICS
}
}
int chNumber = FromString<int>(xmlChannel->Attribute("number"));
size_t chNumber = FromString<size_t>(xmlChannel->Attribute("number"));
if(chNumber >= controlChannelCount)
{
ICS_LOG("ERROR: channel number (chNumber) is out of range");
}
else
{
if(std::string(xmlChannel->Attribute("direction")) == "DIRECT")
{
mControls.back()->attachChannel(mChannels[ chNumber ],Channel::DIRECT, percentage);
@ -273,6 +291,7 @@ namespace ICS
{
mControls.back()->attachChannel(mChannels[ chNumber ],Channel::INVERSE, percentage);
}
}
xmlChannel = xmlChannel->NextSiblingElement("Channel");
}

View file

@ -65,12 +65,14 @@
<Widget type="BookPage" skin="MW_BookPage" position="75 10 92 260" name="CenterTopicIndex"/>
<Widget type="BookPage" skin="MW_BookPage" position="130 10 92 260" name="RightTopicIndex"/>
<Widget type="ImageButton" skin="ImageBox" position="71 15 100 20" Align="Top|Left" name="ShowActiveBTN">
<Widget type="ImageButton" skin="ImageBox" position="76 15 96 32" Align="Top|Left" name="ShowActiveBTN">
<!-- Image set at runtime since it may not be available in all versions of the game -->
<Property key="TextureRect" value="0 0 96 32"/>
</Widget>
<Widget type="ImageButton" skin="ImageBox" position="85 15 72 20" Align="Top|Left" name="ShowAllBTN">
<Widget type="ImageButton" skin="ImageBox" position="83 15 72 32" Align="Top|Left" name="ShowAllBTN">
<!-- Image set at runtime since it may not be available in all versions of the game -->
<Property key="TextureRect" value="0 0 72 32"/>
</Widget>
<Widget type="MWList" skin="MW_QuestList" position="8 40 226 212" name="TopicsList" align="Right VStretch">

View file

@ -17,16 +17,16 @@
<Widget type="Widget" skin="" position="15 55 332 128" align="Left Bottom HCenter">
<Widget type="ItemWidget" skin="MW_ItemIconBox" position="0 0 60 59" name="QuickKey1"/>
<Widget type="ItemWidget" skin="MW_ItemIconBox" position="68 0 60 59" name="QuickKey2"/>
<Widget type="ItemWidget" skin="MW_ItemIconBox" position="136 0 60 59" name="QuickKey3"/>
<Widget type="ItemWidget" skin="MW_ItemIconBox" position="204 0 60 59" name="QuickKey4"/>
<Widget type="ItemWidget" skin="MW_ItemIconBox" position="272 0 60 59" name="QuickKey5"/>
<Widget type="ItemWidget" skin="MW_ItemIconBox" position="0 67 60 59" name="QuickKey6"/>
<Widget type="ItemWidget" skin="MW_ItemIconBox" position="68 67 60 59" name="QuickKey7"/>
<Widget type="ItemWidget" skin="MW_ItemIconBox" position="136 67 60 59" name="QuickKey8"/>
<Widget type="ItemWidget" skin="MW_ItemIconBox" position="204 67 60 59" name="QuickKey9"/>
<Widget type="ItemWidget" skin="MW_ItemIconBox" position="272 67 60 59" name="QuickKey10"/>
<Widget type="ItemWidget" skin="MW_ItemIconBox" position="0 0 60 60" name="QuickKey1"/>
<Widget type="ItemWidget" skin="MW_ItemIconBox" position="68 0 60 60" name="QuickKey2"/>
<Widget type="ItemWidget" skin="MW_ItemIconBox" position="136 0 60 60" name="QuickKey3"/>
<Widget type="ItemWidget" skin="MW_ItemIconBox" position="204 0 60 60" name="QuickKey4"/>
<Widget type="ItemWidget" skin="MW_ItemIconBox" position="272 0 60 60" name="QuickKey5"/>
<Widget type="ItemWidget" skin="MW_ItemIconBox" position="0 67 60 60" name="QuickKey6"/>
<Widget type="ItemWidget" skin="MW_ItemIconBox" position="68 67 60 60" name="QuickKey7"/>
<Widget type="ItemWidget" skin="MW_ItemIconBox" position="136 67 60 60" name="QuickKey8"/>
<Widget type="ItemWidget" skin="MW_ItemIconBox" position="204 67 60 60" name="QuickKey9"/>
<Widget type="ItemWidget" skin="MW_ItemIconBox" position="272 67 60 60" name="QuickKey10"/>
</Widget>

View file

@ -98,7 +98,7 @@ vertex lod mod = 0
# Controls when the distant terrain will flip to composited textures instead of high-detail textures, should be >= -3.
# Higher value is more detailed textures.
composite map level = -2
composite map level = 0
# Controls the resolution of composite maps.
composite map resolution = 512
@ -767,8 +767,8 @@ enable debug hud = false
# Enable the debug overlay to see where each shadow map affects.
enable debug overlay = false
# Attempt to better use the shadow map by making them cover a smaller area. Especially helpful when looking downwards with a high viewing distance. The performance impact of this may be very large.
compute tight scene bounds = false
# Attempt to better use the shadow map by making them cover a smaller area. Especially helpful when looking downwards. May have a minor to major performance impact.
compute tight scene bounds = true
# How large to make the shadow map(s). Higher values increase GPU load, but can produce better-looking results. Power-of-two values may turn out to be faster on some GPU/driver combinations.
shadow map resolution = 1024
@ -785,8 +785,8 @@ polygon offset units = 4.0
# How far along the surface normal to project shadow coordinates. Higher values significantly reduce shadow flicker, usually with a lower increase of Peter Panning than the Polygon Offset settings. This value is in in-game units, so 1.0 is roughly 1.4 cm.
normal offset distance = 1.0
# Excludes theoretically unnecessary faces from shadow maps, slightly increasing performance. In practice, Peter Panning can be much less visible with these faces included, so if you have high polygon offset values, disabling this may help minimise the side effects.
use front face culling = true
# Excludes theoretically unnecessary faces from shadow maps, slightly increasing performance. In practice, Peter Panning can be much less visible with these faces included, so if you have high polygon offset values, leave this off to minimise the side effects.
use front face culling = false
# Allow actors to cast shadows. Potentially decreases performance.
actor shadows = false