diff --git a/CHANGELOG.md b/CHANGELOG.md index bcdf269464..f79eca3e5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,12 @@ 0.48.0 ------ + Bug #3514: Editing a reference's position after loading an esp file makes the reference disappear Bug #3737: Scripts from The Underground 2 .esp do not play (all patched versions) Bug #3846: Strings starting with "-" fail to compile if not enclosed in quotes Bug #3905: Great House Dagoth issues Bug #4203: Resurrecting an actor should close the loot GUI + Bug #4752: UpdateCellCommand doesn't undo properly Bug #5100: Persuasion doesn't always clamp the resulting disposition Bug #5120: Scripted object spawning updates physics system Bug #5379: Wandering NPCs falling through cantons diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index a410d34b2a..9da2c2c144 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -285,7 +285,8 @@ void CSMDoc::WriteCellCollectionStage::writeReferences (const std::deque& r { refRecord.mRefNum.mIndex = newRefNum++; } - else if ((refRecord.mOriginalCell.empty() ? refRecord.mCell : refRecord.mOriginalCell) + + if ((refRecord.mOriginalCell.empty() ? refRecord.mCell : refRecord.mOriginalCell) != stream.str() && !interior) { // An empty mOriginalCell is meant to indicate that it is the same as diff --git a/apps/opencs/model/world/commanddispatcher.cpp b/apps/opencs/model/world/commanddispatcher.cpp index 36b3ba2e00..b517fed0fb 100644 --- a/apps/opencs/model/world/commanddispatcher.cpp +++ b/apps/opencs/model/world/commanddispatcher.cpp @@ -139,13 +139,28 @@ void CSMWorld::CommandDispatcher::executeModify (QAbstractItemModel *model, cons if (mLocked) return; - std::unique_ptr modifyCell; + std::unique_ptr clonedData; + std::unique_ptr deleteData; - std::unique_ptr modifyDataRefNum; + std::string newId; + + std::unique_ptr modifyData; + std::unique_ptr modifyCell; int columnId = model->data (index, ColumnBase::Role_ColumnId).toInt(); - if (columnId==Columns::ColumnId_PositionXPos || columnId==Columns::ColumnId_PositionYPos) + int stateColumn = dynamic_cast(*model).findColumnIndex(Columns::ColumnId_Modification); + + CSMWorld::IdTable& table = dynamic_cast(*model); // for getId() + QModelIndex stateIndex = table.getModelIndex(table.getId(index.row()), stateColumn); + RecordBase::State state = static_cast (model->data(stateIndex).toInt()); + + // This is not guaranteed to be the same as \a model, since a proxy could be used. + IdTable& model2 = dynamic_cast (*mDocument.getData().getTableModel(mId)); + + // DeleteCommand triggers a signal to the whole row from IdTable::setData(), so ignore the second call + if (state != RecordBase::State_Deleted && + (columnId==Columns::ColumnId_PositionXPos || columnId==Columns::ColumnId_PositionYPos)) { const float oldPosition = model->data (index).toFloat(); @@ -157,12 +172,9 @@ void CSMWorld::CommandDispatcher::executeModify (QAbstractItemModel *model, cons int row = proxy ? proxy->mapToSource (index).row() : index.row(); - // This is not guaranteed to be the same as \a model, since a proxy could be used. - IdTable& model2 = dynamic_cast (*mDocument.getData().getTableModel (mId)); - int cellColumn = model2.searchColumnIndex (Columns::ColumnId_Cell); - if (cellColumn!=-1) + if (cellColumn != -1) { QModelIndex cellIndex = model2.index (row, cellColumn); @@ -170,31 +182,46 @@ void CSMWorld::CommandDispatcher::executeModify (QAbstractItemModel *model, cons if (cellId.find ('#')!=std::string::npos) { - // Need to recalculate the cell and (if necessary) clear the instance's refNum - modifyCell.reset (new UpdateCellCommand (model2, row)); + RefCollection& collection = mDocument.getData().getReferences(); + newId = collection.getNewId(); - // Not sure which model this should be applied to - int refNumColumn = model2.searchColumnIndex (Columns::ColumnId_RefNum); + clonedData.reset(new CloneCommand(table, + table.getId(row), + newId, + CSMWorld::UniversalId::Type_Reference)); - if (refNumColumn!=-1) - modifyDataRefNum.reset (new ModifyCommand(*model, model->index(row, refNumColumn), 0)); + deleteData.reset(new DeleteCommand(table, + table.getId(row), + CSMWorld::UniversalId::Type_Reference)); } } } } - std::unique_ptr modifyData ( - new CSMWorld::ModifyCommand (*model, index, new_)); + if (!clonedData.get()) + { + // DeleteCommand will trigger executeModify after setting the state to State_Deleted + // from CommandDelegate::setModelDataImp() - ignore + if (state != RecordBase::State_Deleted) + modifyData.reset(new CSMWorld::ModifyCommand(*model, index, new_)); + } - if (modifyCell.get()) + if (clonedData.get()) { CommandMacro macro (mDocument.getUndoStack()); - macro.push (modifyData.release()); - macro.push (modifyCell.release()); - if (modifyDataRefNum.get()) - macro.push (modifyDataRefNum.release()); + macro.push(clonedData.release()); + macro.push(deleteData.release()); + + // cannot do these earlier because newIndex is not available until CloneCommand is executed + QModelIndex newIndex = model2.getModelIndex (newId, index.column()); + modifyData.reset (new CSMWorld::ModifyCommand (*model, newIndex, new_)); + macro.push(modifyData.release()); + + // once the data is updated update the cell location + modifyCell.reset(new UpdateCellCommand(model2, newIndex.row())); + macro.push(modifyCell.release()); } - else + else if (!clonedData.get() && modifyData.get()) mDocument.getUndoStack().push (modifyData.release()); } diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index f84373fb9d..d2cb23146f 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -311,7 +311,7 @@ namespace ESM mWater = 0; mWaterInt = false; mMapColor = 0; - mRefNumCounter = -1; + mRefNumCounter = 0; mData.mFlags = 0; mData.mX = 0; diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 7770f719e3..23f3d38cc8 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -94,7 +94,7 @@ struct Cell mWater(0), mWaterInt(false), mMapColor(0), - mRefNumCounter(-1) + mRefNumCounter(0) {} // Interior cells are indexed by this (it's the 'id'), for exterior