mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-28 16:39:39 +00:00
merge master
This commit is contained in:
commit
32de86d114
75 changed files with 1009 additions and 537 deletions
|
@ -9,6 +9,7 @@
|
|||
Bug #3109: SetPos/Position handles actors differently
|
||||
Bug #3282: Unintended behaviour when assigning F3 and Windows keys
|
||||
Bug #3550: Companion from mod attacks the air after combat has ended
|
||||
Bug #3609: Items from evidence chest are not considered to be stolen if player is allowed to use the chest
|
||||
Bug #3623: Display scaling breaks mouse recognition
|
||||
Bug #3725: Using script function in a non-conditional expression breaks script compilation
|
||||
Bug #3733: Normal maps are inverted on mirrored UVs
|
||||
|
@ -139,11 +140,16 @@
|
|||
Bug #5137: Textures with Clamp Mode set to Clamp instead of Wrap are too dark outside the boundaries
|
||||
Bug #5149: Failing lock pick attempts isn't always a crime
|
||||
Bug #5155: Lock/unlock behavior differs from vanilla
|
||||
Bug #5159: NiMaterialColorController can only control the diffuse color
|
||||
Bug #5161: Creature companions can't be activated when they are knocked down
|
||||
Bug #5164: Faction owned items handling is incorrect
|
||||
Bug #5188: Objects without a name don't fallback to their ID
|
||||
Feature #1774: Handle AvoidNode
|
||||
Feature #2229: Improve pathfinding AI
|
||||
Feature #3025: Analogue gamepad movement controls
|
||||
Feature #3442: Default values for fallbacks from ini file
|
||||
Feature #3610: Option to invert X axis
|
||||
Feature #3871: Editor: Terrain Selection
|
||||
Feature #3893: Implicit target for "set" function in console
|
||||
Feature #3980: In-game option to disable controller
|
||||
Feature #3999: Shift + Double Click should maximize/restore menu size
|
||||
|
|
|
@ -329,6 +329,7 @@ bool Launcher::MainDialog::setupGameSettings()
|
|||
stream.setCodec(QTextCodec::codecForName("UTF-8"));
|
||||
|
||||
mGameSettings.readUserFile(stream);
|
||||
file.close();
|
||||
}
|
||||
|
||||
// Now the rest - priority: user > local > global
|
||||
|
@ -353,9 +354,9 @@ bool Launcher::MainDialog::setupGameSettings()
|
|||
stream.setCodec(QTextCodec::codecForName("UTF-8"));
|
||||
|
||||
mGameSettings.readFile(stream);
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ opencs_units (view/render
|
|||
scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget
|
||||
previewwidget editmode instancemode instanceselectionmode instancemovemode
|
||||
orbitcameramode pathgridmode selectionmode pathgridselectionmode cameracontroller
|
||||
cellwater terraintexturemode actor
|
||||
cellwater terraintexturemode actor terrainselection
|
||||
)
|
||||
|
||||
opencs_units_noqt (view/render
|
||||
|
|
|
@ -8,13 +8,6 @@
|
|||
#include <components/esm/loadland.hpp>
|
||||
#include <components/misc/constants.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
const int cellSize {ESM::Land::REAL_SIZE};
|
||||
const int landSize {ESM::Land::LAND_SIZE};
|
||||
const int landTextureSize {ESM::Land::LAND_TEXTURE_SIZE};
|
||||
}
|
||||
|
||||
CSMWorld::CellCoordinates::CellCoordinates() : mX (0), mY (0) {}
|
||||
|
||||
CSMWorld::CellCoordinates::CellCoordinates (int x, int y) : mX (x), mY (y) {}
|
||||
|
@ -76,10 +69,10 @@ std::pair<int, int> CSMWorld::CellCoordinates::coordinatesToCellIndex (float x,
|
|||
return std::make_pair (std::floor (x / Constants::CellSizeInUnits), std::floor (y / Constants::CellSizeInUnits));
|
||||
}
|
||||
|
||||
std::pair<int, int> CSMWorld::CellCoordinates::toTextureCoords(osg::Vec3d worldPos)
|
||||
std::pair<int, int> CSMWorld::CellCoordinates::toTextureCoords(const osg::Vec3d& worldPos)
|
||||
{
|
||||
const auto xd = static_cast<float>(worldPos.x() * landTextureSize / cellSize - 0.25f);
|
||||
const auto yd = static_cast<float>(worldPos.y() * landTextureSize / cellSize + 0.25f);
|
||||
const auto xd = static_cast<float>(worldPos.x() * ESM::Land::LAND_TEXTURE_SIZE / ESM::Land::REAL_SIZE - 0.25f);
|
||||
const auto yd = static_cast<float>(worldPos.y() * ESM::Land::LAND_TEXTURE_SIZE / ESM::Land::REAL_SIZE + 0.25f);
|
||||
|
||||
const auto x = static_cast<int>(std::floor(xd));
|
||||
const auto y = static_cast<int>(std::floor(yd));
|
||||
|
@ -87,10 +80,10 @@ std::pair<int, int> CSMWorld::CellCoordinates::toTextureCoords(osg::Vec3d worldP
|
|||
return std::make_pair(x, y);
|
||||
}
|
||||
|
||||
std::pair<int, int> CSMWorld::CellCoordinates::toVertexCoords(osg::Vec3d worldPos)
|
||||
std::pair<int, int> CSMWorld::CellCoordinates::toVertexCoords(const osg::Vec3d& worldPos)
|
||||
{
|
||||
const auto xd = static_cast<float>(worldPos.x() * (landSize - 1) / cellSize + 0.5f);
|
||||
const auto yd = static_cast<float>(worldPos.y() * (landSize - 1) / cellSize + 0.5f);
|
||||
const auto xd = static_cast<float>(worldPos.x() * (ESM::Land::LAND_SIZE - 1) / ESM::Land::REAL_SIZE + 0.5f);
|
||||
const auto yd = static_cast<float>(worldPos.y() * (ESM::Land::LAND_SIZE - 1) / ESM::Land::REAL_SIZE + 0.5f);
|
||||
|
||||
const auto x = static_cast<int>(std::floor(xd));
|
||||
const auto y = static_cast<int>(std::floor(yd));
|
||||
|
@ -98,25 +91,32 @@ std::pair<int, int> CSMWorld::CellCoordinates::toVertexCoords(osg::Vec3d worldPo
|
|||
return std::make_pair(x, y);
|
||||
}
|
||||
|
||||
float CSMWorld::CellCoordinates::textureSelectionToWorldCoords(int pos)
|
||||
float CSMWorld::CellCoordinates::textureGlobalToWorldCoords(int textureGlobal)
|
||||
{
|
||||
return cellSize * static_cast<float>(pos) / landTextureSize;
|
||||
return ESM::Land::REAL_SIZE * static_cast<float>(textureGlobal) / ESM::Land::LAND_TEXTURE_SIZE;
|
||||
}
|
||||
|
||||
float CSMWorld::CellCoordinates::vertexSelectionToWorldCoords(int pos)
|
||||
float CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(int vertexGlobal)
|
||||
{
|
||||
return cellSize * static_cast<float>(pos) / (landSize - 1);
|
||||
return ESM::Land::REAL_SIZE * static_cast<float>(vertexGlobal) / (ESM::Land::LAND_SIZE - 1);
|
||||
}
|
||||
|
||||
int CSMWorld::CellCoordinates::vertexSelectionToInCellCoords(int pos)
|
||||
int CSMWorld::CellCoordinates::vertexGlobalToInCellCoords(int vertexGlobal)
|
||||
{
|
||||
return static_cast<int>(pos - std::floor(static_cast<float>(pos) / (landSize - 1)) * (landSize - 1));
|
||||
return static_cast<int>(vertexGlobal - std::floor(static_cast<float>(vertexGlobal) / (ESM::Land::LAND_SIZE - 1)) * (ESM::Land::LAND_SIZE - 1));
|
||||
}
|
||||
|
||||
std::string CSMWorld::CellCoordinates::vertexGlobalToCellId(std::pair<int, int> vertexGlobal)
|
||||
std::string CSMWorld::CellCoordinates::textureGlobalToCellId(const std::pair<int, int>& textureGlobal)
|
||||
{
|
||||
int x = std::floor(static_cast<float>(vertexGlobal.first) / (landSize - 1));
|
||||
int y = std::floor(static_cast<float>(vertexGlobal.second) / (landSize - 1));
|
||||
int x = std::floor(static_cast<float>(textureGlobal.first) / ESM::Land::LAND_TEXTURE_SIZE);
|
||||
int y = std::floor(static_cast<float>(textureGlobal.second) / ESM::Land::LAND_TEXTURE_SIZE);
|
||||
return generateId(x, y);
|
||||
}
|
||||
|
||||
std::string CSMWorld::CellCoordinates::vertexGlobalToCellId(const std::pair<int, int>& vertexGlobal)
|
||||
{
|
||||
int x = std::floor(static_cast<float>(vertexGlobal.first) / (ESM::Land::LAND_SIZE - 1));
|
||||
int y = std::floor(static_cast<float>(vertexGlobal.second) / (ESM::Land::LAND_SIZE - 1));
|
||||
return generateId(x, y);
|
||||
}
|
||||
|
||||
|
|
|
@ -49,22 +49,25 @@ namespace CSMWorld
|
|||
static std::pair<int, int> coordinatesToCellIndex (float x, float y);
|
||||
|
||||
///Converts worldspace coordinates to global texture selection, taking in account the texture offset.
|
||||
static std::pair<int, int> toTextureCoords(osg::Vec3d worldPos);
|
||||
static std::pair<int, int> toTextureCoords(const osg::Vec3d& worldPos);
|
||||
|
||||
///Converts worldspace coordinates to global vertex selection.
|
||||
static std::pair<int, int> toVertexCoords(osg::Vec3d worldPos);
|
||||
static std::pair<int, int> toVertexCoords(const osg::Vec3d& worldPos);
|
||||
|
||||
///Converts global texture coordinate to worldspace coordinate that is at the upper left corner of the selected texture.
|
||||
static float textureSelectionToWorldCoords(int);
|
||||
static float textureGlobalToWorldCoords(int textureGlobal);
|
||||
|
||||
///Converts global vertex coordinate to worldspace coordinate
|
||||
static float vertexSelectionToWorldCoords(int);
|
||||
static float vertexGlobalToWorldCoords(int vertexGlobal);
|
||||
|
||||
///Converts local cell's heightmap coordinates from the global vertex coordinate
|
||||
static int vertexSelectionToInCellCoords(int);
|
||||
///Converts global vertex coordinate to local cell's heightmap coordinates
|
||||
static int vertexGlobalToInCellCoords(int vertexGlobal);
|
||||
|
||||
///Converts global texture coordinates to cell id
|
||||
static std::string textureGlobalToCellId(const std::pair<int, int>& textureGlobal);
|
||||
|
||||
///Converts global vertex coordinates to cell id
|
||||
static std::string vertexGlobalToCellId(std::pair<int, int>);
|
||||
static std::string vertexGlobalToCellId(const std::pair<int, int>& vertexGlobal);
|
||||
};
|
||||
|
||||
bool operator== (const CellCoordinates& left, const CellCoordinates& right);
|
||||
|
|
|
@ -140,7 +140,7 @@ void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons (
|
|||
new EditMode (this, QIcon (":placeholder"), Mask_Reference, "Terrain shape editing"),
|
||||
"terrain-shape");
|
||||
tool->addButton (
|
||||
new TerrainTextureMode (this, tool),
|
||||
new TerrainTextureMode (this, mRootNode, tool),
|
||||
"terrain-texture");
|
||||
tool->addButton (
|
||||
new EditMode (this, QIcon (":placeholder"), Mask_Reference, "Terrain vertex paint editing"),
|
||||
|
|
261
apps/opencs/view/render/terrainselection.cpp
Normal file
261
apps/opencs/view/render/terrainselection.cpp
Normal file
|
@ -0,0 +1,261 @@
|
|||
#include "terrainselection.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <osg/Group>
|
||||
#include <osg/Geometry>
|
||||
#include <osg/PositionAttitudeTransform>
|
||||
|
||||
#include <components/esm/loadland.hpp>
|
||||
|
||||
#include "../../model/world/cellcoordinates.hpp"
|
||||
#include "../../model/world/columnimp.hpp"
|
||||
#include "../../model/world/idtable.hpp"
|
||||
|
||||
#include "cell.hpp"
|
||||
#include "worldspacewidget.hpp"
|
||||
|
||||
CSVRender::TerrainSelection::TerrainSelection(osg::Group* parentNode, WorldspaceWidget *worldspaceWidget, TerrainSelectionType type):
|
||||
mParentNode(parentNode), mWorldspaceWidget (worldspaceWidget), mDraggedOperationFlag(false), mSelectionType(type)
|
||||
{
|
||||
mGeometry = new osg::Geometry();
|
||||
|
||||
mSelectionNode = new osg::Group();
|
||||
mSelectionNode->addChild(mGeometry);
|
||||
|
||||
activate();
|
||||
}
|
||||
|
||||
CSVRender::TerrainSelection::~TerrainSelection()
|
||||
{
|
||||
deactivate();
|
||||
}
|
||||
|
||||
std::vector<std::pair<int, int>> CSVRender::TerrainSelection::getTerrainSelection() const
|
||||
{
|
||||
return mSelection;
|
||||
}
|
||||
|
||||
void CSVRender::TerrainSelection::onlySelect(const std::vector<std::pair<int, int>> &localPositions)
|
||||
{
|
||||
mSelection = localPositions;
|
||||
update();
|
||||
}
|
||||
|
||||
void CSVRender::TerrainSelection::addSelect(const std::pair<int, int> &localPos)
|
||||
{
|
||||
if (std::find(mSelection.begin(), mSelection.end(), localPos) == mSelection.end())
|
||||
{
|
||||
mSelection.emplace_back(localPos);
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void CSVRender::TerrainSelection::toggleSelect(const std::vector<std::pair<int, int>> &localPositions, bool toggleInProgress)
|
||||
{
|
||||
if (toggleInProgress)
|
||||
{
|
||||
for(auto const& localPos: localPositions)
|
||||
{
|
||||
auto iterTemp = std::find(mTemporarySelection.begin(), mTemporarySelection.end(), localPos);
|
||||
mDraggedOperationFlag = true;
|
||||
|
||||
if (iterTemp == mTemporarySelection.end())
|
||||
{
|
||||
auto iter = std::find(mSelection.begin(), mSelection.end(), localPos);
|
||||
if (iter != mSelection.end())
|
||||
{
|
||||
mSelection.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
mSelection.emplace_back(localPos);
|
||||
}
|
||||
}
|
||||
|
||||
mTemporarySelection.push_back(localPos);
|
||||
}
|
||||
}
|
||||
else if (mDraggedOperationFlag == false)
|
||||
{
|
||||
for(auto const& localPos: localPositions)
|
||||
{
|
||||
const auto iter = std::find(mSelection.begin(), mSelection.end(), localPos);
|
||||
if (iter != mSelection.end())
|
||||
{
|
||||
mSelection.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
mSelection.emplace_back(localPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mDraggedOperationFlag = false;
|
||||
mTemporarySelection.clear();
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void CSVRender::TerrainSelection::activate()
|
||||
{
|
||||
if (!mParentNode->containsNode(mSelectionNode)) mParentNode->addChild(mSelectionNode);
|
||||
}
|
||||
|
||||
void CSVRender::TerrainSelection::deactivate()
|
||||
{
|
||||
mParentNode->removeChild(mSelectionNode);
|
||||
}
|
||||
|
||||
void CSVRender::TerrainSelection::update()
|
||||
{
|
||||
mSelectionNode->removeChild(mGeometry);
|
||||
mGeometry = new osg::Geometry();
|
||||
|
||||
const osg::ref_ptr<osg::Vec3Array> vertices (new osg::Vec3Array);
|
||||
|
||||
switch (mSelectionType)
|
||||
{
|
||||
case TerrainSelectionType::Texture : drawTextureSelection(vertices);
|
||||
break;
|
||||
case TerrainSelectionType::Shape : drawShapeSelection(vertices);
|
||||
break;
|
||||
}
|
||||
|
||||
mGeometry->setVertexArray(vertices);
|
||||
osg::ref_ptr<osg::DrawArrays> drawArrays = new osg::DrawArrays(osg::PrimitiveSet::LINES);
|
||||
drawArrays->setCount(vertices->size());
|
||||
if (vertices->size() != 0) mGeometry->addPrimitiveSet(drawArrays);
|
||||
mSelectionNode->addChild(mGeometry);
|
||||
}
|
||||
|
||||
void CSVRender::TerrainSelection::drawShapeSelection(const osg::ref_ptr<osg::Vec3Array> vertices)
|
||||
{
|
||||
if (!mSelection.empty())
|
||||
{
|
||||
for (std::pair<int, int> &localPos : mSelection)
|
||||
{
|
||||
int x (localPos.first);
|
||||
int y (localPos.second);
|
||||
|
||||
float xWorldCoord(CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(x));
|
||||
float yWorldCoord(CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(y));
|
||||
|
||||
osg::Vec3f pointXY(xWorldCoord, yWorldCoord, calculateLandHeight(x, y) + 2);
|
||||
|
||||
vertices->push_back(pointXY);
|
||||
vertices->push_back(osg::Vec3f(xWorldCoord, CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(y - 1), calculateLandHeight(x, y - 1) + 2));
|
||||
vertices->push_back(pointXY);
|
||||
vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(x - 1), yWorldCoord, calculateLandHeight(x - 1, y) + 2));
|
||||
|
||||
const auto north = std::find(mSelection.begin(), mSelection.end(), std::make_pair(x, y + 1));
|
||||
if (north == mSelection.end())
|
||||
{
|
||||
vertices->push_back(pointXY);
|
||||
vertices->push_back(osg::Vec3f(xWorldCoord, CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(y + 1), calculateLandHeight(x, y + 1) + 2));
|
||||
}
|
||||
|
||||
const auto east = std::find(mSelection.begin(), mSelection.end(), std::make_pair(x + 1, y));
|
||||
if (east == mSelection.end())
|
||||
{
|
||||
vertices->push_back(pointXY);
|
||||
vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(x + 1), yWorldCoord, calculateLandHeight(x + 1, y) + 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSVRender::TerrainSelection::drawTextureSelection(const osg::ref_ptr<osg::Vec3Array> vertices)
|
||||
{
|
||||
if (!mSelection.empty())
|
||||
{
|
||||
// Nudge selection by 1/4th of a texture size, similar how blendmaps are nudged
|
||||
const float nudgePercentage = 0.25f;
|
||||
const int nudgeOffset = (ESM::Land::REAL_SIZE / ESM::Land::LAND_TEXTURE_SIZE) * nudgePercentage;
|
||||
const int landHeightsNudge = (ESM::Land::REAL_SIZE / ESM::Land::LAND_SIZE) / (ESM::Land::LAND_SIZE - 1); // Does this work with all land size configurations?
|
||||
|
||||
const int textureSizeToLandSizeModifier = (ESM::Land::LAND_SIZE - 1) / ESM::Land::LAND_TEXTURE_SIZE;
|
||||
|
||||
for (std::pair<int, int> &localPos : mSelection)
|
||||
{
|
||||
int x (localPos.first);
|
||||
int y (localPos.second);
|
||||
|
||||
// convert texture selection to global vertex coordinates at selection box corners
|
||||
int x1 = x * textureSizeToLandSizeModifier + landHeightsNudge;
|
||||
int x2 = x * textureSizeToLandSizeModifier + textureSizeToLandSizeModifier + landHeightsNudge;
|
||||
int y1 = y * textureSizeToLandSizeModifier - landHeightsNudge;
|
||||
int y2 = y * textureSizeToLandSizeModifier + textureSizeToLandSizeModifier - landHeightsNudge;
|
||||
|
||||
// Draw edges (check all sides, draw lines between vertices, +1 height to keep lines above ground)
|
||||
// Check adjancent selections, draw lines only to edges of the selection
|
||||
const auto north = std::find(mSelection.begin(), mSelection.end(), std::make_pair(x, y + 1));
|
||||
if (north == mSelection.end())
|
||||
{
|
||||
for(int i = 1; i < (textureSizeToLandSizeModifier + 1); i++)
|
||||
{
|
||||
float drawPreviousX = CSMWorld::CellCoordinates::textureGlobalToWorldCoords(x) + (i - 1) * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1));
|
||||
float drawCurrentX = CSMWorld::CellCoordinates::textureGlobalToWorldCoords(x) + i * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1));
|
||||
vertices->push_back(osg::Vec3f(drawPreviousX + nudgeOffset, CSMWorld::CellCoordinates::textureGlobalToWorldCoords(y + 1) - nudgeOffset, calculateLandHeight(x1+(i-1), y2)+2));
|
||||
vertices->push_back(osg::Vec3f(drawCurrentX + nudgeOffset, CSMWorld::CellCoordinates::textureGlobalToWorldCoords(y + 1) - nudgeOffset, calculateLandHeight(x1+i, y2)+2));
|
||||
}
|
||||
}
|
||||
|
||||
const auto south = std::find(mSelection.begin(), mSelection.end(), std::make_pair(x, y - 1));
|
||||
if (south == mSelection.end())
|
||||
{
|
||||
for(int i = 1; i < (textureSizeToLandSizeModifier + 1); i++)
|
||||
{
|
||||
float drawPreviousX = CSMWorld::CellCoordinates::textureGlobalToWorldCoords(x) + (i - 1) *(ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1));
|
||||
float drawCurrentX = CSMWorld::CellCoordinates::textureGlobalToWorldCoords(x) + i * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1));
|
||||
vertices->push_back(osg::Vec3f(drawPreviousX + nudgeOffset, CSMWorld::CellCoordinates::textureGlobalToWorldCoords(y) - nudgeOffset, calculateLandHeight(x1+(i-1), y1)+2));
|
||||
vertices->push_back(osg::Vec3f(drawCurrentX + nudgeOffset, CSMWorld::CellCoordinates::textureGlobalToWorldCoords(y) - nudgeOffset, calculateLandHeight(x1+i, y1)+2));
|
||||
}
|
||||
}
|
||||
|
||||
const auto east = std::find(mSelection.begin(), mSelection.end(), std::make_pair(x + 1, y));
|
||||
if (east == mSelection.end())
|
||||
{
|
||||
for(int i = 1; i < (textureSizeToLandSizeModifier + 1); i++)
|
||||
{
|
||||
float drawPreviousY = CSMWorld::CellCoordinates::textureGlobalToWorldCoords(y) + (i - 1) * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1));
|
||||
float drawCurrentY = CSMWorld::CellCoordinates::textureGlobalToWorldCoords(y) + i * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1));
|
||||
vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureGlobalToWorldCoords(x + 1) + nudgeOffset, drawPreviousY - nudgeOffset, calculateLandHeight(x2, y1+(i-1))+2));
|
||||
vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureGlobalToWorldCoords(x + 1) + nudgeOffset, drawCurrentY - nudgeOffset, calculateLandHeight(x2, y1+i)+2));
|
||||
}
|
||||
}
|
||||
|
||||
const auto west = std::find(mSelection.begin(), mSelection.end(), std::make_pair(x - 1, y));
|
||||
if (west == mSelection.end())
|
||||
{
|
||||
for(int i = 1; i < (textureSizeToLandSizeModifier + 1); i++)
|
||||
{
|
||||
float drawPreviousY = CSMWorld::CellCoordinates::textureGlobalToWorldCoords(y) + (i - 1) * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1));
|
||||
float drawCurrentY = CSMWorld::CellCoordinates::textureGlobalToWorldCoords(y) + i * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1));
|
||||
vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureGlobalToWorldCoords(x) + nudgeOffset, drawPreviousY - nudgeOffset, calculateLandHeight(x1, y1+(i-1))+2));
|
||||
vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureGlobalToWorldCoords(x) + nudgeOffset, drawCurrentY - nudgeOffset, calculateLandHeight(x1, y1+i)+2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CSVRender::TerrainSelection::calculateLandHeight(int x, int y) // global vertex coordinates
|
||||
{
|
||||
int cellX = std::floor((1.0f*x / (ESM::Land::LAND_SIZE - 1)));
|
||||
int cellY = std::floor((1.0f*y / (ESM::Land::LAND_SIZE - 1)));
|
||||
int localX = x - cellX * (ESM::Land::LAND_SIZE - 1);
|
||||
int localY = y - cellY * (ESM::Land::LAND_SIZE - 1);
|
||||
|
||||
std::string cellId = CSMWorld::CellCoordinates::generateId(cellX, cellY);
|
||||
|
||||
CSMDoc::Document& document = mWorldspaceWidget->getDocument();
|
||||
CSMWorld::IdTable& landTable = dynamic_cast<CSMWorld::IdTable&> (
|
||||
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Land));
|
||||
int landshapeColumn = landTable.findColumnIndex(CSMWorld::Columns::ColumnId_LandHeightsIndex);
|
||||
const CSMWorld::LandHeightsColumn::DataType mPointer = landTable.data(landTable.getModelIndex(cellId, landshapeColumn)).value<CSMWorld::LandHeightsColumn::DataType>();
|
||||
|
||||
return mPointer[localY*ESM::Land::LAND_SIZE + localX];
|
||||
}
|
70
apps/opencs/view/render/terrainselection.hpp
Normal file
70
apps/opencs/view/render/terrainselection.hpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
#ifndef CSV_RENDER_TERRAINSELECTION_H
|
||||
#define CSV_RENDER_TERRAINSELECTION_H
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <osg/Vec3d>
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/PositionAttitudeTransform>
|
||||
|
||||
#include <components/esm/loadland.hpp>
|
||||
#include "../../model/world/cellcoordinates.hpp"
|
||||
|
||||
namespace osg
|
||||
{
|
||||
class Group;
|
||||
}
|
||||
|
||||
namespace CSVRender
|
||||
{
|
||||
struct WorldspaceHitResult;
|
||||
class WorldspaceWidget;
|
||||
|
||||
enum class TerrainSelectionType
|
||||
{
|
||||
Texture,
|
||||
Shape
|
||||
};
|
||||
|
||||
/// \brief Class handling the terrain selection data and rendering
|
||||
class TerrainSelection
|
||||
{
|
||||
public:
|
||||
|
||||
TerrainSelection(osg::Group* parentNode, WorldspaceWidget *worldspaceWidget, TerrainSelectionType type);
|
||||
~TerrainSelection();
|
||||
|
||||
void onlySelect(const std::vector<std::pair<int, int>> &localPositions);
|
||||
void addSelect(const std::pair<int, int> &localPos);
|
||||
void toggleSelect(const std::vector<std::pair<int, int>> &localPositions, bool toggleInProgress);
|
||||
|
||||
void activate();
|
||||
void deactivate();
|
||||
|
||||
std::vector<std::pair<int, int>> getTerrainSelection() const;
|
||||
|
||||
protected:
|
||||
|
||||
void update();
|
||||
|
||||
void drawShapeSelection(const osg::ref_ptr<osg::Vec3Array> vertices);
|
||||
void drawTextureSelection(const osg::ref_ptr<osg::Vec3Array> vertices);
|
||||
|
||||
int calculateLandHeight(int x, int y);
|
||||
|
||||
private:
|
||||
|
||||
osg::Group* mParentNode;
|
||||
WorldspaceWidget *mWorldspaceWidget;
|
||||
osg::ref_ptr<osg::PositionAttitudeTransform> mBaseNode;
|
||||
osg::ref_ptr<osg::Geometry> mGeometry;
|
||||
osg::ref_ptr<osg::Group> mSelectionNode;
|
||||
std::vector<std::pair<int, int>> mSelection; // Global terrain selection coordinate in either vertex or texture units
|
||||
std::vector<std::pair<int, int>> mTemporarySelection; // Used during toggle to compare the most recent drag operation
|
||||
bool mDraggedOperationFlag; //true during drag operation, false when click-operation
|
||||
TerrainSelectionType mSelectionType;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -10,6 +10,8 @@
|
|||
#include <QDragEnterEvent>
|
||||
#include <QDrag>
|
||||
|
||||
#include <osg/Group>
|
||||
|
||||
#include <components/esm/loadland.hpp>
|
||||
|
||||
#include "../widget/modebutton.hpp"
|
||||
|
@ -36,12 +38,15 @@
|
|||
#include "object.hpp" // Something small needed regarding pointers from here ()
|
||||
#include "worldspacewidget.hpp"
|
||||
|
||||
CSVRender::TerrainTextureMode::TerrainTextureMode (WorldspaceWidget *worldspaceWidget, QWidget *parent)
|
||||
CSVRender::TerrainTextureMode::TerrainTextureMode (WorldspaceWidget *worldspaceWidget, osg::Group* parentNode, QWidget *parent)
|
||||
: EditMode (worldspaceWidget, QIcon {":scenetoolbar/editing-terrain-texture"}, Mask_Terrain | Mask_Reference, "Terrain texture editing", parent),
|
||||
mBrushTexture("L0#0"),
|
||||
mBrushSize(0),
|
||||
mBrushShape(0),
|
||||
mTextureBrushScenetool(0)
|
||||
mTextureBrushScenetool(0),
|
||||
mDragMode(InteractionType_None),
|
||||
mParentNode(parentNode),
|
||||
mIsEditing(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -62,6 +67,11 @@ void CSVRender::TerrainTextureMode::activate(CSVWidget::SceneToolbar* toolbar)
|
|||
connect(this, SIGNAL(passBrushTexture(std::string)), mTextureBrushScenetool, SLOT(updateBrushHistory(std::string)));
|
||||
}
|
||||
|
||||
if (!mTerrainTextureSelection)
|
||||
{
|
||||
mTerrainTextureSelection.reset(new TerrainSelection(mParentNode, &getWorldspaceWidget(), TerrainSelectionType::Texture));
|
||||
}
|
||||
|
||||
EditMode::activate(toolbar);
|
||||
toolbar->addTool (mTextureBrushScenetool);
|
||||
}
|
||||
|
@ -74,6 +84,12 @@ void CSVRender::TerrainTextureMode::deactivate(CSVWidget::SceneToolbar* toolbar)
|
|||
delete mTextureBrushScenetool;
|
||||
mTextureBrushScenetool = 0;
|
||||
}
|
||||
|
||||
if (mTerrainTextureSelection)
|
||||
{
|
||||
mTerrainTextureSelection.reset();
|
||||
}
|
||||
|
||||
EditMode::deactivate(toolbar);
|
||||
}
|
||||
|
||||
|
@ -95,10 +111,10 @@ void CSVRender::TerrainTextureMode::primaryEditPressed(const WorldspaceHitResult
|
|||
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = document.getData().getLandTextures();
|
||||
int index = landtexturesCollection.searchId(mBrushTexture);
|
||||
|
||||
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted() && hit.hit == true)
|
||||
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted() && hit.hit && hit.tag == 0)
|
||||
{
|
||||
undoStack.beginMacro ("Edit texture records");
|
||||
if(allowLandTextureEditing(mCellId)==true)
|
||||
if(allowLandTextureEditing(mCellId))
|
||||
{
|
||||
undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, mCellId));
|
||||
editTerrainTextureGrid(hit);
|
||||
|
@ -109,10 +125,18 @@ void CSVRender::TerrainTextureMode::primaryEditPressed(const WorldspaceHitResult
|
|||
|
||||
void CSVRender::TerrainTextureMode::primarySelectPressed(const WorldspaceHitResult& hit)
|
||||
{
|
||||
if(hit.hit && hit.tag == 0)
|
||||
{
|
||||
selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::secondarySelectPressed(const WorldspaceHitResult& hit)
|
||||
{
|
||||
if(hit.hit && hit.tag == 0)
|
||||
{
|
||||
selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 1, false);
|
||||
}
|
||||
}
|
||||
|
||||
bool CSVRender::TerrainTextureMode::primaryEditStartDrag (const QPoint& pos)
|
||||
|
@ -129,13 +153,16 @@ bool CSVRender::TerrainTextureMode::primaryEditStartDrag (const QPoint& pos)
|
|||
|
||||
QUndoStack& undoStack = document.getUndoStack();
|
||||
|
||||
mDragMode = InteractionType_PrimaryEdit;
|
||||
|
||||
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = document.getData().getLandTextures();
|
||||
int index = landtexturesCollection.searchId(mBrushTexture);
|
||||
|
||||
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted())
|
||||
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted() && hit.hit && hit.tag == 0)
|
||||
{
|
||||
undoStack.beginMacro ("Edit texture records");
|
||||
if(allowLandTextureEditing(mCellId)==true && hit.hit == true)
|
||||
mIsEditing = true;
|
||||
if(allowLandTextureEditing(mCellId))
|
||||
{
|
||||
undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, mCellId));
|
||||
editTerrainTextureGrid(hit);
|
||||
|
@ -152,29 +179,64 @@ bool CSVRender::TerrainTextureMode::secondaryEditStartDrag (const QPoint& pos)
|
|||
|
||||
bool CSVRender::TerrainTextureMode::primarySelectStartDrag (const QPoint& pos)
|
||||
{
|
||||
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
|
||||
mDragMode = InteractionType_PrimarySelect;
|
||||
if (!hit.hit || hit.tag != 0)
|
||||
{
|
||||
mDragMode = InteractionType_None;
|
||||
return false;
|
||||
}
|
||||
selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 0, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CSVRender::TerrainTextureMode::secondarySelectStartDrag (const QPoint& pos)
|
||||
{
|
||||
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
|
||||
mDragMode = InteractionType_SecondarySelect;
|
||||
if (!hit.hit || hit.tag != 0)
|
||||
{
|
||||
mDragMode = InteractionType_None;
|
||||
return false;
|
||||
}
|
||||
selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 1, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::drag (const QPoint& pos, int diffX, int diffY, double speedFactor)
|
||||
{
|
||||
if (mDragMode == InteractionType_PrimaryEdit)
|
||||
{
|
||||
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
|
||||
std::string cellId = getWorldspaceWidget().getCellId (hit.worldPos);
|
||||
CSMDoc::Document& document = getWorldspaceWidget().getDocument();
|
||||
|
||||
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = document.getData().getLandTextures();
|
||||
int index = landtexturesCollection.searchId(mBrushTexture);
|
||||
|
||||
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted() && hit.hit == true)
|
||||
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted() && hit.hit && hit.tag == 0)
|
||||
{
|
||||
editTerrainTextureGrid(hit);
|
||||
}
|
||||
}
|
||||
|
||||
if (mDragMode == InteractionType_PrimarySelect)
|
||||
{
|
||||
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
|
||||
if (hit.hit && hit.tag == 0) selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 0, true);
|
||||
}
|
||||
|
||||
if (mDragMode == InteractionType_SecondarySelect)
|
||||
{
|
||||
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
|
||||
if (hit.hit && hit.tag == 0) selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 1, true);
|
||||
}
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::dragCompleted(const QPoint& pos) {
|
||||
void CSVRender::TerrainTextureMode::dragCompleted(const QPoint& pos)
|
||||
{
|
||||
if (mDragMode == InteractionType_PrimaryEdit && mIsEditing)
|
||||
{
|
||||
CSMDoc::Document& document = getWorldspaceWidget().getDocument();
|
||||
QUndoStack& undoStack = document.getUndoStack();
|
||||
|
||||
|
@ -184,15 +246,21 @@ void CSVRender::TerrainTextureMode::dragCompleted(const QPoint& pos) {
|
|||
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted())
|
||||
{
|
||||
undoStack.endMacro();
|
||||
mIsEditing = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::dragAborted() {
|
||||
void CSVRender::TerrainTextureMode::dragAborted()
|
||||
{
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::dragWheel (int diff, double speedFactor) {}
|
||||
void CSVRender::TerrainTextureMode::dragWheel (int diff, double speedFactor)
|
||||
{
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::handleDropEvent (QDropEvent *event) {
|
||||
void CSVRender::TerrainTextureMode::handleDropEvent (QDropEvent *event)
|
||||
{
|
||||
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
|
||||
|
||||
if (!mime) // May happen when non-records (e.g. plain text) are dragged and dropped
|
||||
|
@ -228,7 +296,7 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe
|
|||
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Land));
|
||||
|
||||
mCellId = getWorldspaceWidget().getCellId (hit.worldPos);
|
||||
if(allowLandTextureEditing(mCellId)==true) {}
|
||||
if(allowLandTextureEditing(mCellId)) {}
|
||||
|
||||
std::pair<CSMWorld::CellCoordinates, bool> cellCoordinates_pair = CSMWorld::CellCoordinates::fromId (mCellId);
|
||||
|
||||
|
@ -236,8 +304,8 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe
|
|||
int cellY = cellCoordinates_pair.first.getY();
|
||||
|
||||
// The coordinates of hit in mCellId
|
||||
int xHitInCell (float(((hit.worldPos.x() - (cellX* cellSize)) * landTextureSize / cellSize) - 0.5));
|
||||
int yHitInCell (float(((hit.worldPos.y() - (cellY* cellSize)) * landTextureSize / cellSize) + 0.5));
|
||||
int xHitInCell (float(((hit.worldPos.x() - (cellX* cellSize)) * landTextureSize / cellSize) - 0.25));
|
||||
int yHitInCell (float(((hit.worldPos.y() - (cellY* cellSize)) * landTextureSize / cellSize) + 0.25));
|
||||
if (xHitInCell < 0)
|
||||
{
|
||||
xHitInCell = xHitInCell + landTextureSize;
|
||||
|
@ -249,8 +317,8 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe
|
|||
cellY = cellY + 1;
|
||||
}
|
||||
|
||||
mCellId = "#" + std::to_string(cellX) + " " + std::to_string(cellY);
|
||||
if(allowLandTextureEditing(mCellId)==true) {}
|
||||
mCellId = CSMWorld::CellCoordinates::generateId(cellX, cellY);
|
||||
if(allowLandTextureEditing(mCellId)) {}
|
||||
|
||||
std::string iteratedCellId;
|
||||
|
||||
|
@ -266,13 +334,13 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe
|
|||
|
||||
if (mBrushShape == 0)
|
||||
{
|
||||
CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(mCellId, textureColumn)).value<CSMWorld::LandTexturesColumn::DataType>();
|
||||
CSMWorld::LandTexturesColumn::DataType mNew(mPointer);
|
||||
CSMWorld::LandTexturesColumn::DataType newTerrainPointer = landTable.data(landTable.getModelIndex(mCellId, textureColumn)).value<CSMWorld::LandTexturesColumn::DataType>();
|
||||
CSMWorld::LandTexturesColumn::DataType newTerrain(newTerrainPointer);
|
||||
|
||||
if(allowLandTextureEditing(mCellId)==true)
|
||||
if(allowLandTextureEditing(mCellId))
|
||||
{
|
||||
mNew[yHitInCell*landTextureSize+xHitInCell] = brushInt;
|
||||
pushEditToCommand(mNew, document, landTable, mCellId);
|
||||
newTerrain[yHitInCell*landTextureSize+xHitInCell] = brushInt;
|
||||
pushEditToCommand(newTerrain, document, landTable, mCellId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -292,11 +360,11 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe
|
|||
{
|
||||
for(int j_cell = upperLeftCellY; j_cell <= lowerrightCellY; j_cell++)
|
||||
{
|
||||
iteratedCellId = "#" + std::to_string(i_cell) + " " + std::to_string(j_cell);
|
||||
if(allowLandTextureEditing(iteratedCellId)==true)
|
||||
iteratedCellId = CSMWorld::CellCoordinates::generateId(i_cell, j_cell);
|
||||
if(allowLandTextureEditing(iteratedCellId))
|
||||
{
|
||||
CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(iteratedCellId, textureColumn)).value<CSMWorld::LandTexturesColumn::DataType>();
|
||||
CSMWorld::LandTexturesColumn::DataType mNew(mPointer);
|
||||
CSMWorld::LandTexturesColumn::DataType newTerrainPointer = landTable.data(landTable.getModelIndex(iteratedCellId, textureColumn)).value<CSMWorld::LandTexturesColumn::DataType>();
|
||||
CSMWorld::LandTexturesColumn::DataType newTerrain(newTerrainPointer);
|
||||
for(int i = 0; i < landTextureSize; i++)
|
||||
{
|
||||
for(int j = 0; j < landTextureSize; j++)
|
||||
|
@ -304,7 +372,7 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe
|
|||
|
||||
if (i_cell == cellX && j_cell == cellY && abs(i-xHitInCell) < r && abs(j-yHitInCell) < r)
|
||||
{
|
||||
mNew[j*landTextureSize+i] = brushInt;
|
||||
newTerrain[j*landTextureSize+i] = brushInt;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -316,11 +384,11 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe
|
|||
if (j_cell > cellY) distanceY = -yHitInCell + landTextureSize * abs(j_cell-cellY) + j;
|
||||
if (i_cell == cellX) distanceX = abs(i-xHitInCell);
|
||||
if (j_cell == cellY) distanceY = abs(j-yHitInCell);
|
||||
if (distanceX < r && distanceY < r) mNew[j*landTextureSize+i] = brushInt;
|
||||
if (distanceX < r && distanceY < r) newTerrain[j*landTextureSize+i] = brushInt;
|
||||
}
|
||||
}
|
||||
}
|
||||
pushEditToCommand(mNew, document, landTable, iteratedCellId);
|
||||
pushEditToCommand(newTerrain, document, landTable, iteratedCellId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -342,11 +410,11 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe
|
|||
{
|
||||
for(int j_cell = upperLeftCellY; j_cell <= lowerrightCellY; j_cell++)
|
||||
{
|
||||
iteratedCellId = "#" + std::to_string(i_cell) + " " + std::to_string(j_cell);
|
||||
if(allowLandTextureEditing(iteratedCellId)==true)
|
||||
iteratedCellId = CSMWorld::CellCoordinates::generateId(i_cell, j_cell);
|
||||
if(allowLandTextureEditing(iteratedCellId))
|
||||
{
|
||||
CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(iteratedCellId, textureColumn)).value<CSMWorld::LandTexturesColumn::DataType>();
|
||||
CSMWorld::LandTexturesColumn::DataType mNew(mPointer);
|
||||
CSMWorld::LandTexturesColumn::DataType newTerrainPointer = landTable.data(landTable.getModelIndex(iteratedCellId, textureColumn)).value<CSMWorld::LandTexturesColumn::DataType>();
|
||||
CSMWorld::LandTexturesColumn::DataType newTerrain(newTerrainPointer);
|
||||
for(int i = 0; i < landTextureSize; i++)
|
||||
{
|
||||
for(int j = 0; j < landTextureSize; j++)
|
||||
|
@ -363,7 +431,7 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe
|
|||
if (i_cell == cellX) distanceX = abs(i-xHitInCell);
|
||||
if (j_cell == cellY) distanceY = abs(j-yHitInCell);
|
||||
distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2)));
|
||||
if (distance < rf) mNew[j*landTextureSize+i] = brushInt;
|
||||
if (distance < rf) newTerrain[j*landTextureSize+i] = brushInt;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -376,11 +444,11 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe
|
|||
if (i_cell == cellX) distanceX = abs(i-xHitInCell);
|
||||
if (j_cell == cellY) distanceY = abs(j-yHitInCell);
|
||||
distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2)));
|
||||
if (distance < rf) mNew[j*landTextureSize+i] = brushInt;
|
||||
if (distance < rf) newTerrain[j*landTextureSize+i] = brushInt;
|
||||
}
|
||||
}
|
||||
}
|
||||
pushEditToCommand(mNew, document, landTable, iteratedCellId);
|
||||
pushEditToCommand(newTerrain, document, landTable, iteratedCellId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -388,9 +456,115 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe
|
|||
|
||||
if (mBrushShape == 3)
|
||||
{
|
||||
// Not implemented
|
||||
CSMWorld::LandTexturesColumn::DataType newTerrainPointer = landTable.data(landTable.getModelIndex(mCellId, textureColumn)).value<CSMWorld::LandTexturesColumn::DataType>();
|
||||
CSMWorld::LandTexturesColumn::DataType newTerrain(newTerrainPointer);
|
||||
|
||||
if(allowLandTextureEditing(mCellId) && !mCustomBrushShape.empty())
|
||||
{
|
||||
for(auto const& value: mCustomBrushShape)
|
||||
{
|
||||
if(yHitInCell + value.second >= 0 && yHitInCell + value.second <= 15 && xHitInCell + value.first >= 0 && xHitInCell + value.first <= 15)
|
||||
{
|
||||
newTerrain[(yHitInCell+value.second)*landTextureSize+xHitInCell+value.first] = brushInt;
|
||||
}
|
||||
else
|
||||
{
|
||||
int cellXDifference = std::floor(1.0f*(xHitInCell + value.first)/landTextureSize);
|
||||
int cellYDifference = std::floor(1.0f*(yHitInCell + value.second)/landTextureSize);
|
||||
int xInOtherCell = xHitInCell + value.first - cellXDifference * landTextureSize;
|
||||
int yInOtherCell = yHitInCell + value.second - cellYDifference * landTextureSize;
|
||||
|
||||
std::string cellId = CSMWorld::CellCoordinates::generateId(cellX+cellXDifference, cellY+cellYDifference);
|
||||
if (allowLandTextureEditing(cellId))
|
||||
{
|
||||
CSMWorld::LandTexturesColumn::DataType newTerrainPointerOtherCell = landTable.data(landTable.getModelIndex(cellId, textureColumn)).value<CSMWorld::LandTexturesColumn::DataType>();
|
||||
CSMWorld::LandTexturesColumn::DataType newTerrainOtherCell(newTerrainPointerOtherCell);
|
||||
newTerrainOtherCell[yInOtherCell*landTextureSize+xInOtherCell] = brushInt;
|
||||
pushEditToCommand(newTerrainOtherCell, document, landTable, cellId);
|
||||
}
|
||||
}
|
||||
}
|
||||
pushEditToCommand(newTerrain, document, landTable, mCellId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CSVRender::TerrainTextureMode::isInCellSelection(int globalSelectionX, int globalSelectionY)
|
||||
{
|
||||
if (CSVRender::PagedWorldspaceWidget *paged = dynamic_cast<CSVRender::PagedWorldspaceWidget *> (&getWorldspaceWidget()))
|
||||
{
|
||||
std::pair<int, int> textureCoords = std::make_pair(globalSelectionX, globalSelectionY);
|
||||
std::string cellId = CSMWorld::CellCoordinates::textureGlobalToCellId(textureCoords);
|
||||
return paged->getCellSelection().has(CSMWorld::CellCoordinates::fromId(cellId).first);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void CSVRender::TerrainTextureMode::selectTerrainTextures(const std::pair<int, int>& texCoords, unsigned char selectMode, bool dragOperation)
|
||||
{
|
||||
int r = mBrushSize / 2;
|
||||
std::vector<std::pair<int, int>> selections;
|
||||
|
||||
if (mBrushShape == 0)
|
||||
{
|
||||
if (isInCellSelection(texCoords.first, texCoords.second)) selections.emplace_back(texCoords);
|
||||
}
|
||||
|
||||
if (mBrushShape == 1)
|
||||
{
|
||||
for (int i = -r; i <= r; i++)
|
||||
{
|
||||
for (int j = -r; j <= r; j++)
|
||||
{
|
||||
int x = i + texCoords.first;
|
||||
int y = j + texCoords.second;
|
||||
if (isInCellSelection(x, y))
|
||||
{
|
||||
selections.emplace_back(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mBrushShape == 2)
|
||||
{
|
||||
for (int i = -r; i <= r; i++)
|
||||
{
|
||||
for (int j = -r; j <= r; j++)
|
||||
{
|
||||
osg::Vec2f coords(i,j);
|
||||
if (std::round(coords.length()) < r)
|
||||
{
|
||||
int x = i + texCoords.first;
|
||||
int y = j + texCoords.second;
|
||||
if (isInCellSelection(x, y))
|
||||
{
|
||||
selections.emplace_back(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mBrushShape == 3)
|
||||
{
|
||||
if(!mCustomBrushShape.empty())
|
||||
{
|
||||
for(auto const& value: mCustomBrushShape)
|
||||
{
|
||||
int x = texCoords.first + value.first;
|
||||
int y = texCoords.second + value.second;
|
||||
if (isInCellSelection(x, y))
|
||||
{
|
||||
selections.emplace_back(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(selectMode == 0) mTerrainTextureSelection->onlySelect(selections);
|
||||
if(selectMode == 1) mTerrainTextureSelection->toggleSelect(selections, dragOperation);
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::pushEditToCommand(CSMWorld::LandTexturesColumn::DataType& newLandGrid, CSMDoc::Document& document,
|
||||
|
@ -405,8 +579,8 @@ void CSVRender::TerrainTextureMode::pushEditToCommand(CSMWorld::LandTexturesColu
|
|||
QModelIndex index(landTable.getModelIndex (cellId, landTable.findColumnIndex (CSMWorld::Columns::ColumnId_LandTexturesIndex)));
|
||||
|
||||
QUndoStack& undoStack = document.getUndoStack();
|
||||
undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, cellId));
|
||||
undoStack.push (new CSMWorld::ModifyCommand(landTable, index, changedLand));
|
||||
undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, cellId));
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::createTexture(std::string textureFileName)
|
||||
|
@ -422,13 +596,15 @@ void CSVRender::TerrainTextureMode::createTexture(std::string textureFileName)
|
|||
|
||||
int counter=0;
|
||||
bool freeIndexFound = false;
|
||||
do {
|
||||
do
|
||||
{
|
||||
const size_t maxCounter = std::numeric_limits<uint16_t>::max() - 1;
|
||||
try
|
||||
{
|
||||
newId = CSMWorld::LandTexture::createUniqueRecordId(0, counter);
|
||||
if (ltexTable.getRecord(newId).isDeleted() == 0) counter = (counter + 1) % maxCounter;
|
||||
} catch (const std::exception& e)
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
newId = CSMWorld::LandTexture::createUniqueRecordId(0, counter);
|
||||
freeIndexFound = true;
|
||||
|
@ -527,7 +703,8 @@ bool CSVRender::TerrainTextureMode::allowLandTextureEditing(std::string cellId)
|
|||
return true;
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::dragMoveEvent (QDragMoveEvent *event) {
|
||||
void CSVRender::TerrainTextureMode::dragMoveEvent (QDragMoveEvent *event)
|
||||
{
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::setBrushSize(int brushSize)
|
||||
|
@ -538,6 +715,28 @@ void CSVRender::TerrainTextureMode::setBrushSize(int brushSize)
|
|||
void CSVRender::TerrainTextureMode::setBrushShape(int brushShape)
|
||||
{
|
||||
mBrushShape = brushShape;
|
||||
|
||||
//Set custom brush shape
|
||||
if (mBrushShape == 3 && !mTerrainTextureSelection->getTerrainSelection().empty())
|
||||
{
|
||||
auto terrainSelection = mTerrainTextureSelection->getTerrainSelection();
|
||||
int selectionCenterX = 0;
|
||||
int selectionCenterY = 0;
|
||||
int selectionAmount = 0;
|
||||
|
||||
for(auto const& value: terrainSelection)
|
||||
{
|
||||
selectionCenterX += value.first;
|
||||
selectionCenterY += value.second;
|
||||
++selectionAmount;
|
||||
}
|
||||
selectionCenterX /= selectionAmount;
|
||||
selectionCenterY /= selectionAmount;
|
||||
|
||||
mCustomBrushShape.clear();
|
||||
for (auto const& value: terrainSelection)
|
||||
mCustomBrushShape.emplace_back(value.first - selectionCenterX, value.second - selectionCenterY);
|
||||
}
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::setBrushTexture(std::string brushTexture)
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "editmode.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#include <QWidget>
|
||||
#include <QEvent>
|
||||
|
@ -18,6 +19,13 @@
|
|||
#include "../../model/world/landtexture.hpp"
|
||||
#endif
|
||||
|
||||
#include "terrainselection.hpp"
|
||||
|
||||
namespace osg
|
||||
{
|
||||
class Group;
|
||||
}
|
||||
|
||||
namespace CSVWidget
|
||||
{
|
||||
class SceneToolTextureBrush;
|
||||
|
@ -25,15 +33,23 @@ namespace CSVWidget
|
|||
|
||||
namespace CSVRender
|
||||
{
|
||||
|
||||
class TerrainTextureMode : public EditMode
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
enum InteractionType
|
||||
{
|
||||
InteractionType_PrimaryEdit,
|
||||
InteractionType_PrimarySelect,
|
||||
InteractionType_SecondaryEdit,
|
||||
InteractionType_SecondarySelect,
|
||||
InteractionType_None
|
||||
};
|
||||
|
||||
/// \brief Editmode for terrain texture grid
|
||||
TerrainTextureMode(WorldspaceWidget*, QWidget* parent = nullptr);
|
||||
TerrainTextureMode(WorldspaceWidget*, osg::Group* parentNode, QWidget* parent = nullptr);
|
||||
|
||||
void primaryOpenPressed (const WorldspaceHitResult& hit);
|
||||
|
||||
|
@ -68,6 +84,12 @@ namespace CSVRender
|
|||
/// \brief Handle brush mechanics, maths regarding worldspace hit etc.
|
||||
void editTerrainTextureGrid (const WorldspaceHitResult& hit);
|
||||
|
||||
/// \brief Check if global selection coordinate belongs to cell in view
|
||||
bool isInCellSelection(int globalSelectionX, int globalSelectionY);
|
||||
|
||||
/// \brief Handle brush mechanics for texture selection
|
||||
void selectTerrainTextures (const std::pair<int, int>& texCoords, unsigned char selectMode, bool dragOperation);
|
||||
|
||||
/// \brief Push texture edits to command macro
|
||||
void pushEditToCommand (CSMWorld::LandTexturesColumn::DataType& newLandGrid, CSMDoc::Document& document,
|
||||
CSMWorld::IdTable& landTable, std::string cellId);
|
||||
|
@ -83,7 +105,12 @@ namespace CSVRender
|
|||
std::string mBrushTexture;
|
||||
int mBrushSize;
|
||||
int mBrushShape;
|
||||
std::vector<std::pair<int, int>> mCustomBrushShape;
|
||||
CSVWidget::SceneToolTextureBrush *mTextureBrushScenetool;
|
||||
int mDragMode;
|
||||
osg::Group* mParentNode;
|
||||
bool mIsEditing;
|
||||
std::unique_ptr<TerrainSelection> mTerrainTextureSelection;
|
||||
|
||||
const int cellSize {ESM::Land::REAL_SIZE};
|
||||
const int landSize {ESM::Land::LAND_SIZE};
|
||||
|
|
|
@ -130,8 +130,8 @@ namespace MWBase
|
|||
* If this parameter is false, it will be determined by a line-of-sight and awareness check.
|
||||
* @return was the crime seen?
|
||||
*/
|
||||
virtual bool commitCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim,
|
||||
OffenseType type, int arg=0, bool victimAware=false) = 0;
|
||||
virtual bool commitCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, OffenseType type,
|
||||
const std::string& factionId="", int arg=0, bool victimAware=false) = 0;
|
||||
/// @return false if the attack was considered a "friendly hit" and forgiven
|
||||
virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0;
|
||||
|
||||
|
|
|
@ -89,9 +89,7 @@ namespace MWClass
|
|||
|
||||
bool Activator::hasToolTip (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Activator> *ref = ptr.get<ESM::Activator>();
|
||||
|
||||
return (ref->mBase->mName != "");
|
||||
return !getName(ptr).empty();
|
||||
}
|
||||
|
||||
bool Activator::allowTelekinesis(const MWWorld::ConstPtr &ptr) const {
|
||||
|
@ -103,7 +101,7 @@ namespace MWClass
|
|||
const MWWorld::LiveCellRef<ESM::Activator> *ref = ptr.get<ESM::Activator>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + MWGui::ToolTips::getCountString(count);
|
||||
|
||||
std::string text;
|
||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||
|
|
|
@ -20,11 +20,10 @@ namespace MWClass
|
|||
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
|
||||
|
||||
virtual std::string getName (const MWWorld::ConstPtr& ptr) const;
|
||||
///< \return name (the one that is to be presented to the user; not the internal one);
|
||||
/// can return an empty string.
|
||||
///< \return name or ID; can return an empty string.
|
||||
|
||||
virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const;
|
||||
///< @return true if this object has a tooltip when focused (default implementation: false)
|
||||
///< @return true if this object has a tooltip when focused (default implementation: true)
|
||||
|
||||
virtual bool allowTelekinesis(const MWWorld::ConstPtr& ptr) const;
|
||||
///< Return whether this class of object can be activated with telekinesis
|
||||
|
|
|
@ -91,14 +91,4 @@ namespace MWClass
|
|||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Actor::canBeActivated(const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
MWMechanics::CreatureStats &stats = getCreatureStats(ptr);
|
||||
|
||||
if (stats.getAiSequence().isInCombat() && !stats.isDead())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,8 +42,6 @@ namespace MWClass
|
|||
|
||||
virtual bool isActor() const;
|
||||
|
||||
virtual bool canBeActivated(const MWWorld::Ptr& ptr) const;
|
||||
|
||||
// not implemented
|
||||
Actor(const Actor&);
|
||||
Actor& operator= (const Actor&);
|
||||
|
|
|
@ -45,8 +45,9 @@ namespace MWClass
|
|||
std::string Apparatus::getName (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Apparatus> *ref = ptr.get<ESM::Apparatus>();
|
||||
const std::string& name = ref->mBase->mName;
|
||||
|
||||
return ref->mBase->mName;
|
||||
return !name.empty() ? name : ref->mBase->mId;
|
||||
}
|
||||
|
||||
std::shared_ptr<MWWorld::Action> Apparatus::activate (const MWWorld::Ptr& ptr,
|
||||
|
@ -93,19 +94,12 @@ namespace MWClass
|
|||
return ref->mBase->mIcon;
|
||||
}
|
||||
|
||||
bool Apparatus::hasToolTip (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Apparatus> *ref = ptr.get<ESM::Apparatus>();
|
||||
|
||||
return (ref->mBase->mName != "");
|
||||
}
|
||||
|
||||
MWGui::ToolTipInfo Apparatus::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Apparatus> *ref = ptr.get<ESM::Apparatus>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + MWGui::ToolTips::getCountString(count);
|
||||
info.icon = ref->mBase->mIcon;
|
||||
|
||||
std::string text;
|
||||
|
|
|
@ -20,8 +20,7 @@ namespace MWClass
|
|||
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
|
||||
|
||||
virtual std::string getName (const MWWorld::ConstPtr& ptr) const;
|
||||
///< \return name (the one that is to be presented to the user; not the internal one);
|
||||
/// can return an empty string.
|
||||
///< \return name or ID; can return an empty string.
|
||||
|
||||
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor) const;
|
||||
|
@ -33,9 +32,6 @@ namespace MWClass
|
|||
virtual int getValue (const MWWorld::ConstPtr& ptr) const;
|
||||
///< Return trade value of the object. Throws an exception, if the object can't be traded.
|
||||
|
||||
virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const;
|
||||
///< @return true if this object has a tooltip when focused (default implementation: false)
|
||||
|
||||
virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const;
|
||||
///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.
|
||||
|
||||
|
|
|
@ -53,8 +53,9 @@ namespace MWClass
|
|||
std::string Armor::getName (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Armor> *ref = ptr.get<ESM::Armor>();
|
||||
const std::string& name = ref->mBase->mName;
|
||||
|
||||
return ref->mBase->mName;
|
||||
return !name.empty() ? name : ref->mBase->mId;
|
||||
}
|
||||
|
||||
std::shared_ptr<MWWorld::Action> Armor::activate (const MWWorld::Ptr& ptr,
|
||||
|
@ -199,19 +200,12 @@ namespace MWClass
|
|||
return ref->mBase->mIcon;
|
||||
}
|
||||
|
||||
bool Armor::hasToolTip (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Armor> *ref = ptr.get<ESM::Armor>();
|
||||
|
||||
return (ref->mBase->mName != "");
|
||||
}
|
||||
|
||||
MWGui::ToolTipInfo Armor::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Armor> *ref = ptr.get<ESM::Armor>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + MWGui::ToolTips::getCountString(count);
|
||||
info.icon = ref->mBase->mIcon;
|
||||
|
||||
std::string text;
|
||||
|
|
|
@ -19,8 +19,7 @@ namespace MWClass
|
|||
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
|
||||
|
||||
virtual std::string getName (const MWWorld::ConstPtr& ptr) const;
|
||||
///< \return name (the one that is to be presented to the user; not the internal one);
|
||||
/// can return an empty string.
|
||||
///< \return name or ID; can return an empty string.
|
||||
|
||||
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor) const;
|
||||
|
@ -43,9 +42,6 @@ namespace MWClass
|
|||
/// Return the index of the skill this item corresponds to when equipped or -1, if there is
|
||||
/// no such skill.
|
||||
|
||||
virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const;
|
||||
///< @return true if this object has a tooltip when focused (default implementation: false)
|
||||
|
||||
virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const;
|
||||
///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.
|
||||
|
||||
|
|
|
@ -31,6 +31,11 @@ namespace MWClass
|
|||
return std::string();
|
||||
}
|
||||
|
||||
bool BodyPart::hasToolTip(const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void BodyPart::registerSelf()
|
||||
{
|
||||
std::shared_ptr<MWWorld::Class> instance (new BodyPart);
|
||||
|
|
|
@ -18,8 +18,10 @@ namespace MWClass
|
|||
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
|
||||
|
||||
virtual std::string getName (const MWWorld::ConstPtr& ptr) const;
|
||||
///< \return name (the one that is to be presented to the user; not the internal one);
|
||||
/// can return an empty string.
|
||||
///< \return name or ID; can return an empty string.
|
||||
|
||||
virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const;
|
||||
///< @return true if this object has a tooltip when focused (default implementation: true)
|
||||
|
||||
static void registerSelf();
|
||||
|
||||
|
|
|
@ -50,8 +50,9 @@ namespace MWClass
|
|||
std::string Book::getName (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Book> *ref = ptr.get<ESM::Book>();
|
||||
const std::string& name = ref->mBase->mName;
|
||||
|
||||
return ref->mBase->mName;
|
||||
return !name.empty() ? name : ref->mBase->mId;
|
||||
}
|
||||
|
||||
std::shared_ptr<MWWorld::Action> Book::activate (const MWWorld::Ptr& ptr,
|
||||
|
@ -109,19 +110,12 @@ namespace MWClass
|
|||
return ref->mBase->mIcon;
|
||||
}
|
||||
|
||||
bool Book::hasToolTip (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Book> *ref = ptr.get<ESM::Book>();
|
||||
|
||||
return (ref->mBase->mName != "");
|
||||
}
|
||||
|
||||
MWGui::ToolTipInfo Book::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Book> *ref = ptr.get<ESM::Book>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + MWGui::ToolTips::getCountString(count);
|
||||
info.icon = ref->mBase->mIcon;
|
||||
|
||||
std::string text;
|
||||
|
|
|
@ -17,8 +17,7 @@ namespace MWClass
|
|||
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
|
||||
|
||||
virtual std::string getName (const MWWorld::ConstPtr& ptr) const;
|
||||
///< \return name (the one that is to be presented to the user; not the internal one);
|
||||
/// can return an empty string.
|
||||
///< \return name or ID; can return an empty string.
|
||||
|
||||
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor) const;
|
||||
|
@ -27,9 +26,6 @@ namespace MWClass
|
|||
virtual std::string getScript (const MWWorld::ConstPtr& ptr) const;
|
||||
///< Return name of the script attached to ptr
|
||||
|
||||
virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const;
|
||||
///< @return true if this object has a tooltip when focused (default implementation: false)
|
||||
|
||||
virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const;
|
||||
///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.
|
||||
|
||||
|
|
|
@ -48,8 +48,9 @@ namespace MWClass
|
|||
std::string Clothing::getName (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Clothing> *ref = ptr.get<ESM::Clothing>();
|
||||
const std::string& name = ref->mBase->mName;
|
||||
|
||||
return ref->mBase->mName;
|
||||
return !name.empty() ? name : ref->mBase->mId;
|
||||
}
|
||||
|
||||
std::shared_ptr<MWWorld::Action> Clothing::activate (const MWWorld::Ptr& ptr,
|
||||
|
@ -157,19 +158,12 @@ namespace MWClass
|
|||
return ref->mBase->mIcon;
|
||||
}
|
||||
|
||||
bool Clothing::hasToolTip (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Clothing> *ref = ptr.get<ESM::Clothing>();
|
||||
|
||||
return (ref->mBase->mName != "");
|
||||
}
|
||||
|
||||
MWGui::ToolTipInfo Clothing::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Clothing> *ref = ptr.get<ESM::Clothing>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + MWGui::ToolTips::getCountString(count);
|
||||
info.icon = ref->mBase->mIcon;
|
||||
|
||||
std::string text;
|
||||
|
|
|
@ -17,8 +17,7 @@ namespace MWClass
|
|||
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
|
||||
|
||||
virtual std::string getName (const MWWorld::ConstPtr& ptr) const;
|
||||
///< \return name (the one that is to be presented to the user; not the internal one);
|
||||
/// can return an empty string.
|
||||
///< \return name or ID; can return an empty string.
|
||||
|
||||
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor) const;
|
||||
|
@ -35,9 +34,6 @@ namespace MWClass
|
|||
/// Return the index of the skill this item corresponds to when equipped or -1, if there is
|
||||
/// no such skill.
|
||||
|
||||
virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const;
|
||||
///< @return true if this object has a tooltip when focused (default implementation: false)
|
||||
|
||||
virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const;
|
||||
///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.
|
||||
|
||||
|
|
|
@ -224,8 +224,9 @@ namespace MWClass
|
|||
std::string Container::getName (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Container> *ref = ptr.get<ESM::Container>();
|
||||
const std::string& name = ref->mBase->mName;
|
||||
|
||||
return ref->mBase->mName;
|
||||
return !name.empty() ? name : ref->mBase->mId;
|
||||
}
|
||||
|
||||
MWWorld::ContainerStore& Container::getContainerStore (const MWWorld::Ptr& ptr)
|
||||
|
@ -252,26 +253,18 @@ namespace MWClass
|
|||
|
||||
bool Container::hasToolTip (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
if (getName(ptr).empty())
|
||||
return false;
|
||||
|
||||
if (const MWWorld::CustomData* data = ptr.getRefData().getCustomData())
|
||||
return !canBeHarvested(ptr) || data->asContainerCustomData().mContainerStore.hasVisibleItems();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Container::canBeActivated(const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
return hasToolTip(ptr);
|
||||
}
|
||||
|
||||
MWGui::ToolTipInfo Container::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Container> *ref = ptr.get<ESM::Container>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(getName(ptr));
|
||||
|
||||
std::string text;
|
||||
int lockLevel = ptr.getCellRef().getLockLevel();
|
||||
|
@ -282,9 +275,11 @@ namespace MWClass
|
|||
if (ptr.getCellRef().getTrap() != "")
|
||||
text += "\n#{sTrapped}";
|
||||
|
||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
|
||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||
{ text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
||||
if (Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "stolen_goods"))
|
||||
text += "\nYou can not use evidence chests";
|
||||
}
|
||||
|
||||
info.text = text;
|
||||
|
|
|
@ -20,15 +20,14 @@ namespace MWClass
|
|||
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
|
||||
|
||||
virtual std::string getName (const MWWorld::ConstPtr& ptr) const;
|
||||
///< \return name (the one that is to be presented to the user; not the internal one);
|
||||
/// can return an empty string.
|
||||
///< \return name or ID; can return an empty string.
|
||||
|
||||
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor) const;
|
||||
///< Generate action for activation
|
||||
|
||||
virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const;
|
||||
///< @return true if this object has a tooltip when focused (default implementation: false)
|
||||
///< @return true if this object has a tooltip when focused (default implementation: true)
|
||||
|
||||
virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const;
|
||||
///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.
|
||||
|
@ -57,8 +56,6 @@ namespace MWClass
|
|||
const;
|
||||
///< Write additional state from \a ptr into \a state.
|
||||
|
||||
virtual bool canBeActivated(const MWWorld::Ptr& ptr) const;
|
||||
|
||||
static void registerSelf();
|
||||
|
||||
virtual void respawn (const MWWorld::Ptr& ptr) const;
|
||||
|
|
|
@ -214,8 +214,9 @@ namespace MWClass
|
|||
std::string Creature::getName (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
|
||||
const std::string& name = ref->mBase->mName;
|
||||
|
||||
return ref->mBase->mName;
|
||||
return !name.empty() ? name : ref->mBase->mId;
|
||||
}
|
||||
|
||||
MWMechanics::CreatureStats& Creature::getCreatureStats (const MWWorld::Ptr& ptr) const
|
||||
|
@ -454,18 +455,15 @@ namespace MWClass
|
|||
// otherwise wait until death animation
|
||||
if(stats.isDeathAnimationFinished())
|
||||
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr));
|
||||
|
||||
// death animation is not finished, do nothing
|
||||
return std::shared_ptr<MWWorld::Action> (new MWWorld::FailedAction(""));
|
||||
}
|
||||
|
||||
if(stats.getAiSequence().isInCombat())
|
||||
return std::shared_ptr<MWWorld::Action>(new MWWorld::FailedAction(""));
|
||||
|
||||
if(stats.getKnockedDown())
|
||||
return std::shared_ptr<MWWorld::Action>(new MWWorld::FailedAction(""));
|
||||
|
||||
else if (!stats.getAiSequence().isInCombat() && !stats.getKnockedDown())
|
||||
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(ptr));
|
||||
|
||||
// Tribunal and some mod companions oddly enough must use open action as fallback
|
||||
if (!getScript(ptr).empty() && ptr.getRefData().getLocals().getIntVar(getScript(ptr), "companion"))
|
||||
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr));
|
||||
|
||||
return std::shared_ptr<MWWorld::Action>(new MWWorld::FailedAction(""));
|
||||
}
|
||||
|
||||
MWWorld::ContainerStore& Creature::getContainerStore (const MWWorld::Ptr& ptr) const
|
||||
|
@ -586,7 +584,7 @@ namespace MWClass
|
|||
const MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(getName(ptr));
|
||||
|
||||
std::string text;
|
||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||
|
|
|
@ -44,11 +44,10 @@ namespace MWClass
|
|||
///< Add reference into a cell for rendering
|
||||
|
||||
virtual std::string getName (const MWWorld::ConstPtr& ptr) const;
|
||||
///< \return name (the one that is to be presented to the user; not the internal one);
|
||||
/// can return an empty string.
|
||||
///< \return name or ID; can return an empty string.
|
||||
|
||||
virtual bool hasToolTip(const MWWorld::ConstPtr& ptr) const;
|
||||
///< @return true if this object has a tooltip when focused (default implementation: false)
|
||||
///< @return true if this object has a tooltip when focused (default implementation: true)
|
||||
|
||||
virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const;
|
||||
///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.
|
||||
|
|
|
@ -39,6 +39,11 @@ namespace MWClass
|
|||
return "";
|
||||
}
|
||||
|
||||
bool CreatureLevList::hasToolTip(const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void CreatureLevList::respawn(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
ensureCustomData(ptr);
|
||||
|
|
|
@ -12,8 +12,10 @@ namespace MWClass
|
|||
public:
|
||||
|
||||
virtual std::string getName (const MWWorld::ConstPtr& ptr) const;
|
||||
///< \return name (the one that is to be presented to the user; not the internal one);
|
||||
/// can return an empty string.
|
||||
///< \return name or ID; can return an empty string.
|
||||
|
||||
virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const;
|
||||
///< @return true if this object has a tooltip when focused (default implementation: true)
|
||||
|
||||
static void registerSelf();
|
||||
|
||||
|
|
|
@ -102,8 +102,9 @@ namespace MWClass
|
|||
std::string Door::getName (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Door> *ref = ptr.get<ESM::Door>();
|
||||
const std::string& name = ref->mBase->mName;
|
||||
|
||||
return ref->mBase->mName;
|
||||
return !name.empty() ? name : ref->mBase->mId;
|
||||
}
|
||||
|
||||
std::shared_ptr<MWWorld::Action> Door::activate (const MWWorld::Ptr& ptr,
|
||||
|
@ -267,19 +268,12 @@ namespace MWClass
|
|||
registerClass (typeid (ESM::Door).name(), instance);
|
||||
}
|
||||
|
||||
bool Door::hasToolTip (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Door> *ref = ptr.get<ESM::Door>();
|
||||
|
||||
return (ref->mBase->mName != "");
|
||||
}
|
||||
|
||||
MWGui::ToolTipInfo Door::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Door> *ref = ptr.get<ESM::Door>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(getName(ptr));
|
||||
|
||||
std::string text;
|
||||
|
||||
|
|
|
@ -25,16 +25,12 @@ namespace MWClass
|
|||
virtual bool useAnim() const;
|
||||
|
||||
virtual std::string getName (const MWWorld::ConstPtr& ptr) const;
|
||||
///< \return name (the one that is to be presented to the user; not the internal one);
|
||||
/// can return an empty string.
|
||||
///< \return name or ID; can return an empty string.
|
||||
|
||||
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor) const;
|
||||
///< Generate action for activation
|
||||
|
||||
virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const;
|
||||
///< @return true if this object has a tooltip when focused (default implementation: false)
|
||||
|
||||
virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const;
|
||||
///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.
|
||||
|
||||
|
|
|
@ -47,8 +47,9 @@ namespace MWClass
|
|||
std::string Ingredient::getName (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Ingredient> *ref = ptr.get<ESM::Ingredient>();
|
||||
const std::string& name = ref->mBase->mName;
|
||||
|
||||
return ref->mBase->mName;
|
||||
return !name.empty() ? name : ref->mBase->mId;
|
||||
}
|
||||
|
||||
std::shared_ptr<MWWorld::Action> Ingredient::activate (const MWWorld::Ptr& ptr,
|
||||
|
@ -105,19 +106,12 @@ namespace MWClass
|
|||
return ref->mBase->mIcon;
|
||||
}
|
||||
|
||||
bool Ingredient::hasToolTip (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Ingredient> *ref = ptr.get<ESM::Ingredient>();
|
||||
|
||||
return (ref->mBase->mName != "");
|
||||
}
|
||||
|
||||
MWGui::ToolTipInfo Ingredient::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Ingredient> *ref = ptr.get<ESM::Ingredient>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + MWGui::ToolTips::getCountString(count);
|
||||
info.icon = ref->mBase->mIcon;
|
||||
|
||||
std::string text;
|
||||
|
|
|
@ -17,16 +17,12 @@ namespace MWClass
|
|||
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
|
||||
|
||||
virtual std::string getName (const MWWorld::ConstPtr& ptr) const;
|
||||
///< \return name (the one that is to be presented to the user; not the internal one);
|
||||
/// can return an empty string.
|
||||
///< \return name or ID; can return an empty string.
|
||||
|
||||
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor) const;
|
||||
///< Generate action for activation
|
||||
|
||||
virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const;
|
||||
///< @return true if this object has a tooltip when focused (default implementation: false)
|
||||
|
||||
virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const;
|
||||
///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.
|
||||
|
||||
|
|
|
@ -10,6 +10,11 @@ namespace MWClass
|
|||
return "";
|
||||
}
|
||||
|
||||
bool ItemLevList::hasToolTip(const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void ItemLevList::registerSelf()
|
||||
{
|
||||
std::shared_ptr<Class> instance (new ItemLevList);
|
||||
|
|
|
@ -10,8 +10,10 @@ namespace MWClass
|
|||
public:
|
||||
|
||||
virtual std::string getName (const MWWorld::ConstPtr& ptr) const;
|
||||
///< \return name (the one that is to be presented to the user; not the internal one);
|
||||
/// can return an empty string.
|
||||
///< \return name or ID; can return an empty string.
|
||||
|
||||
virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const;
|
||||
///< @return true if this object has a tooltip when focused (default implementation: true)
|
||||
|
||||
static void registerSelf();
|
||||
};
|
||||
|
|
|
@ -70,9 +70,10 @@ namespace MWClass
|
|||
const MWWorld::LiveCellRef<ESM::Light> *ref = ptr.get<ESM::Light>();
|
||||
|
||||
if (ref->mBase->mModel.empty())
|
||||
return "";
|
||||
return std::string();
|
||||
|
||||
return ref->mBase->mName;
|
||||
const std::string& name = ref->mBase->mName;
|
||||
return !name.empty() ? name : ref->mBase->mId;
|
||||
}
|
||||
|
||||
std::shared_ptr<MWWorld::Action> Light::activate (const MWWorld::Ptr& ptr,
|
||||
|
@ -141,9 +142,7 @@ namespace MWClass
|
|||
|
||||
bool Light::hasToolTip (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Light> *ref = ptr.get<ESM::Light>();
|
||||
|
||||
return (ref->mBase->mName != "");
|
||||
return showsInInventory(ptr);
|
||||
}
|
||||
|
||||
MWGui::ToolTipInfo Light::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
|
||||
|
@ -151,7 +150,7 @@ namespace MWClass
|
|||
const MWWorld::LiveCellRef<ESM::Light> *ref = ptr.get<ESM::Light>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + MWGui::ToolTips::getCountString(count);
|
||||
info.icon = ref->mBase->mIcon;
|
||||
|
||||
std::string text;
|
||||
|
|
|
@ -19,11 +19,10 @@ namespace MWClass
|
|||
virtual bool useAnim() const;
|
||||
|
||||
virtual std::string getName (const MWWorld::ConstPtr& ptr) const;
|
||||
///< \return name (the one that is to be presented to the user; not the internal one);
|
||||
/// can return an empty string.
|
||||
///< \return name or ID; can return an empty string.
|
||||
|
||||
virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const;
|
||||
///< @return true if this object has a tooltip when focused (default implementation: false)
|
||||
///< @return true if this object has a tooltip when focused (default implementation: true)
|
||||
|
||||
virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const;
|
||||
///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.
|
||||
|
|
|
@ -47,8 +47,9 @@ namespace MWClass
|
|||
std::string Lockpick::getName (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Lockpick> *ref = ptr.get<ESM::Lockpick>();
|
||||
const std::string& name = ref->mBase->mName;
|
||||
|
||||
return ref->mBase->mName;
|
||||
return !name.empty() ? name : ref->mBase->mId;
|
||||
}
|
||||
|
||||
std::shared_ptr<MWWorld::Action> Lockpick::activate (const MWWorld::Ptr& ptr,
|
||||
|
@ -104,19 +105,12 @@ namespace MWClass
|
|||
return ref->mBase->mIcon;
|
||||
}
|
||||
|
||||
bool Lockpick::hasToolTip (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Lockpick> *ref = ptr.get<ESM::Lockpick>();
|
||||
|
||||
return (ref->mBase->mName != "");
|
||||
}
|
||||
|
||||
MWGui::ToolTipInfo Lockpick::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Lockpick> *ref = ptr.get<ESM::Lockpick>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + MWGui::ToolTips::getCountString(count);
|
||||
info.icon = ref->mBase->mIcon;
|
||||
|
||||
std::string text;
|
||||
|
|
|
@ -17,16 +17,12 @@ namespace MWClass
|
|||
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
|
||||
|
||||
virtual std::string getName (const MWWorld::ConstPtr& ptr) const;
|
||||
///< \return name (the one that is to be presented to the user; not the internal one);
|
||||
/// can return an empty string.
|
||||
///< \return name or ID; can return an empty string.
|
||||
|
||||
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor) const;
|
||||
///< Generate action for activation
|
||||
|
||||
virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const;
|
||||
///< @return true if this object has a tooltip when focused (default implementation: false)
|
||||
|
||||
virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const;
|
||||
///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.
|
||||
|
||||
|
|
|
@ -56,8 +56,9 @@ namespace MWClass
|
|||
std::string Miscellaneous::getName (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Miscellaneous> *ref = ptr.get<ESM::Miscellaneous>();
|
||||
const std::string& name = ref->mBase->mName;
|
||||
|
||||
return ref->mBase->mName;
|
||||
return !name.empty() ? name : ref->mBase->mId;
|
||||
}
|
||||
|
||||
std::shared_ptr<MWWorld::Action> Miscellaneous::activate (const MWWorld::Ptr& ptr,
|
||||
|
@ -134,13 +135,6 @@ namespace MWClass
|
|||
return ref->mBase->mIcon;
|
||||
}
|
||||
|
||||
bool Miscellaneous::hasToolTip (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Miscellaneous> *ref = ptr.get<ESM::Miscellaneous>();
|
||||
|
||||
return (ref->mBase->mName != "");
|
||||
}
|
||||
|
||||
MWGui::ToolTipInfo Miscellaneous::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Miscellaneous> *ref = ptr.get<ESM::Miscellaneous>();
|
||||
|
@ -159,14 +153,16 @@ namespace MWClass
|
|||
else // gold displays its count also if it's 1.
|
||||
countString = " (" + std::to_string(count) + ")";
|
||||
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + countString;
|
||||
info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + countString;
|
||||
info.icon = ref->mBase->mIcon;
|
||||
|
||||
if (ref->mRef.getSoul() != "")
|
||||
{
|
||||
const ESM::Creature *creature = store.get<ESM::Creature>().search(ref->mRef.getSoul());
|
||||
if (creature)
|
||||
if (creature && !creature->mName.empty())
|
||||
info.caption += " (" + creature->mName + ")";
|
||||
else if (creature)
|
||||
info.caption += " (" + creature->mId + ")";
|
||||
}
|
||||
|
||||
std::string text;
|
||||
|
|
|
@ -17,16 +17,12 @@ namespace MWClass
|
|||
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
|
||||
|
||||
virtual std::string getName (const MWWorld::ConstPtr& ptr) const;
|
||||
///< \return name (the one that is to be presented to the user; not the internal one);
|
||||
/// can return an empty string.
|
||||
///< \return name or ID; can return an empty string.
|
||||
|
||||
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor) const;
|
||||
///< Generate action for activation
|
||||
|
||||
virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const;
|
||||
///< @return true if this object has a tooltip when focused (default implementation: false)
|
||||
|
||||
virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const;
|
||||
///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.
|
||||
|
||||
|
|
|
@ -531,7 +531,9 @@ namespace MWClass
|
|||
}
|
||||
|
||||
const MWWorld::LiveCellRef<ESM::NPC> *ref = ptr.get<ESM::NPC>();
|
||||
return ref->mBase->mName;
|
||||
const std::string& name = ref->mBase->mName;
|
||||
|
||||
return !name.empty() ? name : ref->mBase->mId;
|
||||
}
|
||||
|
||||
MWMechanics::CreatureStats& Npc::getCreatureStats (const MWWorld::Ptr& ptr) const
|
||||
|
@ -884,24 +886,24 @@ namespace MWClass
|
|||
// otherwise wait until death animation
|
||||
if(stats.isDeathAnimationFinished())
|
||||
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr));
|
||||
|
||||
// death animation is not finished, do nothing
|
||||
return std::shared_ptr<MWWorld::Action> (new MWWorld::FailedAction(""));
|
||||
}
|
||||
|
||||
if(stats.getAiSequence().isInCombat())
|
||||
return std::shared_ptr<MWWorld::Action>(new MWWorld::FailedAction(""));
|
||||
|
||||
else if (!stats.getAiSequence().isInCombat())
|
||||
{
|
||||
if(getCreatureStats(actor).getStance(MWMechanics::CreatureStats::Stance_Sneak) || stats.getKnockedDown())
|
||||
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr)); // stealing
|
||||
|
||||
// Can't talk to werewolfs
|
||||
if(getNpcStats(ptr).isWerewolf())
|
||||
return std::shared_ptr<MWWorld::Action> (new MWWorld::FailedAction(""));
|
||||
|
||||
// Can't talk to werewolves
|
||||
if (!getNpcStats(ptr).isWerewolf())
|
||||
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(ptr));
|
||||
}
|
||||
|
||||
// Tribunal and some mod companions oddly enough must use open action as fallback
|
||||
if (!getScript(ptr).empty() && ptr.getRefData().getLocals().getIntVar(getScript(ptr), "companion"))
|
||||
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr));
|
||||
|
||||
return std::shared_ptr<MWWorld::Action> (new MWWorld::FailedAction(""));
|
||||
}
|
||||
|
||||
MWWorld::ContainerStore& Npc::getContainerStore (const MWWorld::Ptr& ptr)
|
||||
const
|
||||
{
|
||||
|
@ -1071,7 +1073,7 @@ namespace MWClass
|
|||
MWGui::ToolTipInfo info;
|
||||
|
||||
info.caption = MyGUI::TextIterator::toTagsString(getName(ptr));
|
||||
if(fullHelp && ptr.getRefData().getCustomData() && ptr.getRefData().getCustomData()->asNpcCustomData().mNpcStats.isWerewolf())
|
||||
if(fullHelp && !ref->mBase->mName.empty() && ptr.getRefData().getCustomData() && ptr.getRefData().getCustomData()->asNpcCustomData().mNpcStats.isWerewolf())
|
||||
{
|
||||
info.caption += " (";
|
||||
info.caption += MyGUI::TextIterator::toTagsString(ref->mBase->mName);
|
||||
|
|
|
@ -48,8 +48,7 @@ namespace MWClass
|
|||
///< Add reference into a cell for rendering
|
||||
|
||||
virtual std::string getName (const MWWorld::ConstPtr& ptr) const;
|
||||
///< \return name (the one that is to be presented to the user; not the internal one);
|
||||
/// can return an empty string.
|
||||
///< \return name or ID; can return an empty string.
|
||||
|
||||
virtual MWMechanics::CreatureStats& getCreatureStats (const MWWorld::Ptr& ptr) const;
|
||||
///< Return creature stats
|
||||
|
@ -61,7 +60,7 @@ namespace MWClass
|
|||
///< Return container store
|
||||
|
||||
virtual bool hasToolTip(const MWWorld::ConstPtr& ptr) const;
|
||||
///< @return true if this object has a tooltip when focused (default implementation: false)
|
||||
///< @return true if this object has a tooltip when focused (default implementation: true)
|
||||
|
||||
virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const;
|
||||
///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.
|
||||
|
|
|
@ -49,8 +49,9 @@ namespace MWClass
|
|||
std::string Potion::getName (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Potion> *ref = ptr.get<ESM::Potion>();
|
||||
const std::string& name = ref->mBase->mName;
|
||||
|
||||
return ref->mBase->mName;
|
||||
return !name.empty() ? name : ref->mBase->mId;
|
||||
}
|
||||
|
||||
std::shared_ptr<MWWorld::Action> Potion::activate (const MWWorld::Ptr& ptr,
|
||||
|
@ -98,19 +99,12 @@ namespace MWClass
|
|||
return ref->mBase->mIcon;
|
||||
}
|
||||
|
||||
bool Potion::hasToolTip (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Potion> *ref = ptr.get<ESM::Potion>();
|
||||
|
||||
return (ref->mBase->mName != "");
|
||||
}
|
||||
|
||||
MWGui::ToolTipInfo Potion::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Potion> *ref = ptr.get<ESM::Potion>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + MWGui::ToolTips::getCountString(count);
|
||||
info.icon = ref->mBase->mIcon;
|
||||
|
||||
std::string text;
|
||||
|
|
|
@ -17,16 +17,12 @@ namespace MWClass
|
|||
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
|
||||
|
||||
virtual std::string getName (const MWWorld::ConstPtr& ptr) const;
|
||||
///< \return name (the one that is to be presented to the user; not the internal one);
|
||||
/// can return an empty string.
|
||||
///< \return name or ID; can return an empty string.
|
||||
|
||||
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor) const;
|
||||
///< Generate action for activation
|
||||
|
||||
virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const;
|
||||
///< @return true if this object has a tooltip when focused (default implementation: false)
|
||||
|
||||
virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const;
|
||||
///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.
|
||||
|
||||
|
|
|
@ -47,8 +47,9 @@ namespace MWClass
|
|||
std::string Probe::getName (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Probe> *ref = ptr.get<ESM::Probe>();
|
||||
const std::string& name = ref->mBase->mName;
|
||||
|
||||
return ref->mBase->mName;
|
||||
return !name.empty() ? name : ref->mBase->mId;
|
||||
}
|
||||
std::shared_ptr<MWWorld::Action> Probe::activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor) const
|
||||
|
@ -104,19 +105,12 @@ namespace MWClass
|
|||
return ref->mBase->mIcon;
|
||||
}
|
||||
|
||||
bool Probe::hasToolTip (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Probe> *ref = ptr.get<ESM::Probe>();
|
||||
|
||||
return (ref->mBase->mName != "");
|
||||
}
|
||||
|
||||
MWGui::ToolTipInfo Probe::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Probe> *ref = ptr.get<ESM::Probe>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + MWGui::ToolTips::getCountString(count);
|
||||
info.icon = ref->mBase->mIcon;
|
||||
|
||||
std::string text;
|
||||
|
|
|
@ -17,16 +17,12 @@ namespace MWClass
|
|||
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
|
||||
|
||||
virtual std::string getName (const MWWorld::ConstPtr& ptr) const;
|
||||
///< \return name (the one that is to be presented to the user; not the internal one);
|
||||
/// can return an empty string.
|
||||
///< \return name or ID; can return an empty string.
|
||||
|
||||
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor) const;
|
||||
///< Generate action for activation
|
||||
|
||||
virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const;
|
||||
///< @return true if this object has a tooltip when focused (default implementation: false)
|
||||
|
||||
virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const;
|
||||
///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.
|
||||
|
||||
|
|
|
@ -44,8 +44,9 @@ namespace MWClass
|
|||
std::string Repair::getName (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Repair> *ref = ptr.get<ESM::Repair>();
|
||||
const std::string& name = ref->mBase->mName;
|
||||
|
||||
return ref->mBase->mName;
|
||||
return !name.empty() ? name : ref->mBase->mId;
|
||||
}
|
||||
|
||||
std::shared_ptr<MWWorld::Action> Repair::activate (const MWWorld::Ptr& ptr,
|
||||
|
@ -93,13 +94,6 @@ namespace MWClass
|
|||
return ref->mBase->mIcon;
|
||||
}
|
||||
|
||||
bool Repair::hasToolTip (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Repair> *ref = ptr.get<ESM::Repair>();
|
||||
|
||||
return (ref->mBase->mName != "");
|
||||
}
|
||||
|
||||
bool Repair::hasItemHealth (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
return true;
|
||||
|
@ -117,7 +111,7 @@ namespace MWClass
|
|||
const MWWorld::LiveCellRef<ESM::Repair> *ref = ptr.get<ESM::Repair>();
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + MWGui::ToolTips::getCountString(count);
|
||||
info.icon = ref->mBase->mIcon;
|
||||
|
||||
std::string text;
|
||||
|
|
|
@ -17,16 +17,12 @@ namespace MWClass
|
|||
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
|
||||
|
||||
virtual std::string getName (const MWWorld::ConstPtr& ptr) const;
|
||||
///< \return name (the one that is to be presented to the user; not the internal one);
|
||||
/// can return an empty string.
|
||||
///< \return name or ID; can return an empty string.
|
||||
|
||||
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor) const;
|
||||
///< Generate action for activation
|
||||
|
||||
virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const;
|
||||
///< @return true if this object has a tooltip when focused (default implementation: false)
|
||||
|
||||
virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const;
|
||||
///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.
|
||||
|
||||
|
|
|
@ -45,6 +45,11 @@ namespace MWClass
|
|||
return "";
|
||||
}
|
||||
|
||||
bool Static::hasToolTip(const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void Static::registerSelf()
|
||||
{
|
||||
std::shared_ptr<Class> instance (new Static);
|
||||
|
|
|
@ -17,8 +17,10 @@ namespace MWClass
|
|||
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
|
||||
|
||||
virtual std::string getName (const MWWorld::ConstPtr& ptr) const;
|
||||
///< \return name (the one that is to be presented to the user; not the internal one);
|
||||
/// can return an empty string.
|
||||
///< \return name or ID; can return an empty string.
|
||||
|
||||
virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const;
|
||||
///< @return true if this object has a tooltip when focused (default implementation: true)
|
||||
|
||||
static void registerSelf();
|
||||
|
||||
|
|
|
@ -53,8 +53,9 @@ namespace MWClass
|
|||
std::string Weapon::getName (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Weapon> *ref = ptr.get<ESM::Weapon>();
|
||||
const std::string& name = ref->mBase->mName;
|
||||
|
||||
return ref->mBase->mName;
|
||||
return !name.empty() ? name : ref->mBase->mId;
|
||||
}
|
||||
|
||||
std::shared_ptr<MWWorld::Action> Weapon::activate (const MWWorld::Ptr& ptr,
|
||||
|
@ -155,20 +156,13 @@ namespace MWClass
|
|||
return ref->mBase->mIcon;
|
||||
}
|
||||
|
||||
bool Weapon::hasToolTip (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Weapon> *ref = ptr.get<ESM::Weapon>();
|
||||
|
||||
return (ref->mBase->mName != "");
|
||||
}
|
||||
|
||||
MWGui::ToolTipInfo Weapon::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Weapon> *ref = ptr.get<ESM::Weapon>();
|
||||
const ESM::WeaponType* weaponType = MWMechanics::getWeaponType(ref->mBase->mData.mType);
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + MWGui::ToolTips::getCountString(count);
|
||||
info.icon = ref->mBase->mIcon;
|
||||
|
||||
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
||||
|
|
|
@ -18,16 +18,12 @@ namespace MWClass
|
|||
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
|
||||
|
||||
virtual std::string getName (const MWWorld::ConstPtr& ptr) const;
|
||||
///< \return name (the one that is to be presented to the user; not the internal one);
|
||||
/// can return an empty string.
|
||||
///< \return name or ID; can return an empty string.
|
||||
|
||||
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor) const;
|
||||
///< Generate action for activation
|
||||
|
||||
virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const;
|
||||
///< @return true if this object has a tooltip when focused (default implementation: false)
|
||||
|
||||
virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const;
|
||||
///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.
|
||||
|
||||
|
|
|
@ -651,9 +651,22 @@ namespace MWGui
|
|||
{
|
||||
std::string ret;
|
||||
ret += getMiscString(cellref.getOwner(), "Owner");
|
||||
ret += getMiscString(cellref.getFaction(), "Faction");
|
||||
if (cellref.getFactionRank() > 0)
|
||||
const std::string factionId = cellref.getFaction();
|
||||
ret += getMiscString(factionId, "Faction");
|
||||
if (!factionId.empty() && cellref.getFactionRank() >= 0)
|
||||
{
|
||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||
const ESM::Faction *fact = store.get<ESM::Faction>().search(factionId);
|
||||
if (fact != nullptr)
|
||||
{
|
||||
int rank = cellref.getFactionRank();
|
||||
const std::string rankName = fact->mRanks[rank];
|
||||
if (rankName.empty())
|
||||
ret += getValueString(cellref.getFactionRank(), "Rank");
|
||||
else
|
||||
ret += getMiscString(rankName, "Rank");
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, int> > itemOwners =
|
||||
MWBase::Environment::get().getMechanicsManager()->getStolenItemOwners(cellref.getRefId());
|
||||
|
|
|
@ -959,7 +959,7 @@ namespace MWMechanics
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!target.getClass().canBeActivated(target))
|
||||
if (!target.getClass().hasToolTip(target))
|
||||
return true;
|
||||
|
||||
// TODO: implement a better check to check if target is owned bed
|
||||
|
@ -1005,6 +1005,10 @@ namespace MWMechanics
|
|||
if (!cellref.getOwner().empty())
|
||||
victim = MWBase::Environment::get().getWorld()->searchPtr(cellref.getOwner(), true, false);
|
||||
|
||||
// A special case for evidence chest - we should not allow to take items even if it is technically permitted
|
||||
if (Misc::StringUtils::ciEqual(cellref.getRefId(), "stolen_goods"))
|
||||
return false;
|
||||
|
||||
return (!isOwned && !isFactionOwned);
|
||||
}
|
||||
|
||||
|
@ -1025,7 +1029,7 @@ namespace MWMechanics
|
|||
if (isAllowedToUse(ptr, bed, victim))
|
||||
return false;
|
||||
|
||||
if(commitCrime(ptr, victim, OT_SleepingInOwnedBed))
|
||||
if(commitCrime(ptr, victim, OT_SleepingInOwnedBed, bed.getCellRef().getFaction()))
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage64}");
|
||||
return true;
|
||||
|
@ -1039,7 +1043,7 @@ namespace MWMechanics
|
|||
MWWorld::Ptr victim;
|
||||
if (isAllowedToUse(ptr, item, victim))
|
||||
return;
|
||||
commitCrime(ptr, victim, OT_Trespassing);
|
||||
commitCrime(ptr, victim, OT_Trespassing, item.getCellRef().getFaction());
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, int> > MechanicsManager::getStolenItemOwners(const std::string& itemid)
|
||||
|
@ -1120,7 +1124,7 @@ namespace MWMechanics
|
|||
// move items from player to owner and report about theft
|
||||
victim.getClass().getContainerStore(victim).add(item, toRemove, victim);
|
||||
store.remove(item, toRemove, player);
|
||||
commitCrime(player, victim, OT_Theft, item.getClass().getValue(item) * toRemove);
|
||||
commitCrime(player, victim, OT_Theft, item.getCellRef().getFaction(), item.getClass().getValue(item) * toRemove);
|
||||
}
|
||||
|
||||
void MechanicsManager::confiscateStolenItems(const MWWorld::Ptr &player, const MWWorld::Ptr &targetContainer)
|
||||
|
@ -1207,11 +1211,11 @@ namespace MWMechanics
|
|||
mStolenItems[Misc::StringUtils::lowerCase(item.getCellRef().getRefId())][owner] += count;
|
||||
}
|
||||
if (alarm)
|
||||
commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count);
|
||||
commitCrime(ptr, victim, OT_Theft, ownerCellRef->getFaction(), item.getClass().getValue(item) * count);
|
||||
}
|
||||
|
||||
|
||||
bool MechanicsManager::commitCrime(const MWWorld::Ptr &player, const MWWorld::Ptr &victim, OffenseType type, int arg, bool victimAware)
|
||||
bool MechanicsManager::commitCrime(const MWWorld::Ptr &player, const MWWorld::Ptr &victim, OffenseType type, const std::string& factionId, int arg, bool victimAware)
|
||||
{
|
||||
// NOTE: victim may be empty
|
||||
|
||||
|
@ -1258,13 +1262,13 @@ namespace MWMechanics
|
|||
}
|
||||
|
||||
if (crimeSeen)
|
||||
reportCrime(player, victim, type, arg);
|
||||
reportCrime(player, victim, type, factionId, arg);
|
||||
else if (type == OT_Assault && !victim.isEmpty())
|
||||
{
|
||||
bool reported = false;
|
||||
if (victim.getClass().isClass(victim, "guard")
|
||||
&& !victim.getClass().getCreatureStats(victim).getAiSequence().hasPackage(AiPackage::TypeIdPursue))
|
||||
reported = reportCrime(player, victim, type, arg);
|
||||
reported = reportCrime(player, victim, type, std::string(), arg);
|
||||
|
||||
if (!reported)
|
||||
startCombat(victim, player); // TODO: combat should be started with an "unaware" flag, which makes the victim flee?
|
||||
|
@ -1295,7 +1299,7 @@ namespace MWMechanics
|
|||
return true;
|
||||
}
|
||||
|
||||
bool MechanicsManager::reportCrime(const MWWorld::Ptr &player, const MWWorld::Ptr &victim, OffenseType type, int arg)
|
||||
bool MechanicsManager::reportCrime(const MWWorld::Ptr &player, const MWWorld::Ptr &victim, OffenseType type, const std::string& factionId, int arg)
|
||||
{
|
||||
const MWWorld::Store<ESM::GameSetting>& store = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||
|
||||
|
@ -1466,6 +1470,14 @@ namespace MWMechanics
|
|||
player.getClass().getNpcStats(player).expell(factionID);
|
||||
}
|
||||
}
|
||||
else if (!factionId.empty())
|
||||
{
|
||||
const std::map<std::string, int>& playerRanks = player.getClass().getNpcStats(player).getFactionRanks();
|
||||
if (playerRanks.find(Misc::StringUtils::lowerCase(factionId)) != playerRanks.end())
|
||||
{
|
||||
player.getClass().getNpcStats(player).expell(factionId);
|
||||
}
|
||||
}
|
||||
|
||||
if (type == OT_Assault && !victim.isEmpty()
|
||||
&& !victim.getClass().getCreatureStats(victim).getAiSequence().isInCombat(player)
|
||||
|
|
|
@ -130,7 +130,7 @@ namespace MWMechanics
|
|||
* @return was the crime seen?
|
||||
*/
|
||||
virtual bool commitCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim,
|
||||
OffenseType type, int arg=0, bool victimAware=false) override;
|
||||
OffenseType type, const std::string& factionId="", int arg=0, bool victimAware=false) override;
|
||||
/// @return false if the attack was considered a "friendly hit" and forgiven
|
||||
virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) override;
|
||||
|
||||
|
@ -247,7 +247,7 @@ namespace MWMechanics
|
|||
bool canReportCrime(const MWWorld::Ptr &actor, const MWWorld::Ptr &victim, std::set<MWWorld::Ptr> &playerFollowers);
|
||||
|
||||
bool reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim,
|
||||
OffenseType type, int arg=0);
|
||||
OffenseType type, const std::string& factionId, int arg=0);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -109,11 +109,6 @@ namespace MWWorld
|
|||
throw std::runtime_error("class cannot block");
|
||||
}
|
||||
|
||||
bool Class::canBeActivated(const Ptr& ptr) const
|
||||
{
|
||||
return !getName(ptr).empty();
|
||||
}
|
||||
|
||||
void Class::onHit(const Ptr& ptr, float damage, bool ishealth, const Ptr& object, const Ptr& attacker, const osg::Vec3f& hitPosition, bool successful) const
|
||||
{
|
||||
throw std::runtime_error("class cannot be hit");
|
||||
|
@ -288,7 +283,7 @@ namespace MWWorld
|
|||
|
||||
bool Class::hasToolTip (const ConstPtr& ptr) const
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string Class::getEnchantment (const ConstPtr& ptr) const
|
||||
|
|
|
@ -83,8 +83,7 @@ namespace MWWorld
|
|||
///< Add reference into a cell for rendering (default implementation: don't render anything).
|
||||
|
||||
virtual std::string getName (const ConstPtr& ptr) const = 0;
|
||||
///< \return name (the one that is to be presented to the user; not the internal one);
|
||||
/// can return an empty string.
|
||||
///< \return name or ID; can return an empty string.
|
||||
|
||||
virtual void adjustPosition(const MWWorld::Ptr& ptr, bool force) const;
|
||||
///< Adjust position to stand on ground. Must be called post model load
|
||||
|
@ -95,7 +94,7 @@ namespace MWWorld
|
|||
/// (default implementation: throw an exception)
|
||||
|
||||
virtual bool hasToolTip (const ConstPtr& ptr) const;
|
||||
///< @return true if this object has a tooltip when focused (default implementation: false)
|
||||
///< @return true if this object has a tooltip when focused (default implementation: true)
|
||||
|
||||
virtual MWGui::ToolTipInfo getToolTipInfo (const ConstPtr& ptr, int count) const;
|
||||
///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.
|
||||
|
@ -140,10 +139,6 @@ namespace MWWorld
|
|||
///< Play the appropriate sound for a blocked attack, depending on the currently equipped shield
|
||||
/// (default implementation: throw an exception)
|
||||
|
||||
virtual bool canBeActivated(const Ptr& ptr) const;
|
||||
///< \return Can the player activate this object?
|
||||
/// (default implementation: true if object's user-readable name is not empty, false otherwise)
|
||||
|
||||
virtual std::shared_ptr<Action> activate (const Ptr& ptr, const Ptr& actor) const;
|
||||
///< Generate action for activation (default implementation: return a null action).
|
||||
|
||||
|
|
|
@ -236,7 +236,7 @@ namespace MWWorld
|
|||
if (toActivate.isEmpty())
|
||||
return;
|
||||
|
||||
if (!toActivate.getClass().canBeActivated(toActivate))
|
||||
if (!toActivate.getClass().hasToolTip(toActivate))
|
||||
return;
|
||||
|
||||
MWBase::Environment::get().getWorld()->activate(toActivate, player);
|
||||
|
|
|
@ -3023,7 +3023,7 @@ namespace MWWorld
|
|||
target = getFacedObject();
|
||||
|
||||
// if the faced object can not be activated, do not use it
|
||||
if (!target.isEmpty() && !target.getClass().canBeActivated(target))
|
||||
if (!target.isEmpty() && !target.getClass().hasToolTip(target))
|
||||
target = nullptr;
|
||||
|
||||
if (target.isEmpty())
|
||||
|
@ -3082,7 +3082,7 @@ namespace MWWorld
|
|||
{
|
||||
target = result2.mHitObject;
|
||||
hitPosition = result2.mHitPointWorld;
|
||||
if (dist2 > getMaxActivationDistance() && !target.isEmpty() && !target.getClass().canBeActivated(target))
|
||||
if (dist2 > getMaxActivationDistance() && !target.isEmpty() && !target.getClass().hasToolTip(target))
|
||||
target = nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -3650,7 +3650,7 @@ namespace MWWorld
|
|||
if (fromProjectile && effectInfo.mArea <= 0)
|
||||
continue; // Don't play explosion for projectiles with 0-area effects
|
||||
|
||||
if (!fromProjectile && effectInfo.mRange == ESM::RT_Touch && (!ignore.isEmpty()) && (!ignore.getClass().isActor() && !ignore.getClass().canBeActivated(ignore)))
|
||||
if (!fromProjectile && effectInfo.mRange == ESM::RT_Touch && !ignore.isEmpty() && !ignore.getClass().isActor() && !ignore.getClass().hasToolTip(ignore))
|
||||
continue; // Don't play explosion for touch spells on non-activatable objects except when spell is from the projectile enchantment
|
||||
|
||||
// Spawn the explosion orb effect
|
||||
|
|
|
@ -208,18 +208,13 @@ namespace
|
|||
|
||||
void init(Nif::Extra& value)
|
||||
{
|
||||
value.extra = Nif::ExtraPtr(nullptr);
|
||||
}
|
||||
|
||||
void init(Nif::Controlled& value)
|
||||
{
|
||||
init(static_cast<Nif::Extra&>(value));
|
||||
value.controller = Nif::ControllerPtr(nullptr);
|
||||
value.next = Nif::ExtraPtr(nullptr);
|
||||
}
|
||||
|
||||
void init(Nif::Named& value)
|
||||
{
|
||||
init(static_cast<Nif::Controlled&>(value));
|
||||
value.extra = Nif::ExtraPtr(nullptr);
|
||||
value.controller = Nif::ControllerPtr(nullptr);
|
||||
}
|
||||
|
||||
void init(Nif::Node& value)
|
||||
|
@ -254,7 +249,7 @@ namespace
|
|||
value.phase = 0;
|
||||
value.timeStart = 0;
|
||||
value.timeStop = 0;
|
||||
value.target = Nif::ControlledPtr(nullptr);
|
||||
value.target = Nif::NamedPtr(nullptr);
|
||||
}
|
||||
|
||||
void copy(const btTransform& src, Nif::Transformation& dst)
|
||||
|
@ -884,7 +879,7 @@ namespace
|
|||
|
||||
TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_not_first_extra_data_string_starting_with_nc_should_return_shape_with_null_collision_shape)
|
||||
{
|
||||
mNiStringExtraData.extra = Nif::ExtraPtr(&mNiStringExtraData2);
|
||||
mNiStringExtraData.next = Nif::ExtraPtr(&mNiStringExtraData2);
|
||||
mNiStringExtraData2.string = "NC___";
|
||||
mNiStringExtraData2.recType = Nif::RC_NiStringExtraData;
|
||||
mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
|
||||
|
|
|
@ -10,17 +10,19 @@
|
|||
|
||||
namespace Nif
|
||||
{
|
||||
/** A record that can have extra data. The extra data objects
|
||||
themselves descend from the Extra class, and all the extra data
|
||||
connected to an object form a linked list
|
||||
*/
|
||||
// An extra data record. All the extra data connected to an object form a linked list.
|
||||
class Extra : public Record
|
||||
{
|
||||
public:
|
||||
ExtraPtr extra;
|
||||
ExtraPtr next; // Next extra data record in the list
|
||||
|
||||
void read(NIFStream *nif) { extra.read(nif); }
|
||||
void post(NIFFile *nif) { extra.post(nif); }
|
||||
void read(NIFStream *nif)
|
||||
{
|
||||
next.read(nif);
|
||||
nif->getUInt(); // Size of the record
|
||||
}
|
||||
|
||||
void post(NIFFile *nif) { next.post(nif); }
|
||||
};
|
||||
|
||||
class Controller : public Record
|
||||
|
@ -30,43 +32,33 @@ public:
|
|||
int flags;
|
||||
float frequency, phase;
|
||||
float timeStart, timeStop;
|
||||
ControlledPtr target;
|
||||
NamedPtr target;
|
||||
|
||||
void read(NIFStream *nif);
|
||||
void post(NIFFile *nif);
|
||||
};
|
||||
|
||||
/// Anything that has a controller
|
||||
class Controlled : public Extra
|
||||
/// Has name, extra-data and controller
|
||||
class Named : public Record
|
||||
{
|
||||
public:
|
||||
std::string name;
|
||||
ExtraPtr extra;
|
||||
ControllerPtr controller;
|
||||
|
||||
void read(NIFStream *nif)
|
||||
{
|
||||
Extra::read(nif);
|
||||
name = nif->getString();
|
||||
extra.read(nif);
|
||||
controller.read(nif);
|
||||
}
|
||||
|
||||
void post(NIFFile *nif)
|
||||
{
|
||||
Extra::post(nif);
|
||||
extra.post(nif);
|
||||
controller.post(nif);
|
||||
}
|
||||
};
|
||||
|
||||
/// Has name, extra-data and controller
|
||||
class Named : public Controlled
|
||||
{
|
||||
public:
|
||||
std::string name;
|
||||
|
||||
void read(NIFStream *nif)
|
||||
{
|
||||
name = nif->getString();
|
||||
Controlled::read(nif);
|
||||
}
|
||||
};
|
||||
typedef Named NiSequenceStreamHelper;
|
||||
|
||||
} // Namespace
|
||||
|
|
|
@ -31,28 +31,40 @@ namespace Nif
|
|||
data.post(nif);
|
||||
}
|
||||
|
||||
void NiParticleModifier::read(NIFStream *nif)
|
||||
{
|
||||
next.read(nif);
|
||||
controller.read(nif);
|
||||
}
|
||||
|
||||
void NiParticleModifier::post(NIFFile *nif)
|
||||
{
|
||||
next.post(nif);
|
||||
controller.post(nif);
|
||||
}
|
||||
|
||||
void NiParticleGrowFade::read(NIFStream *nif)
|
||||
{
|
||||
Controlled::read(nif);
|
||||
NiParticleModifier::read(nif);
|
||||
growTime = nif->getFloat();
|
||||
fadeTime = nif->getFloat();
|
||||
}
|
||||
|
||||
void NiParticleColorModifier::read(NIFStream *nif)
|
||||
{
|
||||
Controlled::read(nif);
|
||||
NiParticleModifier::read(nif);
|
||||
data.read(nif);
|
||||
}
|
||||
|
||||
void NiParticleColorModifier::post(NIFFile *nif)
|
||||
{
|
||||
Controlled::post(nif);
|
||||
NiParticleModifier::post(nif);
|
||||
data.post(nif);
|
||||
}
|
||||
|
||||
void NiGravity::read(NIFStream *nif)
|
||||
{
|
||||
Controlled::read(nif);
|
||||
NiParticleModifier::read(nif);
|
||||
|
||||
mDecay = nif->getFloat();
|
||||
mForce = nif->getFloat();
|
||||
|
@ -61,11 +73,17 @@ namespace Nif
|
|||
mDirection = nif->getVector3();
|
||||
}
|
||||
|
||||
void NiPlanarCollider::read(NIFStream *nif)
|
||||
void NiParticleCollider::read(NIFStream *nif)
|
||||
{
|
||||
Controlled::read(nif);
|
||||
NiParticleModifier::read(nif);
|
||||
|
||||
mBounceFactor = nif->getFloat();
|
||||
}
|
||||
|
||||
void NiPlanarCollider::read(NIFStream *nif)
|
||||
{
|
||||
NiParticleCollider::read(nif);
|
||||
|
||||
/*unknown*/nif->getFloat();
|
||||
|
||||
for (int i=0;i<10;++i)
|
||||
|
@ -77,7 +95,7 @@ namespace Nif
|
|||
|
||||
void NiParticleRotation::read(NIFStream *nif)
|
||||
{
|
||||
Controlled::read(nif);
|
||||
NiParticleModifier::read(nif);
|
||||
|
||||
/*
|
||||
byte (0 or 1)
|
||||
|
@ -89,9 +107,8 @@ namespace Nif
|
|||
|
||||
void NiSphericalCollider::read(NIFStream* nif)
|
||||
{
|
||||
Controlled::read(nif);
|
||||
NiParticleCollider::read(nif);
|
||||
|
||||
mBounceFactor = nif->getFloat();
|
||||
mRadius = nif->getFloat();
|
||||
mCenter = nif->getVector3();
|
||||
}
|
||||
|
|
|
@ -66,7 +66,16 @@ public:
|
|||
void post(NIFFile *nif);
|
||||
};
|
||||
|
||||
class NiParticleGrowFade : public Controlled
|
||||
struct NiParticleModifier : public Record
|
||||
{
|
||||
NiParticleModifierPtr next;
|
||||
ControllerPtr controller;
|
||||
|
||||
void read(NIFStream *nif);
|
||||
void post(NIFFile *nif);
|
||||
};
|
||||
|
||||
class NiParticleGrowFade : public NiParticleModifier
|
||||
{
|
||||
public:
|
||||
float growTime;
|
||||
|
@ -75,7 +84,7 @@ public:
|
|||
void read(NIFStream *nif);
|
||||
};
|
||||
|
||||
class NiParticleColorModifier : public Controlled
|
||||
class NiParticleColorModifier : public NiParticleModifier
|
||||
{
|
||||
public:
|
||||
NiColorDataPtr data;
|
||||
|
@ -84,7 +93,7 @@ public:
|
|||
void post(NIFFile *nif);
|
||||
};
|
||||
|
||||
class NiGravity : public Controlled
|
||||
class NiGravity : public NiParticleModifier
|
||||
{
|
||||
public:
|
||||
float mForce;
|
||||
|
@ -99,29 +108,32 @@ public:
|
|||
void read(NIFStream *nif);
|
||||
};
|
||||
|
||||
struct NiParticleCollider : public NiParticleModifier
|
||||
{
|
||||
float mBounceFactor;
|
||||
void read(NIFStream *nif);
|
||||
};
|
||||
|
||||
// NiPinaColada
|
||||
class NiPlanarCollider : public Controlled
|
||||
class NiPlanarCollider : public NiParticleCollider
|
||||
{
|
||||
public:
|
||||
void read(NIFStream *nif);
|
||||
|
||||
float mBounceFactor;
|
||||
|
||||
osg::Vec3f mPlaneNormal;
|
||||
float mPlaneDistance;
|
||||
};
|
||||
|
||||
class NiSphericalCollider : public Controlled
|
||||
class NiSphericalCollider : public NiParticleCollider
|
||||
{
|
||||
public:
|
||||
float mBounceFactor;
|
||||
float mRadius;
|
||||
osg::Vec3f mCenter;
|
||||
|
||||
void read(NIFStream *nif);
|
||||
};
|
||||
|
||||
class NiParticleRotation : public Controlled
|
||||
class NiParticleRotation : public NiParticleModifier
|
||||
{
|
||||
public:
|
||||
void read(NIFStream *nif);
|
||||
|
|
|
@ -72,8 +72,8 @@ public:
|
|||
int activeCount;
|
||||
std::vector<Particle> particles;
|
||||
|
||||
ExtraPtr affectors;
|
||||
ExtraPtr colliders;
|
||||
NiParticleModifierPtr affectors;
|
||||
NiParticleModifierPtr colliders;
|
||||
|
||||
void read(NIFStream *nif);
|
||||
void post(NIFFile *nif);
|
||||
|
|
|
@ -6,8 +6,6 @@ namespace Nif
|
|||
void NiStringExtraData::read(NIFStream *nif)
|
||||
{
|
||||
Extra::read(nif);
|
||||
|
||||
nif->getInt(); // size of string + 4. Really useful...
|
||||
string = nif->getString();
|
||||
}
|
||||
|
||||
|
@ -15,8 +13,6 @@ void NiTextKeyExtraData::read(NIFStream *nif)
|
|||
{
|
||||
Extra::read(nif);
|
||||
|
||||
nif->getInt(); // 0
|
||||
|
||||
int keynum = nif->getInt();
|
||||
list.resize(keynum);
|
||||
for(int i=0; i<keynum; i++)
|
||||
|
@ -30,12 +26,7 @@ void NiVertWeightsExtraData::read(NIFStream *nif)
|
|||
{
|
||||
Extra::read(nif);
|
||||
|
||||
// We should have s*4+2 == i, for some reason. Might simply be the
|
||||
// size of the rest of the record, unhelpful as that may be.
|
||||
/*int i =*/ nif->getInt();
|
||||
int s = nif->getUShort();
|
||||
|
||||
nif->skip(s * sizeof(float)); // vertex weights I guess
|
||||
nif->skip(nif->getUShort() * sizeof(float)); // vertex weights I guess
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -127,7 +127,7 @@ class NiUVData;
|
|||
class NiPosData;
|
||||
class NiVisData;
|
||||
class Controller;
|
||||
class Controlled;
|
||||
class Named;
|
||||
class NiSkinData;
|
||||
class NiFloatData;
|
||||
struct NiMorphData;
|
||||
|
@ -141,6 +141,7 @@ class NiSourceTexture;
|
|||
class NiRotatingParticlesData;
|
||||
class NiAutoNormalParticlesData;
|
||||
class NiPalette;
|
||||
struct NiParticleModifier;
|
||||
|
||||
typedef RecordPtrT<Node> NodePtr;
|
||||
typedef RecordPtrT<Extra> ExtraPtr;
|
||||
|
@ -148,7 +149,7 @@ typedef RecordPtrT<NiUVData> NiUVDataPtr;
|
|||
typedef RecordPtrT<NiPosData> NiPosDataPtr;
|
||||
typedef RecordPtrT<NiVisData> NiVisDataPtr;
|
||||
typedef RecordPtrT<Controller> ControllerPtr;
|
||||
typedef RecordPtrT<Controlled> ControlledPtr;
|
||||
typedef RecordPtrT<Named> NamedPtr;
|
||||
typedef RecordPtrT<NiSkinData> NiSkinDataPtr;
|
||||
typedef RecordPtrT<NiMorphData> NiMorphDataPtr;
|
||||
typedef RecordPtrT<NiPixelData> NiPixelDataPtr;
|
||||
|
@ -162,6 +163,7 @@ typedef RecordPtrT<NiSourceTexture> NiSourceTexturePtr;
|
|||
typedef RecordPtrT<NiRotatingParticlesData> NiRotatingParticlesDataPtr;
|
||||
typedef RecordPtrT<NiAutoNormalParticlesData> NiAutoNormalParticlesDataPtr;
|
||||
typedef RecordPtrT<NiPalette> NiPalettePtr;
|
||||
typedef RecordPtrT<NiParticleModifier> NiParticleModifierPtr;
|
||||
|
||||
typedef RecordListT<Node> NodeList;
|
||||
typedef RecordListT<Property> PropertyList;
|
||||
|
|
|
@ -260,18 +260,13 @@ void BulletNifLoader::handleNode(const std::string& fileName, const Nif::Node *n
|
|||
Log(Debug::Info) << "RootCollisionNode is not attached to the root node in " << fileName << ". Treating it as a common NiTriShape.";
|
||||
|
||||
// Check for extra data
|
||||
Nif::Extra const *e = node;
|
||||
while (!e->extra.empty())
|
||||
for (Nif::ExtraPtr e = node->extra; !e.empty(); e = e->next)
|
||||
{
|
||||
// Get the next extra data in the list
|
||||
e = e->extra.getPtr();
|
||||
assert(e != nullptr);
|
||||
|
||||
if (e->recType == Nif::RC_NiStringExtraData)
|
||||
{
|
||||
// String markers may contain important information
|
||||
// affecting the entire subtree of this node
|
||||
Nif::NiStringExtraData *sd = (Nif::NiStringExtraData*)e;
|
||||
Nif::NiStringExtraData *sd = (Nif::NiStringExtraData*)e.getPtr();
|
||||
|
||||
if (Misc::StringUtils::ciCompareLen(sd->string, "NC", 2) == 0)
|
||||
{
|
||||
|
|
|
@ -385,8 +385,9 @@ void AlphaController::apply(osg::StateSet *stateset, osg::NodeVisitor *nv)
|
|||
}
|
||||
}
|
||||
|
||||
MaterialColorController::MaterialColorController(const Nif::NiPosData *data)
|
||||
MaterialColorController::MaterialColorController(const Nif::NiPosData *data, TargetColor color)
|
||||
: mData(data->mKeyList, osg::Vec3f(1,1,1))
|
||||
, mTargetColor(color)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -397,6 +398,7 @@ MaterialColorController::MaterialColorController()
|
|||
MaterialColorController::MaterialColorController(const MaterialColorController ©, const osg::CopyOp ©op)
|
||||
: StateSetUpdater(copy, copyop), Controller(copy)
|
||||
, mData(copy.mData)
|
||||
, mTargetColor(copy.mTargetColor)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -413,9 +415,37 @@ void MaterialColorController::apply(osg::StateSet *stateset, osg::NodeVisitor *n
|
|||
{
|
||||
osg::Vec3f value = mData.interpKey(getInputValue(nv));
|
||||
osg::Material* mat = static_cast<osg::Material*>(stateset->getAttribute(osg::StateAttribute::MATERIAL));
|
||||
switch (mTargetColor)
|
||||
{
|
||||
case Diffuse:
|
||||
{
|
||||
osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK);
|
||||
diffuse.set(value.x(), value.y(), value.z(), diffuse.a());
|
||||
mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse);
|
||||
break;
|
||||
}
|
||||
case Specular:
|
||||
{
|
||||
osg::Vec4f specular = mat->getSpecular(osg::Material::FRONT_AND_BACK);
|
||||
specular.set(value.x(), value.y(), value.z(), specular.a());
|
||||
mat->setSpecular(osg::Material::FRONT_AND_BACK, specular);
|
||||
break;
|
||||
}
|
||||
case Emissive:
|
||||
{
|
||||
osg::Vec4f emissive = mat->getEmission(osg::Material::FRONT_AND_BACK);
|
||||
emissive.set(value.x(), value.y(), value.z(), emissive.a());
|
||||
mat->setEmission(osg::Material::FRONT_AND_BACK, emissive);
|
||||
break;
|
||||
}
|
||||
case Ambient:
|
||||
default:
|
||||
{
|
||||
osg::Vec4f ambient = mat->getAmbient(osg::Material::FRONT_AND_BACK);
|
||||
ambient.set(value.x(), value.y(), value.z(), ambient.a());
|
||||
mat->setAmbient(osg::Material::FRONT_AND_BACK, ambient);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -281,11 +281,15 @@ namespace NifOsg
|
|||
|
||||
class MaterialColorController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller
|
||||
{
|
||||
private:
|
||||
Vec3Interpolator mData;
|
||||
|
||||
public:
|
||||
MaterialColorController(const Nif::NiPosData *data);
|
||||
enum TargetColor
|
||||
{
|
||||
Ambient = 0,
|
||||
Diffuse = 1,
|
||||
Specular = 2,
|
||||
Emissive = 3
|
||||
};
|
||||
MaterialColorController(const Nif::NiPosData *data, TargetColor color);
|
||||
MaterialColorController();
|
||||
MaterialColorController(const MaterialColorController& copy, const osg::CopyOp& copyop);
|
||||
|
||||
|
@ -294,6 +298,10 @@ namespace NifOsg
|
|||
virtual void setDefaults(osg::StateSet* stateset);
|
||||
|
||||
virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv);
|
||||
|
||||
private:
|
||||
Vec3Interpolator mData;
|
||||
TargetColor mTargetColor;
|
||||
};
|
||||
|
||||
class FlipController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller
|
||||
|
|
|
@ -222,9 +222,9 @@ namespace NifOsg
|
|||
|
||||
extractTextKeys(static_cast<const Nif::NiTextKeyExtraData*>(extra.getPtr()), target.mTextKeys);
|
||||
|
||||
extra = extra->extra;
|
||||
extra = extra->next;
|
||||
Nif::ControllerPtr ctrl = seq->controller;
|
||||
for(;!extra.empty() && !ctrl.empty();(extra=extra->extra),(ctrl=ctrl->next))
|
||||
for(;!extra.empty() && !ctrl.empty();(extra=extra->next),(ctrl=ctrl->next))
|
||||
{
|
||||
if(extra->recType != Nif::RC_NiStringExtraData || ctrl->recType != Nif::RC_NiKeyframeController)
|
||||
{
|
||||
|
@ -524,7 +524,7 @@ namespace NifOsg
|
|||
node->getOrCreateUserDataContainer()->addUserObject(
|
||||
new NodeUserData(nifNode->recIndex, nifNode->trafo.scale, nifNode->trafo.rotation));
|
||||
|
||||
for (Nif::ExtraPtr e = nifNode->extra; !e.empty(); e = e->extra)
|
||||
for (Nif::ExtraPtr e = nifNode->extra; !e.empty(); e = e->next)
|
||||
{
|
||||
if(e->recType == Nif::RC_NiTextKeyExtraData && textKeys)
|
||||
{
|
||||
|
@ -750,7 +750,13 @@ namespace NifOsg
|
|||
else if (ctrl->recType == Nif::RC_NiMaterialColorController)
|
||||
{
|
||||
const Nif::NiMaterialColorController* matctrl = static_cast<const Nif::NiMaterialColorController*>(ctrl.getPtr());
|
||||
osg::ref_ptr<MaterialColorController> osgctrl(new MaterialColorController(matctrl->data.getPtr()));
|
||||
// Two bits that correspond to the controlled material color.
|
||||
// 00: Ambient
|
||||
// 01: Diffuse
|
||||
// 10: Specular
|
||||
// 11: Emissive
|
||||
MaterialColorController::TargetColor targetColor = static_cast<MaterialColorController::TargetColor>((matctrl->flags >> 4) & 3);
|
||||
osg::ref_ptr<MaterialColorController> osgctrl(new MaterialColorController(matctrl->data.getPtr(), targetColor));
|
||||
setupController(matctrl, osgctrl, animflags);
|
||||
composite->addController(osgctrl);
|
||||
}
|
||||
|
@ -802,13 +808,13 @@ namespace NifOsg
|
|||
}
|
||||
}
|
||||
|
||||
void handleParticlePrograms(Nif::ExtraPtr affectors, Nif::ExtraPtr colliders, osg::Group *attachTo, osgParticle::ParticleSystem* partsys, osgParticle::ParticleProcessor::ReferenceFrame rf)
|
||||
void handleParticlePrograms(Nif::NiParticleModifierPtr affectors, Nif::NiParticleModifierPtr colliders, osg::Group *attachTo, osgParticle::ParticleSystem* partsys, osgParticle::ParticleProcessor::ReferenceFrame rf)
|
||||
{
|
||||
osgParticle::ModularProgram* program = new osgParticle::ModularProgram;
|
||||
attachTo->addChild(program);
|
||||
program->setParticleSystem(partsys);
|
||||
program->setReferenceFrame(rf);
|
||||
for (; !affectors.empty(); affectors = affectors->extra)
|
||||
for (; !affectors.empty(); affectors = affectors->next)
|
||||
{
|
||||
if (affectors->recType == Nif::RC_NiParticleGrowFade)
|
||||
{
|
||||
|
@ -833,7 +839,7 @@ namespace NifOsg
|
|||
else
|
||||
Log(Debug::Info) << "Unhandled particle modifier " << affectors->recName << " in " << mFilename;
|
||||
}
|
||||
for (; !colliders.empty(); colliders = colliders->extra)
|
||||
for (; !colliders.empty(); colliders = colliders->next)
|
||||
{
|
||||
if (colliders->recType == Nif::RC_NiPlanarCollider)
|
||||
{
|
||||
|
|
|
@ -48,11 +48,6 @@ const vec3 WATER_COLOR = vec3(0.090195, 0.115685, 0.12745);
|
|||
const float RAIN_RIPPLE_GAPS = 5.0;
|
||||
const float RAIN_RIPPLE_RADIUS = 0.1;
|
||||
|
||||
int modulo(int v1, int v2)
|
||||
{
|
||||
return v1 - v2 * int(floor(float(v1) / float(v2)));
|
||||
}
|
||||
|
||||
vec2 randOffset(vec2 c)
|
||||
{
|
||||
return fract(vec2(
|
||||
|
@ -170,8 +165,6 @@ void main(void)
|
|||
vec2 screenCoords = screenCoordsPassthrough.xy / screenCoordsPassthrough.z;
|
||||
screenCoords.y = (1.0-screenCoords.y);
|
||||
|
||||
vec2 nCoord = vec2(0.0);
|
||||
|
||||
#define waterTimer osg_SimulationTime
|
||||
|
||||
vec3 normal0 = 2.0 * texture2D(normalMap,normalCoords(UV, 0.05, 0.04, waterTimer, -0.015, -0.005, vec3(0.0,0.0,0.0))).rgb - 1.0;
|
||||
|
@ -195,100 +188,66 @@ void main(void)
|
|||
vec2 smallWaves = mix(vec2(SMALL_WAVES_X,SMALL_WAVES_Y),vec2(SMALL_WAVES_RAIN_X,SMALL_WAVES_RAIN_Y),rainIntensity);
|
||||
float bump = mix(BUMP,BUMP_RAIN,rainIntensity);
|
||||
|
||||
vec3 normal = (normal0 * bigWaves.x + normal1 * bigWaves.y +
|
||||
normal2 * midWaves.x + normal3 * midWaves.y +
|
||||
normal4 * smallWaves.x + normal5 * smallWaves.y +
|
||||
rippleAdd);
|
||||
|
||||
normal = normalize(vec3(normal.x * bump, normal.y * bump, normal.z));
|
||||
|
||||
normal = vec3(-normal.x, -normal.y, normal.z);
|
||||
|
||||
// normal for sunlight scattering
|
||||
vec3 lNormal = (normal0 * bigWaves.x * 0.5 + normal1 * bigWaves.y * 0.5 +
|
||||
normal2 * midWaves.x * 0.2 + normal3 * midWaves.y * 0.2 +
|
||||
normal4 * smallWaves.x * 0.1 + normal5 * smallWaves.y * 0.1 +
|
||||
rippleAdd).xyz;
|
||||
|
||||
lNormal = normalize(vec3(lNormal.x * bump, lNormal.y * bump, lNormal.z));
|
||||
lNormal = vec3(-lNormal.x, -lNormal.y, lNormal.z);
|
||||
vec3 normal = (normal0 * bigWaves.x + normal1 * bigWaves.y + normal2 * midWaves.x +
|
||||
normal3 * midWaves.y + normal4 * smallWaves.x + normal5 * smallWaves.y + rippleAdd);
|
||||
normal = normalize(vec3(-normal.x * bump, -normal.y * bump, normal.z));
|
||||
|
||||
vec3 lVec = normalize((gl_ModelViewMatrixInverse * vec4(gl_LightSource[0].position.xyz, 0.0)).xyz);
|
||||
|
||||
vec3 cameraPos = (gl_ModelViewMatrixInverse * vec4(0,0,0,1)).xyz;
|
||||
vec3 vVec = normalize(position.xyz - cameraPos.xyz);
|
||||
|
||||
float isUnderwater = (cameraPos.z > 0.0) ? 0.0 : 1.0;
|
||||
|
||||
// sunlight scattering
|
||||
vec3 pNormal = vec3(0,0,1);
|
||||
vec3 lR = reflect(lVec, lNormal);
|
||||
vec3 llR = reflect(lVec, pNormal);
|
||||
|
||||
float sunHeight = lVec.z;
|
||||
float sunFade = length(gl_LightModel.ambient.xyz);
|
||||
|
||||
float s = clamp(dot(lR, vVec)*2.0-1.2, 0.0, 1.0);
|
||||
float lightScatter = shadow * clamp(dot(lVec,lNormal)*0.7+0.3, 0.0, 1.0) * s * SCATTER_AMOUNT * sunFade * clamp(1.0-exp(-sunHeight), 0.0, 1.0);
|
||||
vec3 scatterColour = mix(vec3(SCATTER_COLOUR)*vec3(1.0,0.4,0.0), SCATTER_COLOUR, clamp(1.0-exp(-sunHeight*SUN_EXT), 0.0, 1.0));
|
||||
|
||||
// fresnel
|
||||
float ior = (cameraPos.z>0.0)?(1.333/1.0):(1.0/1.333); // air to water; water to air
|
||||
float fresnel = fresnel_dielectric(vVec, normal, ior);
|
||||
|
||||
fresnel = clamp(fresnel, 0.0, 1.0);
|
||||
float fresnel = clamp(fresnel_dielectric(vVec, normal, ior), 0.0, 1.0);
|
||||
|
||||
vec2 screenCoordsOffset = normal.xy * REFL_BUMP;
|
||||
#if REFRACTION
|
||||
float depthSample = linearizeDepth(texture2D(refractionDepthMap,screenCoords).x);
|
||||
float depthSampleDistorted = linearizeDepth(texture2D(refractionDepthMap,screenCoords-(normal.xy*REFR_BUMP)).x);
|
||||
float depthSampleDistorted = linearizeDepth(texture2D(refractionDepthMap,screenCoords-screenCoordsOffset).x);
|
||||
float surfaceDepth = linearizeDepth(gl_FragCoord.z);
|
||||
float realWaterDepth = depthSample - surfaceDepth; // undistorted water depth in view direction, independent of frustum
|
||||
float shore = clamp(realWaterDepth / BUMP_SUPPRESS_DEPTH,0,1);
|
||||
#else
|
||||
float shore = 1.0;
|
||||
screenCoordsOffset *= clamp(realWaterDepth / BUMP_SUPPRESS_DEPTH,0,1);
|
||||
#endif
|
||||
vec2 screenCoordsOffset = normal.xy * REFL_BUMP * shore;
|
||||
|
||||
// reflection
|
||||
vec3 reflection = texture2D(reflectionMap, screenCoords + screenCoordsOffset).rgb;
|
||||
|
||||
// refraction
|
||||
// specular
|
||||
float specular = pow(max(dot(reflect(vVec, normal), lVec), 0.0),SPEC_HARDNESS) * shadow;
|
||||
|
||||
vec3 waterColor = WATER_COLOR * sunFade;
|
||||
|
||||
#if REFRACTION
|
||||
// refraction
|
||||
vec3 refraction = texture2D(refractionMap, screenCoords - screenCoordsOffset).rgb;
|
||||
|
||||
// brighten up the refraction underwater
|
||||
refraction = (cameraPos.z < 0.0) ? clamp(refraction * 1.5, 0.0, 1.0) : refraction;
|
||||
#endif
|
||||
// specular
|
||||
vec3 R = reflect(vVec, normal);
|
||||
float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS) * shadow;
|
||||
|
||||
vec3 waterColor = WATER_COLOR;
|
||||
waterColor = waterColor * length(gl_LightModel.ambient.xyz);
|
||||
|
||||
#if REFRACTION
|
||||
if (cameraPos.z > 0.0)
|
||||
if (cameraPos.z < 0.0)
|
||||
refraction = clamp(refraction * 1.5, 0.0, 1.0);
|
||||
else
|
||||
refraction = mix(refraction, waterColor, clamp(depthSampleDistorted/VISIBILITY, 0.0, 1.0));
|
||||
|
||||
gl_FragData[0].xyz = mix( mix(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * gl_LightSource[0].specular.xyz;
|
||||
// sunlight scattering
|
||||
// normal for sunlight scattering
|
||||
vec3 lNormal = (normal0 * bigWaves.x * 0.5 + normal1 * bigWaves.y * 0.5 + normal2 * midWaves.x * 0.2 +
|
||||
normal3 * midWaves.y * 0.2 + normal4 * smallWaves.x * 0.1 + normal5 * smallWaves.y * 0.1 + rippleAdd);
|
||||
lNormal = normalize(vec3(-lNormal.x * bump, -lNormal.y * bump, lNormal.z));
|
||||
float sunHeight = lVec.z;
|
||||
vec3 scatterColour = mix(SCATTER_COLOUR*vec3(1.0,0.4,0.0), SCATTER_COLOUR, clamp(1.0-exp(-sunHeight*SUN_EXT), 0.0, 1.0));
|
||||
vec3 lR = reflect(lVec, lNormal);
|
||||
float lightScatter = shadow * clamp(dot(lVec,lNormal)*0.7+0.3, 0.0, 1.0) * clamp(dot(lR, vVec)*2.0-1.2, 0.0, 1.0) * SCATTER_AMOUNT * sunFade * clamp(1.0-exp(-sunHeight), 0.0, 1.0);
|
||||
gl_FragData[0].xyz = mix( mix(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * gl_LightSource[0].specular.xyz + vec3(rainRipple.w) * 0.2;
|
||||
gl_FragData[0].w = 1.0;
|
||||
#else
|
||||
gl_FragData[0].xyz = mix(reflection, waterColor, (1.0-fresnel)*0.5) + specular * gl_LightSource[0].specular.xyz;
|
||||
gl_FragData[0].xyz = mix(reflection, waterColor, (1.0-fresnel)*0.5) + specular * gl_LightSource[0].specular.xyz + vec3(rainRipple.w) * 0.7;
|
||||
gl_FragData[0].w = clamp(fresnel*6.0 + specular * gl_LightSource[0].specular.w, 0.0, 1.0); //clamp(fresnel*2.0 + specular * gl_LightSource[0].specular.w, 0.0, 1.0);
|
||||
#endif
|
||||
|
||||
// fog
|
||||
float fogValue = clamp((depthPassthrough - gl_Fog.start) * gl_Fog.scale, 0.0, 1.0);
|
||||
gl_FragData[0].xyz = mix(gl_FragData[0].xyz, gl_Fog.color.xyz, fogValue);
|
||||
|
||||
#if REFRACTION
|
||||
gl_FragData[0].xyz += vec3(rainRipple.w) * 0.2;
|
||||
#else
|
||||
gl_FragData[0].xyz += vec3(rainRipple.w) * 0.7;
|
||||
#endif
|
||||
|
||||
#if REFRACTION
|
||||
gl_FragData[0].w = 1.0;
|
||||
#else
|
||||
gl_FragData[0].w = clamp(fresnel*6.0 + specular * gl_LightSource[0].specular.w, 0.0, 1.0); //clamp(fresnel*2.0 + specular * gl_LightSource[0].specular.w, 0.0, 1.0);
|
||||
#endif
|
||||
|
||||
applyShadowDebugOverlay();
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ void main(void)
|
|||
0.5, 0.5, 0.5, 1.0);
|
||||
|
||||
vec4 texcoordProj = ((scalemat) * ( gl_Position));
|
||||
screenCoordsPassthrough = vec3(texcoordProj.x, texcoordProj.y, texcoordProj.w);
|
||||
screenCoordsPassthrough = texcoordProj.xyw;
|
||||
|
||||
position = gl_Vertex;
|
||||
|
||||
|
|
Loading…
Reference in a new issue