forked from teamnwah/openmw-tes3coop
Merge pull request #441 from TES3MP/0.6.3 while resolving conflicts
Conflicts: apps/openmw-mp/Script/Functions/Worldstate.cpp apps/openmw-mp/Script/Functions/Worldstate.hpp
This commit is contained in:
commit
fc4d3fe3fa
75 changed files with 1992 additions and 365 deletions
|
@ -6,4 +6,6 @@ DATE=`date +'%d%m%Y'`
|
|||
SHORT_COMMIT=`git rev-parse --short ${TRAVIS_COMMIT}`
|
||||
TARGET_FILENAME="OpenMW-${DATE}-${SHORT_COMMIT}.dmg"
|
||||
|
||||
curl --ssl --ftp-create-dirs -T *.dmg -u $OSX_FTP_USER:$OSX_FTP_PASSWORD "${OSX_FTP_URL}${TARGET_FILENAME}"
|
||||
if ! curl --ssl -u $OSX_FTP_USER:$OSX_FTP_PASSWORD "${OSX_FTP_URL}" --silent | grep $SHORT_COMMIT > /dev/null; then
|
||||
curl --ssl --ftp-create-dirs -T *.dmg -u $OSX_FTP_USER:$OSX_FTP_PASSWORD "${OSX_FTP_URL}${TARGET_FILENAME}"
|
||||
fi
|
||||
|
|
|
@ -392,6 +392,8 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang)
|
|||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-but-set-parameter")
|
||||
endif()
|
||||
elseif (MSVC)
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} /Zi /bigobj")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF /INCREMENTAL:NO")
|
||||
# Enable link-time code generation globally for all linking
|
||||
if (OPENMW_LTO_BUILD)
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL")
|
||||
|
|
|
@ -81,14 +81,14 @@ opencs_units_noqt (view/world
|
|||
|
||||
opencs_units (view/widget
|
||||
scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun modebutton
|
||||
scenetooltoggle2 completerpopup coloreditor colorpickerpopup droplineedit
|
||||
scenetooltoggle2 scenetooltexturebrush completerpopup coloreditor colorpickerpopup droplineedit
|
||||
)
|
||||
|
||||
opencs_units (view/render
|
||||
scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget
|
||||
previewwidget editmode instancemode instanceselectionmode instancemovemode
|
||||
orbitcameramode pathgridmode selectionmode pathgridselectionmode cameracontroller
|
||||
cellwater
|
||||
cellwater terraintexturemode
|
||||
)
|
||||
|
||||
opencs_units_noqt (view/render
|
||||
|
|
|
@ -222,7 +222,15 @@ void CSMPrefs::State::declare()
|
|||
EnumValues insertOutsideVisibleCell;
|
||||
insertOutsideVisibleCell.add (showAndInsert).add (dontInsert).add (insertAnyway);
|
||||
|
||||
declareCategory ("Scene Drops");
|
||||
EnumValue createAndLandEdit ("Create cell and land, then edit");
|
||||
EnumValue showAndLandEdit ("Show cell and edit");
|
||||
EnumValue dontLandEdit ("Discard");
|
||||
EnumValues landeditOutsideCell;
|
||||
landeditOutsideCell.add (createAndLandEdit).add (dontLandEdit);
|
||||
EnumValues landeditOutsideVisibleCell;
|
||||
landeditOutsideVisibleCell.add (showAndLandEdit).add (dontLandEdit);
|
||||
|
||||
declareCategory ("3D Scene Editing");
|
||||
declareInt ("distance", "Drop Distance", 50).
|
||||
setTooltip ("If an instance drop can not be placed against another object at the "
|
||||
"insert point, it will be placed by this distance from the insert point instead");
|
||||
|
@ -230,6 +238,12 @@ void CSMPrefs::State::declare()
|
|||
addValues (insertOutsideCell);
|
||||
declareEnum ("outside-visible-drop", "Handling drops outside of visible cells", showAndInsert).
|
||||
addValues (insertOutsideVisibleCell);
|
||||
declareEnum ("outside-landedit", "Handling land edit outside of cells", createAndLandEdit).
|
||||
addValues (landeditOutsideCell);
|
||||
declareEnum ("outside-visible-landedit", "Handling land edit outside of visible cells", showAndLandEdit).
|
||||
addValues (landeditOutsideVisibleCell);
|
||||
declareInt ("texturebrush-maximumsize", "Maximum texture brush size", 50).
|
||||
setMin (1);
|
||||
|
||||
declareCategory ("Key Bindings");
|
||||
|
||||
|
|
|
@ -28,9 +28,13 @@ void CSMTools::ClassCheckStage::perform (int stage, CSMDoc::Messages& messages)
|
|||
|
||||
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Class, class_.mId);
|
||||
|
||||
// test for empty name and description
|
||||
// A class should have a name
|
||||
if (class_.mName.empty())
|
||||
messages.push_back (std::make_pair (id, class_.mId + " has an empty name"));
|
||||
messages.push_back (std::make_pair (id, class_.mId + " doesn't have a name"));
|
||||
|
||||
// A playable class should have a description
|
||||
if (class_.mData.mIsPlayable != 0 && class_.mDescription.empty())
|
||||
messages.push_back (std::make_pair (id, class_.mId + " doesn't have a description and it's playable"));
|
||||
|
||||
// test for invalid attributes
|
||||
for (int i=0; i<2; ++i)
|
||||
|
|
|
@ -11,11 +11,6 @@ namespace CSMWorld
|
|||
|
||||
bool LandTextureTableProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const
|
||||
{
|
||||
int columnIndex = mSourceModel->findColumnIndex(Columns::ColumnId_Modification);
|
||||
QModelIndex index = mSourceModel->index(sourceRow, columnIndex);
|
||||
if (mSourceModel->data(index).toInt() != RecordBase::State_ModifiedOnly)
|
||||
return false;
|
||||
|
||||
return IdTableProxyModel::filterAcceptsRow(sourceRow, sourceParent);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -551,7 +551,7 @@ void CSVRender::InstanceMode::dropEvent (QDropEvent* event)
|
|||
|
||||
if (noCell)
|
||||
{
|
||||
std::string mode = CSMPrefs::get()["Scene Drops"]["outside-drop"].toString();
|
||||
std::string mode = CSMPrefs::get()["3D Scene Editing"]["outside-drop"].toString();
|
||||
|
||||
// target cell does not exist
|
||||
if (mode=="Discard")
|
||||
|
@ -585,7 +585,7 @@ void CSVRender::InstanceMode::dropEvent (QDropEvent* event)
|
|||
{
|
||||
// target cell exists, but is not shown
|
||||
std::string mode =
|
||||
CSMPrefs::get()["Scene Drops"]["outside-visible-drop"].toString();
|
||||
CSMPrefs::get()["3D Scene Editing"]["outside-visible-drop"].toString();
|
||||
|
||||
if (mode=="Discard")
|
||||
return;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "mask.hpp"
|
||||
#include "cameracontroller.hpp"
|
||||
#include "cellarrow.hpp"
|
||||
#include "terraintexturemode.hpp"
|
||||
|
||||
bool CSVRender::PagedWorldspaceWidget::adjustCells()
|
||||
{
|
||||
|
@ -136,7 +137,7 @@ void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons (
|
|||
new EditMode (this, QIcon (":placeholder"), Mask_Reference, "Terrain shape editing"),
|
||||
"terrain-shape");
|
||||
tool->addButton (
|
||||
new EditMode (this, QIcon (":placeholder"), Mask_Reference, "Terrain texture editing"),
|
||||
new TerrainTextureMode (this, tool),
|
||||
"terrain-texture");
|
||||
tool->addButton (
|
||||
new EditMode (this, QIcon (":placeholder"), Mask_Reference, "Terrain vertex paint editing"),
|
||||
|
|
542
apps/opencs/view/render/terraintexturemode.cpp
Normal file
542
apps/opencs/view/render/terraintexturemode.cpp
Normal file
|
@ -0,0 +1,542 @@
|
|||
#include "terraintexturemode.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include <QWidget>
|
||||
#include <QIcon>
|
||||
#include <QEvent>
|
||||
#include <QDropEvent>
|
||||
#include <QDragEnterEvent>
|
||||
#include <QDrag>
|
||||
|
||||
#include <components/esm/loadland.hpp>
|
||||
|
||||
#include "../widget/modebutton.hpp"
|
||||
#include "../widget/scenetoolbar.hpp"
|
||||
#include "../widget/scenetooltexturebrush.hpp"
|
||||
|
||||
#include "../../model/doc/document.hpp"
|
||||
#include "../../model/prefs/state.hpp"
|
||||
#include "../../model/world/columnbase.hpp"
|
||||
#include "../../model/world/commandmacro.hpp"
|
||||
#include "../../model/world/commands.hpp"
|
||||
#include "../../model/world/data.hpp"
|
||||
#include "../../model/world/idtable.hpp"
|
||||
#include "../../model/world/idtree.hpp"
|
||||
#include "../../model/world/land.hpp"
|
||||
#include "../../model/world/landtexture.hpp"
|
||||
#include "../../model/world/resourcetable.hpp"
|
||||
#include "../../model/world/tablemimedata.hpp"
|
||||
#include "../../model/world/universalid.hpp"
|
||||
|
||||
#include "editmode.hpp"
|
||||
#include "pagedworldspacewidget.hpp"
|
||||
#include "mask.hpp"
|
||||
#include "object.hpp" // Something small needed regarding pointers from here ()
|
||||
#include "worldspacewidget.hpp"
|
||||
|
||||
CSVRender::TerrainTextureMode::TerrainTextureMode (WorldspaceWidget *worldspaceWidget, QWidget *parent)
|
||||
: EditMode (worldspaceWidget, QIcon {":scenetoolbar/editing-terrain-texture"}, Mask_Terrain | Mask_Reference, "Terrain texture editing", parent),
|
||||
mBrushTexture("L0#0"),
|
||||
mBrushSize(0),
|
||||
mBrushShape(0),
|
||||
mTextureBrushScenetool(0)
|
||||
{
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::activate(CSVWidget::SceneToolbar* toolbar)
|
||||
{
|
||||
if(!mTextureBrushScenetool)
|
||||
{
|
||||
mTextureBrushScenetool = new CSVWidget::SceneToolTextureBrush (toolbar, "scenetooltexturebrush", getWorldspaceWidget().getDocument());
|
||||
connect(mTextureBrushScenetool, SIGNAL (clicked()), mTextureBrushScenetool, SLOT (activate()));
|
||||
connect(mTextureBrushScenetool->mTextureBrushWindow, SIGNAL(passBrushSize(int)), this, SLOT(setBrushSize(int)));
|
||||
connect(mTextureBrushScenetool->mTextureBrushWindow, SIGNAL(passBrushShape(int)), this, SLOT(setBrushShape(int)));
|
||||
connect(mTextureBrushScenetool->mTextureBrushWindow->mSizeSliders->mBrushSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(setBrushSize(int)));
|
||||
connect(mTextureBrushScenetool, SIGNAL(passTextureId(std::string)), this, SLOT(setBrushTexture(std::string)));
|
||||
connect(mTextureBrushScenetool->mTextureBrushWindow, SIGNAL(passTextureId(std::string)), this, SLOT(setBrushTexture(std::string)));
|
||||
|
||||
connect(mTextureBrushScenetool, SIGNAL(passEvent(QDropEvent*)), this, SLOT(handleDropEvent(QDropEvent*)));
|
||||
connect(this, SIGNAL(passBrushTexture(std::string)), mTextureBrushScenetool->mTextureBrushWindow, SLOT(setBrushTexture(std::string)));
|
||||
connect(this, SIGNAL(passBrushTexture(std::string)), mTextureBrushScenetool, SLOT(updateBrushHistory(std::string)));
|
||||
}
|
||||
|
||||
EditMode::activate(toolbar);
|
||||
toolbar->addTool (mTextureBrushScenetool);
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::deactivate(CSVWidget::SceneToolbar* toolbar)
|
||||
{
|
||||
if(mTextureBrushScenetool)
|
||||
{
|
||||
toolbar->removeTool (mTextureBrushScenetool);
|
||||
delete mTextureBrushScenetool;
|
||||
mTextureBrushScenetool = 0;
|
||||
}
|
||||
EditMode::deactivate(toolbar);
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::primaryEditPressed(const WorldspaceHitResult& hit) // Apply changes here
|
||||
{
|
||||
CSMDoc::Document& document = getWorldspaceWidget().getDocument();
|
||||
CSMWorld::IdTable& landTable = dynamic_cast<CSMWorld::IdTable&> (
|
||||
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Land));
|
||||
CSMWorld::IdTable& ltexTable = dynamic_cast<CSMWorld::IdTable&> (
|
||||
*document.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures));
|
||||
|
||||
mCellId = getWorldspaceWidget().getCellId (hit.worldPos);
|
||||
|
||||
QUndoStack& undoStack = document.getUndoStack();
|
||||
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = document.getData().getLandTextures();
|
||||
int index = landtexturesCollection.searchId(mBrushTexture);
|
||||
|
||||
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted() && hit.hit == true)
|
||||
{
|
||||
undoStack.beginMacro ("Edit texture records");
|
||||
if(allowLandTextureEditing(mCellId)==true)
|
||||
{
|
||||
undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, mCellId));
|
||||
editTerrainTextureGrid(hit);
|
||||
}
|
||||
undoStack.endMacro();
|
||||
}
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::primarySelectPressed(const WorldspaceHitResult& hit)
|
||||
{
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::secondarySelectPressed(const WorldspaceHitResult& hit)
|
||||
{
|
||||
}
|
||||
|
||||
bool CSVRender::TerrainTextureMode::primaryEditStartDrag (const QPoint& pos)
|
||||
{
|
||||
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
|
||||
|
||||
CSMDoc::Document& document = getWorldspaceWidget().getDocument();
|
||||
CSMWorld::IdTable& landTable = dynamic_cast<CSMWorld::IdTable&> (
|
||||
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Land));
|
||||
CSMWorld::IdTable& ltexTable = dynamic_cast<CSMWorld::IdTable&> (
|
||||
*document.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures));
|
||||
|
||||
mCellId = getWorldspaceWidget().getCellId (hit.worldPos);
|
||||
|
||||
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.beginMacro ("Edit texture records");
|
||||
if(allowLandTextureEditing(mCellId)==true && hit.hit == true)
|
||||
{
|
||||
undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, mCellId));
|
||||
editTerrainTextureGrid(hit);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSVRender::TerrainTextureMode::secondaryEditStartDrag (const QPoint& pos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CSVRender::TerrainTextureMode::primarySelectStartDrag (const QPoint& pos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CSVRender::TerrainTextureMode::secondarySelectStartDrag (const QPoint& pos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::drag (const QPoint& pos, int diffX, int diffY, double speedFactor)
|
||||
{
|
||||
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::dragCompleted(const QPoint& pos) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::dragAborted() {
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::dragWheel (int diff, double speedFactor) {}
|
||||
|
||||
void CSVRender::TerrainTextureMode::handleDropEvent (QDropEvent *event) {
|
||||
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
|
||||
|
||||
if (!mime) // May happen when non-records (e.g. plain text) are dragged and dropped
|
||||
return;
|
||||
|
||||
if (mime->holdsType (CSMWorld::UniversalId::Type_LandTexture))
|
||||
{
|
||||
const std::vector<CSMWorld::UniversalId> ids = mime->getData();
|
||||
|
||||
for (const CSMWorld::UniversalId& uid : ids)
|
||||
{
|
||||
mBrushTexture = uid.getId();
|
||||
emit passBrushTexture(mBrushTexture);
|
||||
}
|
||||
}
|
||||
if (mime->holdsType (CSMWorld::UniversalId::Type_Texture))
|
||||
{
|
||||
const std::vector<CSMWorld::UniversalId> ids = mime->getData();
|
||||
|
||||
for (const CSMWorld::UniversalId& uid : ids)
|
||||
{
|
||||
std::string textureFileName = uid.toString();
|
||||
createTexture(textureFileName);
|
||||
emit passBrushTexture(mBrushTexture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitResult& hit)
|
||||
{
|
||||
CSMDoc::Document& document = getWorldspaceWidget().getDocument();
|
||||
CSMWorld::IdTable& landTable = dynamic_cast<CSMWorld::IdTable&> (
|
||||
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Land));
|
||||
|
||||
mCellId = getWorldspaceWidget().getCellId (hit.worldPos);
|
||||
if(allowLandTextureEditing(mCellId)==true) {}
|
||||
|
||||
std::pair<CSMWorld::CellCoordinates, bool> cellCoordinates_pair = CSMWorld::CellCoordinates::fromId (mCellId);
|
||||
|
||||
int cellX = cellCoordinates_pair.first.getX();
|
||||
int cellY = cellCoordinates_pair.first.getY();
|
||||
|
||||
// The coordinates of hit in mCellId
|
||||
int xHitInCell (float(((hit.worldPos.x() - (cellX* cellSize)) * landTextureSize / cellSize) - 0.5));
|
||||
int yHitInCell (float(((hit.worldPos.y() - (cellY* cellSize)) * landTextureSize / cellSize) + 0.5));
|
||||
if (xHitInCell < 0)
|
||||
{
|
||||
xHitInCell = xHitInCell + landTextureSize;
|
||||
cellX = cellX - 1;
|
||||
}
|
||||
if (yHitInCell > 15)
|
||||
{
|
||||
yHitInCell = yHitInCell - landTextureSize;
|
||||
cellY = cellY + 1;
|
||||
}
|
||||
|
||||
mCellId = "#" + std::to_string(cellX) + " " + std::to_string(cellY);
|
||||
if(allowLandTextureEditing(mCellId)==true) {}
|
||||
|
||||
std::string iteratedCellId;
|
||||
|
||||
int textureColumn = landTable.findColumnIndex(CSMWorld::Columns::ColumnId_LandTexturesIndex);
|
||||
|
||||
std::size_t hashlocation = mBrushTexture.find("#");
|
||||
std::string mBrushTextureInt = mBrushTexture.substr (hashlocation+1);
|
||||
int brushInt = stoi(mBrushTexture.substr (hashlocation+1))+1; // All indices are offset by +1
|
||||
|
||||
float rf = mBrushSize/2;
|
||||
int r = (mBrushSize/2)+1;
|
||||
float distance = 0;
|
||||
|
||||
if (mBrushShape == 0)
|
||||
{
|
||||
CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(mCellId, textureColumn)).value<CSMWorld::LandTexturesColumn::DataType>();
|
||||
CSMWorld::LandTexturesColumn::DataType mNew(mPointer);
|
||||
|
||||
if(allowLandTextureEditing(mCellId)==true)
|
||||
{
|
||||
mNew[yHitInCell*landTextureSize+xHitInCell] = brushInt;
|
||||
pushEditToCommand(mNew, document, landTable, mCellId);
|
||||
}
|
||||
}
|
||||
|
||||
if (mBrushShape == 1)
|
||||
{
|
||||
int upperLeftCellX = cellX - std::floor(r / landTextureSize);
|
||||
int upperLeftCellY = cellY - std::floor(r / landTextureSize);
|
||||
if (xHitInCell - (r % landTextureSize) < 0) upperLeftCellX--;
|
||||
if (yHitInCell - (r % landTextureSize) < 0) upperLeftCellY--;
|
||||
|
||||
int lowerrightCellX = cellX + std::floor(r / landTextureSize);
|
||||
int lowerrightCellY = cellY + std::floor(r / landTextureSize);
|
||||
if (xHitInCell + (r % landTextureSize) > landTextureSize - 1) lowerrightCellX++;
|
||||
if (yHitInCell + (r % landTextureSize) > landTextureSize - 1) lowerrightCellY++;
|
||||
|
||||
for(int i_cell = upperLeftCellX; i_cell <= lowerrightCellX; i_cell++)
|
||||
{
|
||||
for(int j_cell = upperLeftCellY; j_cell <= lowerrightCellY; j_cell++)
|
||||
{
|
||||
iteratedCellId = "#" + std::to_string(i_cell) + " " + std::to_string(j_cell);
|
||||
if(allowLandTextureEditing(iteratedCellId)==true)
|
||||
{
|
||||
CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(iteratedCellId, textureColumn)).value<CSMWorld::LandTexturesColumn::DataType>();
|
||||
CSMWorld::LandTexturesColumn::DataType mNew(mPointer);
|
||||
for(int i = 0; i < landTextureSize; i++)
|
||||
{
|
||||
for(int j = 0; j < landTextureSize; j++)
|
||||
{
|
||||
|
||||
if (i_cell == cellX && j_cell == cellY && abs(i-xHitInCell) < r && abs(j-yHitInCell) < r)
|
||||
{
|
||||
mNew[j*landTextureSize+i] = brushInt;
|
||||
}
|
||||
else
|
||||
{
|
||||
int distanceX(0);
|
||||
int distanceY(0);
|
||||
if (i_cell < cellX) distanceX = xHitInCell + landTextureSize * abs(i_cell-cellX) - i;
|
||||
if (j_cell < cellY) distanceY = yHitInCell + landTextureSize * abs(j_cell-cellY) - j;
|
||||
if (i_cell > cellX) distanceX = -xHitInCell + landTextureSize * abs(i_cell-cellX) + i;
|
||||
if (j_cell > cellY) distanceY = -yHitInCell + landTextureSize * abs(j_cell-cellY) + j;
|
||||
if (i_cell == cellX) distanceX = abs(i-xHitInCell);
|
||||
if (j_cell == cellY) distanceY = abs(j-yHitInCell);
|
||||
if (distanceX < r && distanceY < r) mNew[j*landTextureSize+i] = brushInt;
|
||||
}
|
||||
}
|
||||
}
|
||||
pushEditToCommand(mNew, document, landTable, iteratedCellId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mBrushShape == 2)
|
||||
{
|
||||
int upperLeftCellX = cellX - std::floor(r / landTextureSize);
|
||||
int upperLeftCellY = cellY - std::floor(r / landTextureSize);
|
||||
if (xHitInCell - (r % landTextureSize) < 0) upperLeftCellX--;
|
||||
if (yHitInCell - (r % landTextureSize) < 0) upperLeftCellY--;
|
||||
|
||||
int lowerrightCellX = cellX + std::floor(r / landTextureSize);
|
||||
int lowerrightCellY = cellY + std::floor(r / landTextureSize);
|
||||
if (xHitInCell + (r % landTextureSize) > landTextureSize - 1) lowerrightCellX++;
|
||||
if (yHitInCell + (r % landTextureSize) > landTextureSize - 1) lowerrightCellY++;
|
||||
|
||||
for(int i_cell = upperLeftCellX; i_cell <= lowerrightCellX; i_cell++)
|
||||
{
|
||||
for(int j_cell = upperLeftCellY; j_cell <= lowerrightCellY; j_cell++)
|
||||
{
|
||||
iteratedCellId = "#" + std::to_string(i_cell) + " " + std::to_string(j_cell);
|
||||
if(allowLandTextureEditing(iteratedCellId)==true)
|
||||
{
|
||||
CSMWorld::LandTexturesColumn::DataType mPointer = landTable.data(landTable.getModelIndex(iteratedCellId, textureColumn)).value<CSMWorld::LandTexturesColumn::DataType>();
|
||||
CSMWorld::LandTexturesColumn::DataType mNew(mPointer);
|
||||
for(int i = 0; i < landTextureSize; i++)
|
||||
{
|
||||
for(int j = 0; j < landTextureSize; j++)
|
||||
{
|
||||
|
||||
if (i_cell == cellX && j_cell == cellY && abs(i-xHitInCell) < r && abs(j-yHitInCell) < r)
|
||||
{
|
||||
int distanceX(0);
|
||||
int distanceY(0);
|
||||
if (i_cell < cellX) distanceX = xHitInCell + landTextureSize * abs(i_cell-cellX) - i;
|
||||
if (j_cell < cellY) distanceY = yHitInCell + landTextureSize * abs(j_cell-cellY) - j;
|
||||
if (i_cell > cellX) distanceX = -xHitInCell + landTextureSize* abs(i_cell-cellX) + i;
|
||||
if (j_cell > cellY) distanceY = -yHitInCell + landTextureSize * abs(j_cell-cellY) + j;
|
||||
if (i_cell == cellX) distanceX = abs(i-xHitInCell);
|
||||
if (j_cell == cellY) distanceY = abs(j-yHitInCell);
|
||||
distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2)));
|
||||
if (distance < rf) mNew[j*landTextureSize+i] = brushInt;
|
||||
}
|
||||
else
|
||||
{
|
||||
int distanceX(0);
|
||||
int distanceY(0);
|
||||
if (i_cell < cellX) distanceX = xHitInCell + landTextureSize * abs(i_cell-cellX) - i;
|
||||
if (j_cell < cellY) distanceY = yHitInCell + landTextureSize * abs(j_cell-cellY) - j;
|
||||
if (i_cell > cellX) distanceX = -xHitInCell + landTextureSize * abs(i_cell-cellX) + i;
|
||||
if (j_cell > cellY) distanceY = -yHitInCell + landTextureSize * abs(j_cell-cellY) + j;
|
||||
if (i_cell == cellX) distanceX = abs(i-xHitInCell);
|
||||
if (j_cell == cellY) distanceY = abs(j-yHitInCell);
|
||||
distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2)));
|
||||
if (distance < rf) mNew[j*landTextureSize+i] = brushInt;
|
||||
}
|
||||
}
|
||||
}
|
||||
pushEditToCommand(mNew, document, landTable, iteratedCellId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mBrushShape == 3)
|
||||
{
|
||||
// Not implemented
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::pushEditToCommand(CSMWorld::LandTexturesColumn::DataType& newLandGrid, CSMDoc::Document& document,
|
||||
CSMWorld::IdTable& landTable, std::string cellId)
|
||||
{
|
||||
CSMWorld::IdTable& ltexTable = dynamic_cast<CSMWorld::IdTable&> (
|
||||
*document.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures));
|
||||
|
||||
QVariant changedLand;
|
||||
changedLand.setValue(newLandGrid);
|
||||
|
||||
QModelIndex index(landTable.getModelIndex (cellId, landTable.findColumnIndex (CSMWorld::Columns::ColumnId_LandTexturesIndex)));
|
||||
|
||||
QUndoStack& undoStack = document.getUndoStack();
|
||||
undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, cellId));
|
||||
undoStack.push (new CSMWorld::ModifyCommand(landTable, index, changedLand));
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::createTexture(std::string textureFileName)
|
||||
{
|
||||
CSMDoc::Document& document = getWorldspaceWidget().getDocument();
|
||||
|
||||
CSMWorld::IdTable& ltexTable = dynamic_cast<CSMWorld::IdTable&> (
|
||||
*document.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures));
|
||||
|
||||
QUndoStack& undoStack = document.getUndoStack();
|
||||
|
||||
std::string newId;
|
||||
|
||||
int counter=0;
|
||||
bool freeIndexFound = false;
|
||||
do {
|
||||
const size_t maxCounter = std::numeric_limits<uint16_t>::max() - 1;
|
||||
try
|
||||
{
|
||||
newId = CSMWorld::LandTexture::createUniqueRecordId(0, counter);
|
||||
if (ltexTable.getRecord(newId).isDeleted() == 0) counter = (counter + 1) % maxCounter;
|
||||
} catch (const std::exception& e)
|
||||
{
|
||||
newId = CSMWorld::LandTexture::createUniqueRecordId(0, counter);
|
||||
freeIndexFound = true;
|
||||
}
|
||||
} while (freeIndexFound == false);
|
||||
|
||||
std::size_t idlocation = textureFileName.find("Texture: ");
|
||||
textureFileName = textureFileName.substr (idlocation + 9);
|
||||
|
||||
QVariant textureNameVariant;
|
||||
|
||||
QVariant textureFileNameVariant;
|
||||
textureFileNameVariant.setValue(QString::fromStdString(textureFileName));
|
||||
|
||||
undoStack.beginMacro ("Add land texture record");
|
||||
|
||||
undoStack.push (new CSMWorld::CreateCommand (ltexTable, newId));
|
||||
QModelIndex index(ltexTable.getModelIndex (newId, ltexTable.findColumnIndex (CSMWorld::Columns::ColumnId_Texture)));
|
||||
undoStack.push (new CSMWorld::ModifyCommand(ltexTable, index, textureFileNameVariant));
|
||||
undoStack.endMacro();
|
||||
mBrushTexture = newId;
|
||||
}
|
||||
|
||||
bool CSVRender::TerrainTextureMode::allowLandTextureEditing(std::string cellId)
|
||||
{
|
||||
CSMDoc::Document& document = getWorldspaceWidget().getDocument();
|
||||
CSMWorld::IdTable& landTable = dynamic_cast<CSMWorld::IdTable&> (
|
||||
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Land));
|
||||
CSMWorld::IdTree& cellTable = dynamic_cast<CSMWorld::IdTree&> (
|
||||
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells));
|
||||
|
||||
bool noCell = document.getData().getCells().searchId (cellId)==-1;
|
||||
bool noLand = document.getData().getLand().searchId (cellId)==-1;
|
||||
|
||||
if (noCell)
|
||||
{
|
||||
std::string mode = CSMPrefs::get()["3D Scene Editing"]["outside-landedit"].toString();
|
||||
|
||||
// target cell does not exist
|
||||
if (mode=="Discard")
|
||||
return false;
|
||||
|
||||
if (mode=="Create cell and land, then edit")
|
||||
{
|
||||
std::unique_ptr<CSMWorld::CreateCommand> createCommand (
|
||||
new CSMWorld::CreateCommand (cellTable, cellId));
|
||||
int parentIndex = cellTable.findColumnIndex (CSMWorld::Columns::ColumnId_Cell);
|
||||
int index = cellTable.findNestedColumnIndex (parentIndex, CSMWorld::Columns::ColumnId_Interior);
|
||||
createCommand->addNestedValue (parentIndex, index, false);
|
||||
document.getUndoStack().push (createCommand.release());
|
||||
|
||||
if (CSVRender::PagedWorldspaceWidget *paged =
|
||||
dynamic_cast<CSVRender::PagedWorldspaceWidget *> (&getWorldspaceWidget()))
|
||||
{
|
||||
CSMWorld::CellSelection selection = paged->getCellSelection();
|
||||
selection.add (CSMWorld::CellCoordinates::fromId (cellId).first);
|
||||
paged->setCellSelection (selection);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (CSVRender::PagedWorldspaceWidget *paged =
|
||||
dynamic_cast<CSVRender::PagedWorldspaceWidget *> (&getWorldspaceWidget()))
|
||||
{
|
||||
CSMWorld::CellSelection selection = paged->getCellSelection();
|
||||
if (!selection.has (CSMWorld::CellCoordinates::fromId (cellId).first))
|
||||
{
|
||||
// target cell exists, but is not shown
|
||||
std::string mode =
|
||||
CSMPrefs::get()["3D Scene Editing"]["outside-visible-landedit"].toString();
|
||||
|
||||
if (mode=="Discard")
|
||||
return false;
|
||||
|
||||
if (mode=="Show cell and edit")
|
||||
{
|
||||
selection.add (CSMWorld::CellCoordinates::fromId (cellId).first);
|
||||
paged->setCellSelection (selection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (noLand)
|
||||
{
|
||||
std::string mode = CSMPrefs::get()["3D Scene Editing"]["outside-landedit"].toString();
|
||||
|
||||
// target cell does not exist
|
||||
if (mode=="Discard")
|
||||
return false;
|
||||
|
||||
if (mode=="Create cell and land, then edit")
|
||||
{
|
||||
document.getUndoStack().push (new CSMWorld::CreateCommand (landTable, cellId));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::dragMoveEvent (QDragMoveEvent *event) {
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::setBrushSize(int brushSize)
|
||||
{
|
||||
mBrushSize = brushSize;
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::setBrushShape(int brushShape)
|
||||
{
|
||||
mBrushShape = brushShape;
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::setBrushTexture(std::string brushTexture)
|
||||
{
|
||||
mBrushTexture = brushTexture;
|
||||
}
|
100
apps/opencs/view/render/terraintexturemode.hpp
Normal file
100
apps/opencs/view/render/terraintexturemode.hpp
Normal file
|
@ -0,0 +1,100 @@
|
|||
#ifndef CSV_RENDER_TERRAINTEXTUREMODE_H
|
||||
#define CSV_RENDER_TERRAINTEXTUREMODE_H
|
||||
|
||||
#include "editmode.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <QWidget>
|
||||
#include <QEvent>
|
||||
|
||||
#include "../../model/world/data.hpp"
|
||||
#include "../../model/world/land.hpp"
|
||||
|
||||
#include "../../model/doc/document.hpp"
|
||||
#include "../../model/world/commands.hpp"
|
||||
#include "../../model/world/idtable.hpp"
|
||||
#include "../../model/world/landtexture.hpp"
|
||||
|
||||
namespace CSVWidget
|
||||
{
|
||||
class SceneToolTextureBrush;
|
||||
}
|
||||
|
||||
namespace CSVRender
|
||||
{
|
||||
|
||||
class TerrainTextureMode : public EditMode
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Editmode for terrain texture grid
|
||||
TerrainTextureMode(WorldspaceWidget*, QWidget* parent = nullptr);
|
||||
|
||||
/// \brief Create single command for one-click texture editing
|
||||
void primaryEditPressed (const WorldspaceHitResult& hit);
|
||||
|
||||
/// \brief Open brush settings window
|
||||
void primarySelectPressed(const WorldspaceHitResult&);
|
||||
|
||||
void secondarySelectPressed(const WorldspaceHitResult&);
|
||||
|
||||
void activate(CSVWidget::SceneToolbar*);
|
||||
void deactivate(CSVWidget::SceneToolbar*);
|
||||
|
||||
/// \brief Start texture editing command macro
|
||||
virtual bool primaryEditStartDrag (const QPoint& pos);
|
||||
|
||||
virtual bool secondaryEditStartDrag (const QPoint& pos);
|
||||
virtual bool primarySelectStartDrag (const QPoint& pos);
|
||||
virtual bool secondarySelectStartDrag (const QPoint& pos);
|
||||
|
||||
/// \brief Handle texture edit behavior during dragging
|
||||
virtual void drag (const QPoint& pos, int diffX, int diffY, double speedFactor);
|
||||
|
||||
/// \brief End texture editing command macro
|
||||
virtual void dragCompleted(const QPoint& pos);
|
||||
|
||||
virtual void dragAborted();
|
||||
virtual void dragWheel (int diff, double speedFactor);
|
||||
virtual void dragMoveEvent (QDragMoveEvent *event);
|
||||
|
||||
/// \brief Handle brush mechanics, maths regarding worldspace hit etc.
|
||||
void editTerrainTextureGrid (const WorldspaceHitResult& hit);
|
||||
|
||||
/// \brief Push texture edits to command macro
|
||||
void pushEditToCommand (CSMWorld::LandTexturesColumn::DataType& newLandGrid, CSMDoc::Document& document,
|
||||
CSMWorld::IdTable& landTable, std::string cellId);
|
||||
|
||||
/// \brief Create new land texture record from texture asset
|
||||
void createTexture(std::string textureFileName);
|
||||
|
||||
/// \brief Create new cell and land if needed
|
||||
bool allowLandTextureEditing(std::string textureFileName);
|
||||
|
||||
private:
|
||||
std::string mCellId;
|
||||
std::string mBrushTexture;
|
||||
int mBrushSize;
|
||||
int mBrushShape;
|
||||
CSVWidget::SceneToolTextureBrush *mTextureBrushScenetool;
|
||||
|
||||
const int cellSize {ESM::Land::REAL_SIZE};
|
||||
const int landSize {ESM::Land::LAND_SIZE};
|
||||
const int landTextureSize {ESM::Land::LAND_TEXTURE_SIZE};
|
||||
|
||||
signals:
|
||||
void passBrushTexture(std::string brushTexture);
|
||||
|
||||
public slots:
|
||||
void handleDropEvent(QDropEvent *event);
|
||||
void setBrushSize(int brushSize);
|
||||
void setBrushShape(int brushShape);
|
||||
void setBrushTexture(std::string brushShape);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -445,7 +445,7 @@ CSVRender::WorldspaceHitResult CSVRender::WorldspaceWidget::mousePick (const QPo
|
|||
|
||||
// Default placement
|
||||
direction.normalize();
|
||||
direction *= CSMPrefs::get()["Scene Drops"]["distance"].toInt();
|
||||
direction *= CSMPrefs::get()["3D Scene Editing"]["distance"].toInt();
|
||||
|
||||
WorldspaceHitResult hit = { false, 0, 0, 0, 0, start + direction };
|
||||
return hit;
|
||||
|
@ -648,6 +648,12 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event)
|
|||
mDragX = event->posF().x();
|
||||
mDragY = height() - event->posF().y();
|
||||
#endif
|
||||
|
||||
if (mDragMode == InteractionType_PrimaryEdit)
|
||||
{
|
||||
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
|
||||
editMode.drag (event->pos(), mDragX, mDragY, mDragFactor); // note: terraintexturemode only uses pos
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
379
apps/opencs/view/widget/scenetooltexturebrush.cpp
Normal file
379
apps/opencs/view/widget/scenetooltexturebrush.cpp
Normal file
|
@ -0,0 +1,379 @@
|
|||
#include "scenetooltexturebrush.hpp"
|
||||
|
||||
#include <QFrame>
|
||||
#include <QIcon>
|
||||
#include <QTableWidget>
|
||||
#include <QHBoxLayout>
|
||||
|
||||
#include <QWidget>
|
||||
#include <QSpinBox>
|
||||
#include <QGroupBox>
|
||||
#include <QSlider>
|
||||
#include <QEvent>
|
||||
#include <QDropEvent>
|
||||
#include <QButtonGroup>
|
||||
#include <QVBoxLayout>
|
||||
#include <QDragEnterEvent>
|
||||
#include <QDrag>
|
||||
#include <QTableWidget>
|
||||
#include <QHeaderView>
|
||||
#include <QApplication>
|
||||
#include <QSizePolicy>
|
||||
|
||||
#include "scenetool.hpp"
|
||||
|
||||
#include "../../model/doc/document.hpp"
|
||||
#include "../../model/prefs/state.hpp"
|
||||
#include "../../model/world/commands.hpp"
|
||||
#include "../../model/world/data.hpp"
|
||||
#include "../../model/world/idcollection.hpp"
|
||||
#include "../../model/world/idtable.hpp"
|
||||
#include "../../model/world/landtexture.hpp"
|
||||
#include "../../model/world/universalid.hpp"
|
||||
|
||||
|
||||
CSVWidget::BrushSizeControls::BrushSizeControls(const QString &title, QWidget *parent)
|
||||
: QGroupBox(title, parent)
|
||||
{
|
||||
mBrushSizeSlider = new QSlider(Qt::Horizontal);
|
||||
mBrushSizeSlider->setTickPosition(QSlider::TicksBothSides);
|
||||
mBrushSizeSlider->setTickInterval(10);
|
||||
mBrushSizeSlider->setRange(1, CSMPrefs::get()["3D Scene Editing"]["texturebrush-maximumsize"].toInt());
|
||||
mBrushSizeSlider->setSingleStep(1);
|
||||
|
||||
mBrushSizeSpinBox = new QSpinBox;
|
||||
mBrushSizeSpinBox->setRange(1, CSMPrefs::get()["3D Scene Editing"]["texturebrush-maximumsize"].toInt());
|
||||
mBrushSizeSpinBox->setSingleStep(1);
|
||||
|
||||
mLayoutSliderSize = new QHBoxLayout;
|
||||
mLayoutSliderSize->addWidget(mBrushSizeSlider);
|
||||
mLayoutSliderSize->addWidget(mBrushSizeSpinBox);
|
||||
|
||||
connect(mBrushSizeSlider, SIGNAL(valueChanged(int)), mBrushSizeSpinBox, SLOT(setValue(int)));
|
||||
connect(mBrushSizeSpinBox, SIGNAL(valueChanged(int)), mBrushSizeSlider, SLOT(setValue(int)));
|
||||
|
||||
setLayout(mLayoutSliderSize);
|
||||
}
|
||||
|
||||
CSVWidget::TextureBrushWindow::TextureBrushWindow(CSMDoc::Document& document, QWidget *parent)
|
||||
: QFrame(parent, Qt::Popup),
|
||||
mBrushShape(0),
|
||||
mBrushSize(0),
|
||||
mBrushTexture("L0#0"),
|
||||
mDocument(document)
|
||||
{
|
||||
mBrushTextureLabel = "Selected texture: " + mBrushTexture + " ";
|
||||
|
||||
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = mDocument.getData().getLandTextures();
|
||||
|
||||
int landTextureFilename = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Texture);
|
||||
int index = landtexturesCollection.searchId(mBrushTexture);
|
||||
|
||||
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted())
|
||||
{
|
||||
mSelectedBrush = new QLabel(QString::fromStdString(mBrushTextureLabel) + landtexturesCollection.getData(index, landTextureFilename).value<QString>());
|
||||
} else
|
||||
{
|
||||
mBrushTextureLabel = "No selected texture or invalid texture";
|
||||
mSelectedBrush = new QLabel(QString::fromStdString(mBrushTextureLabel));
|
||||
}
|
||||
|
||||
mButtonPoint = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-point")), "", this);
|
||||
mButtonSquare = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-square")), "", this);
|
||||
mButtonCircle = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-circle")), "", this);
|
||||
mButtonCustom = new QPushButton(QIcon (QPixmap (":scenetoolbar/brush-custom")), "", this);
|
||||
|
||||
mSizeSliders = new BrushSizeControls("Brush size", this);
|
||||
|
||||
QVBoxLayout *layoutMain = new QVBoxLayout;
|
||||
layoutMain->setSpacing(0);
|
||||
layoutMain->setContentsMargins(4,0,4,4);
|
||||
|
||||
QHBoxLayout *layoutHorizontal = new QHBoxLayout;
|
||||
layoutHorizontal->setSpacing(0);
|
||||
layoutHorizontal->setContentsMargins (QMargins (0, 0, 0, 0));
|
||||
|
||||
configureButtonInitialSettings(mButtonPoint);
|
||||
configureButtonInitialSettings(mButtonSquare);
|
||||
configureButtonInitialSettings(mButtonCircle);
|
||||
configureButtonInitialSettings(mButtonCustom);
|
||||
|
||||
mButtonPoint->setToolTip (toolTipPoint);
|
||||
mButtonSquare->setToolTip (toolTipSquare);
|
||||
mButtonCircle->setToolTip (toolTipCircle);
|
||||
mButtonCustom->setToolTip (toolTipCustom);
|
||||
|
||||
QButtonGroup* brushButtonGroup = new QButtonGroup(this);
|
||||
brushButtonGroup->addButton(mButtonPoint);
|
||||
brushButtonGroup->addButton(mButtonSquare);
|
||||
brushButtonGroup->addButton(mButtonCircle);
|
||||
brushButtonGroup->addButton(mButtonCustom);
|
||||
|
||||
brushButtonGroup->setExclusive(true);
|
||||
|
||||
layoutHorizontal->addWidget(mButtonPoint, 0, Qt::AlignTop);
|
||||
layoutHorizontal->addWidget(mButtonSquare, 0, Qt::AlignTop);
|
||||
layoutHorizontal->addWidget(mButtonCircle, 0, Qt::AlignTop);
|
||||
layoutHorizontal->addWidget(mButtonCustom, 0, Qt::AlignTop);
|
||||
|
||||
mHorizontalGroupBox = new QGroupBox(tr(""));
|
||||
mHorizontalGroupBox->setLayout(layoutHorizontal);
|
||||
|
||||
layoutMain->addWidget(mHorizontalGroupBox);
|
||||
layoutMain->addWidget(mSizeSliders);
|
||||
layoutMain->addWidget(mSelectedBrush);
|
||||
|
||||
setLayout(layoutMain);
|
||||
|
||||
connect(mButtonPoint, SIGNAL(clicked()), this, SLOT(setBrushShape()));
|
||||
connect(mButtonSquare, SIGNAL(clicked()), this, SLOT(setBrushShape()));
|
||||
connect(mButtonCircle, SIGNAL(clicked()), this, SLOT(setBrushShape()));
|
||||
connect(mButtonCustom, SIGNAL(clicked()), this, SLOT(setBrushShape()));
|
||||
}
|
||||
|
||||
void CSVWidget::TextureBrushWindow::configureButtonInitialSettings(QPushButton *button)
|
||||
{
|
||||
button->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed));
|
||||
button->setContentsMargins (QMargins (0, 0, 0, 0));
|
||||
button->setIconSize (QSize (48-6, 48-6));
|
||||
button->setFixedSize (48, 48);
|
||||
button->setCheckable(true);
|
||||
}
|
||||
|
||||
void CSVWidget::TextureBrushWindow::setBrushTexture(std::string brushTexture)
|
||||
{
|
||||
mBrushTexture = brushTexture;
|
||||
|
||||
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = mDocument.getData().getLandTextures();
|
||||
|
||||
int landTextureFilename = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Texture);
|
||||
int columnModification = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Modification);
|
||||
int index = landtexturesCollection.searchId(mBrushTexture);
|
||||
|
||||
// Check if texture exists in current plugin
|
||||
if(landtexturesCollection.getData(index, columnModification).value<int>() == 0)
|
||||
{
|
||||
CSMWorld::IdTable& ltexTable = dynamic_cast<CSMWorld::IdTable&> (
|
||||
*mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures));
|
||||
|
||||
QUndoStack& undoStack = mDocument.getUndoStack();
|
||||
|
||||
QVariant textureFileNameVariant;
|
||||
textureFileNameVariant.setValue(landtexturesCollection.getData(index, landTextureFilename).value<QString>());
|
||||
|
||||
std::size_t hashlocation = mBrushTexture.find("#");
|
||||
std::string mBrushTexturePlugin = "L0#" + mBrushTexture.substr (hashlocation+1);
|
||||
int indexPlugin = landtexturesCollection.searchId(mBrushTexturePlugin);
|
||||
|
||||
// Reindex texture if needed
|
||||
if (indexPlugin != -1 && !landtexturesCollection.getRecord(indexPlugin).isDeleted())
|
||||
{
|
||||
int counter=0;
|
||||
bool freeIndexFound = false;
|
||||
do {
|
||||
const size_t maxCounter = std::numeric_limits<uint16_t>::max() - 1;
|
||||
mBrushTexturePlugin = CSMWorld::LandTexture::createUniqueRecordId(0, counter);
|
||||
if (landtexturesCollection.searchId(mBrushTexturePlugin) != -1 && landtexturesCollection.getRecord(mBrushTexturePlugin).isDeleted() == 0) counter = (counter + 1) % maxCounter;
|
||||
else freeIndexFound = true;
|
||||
} while (freeIndexFound == false);
|
||||
}
|
||||
|
||||
undoStack.beginMacro ("Add land texture record");
|
||||
undoStack.push (new CSMWorld::CloneCommand (ltexTable, mBrushTexture, mBrushTexturePlugin, CSMWorld::UniversalId::Type_LandTexture));
|
||||
undoStack.endMacro();
|
||||
mBrushTexture = mBrushTexturePlugin;
|
||||
emit passTextureId(mBrushTexture);
|
||||
}
|
||||
|
||||
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted())
|
||||
{
|
||||
mBrushTextureLabel = "Selected texture: " + mBrushTexture + " ";
|
||||
mSelectedBrush->setText(QString::fromStdString(mBrushTextureLabel) + landtexturesCollection.getData(index, landTextureFilename).value<QString>());
|
||||
} else
|
||||
{
|
||||
mBrushTextureLabel = "No selected texture or invalid texture";
|
||||
mSelectedBrush->setText(QString::fromStdString(mBrushTextureLabel));
|
||||
}
|
||||
|
||||
emit passBrushShape(mBrushShape); // update icon
|
||||
}
|
||||
|
||||
void CSVWidget::TextureBrushWindow::setBrushSize(int brushSize)
|
||||
{
|
||||
mBrushSize = brushSize;
|
||||
emit passBrushSize(mBrushSize);
|
||||
}
|
||||
|
||||
void CSVWidget::TextureBrushWindow::setBrushShape()
|
||||
{
|
||||
if(mButtonPoint->isChecked()) mBrushShape = 0;
|
||||
if(mButtonSquare->isChecked()) mBrushShape = 1;
|
||||
if(mButtonCircle->isChecked()) mBrushShape = 2;
|
||||
if(mButtonCustom->isChecked()) mBrushShape = 3;
|
||||
emit passBrushShape(mBrushShape);
|
||||
}
|
||||
|
||||
void CSVWidget::SceneToolTextureBrush::adjustToolTips()
|
||||
{
|
||||
}
|
||||
|
||||
CSVWidget::SceneToolTextureBrush::SceneToolTextureBrush (SceneToolbar *parent, const QString& toolTip, CSMDoc::Document& document)
|
||||
: SceneTool (parent, Type_TopAction),
|
||||
mToolTip (toolTip),
|
||||
mDocument (document),
|
||||
mTextureBrushWindow(new TextureBrushWindow(document, this))
|
||||
{
|
||||
mBrushHistory.resize(1);
|
||||
mBrushHistory[0] = "L0#0";
|
||||
|
||||
setAcceptDrops(true);
|
||||
connect(mTextureBrushWindow, SIGNAL(passBrushShape(int)), this, SLOT(setButtonIcon(int)));
|
||||
setButtonIcon(mTextureBrushWindow->mBrushShape);
|
||||
|
||||
mPanel = new QFrame (this, Qt::Popup);
|
||||
|
||||
QHBoxLayout *layout = new QHBoxLayout (mPanel);
|
||||
|
||||
layout->setContentsMargins (QMargins (0, 0, 0, 0));
|
||||
|
||||
mTable = new QTableWidget (0, 2, this);
|
||||
|
||||
mTable->setShowGrid (true);
|
||||
mTable->verticalHeader()->hide();
|
||||
mTable->horizontalHeader()->hide();
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
mTable->horizontalHeader()->setSectionResizeMode (0, QHeaderView::Stretch);
|
||||
mTable->horizontalHeader()->setSectionResizeMode (1, QHeaderView::Stretch);
|
||||
#else
|
||||
mTable->horizontalHeader()->setResizeMode (0, QHeaderView::Stretch);
|
||||
mTable->horizontalHeader()->setResizeMode (1, QHeaderView::Stretch);
|
||||
#endif
|
||||
mTable->setSelectionMode (QAbstractItemView::NoSelection);
|
||||
|
||||
layout->addWidget (mTable);
|
||||
|
||||
connect (mTable, SIGNAL (clicked (const QModelIndex&)),
|
||||
this, SLOT (clicked (const QModelIndex&)));
|
||||
|
||||
}
|
||||
|
||||
void CSVWidget::SceneToolTextureBrush::setButtonIcon (int brushShape)
|
||||
{
|
||||
QString tooltip = "Change brush settings <p>Currently selected: ";
|
||||
|
||||
switch (brushShape)
|
||||
{
|
||||
case 0:
|
||||
|
||||
setIcon (QIcon (QPixmap (":scenetoolbar/brush-point")));
|
||||
tooltip += mTextureBrushWindow->toolTipPoint;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
|
||||
setIcon (QIcon (QPixmap (":scenetoolbar/brush-square")));
|
||||
tooltip += mTextureBrushWindow->toolTipSquare;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
|
||||
setIcon (QIcon (QPixmap (":scenetoolbar/brush-circle")));
|
||||
tooltip += mTextureBrushWindow->toolTipCircle;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
|
||||
setIcon (QIcon (QPixmap (":scenetoolbar/brush-custom")));
|
||||
tooltip += mTextureBrushWindow->toolTipCustom;
|
||||
break;
|
||||
}
|
||||
|
||||
tooltip += "<p>(right click to access of previously used brush settings)";
|
||||
|
||||
|
||||
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = mDocument.getData().getLandTextures();
|
||||
|
||||
int landTextureFilename = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Texture);
|
||||
int index = landtexturesCollection.searchId(mTextureBrushWindow->mBrushTexture);
|
||||
|
||||
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted())
|
||||
{
|
||||
tooltip += "<p>Selected texture: " + QString::fromStdString(mTextureBrushWindow->mBrushTexture) + " ";
|
||||
|
||||
tooltip += landtexturesCollection.getData(index, landTextureFilename).value<QString>();
|
||||
} else
|
||||
{
|
||||
tooltip += "<p>No selected texture or invalid texture";
|
||||
}
|
||||
|
||||
tooltip += "<br>(drop texture here to change)";
|
||||
setToolTip (tooltip);
|
||||
}
|
||||
|
||||
void CSVWidget::SceneToolTextureBrush::showPanel (const QPoint& position)
|
||||
{
|
||||
updatePanel();
|
||||
mPanel->move (position);
|
||||
mPanel->show();
|
||||
}
|
||||
|
||||
void CSVWidget::SceneToolTextureBrush::updatePanel()
|
||||
{
|
||||
mTable->setRowCount (mBrushHistory.size());
|
||||
|
||||
for (int i = mBrushHistory.size()-1; i >= 0; --i)
|
||||
{
|
||||
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = mDocument.getData().getLandTextures();
|
||||
int landTextureFilename = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Texture);
|
||||
int index = landtexturesCollection.searchId(mBrushHistory[i]);
|
||||
|
||||
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted())
|
||||
{
|
||||
mTable->setItem (i, 1, new QTableWidgetItem (landtexturesCollection.getData(index, landTextureFilename).value<QString>()));
|
||||
mTable->setItem (i, 0, new QTableWidgetItem (QString::fromStdString(mBrushHistory[i])));
|
||||
} else
|
||||
{
|
||||
mTable->setItem (i, 1, new QTableWidgetItem ("Invalid/deleted texture"));
|
||||
mTable->setItem (i, 0, new QTableWidgetItem (QString::fromStdString(mBrushHistory[i])));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSVWidget::SceneToolTextureBrush::updateBrushHistory (const std::string& brushTexture)
|
||||
{
|
||||
mBrushHistory.insert(mBrushHistory.begin(), brushTexture);
|
||||
if(mBrushHistory.size() > 5) mBrushHistory.pop_back();
|
||||
}
|
||||
|
||||
void CSVWidget::SceneToolTextureBrush::clicked (const QModelIndex& index)
|
||||
{
|
||||
if (index.column()==0 || index.column()==1)
|
||||
{
|
||||
std::string brushTexture = mBrushHistory[index.row()];
|
||||
std::swap(mBrushHistory[index.row()], mBrushHistory[0]);
|
||||
mTextureBrushWindow->setBrushTexture(brushTexture);
|
||||
emit passTextureId(brushTexture);
|
||||
updatePanel();
|
||||
mPanel->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void CSVWidget::SceneToolTextureBrush::activate ()
|
||||
{
|
||||
QPoint position = QCursor::pos();
|
||||
mTextureBrushWindow->mSizeSliders->mBrushSizeSlider->setRange(1, CSMPrefs::get()["3D Scene Editing"]["texturebrush-maximumsize"].toInt());
|
||||
mTextureBrushWindow->mSizeSliders->mBrushSizeSpinBox->setRange(1, CSMPrefs::get()["3D Scene Editing"]["texturebrush-maximumsize"].toInt());
|
||||
mTextureBrushWindow->move (position);
|
||||
mTextureBrushWindow->show();
|
||||
}
|
||||
|
||||
void CSVWidget::SceneToolTextureBrush::dragEnterEvent (QDragEnterEvent *event)
|
||||
{
|
||||
emit passEvent(event);
|
||||
event->accept();
|
||||
}
|
||||
void CSVWidget::SceneToolTextureBrush::dropEvent (QDropEvent *event)
|
||||
{
|
||||
emit passEvent(event);
|
||||
event->accept();
|
||||
}
|
133
apps/opencs/view/widget/scenetooltexturebrush.hpp
Normal file
133
apps/opencs/view/widget/scenetooltexturebrush.hpp
Normal file
|
@ -0,0 +1,133 @@
|
|||
#ifndef CSV_WIDGET_SCENETOOLTEXTUREBRUSH_H
|
||||
#define CSV_WIDGET_SCENETOOLTEXTUREBRUSH_H
|
||||
|
||||
#include <QIcon>
|
||||
#include <QFrame>
|
||||
#include <QModelIndex>
|
||||
|
||||
#include <QWidget>
|
||||
#include <QLabel>
|
||||
#include <QSpinBox>
|
||||
#include <QGroupBox>
|
||||
#include <QSlider>
|
||||
#include <QEvent>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPushButton>
|
||||
|
||||
#include "scenetool.hpp"
|
||||
|
||||
#include "../../model/doc/document.hpp"
|
||||
|
||||
class QTableWidget;
|
||||
|
||||
namespace CSVRender
|
||||
{
|
||||
class TerrainTextureMode;
|
||||
}
|
||||
|
||||
namespace CSVWidget
|
||||
{
|
||||
class SceneToolTextureBrush;
|
||||
|
||||
/// \brief Layout-box for some brush button settings
|
||||
class BrushSizeControls : public QGroupBox
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
BrushSizeControls(const QString &title, QWidget *parent);
|
||||
|
||||
private:
|
||||
QHBoxLayout *mLayoutSliderSize;
|
||||
QSlider *mBrushSizeSlider;
|
||||
QSpinBox *mBrushSizeSpinBox;
|
||||
|
||||
friend class SceneToolTextureBrush;
|
||||
friend class CSVRender::TerrainTextureMode;
|
||||
};
|
||||
|
||||
class SceneToolTextureBrush;
|
||||
|
||||
/// \brief Brush settings window
|
||||
class TextureBrushWindow : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TextureBrushWindow(CSMDoc::Document& document, QWidget *parent = 0);
|
||||
void configureButtonInitialSettings(QPushButton *button);
|
||||
|
||||
const QString toolTipPoint = "Paint single point";
|
||||
const QString toolTipSquare = "Paint with square brush";
|
||||
const QString toolTipCircle = "Paint with circle brush";
|
||||
const QString toolTipCustom = "Paint custom selection (not implemented yet)";
|
||||
|
||||
private:
|
||||
int mBrushShape;
|
||||
int mBrushSize;
|
||||
std::string mBrushTexture;
|
||||
CSMDoc::Document& mDocument;
|
||||
QLabel *mSelectedBrush;
|
||||
QGroupBox *mHorizontalGroupBox;
|
||||
std::string mBrushTextureLabel;
|
||||
QPushButton *mButtonPoint;
|
||||
QPushButton *mButtonSquare;
|
||||
QPushButton *mButtonCircle;
|
||||
QPushButton *mButtonCustom;
|
||||
BrushSizeControls* mSizeSliders;
|
||||
|
||||
friend class SceneToolTextureBrush;
|
||||
friend class CSVRender::TerrainTextureMode;
|
||||
|
||||
public slots:
|
||||
void setBrushTexture(std::string brushTexture);
|
||||
void setBrushShape();
|
||||
void setBrushSize(int brushSize);
|
||||
|
||||
signals:
|
||||
void passBrushSize (int brushSize);
|
||||
void passBrushShape(int brushShape);
|
||||
void passTextureId(std::string brushTexture);
|
||||
};
|
||||
|
||||
class SceneToolTextureBrush : public SceneTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
QString mToolTip;
|
||||
CSMDoc::Document& mDocument;
|
||||
QFrame *mPanel;
|
||||
QTableWidget *mTable;
|
||||
std::vector<std::string> mBrushHistory;
|
||||
TextureBrushWindow *mTextureBrushWindow;
|
||||
|
||||
private:
|
||||
|
||||
void adjustToolTips();
|
||||
|
||||
public:
|
||||
|
||||
SceneToolTextureBrush (SceneToolbar *parent, const QString& toolTip, CSMDoc::Document& document);
|
||||
|
||||
virtual void showPanel (const QPoint& position);
|
||||
void updatePanel ();
|
||||
|
||||
void dropEvent (QDropEvent *event);
|
||||
void dragEnterEvent (QDragEnterEvent *event);
|
||||
|
||||
friend class CSVRender::TerrainTextureMode;
|
||||
|
||||
public slots:
|
||||
void setButtonIcon(int brushShape);
|
||||
void updateBrushHistory (const std::string& mBrushTexture);
|
||||
void clicked (const QModelIndex& index);
|
||||
virtual void activate();
|
||||
|
||||
signals:
|
||||
void passEvent(QDropEvent *event);
|
||||
void passEvent(QDragEnterEvent *event);
|
||||
void passTextureId(std::string brushTexture);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -338,6 +338,62 @@ LuaState::LuaState()
|
|||
});
|
||||
});
|
||||
|
||||
lua->set_function("setPlayerCollisionState", [](bool state) {
|
||||
|
||||
auto packet = mwmp::Networking::get().getWorldstatePacketController()->GetPacket(ID_WORLD_COLLISION_OVERRIDE);
|
||||
|
||||
tempWorldstate.hasPlayerCollision = state;
|
||||
|
||||
Players::for_each([&state, &packet](Player *player) {
|
||||
|
||||
tempWorldstate.guid = player->guid;
|
||||
packet->setWorldstate(&tempWorldstate);
|
||||
packet->Send(false);
|
||||
});
|
||||
});
|
||||
|
||||
lua->set_function("setActorCollisionState", [](bool state) {
|
||||
|
||||
auto packet = mwmp::Networking::get().getWorldstatePacketController()->GetPacket(ID_WORLD_COLLISION_OVERRIDE);
|
||||
|
||||
tempWorldstate.hasActorCollision = state;
|
||||
|
||||
Players::for_each([&state, &packet](Player *player) {
|
||||
|
||||
tempWorldstate.guid = player->guid;
|
||||
packet->setWorldstate(&tempWorldstate);
|
||||
packet->Send(false);
|
||||
});
|
||||
});
|
||||
|
||||
lua->set_function("setPlacedObjectCollisionState", [](bool state) {
|
||||
|
||||
auto packet = mwmp::Networking::get().getWorldstatePacketController()->GetPacket(ID_WORLD_COLLISION_OVERRIDE);
|
||||
|
||||
tempWorldstate.hasPlacedObjectCollision = state;
|
||||
|
||||
Players::for_each([&state, &packet](Player *player) {
|
||||
|
||||
tempWorldstate.guid = player->guid;
|
||||
packet->setWorldstate(&tempWorldstate);
|
||||
packet->Send(false);
|
||||
});
|
||||
});
|
||||
|
||||
lua->set_function("useActorCollisionForPlacedObjects", [](bool state) {
|
||||
|
||||
auto packet = mwmp::Networking::get().getWorldstatePacketController()->GetPacket(ID_WORLD_COLLISION_OVERRIDE);
|
||||
|
||||
tempWorldstate.useActorCollisionForPlacedObjects = state;
|
||||
|
||||
Players::for_each([&state, &packet](Player *player) {
|
||||
|
||||
tempWorldstate.guid = player->guid;
|
||||
packet->setWorldstate(&tempWorldstate);
|
||||
packet->Send(false);
|
||||
});
|
||||
});
|
||||
|
||||
lua->set_function("createChannel", [](){
|
||||
return mwmp::Networking::get().createChannel();
|
||||
});
|
||||
|
|
|
@ -98,7 +98,7 @@ add_openmw_dir (mwbase
|
|||
)
|
||||
|
||||
add_openmw_dir (mwmp Main Networking LocalPlayer DedicatedPlayer PlayerList LocalActor DedicatedActor ActorList ObjectList
|
||||
Cell CellController MechanicsHelper RecordHelper GUIController
|
||||
Worldstate Cell CellController MechanicsHelper RecordHelper GUIController
|
||||
)
|
||||
|
||||
add_openmw_dir (mwmp/GUI GUIChat GUILogin PlayerMarkerCollection GUIDialogList TextInputDialog GUICustomWindow
|
||||
|
@ -124,15 +124,15 @@ add_openmw_dir (mwmp/processors/player ProcessorChatMessage ProcessorGUIMessageB
|
|||
ProcessorPlayerSkill ProcessorPlayerSpeech ProcessorPlayerSpellbook ProcessorPlayerStatsDynamic ProcessorPlayerTopic
|
||||
)
|
||||
|
||||
add_openmw_dir (mwmp/processors/object BaseObjectProcessor ProcessorConsoleCommand ProcessorContainer ProcessorDoorDestination
|
||||
ProcessorDoorState ProcessorMusicPlay ProcessorVideoPlay ProcessorObjectAnimPlay ProcessorObjectAttach
|
||||
ProcessorObjectCollision ProcessorObjectDelete ProcessorObjectLock ProcessorObjectMove ProcessorObjectPlace
|
||||
ProcessorObjectReset ProcessorObjectRotate ProcessorObjectScale ProcessorObjectSpawn ProcessorObjectState
|
||||
ProcessorObjectTrap ProcessorScriptLocalShort ProcessorScriptLocalFloat ProcessorScriptMemberShort
|
||||
ProcessorScriptMemberFloat ProcessorScriptGlobalShort ProcessorScriptGlobalFloat
|
||||
add_openmw_dir (mwmp/processors/object BaseObjectProcessor ProcessorConsoleCommand ProcessorContainer
|
||||
ProcessorDoorDestination ProcessorDoorState ProcessorMusicPlay ProcessorVideoPlay ProcessorObjectAnimPlay
|
||||
ProcessorObjectAttach ProcessorObjectCollision ProcessorObjectDelete ProcessorObjectLock ProcessorObjectMove
|
||||
ProcessorObjectPlace ProcessorObjectReset ProcessorObjectRotate ProcessorObjectScale ProcessorObjectSpawn
|
||||
ProcessorObjectState ProcessorObjectTrap ProcessorScriptLocalShort ProcessorScriptLocalFloat
|
||||
ProcessorScriptMemberShort ProcessorScriptMemberFloat ProcessorScriptGlobalShort ProcessorScriptGlobalFloat
|
||||
)
|
||||
|
||||
add_openmw_dir (mwmp/processors/worldstate ProcessorRecordDynamic ProcessorWorldTime
|
||||
add_openmw_dir (mwmp/processors/worldstate ProcessorRecordDynamic ProcessorWorldCollisionOverride ProcessorWorldTime
|
||||
)
|
||||
|
||||
# Main executable
|
||||
|
|
|
@ -5,9 +5,6 @@
|
|||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/Node>
|
||||
|
||||
#include <components/esm/cellid.hpp>
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
|
@ -457,7 +454,6 @@ namespace MWBase
|
|||
virtual bool isUnderwater(const MWWorld::ConstPtr &object, const float heightRatio) const = 0;
|
||||
virtual bool isWaterWalkingCastableOnTarget(const MWWorld::ConstPtr &target) const = 0;
|
||||
virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0;
|
||||
virtual bool isIdle(const MWWorld::Ptr &ptr) const = 0;
|
||||
|
||||
virtual osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const = 0;
|
||||
|
||||
|
@ -624,7 +620,7 @@ namespace MWBase
|
|||
/// Spawn a blood effect for \a ptr at \a worldPosition
|
||||
virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition) = 0;
|
||||
|
||||
virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos, float scale = 1.f, bool isMagicVFX = true) = 0;
|
||||
virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos) = 0;
|
||||
|
||||
virtual void explodeSpell(const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster,
|
||||
const MWWorld::Ptr& ignore, ESM::RangeType rangeType, const std::string& id,
|
||||
|
@ -666,8 +662,6 @@ namespace MWBase
|
|||
|
||||
/// Preload VFX associated with this effect list
|
||||
virtual void preloadEffects(const ESM::EffectList* effectList) = 0;
|
||||
|
||||
virtual osg::ref_ptr<osg::Node> getInstance (const std::string& modelName) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
#include "apparatus.hpp"
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Include additional headers for multiplayer purposes
|
||||
*/
|
||||
#include "../mwmp/Main.hpp"
|
||||
#include "../mwmp/Networking.hpp"
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
#include <components/esm/loadappa.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -31,6 +42,27 @@ namespace MWClass
|
|||
void Apparatus::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
||||
{
|
||||
// TODO: add option somewhere to enable collision for placeable objects
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Make it possible to enable collision for this object class from a packet
|
||||
*/
|
||||
if (!model.empty())
|
||||
{
|
||||
mwmp::BaseWorldstate *worldstate = mwmp::Main::get().getNetworking()->getWorldstate();
|
||||
|
||||
if (worldstate->hasPlacedObjectCollision)
|
||||
{
|
||||
if (worldstate->useActorCollisionForPlacedObjects)
|
||||
physics.addObject(ptr, model, MWPhysics::CollisionType_Actor);
|
||||
else
|
||||
physics.addObject(ptr, model, MWPhysics::CollisionType_World);
|
||||
}
|
||||
}
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
}
|
||||
|
||||
std::string Apparatus::getModel(const MWWorld::ConstPtr &ptr) const
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
#include "armor.hpp"
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Include additional headers for multiplayer purposes
|
||||
*/
|
||||
#include "../mwmp/Main.hpp"
|
||||
#include "../mwmp/Networking.hpp"
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
#include <components/esm/loadarmo.hpp>
|
||||
#include <components/esm/loadskil.hpp>
|
||||
#include <components/esm/loadgmst.hpp>
|
||||
|
@ -37,6 +48,27 @@ namespace MWClass
|
|||
void Armor::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
||||
{
|
||||
// TODO: add option somewhere to enable collision for placeable objects
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Make it possible to enable collision for this object class from a packet
|
||||
*/
|
||||
if (!model.empty())
|
||||
{
|
||||
mwmp::BaseWorldstate *worldstate = mwmp::Main::get().getNetworking()->getWorldstate();
|
||||
|
||||
if (worldstate->hasPlacedObjectCollision)
|
||||
{
|
||||
if (worldstate->useActorCollisionForPlacedObjects)
|
||||
physics.addObject(ptr, model, MWPhysics::CollisionType_Actor);
|
||||
else
|
||||
physics.addObject(ptr, model, MWPhysics::CollisionType_World);
|
||||
}
|
||||
}
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
}
|
||||
|
||||
std::string Armor::getModel(const MWWorld::ConstPtr &ptr) const
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
#include "book.hpp"
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Include additional headers for multiplayer purposes
|
||||
*/
|
||||
#include "../mwmp/Main.hpp"
|
||||
#include "../mwmp/Networking.hpp"
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
#include <components/esm/loadbook.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -34,6 +45,27 @@ namespace MWClass
|
|||
void Book::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
||||
{
|
||||
// TODO: add option somewhere to enable collision for placeable objects
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Make it possible to enable collision for this object class from a packet
|
||||
*/
|
||||
if (!model.empty())
|
||||
{
|
||||
mwmp::BaseWorldstate *worldstate = mwmp::Main::get().getNetworking()->getWorldstate();
|
||||
|
||||
if (worldstate->hasPlacedObjectCollision)
|
||||
{
|
||||
if (worldstate->useActorCollisionForPlacedObjects)
|
||||
physics.addObject(ptr, model, MWPhysics::CollisionType_Actor);
|
||||
else
|
||||
physics.addObject(ptr, model, MWPhysics::CollisionType_World);
|
||||
}
|
||||
}
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
}
|
||||
|
||||
std::string Book::getModel(const MWWorld::ConstPtr &ptr) const
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
#include "clothing.hpp"
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Include additional headers for multiplayer purposes
|
||||
*/
|
||||
#include "../mwmp/Main.hpp"
|
||||
#include "../mwmp/Networking.hpp"
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
#include <components/esm/loadclot.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -33,6 +44,27 @@ namespace MWClass
|
|||
void Clothing::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
||||
{
|
||||
// TODO: add option somewhere to enable collision for placeable objects
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Make it possible to enable collision for this object class from a packet
|
||||
*/
|
||||
if (!model.empty())
|
||||
{
|
||||
mwmp::BaseWorldstate *worldstate = mwmp::Main::get().getNetworking()->getWorldstate();
|
||||
|
||||
if (worldstate->hasPlacedObjectCollision)
|
||||
{
|
||||
if (worldstate->useActorCollisionForPlacedObjects)
|
||||
physics.addObject(ptr, model, MWPhysics::CollisionType_Actor);
|
||||
else
|
||||
physics.addObject(ptr, model, MWPhysics::CollisionType_World);
|
||||
}
|
||||
}
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
}
|
||||
|
||||
std::string Clothing::getModel(const MWWorld::ConstPtr &ptr) const
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
#include "ingredient.hpp"
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Include additional headers for multiplayer purposes
|
||||
*/
|
||||
#include "../mwmp/Main.hpp"
|
||||
#include "../mwmp/Networking.hpp"
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
#include <components/esm/loadingr.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -34,6 +45,27 @@ namespace MWClass
|
|||
void Ingredient::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
||||
{
|
||||
// TODO: add option somewhere to enable collision for placeable objects
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Make it possible to enable collision for this object class from a packet
|
||||
*/
|
||||
if (!model.empty())
|
||||
{
|
||||
mwmp::BaseWorldstate *worldstate = mwmp::Main::get().getNetworking()->getWorldstate();
|
||||
|
||||
if (worldstate->hasPlacedObjectCollision)
|
||||
{
|
||||
if (worldstate->useActorCollisionForPlacedObjects)
|
||||
physics.addObject(ptr, model, MWPhysics::CollisionType_Actor);
|
||||
else
|
||||
physics.addObject(ptr, model, MWPhysics::CollisionType_World);
|
||||
}
|
||||
}
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
}
|
||||
|
||||
std::string Ingredient::getModel(const MWWorld::ConstPtr &ptr) const
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
#include "misc.hpp"
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Include additional headers for multiplayer purposes
|
||||
*/
|
||||
#include "../mwmp/Main.hpp"
|
||||
#include "../mwmp/Networking.hpp"
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
#include <components/esm/loadmisc.hpp>
|
||||
#include <components/settings/settings.hpp>
|
||||
|
||||
|
@ -41,6 +52,27 @@ namespace MWClass
|
|||
void Miscellaneous::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
||||
{
|
||||
// TODO: add option somewhere to enable collision for placeable objects
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Make it possible to enable collision for this object class from a packet
|
||||
*/
|
||||
if (!model.empty())
|
||||
{
|
||||
mwmp::BaseWorldstate *worldstate = mwmp::Main::get().getNetworking()->getWorldstate();
|
||||
|
||||
if (worldstate->hasPlacedObjectCollision)
|
||||
{
|
||||
if (worldstate->useActorCollisionForPlacedObjects)
|
||||
physics.addObject(ptr, model, MWPhysics::CollisionType_Actor);
|
||||
else
|
||||
physics.addObject(ptr, model, MWPhysics::CollisionType_World);
|
||||
}
|
||||
}
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
}
|
||||
|
||||
std::string Miscellaneous::getModel(const MWWorld::ConstPtr &ptr) const
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
#include "potion.hpp"
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Include additional headers for multiplayer purposes
|
||||
*/
|
||||
#include "../mwmp/Main.hpp"
|
||||
#include "../mwmp/Networking.hpp"
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
#include <components/esm/loadalch.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -35,6 +46,27 @@ namespace MWClass
|
|||
void Potion::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
||||
{
|
||||
// TODO: add option somewhere to enable collision for placeable objects
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Make it possible to enable collision for this object class from a packet
|
||||
*/
|
||||
if (!model.empty())
|
||||
{
|
||||
mwmp::BaseWorldstate *worldstate = mwmp::Main::get().getNetworking()->getWorldstate();
|
||||
|
||||
if (worldstate->hasPlacedObjectCollision)
|
||||
{
|
||||
if (worldstate->useActorCollisionForPlacedObjects)
|
||||
physics.addObject(ptr, model, MWPhysics::CollisionType_Actor);
|
||||
else
|
||||
physics.addObject(ptr, model, MWPhysics::CollisionType_World);
|
||||
}
|
||||
}
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
}
|
||||
|
||||
std::string Potion::getModel(const MWWorld::ConstPtr &ptr) const
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
#include "repair.hpp"
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Include additional headers for multiplayer purposes
|
||||
*/
|
||||
#include "../mwmp/Main.hpp"
|
||||
#include "../mwmp/Networking.hpp"
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
#include <components/esm/loadrepa.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -31,6 +42,27 @@ namespace MWClass
|
|||
void Repair::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
||||
{
|
||||
// TODO: add option somewhere to enable collision for placeable objects
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Make it possible to enable collision for this object class from a packet
|
||||
*/
|
||||
if (!model.empty())
|
||||
{
|
||||
mwmp::BaseWorldstate *worldstate = mwmp::Main::get().getNetworking()->getWorldstate();
|
||||
|
||||
if (worldstate->hasPlacedObjectCollision)
|
||||
{
|
||||
if (worldstate->useActorCollisionForPlacedObjects)
|
||||
physics.addObject(ptr, model, MWPhysics::CollisionType_Actor);
|
||||
else
|
||||
physics.addObject(ptr, model, MWPhysics::CollisionType_World);
|
||||
}
|
||||
}
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
}
|
||||
|
||||
std::string Repair::getModel(const MWWorld::ConstPtr &ptr) const
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
#include "weapon.hpp"
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Include additional headers for multiplayer purposes
|
||||
*/
|
||||
#include "../mwmp/Main.hpp"
|
||||
#include "../mwmp/Networking.hpp"
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
#include <components/esm/loadweap.hpp>
|
||||
#include <components/settings/settings.hpp>
|
||||
|
||||
|
@ -35,6 +46,27 @@ namespace MWClass
|
|||
void Weapon::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
|
||||
{
|
||||
// TODO: add option somewhere to enable collision for placeable objects
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Make it possible to enable collision for this object class from a packet
|
||||
*/
|
||||
if (!model.empty())
|
||||
{
|
||||
mwmp::BaseWorldstate *worldstate = mwmp::Main::get().getNetworking()->getWorldstate();
|
||||
|
||||
if (worldstate->hasPlacedObjectCollision)
|
||||
{
|
||||
if (worldstate->useActorCollisionForPlacedObjects)
|
||||
physics.addObject(ptr, model, MWPhysics::CollisionType_Actor);
|
||||
else
|
||||
physics.addObject(ptr, model, MWPhysics::CollisionType_World);
|
||||
}
|
||||
}
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
}
|
||||
|
||||
std::string Weapon::getModel(const MWWorld::ConstPtr &ptr) const
|
||||
|
|
|
@ -244,7 +244,7 @@ BookTypesetter::Ptr JournalBooks::createLatinJournalIndex ()
|
|||
const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours();
|
||||
BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic,
|
||||
textColours.journalTopicOver,
|
||||
textColours.journalTopicPressed, (uint32_t) ch);
|
||||
textColours.journalTopicPressed, (Utf8Stream::UnicodeChar) ch);
|
||||
|
||||
if (i == 13)
|
||||
typesetter->sectionBreak ();
|
||||
|
@ -274,7 +274,7 @@ BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex ()
|
|||
sprintf(buffer, "( %c%c )", ch[0], ch[1]);
|
||||
|
||||
Utf8Stream stream ((char*) ch);
|
||||
uint32_t first = stream.peek();
|
||||
Utf8Stream::UnicodeChar first = stream.peek();
|
||||
|
||||
const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours();
|
||||
BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic,
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
#include <components/translation/translation.hpp>
|
||||
#include <components/misc/stringops.hpp>
|
||||
#include <components/misc/utf8stream.hpp>
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/journal.hpp"
|
||||
|
@ -307,39 +306,22 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
visitor (toUtf8Span (topic.getName()));
|
||||
}
|
||||
|
||||
void visitTopicNamesStartingWith (uint32_t character, std::function < void (const std::string&) > visitor) const
|
||||
void visitTopicNamesStartingWith (Utf8Stream::UnicodeChar character, std::function < void (const std::string&) > visitor) const
|
||||
{
|
||||
MWBase::Journal * journal = MWBase::Environment::get().getJournal();
|
||||
|
||||
for (MWBase::Journal::TTopicIter i = journal->topicBegin (); i != journal->topicEnd (); ++i)
|
||||
{
|
||||
Utf8Stream stream (i->first.c_str());
|
||||
uint32_t first = toUpper(stream.peek());
|
||||
Utf8Stream::UnicodeChar first = Misc::StringUtils::toLowerUtf8(stream.peek());
|
||||
|
||||
if (first != character)
|
||||
if (first != Misc::StringUtils::toLowerUtf8(character))
|
||||
continue;
|
||||
|
||||
visitor (i->second.getName());
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t toUpper(uint32_t ch)
|
||||
{
|
||||
// Russian alphabet
|
||||
if (ch >= 0x0430 && ch < 0x0450)
|
||||
ch -= 0x20;
|
||||
|
||||
// Cyrillic IO character
|
||||
if (ch == 0x0451)
|
||||
ch -= 0x50;
|
||||
|
||||
// Latin alphabet
|
||||
if (ch >= 0x61 && ch < 0x80)
|
||||
ch -= 0x20;
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
struct TopicEntryImpl : BaseEntry <MWDialogue::Topic::TEntryIter, TopicEntry>
|
||||
{
|
||||
MWDialogue::Topic const & mTopic;
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include <functional>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <components/misc/utf8stream.hpp>
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
/// View-Model for the journal GUI
|
||||
|
@ -76,7 +78,7 @@ namespace MWGui
|
|||
virtual void visitTopicName (TopicId topicId, std::function <void (Utf8Span)> visitor) const = 0;
|
||||
|
||||
/// walks over the topics whose names start with the character
|
||||
virtual void visitTopicNamesStartingWith (uint32_t character, std::function < void (const std::string&) > visitor) const = 0;
|
||||
virtual void visitTopicNamesStartingWith (Utf8Stream::UnicodeChar character, std::function < void (const std::string&) > visitor) const = 0;
|
||||
|
||||
/// walks over the topic entries for the topic specified by its identifier
|
||||
virtual void visitTopicEntries (TopicId topicId, std::function <void (TopicEntry const &)> visitor) const = 0;
|
||||
|
|
|
@ -14,6 +14,9 @@ namespace MWGui
|
|||
|
||||
bool shouldAcceptKeyFocus(MyGUI::Widget* w)
|
||||
{
|
||||
if (w && w->getUserString("IgnoreTabKey") == "y")
|
||||
return false;
|
||||
|
||||
return w && !w->castType<MyGUI::Window>(false) && w->getInheritedEnabled() && w->getInheritedVisible() && w->getVisible() && w->getEnabled();
|
||||
}
|
||||
|
||||
|
|
|
@ -32,10 +32,14 @@ namespace
|
|||
namespace MWGui
|
||||
{
|
||||
|
||||
SpellModel::SpellModel(const MWWorld::Ptr &actor, const std::string& filter)
|
||||
: mActor(actor), mFilter(filter)
|
||||
{
|
||||
}
|
||||
|
||||
SpellModel::SpellModel(const MWWorld::Ptr &actor)
|
||||
: mActor(actor)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SpellModel::update()
|
||||
|
@ -48,12 +52,19 @@ namespace MWGui
|
|||
const MWWorld::ESMStore &esmStore =
|
||||
MWBase::Environment::get().getWorld()->getStore();
|
||||
|
||||
std::string filter = Misc::StringUtils::lowerCaseUtf8(mFilter);
|
||||
|
||||
for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it)
|
||||
{
|
||||
const ESM::Spell* spell = it->first;
|
||||
if (spell->mData.mType != ESM::Spell::ST_Power && spell->mData.mType != ESM::Spell::ST_Spell)
|
||||
continue;
|
||||
|
||||
std::string name = Misc::StringUtils::lowerCaseUtf8(spell->mName);
|
||||
|
||||
if (name.find(filter) == std::string::npos)
|
||||
continue;
|
||||
|
||||
Spell newSpell;
|
||||
newSpell.mName = spell->mName;
|
||||
if (spell->mData.mType == ESM::Spell::ST_Spell)
|
||||
|
@ -89,6 +100,11 @@ namespace MWGui
|
|||
if (enchant->mData.mType != ESM::Enchantment::WhenUsed && enchant->mData.mType != ESM::Enchantment::CastOnce)
|
||||
continue;
|
||||
|
||||
std::string name = Misc::StringUtils::lowerCaseUtf8(item.getClass().getName(item));
|
||||
|
||||
if (name.find(filter) == std::string::npos)
|
||||
continue;
|
||||
|
||||
Spell newSpell;
|
||||
newSpell.mItem = item;
|
||||
newSpell.mId = item.getCellRef().getRefId();
|
||||
|
|
|
@ -35,6 +35,7 @@ namespace MWGui
|
|||
class SpellModel
|
||||
{
|
||||
public:
|
||||
SpellModel(const MWWorld::Ptr& actor, const std::string& filter);
|
||||
SpellModel(const MWWorld::Ptr& actor);
|
||||
|
||||
typedef int ModelIndex;
|
||||
|
@ -50,6 +51,8 @@ namespace MWGui
|
|||
MWWorld::Ptr mActor;
|
||||
|
||||
std::vector<Spell> mSpells;
|
||||
|
||||
std::string mFilter;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#include <MyGUI_EditBox.h>
|
||||
#include <MyGUI_InputManager.h>
|
||||
|
||||
#include <components/settings/settings.hpp>
|
||||
|
@ -49,8 +50,12 @@ namespace MWGui
|
|||
|
||||
getWidget(mSpellView, "SpellView");
|
||||
getWidget(mEffectBox, "EffectsBox");
|
||||
getWidget(mFilterEdit, "FilterEdit");
|
||||
|
||||
mFilterEdit->setUserString("IgnoreTabKey", "y");
|
||||
|
||||
mSpellView->eventSpellClicked += MyGUI::newDelegate(this, &SpellWindow::onModelIndexSelected);
|
||||
mFilterEdit->eventEditTextChange += MyGUI::newDelegate(this, &SpellWindow::onFilterChanged);
|
||||
|
||||
setCoord(498, 300, 302, 300);
|
||||
}
|
||||
|
@ -75,6 +80,11 @@ namespace MWGui
|
|||
|
||||
void SpellWindow::onOpen()
|
||||
{
|
||||
// Reset the filter focus when opening the window
|
||||
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
|
||||
if (focus == mFilterEdit)
|
||||
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(NULL);
|
||||
|
||||
updateSpells();
|
||||
}
|
||||
|
||||
|
@ -93,7 +103,7 @@ namespace MWGui
|
|||
{
|
||||
mSpellIcons->updateWidgets(mEffectBox, false);
|
||||
|
||||
mSpellView->setModel(new SpellModel(MWMechanics::getPlayer()));
|
||||
mSpellView->setModel(new SpellModel(MWMechanics::getPlayer(), mFilterEdit->getCaption()));
|
||||
}
|
||||
|
||||
void SpellWindow::onEnchantedItemSelected(MWWorld::Ptr item, bool alreadyEquipped)
|
||||
|
@ -178,6 +188,11 @@ namespace MWGui
|
|||
}
|
||||
}
|
||||
|
||||
void SpellWindow::onFilterChanged(MyGUI::EditBox *sender)
|
||||
{
|
||||
mSpellView->setModel(new SpellModel(MWMechanics::getPlayer(), sender->getCaption()));
|
||||
}
|
||||
|
||||
void SpellWindow::onSpellSelected(const std::string& spellId)
|
||||
{
|
||||
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||
|
@ -233,7 +248,7 @@ namespace MWGui
|
|||
if (stats.isParalyzed() || stats.getKnockedDown() || stats.isDead() || stats.getHitRecovery())
|
||||
return;
|
||||
|
||||
mSpellView->setModel(new SpellModel(MWMechanics::getPlayer()));
|
||||
mSpellView->setModel(new SpellModel(MWMechanics::getPlayer(), ""));
|
||||
|
||||
SpellModel::ModelIndex selected = 0;
|
||||
for (SpellModel::ModelIndex i = 0; i<int(mSpellView->getModel()->getItemCount()); ++i)
|
||||
|
|
|
@ -32,6 +32,7 @@ namespace MWGui
|
|||
void onEnchantedItemSelected(MWWorld::Ptr item, bool alreadyEquipped);
|
||||
void onSpellSelected(const std::string& spellId);
|
||||
void onModelIndexSelected(SpellModel::ModelIndex index);
|
||||
void onFilterChanged(MyGUI::EditBox *sender);
|
||||
void onDeleteSpellAccept();
|
||||
void askDeleteSpell(const std::string& spellId);
|
||||
|
||||
|
@ -41,6 +42,7 @@ namespace MWGui
|
|||
|
||||
SpellView* mSpellView;
|
||||
SpellIcons* mSpellIcons;
|
||||
MyGUI::EditBox* mFilterEdit;
|
||||
|
||||
private:
|
||||
float mUpdateTimer;
|
||||
|
|
|
@ -866,7 +866,8 @@ namespace MWMechanics
|
|||
}
|
||||
|
||||
// place above to prevent moving inside objects, e.g. stairs, because a vector between pathgrids can be underground.
|
||||
dest.mZ += 80;
|
||||
// Adding 20 in adjustPosition() is not enough.
|
||||
dest.mZ += 60;
|
||||
|
||||
ToWorldCoordinates(dest, actor.getCell()->getCell());
|
||||
|
||||
|
|
|
@ -863,7 +863,6 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
|
|||
refreshCurrentAnims(mIdleState, mMovementState, mJumpState, true);
|
||||
|
||||
mAnimation->runAnimation(0.f);
|
||||
mAnimation->updateEffects(0.f);
|
||||
|
||||
unpersistAnimationState();
|
||||
}
|
||||
|
@ -2118,13 +2117,6 @@ void CharacterController::update(float duration)
|
|||
}
|
||||
|
||||
osg::Vec3f moved = mAnimation->runAnimation(mSkipAnim ? 0.f : duration);
|
||||
|
||||
// treat player specifically since he is not in rendering mObjects
|
||||
if (mPtr == getPlayer())
|
||||
{
|
||||
mAnimation->updateEffects(mSkipAnim ? 0.f : duration);
|
||||
}
|
||||
|
||||
if(duration > 0.0f)
|
||||
moved /= duration;
|
||||
else
|
||||
|
@ -2157,8 +2149,7 @@ void CharacterController::update(float duration)
|
|||
moved.z() = 1.0;
|
||||
|
||||
// Update movement
|
||||
// We should not apply movement for standing actors
|
||||
if(mMovementAnimationControlled && mPtr.getClass().isActor() && (movement.length2() > 0.f || !world->isIdle(mPtr)))
|
||||
if(mMovementAnimationControlled && mPtr.getClass().isActor())
|
||||
world->queueMovement(mPtr, moved);
|
||||
|
||||
mSkipAnim = false;
|
||||
|
@ -2339,7 +2330,6 @@ void CharacterController::forceStateUpdate()
|
|||
}
|
||||
|
||||
mAnimation->runAnimation(0.f);
|
||||
mAnimation->updateEffects(0.f);
|
||||
}
|
||||
|
||||
CharacterController::KillResult CharacterController::kill()
|
||||
|
|
|
@ -6,12 +6,8 @@
|
|||
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#include <osg/BoundingBox>
|
||||
#include <osg/ComputeBoundsVisitor>
|
||||
|
||||
#include <components/misc/rng.hpp>
|
||||
#include <components/settings/settings.hpp>
|
||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
@ -44,7 +40,6 @@
|
|||
#include "../mwworld/inventorystore.hpp"
|
||||
|
||||
#include "../mwrender/animation.hpp"
|
||||
#include "../mwrender/vismask.hpp"
|
||||
|
||||
#include "npcstats.hpp"
|
||||
#include "actorutil.hpp"
|
||||
|
@ -243,8 +238,6 @@ namespace MWMechanics
|
|||
magicEffects = effects;
|
||||
|
||||
float resisted = 0;
|
||||
if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful)
|
||||
{
|
||||
// Effects with no resistance attribute belonging to them can not be resisted
|
||||
if (ESM::MagicEffect::getResistanceEffect(effectId) == -1)
|
||||
return 0.f;
|
||||
|
@ -281,7 +274,6 @@ namespace MWMechanics
|
|||
x = std::min(x + resistance, 100.f);
|
||||
|
||||
resisted = x;
|
||||
}
|
||||
|
||||
return resisted;
|
||||
}
|
||||
|
@ -479,13 +471,11 @@ namespace MWMechanics
|
|||
}
|
||||
|
||||
float magnitudeMult = 1;
|
||||
if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful && target.getClass().isActor())
|
||||
{
|
||||
if (absorbed)
|
||||
continue;
|
||||
|
||||
// Try reflecting
|
||||
if (!reflected && !caster.isEmpty() && caster != target && !(magicEffect->mData.mFlags & ESM::MagicEffect::Unreflectable))
|
||||
if (!absorbed)
|
||||
{
|
||||
// Reflect harmful effects
|
||||
if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful && !reflected && !caster.isEmpty() && caster != target && !(magicEffect->mData.mFlags & ESM::MagicEffect::Unreflectable))
|
||||
{
|
||||
float reflect = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Reflect).getMagnitude();
|
||||
bool isReflected = (Misc::Rng::roll0to99() < reflect);
|
||||
|
@ -509,16 +499,17 @@ namespace MWMechanics
|
|||
else if (castByPlayer)
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResisted}");
|
||||
}
|
||||
else if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful && castByPlayer && target != caster)
|
||||
{
|
||||
// If player is attempting to cast a harmful spell and it wasn't fully resisted, show the target's HP bar
|
||||
MWBase::Environment::get().getWindowManager()->setEnemy(target);
|
||||
}
|
||||
|
||||
if (target == getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState())
|
||||
magnitudeMult = 0;
|
||||
|
||||
// If player is attempting to cast a harmful spell, show the target's HP bar
|
||||
if (castByPlayer && target != caster)
|
||||
MWBase::Environment::get().getWindowManager()->setEnemy(target);
|
||||
|
||||
// Notify the target actor they've been hit
|
||||
if (target != caster && !caster.isEmpty())
|
||||
if (target != caster && !caster.isEmpty() && magicEffect->mData.mFlags & ESM::MagicEffect::Harmful)
|
||||
target.getClass().onHit(target, 0.0f, true, MWWorld::Ptr(), caster, osg::Vec3f(), true);
|
||||
}
|
||||
|
||||
|
@ -1071,13 +1062,11 @@ namespace MWMechanics
|
|||
return true;
|
||||
}
|
||||
|
||||
void CastSpell::playSpellCastingEffects(const std::string &spellid)
|
||||
{
|
||||
void CastSpell::playSpellCastingEffects(const std::string &spellid){
|
||||
|
||||
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
||||
const ESM::Spell *spell = store.get<ESM::Spell>().find(spellid);
|
||||
|
||||
std::vector<std::string> addedEffects;
|
||||
|
||||
for (std::vector<ESM::ENAMstruct>::const_iterator iter = spell->mEffects.mList.begin();
|
||||
iter != spell->mEffects.mList.end(); ++iter)
|
||||
{
|
||||
|
@ -1086,6 +1075,8 @@ namespace MWMechanics
|
|||
|
||||
MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(mCaster);
|
||||
|
||||
if (animation && mCaster.getClass().isActor()) // TODO: Non-actors should also create a spell cast vfx even if they are disabled (animation == NULL)
|
||||
{
|
||||
const ESM::Static* castStatic;
|
||||
|
||||
if (!effect->mCasting.empty())
|
||||
|
@ -1093,65 +1084,9 @@ namespace MWMechanics
|
|||
else
|
||||
castStatic = store.get<ESM::Static>().find ("VFX_DefaultCast");
|
||||
|
||||
// check if the effect was already added
|
||||
if (std::find(addedEffects.begin(), addedEffects.end(), "meshes\\" + castStatic->mModel) != addedEffects.end())
|
||||
continue;
|
||||
|
||||
std::string texture = effect->mParticle;
|
||||
|
||||
float scale = 1.0f;
|
||||
osg::Vec3f pos (mCaster.getRefData().getPosition().asVec3());
|
||||
|
||||
if (animation && mCaster.getClass().isNpc())
|
||||
{
|
||||
// For NOC we should take race height as scaling factor
|
||||
const ESM::NPC *npc = mCaster.get<ESM::NPC>()->mBase;
|
||||
const MWWorld::ESMStore &esmStore =
|
||||
MWBase::Environment::get().getWorld()->getStore();
|
||||
|
||||
const ESM::Race *race =
|
||||
esmStore.get<ESM::Race>().find(npc->mRace);
|
||||
|
||||
scale = npc->isMale() ? race->mData.mHeight.mMale : race->mData.mHeight.mFemale;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string casterModel = mCaster.getClass().getModel(mCaster);
|
||||
osg::ref_ptr<osg::Node> model = MWBase::Environment::get().getWorld()->getInstance(casterModel);
|
||||
|
||||
osg::ComputeBoundsVisitor computeBoundsVisitor;
|
||||
computeBoundsVisitor.setTraversalMask(~(MWRender::Mask_ParticleSystem|MWRender::Mask_Effect));
|
||||
model->accept(computeBoundsVisitor);
|
||||
osg::BoundingBox bounds = computeBoundsVisitor.getBoundingBox();
|
||||
|
||||
if (bounds.valid())
|
||||
{
|
||||
float meshSizeX = std::abs(bounds.xMax() - bounds.xMin());
|
||||
float meshSizeY = std::abs(bounds.yMax() - bounds.yMin());
|
||||
float meshSizeZ = std::abs(bounds.zMax() - bounds.zMin());
|
||||
|
||||
// TODO: take a size of particle or NPC with height and weight = 1.0 as scale = 1.0
|
||||
float scaleX = meshSizeX/60.f;
|
||||
float scaleY = meshSizeY/60.f;
|
||||
float scaleZ = meshSizeZ/120.f;
|
||||
|
||||
scale = std::max({ scaleX, scaleY, scaleZ });
|
||||
|
||||
//pos = bounds.center();
|
||||
//pos[2] = bounds.zMin();
|
||||
}
|
||||
}
|
||||
|
||||
// If the caster has no animation, add the effect directly to the effectManager
|
||||
if (animation)
|
||||
{
|
||||
animation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex, false, "", texture, scale);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We should set scale for effect manager manually
|
||||
float meshScale = !mCaster.getClass().isActor() ? mCaster.getCellRef().getScale() : 1.0f;
|
||||
MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + castStatic->mModel, effect->mParticle, pos, scale * meshScale);
|
||||
animation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex, false, "", texture);
|
||||
}
|
||||
|
||||
if (animation && !mCaster.getClass().isActor())
|
||||
|
@ -1161,8 +1096,6 @@ namespace MWMechanics
|
|||
"alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration"
|
||||
};
|
||||
|
||||
addedEffects.push_back("meshes\\" + castStatic->mModel);
|
||||
|
||||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||
if(!effect->mCastSound.empty())
|
||||
sndMgr->playSound3D(mCaster, effect->mCastSound, 1.0f, 1.0f);
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
//
|
||||
// Created by koncord on 04.01.16.
|
||||
//
|
||||
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
@ -479,7 +475,7 @@ ObjectList *Networking::getObjectList()
|
|||
return &objectList;
|
||||
}
|
||||
|
||||
BaseWorldstate *Networking::getWorldstate()
|
||||
Worldstate *Networking::getWorldstate()
|
||||
{
|
||||
return &worldstate;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
//
|
||||
// Created by koncord on 04.01.16.
|
||||
//
|
||||
|
||||
#ifndef OPENMW_NETWORKING_HPP
|
||||
#define OPENMW_NETWORKING_HPP
|
||||
|
||||
|
@ -9,8 +5,6 @@
|
|||
#include <BitStream.h>
|
||||
#include <string>
|
||||
|
||||
#include "ActorList.hpp"
|
||||
#include "ObjectList.hpp"
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
|
||||
#include <components/openmw-mp/Controllers/PlayerPacketController.hpp>
|
||||
|
@ -20,6 +14,10 @@
|
|||
|
||||
#include <components/files/collections.hpp>
|
||||
|
||||
#include "ActorList.hpp"
|
||||
#include "ObjectList.hpp"
|
||||
#include "Worldstate.hpp"
|
||||
|
||||
namespace mwmp
|
||||
{
|
||||
class LocalPlayer;
|
||||
|
@ -47,7 +45,7 @@ namespace mwmp
|
|||
LocalPlayer *getLocalPlayer();
|
||||
ActorList *getActorList();
|
||||
ObjectList *getObjectList();
|
||||
BaseWorldstate *getWorldstate();
|
||||
Worldstate *getWorldstate();
|
||||
|
||||
std::string getNetworkStatistics();
|
||||
|
||||
|
@ -64,7 +62,7 @@ namespace mwmp
|
|||
|
||||
ActorList actorList;
|
||||
ObjectList objectList;
|
||||
BaseWorldstate worldstate;
|
||||
Worldstate worldstate;
|
||||
|
||||
void receiveMessage(RakNet::Packet *packet);
|
||||
|
||||
|
|
|
@ -71,8 +71,10 @@ DedicatedPlayer *PlayerList::getPlayer(const MWWorld::Ptr &ptr)
|
|||
{
|
||||
if (p.second == 0 || p.second->getPtr().mRef == 0)
|
||||
continue;
|
||||
string refid = ptr.getCellRef().getRefId();
|
||||
if (p.second->getPtr().getCellRef().getRefId() == refid)
|
||||
|
||||
string refId = ptr.getCellRef().getRefId();
|
||||
|
||||
if (p.second->getPtr().getCellRef().getRefId() == refId)
|
||||
return p.second;
|
||||
}
|
||||
return 0;
|
||||
|
@ -83,6 +85,10 @@ bool PlayerList::isDedicatedPlayer(const MWWorld::Ptr &ptr)
|
|||
if (ptr.mRef == nullptr)
|
||||
return false;
|
||||
|
||||
// Players always have 0 as their refNumIndex and mpNum
|
||||
if (ptr.getCellRef().getRefNum().mIndex != 0 || ptr.getCellRef().getMpNum() != 0)
|
||||
return false;
|
||||
|
||||
return (getPlayer(ptr) != 0);
|
||||
}
|
||||
|
||||
|
|
24
apps/openmw/mwmp/Worldstate.cpp
Normal file
24
apps/openmw/mwmp/Worldstate.cpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
#include "Worldstate.hpp"
|
||||
#include "Main.hpp"
|
||||
#include "Networking.hpp"
|
||||
|
||||
using namespace mwmp;
|
||||
using namespace std;
|
||||
|
||||
Worldstate::Worldstate()
|
||||
{
|
||||
hasPlayerCollision = true;
|
||||
hasActorCollision = true;
|
||||
hasPlacedObjectCollision = false;
|
||||
useActorCollisionForPlacedObjects = false;
|
||||
}
|
||||
|
||||
Worldstate::~Worldstate()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Networking *Worldstate::getNetworking()
|
||||
{
|
||||
return mwmp::Main::get().getNetworking();
|
||||
}
|
22
apps/openmw/mwmp/Worldstate.hpp
Normal file
22
apps/openmw/mwmp/Worldstate.hpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
#ifndef OPENMW_WORLDSTATE_HPP
|
||||
#define OPENMW_WORLDSTATE_HPP
|
||||
|
||||
#include <components/openmw-mp/Base/BaseWorldstate.hpp>
|
||||
|
||||
namespace mwmp
|
||||
{
|
||||
class Networking;
|
||||
class Worldstate : public BaseWorldstate
|
||||
{
|
||||
public:
|
||||
|
||||
Worldstate();
|
||||
virtual ~Worldstate();
|
||||
|
||||
private:
|
||||
Networking *getNetworking();
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif //OPENMW_WORLDSTATE_HPP
|
|
@ -92,6 +92,7 @@
|
|||
|
||||
#include "WorldstateProcessor.hpp"
|
||||
#include "worldstate/ProcessorRecordDynamic.hpp"
|
||||
#include "worldstate/ProcessorWorldCollisionOverride.hpp"
|
||||
#include "worldstate/ProcessorWorldTime.hpp"
|
||||
|
||||
using namespace mwmp;
|
||||
|
@ -186,5 +187,6 @@ void ProcessorInitializer()
|
|||
ActorProcessor::AddProcessor(new ProcessorActorTest());
|
||||
|
||||
WorldstateProcessor::AddProcessor(new ProcessorRecordDynamic());
|
||||
WorldstateProcessor::AddProcessor(new ProcessorWorldCollisionOverride());
|
||||
WorldstateProcessor::AddProcessor(new ProcessorWorldTime());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef OPENMW_PROCESSORWORLDCOLLISIONOVERRIDE_HPP
|
||||
#define OPENMW_PROCESSORWORLDCOLLISIONOVERRIDE_HPP
|
||||
|
||||
|
||||
#include <apps/openmw/mwbase/world.hpp>
|
||||
#include <apps/openmw/mwbase/environment.hpp>
|
||||
#include "../WorldstateProcessor.hpp"
|
||||
|
||||
namespace mwmp
|
||||
{
|
||||
class ProcessorWorldCollisionOverride : public WorldstateProcessor
|
||||
{
|
||||
public:
|
||||
ProcessorWorldCollisionOverride()
|
||||
{
|
||||
BPP_INIT(ID_WORLD_COLLISION_OVERRIDE)
|
||||
}
|
||||
|
||||
virtual void Do(WorldstatePacket &packet, BaseWorldstate &worldstate)
|
||||
{
|
||||
// Placeholder
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif //OPENMW_PROCESSORWORLDCOLLISIONOVERRIDE_HPP
|
|
@ -17,8 +17,6 @@ namespace mwmp
|
|||
}
|
||||
|
||||
virtual void Do(WorldstatePacket &packet, BaseWorldstate &worldstate)
|
||||
{
|
||||
if (isLocal())
|
||||
{
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
|
||||
|
@ -40,7 +38,6 @@ namespace mwmp
|
|||
if (worldstate.timeScale != -1)
|
||||
world->setTimeScale(worldstate.timeScale);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,18 @@
|
|||
#include "actor.hpp"
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Include additional headers for multiplayer purposes
|
||||
*/
|
||||
#include <components/openmw-mp/Log.hpp>
|
||||
#include "../mwmp/Main.hpp"
|
||||
#include "../mwmp/Networking.hpp"
|
||||
#include "../mwmp/PlayerList.hpp"
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
|
||||
#include <BulletCollision/CollisionShapes/btCapsuleShape.h>
|
||||
#include <BulletCollision/CollisionShapes/btBoxShape.h>
|
||||
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
|
||||
|
@ -18,7 +31,7 @@ namespace MWPhysics
|
|||
|
||||
Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr<const Resource::BulletShape> shape, btCollisionWorld* world)
|
||||
: mCanWaterWalk(false), mWalkingOnWater(false)
|
||||
, mCollisionObject(nullptr), mForce(0.f, 0.f, 0.f), mOnGround(true), mOnSlope(false), mIdle(true)
|
||||
, mCollisionObject(nullptr), mForce(0.f, 0.f, 0.f), mOnGround(true), mOnSlope(false)
|
||||
, mInternalCollisionMode(true)
|
||||
, mExternalCollisionMode(true)
|
||||
, mCollisionWorld(world)
|
||||
|
@ -53,6 +66,27 @@ Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr<const Resource::BulletShape>
|
|||
updatePosition();
|
||||
|
||||
addCollisionMask(getCollisionMask());
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
||||
Make it possible to disable collision for players or regular actors from a packet
|
||||
*/
|
||||
mwmp::BaseWorldstate *worldstate = mwmp::Main::get().getNetworking()->getWorldstate();
|
||||
|
||||
if (mwmp::PlayerList::isDedicatedPlayer(ptr))
|
||||
{
|
||||
if (!worldstate->hasPlayerCollision)
|
||||
enableCollisionBody(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!worldstate->hasActorCollision)
|
||||
enableCollisionBody(false);
|
||||
}
|
||||
/*
|
||||
End of tes3mp addition
|
||||
*/
|
||||
}
|
||||
|
||||
Actor::~Actor()
|
||||
|
@ -195,11 +229,6 @@ void Actor::setOnSlope(bool slope)
|
|||
mOnSlope = slope;
|
||||
}
|
||||
|
||||
void Actor::setIdle(bool idle)
|
||||
{
|
||||
mIdle = idle;
|
||||
}
|
||||
|
||||
bool Actor::isWalkingOnWater() const
|
||||
{
|
||||
return mWalkingOnWater;
|
||||
|
|
|
@ -139,13 +139,6 @@ namespace MWPhysics
|
|||
return mInternalCollisionMode && mOnSlope;
|
||||
}
|
||||
|
||||
void setIdle(bool idle);
|
||||
|
||||
bool getIdle() const
|
||||
{
|
||||
return mIdle;
|
||||
}
|
||||
|
||||
btCollisionObject* getCollisionObject() const
|
||||
{
|
||||
return mCollisionObject.get();
|
||||
|
@ -186,7 +179,6 @@ namespace MWPhysics
|
|||
osg::Vec3f mForce;
|
||||
bool mOnGround;
|
||||
bool mOnSlope;
|
||||
bool mIdle;
|
||||
bool mInternalCollisionMode;
|
||||
bool mExternalCollisionMode;
|
||||
|
||||
|
|
|
@ -249,7 +249,7 @@ namespace MWPhysics
|
|||
// Check if we actually found a valid spawn point (use an infinitely thin ray this time).
|
||||
// Required for some broken door destinations in Morrowind.esm, where the spawn point
|
||||
// intersects with other geometry if the actor's base is taken into account
|
||||
btVector3 from = toBullet(position + offset);
|
||||
btVector3 from = toBullet(position);
|
||||
btVector3 to = from - btVector3(0,0,maxHeight);
|
||||
|
||||
btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to);
|
||||
|
@ -683,7 +683,6 @@ namespace MWPhysics
|
|||
, mWaterEnabled(false)
|
||||
, mParentNode(parentNode)
|
||||
, mPhysicsDt(1.f / 60.f)
|
||||
, mIdleUpdateTimer(0)
|
||||
{
|
||||
mResourceSystem->addResourceManager(mShapeManager.get());
|
||||
|
||||
|
@ -740,18 +739,6 @@ namespace MWPhysics
|
|||
delete mBroadphase;
|
||||
}
|
||||
|
||||
void PhysicsSystem::updateIdle()
|
||||
{
|
||||
for (ActorMap::iterator it = mActors.begin(); it != mActors.end(); ++it)
|
||||
{
|
||||
osg::Vec3f pos(it->second->getCollisionObjectPosition());
|
||||
|
||||
RayResult result = castRay(pos, pos - osg::Vec3f(0, 0, it->second->getHalfExtents().z() + 2), it->second->getPtr(), std::vector<MWWorld::Ptr>(), CollisionType_World|CollisionType_HeightMap|CollisionType_Door);
|
||||
|
||||
it->second->setIdle(result.mHit);
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicsSystem::setUnrefQueue(SceneUtil::UnrefQueue *unrefQueue)
|
||||
{
|
||||
mUnrefQueue = unrefQueue;
|
||||
|
@ -1080,11 +1067,6 @@ namespace MWPhysics
|
|||
return physactor && physactor->getOnGround();
|
||||
}
|
||||
|
||||
bool PhysicsSystem::isIdle(const MWWorld::Ptr &actor)
|
||||
{
|
||||
Actor* physactor = getActor(actor);
|
||||
return physactor && physactor->getIdle();
|
||||
}
|
||||
bool PhysicsSystem::canMoveToWaterSurface(const MWWorld::ConstPtr &actor, const float waterlevel)
|
||||
{
|
||||
const Actor* physicActor = getActor(actor);
|
||||
|
@ -1377,10 +1359,6 @@ namespace MWPhysics
|
|||
cmode = !cmode;
|
||||
found->second->enableCollisionMode(cmode);
|
||||
found->second->enableCollisionBody(cmode);
|
||||
|
||||
if (cmode)
|
||||
queueObjectMovement(MWMechanics::getPlayer(), osg::Vec3f(0, 0, -0.1f));
|
||||
|
||||
return cmode;
|
||||
}
|
||||
|
||||
|
@ -1500,13 +1478,6 @@ namespace MWPhysics
|
|||
for (std::set<Object*>::iterator it = mAnimatedObjects.begin(); it != mAnimatedObjects.end(); ++it)
|
||||
(*it)->animateCollisionShapes(mCollisionWorld);
|
||||
|
||||
mIdleUpdateTimer -= dt;
|
||||
if (mIdleUpdateTimer <= 0.f)
|
||||
{
|
||||
mIdleUpdateTimer = 0.5f;
|
||||
updateIdle();
|
||||
}
|
||||
|
||||
#ifndef BT_NO_PROFILE
|
||||
CProfileManager::Reset();
|
||||
CProfileManager::Increment_Frame_Counter();
|
||||
|
|
|
@ -124,7 +124,6 @@ namespace MWPhysics
|
|||
bool getLineOfSight(const MWWorld::ConstPtr& actor1, const MWWorld::ConstPtr& actor2) const;
|
||||
|
||||
bool isOnGround (const MWWorld::Ptr& actor);
|
||||
bool isIdle (const MWWorld::Ptr& actor);
|
||||
|
||||
bool canMoveToWaterSurface (const MWWorld::ConstPtr &actor, const float waterlevel);
|
||||
|
||||
|
@ -184,7 +183,6 @@ namespace MWPhysics
|
|||
private:
|
||||
|
||||
void updateWater();
|
||||
void updateIdle();
|
||||
|
||||
osg::ref_ptr<SceneUtil::UnrefQueue> mUnrefQueue;
|
||||
|
||||
|
@ -233,7 +231,6 @@ namespace MWPhysics
|
|||
osg::ref_ptr<osg::Group> mParentNode;
|
||||
|
||||
float mPhysicsDt;
|
||||
float mIdleUpdateTimer;
|
||||
|
||||
PhysicsSystem (const PhysicsSystem&);
|
||||
PhysicsSystem& operator= (const PhysicsSystem&);
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
#include <osg/MatrixTransform>
|
||||
#include <osg/BlendFunc>
|
||||
#include <osg/Material>
|
||||
#include <osg/ComputeBoundsVisitor>
|
||||
#include <osg/PositionAttitudeTransform>
|
||||
|
||||
#include <osgParticle/ParticleSystem>
|
||||
#include <osgParticle/ParticleProcessor>
|
||||
|
@ -1117,6 +1115,8 @@ namespace MWRender
|
|||
++stateiter;
|
||||
}
|
||||
|
||||
updateEffects(duration);
|
||||
|
||||
if (mHeadController)
|
||||
{
|
||||
const float epsilon = 0.001f;
|
||||
|
@ -1366,7 +1366,7 @@ namespace MWRender
|
|||
useQuadratic, quadraticValue, quadraticRadiusMult, useLinear, linearRadiusMult, linearValue);
|
||||
}
|
||||
|
||||
void Animation::addEffect (const std::string& model, int effectId, bool loop, const std::string& bonename, const std::string& texture, float scale)
|
||||
void Animation::addEffect (const std::string& model, int effectId, bool loop, const std::string& bonename, const std::string& texture)
|
||||
{
|
||||
if (!mObjectRoot.get())
|
||||
return;
|
||||
|
@ -1417,13 +1417,7 @@ namespace MWRender
|
|||
|
||||
overrideFirstRootTexture(texture, mResourceSystem, node);
|
||||
|
||||
osg::Vec3f scale3f (scale, scale, scale);
|
||||
|
||||
osg::ref_ptr<osg::PositionAttitudeTransform> trans = new osg::PositionAttitudeTransform;
|
||||
trans->setScale(scale3f);
|
||||
trans->addChild(node);
|
||||
parentNode->removeChild(node);
|
||||
parentNode->addChild(trans);
|
||||
// TODO: in vanilla morrowind the effect is scaled based on the host object's bounding box.
|
||||
|
||||
mEffects.push_back(params);
|
||||
}
|
||||
|
|
|
@ -364,7 +364,7 @@ public:
|
|||
* @param texture override the texture specified in the model's materials - if empty, do not override
|
||||
* @note Will not add an effect twice.
|
||||
*/
|
||||
void addEffect (const std::string& model, int effectId, bool loop = false, const std::string& bonename = "", const std::string& texture = "", float scale = 1.0f);
|
||||
void addEffect (const std::string& model, int effectId, bool loop = false, const std::string& bonename = "", const std::string& texture = "");
|
||||
void removeEffect (int effectId);
|
||||
void getLoopingEffects (std::vector<int>& out) const;
|
||||
|
||||
|
@ -446,6 +446,7 @@ public:
|
|||
|
||||
void setLoopingEnabled(const std::string &groupname, bool enabled);
|
||||
|
||||
/// This is typically called as part of runAnimation, but may be called manually if needed.
|
||||
void updateEffects(float duration);
|
||||
|
||||
/// Return a node with the specified name, or NULL if not existing.
|
||||
|
|
|
@ -26,13 +26,6 @@ EffectManager::~EffectManager()
|
|||
}
|
||||
|
||||
void EffectManager::addEffect(const std::string &model, const std::string& textureOverride, const osg::Vec3f &worldPosition, float scale, bool isMagicVFX)
|
||||
{
|
||||
osg::Vec3f scale3f (scale, scale, scale);
|
||||
|
||||
addEffect(model, textureOverride, worldPosition, scale3f, isMagicVFX);
|
||||
}
|
||||
|
||||
void EffectManager::addEffect(const std::string &model, const std::string& textureOverride, const osg::Vec3f &worldPosition, const osg::Vec3f &scale, bool isMagicVFX)
|
||||
{
|
||||
osg::ref_ptr<osg::Node> node = mResourceSystem->getSceneManager()->getInstance(model);
|
||||
|
||||
|
@ -47,7 +40,7 @@ void EffectManager::addEffect(const std::string &model, const std::string& textu
|
|||
|
||||
osg::ref_ptr<osg::PositionAttitudeTransform> trans = new osg::PositionAttitudeTransform;
|
||||
trans->setPosition(worldPosition);
|
||||
trans->setScale(scale);
|
||||
trans->setScale(osg::Vec3f(scale, scale, scale));
|
||||
trans->addChild(node);
|
||||
|
||||
SceneUtil::AssignControllerSourcesVisitor assignVisitor(effect.mAnimTime);
|
||||
|
|
|
@ -33,7 +33,6 @@ namespace MWRender
|
|||
|
||||
/// Add an effect. When it's finished playing, it will be removed automatically.
|
||||
void addEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPosition, float scale, bool isMagicVFX = true);
|
||||
void addEffect (const std::string &model, const std::string& textureOverride, const osg::Vec3f &worldPosition, const osg::Vec3f &scale3f, bool isMagicVFX);
|
||||
|
||||
void update(float dt);
|
||||
|
||||
|
|
|
@ -138,14 +138,6 @@ bool Objects::removeObject (const MWWorld::Ptr& ptr)
|
|||
return false;
|
||||
}
|
||||
|
||||
void Objects::updateEffects(float duration)
|
||||
{
|
||||
for(PtrAnimationMap::iterator iter = mObjects.begin();iter != mObjects.end();)
|
||||
{
|
||||
iter->second->updateEffects(duration);
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
void Objects::removeCell(const MWWorld::CellStore* store)
|
||||
{
|
||||
|
|
|
@ -88,8 +88,6 @@ public:
|
|||
bool removeObject (const MWWorld::Ptr& ptr);
|
||||
///< \return found?
|
||||
|
||||
void updateEffects(float duration);
|
||||
|
||||
void removeCell(const MWWorld::CellStore* store);
|
||||
|
||||
/// Updates containing cell for object rendering data
|
||||
|
|
|
@ -557,7 +557,6 @@ namespace MWRender
|
|||
mEffectManager->update(dt);
|
||||
mSky->update(dt);
|
||||
mWater->update(dt);
|
||||
mObjects->updateEffects(dt);
|
||||
}
|
||||
|
||||
mCamera->update(dt, paused);
|
||||
|
@ -842,11 +841,9 @@ namespace MWRender
|
|||
mObjects->updatePtr(old, updated);
|
||||
}
|
||||
|
||||
void RenderingManager::spawnEffect(const std::string &model, const std::string& texture, const osg::Vec3f &worldPosition, float scale, bool isMagicVFX)
|
||||
void RenderingManager::spawnEffect(const std::string &model, const std::string &texture, const osg::Vec3f &worldPosition, float scale, bool isMagicVFX)
|
||||
{
|
||||
osg::Vec3f scale3f (scale, scale, scale);
|
||||
|
||||
mEffectManager->addEffect(model, texture, worldPosition, scale3f, isMagicVFX);
|
||||
mEffectManager->addEffect(model, texture, worldPosition, scale, isMagicVFX);
|
||||
}
|
||||
|
||||
void RenderingManager::notifyWorldSpaceChanged()
|
||||
|
@ -1125,12 +1122,6 @@ namespace MWRender
|
|||
updateProjectionMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Node> RenderingManager::getInstance(const std::string& modelName)
|
||||
{
|
||||
return mResourceSystem->getSceneManager()->getInstance(modelName);
|
||||
}
|
||||
|
||||
void RenderingManager::exportSceneGraph(const MWWorld::Ptr &ptr, const std::string &filename, const std::string &format)
|
||||
{
|
||||
osg::Node* node = mViewer->getSceneData();
|
||||
|
|
|
@ -205,8 +205,6 @@ namespace MWRender
|
|||
|
||||
LandManager* getLandManager() const;
|
||||
|
||||
osg::ref_ptr<osg::Node> getInstance(const std::string& modelName);
|
||||
|
||||
private:
|
||||
void updateProjectionMatrix();
|
||||
void updateTextureFiltering();
|
||||
|
|
|
@ -270,12 +270,16 @@ namespace MWScript
|
|||
|
||||
bool InterpreterContext::menuMode()
|
||||
{
|
||||
/* Disabled by tes3mp, because being in a menu should not pause scripts in it
|
||||
/*
|
||||
Start of tes3mp change (major)
|
||||
|
||||
return MWBase::Environment::get().getWindowManager()->isGuiMode();
|
||||
Being in a menu should not pause scripts in multiplayer, so always return false
|
||||
*/
|
||||
|
||||
//return MWBase::Environment::get().getWindowManager()->isGuiMode();
|
||||
return false;
|
||||
/*
|
||||
End of tes3mp change (major)
|
||||
*/
|
||||
}
|
||||
|
||||
int InterpreterContext::getGlobalShort (const std::string& name) const
|
||||
|
@ -672,10 +676,17 @@ namespace MWScript
|
|||
|
||||
Locals& locals = getMemberLocals (scriptId, global);
|
||||
|
||||
// Added by tes3mp so it can be reused by it
|
||||
/*
|
||||
Start of tes3mp change (minor)
|
||||
|
||||
Declare an integer so it can be reused below for multiplayer script sync purposes
|
||||
*/
|
||||
int index = findLocalVariableIndex(scriptId, name, 's');
|
||||
|
||||
locals.mShorts[index] = value;
|
||||
/*
|
||||
End of tes3mp change (minor)
|
||||
*/
|
||||
|
||||
/*
|
||||
Start of tes3mp addition
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include <components/esm/loadcrea.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/scriptmanager.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
@ -771,8 +770,6 @@ namespace MWScript
|
|||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
MWBase::Environment::get().getWorld()->queueMovement(ptr, osg::Vec3f(0, 0, -0.1f));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1124,7 +1121,6 @@ namespace MWScript
|
|||
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr (targetId, false);
|
||||
|
||||
MWMechanics::CastSpell cast(ptr, target);
|
||||
cast.playSpellCastingEffects(spell);
|
||||
cast.mHitPosition = target.getRefData().getPosition().asVec3();
|
||||
cast.mAlwaysSucceed = true;
|
||||
cast.cast(spell);
|
||||
|
|
|
@ -506,7 +506,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str
|
|||
if (firstPersonCam != MWBase::Environment::get().getWorld()->isFirstPerson())
|
||||
MWBase::Environment::get().getWorld()->togglePOV();
|
||||
|
||||
const MWWorld::Ptr ptr = MWMechanics::getPlayer();
|
||||
MWWorld::ConstPtr ptr = MWMechanics::getPlayer();
|
||||
|
||||
if (ptr.isInCell())
|
||||
{
|
||||
|
@ -538,9 +538,6 @@ void MWState::StateManager::loadGame (const Character *character, const std::str
|
|||
// Since we passed "changeEvent=false" to changeCell, we shouldn't have triggered the cell change flag.
|
||||
// But make sure the flag is cleared anyway in case it was set from an earlier game.
|
||||
MWBase::Environment::get().getWorld()->markCellAsUnchanged();
|
||||
|
||||
// Workaround to fix camera position upon game load
|
||||
MWBase::Environment::get().getWorld()->queueMovement(ptr, osg::Vec3f(0, 0, 0));
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
|
|
|
@ -280,10 +280,11 @@ namespace MWWorld
|
|||
{
|
||||
ESM::Position pos;
|
||||
|
||||
// Major change made by tes3mp
|
||||
//
|
||||
// If Pelagiad exists, spawn there; otherwise, spawn at 0,0
|
||||
/*
|
||||
Start of tes3mp change (major)
|
||||
|
||||
If Pelagiad exists, spawn there; otherwise, spawn at 0 ,0
|
||||
*/
|
||||
if (findExteriorPosition("Pelagiad", pos))
|
||||
{
|
||||
changeToExteriorCell(pos, true);
|
||||
|
@ -300,6 +301,9 @@ namespace MWWorld
|
|||
pos.rot[2] = 0;
|
||||
mWorldScene->changeToExteriorCell(pos, true);
|
||||
}
|
||||
/*
|
||||
End of tes3mp change (major)
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1437,6 +1441,8 @@ namespace MWWorld
|
|||
if (pos.z() < terrainHeight)
|
||||
pos.z() = terrainHeight;
|
||||
|
||||
pos.z() += 20; // place slightly above. will snap down to ground with code below
|
||||
|
||||
if (force || !isFlying(ptr))
|
||||
{
|
||||
osg::Vec3f traced = mPhysics->traceDown(ptr, pos, 500);
|
||||
|
@ -1682,11 +1688,6 @@ namespace MWWorld
|
|||
}
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Node> World::getInstance (const std::string& modelName)
|
||||
{
|
||||
return mRendering->getInstance(modelName);
|
||||
}
|
||||
|
||||
const ESM::Potion *World::createRecord (const ESM::Potion& record)
|
||||
{
|
||||
return mStore.insert(record);
|
||||
|
@ -2314,11 +2315,6 @@ namespace MWWorld
|
|||
return mPhysics->isOnGround(ptr);
|
||||
}
|
||||
|
||||
bool World::isIdle(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
return mPhysics->isIdle(ptr);
|
||||
}
|
||||
|
||||
void World::togglePOV()
|
||||
{
|
||||
mRendering->togglePOV();
|
||||
|
@ -2559,10 +2555,16 @@ namespace MWWorld
|
|||
|
||||
void World::hurtStandingActors(const ConstPtr &object, float healthPerSecond)
|
||||
{
|
||||
/* Disabled by tes3mp, because being in a menu should not pause the game in it
|
||||
/*
|
||||
Start of tes3mp change (major)
|
||||
|
||||
if (MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||
return;
|
||||
Being in a menu should not prevent actors from being hurt in multiplayer,
|
||||
so that check has been commented out
|
||||
*/
|
||||
//if (MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||
// return;
|
||||
/*
|
||||
End of tes3mp change (major)
|
||||
*/
|
||||
|
||||
std::vector<MWWorld::Ptr> actors;
|
||||
|
@ -2596,10 +2598,16 @@ namespace MWWorld
|
|||
|
||||
void World::hurtCollidingActors(const ConstPtr &object, float healthPerSecond)
|
||||
{
|
||||
/* Disabled by tes3mp, because being in a menu should not pause the game in it
|
||||
/*
|
||||
Start of tes3mp change (major)
|
||||
|
||||
if (MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||
return;
|
||||
Being in a menu should not prevent actors from being hurt in multiplayer,
|
||||
so that check has been commented out
|
||||
*/
|
||||
//if (MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||
// return;
|
||||
/*
|
||||
End of tes3mp change (major)
|
||||
*/
|
||||
|
||||
std::vector<MWWorld::Ptr> actors;
|
||||
|
@ -3575,9 +3583,9 @@ namespace MWWorld
|
|||
mRendering->spawnEffect(model, texture, worldPosition, 1.0f, false);
|
||||
}
|
||||
|
||||
void World::spawnEffect(const std::string &model, const std::string &textureOverride, const osg::Vec3f &worldPos, float scale, bool isMagicVFX)
|
||||
void World::spawnEffect(const std::string &model, const std::string &textureOverride, const osg::Vec3f &worldPos)
|
||||
{
|
||||
mRendering->spawnEffect(model, textureOverride, worldPos, scale, isMagicVFX);
|
||||
mRendering->spawnEffect(model, textureOverride, worldPos);
|
||||
}
|
||||
|
||||
void World::explodeSpell(const osg::Vec3f& origin, const ESM::EffectList& effects, const Ptr& caster, const Ptr& ignore, ESM::RangeType rangeType,
|
||||
|
|
|
@ -553,7 +553,6 @@ namespace MWWorld
|
|||
bool isWading(const MWWorld::ConstPtr &object) const override;
|
||||
bool isWaterWalkingCastableOnTarget(const MWWorld::ConstPtr &target) const override;
|
||||
bool isOnGround(const MWWorld::Ptr &ptr) const override;
|
||||
bool isIdle(const MWWorld::Ptr &ptr) const override;
|
||||
|
||||
osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const override;
|
||||
|
||||
|
@ -725,7 +724,7 @@ namespace MWWorld
|
|||
/// Spawn a blood effect for \a ptr at \a worldPosition
|
||||
void spawnBloodEffect (const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition) override;
|
||||
|
||||
void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos, float scale = 1.f, bool isMagicVFX = true) override;
|
||||
void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos) override;
|
||||
|
||||
void explodeSpell(const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const MWWorld::Ptr& ignore,
|
||||
ESM::RangeType rangeType, const std::string& id, const std::string& sourceName,
|
||||
|
@ -765,8 +764,6 @@ namespace MWWorld
|
|||
|
||||
/// Preload VFX associated with this effect list
|
||||
void preloadEffects(const ESM::EffectList* effectList) override;
|
||||
|
||||
osg::ref_ptr<osg::Node> getInstance (const std::string& modelName);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
14
appveyor.yml
14
appveyor.yml
|
@ -18,8 +18,8 @@ platform:
|
|||
- x64
|
||||
|
||||
configuration:
|
||||
- Debug
|
||||
# - Release
|
||||
# - Debug
|
||||
- Release
|
||||
|
||||
# For the Qt, Boost, CMake, etc installs
|
||||
#os: Visual Studio 2017
|
||||
|
@ -55,6 +55,10 @@ build_script:
|
|||
- cmd: if %PLATFORM%==x64 set build=MSVC%msvc%_64
|
||||
- cmd: msbuild %build%\OpenMW.sln /t:Build /p:Configuration=%configuration% /m:2 /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
|
||||
|
||||
after_build:
|
||||
- cmd: if %PLATFORM%==x64 7z a OpenMW_MSVC%msvc%_x64.zip %APPVEYOR_BUILD_FOLDER%\MSVC%msvc%_64\Release\ -xr"!*.pdb"
|
||||
- cmd: if %PLATFORM%==x64 7z a OpenMW_MSVC%msvc%_x64_pdb.zip %APPVEYOR_BUILD_FOLDER%\MSVC%msvc%_64\Release\*.pdb
|
||||
|
||||
test: off
|
||||
|
||||
#notifications:
|
||||
|
@ -63,3 +67,9 @@ test: off
|
|||
# -
|
||||
# on_build_failure: true
|
||||
# on_build_status_changed: true
|
||||
|
||||
artifacts:
|
||||
- path: OpenMW_MSVC%msvc%_x64.zip
|
||||
name: OpenMW_MSVC%msvc%_x64
|
||||
- path: OpenMW_MSVC%msvc%_x64_pdb.zip
|
||||
name: OpenMW_MSVC%msvc%_x64_pdb
|
||||
|
|
|
@ -202,7 +202,7 @@ add_component_dir (openmw-mp/Packets/Object
|
|||
add_component_dir (openmw-mp/Packets/Worldstate
|
||||
WorldstatePacket
|
||||
|
||||
PacketRecordDynamic PacketWorldTime
|
||||
PacketRecordDynamic PacketWorldCollisionOverride PacketWorldTime
|
||||
)
|
||||
|
||||
add_component_dir (fallback
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include "utf8stream.hpp"
|
||||
|
||||
namespace Misc
|
||||
{
|
||||
class StringUtils
|
||||
|
@ -56,6 +58,70 @@ public:
|
|||
};
|
||||
}
|
||||
|
||||
static Utf8Stream::UnicodeChar toLowerUtf8(Utf8Stream::UnicodeChar ch)
|
||||
{
|
||||
// Russian alphabet
|
||||
if (ch >= 0x0410 && ch < 0x0430)
|
||||
return ch += 0x20;
|
||||
|
||||
// Cyrillic IO character
|
||||
if (ch == 0x0401)
|
||||
return ch += 0x50;
|
||||
|
||||
// Latin alphabet
|
||||
if (ch >= 0x41 && ch < 0x60)
|
||||
return ch += 0x20;
|
||||
|
||||
// Deutch characters
|
||||
if (ch == 0xc4 || ch == 0xd6 || ch == 0xdc)
|
||||
return ch += 0x20;
|
||||
if (ch == 0x1e9e)
|
||||
return 0xdf;
|
||||
|
||||
// TODO: probably we will need to support characters from other languages
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
static std::string lowerCaseUtf8(const std::string str)
|
||||
{
|
||||
if (str.empty())
|
||||
return str;
|
||||
|
||||
// Decode string as utf8 characters, convert to lower case and pack them to string
|
||||
std::string out;
|
||||
Utf8Stream stream (str.c_str());
|
||||
while (!stream.eof ())
|
||||
{
|
||||
Utf8Stream::UnicodeChar character = toLowerUtf8(stream.peek());
|
||||
|
||||
if (character <= 0x7f)
|
||||
out.append(1, static_cast<char>(character));
|
||||
else if (character <= 0x7ff)
|
||||
{
|
||||
out.append(1, static_cast<char>(0xc0 | ((character >> 6) & 0x1f)));
|
||||
out.append(1, static_cast<char>(0x80 | (character & 0x3f)));
|
||||
}
|
||||
else if (character <= 0xffff)
|
||||
{
|
||||
out.append(1, static_cast<char>(0xe0 | ((character >> 12) & 0x0f)));
|
||||
out.append(1, static_cast<char>(0x80 | ((character >> 6) & 0x3f)));
|
||||
out.append(1, static_cast<char>(0x80 | (character & 0x3f)));
|
||||
}
|
||||
else
|
||||
{
|
||||
out.append(1, static_cast<char>(0xf0 | ((character >> 18) & 0x07)));
|
||||
out.append(1, static_cast<char>(0x80 | ((character >> 12) & 0x3f)));
|
||||
out.append(1, static_cast<char>(0x80 | ((character >> 6) & 0x3f)));
|
||||
out.append(1, static_cast<char>(0x80 | (character & 0x3f)));
|
||||
}
|
||||
|
||||
stream.consume();
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static bool ciLess(const std::string &x, const std::string &y) {
|
||||
return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end(), ci());
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef MISC_UTF8ITER_HPP
|
||||
#define MISC_UTF8ITER_HPP
|
||||
|
||||
#include <cstring>
|
||||
#include <tuple>
|
||||
|
||||
class Utf8Stream
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
//
|
||||
// Created by koncord on 07.01.16.
|
||||
//
|
||||
|
||||
#ifndef OPENMW_BASEPLAYER_HPP
|
||||
#define OPENMW_BASEPLAYER_HPP
|
||||
|
||||
|
|
|
@ -32,6 +32,11 @@ namespace mwmp
|
|||
int daysPassed;
|
||||
float timeScale;
|
||||
|
||||
bool hasPlayerCollision;
|
||||
bool hasActorCollision;
|
||||
bool hasPlacedObjectCollision;
|
||||
bool useActorCollisionForPlacedObjects;
|
||||
|
||||
bool isValid;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "../Packets/Worldstate/PacketRecordDynamic.hpp"
|
||||
#include "../Packets/Worldstate/PacketWorldCollisionOverride.hpp"
|
||||
#include "../Packets/Worldstate/PacketWorldTime.hpp"
|
||||
|
||||
#include "WorldstatePacketController.hpp"
|
||||
|
@ -6,5 +7,6 @@
|
|||
mwmp::WorldstatePacketController::WorldstatePacketController(RakNet::RakPeerInterface *peer)
|
||||
{
|
||||
AddPacket<PacketRecordDynamic>(&packets, peer);
|
||||
AddPacket<PacketWorldCollisionOverride>(&packets, peer);
|
||||
AddPacket<PacketWorldTime>(&packets, peer);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ enum GameMessages
|
|||
ID_GUI_MESSAGEBOX,
|
||||
ID_GUI_WINDOW,
|
||||
|
||||
ID_WORLD_TIME,
|
||||
ID_GAME_WEATHER,
|
||||
|
||||
ID_PLAYER_BASEINFO,
|
||||
|
@ -91,7 +90,6 @@ enum GameMessages
|
|||
ID_OBJECT_TRAP,
|
||||
|
||||
ID_CELL_CREATE,
|
||||
ID_RECORD_DYNAMIC,
|
||||
|
||||
ID_CONSOLE_COMMAND,
|
||||
ID_CONTAINER,
|
||||
|
@ -108,7 +106,11 @@ enum GameMessages
|
|||
ID_SCRIPT_GLOBAL_FLOAT,
|
||||
|
||||
ID_GAME_SETTINGS,
|
||||
ID_GAME_PREINIT
|
||||
ID_GAME_PREINIT,
|
||||
|
||||
ID_RECORD_DYNAMIC,
|
||||
ID_WORLD_COLLISION_OVERRIDE,
|
||||
ID_WORLD_TIME,
|
||||
};
|
||||
|
||||
enum OrderingChannel
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
#include "PacketWorldCollisionOverride.hpp"
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
|
||||
using namespace mwmp;
|
||||
|
||||
PacketWorldCollisionOverride::PacketWorldCollisionOverride(RakNet::RakPeerInterface *peer) : WorldstatePacket(peer)
|
||||
{
|
||||
packetID = ID_WORLD_COLLISION_OVERRIDE;
|
||||
orderChannel = CHANNEL_WORLDSTATE;
|
||||
}
|
||||
|
||||
void PacketWorldCollisionOverride::Packet(RakNet::BitStream *bs, bool send)
|
||||
{
|
||||
WorldstatePacket::Packet(bs, send);
|
||||
|
||||
RW(worldstate->hasPlayerCollision, send);
|
||||
RW(worldstate->hasActorCollision, send);
|
||||
RW(worldstate->hasPlacedObjectCollision, send);
|
||||
RW(worldstate->useActorCollisionForPlacedObjects, send);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef OPENMW_PACKETWORLDCOLLISIONOVERRIDE_HPP
|
||||
#define OPENMW_PACKETWORLDCOLLISIONOVERRIDE_HPP
|
||||
|
||||
#include <components/openmw-mp/Packets/Worldstate/WorldstatePacket.hpp>
|
||||
|
||||
namespace mwmp
|
||||
{
|
||||
class PacketWorldCollisionOverride : public WorldstatePacket
|
||||
{
|
||||
public:
|
||||
PacketWorldCollisionOverride(RakNet::RakPeerInterface *peer);
|
||||
|
||||
virtual void Packet(RakNet::BitStream *bs, bool send);
|
||||
};
|
||||
}
|
||||
|
||||
#endif //OPENMW_PACKETWORLDCOLLISIONOVERRIDE_HPP
|
|
@ -10,7 +10,11 @@
|
|||
</Widget>
|
||||
|
||||
<!-- Spell list -->
|
||||
<Widget type="SpellView" skin="MW_SpellView" position="8 38 268 518" align="Left Top Stretch" name="SpellView">
|
||||
<Widget type="SpellView" skin="MW_SpellView" position="8 38 268 490" align="Left Top Stretch" name="SpellView">
|
||||
</Widget>
|
||||
|
||||
<!-- Search box-->
|
||||
<Widget type="EditBox" skin="MW_TextBoxEditWithBorder" position="8 535 268 23" align="Left Bottom HStretch" name="FilterEdit">
|
||||
</Widget>
|
||||
|
||||
</Widget>
|
||||
|
|
|
@ -150,5 +150,9 @@
|
|||
<file alias="selection-mode-cube">selection-mode-cube.png</file>
|
||||
<file alias="selection-mode-cube-corner">selection-mode-cube-corner.png</file>
|
||||
<file alias="selection-mode-cube-sphere">selection-mode-cube-sphere.png</file>
|
||||
<file alias="brush-point">brush-point.png</file>
|
||||
<file alias="brush-square">brush-square.png</file>
|
||||
<file alias="brush-circle">brush-circle.png</file>
|
||||
<file alias="brush-custom">brush-custom.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -217,7 +217,7 @@ followers attack on sight = false
|
|||
can loot during death animation = true
|
||||
|
||||
# Makes the value of filled soul gems dependent only on soul magnitude (with formula from the Morrowind Code Patch)
|
||||
rebalance soul gem values = true
|
||||
rebalance soul gem values = false
|
||||
|
||||
[General]
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@
|
|||
<item>
|
||||
<widget class="QCheckBox" name="rebalanceSoulGemValuesCheckBox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>If this setting is true, the value of filled soul gems is dependent only on soul magnitude.</p><p>The default value is true.</p></body></html></string>
|
||||
<string><html><head/><body><p>If this setting is true, the value of filled soul gems is dependent only on soul magnitude.</p><p>The default value is false.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Rebalance soul gem values</string>
|
||||
|
|
Loading…
Reference in a new issue