mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-04-01 07:36:44 +00:00
Merge branch 'master' into windspeed
This commit is contained in:
commit
cdbe58c33a
44 changed files with 536 additions and 318 deletions
|
@ -2,6 +2,7 @@
|
||||||
------
|
------
|
||||||
|
|
||||||
Bug #1515: Opening console masks dialogue, inventory menu
|
Bug #1515: Opening console masks dialogue, inventory menu
|
||||||
|
Bug #1933: Actors can have few stocks of the same item
|
||||||
Bug #2395: Duplicated plugins in the launcher when multiple data directories provide the same plugin
|
Bug #2395: Duplicated plugins in the launcher when multiple data directories provide the same plugin
|
||||||
Bug #2969: Scripted items can stack
|
Bug #2969: Scripted items can stack
|
||||||
Bug #2976: Data lines in global openmw.cfg take priority over user openmw.cfg
|
Bug #2976: Data lines in global openmw.cfg take priority over user openmw.cfg
|
||||||
|
@ -18,6 +19,7 @@
|
||||||
Bug #3778: [Mod] Improved Thrown Weapon Projectiles - weapons have wrong transformation during throw animation
|
Bug #3778: [Mod] Improved Thrown Weapon Projectiles - weapons have wrong transformation during throw animation
|
||||||
Bug #3812: Wrong multiline tooltips width when word-wrapping is enabled
|
Bug #3812: Wrong multiline tooltips width when word-wrapping is enabled
|
||||||
Bug #3894: Hostile spell effects not detected/present on first frame of OnPCHitMe
|
Bug #3894: Hostile spell effects not detected/present on first frame of OnPCHitMe
|
||||||
|
Bug #4077: Enchanted items are not recharged if they are not in the player's inventory
|
||||||
Bug #4202: Open .omwaddon files without needing toopen openmw-cs first
|
Bug #4202: Open .omwaddon files without needing toopen openmw-cs first
|
||||||
Bug #4240: Ash storm origin coordinates and hand shielding animation behavior are incorrect
|
Bug #4240: Ash storm origin coordinates and hand shielding animation behavior are incorrect
|
||||||
Bug #4270: Closing doors while they are obstructed desyncs closing sfx
|
Bug #4270: Closing doors while they are obstructed desyncs closing sfx
|
||||||
|
@ -28,6 +30,7 @@
|
||||||
Bug #4384: Resist Normal Weapons only checks ammunition for ranged weapons
|
Bug #4384: Resist Normal Weapons only checks ammunition for ranged weapons
|
||||||
Bug #4411: Reloading a saved game while falling prevents damage in some cases
|
Bug #4411: Reloading a saved game while falling prevents damage in some cases
|
||||||
Bug #4449: Value returned by GetWindSpeed is incorrect
|
Bug #4449: Value returned by GetWindSpeed is incorrect
|
||||||
|
Bug #4456: AiActivate should not be cancelled after target activation
|
||||||
Bug #4540: Rain delay when exiting water
|
Bug #4540: Rain delay when exiting water
|
||||||
Bug #4600: Crash when no sound output is available or --no-sound is used.
|
Bug #4600: Crash when no sound output is available or --no-sound is used.
|
||||||
Bug #4639: Black screen after completing first mages guild mission + training
|
Bug #4639: Black screen after completing first mages guild mission + training
|
||||||
|
@ -77,6 +80,7 @@
|
||||||
Bug #4888: Global variable stray explicit reference calls break script compilation
|
Bug #4888: Global variable stray explicit reference calls break script compilation
|
||||||
Bug #4896: Title screen music doesn't loop
|
Bug #4896: Title screen music doesn't loop
|
||||||
Bug #4902: Using scrollbars in settings causes resolution to change
|
Bug #4902: Using scrollbars in settings causes resolution to change
|
||||||
|
Bug #4904: Editor: Texture painting with duplicate of a base-version texture
|
||||||
Bug #4911: Editor: QOpenGLContext::swapBuffers() warning with Qt5
|
Bug #4911: Editor: QOpenGLContext::swapBuffers() warning with Qt5
|
||||||
Bug #4916: Specular power (shininess) material parameter is ignored when shaders are used.
|
Bug #4916: Specular power (shininess) material parameter is ignored when shaders are used.
|
||||||
Bug #4918: Abilities don't play looping VFX when they're initially applied
|
Bug #4918: Abilities don't play looping VFX when they're initially applied
|
||||||
|
@ -116,6 +120,7 @@
|
||||||
Bug #5050: Invalid spell effects are not handled gracefully
|
Bug #5050: Invalid spell effects are not handled gracefully
|
||||||
Bug #5055: Mark, Recall, Intervention magic effect abilities have no effect when added and removed in the same frame
|
Bug #5055: Mark, Recall, Intervention magic effect abilities have no effect when added and removed in the same frame
|
||||||
Bug #5056: Calling Cast function on player doesn't equip the spell but casts it
|
Bug #5056: Calling Cast function on player doesn't equip the spell but casts it
|
||||||
|
Bug #5059: Modded animation with combined attack keys always does max damage and can double damage
|
||||||
Bug #5060: Magic effect visuals stop when death animation begins instead of when it ends
|
Bug #5060: Magic effect visuals stop when death animation begins instead of when it ends
|
||||||
Bug #5063: Shape named "Tri Shadow" in creature mesh is visible if it isn't hidden
|
Bug #5063: Shape named "Tri Shadow" in creature mesh is visible if it isn't hidden
|
||||||
Bug #5067: Ranged attacks on unaware opponents ("critical hits") differ from the vanilla engine
|
Bug #5067: Ranged attacks on unaware opponents ("critical hits") differ from the vanilla engine
|
||||||
|
@ -140,6 +145,7 @@
|
||||||
Bug #5124: Arrow remains attached to actor if pulling animation was cancelled
|
Bug #5124: Arrow remains attached to actor if pulling animation was cancelled
|
||||||
Bug #5126: Swimming creatures without RunForward animations are motionless during combat
|
Bug #5126: Swimming creatures without RunForward animations are motionless during combat
|
||||||
Bug #5134: Doors rotation by "Lock" console command is inconsistent
|
Bug #5134: Doors rotation by "Lock" console command is inconsistent
|
||||||
|
Bug #5136: LegionUniform script: can not access local variables
|
||||||
Bug #5137: Textures with Clamp Mode set to Clamp instead of Wrap are too dark outside the boundaries
|
Bug #5137: Textures with Clamp Mode set to Clamp instead of Wrap are too dark outside the boundaries
|
||||||
Bug #5149: Failing lock pick attempts isn't always a crime
|
Bug #5149: Failing lock pick attempts isn't always a crime
|
||||||
Bug #5155: Lock/unlock behavior differs from vanilla
|
Bug #5155: Lock/unlock behavior differs from vanilla
|
||||||
|
@ -151,6 +157,8 @@
|
||||||
Bug #5167: Player can select and cast spells before magic menu is enabled
|
Bug #5167: Player can select and cast spells before magic menu is enabled
|
||||||
Bug #5168: Force1stPerson and Force3rdPerson commands are not really force view change
|
Bug #5168: Force1stPerson and Force3rdPerson commands are not really force view change
|
||||||
Bug #5169: Nested levelled items/creatures have significantly higher chance not to spawn
|
Bug #5169: Nested levelled items/creatures have significantly higher chance not to spawn
|
||||||
|
Bug #5175: Random script function returns an integer value
|
||||||
|
Bug #5177: Editor: Unexplored map tiles get corrupted after a file with terrain is saved
|
||||||
Feature #1774: Handle AvoidNode
|
Feature #1774: Handle AvoidNode
|
||||||
Feature #2229: Improve pathfinding AI
|
Feature #2229: Improve pathfinding AI
|
||||||
Feature #3025: Analogue gamepad movement controls
|
Feature #3025: Analogue gamepad movement controls
|
||||||
|
|
|
@ -101,7 +101,9 @@ Editor Bug Fixes:
|
||||||
- Colour fields in interior-cell records now also use the colour picker widget (#4745)
|
- Colour fields in interior-cell records now also use the colour picker widget (#4745)
|
||||||
- Cloned, added, or moved instances no longer disappear at load-time (#4748)
|
- Cloned, added, or moved instances no longer disappear at load-time (#4748)
|
||||||
- "Clear" function in the content selector no longer tries to execute a "Remove" action on an empty file list (#4757)
|
- "Clear" function in the content selector no longer tries to execute a "Remove" action on an empty file list (#4757)
|
||||||
|
- Terrain texture editing for plugins now correctly handles drags from base file (#4904)
|
||||||
- Engine no longer tries to swap buffers of windows which weren't exposed to Qt's window management system (#4911)
|
- Engine no longer tries to swap buffers of windows which weren't exposed to Qt's window management system (#4911)
|
||||||
|
- Minimap doesn't get corrupted, when editing new omwgame (#5177)
|
||||||
|
|
||||||
Miscellaneous:
|
Miscellaneous:
|
||||||
- Upgraded to FFMPEG3 for media decoding (#4686)
|
- Upgraded to FFMPEG3 for media decoding (#4686)
|
||||||
|
|
|
@ -41,9 +41,9 @@
|
||||||
CSVRender::TerrainTextureMode::TerrainTextureMode (WorldspaceWidget *worldspaceWidget, osg::Group* parentNode, QWidget *parent)
|
CSVRender::TerrainTextureMode::TerrainTextureMode (WorldspaceWidget *worldspaceWidget, osg::Group* parentNode, QWidget *parent)
|
||||||
: EditMode (worldspaceWidget, QIcon {":scenetoolbar/editing-terrain-texture"}, Mask_Terrain | Mask_Reference, "Terrain texture editing", parent),
|
: EditMode (worldspaceWidget, QIcon {":scenetoolbar/editing-terrain-texture"}, Mask_Terrain | Mask_Reference, "Terrain texture editing", parent),
|
||||||
mBrushTexture("L0#0"),
|
mBrushTexture("L0#0"),
|
||||||
mBrushSize(0),
|
mBrushSize(1),
|
||||||
mBrushShape(0),
|
mBrushShape(0),
|
||||||
mTextureBrushScenetool(0),
|
mTextureBrushScenetool(nullptr),
|
||||||
mDragMode(InteractionType_None),
|
mDragMode(InteractionType_None),
|
||||||
mParentNode(parentNode),
|
mParentNode(parentNode),
|
||||||
mIsEditing(false)
|
mIsEditing(false)
|
||||||
|
@ -82,7 +82,7 @@ void CSVRender::TerrainTextureMode::deactivate(CSVWidget::SceneToolbar* toolbar)
|
||||||
{
|
{
|
||||||
toolbar->removeTool (mTextureBrushScenetool);
|
toolbar->removeTool (mTextureBrushScenetool);
|
||||||
delete mTextureBrushScenetool;
|
delete mTextureBrushScenetool;
|
||||||
mTextureBrushScenetool = 0;
|
mTextureBrushScenetool = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mTerrainTextureSelection)
|
if (mTerrainTextureSelection)
|
||||||
|
|
|
@ -51,36 +51,37 @@ namespace CSVRender
|
||||||
/// \brief Editmode for terrain texture grid
|
/// \brief Editmode for terrain texture grid
|
||||||
TerrainTextureMode(WorldspaceWidget*, osg::Group* parentNode, QWidget* parent = nullptr);
|
TerrainTextureMode(WorldspaceWidget*, osg::Group* parentNode, QWidget* parent = nullptr);
|
||||||
|
|
||||||
void primaryOpenPressed (const WorldspaceHitResult& hit);
|
void primaryOpenPressed (const WorldspaceHitResult& hit) final;
|
||||||
|
|
||||||
/// \brief Create single command for one-click texture editing
|
/// \brief Create single command for one-click texture editing
|
||||||
void primaryEditPressed (const WorldspaceHitResult& hit);
|
void primaryEditPressed (const WorldspaceHitResult& hit) final;
|
||||||
|
|
||||||
/// \brief Open brush settings window
|
/// \brief Open brush settings window
|
||||||
void primarySelectPressed(const WorldspaceHitResult&);
|
void primarySelectPressed(const WorldspaceHitResult&) final;
|
||||||
|
|
||||||
void secondarySelectPressed(const WorldspaceHitResult&);
|
void secondarySelectPressed(const WorldspaceHitResult&) final;
|
||||||
|
|
||||||
void activate(CSVWidget::SceneToolbar*);
|
void activate(CSVWidget::SceneToolbar*) final;
|
||||||
void deactivate(CSVWidget::SceneToolbar*);
|
void deactivate(CSVWidget::SceneToolbar*) final;
|
||||||
|
|
||||||
/// \brief Start texture editing command macro
|
/// \brief Start texture editing command macro
|
||||||
virtual bool primaryEditStartDrag (const QPoint& pos);
|
bool primaryEditStartDrag (const QPoint& pos) final;
|
||||||
|
|
||||||
virtual bool secondaryEditStartDrag (const QPoint& pos);
|
bool secondaryEditStartDrag (const QPoint& pos) final;
|
||||||
virtual bool primarySelectStartDrag (const QPoint& pos);
|
bool primarySelectStartDrag (const QPoint& pos) final;
|
||||||
virtual bool secondarySelectStartDrag (const QPoint& pos);
|
bool secondarySelectStartDrag (const QPoint& pos) final;
|
||||||
|
|
||||||
/// \brief Handle texture edit behavior during dragging
|
/// \brief Handle texture edit behavior during dragging
|
||||||
virtual void drag (const QPoint& pos, int diffX, int diffY, double speedFactor);
|
void drag (const QPoint& pos, int diffX, int diffY, double speedFactor) final;
|
||||||
|
|
||||||
/// \brief End texture editing command macro
|
/// \brief End texture editing command macro
|
||||||
virtual void dragCompleted(const QPoint& pos);
|
void dragCompleted(const QPoint& pos) final;
|
||||||
|
|
||||||
virtual void dragAborted();
|
void dragAborted() final;
|
||||||
virtual void dragWheel (int diff, double speedFactor);
|
void dragWheel (int diff, double speedFactor) final;
|
||||||
virtual void dragMoveEvent (QDragMoveEvent *event);
|
void dragMoveEvent (QDragMoveEvent *event) final;
|
||||||
|
|
||||||
|
private:
|
||||||
/// \brief Handle brush mechanics, maths regarding worldspace hit etc.
|
/// \brief Handle brush mechanics, maths regarding worldspace hit etc.
|
||||||
void editTerrainTextureGrid (const WorldspaceHitResult& hit);
|
void editTerrainTextureGrid (const WorldspaceHitResult& hit);
|
||||||
|
|
||||||
|
@ -100,7 +101,6 @@ namespace CSVRender
|
||||||
/// \brief Create new cell and land if needed
|
/// \brief Create new cell and land if needed
|
||||||
bool allowLandTextureEditing(std::string textureFileName);
|
bool allowLandTextureEditing(std::string textureFileName);
|
||||||
|
|
||||||
private:
|
|
||||||
std::string mCellId;
|
std::string mCellId;
|
||||||
std::string mBrushTexture;
|
std::string mBrushTexture;
|
||||||
int mBrushSize;
|
int mBrushSize;
|
||||||
|
@ -113,7 +113,6 @@ namespace CSVRender
|
||||||
std::unique_ptr<TerrainSelection> mTerrainTextureSelection;
|
std::unique_ptr<TerrainSelection> mTerrainTextureSelection;
|
||||||
|
|
||||||
const int cellSize {ESM::Land::REAL_SIZE};
|
const int cellSize {ESM::Land::REAL_SIZE};
|
||||||
const int landSize {ESM::Land::LAND_SIZE};
|
|
||||||
const int landTextureSize {ESM::Land::LAND_TEXTURE_SIZE};
|
const int landTextureSize {ESM::Land::LAND_TEXTURE_SIZE};
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
|
@ -33,19 +33,19 @@
|
||||||
|
|
||||||
|
|
||||||
CSVWidget::BrushSizeControls::BrushSizeControls(const QString &title, QWidget *parent)
|
CSVWidget::BrushSizeControls::BrushSizeControls(const QString &title, QWidget *parent)
|
||||||
: QGroupBox(title, parent)
|
: QGroupBox(title, parent),
|
||||||
|
mLayoutSliderSize(new QHBoxLayout),
|
||||||
|
mBrushSizeSlider(new QSlider(Qt::Horizontal)),
|
||||||
|
mBrushSizeSpinBox(new QSpinBox)
|
||||||
{
|
{
|
||||||
mBrushSizeSlider = new QSlider(Qt::Horizontal);
|
|
||||||
mBrushSizeSlider->setTickPosition(QSlider::TicksBothSides);
|
mBrushSizeSlider->setTickPosition(QSlider::TicksBothSides);
|
||||||
mBrushSizeSlider->setTickInterval(10);
|
mBrushSizeSlider->setTickInterval(10);
|
||||||
mBrushSizeSlider->setRange(1, CSMPrefs::get()["3D Scene Editing"]["texturebrush-maximumsize"].toInt());
|
mBrushSizeSlider->setRange(1, CSMPrefs::get()["3D Scene Editing"]["texturebrush-maximumsize"].toInt());
|
||||||
mBrushSizeSlider->setSingleStep(1);
|
mBrushSizeSlider->setSingleStep(1);
|
||||||
|
|
||||||
mBrushSizeSpinBox = new QSpinBox;
|
|
||||||
mBrushSizeSpinBox->setRange(1, CSMPrefs::get()["3D Scene Editing"]["texturebrush-maximumsize"].toInt());
|
mBrushSizeSpinBox->setRange(1, CSMPrefs::get()["3D Scene Editing"]["texturebrush-maximumsize"].toInt());
|
||||||
mBrushSizeSpinBox->setSingleStep(1);
|
mBrushSizeSpinBox->setSingleStep(1);
|
||||||
|
|
||||||
mLayoutSliderSize = new QHBoxLayout;
|
|
||||||
mLayoutSliderSize->addWidget(mBrushSizeSlider);
|
mLayoutSliderSize->addWidget(mBrushSizeSlider);
|
||||||
mLayoutSliderSize->addWidget(mBrushSizeSpinBox);
|
mLayoutSliderSize->addWidget(mBrushSizeSpinBox);
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ CSVWidget::BrushSizeControls::BrushSizeControls(const QString &title, QWidget *p
|
||||||
CSVWidget::TextureBrushWindow::TextureBrushWindow(CSMDoc::Document& document, QWidget *parent)
|
CSVWidget::TextureBrushWindow::TextureBrushWindow(CSMDoc::Document& document, QWidget *parent)
|
||||||
: QFrame(parent, Qt::Popup),
|
: QFrame(parent, Qt::Popup),
|
||||||
mBrushShape(0),
|
mBrushShape(0),
|
||||||
mBrushSize(0),
|
mBrushSize(1),
|
||||||
mBrushTexture("L0#0"),
|
mBrushTexture("L0#0"),
|
||||||
mDocument(document)
|
mDocument(document)
|
||||||
{
|
{
|
||||||
|
@ -142,60 +142,61 @@ void CSVWidget::TextureBrushWindow::configureButtonInitialSettings(QPushButton *
|
||||||
|
|
||||||
void CSVWidget::TextureBrushWindow::setBrushTexture(std::string brushTexture)
|
void CSVWidget::TextureBrushWindow::setBrushTexture(std::string brushTexture)
|
||||||
{
|
{
|
||||||
mBrushTexture = brushTexture;
|
CSMWorld::IdTable& ltexTable = dynamic_cast<CSMWorld::IdTable&> (
|
||||||
|
*mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures));
|
||||||
|
QUndoStack& undoStack = mDocument.getUndoStack();
|
||||||
|
|
||||||
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = mDocument.getData().getLandTextures();
|
CSMWorld::IdCollection<CSMWorld::LandTexture>& landtexturesCollection = mDocument.getData().getLandTextures();
|
||||||
|
|
||||||
int landTextureFilename = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Texture);
|
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
|
int index = 0;
|
||||||
if(landtexturesCollection.getData(index, columnModification).value<int>() == 0)
|
int pluginInDragged = 0;
|
||||||
|
CSMWorld::LandTexture::parseUniqueRecordId(brushTexture, pluginInDragged, index);
|
||||||
|
std::string newBrushTextureId = CSMWorld::LandTexture::createUniqueRecordId(0, index);
|
||||||
|
int rowInBase = landtexturesCollection.searchId(brushTexture);
|
||||||
|
int rowInNew = landtexturesCollection.searchId(newBrushTextureId);
|
||||||
|
|
||||||
|
// Check if texture exists in current plugin, and clone if id found in base, otherwise reindex the texture
|
||||||
|
// TO-DO: Handle case when texture is not found in neither base or plugin properly (finding new index is not enough)
|
||||||
|
// TO-DO: Handle conflicting plugins properly
|
||||||
|
if (rowInNew == -1)
|
||||||
{
|
{
|
||||||
CSMWorld::IdTable& ltexTable = dynamic_cast<CSMWorld::IdTable&> (
|
if (rowInBase == -1)
|
||||||
*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;
|
int counter=0;
|
||||||
bool freeIndexFound = false;
|
bool freeIndexFound = false;
|
||||||
|
const int maxCounter = std::numeric_limits<uint16_t>::max() - 1;
|
||||||
do {
|
do {
|
||||||
const size_t maxCounter = std::numeric_limits<uint16_t>::max() - 1;
|
newBrushTextureId = CSMWorld::LandTexture::createUniqueRecordId(0, counter);
|
||||||
mBrushTexturePlugin = CSMWorld::LandTexture::createUniqueRecordId(0, counter);
|
if (landtexturesCollection.searchId(brushTexture) != -1 &&
|
||||||
if (landtexturesCollection.searchId(mBrushTexturePlugin) != -1 && landtexturesCollection.getRecord(mBrushTexturePlugin).isDeleted() == 0) counter = (counter + 1) % maxCounter;
|
landtexturesCollection.getRecord(brushTexture).isDeleted() == 0 &&
|
||||||
|
landtexturesCollection.searchId(newBrushTextureId) != -1 &&
|
||||||
|
landtexturesCollection.getRecord(newBrushTextureId).isDeleted() == 0)
|
||||||
|
counter = (counter + 1) % maxCounter;
|
||||||
else freeIndexFound = true;
|
else freeIndexFound = true;
|
||||||
} while (freeIndexFound == false);
|
} while (freeIndexFound == false || counter < maxCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
undoStack.beginMacro ("Add land texture record");
|
undoStack.beginMacro ("Add land texture record");
|
||||||
undoStack.push (new CSMWorld::CloneCommand (ltexTable, mBrushTexture, mBrushTexturePlugin, CSMWorld::UniversalId::Type_LandTexture));
|
undoStack.push (new CSMWorld::CloneCommand (ltexTable, brushTexture, newBrushTextureId, CSMWorld::UniversalId::Type_LandTexture));
|
||||||
undoStack.endMacro();
|
undoStack.endMacro();
|
||||||
mBrushTexture = mBrushTexturePlugin;
|
|
||||||
emit passTextureId(mBrushTexture);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted())
|
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted())
|
||||||
{
|
{
|
||||||
mBrushTextureLabel = "Selected texture: " + mBrushTexture + " ";
|
mBrushTextureLabel = "Selected texture: " + newBrushTextureId + " ";
|
||||||
mSelectedBrush->setText(QString::fromStdString(mBrushTextureLabel) + landtexturesCollection.getData(index, landTextureFilename).value<QString>());
|
mSelectedBrush->setText(QString::fromStdString(mBrushTextureLabel) + landtexturesCollection.getData(index, landTextureFilename).value<QString>());
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
|
newBrushTextureId = "";
|
||||||
mBrushTextureLabel = "No selected texture or invalid texture";
|
mBrushTextureLabel = "No selected texture or invalid texture";
|
||||||
mSelectedBrush->setText(QString::fromStdString(mBrushTextureLabel));
|
mSelectedBrush->setText(QString::fromStdString(mBrushTextureLabel));
|
||||||
}
|
}
|
||||||
|
|
||||||
emit passBrushShape(mBrushShape); // update icon
|
mBrushTexture = newBrushTextureId;
|
||||||
|
|
||||||
|
emit passTextureId(mBrushTexture);
|
||||||
|
emit passBrushShape(mBrushShape); // updates the icon tooltip
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWidget::TextureBrushWindow::setBrushSize(int brushSize)
|
void CSVWidget::TextureBrushWindow::setBrushSize(int brushSize)
|
||||||
|
|
|
@ -81,7 +81,7 @@ add_openmw_dir (mwclass
|
||||||
add_openmw_dir (mwmechanics
|
add_openmw_dir (mwmechanics
|
||||||
mechanicsmanagerimp stat creaturestats magiceffects movement actorutil
|
mechanicsmanagerimp stat creaturestats magiceffects movement actorutil
|
||||||
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aibreathe
|
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aibreathe
|
||||||
aicast aiescort aiface aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting
|
aicast aiescort aiface aiactivate aicombat recharge repair enchanting pathfinding pathgrid security spellsuccess spellcasting
|
||||||
disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning
|
disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning
|
||||||
character actors objects aistate coordinateconverter trading weaponpriority spellpriority weapontype
|
character actors objects aistate coordinateconverter trading weaponpriority spellpriority weapontype
|
||||||
)
|
)
|
||||||
|
|
|
@ -133,6 +133,7 @@ bool OMW::Engine::frame(float frametime)
|
||||||
{
|
{
|
||||||
double hours = (frametime * mEnvironment.getWorld()->getTimeScaleFactor()) / 3600.0;
|
double hours = (frametime * mEnvironment.getWorld()->getTimeScaleFactor()) / 3600.0;
|
||||||
mEnvironment.getWorld()->advanceTime(hours, true);
|
mEnvironment.getWorld()->advanceTime(hours, true);
|
||||||
|
mEnvironment.getWorld()->rechargeItems(frametime, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
osg::Timer_t afterScriptTick = osg::Timer::instance()->tick();
|
osg::Timer_t afterScriptTick = osg::Timer::instance()->tick();
|
||||||
|
|
|
@ -73,8 +73,6 @@ namespace MWBase
|
||||||
/// \param paused In game type does not currently advance (this usually means some GUI
|
/// \param paused In game type does not currently advance (this usually means some GUI
|
||||||
/// component is up).
|
/// component is up).
|
||||||
|
|
||||||
virtual void advanceTime (float duration) = 0;
|
|
||||||
|
|
||||||
virtual void setPlayerName (const std::string& name) = 0;
|
virtual void setPlayerName (const std::string& name) = 0;
|
||||||
///< Set player name.
|
///< Set player name.
|
||||||
|
|
||||||
|
|
|
@ -584,6 +584,7 @@ namespace MWBase
|
||||||
virtual bool isPlayerInJail() const = 0;
|
virtual bool isPlayerInJail() const = 0;
|
||||||
|
|
||||||
virtual void rest(double hours) = 0;
|
virtual void rest(double hours) = 0;
|
||||||
|
virtual void rechargeItems(double duration, bool activeOnly) = 0;
|
||||||
|
|
||||||
virtual void setPlayerTraveling(bool traveling) = 0;
|
virtual void setPlayerTraveling(bool traveling) = 0;
|
||||||
virtual bool isPlayerTraveling() const = 0;
|
virtual bool isPlayerTraveling() const = 0;
|
||||||
|
|
|
@ -25,12 +25,12 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::Ptr CompanionItemModel::copyItem (const ItemStack& item, size_t count, bool setNewOwner=false)
|
MWWorld::Ptr CompanionItemModel::copyItem (const ItemStack& item, size_t count)
|
||||||
{
|
{
|
||||||
if (hasProfit(mActor))
|
if (hasProfit(mActor))
|
||||||
modifyProfit(mActor, item.mBase.getClass().getValue(item.mBase) * count);
|
modifyProfit(mActor, item.mBase.getClass().getValue(item.mBase) * count);
|
||||||
|
|
||||||
return InventoryItemModel::copyItem(item, count, setNewOwner);
|
return InventoryItemModel::copyItem(item, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompanionItemModel::removeItem (const ItemStack& item, size_t count)
|
void CompanionItemModel::removeItem (const ItemStack& item, size_t count)
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace MWGui
|
||||||
public:
|
public:
|
||||||
CompanionItemModel (const MWWorld::Ptr& actor);
|
CompanionItemModel (const MWWorld::Ptr& actor);
|
||||||
|
|
||||||
virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner);
|
virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count);
|
||||||
virtual void removeItem (const ItemStack& item, size_t count);
|
virtual void removeItem (const ItemStack& item, size_t count);
|
||||||
|
|
||||||
bool hasProfit(const MWWorld::Ptr& actor);
|
bool hasProfit(const MWWorld::Ptr& actor);
|
||||||
|
|
|
@ -91,7 +91,7 @@ ItemModel::ModelIndex ContainerItemModel::getIndex (ItemStack item)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::Ptr ContainerItemModel::copyItem (const ItemStack& item, size_t count, bool setNewOwner)
|
MWWorld::Ptr ContainerItemModel::copyItem (const ItemStack& item, size_t count)
|
||||||
{
|
{
|
||||||
const MWWorld::Ptr& source = mItemSources[mItemSources.size()-1];
|
const MWWorld::Ptr& source = mItemSources[mItemSources.size()-1];
|
||||||
if (item.mBase.getContainerStore() == &source.getClass().getContainerStore(source))
|
if (item.mBase.getContainerStore() == &source.getClass().getContainerStore(source))
|
||||||
|
|
|
@ -26,7 +26,7 @@ namespace MWGui
|
||||||
virtual ModelIndex getIndex (ItemStack item);
|
virtual ModelIndex getIndex (ItemStack item);
|
||||||
virtual size_t getItemCount();
|
virtual size_t getItemCount();
|
||||||
|
|
||||||
virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false);
|
virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count);
|
||||||
virtual void removeItem (const ItemStack& item, size_t count);
|
virtual void removeItem (const ItemStack& item, size_t count);
|
||||||
|
|
||||||
virtual void update();
|
virtual void update();
|
||||||
|
|
|
@ -38,7 +38,7 @@ namespace MWGui
|
||||||
public:
|
public:
|
||||||
WorldItemModel(float left, float top) : mLeft(left), mTop(top) {}
|
WorldItemModel(float left, float top) : mLeft(left), mTop(top) {}
|
||||||
virtual ~WorldItemModel() {}
|
virtual ~WorldItemModel() {}
|
||||||
virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false)
|
virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count)
|
||||||
{
|
{
|
||||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
|
|
||||||
|
@ -47,8 +47,7 @@ namespace MWGui
|
||||||
dropped = world->placeObject(item.mBase, mLeft, mTop, count);
|
dropped = world->placeObject(item.mBase, mLeft, mTop, count);
|
||||||
else
|
else
|
||||||
dropped = world->dropObjectOnGround(world->getPlayerPtr(), item.mBase, count);
|
dropped = world->dropObjectOnGround(world->getPlayerPtr(), item.mBase, count);
|
||||||
if (setNewOwner)
|
dropped.getCellRef().setOwner("");
|
||||||
dropped.getCellRef().setOwner("");
|
|
||||||
|
|
||||||
return dropped;
|
return dropped;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,11 +46,11 @@ ItemModel::ModelIndex InventoryItemModel::getIndex (ItemStack item)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::Ptr InventoryItemModel::copyItem (const ItemStack& item, size_t count, bool setNewOwner)
|
MWWorld::Ptr InventoryItemModel::copyItem (const ItemStack& item, size_t count)
|
||||||
{
|
{
|
||||||
if (item.mBase.getContainerStore() == &mActor.getClass().getContainerStore(mActor))
|
if (item.mBase.getContainerStore() == &mActor.getClass().getContainerStore(mActor))
|
||||||
throw std::runtime_error("Item to copy needs to be from a different container!");
|
throw std::runtime_error("Item to copy needs to be from a different container!");
|
||||||
return *mActor.getClass().getContainerStore(mActor).add(item.mBase, count, mActor, setNewOwner);
|
return *mActor.getClass().getContainerStore(mActor).add(item.mBase, count, mActor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InventoryItemModel::removeItem (const ItemStack& item, size_t count)
|
void InventoryItemModel::removeItem (const ItemStack& item, size_t count)
|
||||||
|
@ -88,7 +88,7 @@ MWWorld::Ptr InventoryItemModel::moveItem(const ItemStack &item, size_t count, I
|
||||||
if (item.mFlags & ItemStack::Flag_Bound)
|
if (item.mFlags & ItemStack::Flag_Bound)
|
||||||
return MWWorld::Ptr();
|
return MWWorld::Ptr();
|
||||||
|
|
||||||
MWWorld::Ptr ret = otherModel->copyItem(item, count, false);
|
MWWorld::Ptr ret = otherModel->copyItem(item, count);
|
||||||
removeItem(item, count);
|
removeItem(item, count);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace MWGui
|
||||||
|
|
||||||
virtual bool onTakeItem(const MWWorld::Ptr &item, int count);
|
virtual bool onTakeItem(const MWWorld::Ptr &item, int count);
|
||||||
|
|
||||||
virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false);
|
virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count);
|
||||||
virtual void removeItem (const ItemStack& item, size_t count);
|
virtual void removeItem (const ItemStack& item, size_t count);
|
||||||
|
|
||||||
/// Move items from this model to \a otherModel.
|
/// Move items from this model to \a otherModel.
|
||||||
|
|
|
@ -116,9 +116,9 @@ namespace MWGui
|
||||||
return mSourceModel->allowedToUseItems();
|
return mSourceModel->allowedToUseItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::Ptr ProxyItemModel::copyItem (const ItemStack& item, size_t count, bool setNewOwner)
|
MWWorld::Ptr ProxyItemModel::copyItem (const ItemStack& item, size_t count)
|
||||||
{
|
{
|
||||||
return mSourceModel->copyItem (item, count, setNewOwner);
|
return mSourceModel->copyItem (item, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProxyItemModel::removeItem (const ItemStack& item, size_t count)
|
void ProxyItemModel::removeItem (const ItemStack& item, size_t count)
|
||||||
|
|
|
@ -67,7 +67,7 @@ namespace MWGui
|
||||||
|
|
||||||
/// @param setNewOwner If true, set the copied item's owner to the actor we are copying to,
|
/// @param setNewOwner If true, set the copied item's owner to the actor we are copying to,
|
||||||
/// otherwise reset owner to ""
|
/// otherwise reset owner to ""
|
||||||
virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false) = 0;
|
virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count) = 0;
|
||||||
virtual void removeItem (const ItemStack& item, size_t count) = 0;
|
virtual void removeItem (const ItemStack& item, size_t count) = 0;
|
||||||
|
|
||||||
/// Is the player allowed to use items from this item model? (default true)
|
/// Is the player allowed to use items from this item model? (default true)
|
||||||
|
@ -97,7 +97,7 @@ namespace MWGui
|
||||||
virtual bool onDropItem(const MWWorld::Ptr &item, int count);
|
virtual bool onDropItem(const MWWorld::Ptr &item, int count);
|
||||||
virtual bool onTakeItem(const MWWorld::Ptr &item, int count);
|
virtual bool onTakeItem(const MWWorld::Ptr &item, int count);
|
||||||
|
|
||||||
virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false);
|
virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count);
|
||||||
virtual void removeItem (const ItemStack& item, size_t count);
|
virtual void removeItem (const ItemStack& item, size_t count);
|
||||||
virtual ModelIndex getIndex (ItemStack item);
|
virtual ModelIndex getIndex (ItemStack item);
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,7 @@ namespace MWGui
|
||||||
if (pickpocket.finish())
|
if (pickpocket.finish())
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getMechanicsManager()->commitCrime(
|
MWBase::Environment::get().getMechanicsManager()->commitCrime(
|
||||||
player, mActor, MWBase::MechanicsManager::OT_Pickpocket, 0, true);
|
player, mActor, MWBase::MechanicsManager::OT_Pickpocket, std::string(), 0, true);
|
||||||
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container);
|
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container);
|
||||||
mPickpocketDetected = true;
|
mPickpocketDetected = true;
|
||||||
}
|
}
|
||||||
|
@ -126,7 +126,7 @@ namespace MWGui
|
||||||
if (pickpocket.pick(item, count))
|
if (pickpocket.pick(item, count))
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getMechanicsManager()->commitCrime(
|
MWBase::Environment::get().getMechanicsManager()->commitCrime(
|
||||||
player, mActor, MWBase::MechanicsManager::OT_Pickpocket, 0, true);
|
player, mActor, MWBase::MechanicsManager::OT_Pickpocket, std::string(), 0, true);
|
||||||
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container);
|
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container);
|
||||||
mPickpocketDetected = true;
|
mPickpocketDetected = true;
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include "../mwmechanics/creaturestats.hpp"
|
#include "../mwmechanics/creaturestats.hpp"
|
||||||
#include "../mwmechanics/actorutil.hpp"
|
#include "../mwmechanics/actorutil.hpp"
|
||||||
|
#include "../mwmechanics/recharge.hpp"
|
||||||
|
|
||||||
#include "itemwidget.hpp"
|
#include "itemwidget.hpp"
|
||||||
#include "itemchargeview.hpp"
|
#include "itemchargeview.hpp"
|
||||||
|
@ -130,62 +131,9 @@ void Recharge::onItemCancel()
|
||||||
void Recharge::onItemClicked(MyGUI::Widget *sender, const MWWorld::Ptr& item)
|
void Recharge::onItemClicked(MyGUI::Widget *sender, const MWWorld::Ptr& item)
|
||||||
{
|
{
|
||||||
MWWorld::Ptr gem = *mGemIcon->getUserData<MWWorld::Ptr>();
|
MWWorld::Ptr gem = *mGemIcon->getUserData<MWWorld::Ptr>();
|
||||||
|
if (!MWMechanics::rechargeItem(item, gem))
|
||||||
if (!gem.getRefData().getCount())
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
MWWorld::Ptr player = MWMechanics::getPlayer();
|
|
||||||
MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
|
|
||||||
|
|
||||||
float luckTerm = 0.1f * stats.getAttribute(ESM::Attribute::Luck).getModified();
|
|
||||||
if (luckTerm < 1|| luckTerm > 10)
|
|
||||||
luckTerm = 1;
|
|
||||||
|
|
||||||
float intelligenceTerm = 0.2f * stats.getAttribute(ESM::Attribute::Intelligence).getModified();
|
|
||||||
|
|
||||||
if (intelligenceTerm > 20)
|
|
||||||
intelligenceTerm = 20;
|
|
||||||
if (intelligenceTerm < 1)
|
|
||||||
intelligenceTerm = 1;
|
|
||||||
|
|
||||||
float x = (player.getClass().getSkill(player, ESM::Skill::Enchant) + intelligenceTerm + luckTerm) * stats.getFatigueTerm();
|
|
||||||
int roll = Misc::Rng::roll0to99();
|
|
||||||
if (roll < x)
|
|
||||||
{
|
|
||||||
std::string soul = gem.getCellRef().getSoul();
|
|
||||||
const ESM::Creature *creature = MWBase::Environment::get().getWorld()->getStore().get<ESM::Creature>().find(soul);
|
|
||||||
|
|
||||||
float restored = creature->mData.mSoul * (roll / x);
|
|
||||||
|
|
||||||
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find(
|
|
||||||
item.getClass().getEnchantment(item));
|
|
||||||
item.getCellRef().setEnchantmentCharge(
|
|
||||||
std::min(item.getCellRef().getEnchantmentCharge() + restored, static_cast<float>(enchantment->mData.mCharge)));
|
|
||||||
|
|
||||||
MWBase::Environment::get().getWindowManager()->playSound("Enchant Success");
|
|
||||||
|
|
||||||
player.getClass().getContainerStore(player).restack(item);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MWBase::Environment::get().getWindowManager()->playSound("Enchant Fail");
|
|
||||||
}
|
|
||||||
|
|
||||||
player.getClass().skillUsageSucceeded (player, ESM::Skill::Enchant, 0);
|
|
||||||
gem.getContainerStore()->remove(gem, 1, player);
|
|
||||||
|
|
||||||
if (gem.getRefData().getCount() == 0)
|
|
||||||
{
|
|
||||||
std::string message = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sNotifyMessage51")->mValue.getString();
|
|
||||||
message = Misc::StringUtils::format(message, gem.getClass().getName(gem));
|
|
||||||
|
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox(message);
|
|
||||||
|
|
||||||
// special case: readd Azura's Star
|
|
||||||
if (Misc::StringUtils::ciEqual(gem.get<ESM::Miscellaneous>()->mBase->mId, "Misc_SoulGem_Azura"))
|
|
||||||
player.getClass().getContainerStore(player).add("Misc_SoulGem_Azura", 1, player);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateView();
|
updateView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -652,19 +652,22 @@ namespace MWGui
|
||||||
std::string ret;
|
std::string ret;
|
||||||
ret += getMiscString(cellref.getOwner(), "Owner");
|
ret += getMiscString(cellref.getOwner(), "Owner");
|
||||||
const std::string factionId = cellref.getFaction();
|
const std::string factionId = cellref.getFaction();
|
||||||
ret += getMiscString(factionId, "Faction");
|
if (!factionId.empty())
|
||||||
if (!factionId.empty() && cellref.getFactionRank() >= 0)
|
|
||||||
{
|
{
|
||||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||||
const ESM::Faction *fact = store.get<ESM::Faction>().search(factionId);
|
const ESM::Faction *fact = store.get<ESM::Faction>().search(factionId);
|
||||||
if (fact != nullptr)
|
if (fact != nullptr)
|
||||||
{
|
{
|
||||||
int rank = cellref.getFactionRank();
|
ret += getMiscString(fact->mName.empty() ? factionId : fact->mName, "Owner Faction");
|
||||||
const std::string rankName = fact->mRanks[rank];
|
if (cellref.getFactionRank() >= 0)
|
||||||
if (rankName.empty())
|
{
|
||||||
ret += getValueString(cellref.getFactionRank(), "Rank");
|
int rank = cellref.getFactionRank();
|
||||||
else
|
const std::string rankName = fact->mRanks[rank];
|
||||||
ret += getMiscString(rankName, "Rank");
|
if (rankName.empty())
|
||||||
|
ret += getValueString(cellref.getFactionRank(), "Rank");
|
||||||
|
else
|
||||||
|
ret += getMiscString(rankName, "Rank");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "creaturestats.hpp"
|
#include "creaturestats.hpp"
|
||||||
#include "movement.hpp"
|
#include "movement.hpp"
|
||||||
|
#include "steering.hpp"
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
@ -33,16 +34,18 @@ namespace MWMechanics
|
||||||
if (target == MWWorld::Ptr() || !target.getRefData().getCount() || !target.getRefData().isEnabled())
|
if (target == MWWorld::Ptr() || !target.getRefData().getCount() || !target.getRefData().isEnabled())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
//Set the target destination for the actor
|
// Turn to target and move to it directly, without pathfinding.
|
||||||
const osg::Vec3f dest = target.getRefData().getPosition().asVec3();
|
const osg::Vec3f targetDir = target.getRefData().getPosition().asVec3() - actor.getRefData().getPosition().asVec3();
|
||||||
|
|
||||||
if (pathTo(actor, dest, duration, MWBase::Environment::get().getWorld()->getMaxActivationDistance())) //Stop when you get in activation range
|
zTurn(actor, std::atan2(targetDir.x(), targetDir.y()), 0.f);
|
||||||
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
|
||||||
|
actor.getClass().getMovementSettings(actor).mPosition[0] = 0;
|
||||||
|
|
||||||
|
if (MWBase::Environment::get().getWorld()->getMaxActivationDistance() >= targetDir.length())
|
||||||
{
|
{
|
||||||
// activate when reached
|
// Note: we intentionally do not cancel package after activation here for backward compatibility with original engine.
|
||||||
MWBase::Environment::get().getWorld()->activate(target, actor);
|
MWBase::Environment::get().getWorld()->activate(target, actor);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "aiavoiddoor.hpp"
|
#include "aiavoiddoor.hpp"
|
||||||
|
|
||||||
|
#include <components/misc/rng.hpp>
|
||||||
|
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
@ -11,8 +13,10 @@
|
||||||
#include "actorutil.hpp"
|
#include "actorutil.hpp"
|
||||||
#include "steering.hpp"
|
#include "steering.hpp"
|
||||||
|
|
||||||
|
static const int MAX_DIRECTIONS = 4;
|
||||||
|
|
||||||
MWMechanics::AiAvoidDoor::AiAvoidDoor(const MWWorld::ConstPtr& doorPtr)
|
MWMechanics::AiAvoidDoor::AiAvoidDoor(const MWWorld::ConstPtr& doorPtr)
|
||||||
: AiPackage(), mDuration(1), mDoorPtr(doorPtr), mLastPos(ESM::Position()), mAdjAngle(0)
|
: AiPackage(), mDuration(1), mDoorPtr(doorPtr), mDirection(0)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -22,25 +26,18 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, CharacterCont
|
||||||
|
|
||||||
ESM::Position pos = actor.getRefData().getPosition();
|
ESM::Position pos = actor.getRefData().getPosition();
|
||||||
if(mDuration == 1) //If it just started, get the actor position as the stuck detection thing
|
if(mDuration == 1) //If it just started, get the actor position as the stuck detection thing
|
||||||
mLastPos = pos;
|
mLastPos = pos.asVec3();
|
||||||
|
|
||||||
mDuration -= duration; //Update timer
|
mDuration -= duration; //Update timer
|
||||||
|
|
||||||
if(mDuration < 0) {
|
if (mDuration < 0)
|
||||||
float x = pos.pos[0] - mLastPos.pos[0];
|
{
|
||||||
float y = pos.pos[1] - mLastPos.pos[1];
|
if (isStuck(pos.asVec3()))
|
||||||
float z = pos.pos[2] - mLastPos.pos[2];
|
{
|
||||||
float distance = x * x + y * y + z * z;
|
adjustDirection();
|
||||||
if(distance < 10 * 10) { //Got stuck, didn't move
|
|
||||||
if(mAdjAngle == 0) //Try going in various directions
|
|
||||||
mAdjAngle = osg::PI / 2;
|
|
||||||
else if (mAdjAngle == osg::PI / 2)
|
|
||||||
mAdjAngle = -osg::PI / 2;
|
|
||||||
else
|
|
||||||
mAdjAngle = 0;
|
|
||||||
mDuration = 1; //reset timer
|
mDuration = 1; //reset timer
|
||||||
}
|
}
|
||||||
else //Not stuck
|
else
|
||||||
return true; // We have tried backing up for more than one second, we've probably cleared it
|
return true; // We have tried backing up for more than one second, we've probably cleared it
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +51,7 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, CharacterCont
|
||||||
actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
|
actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
|
||||||
|
|
||||||
// Turn away from the door and move when turn completed
|
// Turn away from the door and move when turn completed
|
||||||
if (zTurn(actor, std::atan2(x,y) + mAdjAngle, osg::DegreesToRadians(5.f)))
|
if (zTurn(actor, std::atan2(x,y) + getAdjustedAngle(), osg::DegreesToRadians(5.f)))
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
|
||||||
else
|
else
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
||||||
|
@ -90,4 +87,17 @@ unsigned int MWMechanics::AiAvoidDoor::getPriority() const
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MWMechanics::AiAvoidDoor::isStuck(const osg::Vec3f& actorPos) const
|
||||||
|
{
|
||||||
|
return (actorPos - mLastPos).length2() < 10 * 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MWMechanics::AiAvoidDoor::adjustDirection()
|
||||||
|
{
|
||||||
|
mDirection = Misc::Rng::rollDice(MAX_DIRECTIONS);
|
||||||
|
}
|
||||||
|
|
||||||
|
float MWMechanics::AiAvoidDoor::getAdjustedAngle() const
|
||||||
|
{
|
||||||
|
return 2 * osg::PI / MAX_DIRECTIONS * mDirection;
|
||||||
|
}
|
||||||
|
|
|
@ -36,8 +36,14 @@ namespace MWMechanics
|
||||||
private:
|
private:
|
||||||
float mDuration;
|
float mDuration;
|
||||||
MWWorld::ConstPtr mDoorPtr;
|
MWWorld::ConstPtr mDoorPtr;
|
||||||
ESM::Position mLastPos;
|
osg::Vec3f mLastPos;
|
||||||
float mAdjAngle;
|
int mDirection;
|
||||||
|
|
||||||
|
bool isStuck(const osg::Vec3f& actorPos) const;
|
||||||
|
|
||||||
|
void adjustDirection();
|
||||||
|
|
||||||
|
float getAdjustedAngle() const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1629,7 +1629,9 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && !isKnockedDown())
|
if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && !isKnockedDown())
|
||||||
{
|
{
|
||||||
float attackStrength = complete;
|
float attackStrength = complete;
|
||||||
if (!mPtr.getClass().isNpc())
|
float minAttackTime = mAnimation->getTextKeyTime(mCurrentWeapon+": "+mAttackType+" "+"min attack");
|
||||||
|
float maxAttackTime = mAnimation->getTextKeyTime(mCurrentWeapon+": "+mAttackType+" "+"max attack");
|
||||||
|
if (minAttackTime == maxAttackTime)
|
||||||
{
|
{
|
||||||
// most creatures don't actually have an attack wind-up animation, so use a uniform random value
|
// most creatures don't actually have an attack wind-up animation, so use a uniform random value
|
||||||
// (even some creatures that can use weapons don't have a wind-up animation either, e.g. Rieklings)
|
// (even some creatures that can use weapons don't have a wind-up animation either, e.g. Rieklings)
|
||||||
|
@ -1735,7 +1737,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
{
|
{
|
||||||
// If actor is already stopped preparing attack, do not play the "min attack -> max attack" part.
|
// If actor is already stopped preparing attack, do not play the "min attack -> max attack" part.
|
||||||
// Happens if the player did not hold the attack button.
|
// Happens if the player did not hold the attack button.
|
||||||
// Note: if the "min attack"->"max attack" is a stub, "play" it anyway. Attack strength will be 1.
|
// Note: if the "min attack"->"max attack" is a stub, "play" it anyway. Attack strength will be random.
|
||||||
float minAttackTime = mAnimation->getTextKeyTime(mCurrentWeapon+": "+mAttackType+" "+"min attack");
|
float minAttackTime = mAnimation->getTextKeyTime(mCurrentWeapon+": "+mAttackType+" "+"min attack");
|
||||||
float maxAttackTime = mAnimation->getTextKeyTime(mCurrentWeapon+": "+mAttackType+" "+"max attack");
|
float maxAttackTime = mAnimation->getTextKeyTime(mCurrentWeapon+": "+mAttackType+" "+"max attack");
|
||||||
if (mAttackingOrSpell || minAttackTime == maxAttackTime)
|
if (mAttackingOrSpell || minAttackTime == maxAttackTime)
|
||||||
|
|
|
@ -287,16 +287,6 @@ namespace MWMechanics
|
||||||
mWatched = ptr;
|
mWatched = ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MechanicsManager::advanceTime (float duration)
|
|
||||||
{
|
|
||||||
// Uses ingame time, but scaled to real time
|
|
||||||
const float timeScaleFactor = MWBase::Environment::get().getWorld()->getTimeScaleFactor();
|
|
||||||
if (timeScaleFactor != 0.0f)
|
|
||||||
duration /= timeScaleFactor;
|
|
||||||
MWWorld::Ptr player = getPlayer();
|
|
||||||
player.getClass().getInventoryStore(player).rechargeItems(duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MechanicsManager::update(float duration, bool paused)
|
void MechanicsManager::update(float duration, bool paused)
|
||||||
{
|
{
|
||||||
if(!mWatched.isEmpty())
|
if(!mWatched.isEmpty())
|
||||||
|
|
|
@ -78,8 +78,6 @@ namespace MWMechanics
|
||||||
/// \param paused In game type does not currently advance (this usually means some GUI
|
/// \param paused In game type does not currently advance (this usually means some GUI
|
||||||
/// component is up).
|
/// component is up).
|
||||||
|
|
||||||
virtual void advanceTime (float duration) override;
|
|
||||||
|
|
||||||
virtual void setPlayerName (const std::string& name) override;
|
virtual void setPlayerName (const std::string& name) override;
|
||||||
///< Set player name.
|
///< Set player name.
|
||||||
|
|
||||||
|
|
92
apps/openmw/mwmechanics/recharge.cpp
Normal file
92
apps/openmw/mwmechanics/recharge.cpp
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
#include "recharge.hpp"
|
||||||
|
|
||||||
|
#include <components/misc/rng.hpp>
|
||||||
|
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/containerstore.hpp"
|
||||||
|
#include "../mwworld/class.hpp"
|
||||||
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
||||||
|
#include "creaturestats.hpp"
|
||||||
|
#include "actorutil.hpp"
|
||||||
|
|
||||||
|
namespace MWMechanics
|
||||||
|
{
|
||||||
|
|
||||||
|
bool rechargeItem(const MWWorld::Ptr &item, const float maxCharge, const float duration)
|
||||||
|
{
|
||||||
|
float charge = item.getCellRef().getEnchantmentCharge();
|
||||||
|
if (charge == -1 || charge == maxCharge)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
static const float fMagicItemRechargePerSecond = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
||||||
|
"fMagicItemRechargePerSecond")->mValue.getFloat();
|
||||||
|
|
||||||
|
item.getCellRef().setEnchantmentCharge(std::min(charge + fMagicItemRechargePerSecond * duration, maxCharge));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rechargeItem(const MWWorld::Ptr &item, const MWWorld::Ptr &gem)
|
||||||
|
{
|
||||||
|
if (!gem.getRefData().getCount())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||||
|
MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
|
||||||
|
|
||||||
|
float luckTerm = 0.1f * stats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||||
|
if (luckTerm < 1 || luckTerm > 10)
|
||||||
|
luckTerm = 1;
|
||||||
|
|
||||||
|
float intelligenceTerm = 0.2f * stats.getAttribute(ESM::Attribute::Intelligence).getModified();
|
||||||
|
|
||||||
|
if (intelligenceTerm > 20)
|
||||||
|
intelligenceTerm = 20;
|
||||||
|
if (intelligenceTerm < 1)
|
||||||
|
intelligenceTerm = 1;
|
||||||
|
|
||||||
|
float x = (player.getClass().getSkill(player, ESM::Skill::Enchant) + intelligenceTerm + luckTerm) * stats.getFatigueTerm();
|
||||||
|
int roll = Misc::Rng::roll0to99();
|
||||||
|
if (roll < x)
|
||||||
|
{
|
||||||
|
std::string soul = gem.getCellRef().getSoul();
|
||||||
|
const ESM::Creature *creature = MWBase::Environment::get().getWorld()->getStore().get<ESM::Creature>().find(soul);
|
||||||
|
|
||||||
|
float restored = creature->mData.mSoul * (roll / x);
|
||||||
|
|
||||||
|
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find(
|
||||||
|
item.getClass().getEnchantment(item));
|
||||||
|
item.getCellRef().setEnchantmentCharge(
|
||||||
|
std::min(item.getCellRef().getEnchantmentCharge() + restored, static_cast<float>(enchantment->mData.mCharge)));
|
||||||
|
|
||||||
|
MWBase::Environment::get().getWindowManager()->playSound("Enchant Success");
|
||||||
|
|
||||||
|
player.getClass().getContainerStore(player).restack(item);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->playSound("Enchant Fail");
|
||||||
|
}
|
||||||
|
|
||||||
|
player.getClass().skillUsageSucceeded (player, ESM::Skill::Enchant, 0);
|
||||||
|
gem.getContainerStore()->remove(gem, 1, player);
|
||||||
|
|
||||||
|
if (gem.getRefData().getCount() == 0)
|
||||||
|
{
|
||||||
|
std::string message = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sNotifyMessage51")->mValue.getString();
|
||||||
|
message = Misc::StringUtils::format(message, gem.getClass().getName(gem));
|
||||||
|
|
||||||
|
MWBase::Environment::get().getWindowManager()->messageBox(message);
|
||||||
|
|
||||||
|
// special case: readd Azura's Star
|
||||||
|
if (Misc::StringUtils::ciEqual(gem.get<ESM::Miscellaneous>()->mBase->mId, "Misc_SoulGem_Azura"))
|
||||||
|
player.getClass().getContainerStore(player).add("Misc_SoulGem_Azura", 1, player);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
15
apps/openmw/mwmechanics/recharge.hpp
Normal file
15
apps/openmw/mwmechanics/recharge.hpp
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef MWMECHANICS_RECHARGE_H
|
||||||
|
#define MWMECHANICS_RECHARGE_H
|
||||||
|
|
||||||
|
#include "../mwworld/ptr.hpp"
|
||||||
|
|
||||||
|
namespace MWMechanics
|
||||||
|
{
|
||||||
|
|
||||||
|
bool rechargeItem(const MWWorld::Ptr &item, const float maxCharge, const float duration);
|
||||||
|
|
||||||
|
bool rechargeItem(const MWWorld::Ptr &item, const MWWorld::Ptr &gem);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -163,6 +163,19 @@ void MWWorld::Cells::rest (double hours)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MWWorld::Cells::recharge (float duration)
|
||||||
|
{
|
||||||
|
for (auto &interior : mInteriors)
|
||||||
|
{
|
||||||
|
interior.second.recharge(duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &exterior : mExteriors)
|
||||||
|
{
|
||||||
|
exterior.second.recharge(duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MWWorld::CellStore *MWWorld::Cells::getCell (const ESM::CellId& id)
|
MWWorld::CellStore *MWWorld::Cells::getCell (const ESM::CellId& id)
|
||||||
{
|
{
|
||||||
if (id.mPaged)
|
if (id.mPaged)
|
||||||
|
|
|
@ -61,7 +61,9 @@ namespace MWWorld
|
||||||
|
|
||||||
/// @note name must be lower case
|
/// @note name must be lower case
|
||||||
Ptr getPtr (const std::string& name);
|
Ptr getPtr (const std::string& name);
|
||||||
|
|
||||||
void rest (double hours);
|
void rest (double hours);
|
||||||
|
void recharge (float duration);
|
||||||
|
|
||||||
/// Get all Ptrs referencing \a name in exterior cells
|
/// Get all Ptrs referencing \a name in exterior cells
|
||||||
/// @note Due to the current implementation of getPtr this only supports one Ptr per cell.
|
/// @note Due to the current implementation of getPtr this only supports one Ptr per cell.
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
#include "../mwmechanics/creaturestats.hpp"
|
#include "../mwmechanics/creaturestats.hpp"
|
||||||
|
#include "../mwmechanics/recharge.hpp"
|
||||||
|
|
||||||
#include "ptr.hpp"
|
#include "ptr.hpp"
|
||||||
#include "esmstore.hpp"
|
#include "esmstore.hpp"
|
||||||
|
@ -328,6 +329,7 @@ namespace MWWorld
|
||||||
void CellStore::updateMergedRefs()
|
void CellStore::updateMergedRefs()
|
||||||
{
|
{
|
||||||
mMergedRefs.clear();
|
mMergedRefs.clear();
|
||||||
|
mRechargingItemsUpToDate = false;
|
||||||
MergeVisitor visitor(mMergedRefs, mMovedHere, mMovedToAnotherCell);
|
MergeVisitor visitor(mMergedRefs, mMovedHere, mMovedToAnotherCell);
|
||||||
forEachInternal(visitor);
|
forEachInternal(visitor);
|
||||||
visitor.merge();
|
visitor.merge();
|
||||||
|
@ -345,7 +347,7 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
|
|
||||||
CellStore::CellStore (const ESM::Cell *cell, const MWWorld::ESMStore& esmStore, std::vector<ESM::ESMReader>& readerList)
|
CellStore::CellStore (const ESM::Cell *cell, const MWWorld::ESMStore& esmStore, std::vector<ESM::ESMReader>& readerList)
|
||||||
: mStore(esmStore), mReader(readerList), mCell (cell), mState (State_Unloaded), mHasState (false), mLastRespawn(0,0)
|
: mStore(esmStore), mReader(readerList), mCell (cell), mState (State_Unloaded), mHasState (false), mLastRespawn(0,0), mRechargingItemsUpToDate(false)
|
||||||
{
|
{
|
||||||
mWaterLevel = cell->mWater;
|
mWaterLevel = cell->mWater;
|
||||||
}
|
}
|
||||||
|
@ -992,6 +994,42 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CellStore::recharge(float duration)
|
||||||
|
{
|
||||||
|
if (duration <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mState == State_Loaded)
|
||||||
|
{
|
||||||
|
for (CellRefList<ESM::Creature>::List::iterator it (mCreatures.mList.begin()); it!=mCreatures.mList.end(); ++it)
|
||||||
|
{
|
||||||
|
Ptr ptr = getCurrentPtr(&*it);
|
||||||
|
if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0)
|
||||||
|
{
|
||||||
|
ptr.getClass().getContainerStore(ptr).rechargeItems(duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (CellRefList<ESM::NPC>::List::iterator it (mNpcs.mList.begin()); it!=mNpcs.mList.end(); ++it)
|
||||||
|
{
|
||||||
|
Ptr ptr = getCurrentPtr(&*it);
|
||||||
|
if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0)
|
||||||
|
{
|
||||||
|
ptr.getClass().getContainerStore(ptr).rechargeItems(duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (CellRefList<ESM::Container>::List::iterator it (mContainers.mList.begin()); it!=mContainers.mList.end(); ++it)
|
||||||
|
{
|
||||||
|
Ptr ptr = getCurrentPtr(&*it);
|
||||||
|
if (!ptr.isEmpty() && ptr.getRefData().getCustomData() != nullptr && ptr.getRefData().getCount() > 0)
|
||||||
|
{
|
||||||
|
ptr.getClass().getContainerStore(ptr).rechargeItems(duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rechargeItems(duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CellStore::respawn()
|
void CellStore::respawn()
|
||||||
{
|
{
|
||||||
if (mState == State_Loaded)
|
if (mState == State_Loaded)
|
||||||
|
@ -1027,4 +1065,73 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MWWorld::CellStore::rechargeItems(float duration)
|
||||||
|
{
|
||||||
|
if (!mRechargingItemsUpToDate)
|
||||||
|
{
|
||||||
|
updateRechargingItems();
|
||||||
|
mRechargingItemsUpToDate = true;
|
||||||
|
}
|
||||||
|
for (TRechargingItems::iterator it = mRechargingItems.begin(); it != mRechargingItems.end(); ++it)
|
||||||
|
{
|
||||||
|
MWMechanics::rechargeItem(it->first, it->second, duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MWWorld::CellStore::updateRechargingItems()
|
||||||
|
{
|
||||||
|
mRechargingItems.clear();
|
||||||
|
|
||||||
|
for (CellRefList<ESM::Weapon>::List::iterator it (mWeapons.mList.begin()); it!=mWeapons.mList.end(); ++it)
|
||||||
|
{
|
||||||
|
Ptr ptr = getCurrentPtr(&*it);
|
||||||
|
if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0)
|
||||||
|
{
|
||||||
|
checkItem(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (CellRefList<ESM::Armor>::List::iterator it (mArmors.mList.begin()); it!=mArmors.mList.end(); ++it)
|
||||||
|
{
|
||||||
|
Ptr ptr = getCurrentPtr(&*it);
|
||||||
|
if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0)
|
||||||
|
{
|
||||||
|
checkItem(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (CellRefList<ESM::Clothing>::List::iterator it (mClothes.mList.begin()); it!=mClothes.mList.end(); ++it)
|
||||||
|
{
|
||||||
|
Ptr ptr = getCurrentPtr(&*it);
|
||||||
|
if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0)
|
||||||
|
{
|
||||||
|
checkItem(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (CellRefList<ESM::Book>::List::iterator it (mBooks.mList.begin()); it!=mBooks.mList.end(); ++it)
|
||||||
|
{
|
||||||
|
Ptr ptr = getCurrentPtr(&*it);
|
||||||
|
if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0)
|
||||||
|
{
|
||||||
|
checkItem(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MWWorld::CellStore::checkItem(Ptr ptr)
|
||||||
|
{
|
||||||
|
if (ptr.getClass().getEnchantment(ptr).empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::string enchantmentId = ptr.getClass().getEnchantment(ptr);
|
||||||
|
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().search(enchantmentId);
|
||||||
|
if (!enchantment)
|
||||||
|
{
|
||||||
|
Log(Debug::Warning) << "Warning: Can't find enchantment '" << enchantmentId << "' on item " << ptr.getCellRef().getRefId();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enchantment->mData.mType == ESM::Enchantment::WhenUsed
|
||||||
|
|| enchantment->mData.mType == ESM::Enchantment::WhenStrikes)
|
||||||
|
mRechargingItems.emplace_back(ptr.getBase(), static_cast<float>(enchantment->mData.mCharge));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,6 +118,16 @@ namespace MWWorld
|
||||||
/// Repopulate mMergedRefs.
|
/// Repopulate mMergedRefs.
|
||||||
void updateMergedRefs();
|
void updateMergedRefs();
|
||||||
|
|
||||||
|
// (item, max charge)
|
||||||
|
typedef std::vector<std::pair<LiveCellRefBase*, float> > TRechargingItems;
|
||||||
|
TRechargingItems mRechargingItems;
|
||||||
|
|
||||||
|
bool mRechargingItemsUpToDate;
|
||||||
|
|
||||||
|
void updateRechargingItems();
|
||||||
|
void rechargeItems(float duration);
|
||||||
|
void checkItem(Ptr ptr);
|
||||||
|
|
||||||
// helper function for forEachInternal
|
// helper function for forEachInternal
|
||||||
template<class Visitor, class List>
|
template<class Visitor, class List>
|
||||||
bool forEachImp (Visitor& visitor, List& list)
|
bool forEachImp (Visitor& visitor, List& list)
|
||||||
|
@ -184,6 +194,7 @@ namespace MWWorld
|
||||||
MWWorld::Ptr moveTo(const MWWorld::Ptr& object, MWWorld::CellStore* cellToMoveTo);
|
MWWorld::Ptr moveTo(const MWWorld::Ptr& object, MWWorld::CellStore* cellToMoveTo);
|
||||||
|
|
||||||
void rest(double hours);
|
void rest(double hours);
|
||||||
|
void recharge(float duration);
|
||||||
|
|
||||||
/// Make a copy of the given object and insert it into this cell.
|
/// Make a copy of the given object and insert it into this cell.
|
||||||
/// @note If you get a linker error here, this means the given type can not be inserted into a cell.
|
/// @note If you get a linker error here, this means the given type can not be inserted into a cell.
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "../mwmechanics/creaturestats.hpp"
|
#include "../mwmechanics/creaturestats.hpp"
|
||||||
#include "../mwmechanics/levelledlist.hpp"
|
#include "../mwmechanics/levelledlist.hpp"
|
||||||
#include "../mwmechanics/actorutil.hpp"
|
#include "../mwmechanics/actorutil.hpp"
|
||||||
|
#include "../mwmechanics/recharge.hpp"
|
||||||
|
|
||||||
#include "manualref.hpp"
|
#include "manualref.hpp"
|
||||||
#include "refdata.hpp"
|
#include "refdata.hpp"
|
||||||
|
@ -114,7 +115,11 @@ void MWWorld::ContainerStore::storeStates (const CellRefList<T>& collection,
|
||||||
|
|
||||||
const std::string MWWorld::ContainerStore::sGoldId = "gold_001";
|
const std::string MWWorld::ContainerStore::sGoldId = "gold_001";
|
||||||
|
|
||||||
MWWorld::ContainerStore::ContainerStore() : mListener(nullptr), mCachedWeight (0), mWeightUpToDate (false) {}
|
MWWorld::ContainerStore::ContainerStore()
|
||||||
|
: mListener(nullptr)
|
||||||
|
, mRechargingItemsUpToDate(false)
|
||||||
|
, mCachedWeight (0)
|
||||||
|
, mWeightUpToDate (false) {}
|
||||||
|
|
||||||
MWWorld::ContainerStore::~ContainerStore() {}
|
MWWorld::ContainerStore::~ContainerStore() {}
|
||||||
|
|
||||||
|
@ -241,7 +246,6 @@ bool MWWorld::ContainerStore::stacks(const ConstPtr& ptr1, const ConstPtr& ptr2)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ptr1 != ptr2 // an item never stacks onto itself
|
return ptr1 != ptr2 // an item never stacks onto itself
|
||||||
&& ptr1.getCellRef().getOwner() == ptr2.getCellRef().getOwner()
|
|
||||||
&& ptr1.getCellRef().getSoul() == ptr2.getCellRef().getSoul()
|
&& ptr1.getCellRef().getSoul() == ptr2.getCellRef().getSoul()
|
||||||
|
|
||||||
&& ptr1.getClass().getRemainingUsageTime(ptr1) == ptr2.getClass().getRemainingUsageTime(ptr2)
|
&& ptr1.getClass().getRemainingUsageTime(ptr1) == ptr2.getClass().getRemainingUsageTime(ptr2)
|
||||||
|
@ -259,30 +263,14 @@ bool MWWorld::ContainerStore::stacks(const ConstPtr& ptr1, const ConstPtr& ptr2)
|
||||||
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add(const std::string &id, int count, const Ptr &actorPtr)
|
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add(const std::string &id, int count, const Ptr &actorPtr)
|
||||||
{
|
{
|
||||||
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), id, count);
|
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), id, count);
|
||||||
return add(ref.getPtr(), count, actorPtr, true);
|
return add(ref.getPtr(), count, actorPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr, int count, const Ptr& actorPtr, bool setOwner)
|
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr, int count, const Ptr& actorPtr)
|
||||||
{
|
{
|
||||||
Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
|
Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
|
||||||
|
|
||||||
MWWorld::ContainerStoreIterator it = end();
|
MWWorld::ContainerStoreIterator it = addImp(itemPtr, count);
|
||||||
|
|
||||||
// HACK: Set owner on the original item, then reset it after we have copied it
|
|
||||||
// If we set the owner on the copied item, it would not stack correctly...
|
|
||||||
std::string oldOwner = itemPtr.getCellRef().getOwner();
|
|
||||||
if (!setOwner || actorPtr == MWMechanics::getPlayer()) // No point in setting owner to the player - NPCs will not respect this anyway
|
|
||||||
{
|
|
||||||
itemPtr.getCellRef().setOwner("");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
itemPtr.getCellRef().setOwner(actorPtr.getCellRef().getRefId());
|
|
||||||
}
|
|
||||||
|
|
||||||
it = addImp(itemPtr, count);
|
|
||||||
|
|
||||||
itemPtr.getCellRef().setOwner(oldOwner);
|
|
||||||
|
|
||||||
// The copy of the original item we just made
|
// The copy of the original item we just made
|
||||||
MWWorld::Ptr item = *it;
|
MWWorld::Ptr item = *it;
|
||||||
|
@ -298,7 +286,8 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr
|
||||||
pos.pos[2] = 0;
|
pos.pos[2] = 0;
|
||||||
item.getCellRef().setPosition(pos);
|
item.getCellRef().setPosition(pos);
|
||||||
|
|
||||||
// reset ownership stuff, owner was already handled above
|
// We do not need to store owners for items in container stores - we do not use it anyway.
|
||||||
|
item.getCellRef().setOwner("");
|
||||||
item.getCellRef().resetGlobalVariable();
|
item.getCellRef().resetGlobalVariable();
|
||||||
item.getCellRef().setFaction("");
|
item.getCellRef().setFaction("");
|
||||||
item.getCellRef().setFactionRank(-1);
|
item.getCellRef().setFactionRank(-1);
|
||||||
|
@ -408,6 +397,46 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addNewStack (const Cons
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MWWorld::ContainerStore::rechargeItems(float duration)
|
||||||
|
{
|
||||||
|
if (!mRechargingItemsUpToDate)
|
||||||
|
{
|
||||||
|
updateRechargingItems();
|
||||||
|
mRechargingItemsUpToDate = true;
|
||||||
|
}
|
||||||
|
for (TRechargingItems::iterator it = mRechargingItems.begin(); it != mRechargingItems.end(); ++it)
|
||||||
|
{
|
||||||
|
if (!MWMechanics::rechargeItem(*it->first, it->second, duration))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// attempt to restack when fully recharged
|
||||||
|
if (it->first->getCellRef().getEnchantmentCharge() == it->second)
|
||||||
|
it->first = restack(*it->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MWWorld::ContainerStore::updateRechargingItems()
|
||||||
|
{
|
||||||
|
mRechargingItems.clear();
|
||||||
|
for (ContainerStoreIterator it = begin(); it != end(); ++it)
|
||||||
|
{
|
||||||
|
const std::string& enchantmentId = it->getClass().getEnchantment(*it);
|
||||||
|
if (!enchantmentId.empty())
|
||||||
|
{
|
||||||
|
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().search(enchantmentId);
|
||||||
|
if (!enchantment)
|
||||||
|
{
|
||||||
|
Log(Debug::Warning) << "Warning: Can't find enchantment '" << enchantmentId << "' on item " << it->getCellRef().getRefId();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enchantment->mData.mType == ESM::Enchantment::WhenUsed
|
||||||
|
|| enchantment->mData.mType == ESM::Enchantment::WhenStrikes)
|
||||||
|
mRechargingItems.emplace_back(it, static_cast<float>(enchantment->mData.mCharge));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int MWWorld::ContainerStore::remove(const std::string& itemId, int count, const Ptr& actor)
|
int MWWorld::ContainerStore::remove(const std::string& itemId, int count, const Ptr& actor)
|
||||||
{
|
{
|
||||||
int toRemove = count;
|
int toRemove = count;
|
||||||
|
@ -477,50 +506,64 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::
|
||||||
int count, bool topLevel, const std::string& levItem)
|
int count, bool topLevel, const std::string& levItem)
|
||||||
{
|
{
|
||||||
if (count == 0) return; //Don't restock with nothing.
|
if (count == 0) return; //Don't restock with nothing.
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count);
|
ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count);
|
||||||
|
if (ref.getPtr().getClass().getScript(ref.getPtr()).empty())
|
||||||
if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name())
|
|
||||||
{
|
{
|
||||||
const ESM::ItemLevList* levItemList = ref.getPtr().get<ESM::ItemLevList>()->mBase;
|
addInitialItemImp(ref.getPtr(), owner, count, topLevel, levItem);
|
||||||
|
|
||||||
if (topLevel && std::abs(count) > 1 && levItemList->mFlags & ESM::ItemLevList::Each)
|
|
||||||
{
|
|
||||||
for (int i=0; i<std::abs(count); ++i)
|
|
||||||
addInitialItem(id, owner, count > 0 ? 1 : -1, true, levItemList->mId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::string itemId = MWMechanics::getLevelledItem(ref.getPtr().get<ESM::ItemLevList>()->mBase, false);
|
|
||||||
if (itemId.empty())
|
|
||||||
return;
|
|
||||||
addInitialItem(itemId, owner, count, false, levItemList->mId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// A negative count indicates restocking items
|
// Adding just one item per time to make sure there isn't a stack of scripted items
|
||||||
// For a restocking levelled item, remember what we spawned so we can delete it later when the merchant restocks
|
for (int i = 0; i < abs(count); i++)
|
||||||
if (!levItem.empty() && count < 0)
|
addInitialItemImp(ref.getPtr(), owner, count < 0 ? -1 : 1, topLevel, levItem);
|
||||||
{
|
|
||||||
//If there is no item in map, insert it
|
|
||||||
std::map<std::pair<std::string, std::string>, int>::iterator itemInMap =
|
|
||||||
mLevelledItemMap.insert(std::make_pair(std::make_pair(id, levItem), 0)).first;
|
|
||||||
//Update spawned count
|
|
||||||
itemInMap->second += std::abs(count);
|
|
||||||
}
|
|
||||||
count = std::abs(count);
|
|
||||||
|
|
||||||
ref.getPtr().getCellRef().setOwner(owner);
|
|
||||||
addImp (ref.getPtr(), count);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
Log(Debug::Warning) << "Warning: MWWorld::ContainerStore::addInitialItem: " << e.what();
|
Log(Debug::Warning) << "Warning: MWWorld::ContainerStore::addInitialItem: " << e.what();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MWWorld::ContainerStore::addInitialItemImp(const MWWorld::Ptr& ptr, const std::string& owner,
|
||||||
|
int count, bool topLevel, const std::string& levItem)
|
||||||
|
{
|
||||||
|
if (ptr.getTypeName()==typeid (ESM::ItemLevList).name())
|
||||||
|
{
|
||||||
|
const ESM::ItemLevList* levItemList = ptr.get<ESM::ItemLevList>()->mBase;
|
||||||
|
|
||||||
|
if (topLevel && std::abs(count) > 1 && levItemList->mFlags & ESM::ItemLevList::Each)
|
||||||
|
{
|
||||||
|
for (int i=0; i<std::abs(count); ++i)
|
||||||
|
addInitialItem(ptr.getCellRef().getRefId(), owner, count > 0 ? 1 : -1, true, levItemList->mId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string itemId = MWMechanics::getLevelledItem(ptr.get<ESM::ItemLevList>()->mBase, false);
|
||||||
|
if (itemId.empty())
|
||||||
|
return;
|
||||||
|
addInitialItem(itemId, owner, count, false, levItemList->mId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// A negative count indicates restocking items
|
||||||
|
// For a restocking levelled item, remember what we spawned so we can delete it later when the merchant restocks
|
||||||
|
if (!levItem.empty() && count < 0)
|
||||||
|
{
|
||||||
|
//If there is no item in map, insert it
|
||||||
|
std::map<std::pair<std::string, std::string>, int>::iterator itemInMap =
|
||||||
|
mLevelledItemMap.insert(std::make_pair(std::make_pair(ptr.getCellRef().getRefId(), levItem), 0)).first;
|
||||||
|
//Update spawned count
|
||||||
|
itemInMap->second += std::abs(count);
|
||||||
|
}
|
||||||
|
count = std::abs(count);
|
||||||
|
|
||||||
|
ptr.getCellRef().setOwner(owner);
|
||||||
|
addImp (ptr, count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner)
|
void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner)
|
||||||
|
@ -619,6 +662,7 @@ void MWWorld::ContainerStore::clear()
|
||||||
void MWWorld::ContainerStore::flagAsModified()
|
void MWWorld::ContainerStore::flagAsModified()
|
||||||
{
|
{
|
||||||
mWeightUpToDate = false;
|
mWeightUpToDate = false;
|
||||||
|
mRechargingItemsUpToDate = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
float MWWorld::ContainerStore::getWeight() const
|
float MWWorld::ContainerStore::getWeight() const
|
||||||
|
|
|
@ -71,6 +71,12 @@ namespace MWWorld
|
||||||
protected:
|
protected:
|
||||||
ContainerStoreListener* mListener;
|
ContainerStoreListener* mListener;
|
||||||
|
|
||||||
|
// (item, max charge)
|
||||||
|
typedef std::vector<std::pair<ContainerStoreIterator, float> > TRechargingItems;
|
||||||
|
TRechargingItems mRechargingItems;
|
||||||
|
|
||||||
|
bool mRechargingItemsUpToDate;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
MWWorld::CellRefList<ESM::Potion> potions;
|
MWWorld::CellRefList<ESM::Potion> potions;
|
||||||
|
@ -94,6 +100,7 @@ namespace MWWorld
|
||||||
mutable bool mWeightUpToDate;
|
mutable bool mWeightUpToDate;
|
||||||
ContainerStoreIterator addImp (const Ptr& ptr, int count);
|
ContainerStoreIterator addImp (const Ptr& ptr, int count);
|
||||||
void addInitialItem (const std::string& id, const std::string& owner, int count, bool topLevel=true, const std::string& levItem = "");
|
void addInitialItem (const std::string& id, const std::string& owner, int count, bool topLevel=true, const std::string& levItem = "");
|
||||||
|
void addInitialItemImp (const MWWorld::Ptr& ptr, const std::string& owner, int count, bool topLevel=true, const std::string& levItem = "");
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ContainerStoreIterator getState (CellRefList<T>& collection,
|
ContainerStoreIterator getState (CellRefList<T>& collection,
|
||||||
|
@ -107,6 +114,7 @@ namespace MWWorld
|
||||||
ESM::InventoryState& inventory, int& index,
|
ESM::InventoryState& inventory, int& index,
|
||||||
bool equipable = false) const;
|
bool equipable = false) const;
|
||||||
|
|
||||||
|
void updateRechargingItems();
|
||||||
|
|
||||||
virtual void storeEquipmentState (const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const;
|
virtual void storeEquipmentState (const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const;
|
||||||
|
|
||||||
|
@ -130,7 +138,7 @@ namespace MWWorld
|
||||||
|
|
||||||
bool hasVisibleItems() const;
|
bool hasVisibleItems() const;
|
||||||
|
|
||||||
virtual ContainerStoreIterator add (const Ptr& itemPtr, int count, const Ptr& actorPtr, bool setOwner=false);
|
virtual ContainerStoreIterator add (const Ptr& itemPtr, int count, const Ptr& actorPtr);
|
||||||
///< Add the item pointed to by \a ptr to this container. (Stacks automatically if needed)
|
///< Add the item pointed to by \a ptr to this container. (Stacks automatically if needed)
|
||||||
///
|
///
|
||||||
/// \note The item pointed to is not required to exist beyond this function call.
|
/// \note The item pointed to is not required to exist beyond this function call.
|
||||||
|
@ -155,6 +163,9 @@ namespace MWWorld
|
||||||
///
|
///
|
||||||
/// @return the number of items actually removed
|
/// @return the number of items actually removed
|
||||||
|
|
||||||
|
void rechargeItems (float duration);
|
||||||
|
///< Restore charge on enchanted items. Note this should only be done for the player.
|
||||||
|
|
||||||
ContainerStoreIterator unstack (const Ptr& ptr, const Ptr& container, int count = 1);
|
ContainerStoreIterator unstack (const Ptr& ptr, const Ptr& container, int count = 1);
|
||||||
///< Unstack an item in this container. The item's count will be set to count, then a new stack will be added with (origCount-count).
|
///< Unstack an item in this container. The item's count will be set to count, then a new stack will be added with (origCount-count).
|
||||||
///
|
///
|
||||||
|
|
|
@ -101,7 +101,6 @@ MWWorld::InventoryStore::InventoryStore()
|
||||||
, mUpdatesEnabled (true)
|
, mUpdatesEnabled (true)
|
||||||
, mFirstAutoEquip(true)
|
, mFirstAutoEquip(true)
|
||||||
, mSelectedEnchantItem(end())
|
, mSelectedEnchantItem(end())
|
||||||
, mRechargingItemsUpToDate(false)
|
|
||||||
{
|
{
|
||||||
initSlots (mSlots);
|
initSlots (mSlots);
|
||||||
}
|
}
|
||||||
|
@ -114,7 +113,6 @@ MWWorld::InventoryStore::InventoryStore (const InventoryStore& store)
|
||||||
, mFirstAutoEquip(store.mFirstAutoEquip)
|
, mFirstAutoEquip(store.mFirstAutoEquip)
|
||||||
, mPermanentMagicEffectMagnitudes(store.mPermanentMagicEffectMagnitudes)
|
, mPermanentMagicEffectMagnitudes(store.mPermanentMagicEffectMagnitudes)
|
||||||
, mSelectedEnchantItem(end())
|
, mSelectedEnchantItem(end())
|
||||||
, mRechargingItemsUpToDate(false)
|
|
||||||
{
|
{
|
||||||
copySlots (store);
|
copySlots (store);
|
||||||
}
|
}
|
||||||
|
@ -133,9 +131,9 @@ MWWorld::InventoryStore& MWWorld::InventoryStore::operator= (const InventoryStor
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::ContainerStoreIterator MWWorld::InventoryStore::add(const Ptr& itemPtr, int count, const Ptr& actorPtr, bool setOwner)
|
MWWorld::ContainerStoreIterator MWWorld::InventoryStore::add(const Ptr& itemPtr, int count, const Ptr& actorPtr)
|
||||||
{
|
{
|
||||||
const MWWorld::ContainerStoreIterator& retVal = MWWorld::ContainerStore::add(itemPtr, count, actorPtr, setOwner);
|
const MWWorld::ContainerStoreIterator& retVal = MWWorld::ContainerStore::add(itemPtr, count, actorPtr);
|
||||||
|
|
||||||
// Auto-equip items if an armor/clothing or weapon item is added, but not for the player nor werewolves
|
// Auto-equip items if an armor/clothing or weapon item is added, but not for the player nor werewolves
|
||||||
if (actorPtr != MWMechanics::getPlayer()
|
if (actorPtr != MWMechanics::getPlayer()
|
||||||
|
@ -709,12 +707,6 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor)
|
||||||
mFirstAutoEquip = false;
|
mFirstAutoEquip = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MWWorld::InventoryStore::flagAsModified()
|
|
||||||
{
|
|
||||||
ContainerStore::flagAsModified();
|
|
||||||
mRechargingItemsUpToDate = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MWWorld::InventoryStore::stacks(const ConstPtr& ptr1, const ConstPtr& ptr2) const
|
bool MWWorld::InventoryStore::stacks(const ConstPtr& ptr1, const ConstPtr& ptr2) const
|
||||||
{
|
{
|
||||||
bool canStack = MWWorld::ContainerStore::stacks(ptr1, ptr2);
|
bool canStack = MWWorld::ContainerStore::stacks(ptr1, ptr2);
|
||||||
|
@ -957,57 +949,6 @@ void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisito
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MWWorld::InventoryStore::updateRechargingItems()
|
|
||||||
{
|
|
||||||
mRechargingItems.clear();
|
|
||||||
for (ContainerStoreIterator it = begin(); it != end(); ++it)
|
|
||||||
{
|
|
||||||
if (it->getClass().getEnchantment(*it) != "")
|
|
||||||
{
|
|
||||||
std::string enchantmentId = it->getClass().getEnchantment(*it);
|
|
||||||
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().search(
|
|
||||||
enchantmentId);
|
|
||||||
if (!enchantment)
|
|
||||||
{
|
|
||||||
Log(Debug::Warning) << "Warning: Can't find enchantment '" << enchantmentId << "' on item " << it->getCellRef().getRefId();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enchantment->mData.mType == ESM::Enchantment::WhenUsed
|
|
||||||
|| enchantment->mData.mType == ESM::Enchantment::WhenStrikes)
|
|
||||||
mRechargingItems.push_back(std::make_pair(it, static_cast<float>(enchantment->mData.mCharge)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MWWorld::InventoryStore::rechargeItems(float duration)
|
|
||||||
{
|
|
||||||
if (!mRechargingItemsUpToDate)
|
|
||||||
{
|
|
||||||
updateRechargingItems();
|
|
||||||
mRechargingItemsUpToDate = true;
|
|
||||||
}
|
|
||||||
for (TRechargingItems::iterator it = mRechargingItems.begin(); it != mRechargingItems.end(); ++it)
|
|
||||||
{
|
|
||||||
if (it->first->getCellRef().getEnchantmentCharge() == -1
|
|
||||||
|| it->first->getCellRef().getEnchantmentCharge() == it->second)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
static float fMagicItemRechargePerSecond = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
|
||||||
"fMagicItemRechargePerSecond")->mValue.getFloat();
|
|
||||||
|
|
||||||
if (it->first->getCellRef().getEnchantmentCharge() <= it->second)
|
|
||||||
{
|
|
||||||
it->first->getCellRef().setEnchantmentCharge(std::min (it->first->getCellRef().getEnchantmentCharge() + fMagicItemRechargePerSecond * duration,
|
|
||||||
it->second));
|
|
||||||
|
|
||||||
// attempt to restack when fully recharged
|
|
||||||
if (it->first->getCellRef().getEnchantmentCharge() == it->second)
|
|
||||||
it->first = restack(*it->first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MWWorld::InventoryStore::purgeEffect(short effectId)
|
void MWWorld::InventoryStore::purgeEffect(short effectId)
|
||||||
{
|
{
|
||||||
for (TSlots::const_iterator it = mSlots.begin(); it != mSlots.end(); ++it)
|
for (TSlots::const_iterator it = mSlots.begin(); it != mSlots.end(); ++it)
|
||||||
|
|
|
@ -101,18 +101,11 @@ namespace MWWorld
|
||||||
// selected magic item (for using enchantments of type "Cast once" or "Cast when used")
|
// selected magic item (for using enchantments of type "Cast once" or "Cast when used")
|
||||||
ContainerStoreIterator mSelectedEnchantItem;
|
ContainerStoreIterator mSelectedEnchantItem;
|
||||||
|
|
||||||
// (item, max charge)
|
|
||||||
typedef std::vector<std::pair<ContainerStoreIterator, float> > TRechargingItems;
|
|
||||||
TRechargingItems mRechargingItems;
|
|
||||||
|
|
||||||
bool mRechargingItemsUpToDate;
|
|
||||||
|
|
||||||
void copySlots (const InventoryStore& store);
|
void copySlots (const InventoryStore& store);
|
||||||
|
|
||||||
void initSlots (TSlots& slots_);
|
void initSlots (TSlots& slots_);
|
||||||
|
|
||||||
void updateMagicEffects(const Ptr& actor);
|
void updateMagicEffects(const Ptr& actor);
|
||||||
void updateRechargingItems();
|
|
||||||
|
|
||||||
void fireEquipmentChangedEvent(const Ptr& actor);
|
void fireEquipmentChangedEvent(const Ptr& actor);
|
||||||
|
|
||||||
|
@ -132,7 +125,7 @@ namespace MWWorld
|
||||||
|
|
||||||
virtual InventoryStore* clone() { return new InventoryStore(*this); }
|
virtual InventoryStore* clone() { return new InventoryStore(*this); }
|
||||||
|
|
||||||
virtual ContainerStoreIterator add (const Ptr& itemPtr, int count, const Ptr& actorPtr, bool setOwner=false);
|
virtual ContainerStoreIterator add (const Ptr& itemPtr, int count, const Ptr& actorPtr);
|
||||||
///< Add the item pointed to by \a ptr to this container. (Stacks automatically if needed)
|
///< Add the item pointed to by \a ptr to this container. (Stacks automatically if needed)
|
||||||
/// Auto-equip items if specific conditions are fulfilled (see the implementation).
|
/// Auto-equip items if specific conditions are fulfilled (see the implementation).
|
||||||
///
|
///
|
||||||
|
@ -171,10 +164,6 @@ namespace MWWorld
|
||||||
const MWMechanics::MagicEffects& getMagicEffects() const;
|
const MWMechanics::MagicEffects& getMagicEffects() const;
|
||||||
///< Return magic effects from worn items.
|
///< Return magic effects from worn items.
|
||||||
|
|
||||||
virtual void flagAsModified();
|
|
||||||
///< \attention This function is internal to the world model and should not be called from
|
|
||||||
/// outside.
|
|
||||||
|
|
||||||
virtual bool stacks (const ConstPtr& ptr1, const ConstPtr& ptr2) const;
|
virtual bool stacks (const ConstPtr& ptr1, const ConstPtr& ptr2) const;
|
||||||
///< @return true if the two specified objects can stack with each other
|
///< @return true if the two specified objects can stack with each other
|
||||||
|
|
||||||
|
@ -216,9 +205,6 @@ namespace MWWorld
|
||||||
|
|
||||||
void visitEffectSources (MWMechanics::EffectSourceVisitor& visitor);
|
void visitEffectSources (MWMechanics::EffectSourceVisitor& visitor);
|
||||||
|
|
||||||
void rechargeItems (float duration);
|
|
||||||
///< Restore charge on enchanted items. Note this should only be done for the player.
|
|
||||||
|
|
||||||
void purgeEffect (short effectId);
|
void purgeEffect (short effectId);
|
||||||
///< Remove a magic effect
|
///< Remove a magic effect
|
||||||
|
|
||||||
|
|
|
@ -857,7 +857,17 @@ namespace MWWorld
|
||||||
|
|
||||||
void World::advanceTime (double hours, bool incremental)
|
void World::advanceTime (double hours, bool incremental)
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getMechanicsManager()->advanceTime(static_cast<float>(hours * 3600));
|
if (!incremental)
|
||||||
|
{
|
||||||
|
// When we fast-forward time, we should recharge magic items
|
||||||
|
// in all loaded cells, using game world time
|
||||||
|
float duration = hours * 3600;
|
||||||
|
const float timeScaleFactor = getTimeScaleFactor();
|
||||||
|
if (timeScaleFactor != 0.0f)
|
||||||
|
duration /= timeScaleFactor;
|
||||||
|
|
||||||
|
rechargeItems(duration, false);
|
||||||
|
}
|
||||||
|
|
||||||
mWeatherManager->advanceTime (hours, incremental);
|
mWeatherManager->advanceTime (hours, incremental);
|
||||||
|
|
||||||
|
@ -1649,7 +1659,6 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
|
|
||||||
// we need to undo the rotation
|
// we need to undo the rotation
|
||||||
rotateObject(door, objPos.rot[0], objPos.rot[1], oldRot);
|
|
||||||
reached = false;
|
reached = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1671,6 +1680,8 @@ namespace MWWorld
|
||||||
if (!closeSound.empty() && MWBase::Environment::get().getSoundManager()->getSoundPlaying(door, closeSound))
|
if (!closeSound.empty() && MWBase::Environment::get().getSoundManager()->getSoundPlaying(door, closeSound))
|
||||||
MWBase::Environment::get().getSoundManager()->stopSound3D(door, closeSound);
|
MWBase::Environment::get().getSoundManager()->stopSound3D(door, closeSound);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rotateObject(door, objPos.rot[0], objPos.rot[1], oldRot);
|
||||||
}
|
}
|
||||||
|
|
||||||
// the rotation order we want to use
|
// the rotation order we want to use
|
||||||
|
@ -3304,7 +3315,6 @@ namespace MWWorld
|
||||||
closestDistance = distance;
|
closestDistance = distance;
|
||||||
closestMarker = marker;
|
closestMarker = marker;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return closestMarker;
|
return closestMarker;
|
||||||
|
@ -3315,6 +3325,22 @@ namespace MWWorld
|
||||||
mCells.rest(hours);
|
mCells.rest(hours);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void World::rechargeItems(double duration, bool activeOnly)
|
||||||
|
{
|
||||||
|
MWWorld::Ptr player = getPlayerPtr();
|
||||||
|
player.getClass().getInventoryStore(player).rechargeItems(duration);
|
||||||
|
|
||||||
|
if (activeOnly)
|
||||||
|
{
|
||||||
|
for (auto &cell : mWorldScene->getActiveCells())
|
||||||
|
{
|
||||||
|
cell->recharge(duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mCells.recharge(duration);
|
||||||
|
}
|
||||||
|
|
||||||
void World::teleportToClosestMarker (const MWWorld::Ptr& ptr,
|
void World::teleportToClosestMarker (const MWWorld::Ptr& ptr,
|
||||||
const std::string& id)
|
const std::string& id)
|
||||||
{
|
{
|
||||||
|
|
|
@ -574,6 +574,7 @@ namespace MWWorld
|
||||||
///< check if the player is allowed to rest
|
///< check if the player is allowed to rest
|
||||||
|
|
||||||
void rest(double hours) override;
|
void rest(double hours) override;
|
||||||
|
void rechargeItems(double duration, bool activeOnly) override;
|
||||||
|
|
||||||
/// \todo Probably shouldn't be here
|
/// \todo Probably shouldn't be here
|
||||||
MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) override;
|
MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) override;
|
||||||
|
|
|
@ -489,7 +489,7 @@ namespace Compiler
|
||||||
parseArguments ("l", scanner);
|
parseArguments ("l", scanner);
|
||||||
|
|
||||||
Generator::random (mCode);
|
Generator::random (mCode);
|
||||||
mOperands.push_back ('l');
|
mOperands.push_back ('f');
|
||||||
|
|
||||||
mNextOperand = false;
|
mNextOperand = false;
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -323,7 +323,9 @@ namespace ESM
|
||||||
: mFlags (land.mFlags), mX (land.mX), mY (land.mY), mPlugin (land.mPlugin),
|
: mFlags (land.mFlags), mX (land.mX), mY (land.mY), mPlugin (land.mPlugin),
|
||||||
mContext (land.mContext), mDataTypes (land.mDataTypes),
|
mContext (land.mContext), mDataTypes (land.mDataTypes),
|
||||||
mLandData (land.mLandData ? new LandData (*land.mLandData) : 0)
|
mLandData (land.mLandData ? new LandData (*land.mLandData) : 0)
|
||||||
{}
|
{
|
||||||
|
std::copy(land.mWnam, land.mWnam + LAND_GLOBAL_MAP_LOD_SIZE, mWnam);
|
||||||
|
}
|
||||||
|
|
||||||
Land& Land::operator= (Land land)
|
Land& Land::operator= (Land land)
|
||||||
{
|
{
|
||||||
|
@ -340,6 +342,7 @@ namespace ESM
|
||||||
std::swap (mContext, land.mContext);
|
std::swap (mContext, land.mContext);
|
||||||
std::swap (mDataTypes, land.mDataTypes);
|
std::swap (mDataTypes, land.mDataTypes);
|
||||||
std::swap (mLandData, land.mLandData);
|
std::swap (mLandData, land.mLandData);
|
||||||
|
std::swap (mWnam, land.mWnam);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Land::LandData *Land::getLandData (int flags) const
|
const Land::LandData *Land::getLandData (int flags) const
|
||||||
|
|
|
@ -190,9 +190,7 @@ namespace Interpreter
|
||||||
throw std::runtime_error (
|
throw std::runtime_error (
|
||||||
"random: argument out of range (Don't be so negative!)");
|
"random: argument out of range (Don't be so negative!)");
|
||||||
|
|
||||||
Type_Integer value = Misc::Rng::rollDice(limit); // [o, limit)
|
runtime[0].mFloat = static_cast<Type_Float>(Misc::Rng::rollDice(limit)); // [o, limit)
|
||||||
|
|
||||||
runtime[0].mInteger = value;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -210,7 +210,6 @@ public:
|
||||||
private:
|
private:
|
||||||
Terrain::Storage* mStorage;
|
Terrain::Storage* mStorage;
|
||||||
|
|
||||||
float mLodFactor;
|
|
||||||
float mMinX, mMaxX, mMinY, mMaxY;
|
float mMinX, mMaxX, mMinY, mMaxY;
|
||||||
float mMinSize;
|
float mMinSize;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
Shadow Settings
|
Shadows Settings
|
||||||
###############
|
################
|
||||||
|
|
||||||
Main settings
|
Main settings
|
||||||
*************
|
*************
|
||||||
|
|
Loading…
Reference in a new issue