mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-21 06:39:42 +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 #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 #2969: Scripted items can stack
|
||||
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 #3812: Wrong multiline tooltips width when word-wrapping is enabled
|
||||
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 #4240: Ash storm origin coordinates and hand shielding animation behavior are incorrect
|
||||
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 #4411: Reloading a saved game while falling prevents damage in some cases
|
||||
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 #4600: Crash when no sound output is available or --no-sound is used.
|
||||
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 #4896: Title screen music doesn't loop
|
||||
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 #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
|
||||
|
@ -116,6 +120,7 @@
|
|||
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 #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 #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
|
||||
|
@ -140,6 +145,7 @@
|
|||
Bug #5124: Arrow remains attached to actor if pulling animation was cancelled
|
||||
Bug #5126: Swimming creatures without RunForward animations are motionless during combat
|
||||
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 #5149: Failing lock pick attempts isn't always a crime
|
||||
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 #5168: Force1stPerson and Force3rdPerson commands are not really force view change
|
||||
Bug #5169: Nested levelled items/creatures have significantly higher chance not to spawn
|
||||
Bug #5175: Random script function returns an integer value
|
||||
Bug #5177: Editor: Unexplored map tiles get corrupted after a file with terrain is saved
|
||||
Feature #1774: Handle AvoidNode
|
||||
Feature #2229: Improve pathfinding AI
|
||||
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)
|
||||
- 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)
|
||||
- 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)
|
||||
- Minimap doesn't get corrupted, when editing new omwgame (#5177)
|
||||
|
||||
Miscellaneous:
|
||||
- Upgraded to FFMPEG3 for media decoding (#4686)
|
||||
|
|
|
@ -41,9 +41,9 @@
|
|||
CSVRender::TerrainTextureMode::TerrainTextureMode (WorldspaceWidget *worldspaceWidget, osg::Group* parentNode, QWidget *parent)
|
||||
: EditMode (worldspaceWidget, QIcon {":scenetoolbar/editing-terrain-texture"}, Mask_Terrain | Mask_Reference, "Terrain texture editing", parent),
|
||||
mBrushTexture("L0#0"),
|
||||
mBrushSize(0),
|
||||
mBrushSize(1),
|
||||
mBrushShape(0),
|
||||
mTextureBrushScenetool(0),
|
||||
mTextureBrushScenetool(nullptr),
|
||||
mDragMode(InteractionType_None),
|
||||
mParentNode(parentNode),
|
||||
mIsEditing(false)
|
||||
|
@ -82,7 +82,7 @@ void CSVRender::TerrainTextureMode::deactivate(CSVWidget::SceneToolbar* toolbar)
|
|||
{
|
||||
toolbar->removeTool (mTextureBrushScenetool);
|
||||
delete mTextureBrushScenetool;
|
||||
mTextureBrushScenetool = 0;
|
||||
mTextureBrushScenetool = nullptr;
|
||||
}
|
||||
|
||||
if (mTerrainTextureSelection)
|
||||
|
|
|
@ -51,36 +51,37 @@ namespace CSVRender
|
|||
/// \brief Editmode for terrain texture grid
|
||||
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
|
||||
void primaryEditPressed (const WorldspaceHitResult& hit);
|
||||
void primaryEditPressed (const WorldspaceHitResult& hit) final;
|
||||
|
||||
/// \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 deactivate(CSVWidget::SceneToolbar*);
|
||||
void activate(CSVWidget::SceneToolbar*) final;
|
||||
void deactivate(CSVWidget::SceneToolbar*) final;
|
||||
|
||||
/// \brief Start texture editing command macro
|
||||
virtual bool primaryEditStartDrag (const QPoint& pos);
|
||||
bool primaryEditStartDrag (const QPoint& pos) final;
|
||||
|
||||
virtual bool secondaryEditStartDrag (const QPoint& pos);
|
||||
virtual bool primarySelectStartDrag (const QPoint& pos);
|
||||
virtual bool secondarySelectStartDrag (const QPoint& pos);
|
||||
bool secondaryEditStartDrag (const QPoint& pos) final;
|
||||
bool primarySelectStartDrag (const QPoint& pos) final;
|
||||
bool secondarySelectStartDrag (const QPoint& pos) final;
|
||||
|
||||
/// \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
|
||||
virtual void dragCompleted(const QPoint& pos);
|
||||
void dragCompleted(const QPoint& pos) final;
|
||||
|
||||
virtual void dragAborted();
|
||||
virtual void dragWheel (int diff, double speedFactor);
|
||||
virtual void dragMoveEvent (QDragMoveEvent *event);
|
||||
void dragAborted() final;
|
||||
void dragWheel (int diff, double speedFactor) final;
|
||||
void dragMoveEvent (QDragMoveEvent *event) final;
|
||||
|
||||
private:
|
||||
/// \brief Handle brush mechanics, maths regarding worldspace hit etc.
|
||||
void editTerrainTextureGrid (const WorldspaceHitResult& hit);
|
||||
|
||||
|
@ -100,7 +101,6 @@ namespace CSVRender
|
|||
/// \brief Create new cell and land if needed
|
||||
bool allowLandTextureEditing(std::string textureFileName);
|
||||
|
||||
private:
|
||||
std::string mCellId;
|
||||
std::string mBrushTexture;
|
||||
int mBrushSize;
|
||||
|
@ -113,7 +113,6 @@ namespace CSVRender
|
|||
std::unique_ptr<TerrainSelection> mTerrainTextureSelection;
|
||||
|
||||
const int cellSize {ESM::Land::REAL_SIZE};
|
||||
const int landSize {ESM::Land::LAND_SIZE};
|
||||
const int landTextureSize {ESM::Land::LAND_TEXTURE_SIZE};
|
||||
|
||||
signals:
|
||||
|
|
|
@ -33,19 +33,19 @@
|
|||
|
||||
|
||||
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->setTickInterval(10);
|
||||
mBrushSizeSlider->setRange(1, CSMPrefs::get()["3D Scene Editing"]["texturebrush-maximumsize"].toInt());
|
||||
mBrushSizeSlider->setSingleStep(1);
|
||||
|
||||
mBrushSizeSpinBox = new QSpinBox;
|
||||
mBrushSizeSpinBox->setRange(1, CSMPrefs::get()["3D Scene Editing"]["texturebrush-maximumsize"].toInt());
|
||||
mBrushSizeSpinBox->setSingleStep(1);
|
||||
|
||||
mLayoutSliderSize = new QHBoxLayout;
|
||||
mLayoutSliderSize->addWidget(mBrushSizeSlider);
|
||||
mLayoutSliderSize->addWidget(mBrushSizeSpinBox);
|
||||
|
||||
|
@ -58,7 +58,7 @@ CSVWidget::BrushSizeControls::BrushSizeControls(const QString &title, QWidget *p
|
|||
CSVWidget::TextureBrushWindow::TextureBrushWindow(CSMDoc::Document& document, QWidget *parent)
|
||||
: QFrame(parent, Qt::Popup),
|
||||
mBrushShape(0),
|
||||
mBrushSize(0),
|
||||
mBrushSize(1),
|
||||
mBrushTexture("L0#0"),
|
||||
mDocument(document)
|
||||
{
|
||||
|
@ -142,60 +142,61 @@ void CSVWidget::TextureBrushWindow::configureButtonInitialSettings(QPushButton *
|
|||
|
||||
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();
|
||||
|
||||
int landTextureFilename = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Texture);
|
||||
int columnModification = landtexturesCollection.findColumnIndex(CSMWorld::Columns::ColumnId_Modification);
|
||||
int index = landtexturesCollection.searchId(mBrushTexture);
|
||||
|
||||
// Check if texture exists in current plugin
|
||||
if(landtexturesCollection.getData(index, columnModification).value<int>() == 0)
|
||||
int index = 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&> (
|
||||
*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())
|
||||
if (rowInBase == -1)
|
||||
{
|
||||
int counter=0;
|
||||
bool freeIndexFound = false;
|
||||
const int maxCounter = std::numeric_limits<uint16_t>::max() - 1;
|
||||
do {
|
||||
const size_t maxCounter = std::numeric_limits<uint16_t>::max() - 1;
|
||||
mBrushTexturePlugin = CSMWorld::LandTexture::createUniqueRecordId(0, counter);
|
||||
if (landtexturesCollection.searchId(mBrushTexturePlugin) != -1 && landtexturesCollection.getRecord(mBrushTexturePlugin).isDeleted() == 0) counter = (counter + 1) % maxCounter;
|
||||
newBrushTextureId = CSMWorld::LandTexture::createUniqueRecordId(0, counter);
|
||||
if (landtexturesCollection.searchId(brushTexture) != -1 &&
|
||||
landtexturesCollection.getRecord(brushTexture).isDeleted() == 0 &&
|
||||
landtexturesCollection.searchId(newBrushTextureId) != -1 &&
|
||||
landtexturesCollection.getRecord(newBrushTextureId).isDeleted() == 0)
|
||||
counter = (counter + 1) % maxCounter;
|
||||
else freeIndexFound = true;
|
||||
} while (freeIndexFound == false);
|
||||
} while (freeIndexFound == false || counter < maxCounter);
|
||||
}
|
||||
|
||||
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();
|
||||
mBrushTexture = mBrushTexturePlugin;
|
||||
emit passTextureId(mBrushTexture);
|
||||
}
|
||||
|
||||
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>());
|
||||
} else
|
||||
{
|
||||
newBrushTextureId = "";
|
||||
mBrushTextureLabel = "No selected texture or invalid texture";
|
||||
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)
|
||||
|
|
|
@ -81,7 +81,7 @@ add_openmw_dir (mwclass
|
|||
add_openmw_dir (mwmechanics
|
||||
mechanicsmanagerimp stat creaturestats magiceffects movement actorutil
|
||||
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
|
||||
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;
|
||||
mEnvironment.getWorld()->advanceTime(hours, true);
|
||||
mEnvironment.getWorld()->rechargeItems(frametime, true);
|
||||
}
|
||||
}
|
||||
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
|
||||
/// component is up).
|
||||
|
||||
virtual void advanceTime (float duration) = 0;
|
||||
|
||||
virtual void setPlayerName (const std::string& name) = 0;
|
||||
///< Set player name.
|
||||
|
||||
|
|
|
@ -584,6 +584,7 @@ namespace MWBase
|
|||
virtual bool isPlayerInJail() const = 0;
|
||||
|
||||
virtual void rest(double hours) = 0;
|
||||
virtual void rechargeItems(double duration, bool activeOnly) = 0;
|
||||
|
||||
virtual void setPlayerTraveling(bool traveling) = 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))
|
||||
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)
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace MWGui
|
|||
public:
|
||||
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);
|
||||
|
||||
bool hasProfit(const MWWorld::Ptr& actor);
|
||||
|
|
|
@ -91,7 +91,7 @@ ItemModel::ModelIndex ContainerItemModel::getIndex (ItemStack item)
|
|||
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];
|
||||
if (item.mBase.getContainerStore() == &source.getClass().getContainerStore(source))
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace MWGui
|
|||
virtual ModelIndex getIndex (ItemStack item);
|
||||
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 update();
|
||||
|
|
|
@ -38,7 +38,7 @@ namespace MWGui
|
|||
public:
|
||||
WorldItemModel(float left, float top) : mLeft(left), mTop(top) {}
|
||||
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();
|
||||
|
||||
|
@ -47,8 +47,7 @@ namespace MWGui
|
|||
dropped = world->placeObject(item.mBase, mLeft, mTop, count);
|
||||
else
|
||||
dropped = world->dropObjectOnGround(world->getPlayerPtr(), item.mBase, count);
|
||||
if (setNewOwner)
|
||||
dropped.getCellRef().setOwner("");
|
||||
dropped.getCellRef().setOwner("");
|
||||
|
||||
return dropped;
|
||||
}
|
||||
|
|
|
@ -46,11 +46,11 @@ ItemModel::ModelIndex InventoryItemModel::getIndex (ItemStack item)
|
|||
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))
|
||||
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)
|
||||
|
@ -88,7 +88,7 @@ MWWorld::Ptr InventoryItemModel::moveItem(const ItemStack &item, size_t count, I
|
|||
if (item.mFlags & ItemStack::Flag_Bound)
|
||||
return MWWorld::Ptr();
|
||||
|
||||
MWWorld::Ptr ret = otherModel->copyItem(item, count, false);
|
||||
MWWorld::Ptr ret = otherModel->copyItem(item, count);
|
||||
removeItem(item, count);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace MWGui
|
|||
|
||||
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);
|
||||
|
||||
/// Move items from this model to \a otherModel.
|
||||
|
|
|
@ -116,9 +116,9 @@ namespace MWGui
|
|||
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)
|
||||
|
|
|
@ -67,7 +67,7 @@ namespace MWGui
|
|||
|
||||
/// @param setNewOwner If true, set the copied item's owner to the actor we are copying 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;
|
||||
|
||||
/// 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 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 ModelIndex getIndex (ItemStack item);
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ namespace MWGui
|
|||
if (pickpocket.finish())
|
||||
{
|
||||
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);
|
||||
mPickpocketDetected = true;
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ namespace MWGui
|
|||
if (pickpocket.pick(item, count))
|
||||
{
|
||||
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);
|
||||
mPickpocketDetected = true;
|
||||
return false;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwmechanics/actorutil.hpp"
|
||||
#include "../mwmechanics/recharge.hpp"
|
||||
|
||||
#include "itemwidget.hpp"
|
||||
#include "itemchargeview.hpp"
|
||||
|
@ -130,62 +131,9 @@ void Recharge::onItemCancel()
|
|||
void Recharge::onItemClicked(MyGUI::Widget *sender, const MWWorld::Ptr& item)
|
||||
{
|
||||
MWWorld::Ptr gem = *mGemIcon->getUserData<MWWorld::Ptr>();
|
||||
|
||||
if (!gem.getRefData().getCount())
|
||||
if (!MWMechanics::rechargeItem(item, gem))
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -652,19 +652,22 @@ namespace MWGui
|
|||
std::string ret;
|
||||
ret += getMiscString(cellref.getOwner(), "Owner");
|
||||
const std::string factionId = cellref.getFaction();
|
||||
ret += getMiscString(factionId, "Faction");
|
||||
if (!factionId.empty() && cellref.getFactionRank() >= 0)
|
||||
if (!factionId.empty())
|
||||
{
|
||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||
const ESM::Faction *fact = store.get<ESM::Faction>().search(factionId);
|
||||
if (fact != nullptr)
|
||||
{
|
||||
int rank = cellref.getFactionRank();
|
||||
const std::string rankName = fact->mRanks[rank];
|
||||
if (rankName.empty())
|
||||
ret += getValueString(cellref.getFactionRank(), "Rank");
|
||||
else
|
||||
ret += getMiscString(rankName, "Rank");
|
||||
ret += getMiscString(fact->mName.empty() ? factionId : fact->mName, "Owner Faction");
|
||||
if (cellref.getFactionRank() >= 0)
|
||||
{
|
||||
int rank = cellref.getFactionRank();
|
||||
const std::string rankName = fact->mRanks[rank];
|
||||
if (rankName.empty())
|
||||
ret += getValueString(cellref.getFactionRank(), "Rank");
|
||||
else
|
||||
ret += getMiscString(rankName, "Rank");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "creaturestats.hpp"
|
||||
#include "movement.hpp"
|
||||
#include "steering.hpp"
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
|
@ -33,16 +34,18 @@ namespace MWMechanics
|
|||
if (target == MWWorld::Ptr() || !target.getRefData().getCount() || !target.getRefData().isEnabled())
|
||||
return true;
|
||||
|
||||
//Set the target destination for the actor
|
||||
const osg::Vec3f dest = target.getRefData().getPosition().asVec3();
|
||||
// Turn to target and move to it directly, without pathfinding.
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "aiavoiddoor.hpp"
|
||||
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
|
@ -11,8 +13,10 @@
|
|||
#include "actorutil.hpp"
|
||||
#include "steering.hpp"
|
||||
|
||||
static const int MAX_DIRECTIONS = 4;
|
||||
|
||||
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();
|
||||
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
|
||||
|
||||
if(mDuration < 0) {
|
||||
float x = pos.pos[0] - mLastPos.pos[0];
|
||||
float y = pos.pos[1] - mLastPos.pos[1];
|
||||
float z = pos.pos[2] - mLastPos.pos[2];
|
||||
float distance = x * x + y * y + z * z;
|
||||
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;
|
||||
if (mDuration < 0)
|
||||
{
|
||||
if (isStuck(pos.asVec3()))
|
||||
{
|
||||
adjustDirection();
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -54,7 +51,7 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, CharacterCont
|
|||
actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
|
||||
|
||||
// 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;
|
||||
else
|
||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
||||
|
@ -90,4 +87,17 @@ unsigned int MWMechanics::AiAvoidDoor::getPriority() const
|
|||
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:
|
||||
float mDuration;
|
||||
MWWorld::ConstPtr mDoorPtr;
|
||||
ESM::Position mLastPos;
|
||||
float mAdjAngle;
|
||||
osg::Vec3f mLastPos;
|
||||
int mDirection;
|
||||
|
||||
bool isStuck(const osg::Vec3f& actorPos) const;
|
||||
|
||||
void adjustDirection();
|
||||
|
||||
float getAdjustedAngle() const;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1629,7 +1629,9 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
|||
if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && !isKnockedDown())
|
||||
{
|
||||
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
|
||||
// (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.
|
||||
// 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 maxAttackTime = mAnimation->getTextKeyTime(mCurrentWeapon+": "+mAttackType+" "+"max attack");
|
||||
if (mAttackingOrSpell || minAttackTime == maxAttackTime)
|
||||
|
|
|
@ -287,16 +287,6 @@ namespace MWMechanics
|
|||
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)
|
||||
{
|
||||
if(!mWatched.isEmpty())
|
||||
|
|
|
@ -78,8 +78,6 @@ namespace MWMechanics
|
|||
/// \param paused In game type does not currently advance (this usually means some GUI
|
||||
/// component is up).
|
||||
|
||||
virtual void advanceTime (float duration) override;
|
||||
|
||||
virtual void setPlayerName (const std::string& name) override;
|
||||
///< 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)
|
||||
{
|
||||
if (id.mPaged)
|
||||
|
|
|
@ -61,7 +61,9 @@ namespace MWWorld
|
|||
|
||||
/// @note name must be lower case
|
||||
Ptr getPtr (const std::string& name);
|
||||
|
||||
void rest (double hours);
|
||||
void recharge (float duration);
|
||||
|
||||
/// Get all Ptrs referencing \a name in exterior cells
|
||||
/// @note Due to the current implementation of getPtr this only supports one Ptr per cell.
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwmechanics/recharge.hpp"
|
||||
|
||||
#include "ptr.hpp"
|
||||
#include "esmstore.hpp"
|
||||
|
@ -328,6 +329,7 @@ namespace MWWorld
|
|||
void CellStore::updateMergedRefs()
|
||||
{
|
||||
mMergedRefs.clear();
|
||||
mRechargingItemsUpToDate = false;
|
||||
MergeVisitor visitor(mMergedRefs, mMovedHere, mMovedToAnotherCell);
|
||||
forEachInternal(visitor);
|
||||
visitor.merge();
|
||||
|
@ -345,7 +347,7 @@ namespace MWWorld
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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()
|
||||
{
|
||||
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.
|
||||
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
|
||||
template<class Visitor, class List>
|
||||
bool forEachImp (Visitor& visitor, List& list)
|
||||
|
@ -184,6 +194,7 @@ namespace MWWorld
|
|||
MWWorld::Ptr moveTo(const MWWorld::Ptr& object, MWWorld::CellStore* cellToMoveTo);
|
||||
|
||||
void rest(double hours);
|
||||
void recharge(float duration);
|
||||
|
||||
/// 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.
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwmechanics/levelledlist.hpp"
|
||||
#include "../mwmechanics/actorutil.hpp"
|
||||
#include "../mwmechanics/recharge.hpp"
|
||||
|
||||
#include "manualref.hpp"
|
||||
#include "refdata.hpp"
|
||||
|
@ -114,7 +115,11 @@ void MWWorld::ContainerStore::storeStates (const CellRefList<T>& collection,
|
|||
|
||||
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() {}
|
||||
|
||||
|
@ -241,7 +246,6 @@ bool MWWorld::ContainerStore::stacks(const ConstPtr& ptr1, const ConstPtr& ptr2)
|
|||
}
|
||||
|
||||
return ptr1 != ptr2 // an item never stacks onto itself
|
||||
&& ptr1.getCellRef().getOwner() == ptr2.getCellRef().getOwner()
|
||||
&& ptr1.getCellRef().getSoul() == ptr2.getCellRef().getSoul()
|
||||
|
||||
&& 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::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();
|
||||
|
||||
MWWorld::ContainerStoreIterator it = end();
|
||||
|
||||
// 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);
|
||||
MWWorld::ContainerStoreIterator it = addImp(itemPtr, count);
|
||||
|
||||
// The copy of the original item we just made
|
||||
MWWorld::Ptr item = *it;
|
||||
|
@ -298,7 +286,8 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr
|
|||
pos.pos[2] = 0;
|
||||
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().setFaction("");
|
||||
item.getCellRef().setFactionRank(-1);
|
||||
|
@ -408,6 +397,46 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addNewStack (const Cons
|
|||
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 toRemove = count;
|
||||
|
@ -477,50 +506,64 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::
|
|||
int count, bool topLevel, const std::string& levItem)
|
||||
{
|
||||
if (count == 0) return; //Don't restock with nothing.
|
||||
try {
|
||||
try
|
||||
{
|
||||
ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count);
|
||||
|
||||
if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name())
|
||||
if (ref.getPtr().getClass().getScript(ref.getPtr()).empty())
|
||||
{
|
||||
const ESM::ItemLevList* levItemList = ref.getPtr().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(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);
|
||||
}
|
||||
addInitialItemImp(ref.getPtr(), owner, count, topLevel, levItem);
|
||||
}
|
||||
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(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);
|
||||
// Adding just one item per time to make sure there isn't a stack of scripted items
|
||||
for (int i = 0; i < abs(count); i++)
|
||||
addInitialItemImp(ref.getPtr(), owner, count < 0 ? -1 : 1, topLevel, levItem);
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
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)
|
||||
|
@ -619,6 +662,7 @@ void MWWorld::ContainerStore::clear()
|
|||
void MWWorld::ContainerStore::flagAsModified()
|
||||
{
|
||||
mWeightUpToDate = false;
|
||||
mRechargingItemsUpToDate = false;
|
||||
}
|
||||
|
||||
float MWWorld::ContainerStore::getWeight() const
|
||||
|
|
|
@ -71,6 +71,12 @@ namespace MWWorld
|
|||
protected:
|
||||
ContainerStoreListener* mListener;
|
||||
|
||||
// (item, max charge)
|
||||
typedef std::vector<std::pair<ContainerStoreIterator, float> > TRechargingItems;
|
||||
TRechargingItems mRechargingItems;
|
||||
|
||||
bool mRechargingItemsUpToDate;
|
||||
|
||||
private:
|
||||
|
||||
MWWorld::CellRefList<ESM::Potion> potions;
|
||||
|
@ -94,6 +100,7 @@ namespace MWWorld
|
|||
mutable bool mWeightUpToDate;
|
||||
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 addInitialItemImp (const MWWorld::Ptr& ptr, const std::string& owner, int count, bool topLevel=true, const std::string& levItem = "");
|
||||
|
||||
template<typename T>
|
||||
ContainerStoreIterator getState (CellRefList<T>& collection,
|
||||
|
@ -107,6 +114,7 @@ namespace MWWorld
|
|||
ESM::InventoryState& inventory, int& index,
|
||||
bool equipable = false) const;
|
||||
|
||||
void updateRechargingItems();
|
||||
|
||||
virtual void storeEquipmentState (const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const;
|
||||
|
||||
|
@ -130,7 +138,7 @@ namespace MWWorld
|
|||
|
||||
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)
|
||||
///
|
||||
/// \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
|
||||
|
||||
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);
|
||||
///< 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)
|
||||
, mFirstAutoEquip(true)
|
||||
, mSelectedEnchantItem(end())
|
||||
, mRechargingItemsUpToDate(false)
|
||||
{
|
||||
initSlots (mSlots);
|
||||
}
|
||||
|
@ -114,7 +113,6 @@ MWWorld::InventoryStore::InventoryStore (const InventoryStore& store)
|
|||
, mFirstAutoEquip(store.mFirstAutoEquip)
|
||||
, mPermanentMagicEffectMagnitudes(store.mPermanentMagicEffectMagnitudes)
|
||||
, mSelectedEnchantItem(end())
|
||||
, mRechargingItemsUpToDate(false)
|
||||
{
|
||||
copySlots (store);
|
||||
}
|
||||
|
@ -133,9 +131,9 @@ MWWorld::InventoryStore& MWWorld::InventoryStore::operator= (const InventoryStor
|
|||
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
|
||||
if (actorPtr != MWMechanics::getPlayer()
|
||||
|
@ -709,12 +707,6 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor)
|
|||
mFirstAutoEquip = false;
|
||||
}
|
||||
|
||||
void MWWorld::InventoryStore::flagAsModified()
|
||||
{
|
||||
ContainerStore::flagAsModified();
|
||||
mRechargingItemsUpToDate = false;
|
||||
}
|
||||
|
||||
bool MWWorld::InventoryStore::stacks(const ConstPtr& ptr1, const ConstPtr& ptr2) const
|
||||
{
|
||||
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)
|
||||
{
|
||||
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")
|
||||
ContainerStoreIterator mSelectedEnchantItem;
|
||||
|
||||
// (item, max charge)
|
||||
typedef std::vector<std::pair<ContainerStoreIterator, float> > TRechargingItems;
|
||||
TRechargingItems mRechargingItems;
|
||||
|
||||
bool mRechargingItemsUpToDate;
|
||||
|
||||
void copySlots (const InventoryStore& store);
|
||||
|
||||
void initSlots (TSlots& slots_);
|
||||
|
||||
void updateMagicEffects(const Ptr& actor);
|
||||
void updateRechargingItems();
|
||||
|
||||
void fireEquipmentChangedEvent(const Ptr& actor);
|
||||
|
||||
|
@ -132,7 +125,7 @@ namespace MWWorld
|
|||
|
||||
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)
|
||||
/// Auto-equip items if specific conditions are fulfilled (see the implementation).
|
||||
///
|
||||
|
@ -171,10 +164,6 @@ namespace MWWorld
|
|||
const MWMechanics::MagicEffects& getMagicEffects() const;
|
||||
///< 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;
|
||||
///< @return true if the two specified objects can stack with each other
|
||||
|
||||
|
@ -216,9 +205,6 @@ namespace MWWorld
|
|||
|
||||
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);
|
||||
///< Remove a magic effect
|
||||
|
||||
|
|
|
@ -857,7 +857,17 @@ namespace MWWorld
|
|||
|
||||
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);
|
||||
|
||||
|
@ -1649,7 +1659,6 @@ namespace MWWorld
|
|||
}
|
||||
|
||||
// we need to undo the rotation
|
||||
rotateObject(door, objPos.rot[0], objPos.rot[1], oldRot);
|
||||
reached = false;
|
||||
}
|
||||
}
|
||||
|
@ -1671,6 +1680,8 @@ namespace MWWorld
|
|||
if (!closeSound.empty() && MWBase::Environment::get().getSoundManager()->getSoundPlaying(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
|
||||
|
@ -3304,7 +3315,6 @@ namespace MWWorld
|
|||
closestDistance = distance;
|
||||
closestMarker = marker;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return closestMarker;
|
||||
|
@ -3315,6 +3325,22 @@ namespace MWWorld
|
|||
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,
|
||||
const std::string& id)
|
||||
{
|
||||
|
|
|
@ -574,6 +574,7 @@ namespace MWWorld
|
|||
///< check if the player is allowed to rest
|
||||
|
||||
void rest(double hours) override;
|
||||
void rechargeItems(double duration, bool activeOnly) override;
|
||||
|
||||
/// \todo Probably shouldn't be here
|
||||
MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) override;
|
||||
|
|
|
@ -489,7 +489,7 @@ namespace Compiler
|
|||
parseArguments ("l", scanner);
|
||||
|
||||
Generator::random (mCode);
|
||||
mOperands.push_back ('l');
|
||||
mOperands.push_back ('f');
|
||||
|
||||
mNextOperand = false;
|
||||
return true;
|
||||
|
|
|
@ -323,7 +323,9 @@ namespace ESM
|
|||
: mFlags (land.mFlags), mX (land.mX), mY (land.mY), mPlugin (land.mPlugin),
|
||||
mContext (land.mContext), mDataTypes (land.mDataTypes),
|
||||
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)
|
||||
{
|
||||
|
@ -340,6 +342,7 @@ namespace ESM
|
|||
std::swap (mContext, land.mContext);
|
||||
std::swap (mDataTypes, land.mDataTypes);
|
||||
std::swap (mLandData, land.mLandData);
|
||||
std::swap (mWnam, land.mWnam);
|
||||
}
|
||||
|
||||
const Land::LandData *Land::getLandData (int flags) const
|
||||
|
|
|
@ -190,9 +190,7 @@ namespace Interpreter
|
|||
throw std::runtime_error (
|
||||
"random: argument out of range (Don't be so negative!)");
|
||||
|
||||
Type_Integer value = Misc::Rng::rollDice(limit); // [o, limit)
|
||||
|
||||
runtime[0].mInteger = value;
|
||||
runtime[0].mFloat = static_cast<Type_Float>(Misc::Rng::rollDice(limit)); // [o, limit)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -210,7 +210,6 @@ public:
|
|||
private:
|
||||
Terrain::Storage* mStorage;
|
||||
|
||||
float mLodFactor;
|
||||
float mMinX, mMaxX, mMinY, mMaxY;
|
||||
float mMinSize;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Shadow Settings
|
||||
###############
|
||||
Shadows Settings
|
||||
################
|
||||
|
||||
Main settings
|
||||
*************
|
||||
|
|
Loading…
Reference in a new issue