1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-04-13 11:06:43 +00:00

Merge branch 'master' into wnamfix

This commit is contained in:
unelsson 2019-10-07 01:40:23 +03:00 committed by GitHub
commit 3deebf0247
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
108 changed files with 1733 additions and 722 deletions

View file

@ -4,11 +4,13 @@
Bug #1515: Opening console masks dialogue, inventory menu Bug #1515: Opening console masks dialogue, inventory menu
Bug #2395: Duplicated plugins in the launcher when multiple data directories provide the same plugin Bug #2395: Duplicated plugins in the launcher when multiple data directories provide the same plugin
Bug #2969: Scripted items can stack Bug #2969: Scripted items can stack
Bug #2976: Data lines in global openmw.cfg take priority over user openmw.cfg
Bug #2987: Editor: some chance and AI data fields can overflow Bug #2987: Editor: some chance and AI data fields can overflow
Bug #3006: 'else if' operator breaks script compilation Bug #3006: 'else if' operator breaks script compilation
Bug #3109: SetPos/Position handles actors differently Bug #3109: SetPos/Position handles actors differently
Bug #3282: Unintended behaviour when assigning F3 and Windows keys Bug #3282: Unintended behaviour when assigning F3 and Windows keys
Bug #3550: Companion from mod attacks the air after combat has ended 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 #3623: Display scaling breaks mouse recognition
Bug #3725: Using script function in a non-conditional expression breaks script compilation Bug #3725: Using script function in a non-conditional expression breaks script compilation
Bug #3733: Normal maps are inverted on mirrored UVs Bug #3733: Normal maps are inverted on mirrored UVs
@ -25,6 +27,7 @@
Bug #4383: Bow model obscures crosshair when arrow is drawn Bug #4383: Bow model obscures crosshair when arrow is drawn
Bug #4384: Resist Normal Weapons only checks ammunition for ranged weapons Bug #4384: Resist Normal Weapons only checks ammunition for ranged weapons
Bug #4411: Reloading a saved game while falling prevents damage in some cases Bug #4411: Reloading a saved game while falling prevents damage in some cases
Bug #4456: AiActivate should not be cancelled after target activation
Bug #4540: Rain delay when exiting water Bug #4540: Rain delay when exiting water
Bug #4600: Crash when no sound output is available or --no-sound is used. Bug #4600: Crash when no sound output is available or --no-sound is used.
Bug #4639: Black screen after completing first mages guild mission + training Bug #4639: Black screen after completing first mages guild mission + training
@ -113,6 +116,7 @@
Bug #5050: Invalid spell effects are not handled gracefully Bug #5050: Invalid spell effects are not handled gracefully
Bug #5055: Mark, Recall, Intervention magic effect abilities have no effect when added and removed in the same frame Bug #5055: Mark, Recall, Intervention magic effect abilities have no effect when added and removed in the same frame
Bug #5056: Calling Cast function on player doesn't equip the spell but casts it Bug #5056: Calling Cast function on player doesn't equip the spell but casts it
Bug #5059: Modded animation with combined attack keys always does max damage and can double damage
Bug #5060: Magic effect visuals stop when death animation begins instead of when it ends Bug #5060: Magic effect visuals stop when death animation begins instead of when it ends
Bug #5063: Shape named "Tri Shadow" in creature mesh is visible if it isn't hidden Bug #5063: Shape named "Tri Shadow" in creature mesh is visible if it isn't hidden
Bug #5067: Ranged attacks on unaware opponents ("critical hits") differ from the vanilla engine Bug #5067: Ranged attacks on unaware opponents ("critical hits") differ from the vanilla engine
@ -121,6 +125,7 @@
Bug #5075: Enchanting cast style can be changed if there's no object Bug #5075: Enchanting cast style can be changed if there's no object
Bug #5078: DisablePlayerLooking is broken Bug #5078: DisablePlayerLooking is broken
Bug #5082: Scrolling with controller in GUI mode is broken Bug #5082: Scrolling with controller in GUI mode is broken
Bug #5087: Some valid script names can't be used as string arguments
Bug #5089: Swimming/Underwater creatures only swim around ground level Bug #5089: Swimming/Underwater creatures only swim around ground level
Bug #5092: NPCs with enchanted weapons play sound when out of charges Bug #5092: NPCs with enchanted weapons play sound when out of charges
Bug #5093: Hand to hand sound plays on knocked out enemies Bug #5093: Hand to hand sound plays on knocked out enemies
@ -136,14 +141,26 @@
Bug #5124: Arrow remains attached to actor if pulling animation was cancelled Bug #5124: Arrow remains attached to actor if pulling animation was cancelled
Bug #5126: Swimming creatures without RunForward animations are motionless during combat Bug #5126: Swimming creatures without RunForward animations are motionless during combat
Bug #5134: Doors rotation by "Lock" console command is inconsistent Bug #5134: Doors rotation by "Lock" console command is inconsistent
Bug #5136: LegionUniform script: can not access local variables
Bug #5137: Textures with Clamp Mode set to Clamp instead of Wrap are too dark outside the boundaries 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 #5149: Failing lock pick attempts isn't always a crime
Bug #5155: Lock/unlock behavior differs from vanilla
Bug #5158: Objects without a name don't fallback to their ID
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 #5166: Scripts still should be executed after player's death
Bug #5167: Player can select and cast spells before magic menu is enabled
Bug #5168: Force1stPerson and Force3rdPerson commands are not really force view change
Bug #5169: Nested levelled items/creatures have significantly higher chance not to spawn
Bug #5175: Random script function returns an integer value
Bug #5177: Editor: Unexplored map tiles get corrupted after a file with terrain is saved Bug #5177: Editor: Unexplored map tiles get corrupted after a file with terrain is saved
Feature #1774: Handle AvoidNode Feature #1774: Handle AvoidNode
Feature #2229: Improve pathfinding AI Feature #2229: Improve pathfinding AI
Feature #3025: Analogue gamepad movement controls Feature #3025: Analogue gamepad movement controls
Feature #3442: Default values for fallbacks from ini file Feature #3442: Default values for fallbacks from ini file
Feature #3610: Option to invert X axis Feature #3610: Option to invert X axis
Feature #3871: Editor: Terrain Selection
Feature #3893: Implicit target for "set" function in console Feature #3893: Implicit target for "set" function in console
Feature #3980: In-game option to disable controller Feature #3980: In-game option to disable controller
Feature #3999: Shift + Double Click should maximize/restore menu size Feature #3999: Shift + Double Click should maximize/restore menu size

View file

@ -329,6 +329,7 @@ bool Launcher::MainDialog::setupGameSettings()
stream.setCodec(QTextCodec::codecForName("UTF-8")); stream.setCodec(QTextCodec::codecForName("UTF-8"));
mGameSettings.readUserFile(stream); mGameSettings.readUserFile(stream);
file.close();
} }
// Now the rest - priority: user > local > global // Now the rest - priority: user > local > global
@ -353,8 +354,8 @@ bool Launcher::MainDialog::setupGameSettings()
stream.setCodec(QTextCodec::codecForName("UTF-8")); stream.setCodec(QTextCodec::codecForName("UTF-8"));
mGameSettings.readFile(stream); mGameSettings.readFile(stream);
file.close();
} }
file.close();
} }
return true; return true;

View file

@ -89,7 +89,7 @@ opencs_units (view/render
scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget
previewwidget editmode instancemode instanceselectionmode instancemovemode previewwidget editmode instancemode instanceselectionmode instancemovemode
orbitcameramode pathgridmode selectionmode pathgridselectionmode cameracontroller orbitcameramode pathgridmode selectionmode pathgridselectionmode cameracontroller
cellwater terraintexturemode actor cellwater terraintexturemode actor terrainselection
) )
opencs_units_noqt (view/render opencs_units_noqt (view/render

View file

@ -8,13 +8,6 @@
#include <components/esm/loadland.hpp> #include <components/esm/loadland.hpp>
#include <components/misc/constants.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() : mX (0), mY (0) {}
CSMWorld::CellCoordinates::CellCoordinates (int x, int y) : mX (x), mY (y) {} 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)); 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 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() * landTextureSize / cellSize + 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 x = static_cast<int>(std::floor(xd));
const auto y = static_cast<int>(std::floor(yd)); 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); 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 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() * (landSize - 1) / cellSize + 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 x = static_cast<int>(std::floor(xd));
const auto y = static_cast<int>(std::floor(yd)); 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); 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 x = std::floor(static_cast<float>(textureGlobal.first) / ESM::Land::LAND_TEXTURE_SIZE);
int y = std::floor(static_cast<float>(vertexGlobal.second) / (landSize - 1)); 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); return generateId(x, y);
} }

View file

@ -49,22 +49,25 @@ namespace CSMWorld
static std::pair<int, int> coordinatesToCellIndex (float x, float y); static std::pair<int, int> coordinatesToCellIndex (float x, float y);
///Converts worldspace coordinates to global texture selection, taking in account the texture offset. ///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. ///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. ///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 ///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 ///Converts global vertex coordinate to local cell's heightmap coordinates
static int vertexSelectionToInCellCoords(int); 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 ///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); bool operator== (const CellCoordinates& left, const CellCoordinates& right);

View file

@ -140,7 +140,7 @@ void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons (
new EditMode (this, QIcon (":placeholder"), Mask_Reference, "Terrain shape editing"), new EditMode (this, QIcon (":placeholder"), Mask_Reference, "Terrain shape editing"),
"terrain-shape"); "terrain-shape");
tool->addButton ( tool->addButton (
new TerrainTextureMode (this, tool), new TerrainTextureMode (this, mRootNode, tool),
"terrain-texture"); "terrain-texture");
tool->addButton ( tool->addButton (
new EditMode (this, QIcon (":placeholder"), Mask_Reference, "Terrain vertex paint editing"), new EditMode (this, QIcon (":placeholder"), Mask_Reference, "Terrain vertex paint editing"),

View 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];
}

View 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

View file

@ -10,6 +10,8 @@
#include <QDragEnterEvent> #include <QDragEnterEvent>
#include <QDrag> #include <QDrag>
#include <osg/Group>
#include <components/esm/loadland.hpp> #include <components/esm/loadland.hpp>
#include "../widget/modebutton.hpp" #include "../widget/modebutton.hpp"
@ -36,12 +38,15 @@
#include "object.hpp" // Something small needed regarding pointers from here () #include "object.hpp" // Something small needed regarding pointers from here ()
#include "worldspacewidget.hpp" #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), : EditMode (worldspaceWidget, QIcon {":scenetoolbar/editing-terrain-texture"}, Mask_Terrain | Mask_Reference, "Terrain texture editing", parent),
mBrushTexture("L0#0"), mBrushTexture("L0#0"),
mBrushSize(0), mBrushSize(0),
mBrushShape(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))); connect(this, SIGNAL(passBrushTexture(std::string)), mTextureBrushScenetool, SLOT(updateBrushHistory(std::string)));
} }
if (!mTerrainTextureSelection)
{
mTerrainTextureSelection.reset(new TerrainSelection(mParentNode, &getWorldspaceWidget(), TerrainSelectionType::Texture));
}
EditMode::activate(toolbar); EditMode::activate(toolbar);
toolbar->addTool (mTextureBrushScenetool); toolbar->addTool (mTextureBrushScenetool);
} }
@ -74,6 +84,12 @@ void CSVRender::TerrainTextureMode::deactivate(CSVWidget::SceneToolbar* toolbar)
delete mTextureBrushScenetool; delete mTextureBrushScenetool;
mTextureBrushScenetool = 0; mTextureBrushScenetool = 0;
} }
if (mTerrainTextureSelection)
{
mTerrainTextureSelection.reset();
}
EditMode::deactivate(toolbar); EditMode::deactivate(toolbar);
} }
@ -95,10 +111,10 @@ void CSVRender::TerrainTextureMode::primaryEditPressed(const WorldspaceHitResult
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = document.getData().getLandTextures(); CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = document.getData().getLandTextures();
int index = landtexturesCollection.searchId(mBrushTexture); 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"); undoStack.beginMacro ("Edit texture records");
if(allowLandTextureEditing(mCellId)==true) if(allowLandTextureEditing(mCellId))
{ {
undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, mCellId)); undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, mCellId));
editTerrainTextureGrid(hit); editTerrainTextureGrid(hit);
@ -109,10 +125,18 @@ void CSVRender::TerrainTextureMode::primaryEditPressed(const WorldspaceHitResult
void CSVRender::TerrainTextureMode::primarySelectPressed(const WorldspaceHitResult& hit) 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) 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) bool CSVRender::TerrainTextureMode::primaryEditStartDrag (const QPoint& pos)
@ -129,13 +153,16 @@ bool CSVRender::TerrainTextureMode::primaryEditStartDrag (const QPoint& pos)
QUndoStack& undoStack = document.getUndoStack(); QUndoStack& undoStack = document.getUndoStack();
mDragMode = InteractionType_PrimaryEdit;
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = document.getData().getLandTextures(); CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = document.getData().getLandTextures();
int index = landtexturesCollection.searchId(mBrushTexture); 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"); 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)); undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, mCellId));
editTerrainTextureGrid(hit); editTerrainTextureGrid(hit);
@ -152,47 +179,88 @@ bool CSVRender::TerrainTextureMode::secondaryEditStartDrag (const QPoint& pos)
bool CSVRender::TerrainTextureMode::primarySelectStartDrag (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; return false;
} }
bool CSVRender::TerrainTextureMode::secondarySelectStartDrag (const QPoint& pos) 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; return false;
} }
void CSVRender::TerrainTextureMode::drag (const QPoint& pos, int diffX, int diffY, double speedFactor) void CSVRender::TerrainTextureMode::drag (const QPoint& pos, int diffX, int diffY, double speedFactor)
{ {
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask()); if (mDragMode == InteractionType_PrimaryEdit)
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)
{ {
editTerrainTextureGrid(hit); 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 && 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)
CSMDoc::Document& document = getWorldspaceWidget().getDocument(); {
QUndoStack& undoStack = document.getUndoStack(); if (mDragMode == InteractionType_PrimaryEdit && mIsEditing)
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = document.getData().getLandTextures();
int index = landtexturesCollection.searchId(mBrushTexture);
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted())
{ {
undoStack.endMacro(); CSMDoc::Document& document = getWorldspaceWidget().getDocument();
QUndoStack& undoStack = document.getUndoStack();
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = document.getData().getLandTextures();
int index = landtexturesCollection.searchId(mBrushTexture);
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()); 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 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)); *document.getData().getTableModel (CSMWorld::UniversalId::Type_Land));
mCellId = getWorldspaceWidget().getCellId (hit.worldPos); mCellId = getWorldspaceWidget().getCellId (hit.worldPos);
if(allowLandTextureEditing(mCellId)==true) {} if(allowLandTextureEditing(mCellId)) {}
std::pair<CSMWorld::CellCoordinates, bool> cellCoordinates_pair = CSMWorld::CellCoordinates::fromId (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(); int cellY = cellCoordinates_pair.first.getY();
// The coordinates of hit in mCellId // The coordinates of hit in mCellId
int xHitInCell (float(((hit.worldPos.x() - (cellX* 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.5)); int yHitInCell (float(((hit.worldPos.y() - (cellY* cellSize)) * landTextureSize / cellSize) + 0.25));
if (xHitInCell < 0) if (xHitInCell < 0)
{ {
xHitInCell = xHitInCell + landTextureSize; xHitInCell = xHitInCell + landTextureSize;
@ -249,8 +317,8 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe
cellY = cellY + 1; cellY = cellY + 1;
} }
mCellId = "#" + std::to_string(cellX) + " " + std::to_string(cellY); mCellId = CSMWorld::CellCoordinates::generateId(cellX, cellY);
if(allowLandTextureEditing(mCellId)==true) {} if(allowLandTextureEditing(mCellId)) {}
std::string iteratedCellId; std::string iteratedCellId;
@ -266,13 +334,13 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe
if (mBrushShape == 0) if (mBrushShape == 0)
{ {
CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(mCellId, textureColumn)).value<CSMWorld::LandTexturesColumn::DataType>(); CSMWorld::LandTexturesColumn::DataType newTerrainPointer = landTable.data(landTable.getModelIndex(mCellId, textureColumn)).value<CSMWorld::LandTexturesColumn::DataType>();
CSMWorld::LandTexturesColumn::DataType mNew(mPointer); CSMWorld::LandTexturesColumn::DataType newTerrain(newTerrainPointer);
if(allowLandTextureEditing(mCellId)==true) if(allowLandTextureEditing(mCellId))
{ {
mNew[yHitInCell*landTextureSize+xHitInCell] = brushInt; newTerrain[yHitInCell*landTextureSize+xHitInCell] = brushInt;
pushEditToCommand(mNew, document, landTable, mCellId); pushEditToCommand(newTerrain, document, landTable, mCellId);
} }
} }
@ -292,19 +360,19 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe
{ {
for(int j_cell = upperLeftCellY; j_cell <= lowerrightCellY; j_cell++) for(int j_cell = upperLeftCellY; j_cell <= lowerrightCellY; j_cell++)
{ {
iteratedCellId = "#" + std::to_string(i_cell) + " " + std::to_string(j_cell); iteratedCellId = CSMWorld::CellCoordinates::generateId(i_cell, j_cell);
if(allowLandTextureEditing(iteratedCellId)==true) if(allowLandTextureEditing(iteratedCellId))
{ {
CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(iteratedCellId, textureColumn)).value<CSMWorld::LandTexturesColumn::DataType>(); CSMWorld::LandTexturesColumn::DataType newTerrainPointer = landTable.data(landTable.getModelIndex(iteratedCellId, textureColumn)).value<CSMWorld::LandTexturesColumn::DataType>();
CSMWorld::LandTexturesColumn::DataType mNew(mPointer); CSMWorld::LandTexturesColumn::DataType newTerrain(newTerrainPointer);
for(int i = 0; i < landTextureSize; i++) for(int i = 0; i < landTextureSize; i++)
{ {
for(int j = 0; j < landTextureSize; j++) for(int j = 0; j < landTextureSize; j++)
{ {
if (i_cell == cellX && j_cell == cellY && abs(i-xHitInCell) < r && abs(j-yHitInCell) < r) 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 else
{ {
@ -316,11 +384,11 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe
if (j_cell > cellY) distanceY = -yHitInCell + landTextureSize * abs(j_cell-cellY) + j; if (j_cell > cellY) distanceY = -yHitInCell + landTextureSize * abs(j_cell-cellY) + j;
if (i_cell == cellX) distanceX = abs(i-xHitInCell); if (i_cell == cellX) distanceX = abs(i-xHitInCell);
if (j_cell == cellY) distanceY = abs(j-yHitInCell); 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++) for(int j_cell = upperLeftCellY; j_cell <= lowerrightCellY; j_cell++)
{ {
iteratedCellId = "#" + std::to_string(i_cell) + " " + std::to_string(j_cell); iteratedCellId = CSMWorld::CellCoordinates::generateId(i_cell, j_cell);
if(allowLandTextureEditing(iteratedCellId)==true) if(allowLandTextureEditing(iteratedCellId))
{ {
CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(iteratedCellId, textureColumn)).value<CSMWorld::LandTexturesColumn::DataType>(); CSMWorld::LandTexturesColumn::DataType newTerrainPointer = landTable.data(landTable.getModelIndex(iteratedCellId, textureColumn)).value<CSMWorld::LandTexturesColumn::DataType>();
CSMWorld::LandTexturesColumn::DataType mNew(mPointer); CSMWorld::LandTexturesColumn::DataType newTerrain(newTerrainPointer);
for(int i = 0; i < landTextureSize; i++) for(int i = 0; i < landTextureSize; i++)
{ {
for(int j = 0; j < landTextureSize; j++) 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 (i_cell == cellX) distanceX = abs(i-xHitInCell);
if (j_cell == cellY) distanceY = abs(j-yHitInCell); if (j_cell == cellY) distanceY = abs(j-yHitInCell);
distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2))); 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 else
{ {
@ -376,11 +444,11 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe
if (i_cell == cellX) distanceX = abs(i-xHitInCell); if (i_cell == cellX) distanceX = abs(i-xHitInCell);
if (j_cell == cellY) distanceY = abs(j-yHitInCell); if (j_cell == cellY) distanceY = abs(j-yHitInCell);
distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2))); 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) 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, 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))); QModelIndex index(landTable.getModelIndex (cellId, landTable.findColumnIndex (CSMWorld::Columns::ColumnId_LandTexturesIndex)));
QUndoStack& undoStack = document.getUndoStack(); QUndoStack& undoStack = document.getUndoStack();
undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, cellId));
undoStack.push (new CSMWorld::ModifyCommand(landTable, index, changedLand)); undoStack.push (new CSMWorld::ModifyCommand(landTable, index, changedLand));
undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, cellId));
} }
void CSVRender::TerrainTextureMode::createTexture(std::string textureFileName) void CSVRender::TerrainTextureMode::createTexture(std::string textureFileName)
@ -422,13 +596,15 @@ void CSVRender::TerrainTextureMode::createTexture(std::string textureFileName)
int counter=0; int counter=0;
bool freeIndexFound = false; bool freeIndexFound = false;
do { do
{
const size_t maxCounter = std::numeric_limits<uint16_t>::max() - 1; const size_t maxCounter = std::numeric_limits<uint16_t>::max() - 1;
try try
{ {
newId = CSMWorld::LandTexture::createUniqueRecordId(0, counter); newId = CSMWorld::LandTexture::createUniqueRecordId(0, counter);
if (ltexTable.getRecord(newId).isDeleted() == 0) counter = (counter + 1) % maxCounter; 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); newId = CSMWorld::LandTexture::createUniqueRecordId(0, counter);
freeIndexFound = true; freeIndexFound = true;
@ -527,7 +703,8 @@ bool CSVRender::TerrainTextureMode::allowLandTextureEditing(std::string cellId)
return true; return true;
} }
void CSVRender::TerrainTextureMode::dragMoveEvent (QDragMoveEvent *event) { void CSVRender::TerrainTextureMode::dragMoveEvent (QDragMoveEvent *event)
{
} }
void CSVRender::TerrainTextureMode::setBrushSize(int brushSize) void CSVRender::TerrainTextureMode::setBrushSize(int brushSize)
@ -538,6 +715,28 @@ void CSVRender::TerrainTextureMode::setBrushSize(int brushSize)
void CSVRender::TerrainTextureMode::setBrushShape(int brushShape) void CSVRender::TerrainTextureMode::setBrushShape(int brushShape)
{ {
mBrushShape = 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) void CSVRender::TerrainTextureMode::setBrushTexture(std::string brushTexture)

View file

@ -4,6 +4,7 @@
#include "editmode.hpp" #include "editmode.hpp"
#include <string> #include <string>
#include <memory>
#include <QWidget> #include <QWidget>
#include <QEvent> #include <QEvent>
@ -18,6 +19,13 @@
#include "../../model/world/landtexture.hpp" #include "../../model/world/landtexture.hpp"
#endif #endif
#include "terrainselection.hpp"
namespace osg
{
class Group;
}
namespace CSVWidget namespace CSVWidget
{ {
class SceneToolTextureBrush; class SceneToolTextureBrush;
@ -25,15 +33,23 @@ namespace CSVWidget
namespace CSVRender namespace CSVRender
{ {
class TerrainTextureMode : public EditMode class TerrainTextureMode : public EditMode
{ {
Q_OBJECT Q_OBJECT
public: public:
enum InteractionType
{
InteractionType_PrimaryEdit,
InteractionType_PrimarySelect,
InteractionType_SecondaryEdit,
InteractionType_SecondarySelect,
InteractionType_None
};
/// \brief Editmode for terrain texture grid /// \brief Editmode for terrain texture grid
TerrainTextureMode(WorldspaceWidget*, QWidget* parent = nullptr); TerrainTextureMode(WorldspaceWidget*, osg::Group* parentNode, QWidget* parent = nullptr);
void primaryOpenPressed (const WorldspaceHitResult& hit); void primaryOpenPressed (const WorldspaceHitResult& hit);
@ -68,6 +84,12 @@ namespace CSVRender
/// \brief Handle brush mechanics, maths regarding worldspace hit etc. /// \brief Handle brush mechanics, maths regarding worldspace hit etc.
void editTerrainTextureGrid (const WorldspaceHitResult& hit); 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 /// \brief Push texture edits to command macro
void pushEditToCommand (CSMWorld::LandTexturesColumn::DataType& newLandGrid, CSMDoc::Document& document, void pushEditToCommand (CSMWorld::LandTexturesColumn::DataType& newLandGrid, CSMDoc::Document& document,
CSMWorld::IdTable& landTable, std::string cellId); CSMWorld::IdTable& landTable, std::string cellId);
@ -83,7 +105,12 @@ namespace CSVRender
std::string mBrushTexture; std::string mBrushTexture;
int mBrushSize; int mBrushSize;
int mBrushShape; int mBrushShape;
std::vector<std::pair<int, int>> mCustomBrushShape;
CSVWidget::SceneToolTextureBrush *mTextureBrushScenetool; CSVWidget::SceneToolTextureBrush *mTextureBrushScenetool;
int mDragMode;
osg::Group* mParentNode;
bool mIsEditing;
std::unique_ptr<TerrainSelection> mTerrainTextureSelection;
const int cellSize {ESM::Land::REAL_SIZE}; const int cellSize {ESM::Land::REAL_SIZE};
const int landSize {ESM::Land::LAND_SIZE}; const int landSize {ESM::Land::LAND_SIZE};

View file

@ -112,8 +112,8 @@ bool OMW::Engine::frame(float frametime)
bool guiActive = mEnvironment.getWindowManager()->isGuiMode(); bool guiActive = mEnvironment.getWindowManager()->isGuiMode();
osg::Timer_t beforeScriptTick = osg::Timer::instance()->tick(); osg::Timer_t beforeScriptTick = osg::Timer::instance()->tick();
if (mEnvironment.getStateManager()->getState()== if (mEnvironment.getStateManager()->getState()!=
MWBase::StateManager::State_Running) MWBase::StateManager::State_NoGame)
{ {
if (!paused) if (!paused)
{ {

View file

@ -130,8 +130,8 @@ namespace MWBase
* If this parameter is false, it will be determined by a line-of-sight and awareness check. * If this parameter is false, it will be determined by a line-of-sight and awareness check.
* @return was the crime seen? * @return was the crime seen?
*/ */
virtual bool commitCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, virtual bool commitCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, OffenseType type,
OffenseType type, int arg=0, bool victimAware=false) = 0; const std::string& factionId="", int arg=0, bool victimAware=false) = 0;
/// @return false if the attack was considered a "friendly hit" and forgiven /// @return false if the attack was considered a "friendly hit" and forgiven
virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0; virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0;
@ -225,7 +225,7 @@ namespace MWBase
virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target) = 0; virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target) = 0;
/// Resurrects the player if necessary /// Resurrects the player if necessary
virtual void keepPlayerAlive() = 0; virtual void resurrect(const MWWorld::Ptr& ptr) = 0;
virtual bool isCastingSpell (const MWWorld::Ptr& ptr) const = 0; virtual bool isCastingSpell (const MWWorld::Ptr& ptr) const = 0;
virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const = 0; virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const = 0;

View file

@ -403,7 +403,7 @@ namespace MWBase
virtual osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const = 0; virtual osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const = 0;
virtual void togglePOV() = 0; virtual void togglePOV(bool force = false) = 0;
virtual bool isFirstPerson() const = 0; virtual bool isFirstPerson() const = 0;
virtual void togglePreviewMode(bool enable) = 0; virtual void togglePreviewMode(bool enable) = 0;
virtual bool toggleVanityMode(bool enable) = 0; virtual bool toggleVanityMode(bool enable) = 0;

View file

@ -89,9 +89,7 @@ namespace MWClass
bool Activator::hasToolTip (const MWWorld::ConstPtr& ptr) const bool Activator::hasToolTip (const MWWorld::ConstPtr& ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Activator> *ref = ptr.get<ESM::Activator>(); return !getName(ptr).empty();
return (ref->mBase->mName != "");
} }
bool Activator::allowTelekinesis(const MWWorld::ConstPtr &ptr) const { bool Activator::allowTelekinesis(const MWWorld::ConstPtr &ptr) const {
@ -103,7 +101,7 @@ namespace MWClass
const MWWorld::LiveCellRef<ESM::Activator> *ref = ptr.get<ESM::Activator>(); const MWWorld::LiveCellRef<ESM::Activator> *ref = ptr.get<ESM::Activator>();
MWGui::ToolTipInfo info; 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; std::string text;
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) if (MWBase::Environment::get().getWindowManager()->getFullHelp())

View file

@ -20,11 +20,10 @@ namespace MWClass
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
virtual std::string getName (const MWWorld::ConstPtr& ptr) 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); ///< \return name or ID; can return an empty string.
/// can return an empty string.
virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; 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; virtual bool allowTelekinesis(const MWWorld::ConstPtr& ptr) const;
///< Return whether this class of object can be activated with telekinesis ///< Return whether this class of object can be activated with telekinesis

View file

@ -91,14 +91,4 @@ namespace MWClass
{ {
return true; 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;
}
} }

View file

@ -42,8 +42,6 @@ namespace MWClass
virtual bool isActor() const; virtual bool isActor() const;
virtual bool canBeActivated(const MWWorld::Ptr& ptr) const;
// not implemented // not implemented
Actor(const Actor&); Actor(const Actor&);
Actor& operator= (const Actor&); Actor& operator= (const Actor&);

View file

@ -45,8 +45,9 @@ namespace MWClass
std::string Apparatus::getName (const MWWorld::ConstPtr& ptr) const std::string Apparatus::getName (const MWWorld::ConstPtr& ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Apparatus> *ref = ptr.get<ESM::Apparatus>(); 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, std::shared_ptr<MWWorld::Action> Apparatus::activate (const MWWorld::Ptr& ptr,
@ -93,19 +94,12 @@ namespace MWClass
return ref->mBase->mIcon; 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 MWGui::ToolTipInfo Apparatus::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
{ {
const MWWorld::LiveCellRef<ESM::Apparatus> *ref = ptr.get<ESM::Apparatus>(); const MWWorld::LiveCellRef<ESM::Apparatus> *ref = ptr.get<ESM::Apparatus>();
MWGui::ToolTipInfo info; 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; info.icon = ref->mBase->mIcon;
std::string text; std::string text;

View file

@ -20,8 +20,7 @@ namespace MWClass
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
virtual std::string getName (const MWWorld::ConstPtr& ptr) 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); ///< \return name or ID; can return an empty string.
/// can return an empty string.
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr, virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor) const; const MWWorld::Ptr& actor) const;
@ -33,9 +32,6 @@ namespace MWClass
virtual int getValue (const MWWorld::ConstPtr& ptr) const; virtual int getValue (const MWWorld::ConstPtr& ptr) const;
///< Return trade value of the object. Throws an exception, if the object can't be traded. ///< 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; 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. ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.

View file

@ -53,8 +53,9 @@ namespace MWClass
std::string Armor::getName (const MWWorld::ConstPtr& ptr) const std::string Armor::getName (const MWWorld::ConstPtr& ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Armor> *ref = ptr.get<ESM::Armor>(); 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, std::shared_ptr<MWWorld::Action> Armor::activate (const MWWorld::Ptr& ptr,
@ -199,19 +200,12 @@ namespace MWClass
return ref->mBase->mIcon; 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 MWGui::ToolTipInfo Armor::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
{ {
const MWWorld::LiveCellRef<ESM::Armor> *ref = ptr.get<ESM::Armor>(); const MWWorld::LiveCellRef<ESM::Armor> *ref = ptr.get<ESM::Armor>();
MWGui::ToolTipInfo info; 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; info.icon = ref->mBase->mIcon;
std::string text; std::string text;

View file

@ -19,8 +19,7 @@ namespace MWClass
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
virtual std::string getName (const MWWorld::ConstPtr& ptr) 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); ///< \return name or ID; can return an empty string.
/// can return an empty string.
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr, virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor) const; 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 /// Return the index of the skill this item corresponds to when equipped or -1, if there is
/// no such skill. /// 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; 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. ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.

View file

@ -31,6 +31,11 @@ namespace MWClass
return std::string(); return std::string();
} }
bool BodyPart::hasToolTip(const MWWorld::ConstPtr& ptr) const
{
return false;
}
void BodyPart::registerSelf() void BodyPart::registerSelf()
{ {
std::shared_ptr<MWWorld::Class> instance (new BodyPart); std::shared_ptr<MWWorld::Class> instance (new BodyPart);

View file

@ -18,8 +18,10 @@ namespace MWClass
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
virtual std::string getName (const MWWorld::ConstPtr& ptr) 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); ///< \return name or ID; can return an empty string.
/// 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(); static void registerSelf();

View file

@ -50,8 +50,9 @@ namespace MWClass
std::string Book::getName (const MWWorld::ConstPtr& ptr) const std::string Book::getName (const MWWorld::ConstPtr& ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Book> *ref = ptr.get<ESM::Book>(); 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, std::shared_ptr<MWWorld::Action> Book::activate (const MWWorld::Ptr& ptr,
@ -109,19 +110,12 @@ namespace MWClass
return ref->mBase->mIcon; 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 MWGui::ToolTipInfo Book::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
{ {
const MWWorld::LiveCellRef<ESM::Book> *ref = ptr.get<ESM::Book>(); const MWWorld::LiveCellRef<ESM::Book> *ref = ptr.get<ESM::Book>();
MWGui::ToolTipInfo info; 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; info.icon = ref->mBase->mIcon;
std::string text; std::string text;

View file

@ -17,8 +17,7 @@ namespace MWClass
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
virtual std::string getName (const MWWorld::ConstPtr& ptr) 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); ///< \return name or ID; can return an empty string.
/// can return an empty string.
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr, virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor) const; const MWWorld::Ptr& actor) const;
@ -27,9 +26,6 @@ namespace MWClass
virtual std::string getScript (const MWWorld::ConstPtr& ptr) const; virtual std::string getScript (const MWWorld::ConstPtr& ptr) const;
///< Return name of the script attached to ptr ///< 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; 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. ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.

View file

@ -48,8 +48,9 @@ namespace MWClass
std::string Clothing::getName (const MWWorld::ConstPtr& ptr) const std::string Clothing::getName (const MWWorld::ConstPtr& ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Clothing> *ref = ptr.get<ESM::Clothing>(); 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, std::shared_ptr<MWWorld::Action> Clothing::activate (const MWWorld::Ptr& ptr,
@ -157,19 +158,12 @@ namespace MWClass
return ref->mBase->mIcon; 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 MWGui::ToolTipInfo Clothing::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
{ {
const MWWorld::LiveCellRef<ESM::Clothing> *ref = ptr.get<ESM::Clothing>(); const MWWorld::LiveCellRef<ESM::Clothing> *ref = ptr.get<ESM::Clothing>();
MWGui::ToolTipInfo info; 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; info.icon = ref->mBase->mIcon;
std::string text; std::string text;

View file

@ -17,8 +17,7 @@ namespace MWClass
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
virtual std::string getName (const MWWorld::ConstPtr& ptr) 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); ///< \return name or ID; can return an empty string.
/// can return an empty string.
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr, virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor) const; 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 /// Return the index of the skill this item corresponds to when equipped or -1, if there is
/// no such skill. /// 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; 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. ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.

View file

@ -181,7 +181,7 @@ namespace MWClass
{ {
MWBase::Environment::get().getWindowManager ()->messageBox (keyName + " #{sKeyUsed}"); MWBase::Environment::get().getWindowManager ()->messageBox (keyName + " #{sKeyUsed}");
if(isLocked) if(isLocked)
unlock(ptr); ptr.getCellRef().unlock();
// using a key disarms the trap // using a key disarms the trap
if(isTrapped) if(isTrapped)
{ {
@ -224,8 +224,9 @@ namespace MWClass
std::string Container::getName (const MWWorld::ConstPtr& ptr) const std::string Container::getName (const MWWorld::ConstPtr& ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Container> *ref = ptr.get<ESM::Container>(); 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) MWWorld::ContainerStore& Container::getContainerStore (const MWWorld::Ptr& ptr)
@ -252,26 +253,18 @@ namespace MWClass
bool Container::hasToolTip (const MWWorld::ConstPtr& ptr) const bool Container::hasToolTip (const MWWorld::ConstPtr& ptr) const
{ {
if (getName(ptr).empty())
return false;
if (const MWWorld::CustomData* data = ptr.getRefData().getCustomData()) if (const MWWorld::CustomData* data = ptr.getRefData().getCustomData())
return !canBeHarvested(ptr) || data->asContainerCustomData().mContainerStore.hasVisibleItems(); return !canBeHarvested(ptr) || data->asContainerCustomData().mContainerStore.hasVisibleItems();
return true; return true;
} }
bool Container::canBeActivated(const MWWorld::Ptr& ptr) const
{
return hasToolTip(ptr);
}
MWGui::ToolTipInfo Container::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const MWGui::ToolTipInfo Container::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
{ {
const MWWorld::LiveCellRef<ESM::Container> *ref = ptr.get<ESM::Container>(); const MWWorld::LiveCellRef<ESM::Container> *ref = ptr.get<ESM::Container>();
MWGui::ToolTipInfo info; MWGui::ToolTipInfo info;
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName); info.caption = MyGUI::TextIterator::toTagsString(getName(ptr));
std::string text; std::string text;
int lockLevel = ptr.getCellRef().getLockLevel(); int lockLevel = ptr.getCellRef().getLockLevel();
@ -282,9 +275,11 @@ namespace MWClass
if (ptr.getCellRef().getTrap() != "") if (ptr.getCellRef().getTrap() != "")
text += "\n#{sTrapped}"; text += "\n#{sTrapped}";
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { if (MWBase::Environment::get().getWindowManager()->getFullHelp())
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef()); { text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); 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; info.text = text;
@ -305,23 +300,10 @@ namespace MWClass
return getContainerStore (ptr).getWeight(); return getContainerStore (ptr).getWeight();
} }
void Container::lock (const MWWorld::Ptr& ptr, int lockLevel) const
{
if(lockLevel != 0)
ptr.getCellRef().setLockLevel(abs(lockLevel)); //Changes lock to locklevel, if positive
else
ptr.getCellRef().setLockLevel(ESM::UnbreakableLock); // If zero, set to max lock level
}
void Container::unlock (const MWWorld::Ptr& ptr) const
{
int lockLevel = ptr.getCellRef().getLockLevel();
ptr.getCellRef().setLockLevel(-abs(lockLevel)); //Makes lockLevel negative
}
bool Container::canLock(const MWWorld::ConstPtr &ptr) const bool Container::canLock(const MWWorld::ConstPtr &ptr) const
{ {
return true; const MWWorld::LiveCellRef<ESM::Container> *ref = ptr.get<ESM::Container>();
return !(ref->mBase->mFlags & ESM::Container::Organic);
} }
MWWorld::Ptr Container::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const MWWorld::Ptr Container::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const

View file

@ -20,15 +20,14 @@ namespace MWClass
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
virtual std::string getName (const MWWorld::ConstPtr& ptr) 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); ///< \return name or ID; can return an empty string.
/// can return an empty string.
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr, virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor) const; const MWWorld::Ptr& actor) const;
///< Generate action for activation ///< Generate action for activation
virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; 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; 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. ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.
@ -47,12 +46,6 @@ namespace MWClass
///< Returns total weight of objects inside this object (including modifications from magic ///< Returns total weight of objects inside this object (including modifications from magic
/// effects). Throws an exception, if the object can't hold other objects. /// effects). Throws an exception, if the object can't hold other objects.
virtual void lock (const MWWorld::Ptr& ptr, int lockLevel = 0) const;
///< Lock object
virtual void unlock (const MWWorld::Ptr& ptr) const;
///< Unlock object
virtual bool canLock(const MWWorld::ConstPtr &ptr) const; virtual bool canLock(const MWWorld::ConstPtr &ptr) const;
virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
@ -63,8 +56,6 @@ namespace MWClass
const; const;
///< Write additional state from \a ptr into \a state. ///< Write additional state from \a ptr into \a state.
virtual bool canBeActivated(const MWWorld::Ptr& ptr) const;
static void registerSelf(); static void registerSelf();
virtual void respawn (const MWWorld::Ptr& ptr) const; virtual void respawn (const MWWorld::Ptr& ptr) const;

View file

@ -214,8 +214,9 @@ namespace MWClass
std::string Creature::getName (const MWWorld::ConstPtr& ptr) const std::string Creature::getName (const MWWorld::ConstPtr& ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>(); 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 MWMechanics::CreatureStats& Creature::getCreatureStats (const MWWorld::Ptr& ptr) const
@ -454,18 +455,15 @@ namespace MWClass
// otherwise wait until death animation // otherwise wait until death animation
if(stats.isDeathAnimationFinished()) if(stats.isDeathAnimationFinished())
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr)); 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(""));
} }
else if (!stats.getAiSequence().isInCombat() && !stats.getKnockedDown())
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(ptr));
if(stats.getAiSequence().isInCombat()) // Tribunal and some mod companions oddly enough must use open action as fallback
return std::shared_ptr<MWWorld::Action>(new MWWorld::FailedAction("")); if (!getScript(ptr).empty() && ptr.getRefData().getLocals().getIntVar(getScript(ptr), "companion"))
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr));
if(stats.getKnockedDown()) return std::shared_ptr<MWWorld::Action>(new MWWorld::FailedAction(""));
return std::shared_ptr<MWWorld::Action>(new MWWorld::FailedAction(""));
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(ptr));
} }
MWWorld::ContainerStore& Creature::getContainerStore (const MWWorld::Ptr& ptr) const 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>(); const MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
MWGui::ToolTipInfo info; MWGui::ToolTipInfo info;
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName); info.caption = MyGUI::TextIterator::toTagsString(getName(ptr));
std::string text; std::string text;
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) if (MWBase::Environment::get().getWindowManager()->getFullHelp())

View file

@ -44,11 +44,10 @@ namespace MWClass
///< Add reference into a cell for rendering ///< Add reference into a cell for rendering
virtual std::string getName (const MWWorld::ConstPtr& ptr) 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); ///< \return name or ID; can return an empty string.
/// can return an empty string.
virtual bool hasToolTip(const MWWorld::ConstPtr& ptr) const; 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; 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. ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.

View file

@ -39,6 +39,11 @@ namespace MWClass
return ""; return "";
} }
bool CreatureLevList::hasToolTip(const MWWorld::ConstPtr& ptr) const
{
return false;
}
void CreatureLevList::respawn(const MWWorld::Ptr &ptr) const void CreatureLevList::respawn(const MWWorld::Ptr &ptr) const
{ {
ensureCustomData(ptr); ensureCustomData(ptr);

View file

@ -12,8 +12,10 @@ namespace MWClass
public: public:
virtual std::string getName (const MWWorld::ConstPtr& ptr) 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); ///< \return name or ID; can return an empty string.
/// 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(); static void registerSelf();

View file

@ -102,8 +102,9 @@ namespace MWClass
std::string Door::getName (const MWWorld::ConstPtr& ptr) const std::string Door::getName (const MWWorld::ConstPtr& ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Door> *ref = ptr.get<ESM::Door>(); 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, std::shared_ptr<MWWorld::Action> Door::activate (const MWWorld::Ptr& ptr,
@ -162,7 +163,7 @@ namespace MWClass
if(actor == MWMechanics::getPlayer()) if(actor == MWMechanics::getPlayer())
MWBase::Environment::get().getWindowManager()->messageBox(keyName + " #{sKeyUsed}"); MWBase::Environment::get().getWindowManager()->messageBox(keyName + " #{sKeyUsed}");
if(isLocked) if(isLocked)
unlock(ptr); //Call the function here. because that makes sense. ptr.getCellRef().unlock(); //Call the function here. because that makes sense.
// using a key disarms the trap // using a key disarms the trap
if(isTrapped) if(isTrapped)
{ {
@ -240,20 +241,6 @@ namespace MWClass
} }
} }
void Door::lock (const MWWorld::Ptr& ptr, int lockLevel) const
{
if(lockLevel != 0)
ptr.getCellRef().setLockLevel(abs(lockLevel)); //Changes lock to locklevel, if positive
else
ptr.getCellRef().setLockLevel(ESM::UnbreakableLock); // If zero, set to max lock level
}
void Door::unlock (const MWWorld::Ptr& ptr) const
{
int lockLevel = ptr.getCellRef().getLockLevel();
ptr.getCellRef().setLockLevel(-abs(lockLevel)); //Makes lockLevel negative
}
bool Door::canLock(const MWWorld::ConstPtr &ptr) const bool Door::canLock(const MWWorld::ConstPtr &ptr) const
{ {
return true; return true;
@ -281,19 +268,12 @@ namespace MWClass
registerClass (typeid (ESM::Door).name(), instance); 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 MWGui::ToolTipInfo Door::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
{ {
const MWWorld::LiveCellRef<ESM::Door> *ref = ptr.get<ESM::Door>(); const MWWorld::LiveCellRef<ESM::Door> *ref = ptr.get<ESM::Door>();
MWGui::ToolTipInfo info; MWGui::ToolTipInfo info;
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName); info.caption = MyGUI::TextIterator::toTagsString(getName(ptr));
std::string text; std::string text;

View file

@ -25,28 +25,18 @@ namespace MWClass
virtual bool useAnim() const; virtual bool useAnim() const;
virtual std::string getName (const MWWorld::ConstPtr& ptr) 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); ///< \return name or ID; can return an empty string.
/// can return an empty string.
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr, virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor) const; const MWWorld::Ptr& actor) const;
///< Generate action for activation ///< 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; 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. ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.
static std::string getDestination (const MWWorld::LiveCellRef<ESM::Door>& door); static std::string getDestination (const MWWorld::LiveCellRef<ESM::Door>& door);
///< @return destination cell name or token ///< @return destination cell name or token
virtual void lock (const MWWorld::Ptr& ptr, int lockLevel = 0) const;
///< Lock object
virtual void unlock (const MWWorld::Ptr& ptr) const;
///< Unlock object
virtual bool canLock(const MWWorld::ConstPtr &ptr) const; virtual bool canLock(const MWWorld::ConstPtr &ptr) const;
virtual bool allowTelekinesis(const MWWorld::ConstPtr &ptr) const; virtual bool allowTelekinesis(const MWWorld::ConstPtr &ptr) const;

View file

@ -47,8 +47,9 @@ namespace MWClass
std::string Ingredient::getName (const MWWorld::ConstPtr& ptr) const std::string Ingredient::getName (const MWWorld::ConstPtr& ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Ingredient> *ref = ptr.get<ESM::Ingredient>(); 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, std::shared_ptr<MWWorld::Action> Ingredient::activate (const MWWorld::Ptr& ptr,
@ -105,19 +106,12 @@ namespace MWClass
return ref->mBase->mIcon; 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 MWGui::ToolTipInfo Ingredient::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
{ {
const MWWorld::LiveCellRef<ESM::Ingredient> *ref = ptr.get<ESM::Ingredient>(); const MWWorld::LiveCellRef<ESM::Ingredient> *ref = ptr.get<ESM::Ingredient>();
MWGui::ToolTipInfo info; 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; info.icon = ref->mBase->mIcon;
std::string text; std::string text;

View file

@ -17,16 +17,12 @@ namespace MWClass
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
virtual std::string getName (const MWWorld::ConstPtr& ptr) 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); ///< \return name or ID; can return an empty string.
/// can return an empty string.
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr, virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor) const; const MWWorld::Ptr& actor) const;
///< Generate action for activation ///< 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; 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. ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.

View file

@ -10,6 +10,11 @@ namespace MWClass
return ""; return "";
} }
bool ItemLevList::hasToolTip(const MWWorld::ConstPtr& ptr) const
{
return false;
}
void ItemLevList::registerSelf() void ItemLevList::registerSelf()
{ {
std::shared_ptr<Class> instance (new ItemLevList); std::shared_ptr<Class> instance (new ItemLevList);

View file

@ -10,8 +10,10 @@ namespace MWClass
public: public:
virtual std::string getName (const MWWorld::ConstPtr& ptr) 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); ///< \return name or ID; can return an empty string.
/// 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(); static void registerSelf();
}; };

View file

@ -70,9 +70,10 @@ namespace MWClass
const MWWorld::LiveCellRef<ESM::Light> *ref = ptr.get<ESM::Light>(); const MWWorld::LiveCellRef<ESM::Light> *ref = ptr.get<ESM::Light>();
if (ref->mBase->mModel.empty()) 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, 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 bool Light::hasToolTip (const MWWorld::ConstPtr& ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Light> *ref = ptr.get<ESM::Light>(); return showsInInventory(ptr);
return (ref->mBase->mName != "");
} }
MWGui::ToolTipInfo Light::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const 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>(); const MWWorld::LiveCellRef<ESM::Light> *ref = ptr.get<ESM::Light>();
MWGui::ToolTipInfo info; 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; info.icon = ref->mBase->mIcon;
std::string text; std::string text;

View file

@ -19,11 +19,10 @@ namespace MWClass
virtual bool useAnim() const; virtual bool useAnim() const;
virtual std::string getName (const MWWorld::ConstPtr& ptr) 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); ///< \return name or ID; can return an empty string.
/// can return an empty string.
virtual bool hasToolTip (const MWWorld::ConstPtr& ptr) const; 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; 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. ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.

View file

@ -47,8 +47,9 @@ namespace MWClass
std::string Lockpick::getName (const MWWorld::ConstPtr& ptr) const std::string Lockpick::getName (const MWWorld::ConstPtr& ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Lockpick> *ref = ptr.get<ESM::Lockpick>(); 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, std::shared_ptr<MWWorld::Action> Lockpick::activate (const MWWorld::Ptr& ptr,
@ -104,19 +105,12 @@ namespace MWClass
return ref->mBase->mIcon; 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 MWGui::ToolTipInfo Lockpick::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
{ {
const MWWorld::LiveCellRef<ESM::Lockpick> *ref = ptr.get<ESM::Lockpick>(); const MWWorld::LiveCellRef<ESM::Lockpick> *ref = ptr.get<ESM::Lockpick>();
MWGui::ToolTipInfo info; 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; info.icon = ref->mBase->mIcon;
std::string text; std::string text;

View file

@ -17,16 +17,12 @@ namespace MWClass
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
virtual std::string getName (const MWWorld::ConstPtr& ptr) 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); ///< \return name or ID; can return an empty string.
/// can return an empty string.
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr, virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor) const; const MWWorld::Ptr& actor) const;
///< Generate action for activation ///< 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; 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. ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.

View file

@ -56,8 +56,9 @@ namespace MWClass
std::string Miscellaneous::getName (const MWWorld::ConstPtr& ptr) const std::string Miscellaneous::getName (const MWWorld::ConstPtr& ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Miscellaneous> *ref = ptr.get<ESM::Miscellaneous>(); 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, std::shared_ptr<MWWorld::Action> Miscellaneous::activate (const MWWorld::Ptr& ptr,
@ -134,13 +135,6 @@ namespace MWClass
return ref->mBase->mIcon; 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 MWGui::ToolTipInfo Miscellaneous::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
{ {
const MWWorld::LiveCellRef<ESM::Miscellaneous> *ref = ptr.get<ESM::Miscellaneous>(); 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. else // gold displays its count also if it's 1.
countString = " (" + std::to_string(count) + ")"; 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; info.icon = ref->mBase->mIcon;
if (ref->mRef.getSoul() != "") if (ref->mRef.getSoul() != "")
{ {
const ESM::Creature *creature = store.get<ESM::Creature>().search(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 + ")"; info.caption += " (" + creature->mName + ")";
else if (creature)
info.caption += " (" + creature->mId + ")";
} }
std::string text; std::string text;

View file

@ -17,16 +17,12 @@ namespace MWClass
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
virtual std::string getName (const MWWorld::ConstPtr& ptr) 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); ///< \return name or ID; can return an empty string.
/// can return an empty string.
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr, virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor) const; const MWWorld::Ptr& actor) const;
///< Generate action for activation ///< 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; 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. ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.

View file

@ -531,7 +531,9 @@ namespace MWClass
} }
const MWWorld::LiveCellRef<ESM::NPC> *ref = ptr.get<ESM::NPC>(); 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 MWMechanics::CreatureStats& Npc::getCreatureStats (const MWWorld::Ptr& ptr) const
@ -884,22 +886,22 @@ namespace MWClass
// otherwise wait until death animation // otherwise wait until death animation
if(stats.isDeathAnimationFinished()) if(stats.isDeathAnimationFinished())
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr)); return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr));
}
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
// death animation is not finished, do nothing // Can't talk to werewolves
return std::shared_ptr<MWWorld::Action> (new MWWorld::FailedAction("")); if (!getNpcStats(ptr).isWerewolf())
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(ptr));
} }
if(stats.getAiSequence().isInCombat()) // Tribunal and some mod companions oddly enough must use open action as fallback
return std::shared_ptr<MWWorld::Action>(new MWWorld::FailedAction("")); if (!getScript(ptr).empty() && ptr.getRefData().getLocals().getIntVar(getScript(ptr), "companion"))
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr));
if(getCreatureStats(actor).getStance(MWMechanics::CreatureStats::Stance_Sneak) || stats.getKnockedDown()) return std::shared_ptr<MWWorld::Action> (new MWWorld::FailedAction(""));
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(""));
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(ptr));
} }
MWWorld::ContainerStore& Npc::getContainerStore (const MWWorld::Ptr& ptr) MWWorld::ContainerStore& Npc::getContainerStore (const MWWorld::Ptr& ptr)
@ -1071,7 +1073,7 @@ namespace MWClass
MWGui::ToolTipInfo info; MWGui::ToolTipInfo info;
info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)); 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 += " (";
info.caption += MyGUI::TextIterator::toTagsString(ref->mBase->mName); info.caption += MyGUI::TextIterator::toTagsString(ref->mBase->mName);

View file

@ -48,8 +48,7 @@ namespace MWClass
///< Add reference into a cell for rendering ///< Add reference into a cell for rendering
virtual std::string getName (const MWWorld::ConstPtr& ptr) 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); ///< \return name or ID; can return an empty string.
/// can return an empty string.
virtual MWMechanics::CreatureStats& getCreatureStats (const MWWorld::Ptr& ptr) const; virtual MWMechanics::CreatureStats& getCreatureStats (const MWWorld::Ptr& ptr) const;
///< Return creature stats ///< Return creature stats
@ -61,7 +60,7 @@ namespace MWClass
///< Return container store ///< Return container store
virtual bool hasToolTip(const MWWorld::ConstPtr& ptr) const; 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; 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. ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.

View file

@ -49,8 +49,9 @@ namespace MWClass
std::string Potion::getName (const MWWorld::ConstPtr& ptr) const std::string Potion::getName (const MWWorld::ConstPtr& ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Potion> *ref = ptr.get<ESM::Potion>(); 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, std::shared_ptr<MWWorld::Action> Potion::activate (const MWWorld::Ptr& ptr,
@ -98,19 +99,12 @@ namespace MWClass
return ref->mBase->mIcon; 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 MWGui::ToolTipInfo Potion::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
{ {
const MWWorld::LiveCellRef<ESM::Potion> *ref = ptr.get<ESM::Potion>(); const MWWorld::LiveCellRef<ESM::Potion> *ref = ptr.get<ESM::Potion>();
MWGui::ToolTipInfo info; 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; info.icon = ref->mBase->mIcon;
std::string text; std::string text;

View file

@ -17,16 +17,12 @@ namespace MWClass
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
virtual std::string getName (const MWWorld::ConstPtr& ptr) 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); ///< \return name or ID; can return an empty string.
/// can return an empty string.
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr, virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor) const; const MWWorld::Ptr& actor) const;
///< Generate action for activation ///< 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; 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. ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.

View file

@ -47,8 +47,9 @@ namespace MWClass
std::string Probe::getName (const MWWorld::ConstPtr& ptr) const std::string Probe::getName (const MWWorld::ConstPtr& ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Probe> *ref = ptr.get<ESM::Probe>(); 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, std::shared_ptr<MWWorld::Action> Probe::activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor) const const MWWorld::Ptr& actor) const
@ -104,19 +105,12 @@ namespace MWClass
return ref->mBase->mIcon; 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 MWGui::ToolTipInfo Probe::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
{ {
const MWWorld::LiveCellRef<ESM::Probe> *ref = ptr.get<ESM::Probe>(); const MWWorld::LiveCellRef<ESM::Probe> *ref = ptr.get<ESM::Probe>();
MWGui::ToolTipInfo info; 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; info.icon = ref->mBase->mIcon;
std::string text; std::string text;

View file

@ -17,16 +17,12 @@ namespace MWClass
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
virtual std::string getName (const MWWorld::ConstPtr& ptr) 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); ///< \return name or ID; can return an empty string.
/// can return an empty string.
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr, virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor) const; const MWWorld::Ptr& actor) const;
///< Generate action for activation ///< 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; 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. ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.

View file

@ -44,8 +44,9 @@ namespace MWClass
std::string Repair::getName (const MWWorld::ConstPtr& ptr) const std::string Repair::getName (const MWWorld::ConstPtr& ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Repair> *ref = ptr.get<ESM::Repair>(); 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, std::shared_ptr<MWWorld::Action> Repair::activate (const MWWorld::Ptr& ptr,
@ -93,13 +94,6 @@ namespace MWClass
return ref->mBase->mIcon; 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 bool Repair::hasItemHealth (const MWWorld::ConstPtr& ptr) const
{ {
return true; return true;
@ -117,7 +111,7 @@ namespace MWClass
const MWWorld::LiveCellRef<ESM::Repair> *ref = ptr.get<ESM::Repair>(); const MWWorld::LiveCellRef<ESM::Repair> *ref = ptr.get<ESM::Repair>();
MWGui::ToolTipInfo info; 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; info.icon = ref->mBase->mIcon;
std::string text; std::string text;

View file

@ -17,16 +17,12 @@ namespace MWClass
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
virtual std::string getName (const MWWorld::ConstPtr& ptr) 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); ///< \return name or ID; can return an empty string.
/// can return an empty string.
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr, virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor) const; const MWWorld::Ptr& actor) const;
///< Generate action for activation ///< 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; 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. ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.

View file

@ -45,6 +45,11 @@ namespace MWClass
return ""; return "";
} }
bool Static::hasToolTip(const MWWorld::ConstPtr& ptr) const
{
return false;
}
void Static::registerSelf() void Static::registerSelf()
{ {
std::shared_ptr<Class> instance (new Static); std::shared_ptr<Class> instance (new Static);

View file

@ -17,8 +17,10 @@ namespace MWClass
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
virtual std::string getName (const MWWorld::ConstPtr& ptr) 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); ///< \return name or ID; can return an empty string.
/// 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(); static void registerSelf();

View file

@ -53,8 +53,9 @@ namespace MWClass
std::string Weapon::getName (const MWWorld::ConstPtr& ptr) const std::string Weapon::getName (const MWWorld::ConstPtr& ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Weapon> *ref = ptr.get<ESM::Weapon>(); 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, std::shared_ptr<MWWorld::Action> Weapon::activate (const MWWorld::Ptr& ptr,
@ -155,20 +156,13 @@ namespace MWClass
return ref->mBase->mIcon; 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 MWGui::ToolTipInfo Weapon::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
{ {
const MWWorld::LiveCellRef<ESM::Weapon> *ref = ptr.get<ESM::Weapon>(); const MWWorld::LiveCellRef<ESM::Weapon> *ref = ptr.get<ESM::Weapon>();
const ESM::WeaponType* weaponType = MWMechanics::getWeaponType(ref->mBase->mData.mType); const ESM::WeaponType* weaponType = MWMechanics::getWeaponType(ref->mBase->mData.mType);
MWGui::ToolTipInfo info; 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; info.icon = ref->mBase->mIcon;
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();

View file

@ -18,16 +18,12 @@ namespace MWClass
virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const;
virtual std::string getName (const MWWorld::ConstPtr& ptr) 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); ///< \return name or ID; can return an empty string.
/// can return an empty string.
virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr, virtual std::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor) const; const MWWorld::Ptr& actor) const;
///< Generate action for activation ///< 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; 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. ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.

View file

@ -98,7 +98,7 @@ namespace MWGui
if (pickpocket.finish()) if (pickpocket.finish())
{ {
MWBase::Environment::get().getMechanicsManager()->commitCrime( MWBase::Environment::get().getMechanicsManager()->commitCrime(
player, mActor, MWBase::MechanicsManager::OT_Pickpocket, 0, true); player, mActor, MWBase::MechanicsManager::OT_Pickpocket, std::string(), 0, true);
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container); MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container);
mPickpocketDetected = true; mPickpocketDetected = true;
} }
@ -126,7 +126,7 @@ namespace MWGui
if (pickpocket.pick(item, count)) if (pickpocket.pick(item, count))
{ {
MWBase::Environment::get().getMechanicsManager()->commitCrime( MWBase::Environment::get().getMechanicsManager()->commitCrime(
player, mActor, MWBase::MechanicsManager::OT_Pickpocket, 0, true); player, mActor, MWBase::MechanicsManager::OT_Pickpocket, std::string(), 0, true);
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container); MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container);
mPickpocketDetected = true; mPickpocketDetected = true;
return false; return false;

View file

@ -651,9 +651,22 @@ namespace MWGui
{ {
std::string ret; std::string ret;
ret += getMiscString(cellref.getOwner(), "Owner"); ret += getMiscString(cellref.getOwner(), "Owner");
ret += getMiscString(cellref.getFaction(), "Faction"); const std::string factionId = cellref.getFaction();
if (cellref.getFactionRank() > 0) ret += getMiscString(factionId, "Faction");
ret += getValueString(cellref.getFactionRank(), "Rank"); 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 = std::vector<std::pair<std::string, int> > itemOwners =
MWBase::Environment::get().getMechanicsManager()->getStolenItemOwners(cellref.getRefId()); MWBase::Environment::get().getMechanicsManager()->getStolenItemOwners(cellref.getRefId());

View file

@ -471,19 +471,19 @@ namespace MWInput
quickLoad(); quickLoad();
break; break;
case A_CycleSpellLeft: case A_CycleSpellLeft:
if (checkAllowedToUseItems()) if (checkAllowedToUseItems() && MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Magic))
MWBase::Environment::get().getWindowManager()->cycleSpell(false); MWBase::Environment::get().getWindowManager()->cycleSpell(false);
break; break;
case A_CycleSpellRight: case A_CycleSpellRight:
if (checkAllowedToUseItems()) if (checkAllowedToUseItems() && MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Magic))
MWBase::Environment::get().getWindowManager()->cycleSpell(true); MWBase::Environment::get().getWindowManager()->cycleSpell(true);
break; break;
case A_CycleWeaponLeft: case A_CycleWeaponLeft:
if (checkAllowedToUseItems()) if (checkAllowedToUseItems() && MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory))
MWBase::Environment::get().getWindowManager()->cycleWeapon(false); MWBase::Environment::get().getWindowManager()->cycleWeapon(false);
break; break;
case A_CycleWeaponRight: case A_CycleWeaponRight:
if (checkAllowedToUseItems()) if (checkAllowedToUseItems() && MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory))
MWBase::Environment::get().getWindowManager()->cycleWeapon(true); MWBase::Environment::get().getWindowManager()->cycleWeapon(true);
break; break;
case A_Sneak: case A_Sneak:
@ -1312,6 +1312,9 @@ namespace MWInput
if (!checkAllowedToUseItems()) if (!checkAllowedToUseItems())
return; return;
if (MWBase::Environment::get().getWorld()->getGlobalFloat ("chargenstate")!=-1)
return;
if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) if (!MWBase::Environment::get().getWindowManager()->isGuiMode())
MWBase::Environment::get().getWindowManager()->activateQuickKey (index); MWBase::Environment::get().getWindowManager()->activateQuickKey (index);
} }

View file

@ -1637,6 +1637,20 @@ namespace MWMechanics
++mDeathCount[Misc::StringUtils::lowerCase(actor.getCellRef().getRefId())]; ++mDeathCount[Misc::StringUtils::lowerCase(actor.getCellRef().getRefId())];
} }
void Actors::resurrect(const MWWorld::Ptr &ptr)
{
PtrActorMap::iterator iter = mActors.find(ptr);
if(iter != mActors.end())
{
if(iter->second->getCharacterController()->isDead())
{
// Actor has been resurrected. Notify the CharacterController and re-enable collision.
MWBase::Environment::get().getWorld()->enableActorCollision(iter->first, true);
iter->second->getCharacterController()->resurrect();
}
}
}
void Actors::killDeadActors() void Actors::killDeadActors()
{ {
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
@ -1645,17 +1659,7 @@ namespace MWMechanics
CreatureStats &stats = cls.getCreatureStats(iter->first); CreatureStats &stats = cls.getCreatureStats(iter->first);
if(!stats.isDead()) if(!stats.isDead())
{ continue;
if(iter->second->getCharacterController()->isDead())
{
// Actor has been resurrected. Notify the CharacterController and re-enable collision.
MWBase::Environment::get().getWorld()->enableActorCollision(iter->first, true);
iter->second->getCharacterController()->resurrect();
}
if(!stats.isDead())
continue;
}
MWBase::Environment::get().getWorld()->removeActorPath(iter->first); MWBase::Environment::get().getWorld()->removeActorPath(iter->first);
CharacterController::KillResult killResult = iter->second->getCharacterController()->kill(); CharacterController::KillResult killResult = iter->second->getCharacterController()->kill();

View file

@ -94,6 +94,8 @@ namespace MWMechanics
/// ///
/// \note Ignored, if \a ptr is not a registered actor. /// \note Ignored, if \a ptr is not a registered actor.
void resurrect (const MWWorld::Ptr& ptr);
void castSpell(const MWWorld::Ptr& ptr, const std::string spellId, bool manualSpell=false); void castSpell(const MWWorld::Ptr& ptr, const std::string spellId, bool manualSpell=false);
void updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr& ptr); void updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr& ptr);

View file

@ -9,6 +9,7 @@
#include "creaturestats.hpp" #include "creaturestats.hpp"
#include "movement.hpp" #include "movement.hpp"
#include "steering.hpp"
namespace MWMechanics namespace MWMechanics
{ {
@ -33,16 +34,18 @@ namespace MWMechanics
if (target == MWWorld::Ptr() || !target.getRefData().getCount() || !target.getRefData().isEnabled()) if (target == MWWorld::Ptr() || !target.getRefData().getCount() || !target.getRefData().isEnabled())
return true; return true;
//Set the target destination for the actor // Turn to target and move to it directly, without pathfinding.
const osg::Vec3f dest = target.getRefData().getPosition().asVec3(); const osg::Vec3f targetDir = target.getRefData().getPosition().asVec3() - actor.getRefData().getPosition().asVec3();
if (pathTo(actor, dest, duration, MWBase::Environment::get().getWorld()->getMaxActivationDistance())) //Stop when you get in activation range zTurn(actor, std::atan2(targetDir.x(), targetDir.y()), 0.f);
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
actor.getClass().getMovementSettings(actor).mPosition[0] = 0;
if (MWBase::Environment::get().getWorld()->getMaxActivationDistance() >= targetDir.length())
{ {
// activate when reached // Note: we intentionally do not cancel package after activation here for backward compatibility with original engine.
MWBase::Environment::get().getWorld()->activate(target, actor); MWBase::Environment::get().getWorld()->activate(target, actor);
return true;
} }
return false; return false;
} }

View file

@ -1,5 +1,7 @@
#include "aiavoiddoor.hpp" #include "aiavoiddoor.hpp"
#include <components/misc/rng.hpp>
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
@ -11,8 +13,10 @@
#include "actorutil.hpp" #include "actorutil.hpp"
#include "steering.hpp" #include "steering.hpp"
static const int MAX_DIRECTIONS = 4;
MWMechanics::AiAvoidDoor::AiAvoidDoor(const MWWorld::ConstPtr& doorPtr) MWMechanics::AiAvoidDoor::AiAvoidDoor(const MWWorld::ConstPtr& doorPtr)
: AiPackage(), mDuration(1), mDoorPtr(doorPtr), mLastPos(ESM::Position()), mAdjAngle(0) : AiPackage(), mDuration(1), mDoorPtr(doorPtr), mDirection(0)
{ {
} }
@ -22,25 +26,18 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, CharacterCont
ESM::Position pos = actor.getRefData().getPosition(); ESM::Position pos = actor.getRefData().getPosition();
if(mDuration == 1) //If it just started, get the actor position as the stuck detection thing if(mDuration == 1) //If it just started, get the actor position as the stuck detection thing
mLastPos = pos; mLastPos = pos.asVec3();
mDuration -= duration; //Update timer mDuration -= duration; //Update timer
if(mDuration < 0) { if (mDuration < 0)
float x = pos.pos[0] - mLastPos.pos[0]; {
float y = pos.pos[1] - mLastPos.pos[1]; if (isStuck(pos.asVec3()))
float z = pos.pos[2] - mLastPos.pos[2]; {
float distance = x * x + y * y + z * z; adjustDirection();
if(distance < 10 * 10) { //Got stuck, didn't move
if(mAdjAngle == 0) //Try going in various directions
mAdjAngle = osg::PI / 2;
else if (mAdjAngle == osg::PI / 2)
mAdjAngle = -osg::PI / 2;
else
mAdjAngle = 0;
mDuration = 1; //reset timer mDuration = 1; //reset timer
} }
else //Not stuck else
return true; // We have tried backing up for more than one second, we've probably cleared it return true; // We have tried backing up for more than one second, we've probably cleared it
} }
@ -54,7 +51,7 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, CharacterCont
actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true); actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
// Turn away from the door and move when turn completed // Turn away from the door and move when turn completed
if (zTurn(actor, std::atan2(x,y) + mAdjAngle, osg::DegreesToRadians(5.f))) if (zTurn(actor, std::atan2(x,y) + getAdjustedAngle(), osg::DegreesToRadians(5.f)))
actor.getClass().getMovementSettings(actor).mPosition[1] = 1; actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
else else
actor.getClass().getMovementSettings(actor).mPosition[1] = 0; actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
@ -90,4 +87,17 @@ unsigned int MWMechanics::AiAvoidDoor::getPriority() const
return 2; return 2;
} }
bool MWMechanics::AiAvoidDoor::isStuck(const osg::Vec3f& actorPos) const
{
return (actorPos - mLastPos).length2() < 10 * 10;
}
void MWMechanics::AiAvoidDoor::adjustDirection()
{
mDirection = Misc::Rng::rollDice(MAX_DIRECTIONS);
}
float MWMechanics::AiAvoidDoor::getAdjustedAngle() const
{
return 2 * osg::PI / MAX_DIRECTIONS * mDirection;
}

View file

@ -36,8 +36,14 @@ namespace MWMechanics
private: private:
float mDuration; float mDuration;
MWWorld::ConstPtr mDoorPtr; MWWorld::ConstPtr mDoorPtr;
ESM::Position mLastPos; osg::Vec3f mLastPos;
float mAdjAngle; int mDirection;
bool isStuck(const osg::Vec3f& actorPos) const;
void adjustDirection();
float getAdjustedAngle() const;
}; };
} }
#endif #endif

View file

@ -1629,7 +1629,9 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && !isKnockedDown()) if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && !isKnockedDown())
{ {
float attackStrength = complete; float attackStrength = complete;
if (!mPtr.getClass().isNpc()) float minAttackTime = mAnimation->getTextKeyTime(mCurrentWeapon+": "+mAttackType+" "+"min attack");
float maxAttackTime = mAnimation->getTextKeyTime(mCurrentWeapon+": "+mAttackType+" "+"max attack");
if (minAttackTime == maxAttackTime)
{ {
// most creatures don't actually have an attack wind-up animation, so use a uniform random value // most creatures don't actually have an attack wind-up animation, so use a uniform random value
// (even some creatures that can use weapons don't have a wind-up animation either, e.g. Rieklings) // (even some creatures that can use weapons don't have a wind-up animation either, e.g. Rieklings)
@ -1735,7 +1737,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
{ {
// If actor is already stopped preparing attack, do not play the "min attack -> max attack" part. // If actor is already stopped preparing attack, do not play the "min attack -> max attack" part.
// Happens if the player did not hold the attack button. // Happens if the player did not hold the attack button.
// Note: if the "min attack"->"max attack" is a stub, "play" it anyway. Attack strength will be 1. // Note: if the "min attack"->"max attack" is a stub, "play" it anyway. Attack strength will be random.
float minAttackTime = mAnimation->getTextKeyTime(mCurrentWeapon+": "+mAttackType+" "+"min attack"); float minAttackTime = mAnimation->getTextKeyTime(mCurrentWeapon+": "+mAttackType+" "+"min attack");
float maxAttackTime = mAnimation->getTextKeyTime(mCurrentWeapon+": "+mAttackType+" "+"max attack"); float maxAttackTime = mAnimation->getTextKeyTime(mCurrentWeapon+": "+mAttackType+" "+"max attack");
if (mAttackingOrSpell || minAttackTime == maxAttackTime) if (mAttackingOrSpell || minAttackTime == maxAttackTime)

View file

@ -198,9 +198,6 @@ namespace MWMechanics
mDynamic[index].setModifier(0); mDynamic[index].setModifier(0);
mDynamic[index].setCurrentModifier(0); mDynamic[index].setCurrentModifier(0);
mDynamic[index].setCurrent(0); mDynamic[index].setCurrent(0);
if (MWBase::Environment::get().getWorld()->getGodModeState())
MWBase::Environment::get().getMechanicsManager()->keepPlayerAlive();
} }
} }

View file

@ -19,16 +19,14 @@ namespace MWMechanics
{ {
/// @return ID of resulting item, or empty if none /// @return ID of resulting item, or empty if none
inline std::string getLevelledItem (const ESM::LevelledListBase* levItem, bool creature, unsigned char failChance=0) inline std::string getLevelledItem (const ESM::LevelledListBase* levItem, bool creature)
{ {
const std::vector<ESM::LevelledListBase::LevelItem>& items = levItem->mList; const std::vector<ESM::LevelledListBase::LevelItem>& items = levItem->mList;
const MWWorld::Ptr& player = getPlayer(); const MWWorld::Ptr& player = getPlayer();
int playerLevel = player.getClass().getCreatureStats(player).getLevel(); int playerLevel = player.getClass().getCreatureStats(player).getLevel();
failChance += levItem->mChanceNone; if (Misc::Rng::roll0to99() < levItem->mChanceNone)
if (Misc::Rng::roll0to99() < failChance)
return std::string(); return std::string();
std::vector<std::string> candidates; std::vector<std::string> candidates;
@ -76,9 +74,9 @@ namespace MWMechanics
else else
{ {
if (ref.getPtr().getTypeName() == typeid(ESM::ItemLevList).name()) if (ref.getPtr().getTypeName() == typeid(ESM::ItemLevList).name())
return getLevelledItem(ref.getPtr().get<ESM::ItemLevList>()->mBase, false, failChance); return getLevelledItem(ref.getPtr().get<ESM::ItemLevList>()->mBase, false);
else else
return getLevelledItem(ref.getPtr().get<ESM::CreatureLevList>()->mBase, true, failChance); return getLevelledItem(ref.getPtr().get<ESM::CreatureLevList>()->mBase, true);
} }
} }

View file

@ -959,7 +959,7 @@ namespace MWMechanics
return true; return true;
} }
if (!target.getClass().canBeActivated(target)) if (!target.getClass().hasToolTip(target))
return true; return true;
// TODO: implement a better check to check if target is owned bed // TODO: implement a better check to check if target is owned bed
@ -1005,6 +1005,10 @@ namespace MWMechanics
if (!cellref.getOwner().empty()) if (!cellref.getOwner().empty())
victim = MWBase::Environment::get().getWorld()->searchPtr(cellref.getOwner(), true, false); 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); return (!isOwned && !isFactionOwned);
} }
@ -1025,7 +1029,7 @@ namespace MWMechanics
if (isAllowedToUse(ptr, bed, victim)) if (isAllowedToUse(ptr, bed, victim))
return false; return false;
if(commitCrime(ptr, victim, OT_SleepingInOwnedBed)) if(commitCrime(ptr, victim, OT_SleepingInOwnedBed, bed.getCellRef().getFaction()))
{ {
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage64}"); MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage64}");
return true; return true;
@ -1039,7 +1043,7 @@ namespace MWMechanics
MWWorld::Ptr victim; MWWorld::Ptr victim;
if (isAllowedToUse(ptr, item, victim)) if (isAllowedToUse(ptr, item, victim))
return; 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) 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 // move items from player to owner and report about theft
victim.getClass().getContainerStore(victim).add(item, toRemove, victim); victim.getClass().getContainerStore(victim).add(item, toRemove, victim);
store.remove(item, toRemove, player); 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) void MechanicsManager::confiscateStolenItems(const MWWorld::Ptr &player, const MWWorld::Ptr &targetContainer)
@ -1150,7 +1154,7 @@ namespace MWMechanics
store.remove(*it, toMove, player); store.remove(*it, toMove, player);
} }
// TODO: unhardcode the locklevel // TODO: unhardcode the locklevel
targetContainer.getClass().lock(targetContainer,50); targetContainer.getCellRef().lock(50);
} }
void MechanicsManager::itemTaken(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item, const MWWorld::Ptr& container, void MechanicsManager::itemTaken(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item, const MWWorld::Ptr& container,
@ -1207,11 +1211,11 @@ namespace MWMechanics
mStolenItems[Misc::StringUtils::lowerCase(item.getCellRef().getRefId())][owner] += count; mStolenItems[Misc::StringUtils::lowerCase(item.getCellRef().getRefId())][owner] += count;
} }
if (alarm) 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 // NOTE: victim may be empty
@ -1258,13 +1262,13 @@ namespace MWMechanics
} }
if (crimeSeen) if (crimeSeen)
reportCrime(player, victim, type, arg); reportCrime(player, victim, type, factionId, arg);
else if (type == OT_Assault && !victim.isEmpty()) else if (type == OT_Assault && !victim.isEmpty())
{ {
bool reported = false; bool reported = false;
if (victim.getClass().isClass(victim, "guard") if (victim.getClass().isClass(victim, "guard")
&& !victim.getClass().getCreatureStats(victim).getAiSequence().hasPackage(AiPackage::TypeIdPursue)) && !victim.getClass().getCreatureStats(victim).getAiSequence().hasPackage(AiPackage::TypeIdPursue))
reported = reportCrime(player, victim, type, arg); reported = reportCrime(player, victim, type, std::string(), arg);
if (!reported) if (!reported)
startCombat(victim, player); // TODO: combat should be started with an "unaware" flag, which makes the victim flee? 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; 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>(); 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); 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() if (type == OT_Assault && !victim.isEmpty()
&& !victim.getClass().getCreatureStats(victim).getAiSequence().isInCombat(player) && !victim.getClass().getCreatureStats(victim).getAiSequence().isInCombat(player)
@ -1808,12 +1820,14 @@ namespace MWMechanics
return (fight >= 100); return (fight >= 100);
} }
void MechanicsManager::keepPlayerAlive() void MechanicsManager::resurrect(const MWWorld::Ptr &ptr)
{ {
MWWorld::Ptr player = getPlayer(); CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
CreatureStats& stats = player.getClass().getCreatureStats(player);
if (stats.isDead()) if (stats.isDead())
{
stats.resurrect(); stats.resurrect();
mActors.resurrect(ptr);
}
} }
bool MechanicsManager::isCastingSpell(const MWWorld::Ptr &ptr) const bool MechanicsManager::isCastingSpell(const MWWorld::Ptr &ptr) const

View file

@ -130,7 +130,7 @@ namespace MWMechanics
* @return was the crime seen? * @return was the crime seen?
*/ */
virtual bool commitCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, 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 /// @return false if the attack was considered a "friendly hit" and forgiven
virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) override; virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) override;
@ -197,7 +197,7 @@ namespace MWMechanics
virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target) override; virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target) override;
virtual void keepPlayerAlive() override; virtual void resurrect(const MWWorld::Ptr& ptr) override;
virtual bool isCastingSpell (const MWWorld::Ptr& ptr) const override; virtual bool isCastingSpell (const MWWorld::Ptr& ptr) const override;
@ -247,7 +247,7 @@ namespace MWMechanics
bool canReportCrime(const MWWorld::Ptr &actor, const MWWorld::Ptr &victim, std::set<MWWorld::Ptr> &playerFollowers); 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, bool reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim,
OffenseType type, int arg=0); OffenseType type, const std::string& factionId, int arg=0);
}; };
} }

View file

@ -30,7 +30,7 @@ namespace MWMechanics
{ {
if (lock.getCellRef().getLockLevel() <= 0 || if (lock.getCellRef().getLockLevel() <= 0 ||
lock.getCellRef().getLockLevel() == ESM::UnbreakableLock || lock.getCellRef().getLockLevel() == ESM::UnbreakableLock ||
!lock.getClass().canLock(lock)) //If it's unlocked or can not be unlocked back out immediately !lock.getClass().hasToolTip(lock)) //If it's unlocked or can not be unlocked back out immediately
return; return;
int lockStrength = lock.getCellRef().getLockLevel(); int lockStrength = lock.getCellRef().getLockLevel();
@ -50,7 +50,7 @@ namespace MWMechanics
{ {
if (Misc::Rng::roll0to99() <= x) if (Misc::Rng::roll0to99() <= x)
{ {
lock.getClass().unlock(lock); lock.getCellRef().unlock();
resultMessage = "#{sLockSuccess}"; resultMessage = "#{sLockSuccess}";
resultSound = "Open Lock"; resultSound = "Open Lock";
mActor.getClass().skillUsageSucceeded(mActor, ESM::Skill::Security, 1); mActor.getClass().skillUsageSucceeded(mActor, ESM::Skill::Security, 1);

View file

@ -696,7 +696,7 @@ namespace MWMechanics
{ {
if (caster == getPlayer()) if (caster == getPlayer())
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicLockSuccess}"); MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicLockSuccess}");
target.getClass().lock(target, static_cast<int>(magnitude)); target.getCellRef().lock(static_cast<int>(magnitude));
} }
return true; return true;
} }
@ -716,7 +716,7 @@ namespace MWMechanics
if (caster == getPlayer()) if (caster == getPlayer())
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicOpenSuccess}"); MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicOpenSuccess}");
} }
target.getClass().unlock(target); target.getCellRef().unlock();
} }
else else
MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock Fail", 1.f, 1.f); MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock Fail", 1.f, 1.f);

View file

@ -1333,9 +1333,9 @@ namespace MWRender
return mCurrentCameraPos; return mCurrentCameraPos;
} }
void RenderingManager::togglePOV() void RenderingManager::togglePOV(bool force)
{ {
mCamera->toggleViewMode(); mCamera->toggleViewMode(force);
} }
void RenderingManager::togglePreviewMode(bool enable) void RenderingManager::togglePreviewMode(bool enable)

View file

@ -204,7 +204,7 @@ namespace MWRender
float getCameraDistance() const; float getCameraDistance() const;
Camera* getCamera(); Camera* getCamera();
const osg::Vec3f& getCameraPosition() const; const osg::Vec3f& getCameraPosition() const;
void togglePOV(); void togglePOV(bool force = false);
void togglePreviewMode(bool enable); void togglePreviewMode(bool enable);
bool toggleVanityMode(bool enable); bool toggleVanityMode(bool enable);
void allowVanityMode(bool allow); void allowVanityMode(bool allow);

View file

@ -182,7 +182,7 @@ namespace MWScript
runtime.pop(); runtime.pop();
} }
ptr.getClass().lock (ptr, lockLevel); ptr.getCellRef().lock (lockLevel);
// Instantly reset door to closed state // Instantly reset door to closed state
// This is done when using Lock in scripts, but not when using Lock spells. // This is done when using Lock in scripts, but not when using Lock spells.
@ -202,7 +202,7 @@ namespace MWScript
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
ptr.getClass().unlock (ptr); ptr.getCellRef().unlock ();
} }
}; };
@ -358,7 +358,7 @@ namespace MWScript
virtual void execute (Interpreter::Runtime& runtime) virtual void execute (Interpreter::Runtime& runtime)
{ {
if (!MWBase::Environment::get().getWorld()->isFirstPerson()) if (!MWBase::Environment::get().getWorld()->isFirstPerson())
MWBase::Environment::get().getWorld()->togglePOV(); MWBase::Environment::get().getWorld()->togglePOV(true);
} }
}; };
@ -367,7 +367,7 @@ namespace MWScript
virtual void execute (Interpreter::Runtime& runtime) virtual void execute (Interpreter::Runtime& runtime)
{ {
if (MWBase::Environment::get().getWorld()->isFirstPerson()) if (MWBase::Environment::get().getWorld()->isFirstPerson())
MWBase::Environment::get().getWorld()->togglePOV(); MWBase::Environment::get().getWorld()->togglePOV(true);
} }
}; };

View file

@ -1184,7 +1184,7 @@ namespace MWScript
if (ptr == MWMechanics::getPlayer()) if (ptr == MWMechanics::getPlayer())
{ {
ptr.getClass().getCreatureStats(ptr).resurrect(); MWBase::Environment::get().getMechanicsManager()->resurrect(ptr);
if (MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_Ended) if (MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_Ended)
MWBase::Environment::get().getStateManager()->resumeGame(); MWBase::Environment::get().getStateManager()->resumeGame();
} }

View file

@ -225,6 +225,19 @@ namespace MWWorld
} }
} }
void CellRef::lock(int lockLevel)
{
if(lockLevel != 0)
setLockLevel(abs(lockLevel)); //Changes lock to locklevel, if positive
else
setLockLevel(ESM::UnbreakableLock); // If zero, set to max lock level
}
void CellRef::unlock()
{
setLockLevel(-abs(mCellRef.mLockLevel)); //Makes lockLevel negative
}
std::string CellRef::getKey() const std::string CellRef::getKey() const
{ {
return mCellRef.mKey; return mCellRef.mKey;

View file

@ -99,6 +99,8 @@ namespace MWWorld
// For an unlocked door, it is set to -(previous locklevel) // For an unlocked door, it is set to -(previous locklevel)
int getLockLevel() const; int getLockLevel() const;
void setLockLevel(int lockLevel); void setLockLevel(int lockLevel);
void lock(int lockLevel);
void unlock();
// Key and trap ID names, if any // Key and trap ID names, if any
std::string getKey() const; std::string getKey() const;
std::string getTrap() const; std::string getTrap() const;

View file

@ -109,11 +109,6 @@ namespace MWWorld
throw std::runtime_error("class cannot block"); 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 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"); throw std::runtime_error("class cannot be hit");
@ -144,16 +139,6 @@ namespace MWWorld
return false; return false;
} }
void Class::lock (const Ptr& ptr, int lockLevel) const
{
throw std::runtime_error ("class does not support locking");
}
void Class::unlock (const Ptr& ptr) const
{
throw std::runtime_error ("class does not support unlocking");
}
bool Class::canLock(const ConstPtr &ptr) const bool Class::canLock(const ConstPtr &ptr) const
{ {
return false; return false;
@ -298,7 +283,7 @@ namespace MWWorld
bool Class::hasToolTip (const ConstPtr& ptr) const bool Class::hasToolTip (const ConstPtr& ptr) const
{ {
return false; return true;
} }
std::string Class::getEnchantment (const ConstPtr& ptr) const std::string Class::getEnchantment (const ConstPtr& ptr) const

View file

@ -83,8 +83,7 @@ namespace MWWorld
///< Add reference into a cell for rendering (default implementation: don't render anything). ///< Add reference into a cell for rendering (default implementation: don't render anything).
virtual std::string getName (const ConstPtr& ptr) const = 0; 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); ///< \return name or ID; can return an empty string.
/// can return an empty string.
virtual void adjustPosition(const MWWorld::Ptr& ptr, bool force) const; virtual void adjustPosition(const MWWorld::Ptr& ptr, bool force) const;
///< Adjust position to stand on ground. Must be called post model load ///< Adjust position to stand on ground. Must be called post model load
@ -95,7 +94,7 @@ namespace MWWorld
/// (default implementation: throw an exception) /// (default implementation: throw an exception)
virtual bool hasToolTip (const ConstPtr& ptr) const; 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; 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. ///< @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 ///< Play the appropriate sound for a blocked attack, depending on the currently equipped shield
/// (default implementation: throw an exception) /// (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; virtual std::shared_ptr<Action> activate (const Ptr& ptr, const Ptr& actor) const;
///< Generate action for activation (default implementation: return a null action). ///< Generate action for activation (default implementation: return a null action).
@ -163,12 +158,6 @@ namespace MWWorld
virtual bool hasInventoryStore (const Ptr& ptr) const; virtual bool hasInventoryStore (const Ptr& ptr) const;
///< Does this object have an inventory store, i.e. equipment slots? (default implementation: false) ///< Does this object have an inventory store, i.e. equipment slots? (default implementation: false)
virtual void lock (const Ptr& ptr, int lockLevel) const;
///< Lock object (default implementation: throw an exception)
virtual void unlock (const Ptr& ptr) const;
///< Unlock object (default implementation: throw an exception)
virtual bool canLock (const ConstPtr& ptr) const; virtual bool canLock (const ConstPtr& ptr) const;
virtual void setRemainingUsageTime (const Ptr& ptr, float duration) const; virtual void setRemainingUsageTime (const Ptr& ptr, float duration) const;

View file

@ -477,50 +477,64 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::
int count, bool topLevel, const std::string& levItem) int count, bool topLevel, const std::string& levItem)
{ {
if (count == 0) return; //Don't restock with nothing. if (count == 0) return; //Don't restock with nothing.
try { try
{
ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count); ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count);
if (ref.getPtr().getClass().getScript(ref.getPtr()).empty())
if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name())
{ {
const ESM::ItemLevList* levItemList = ref.getPtr().get<ESM::ItemLevList>()->mBase; addInitialItemImp(ref.getPtr(), owner, count, topLevel, levItem);
if (topLevel && std::abs(count) > 1 && levItemList->mFlags & ESM::ItemLevList::Each)
{
for (int i=0; i<std::abs(count); ++i)
addInitialItem(id, owner, count > 0 ? 1 : -1, true, levItemList->mId);
return;
}
else
{
std::string itemId = MWMechanics::getLevelledItem(ref.getPtr().get<ESM::ItemLevList>()->mBase, false);
if (itemId.empty())
return;
addInitialItem(itemId, owner, count, false, levItemList->mId);
}
} }
else else
{ {
// A negative count indicates restocking items // Adding just one item per time to make sure there isn't a stack of scripted items
// For a restocking levelled item, remember what we spawned so we can delete it later when the merchant restocks for (int i = 0; i < abs(count); i++)
if (!levItem.empty() && count < 0) addInitialItemImp(ref.getPtr(), owner, count < 0 ? -1 : 1, topLevel, levItem);
{
//If there is no item in map, insert it
std::map<std::pair<std::string, std::string>, int>::iterator itemInMap =
mLevelledItemMap.insert(std::make_pair(std::make_pair(id, levItem), 0)).first;
//Update spawned count
itemInMap->second += std::abs(count);
}
count = std::abs(count);
ref.getPtr().getCellRef().setOwner(owner);
addImp (ref.getPtr(), count);
} }
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
Log(Debug::Warning) << "Warning: MWWorld::ContainerStore::addInitialItem: " << e.what(); Log(Debug::Warning) << "Warning: MWWorld::ContainerStore::addInitialItem: " << e.what();
} }
}
void MWWorld::ContainerStore::addInitialItemImp(const MWWorld::Ptr& ptr, const std::string& owner,
int count, bool topLevel, const std::string& levItem)
{
if (ptr.getTypeName()==typeid (ESM::ItemLevList).name())
{
const ESM::ItemLevList* levItemList = ptr.get<ESM::ItemLevList>()->mBase;
if (topLevel && std::abs(count) > 1 && levItemList->mFlags & ESM::ItemLevList::Each)
{
for (int i=0; i<std::abs(count); ++i)
addInitialItem(ptr.getCellRef().getRefId(), owner, count > 0 ? 1 : -1, true, levItemList->mId);
return;
}
else
{
std::string itemId = MWMechanics::getLevelledItem(ptr.get<ESM::ItemLevList>()->mBase, false);
if (itemId.empty())
return;
addInitialItem(itemId, owner, count, false, levItemList->mId);
}
}
else
{
// A negative count indicates restocking items
// For a restocking levelled item, remember what we spawned so we can delete it later when the merchant restocks
if (!levItem.empty() && count < 0)
{
//If there is no item in map, insert it
std::map<std::pair<std::string, std::string>, int>::iterator itemInMap =
mLevelledItemMap.insert(std::make_pair(std::make_pair(ptr.getCellRef().getRefId(), levItem), 0)).first;
//Update spawned count
itemInMap->second += std::abs(count);
}
count = std::abs(count);
ptr.getCellRef().setOwner(owner);
addImp (ptr, count);
}
} }
void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner) void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner)

View file

@ -94,6 +94,7 @@ namespace MWWorld
mutable bool mWeightUpToDate; mutable bool mWeightUpToDate;
ContainerStoreIterator addImp (const Ptr& ptr, int count); ContainerStoreIterator addImp (const Ptr& ptr, int count);
void addInitialItem (const std::string& id, const std::string& owner, int count, bool topLevel=true, const std::string& levItem = ""); void addInitialItem (const std::string& id, const std::string& owner, int count, bool topLevel=true, const std::string& levItem = "");
void addInitialItemImp (const MWWorld::Ptr& ptr, const std::string& owner, int count, bool topLevel=true, const std::string& levItem = "");
template<typename T> template<typename T>
ContainerStoreIterator getState (CellRefList<T>& collection, ContainerStoreIterator getState (CellRefList<T>& collection,

View file

@ -236,7 +236,7 @@ namespace MWWorld
if (toActivate.isEmpty()) if (toActivate.isEmpty())
return; return;
if (!toActivate.getClass().canBeActivated(toActivate)) if (!toActivate.getClass().hasToolTip(toActivate))
return; return;
MWBase::Environment::get().getWorld()->activate(toActivate, player); MWBase::Environment::get().getWorld()->activate(toActivate, player);

View file

@ -1091,6 +1091,18 @@ namespace MWWorld
return RecordId(dialogue.mId, isDeleted); return RecordId(dialogue.mId, isDeleted);
} }
template<>
bool Store<ESM::Dialogue>::eraseStatic(const std::string &id)
{
auto it = mStatic.find(Misc::StringUtils::lowerCase(id));
if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) {
mStatic.erase(it);
}
return true;
}
} }
template class MWWorld::Store<ESM::Activator>; template class MWWorld::Store<ESM::Activator>;

View file

@ -1649,7 +1649,6 @@ namespace MWWorld
} }
// we need to undo the rotation // we need to undo the rotation
rotateObject(door, objPos.rot[0], objPos.rot[1], oldRot);
reached = false; reached = false;
} }
} }
@ -1671,6 +1670,8 @@ namespace MWWorld
if (!closeSound.empty() && MWBase::Environment::get().getSoundManager()->getSoundPlaying(door, closeSound)) if (!closeSound.empty() && MWBase::Environment::get().getSoundManager()->getSoundPlaying(door, closeSound))
MWBase::Environment::get().getSoundManager()->stopSound3D(door, closeSound); MWBase::Environment::get().getSoundManager()->stopSound3D(door, closeSound);
} }
rotateObject(door, objPos.rot[0], objPos.rot[1], oldRot);
} }
// the rotation order we want to use // the rotation order we want to use
@ -2395,9 +2396,9 @@ namespace MWWorld
return mPhysics->isOnGround(ptr); return mPhysics->isOnGround(ptr);
} }
void World::togglePOV() void World::togglePOV(bool force)
{ {
mRendering->togglePOV(); mRendering->togglePOV(force);
} }
bool World::isFirstPerson() const bool World::isFirstPerson() const
@ -3023,7 +3024,7 @@ namespace MWWorld
target = getFacedObject(); target = getFacedObject();
// if the faced object can not be activated, do not use it // 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; target = nullptr;
if (target.isEmpty()) if (target.isEmpty())
@ -3082,7 +3083,7 @@ namespace MWWorld
{ {
target = result2.mHitObject; target = result2.mHitObject;
hitPosition = result2.mHitPointWorld; hitPosition = result2.mHitPointWorld;
if (dist2 > getMaxActivationDistance() && !target.isEmpty() && !target.getClass().canBeActivated(target)) if (dist2 > getMaxActivationDistance() && !target.isEmpty() && !target.getClass().hasToolTip(target))
target = nullptr; target = nullptr;
} }
} }
@ -3650,7 +3651,7 @@ namespace MWWorld
if (fromProjectile && effectInfo.mArea <= 0) if (fromProjectile && effectInfo.mArea <= 0)
continue; // Don't play explosion for projectiles with 0-area effects 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 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 // Spawn the explosion orb effect

View file

@ -518,7 +518,7 @@ namespace MWWorld
osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const override; osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const override;
void togglePOV() override; void togglePOV(bool force = false) override;
bool isFirstPerson() const override; bool isFirstPerson() const override;

View file

@ -208,18 +208,13 @@ namespace
void init(Nif::Extra& value) void init(Nif::Extra& value)
{ {
value.extra = Nif::ExtraPtr(nullptr); value.next = Nif::ExtraPtr(nullptr);
}
void init(Nif::Controlled& value)
{
init(static_cast<Nif::Extra&>(value));
value.controller = Nif::ControllerPtr(nullptr);
} }
void init(Nif::Named& value) 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) void init(Nif::Node& value)
@ -254,7 +249,7 @@ namespace
value.phase = 0; value.phase = 0;
value.timeStart = 0; value.timeStart = 0;
value.timeStop = 0; value.timeStop = 0;
value.target = Nif::ControlledPtr(nullptr); value.target = Nif::NamedPtr(nullptr);
} }
void copy(const btTransform& src, Nif::Transformation& dst) 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) 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.string = "NC___";
mNiStringExtraData2.recType = Nif::RC_NiStringExtraData; mNiStringExtraData2.recType = Nif::RC_NiStringExtraData;
mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData); mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);

View file

@ -489,7 +489,7 @@ namespace Compiler
parseArguments ("l", scanner); parseArguments ("l", scanner);
Generator::random (mCode); Generator::random (mCode);
mOperands.push_back ('l'); mOperands.push_back ('f');
mNextOperand = false; mNextOperand = false;
return true; return true;

View file

@ -56,6 +56,23 @@ namespace Compiler
} }
} }
if (keyword==Scanner::K_end || keyword==Scanner::K_begin ||
keyword==Scanner::K_short || keyword==Scanner::K_long ||
keyword==Scanner::K_float || keyword==Scanner::K_if ||
keyword==Scanner::K_endif || keyword==Scanner::K_else ||
keyword==Scanner::K_elseif || keyword==Scanner::K_while ||
keyword==Scanner::K_endwhile || keyword==Scanner::K_return ||
keyword==Scanner::K_messagebox || keyword==Scanner::K_set ||
keyword==Scanner::K_to || keyword==Scanner::K_startscript ||
keyword==Scanner::K_stopscript || keyword==Scanner::K_enable ||
keyword==Scanner::K_disable || keyword==Scanner::K_getdisabled ||
keyword==Scanner::K_getdistance || keyword==Scanner::K_scriptrunning ||
keyword==Scanner::K_getsquareroot || keyword==Scanner::K_menumode ||
keyword==Scanner::K_random || keyword==Scanner::K_getsecondspassed)
{
return parseName (loc.mLiteral, loc, scanner);
}
return Parser::parseKeyword (keyword, loc, scanner); return Parser::parseKeyword (keyword, loc, scanner);
} }

View file

@ -39,10 +39,7 @@ namespace Fallback
std::string key(temp.substr(0, sep)); std::string key(temp.substr(0, sep));
std::string value(temp.substr(sep + 1)); std::string value(temp.substr(sep + 1));
if (map->mMap.find(key) == map->mMap.end()) map->mMap[key] = value;
{
map->mMap.insert(std::make_pair(key, value));
}
} }
} }
} }

View file

@ -51,9 +51,6 @@ void ConfigurationManager::readConfiguration(boost::program_options::variables_m
bool silent = mSilent; bool silent = mSilent;
mSilent = quiet; mSilent = quiet;
loadConfig(mFixedPath.getUserConfigPath(), variables, description);
boost::program_options::notify(variables);
// read either local or global config depending on type of installation // read either local or global config depending on type of installation
bool loaded = loadConfig(mFixedPath.getLocalPath(), variables, description); bool loaded = loadConfig(mFixedPath.getLocalPath(), variables, description);
boost::program_options::notify(variables); boost::program_options::notify(variables);
@ -63,6 +60,10 @@ void ConfigurationManager::readConfiguration(boost::program_options::variables_m
boost::program_options::notify(variables); boost::program_options::notify(variables);
} }
// User config has the highest priority.
loadConfig(mFixedPath.getUserConfigPath(), variables, description);
boost::program_options::notify(variables);
mSilent = silent; mSilent = silent;
} }

View file

@ -190,9 +190,7 @@ namespace Interpreter
throw std::runtime_error ( throw std::runtime_error (
"random: argument out of range (Don't be so negative!)"); "random: argument out of range (Don't be so negative!)");
Type_Integer value = Misc::Rng::rollDice(limit); // [o, limit) runtime[0].mFloat = static_cast<Type_Float>(Misc::Rng::rollDice(limit)); // [o, limit)
runtime[0].mInteger = value;
} }
}; };

View file

@ -10,17 +10,19 @@
namespace Nif namespace Nif
{ {
/** A record that can have extra data. The extra data objects // An extra data record. All the extra data connected to an object form a linked list.
themselves descend from the Extra class, and all the extra data
connected to an object form a linked list
*/
class Extra : public Record class Extra : public Record
{ {
public: public:
ExtraPtr extra; ExtraPtr next; // Next extra data record in the list
void read(NIFStream *nif) { extra.read(nif); } void read(NIFStream *nif)
void post(NIFFile *nif) { extra.post(nif); } {
next.read(nif);
nif->getUInt(); // Size of the record
}
void post(NIFFile *nif) { next.post(nif); }
}; };
class Controller : public Record class Controller : public Record
@ -30,43 +32,33 @@ public:
int flags; int flags;
float frequency, phase; float frequency, phase;
float timeStart, timeStop; float timeStart, timeStop;
ControlledPtr target; NamedPtr target;
void read(NIFStream *nif); void read(NIFStream *nif);
void post(NIFFile *nif); void post(NIFFile *nif);
}; };
/// Anything that has a controller /// Has name, extra-data and controller
class Controlled : public Extra class Named : public Record
{ {
public: public:
std::string name;
ExtraPtr extra;
ControllerPtr controller; ControllerPtr controller;
void read(NIFStream *nif) void read(NIFStream *nif)
{ {
Extra::read(nif); name = nif->getString();
extra.read(nif);
controller.read(nif); controller.read(nif);
} }
void post(NIFFile *nif) void post(NIFFile *nif)
{ {
Extra::post(nif); extra.post(nif);
controller.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; typedef Named NiSequenceStreamHelper;
} // Namespace } // Namespace

View file

@ -31,28 +31,40 @@ namespace Nif
data.post(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) void NiParticleGrowFade::read(NIFStream *nif)
{ {
Controlled::read(nif); NiParticleModifier::read(nif);
growTime = nif->getFloat(); growTime = nif->getFloat();
fadeTime = nif->getFloat(); fadeTime = nif->getFloat();
} }
void NiParticleColorModifier::read(NIFStream *nif) void NiParticleColorModifier::read(NIFStream *nif)
{ {
Controlled::read(nif); NiParticleModifier::read(nif);
data.read(nif); data.read(nif);
} }
void NiParticleColorModifier::post(NIFFile *nif) void NiParticleColorModifier::post(NIFFile *nif)
{ {
Controlled::post(nif); NiParticleModifier::post(nif);
data.post(nif); data.post(nif);
} }
void NiGravity::read(NIFStream *nif) void NiGravity::read(NIFStream *nif)
{ {
Controlled::read(nif); NiParticleModifier::read(nif);
mDecay = nif->getFloat(); mDecay = nif->getFloat();
mForce = nif->getFloat(); mForce = nif->getFloat();
@ -61,11 +73,17 @@ namespace Nif
mDirection = nif->getVector3(); mDirection = nif->getVector3();
} }
void NiPlanarCollider::read(NIFStream *nif) void NiParticleCollider::read(NIFStream *nif)
{ {
Controlled::read(nif); NiParticleModifier::read(nif);
mBounceFactor = nif->getFloat(); mBounceFactor = nif->getFloat();
}
void NiPlanarCollider::read(NIFStream *nif)
{
NiParticleCollider::read(nif);
/*unknown*/nif->getFloat(); /*unknown*/nif->getFloat();
for (int i=0;i<10;++i) for (int i=0;i<10;++i)
@ -77,7 +95,7 @@ namespace Nif
void NiParticleRotation::read(NIFStream *nif) void NiParticleRotation::read(NIFStream *nif)
{ {
Controlled::read(nif); NiParticleModifier::read(nif);
/* /*
byte (0 or 1) byte (0 or 1)
@ -89,9 +107,8 @@ namespace Nif
void NiSphericalCollider::read(NIFStream* nif) void NiSphericalCollider::read(NIFStream* nif)
{ {
Controlled::read(nif); NiParticleCollider::read(nif);
mBounceFactor = nif->getFloat();
mRadius = nif->getFloat(); mRadius = nif->getFloat();
mCenter = nif->getVector3(); mCenter = nif->getVector3();
} }

View file

@ -66,7 +66,16 @@ public:
void post(NIFFile *nif); 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: public:
float growTime; float growTime;
@ -75,7 +84,7 @@ public:
void read(NIFStream *nif); void read(NIFStream *nif);
}; };
class NiParticleColorModifier : public Controlled class NiParticleColorModifier : public NiParticleModifier
{ {
public: public:
NiColorDataPtr data; NiColorDataPtr data;
@ -84,7 +93,7 @@ public:
void post(NIFFile *nif); void post(NIFFile *nif);
}; };
class NiGravity : public Controlled class NiGravity : public NiParticleModifier
{ {
public: public:
float mForce; float mForce;
@ -99,29 +108,32 @@ public:
void read(NIFStream *nif); void read(NIFStream *nif);
}; };
struct NiParticleCollider : public NiParticleModifier
{
float mBounceFactor;
void read(NIFStream *nif);
};
// NiPinaColada // NiPinaColada
class NiPlanarCollider : public Controlled class NiPlanarCollider : public NiParticleCollider
{ {
public: public:
void read(NIFStream *nif); void read(NIFStream *nif);
float mBounceFactor;
osg::Vec3f mPlaneNormal; osg::Vec3f mPlaneNormal;
float mPlaneDistance; float mPlaneDistance;
}; };
class NiSphericalCollider : public Controlled class NiSphericalCollider : public NiParticleCollider
{ {
public: public:
float mBounceFactor;
float mRadius; float mRadius;
osg::Vec3f mCenter; osg::Vec3f mCenter;
void read(NIFStream *nif); void read(NIFStream *nif);
}; };
class NiParticleRotation : public Controlled class NiParticleRotation : public NiParticleModifier
{ {
public: public:
void read(NIFStream *nif); void read(NIFStream *nif);

View file

@ -72,8 +72,8 @@ public:
int activeCount; int activeCount;
std::vector<Particle> particles; std::vector<Particle> particles;
ExtraPtr affectors; NiParticleModifierPtr affectors;
ExtraPtr colliders; NiParticleModifierPtr colliders;
void read(NIFStream *nif); void read(NIFStream *nif);
void post(NIFFile *nif); void post(NIFFile *nif);

View file

@ -6,8 +6,6 @@ namespace Nif
void NiStringExtraData::read(NIFStream *nif) void NiStringExtraData::read(NIFStream *nif)
{ {
Extra::read(nif); Extra::read(nif);
nif->getInt(); // size of string + 4. Really useful...
string = nif->getString(); string = nif->getString();
} }
@ -15,8 +13,6 @@ void NiTextKeyExtraData::read(NIFStream *nif)
{ {
Extra::read(nif); Extra::read(nif);
nif->getInt(); // 0
int keynum = nif->getInt(); int keynum = nif->getInt();
list.resize(keynum); list.resize(keynum);
for(int i=0; i<keynum; i++) for(int i=0; i<keynum; i++)
@ -30,12 +26,7 @@ void NiVertWeightsExtraData::read(NIFStream *nif)
{ {
Extra::read(nif); Extra::read(nif);
// We should have s*4+2 == i, for some reason. Might simply be the nif->skip(nif->getUShort() * sizeof(float)); // vertex weights I guess
// 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
} }

View file

@ -127,7 +127,7 @@ class NiUVData;
class NiPosData; class NiPosData;
class NiVisData; class NiVisData;
class Controller; class Controller;
class Controlled; class Named;
class NiSkinData; class NiSkinData;
class NiFloatData; class NiFloatData;
struct NiMorphData; struct NiMorphData;
@ -141,6 +141,7 @@ class NiSourceTexture;
class NiRotatingParticlesData; class NiRotatingParticlesData;
class NiAutoNormalParticlesData; class NiAutoNormalParticlesData;
class NiPalette; class NiPalette;
struct NiParticleModifier;
typedef RecordPtrT<Node> NodePtr; typedef RecordPtrT<Node> NodePtr;
typedef RecordPtrT<Extra> ExtraPtr; typedef RecordPtrT<Extra> ExtraPtr;
@ -148,7 +149,7 @@ typedef RecordPtrT<NiUVData> NiUVDataPtr;
typedef RecordPtrT<NiPosData> NiPosDataPtr; typedef RecordPtrT<NiPosData> NiPosDataPtr;
typedef RecordPtrT<NiVisData> NiVisDataPtr; typedef RecordPtrT<NiVisData> NiVisDataPtr;
typedef RecordPtrT<Controller> ControllerPtr; typedef RecordPtrT<Controller> ControllerPtr;
typedef RecordPtrT<Controlled> ControlledPtr; typedef RecordPtrT<Named> NamedPtr;
typedef RecordPtrT<NiSkinData> NiSkinDataPtr; typedef RecordPtrT<NiSkinData> NiSkinDataPtr;
typedef RecordPtrT<NiMorphData> NiMorphDataPtr; typedef RecordPtrT<NiMorphData> NiMorphDataPtr;
typedef RecordPtrT<NiPixelData> NiPixelDataPtr; typedef RecordPtrT<NiPixelData> NiPixelDataPtr;
@ -162,6 +163,7 @@ typedef RecordPtrT<NiSourceTexture> NiSourceTexturePtr;
typedef RecordPtrT<NiRotatingParticlesData> NiRotatingParticlesDataPtr; typedef RecordPtrT<NiRotatingParticlesData> NiRotatingParticlesDataPtr;
typedef RecordPtrT<NiAutoNormalParticlesData> NiAutoNormalParticlesDataPtr; typedef RecordPtrT<NiAutoNormalParticlesData> NiAutoNormalParticlesDataPtr;
typedef RecordPtrT<NiPalette> NiPalettePtr; typedef RecordPtrT<NiPalette> NiPalettePtr;
typedef RecordPtrT<NiParticleModifier> NiParticleModifierPtr;
typedef RecordListT<Node> NodeList; typedef RecordListT<Node> NodeList;
typedef RecordListT<Property> PropertyList; typedef RecordListT<Property> PropertyList;

View file

@ -78,7 +78,7 @@ void fillTriangleMeshWithTransform(btTriangleMesh& mesh, const Nif::NiTriStripsD
continue; continue;
unsigned short a = strip[0], b = strip[0], c = strip[1]; unsigned short a = strip[0], b = strip[0], c = strip[1];
for (int i = 2; i < static_cast<int>(strip.size()); i++) for (size_t i = 2; i < strip.size(); i++)
{ {
a = b; a = b;
b = c; b = c;
@ -86,9 +86,21 @@ void fillTriangleMeshWithTransform(btTriangleMesh& mesh, const Nif::NiTriStripsD
if (a != b && b != c && a != c) if (a != b && b != c && a != c)
{ {
if (i%2==0) if (i%2==0)
mesh.addTriangle(getbtVector(vertices[a]), getbtVector(vertices[b]), getbtVector(vertices[c])); {
mesh.addTriangle(
getbtVector(vertices[a] * transform),
getbtVector(vertices[b] * transform),
getbtVector(vertices[c] * transform)
);
}
else else
mesh.addTriangle(getbtVector(vertices[a]), getbtVector(vertices[c]), getbtVector(vertices[b])); {
mesh.addTriangle(
getbtVector(vertices[a] * transform),
getbtVector(vertices[c] * transform),
getbtVector(vertices[b] * transform)
);
}
} }
} }
} }
@ -260,18 +272,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."; Log(Debug::Info) << "RootCollisionNode is not attached to the root node in " << fileName << ". Treating it as a common NiTriShape.";
// Check for extra data // Check for extra data
Nif::Extra const *e = node; for (Nif::ExtraPtr e = node->extra; !e.empty(); e = e->next)
while (!e->extra.empty())
{ {
// Get the next extra data in the list
e = e->extra.getPtr();
assert(e != nullptr);
if (e->recType == Nif::RC_NiStringExtraData) if (e->recType == Nif::RC_NiStringExtraData)
{ {
// String markers may contain important information // String markers may contain important information
// affecting the entire subtree of this node // 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) if (Misc::StringUtils::ciCompareLen(sd->string, "NC", 2) == 0)
{ {

View file

@ -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)) : mData(data->mKeyList, osg::Vec3f(1,1,1))
, mTargetColor(color)
{ {
} }
@ -397,6 +398,7 @@ MaterialColorController::MaterialColorController()
MaterialColorController::MaterialColorController(const MaterialColorController &copy, const osg::CopyOp &copyop) MaterialColorController::MaterialColorController(const MaterialColorController &copy, const osg::CopyOp &copyop)
: StateSetUpdater(copy, copyop), Controller(copy) : StateSetUpdater(copy, copyop), Controller(copy)
, mData(copy.mData) , 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::Vec3f value = mData.interpKey(getInputValue(nv));
osg::Material* mat = static_cast<osg::Material*>(stateset->getAttribute(osg::StateAttribute::MATERIAL)); osg::Material* mat = static_cast<osg::Material*>(stateset->getAttribute(osg::StateAttribute::MATERIAL));
osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); switch (mTargetColor)
diffuse.set(value.x(), value.y(), value.z(), diffuse.a()); {
mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); 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);
}
}
} }
} }

Some files were not shown because too many files have changed in this diff Show more