From 3e29bb8a860cfdc3dc58855b616f2fc2f38b0a05 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 26 Jun 2015 16:10:50 +1000 Subject: [PATCH] Fix undo for NPC autocalc changes. Fix the lack of refresh after race powers subtable. --- apps/opencs/model/world/data.cpp | 83 +++------------------ apps/opencs/model/world/data.hpp | 2 - apps/opencs/model/world/refidadapterimp.cpp | 47 +++++++++++- apps/opencs/model/world/refidadapterimp.hpp | 3 +- apps/opencs/model/world/refidcollection.cpp | 2 +- 5 files changed, 58 insertions(+), 79 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 3cb5d3cbb..6d17e90b7 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -1324,25 +1324,33 @@ void CSMWorld::Data::raceDataChanged (const QModelIndex& topLeft, const QModelIn // affects racial bonus attributes & skills // - mData.mAttributeValues[] // - mData.mBonus[].mBonus + // - mPowers.mList[] CSMWorld::IdTree *raceModel = static_cast(getTableModel(CSMWorld::UniversalId::Type_Race)); int attrColumn = raceModel->findColumnIndex(CSMWorld::Columns::ColumnId_RaceAttributes); int bonusColumn = raceModel->findColumnIndex(CSMWorld::Columns::ColumnId_RaceSkillBonus); + int powersColumn = raceModel->findColumnIndex(CSMWorld::Columns::ColumnId_PowerList); bool match = false; + int raceRow = topLeft.row(); + int raceEnd = bottomRight.row(); if (topLeft.parent().isValid() && bottomRight.parent().isValid()) { if ((topLeft.parent().column() <= attrColumn && attrColumn <= bottomRight.parent().column()) - || (topLeft.parent().column() <= bonusColumn && bonusColumn <= bottomRight.parent().column())) + || (topLeft.parent().column() <= bonusColumn && bonusColumn <= bottomRight.parent().column()) + || (topLeft.parent().column() <= powersColumn && powersColumn <= bottomRight.parent().column())) { match = true; // TODO: check for specific nested column? + raceRow = topLeft.parent().row(); + raceEnd = bottomRight.parent().row(); } } else { if ((topLeft.column() <= attrColumn && attrColumn <= bottomRight.column()) - || (topLeft.column() <= bonusColumn && bonusColumn <= bottomRight.column())) + || (topLeft.column() <= bonusColumn && bonusColumn <= bottomRight.column()) + || (topLeft.column() <= powersColumn && powersColumn <= bottomRight.column())) { match = true; // maybe the whole table changed } @@ -1353,7 +1361,7 @@ void CSMWorld::Data::raceDataChanged (const QModelIndex& topLeft, const QModelIn // update autocalculated attributes/skills of every NPC with matching race int idColumn = raceModel->findColumnIndex(CSMWorld::Columns::ColumnId_Id); - for (int raceRow = topLeft.parent().row(); raceRow <= bottomRight.parent().row(); ++raceRow) + for (; raceRow <= raceEnd; ++raceRow) { clearNpcStatsCache(); @@ -1363,44 +1371,10 @@ void CSMWorld::Data::raceDataChanged (const QModelIndex& topLeft, const QModelIn } } -// FIXME: currently ignoring level changes void CSMWorld::Data::npcDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { + // TODO: for now always recalculate clearNpcStatsCache(); - - // Either autoCalc flag changed or NPC level changed - CSMWorld::IdTree *objectModel = - static_cast(getTableModel(CSMWorld::UniversalId::Type_Referenceable)); - - int autoCalcColumn = objectModel->findColumnIndex(CSMWorld::Columns::ColumnId_AutoCalc); - - // check for autocalc - if (topLeft.parent().isValid() || bottomRight.parent().isValid() - || topLeft.column() > autoCalcColumn || autoCalcColumn > bottomRight.column()) - { - return; - } - - int row = topLeft.row(); - for (; row <= bottomRight.row(); ++row) - { - Record record = - static_cast&>(mReferenceables.getRecord(row)); - ESM::NPC &npc = record.get(); - - if (npc.mNpdtType != ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS) - { - // first pretend autocalc to force recalculation - npc.mNpdtType = ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS; - saveAutoCalcValues(npc); // update attributes and skills - npc.mNpdtType = ESM::NPC::NPC_DEFAULT; - } - else - npc.mNpdt12.mLevel = npc.mNpdt52.mLevel; // for NPC's loaded as non-autocalc - - record.setModified(npc); - mReferenceables.replace(row, record); - } } void CSMWorld::Data::gmstDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) @@ -1429,39 +1403,6 @@ void CSMWorld::Data::gmstDataChanged (const QModelIndex& topLeft, const QModelIn emit updateNpcAutocalc(0/*all*/, empty); } -// FIXME: how to undo? -void CSMWorld::Data::saveAutoCalcValues(ESM::NPC& npc) -{ - CSMWorld::NpcStats *stats = npcAutoCalculate(npc); - - // update npc - npc.mNpdt52.mLevel = npc.mNpdt12.mLevel; - - npc.mNpdt52.mStrength = stats->getBaseAttribute(ESM::Attribute::Strength); - npc.mNpdt52.mIntelligence = stats->getBaseAttribute(ESM::Attribute::Intelligence); - npc.mNpdt52.mWillpower = stats->getBaseAttribute(ESM::Attribute::Willpower); - npc.mNpdt52.mAgility = stats->getBaseAttribute(ESM::Attribute::Agility); - npc.mNpdt52.mSpeed = stats->getBaseAttribute(ESM::Attribute::Speed); - npc.mNpdt52.mEndurance = stats->getBaseAttribute(ESM::Attribute::Endurance); - npc.mNpdt52.mPersonality = stats->getBaseAttribute(ESM::Attribute::Personality); - npc.mNpdt52.mLuck = stats->getBaseAttribute(ESM::Attribute::Luck); - - for (int i = 0; i < ESM::Skill::Length; ++i) - { - npc.mNpdt52.mSkills[i] = stats->getBaseSkill(i); - } - - npc.mNpdt52.mHealth = stats->getHealth(); - npc.mNpdt52.mMana = stats->getMana(); - npc.mNpdt52.mFatigue = stats->getFatigue(); - npc.mNpdt52.mDisposition = npc.mNpdt12.mDisposition; - npc.mNpdt52.mReputation = npc.mNpdt12.mReputation; - npc.mNpdt52.mRank = npc.mNpdt12.mRank; - npc.mNpdt52.mGold = npc.mNpdt12.mGold; - - // TODO: add spells from autogenerated list like vanilla (but excluding any race powers or abilities) -} - void CSMWorld::Data::clearNpcStatsCache () { for (std::map::iterator it (mNpcStatCache.begin()); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index fdc76fd73..e081318a6 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -126,8 +126,6 @@ namespace CSMWorld const Data& self (); - void saveAutoCalcValues(ESM::NPC& npc); - void clearNpcStatsCache (); public: diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 99ca76d73..2bb980bfe 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -558,8 +558,8 @@ CSMWorld::NpcColumns::NpcColumns (const ActorColumns& actorColumns) mMisc(NULL) {} -CSMWorld::NpcRefIdAdapter::NpcRefIdAdapter (const NpcColumns& columns) -: ActorRefIdAdapter (UniversalId::Type_Npc, columns), mColumns (columns) +CSMWorld::NpcRefIdAdapter::NpcRefIdAdapter (const NpcColumns& columns, const CSMWorld::Data& data) +: ActorRefIdAdapter (UniversalId::Type_Npc, columns), mColumns (columns), mData(data) {} QVariant CSMWorld::NpcRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, int index) @@ -634,8 +634,47 @@ void CSMWorld::NpcRefIdAdapter::setData (const RefIdColumn *column, RefIdData& d npc.mFlags &= ~iter->second; if (iter->second == ESM::NPC::Autocalc) - npc.mNpdtType = (value.toInt() != 0) ? ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS - : ESM::NPC::NPC_DEFAULT; + { + if (npc.mNpdtType == ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS) + { + CSMWorld::NpcStats *stats = mData.npcAutoCalculate(npc); + + // update npc + npc.mNpdtType = ESM::NPC::NPC_DEFAULT; + npc.mNpdt52.mLevel = npc.mNpdt12.mLevel; + + npc.mNpdt52.mStrength = stats->getBaseAttribute(ESM::Attribute::Strength); + npc.mNpdt52.mIntelligence = stats->getBaseAttribute(ESM::Attribute::Intelligence); + npc.mNpdt52.mWillpower = stats->getBaseAttribute(ESM::Attribute::Willpower); + npc.mNpdt52.mAgility = stats->getBaseAttribute(ESM::Attribute::Agility); + npc.mNpdt52.mSpeed = stats->getBaseAttribute(ESM::Attribute::Speed); + npc.mNpdt52.mEndurance = stats->getBaseAttribute(ESM::Attribute::Endurance); + npc.mNpdt52.mPersonality = stats->getBaseAttribute(ESM::Attribute::Personality); + npc.mNpdt52.mLuck = stats->getBaseAttribute(ESM::Attribute::Luck); + + for (int i = 0; i < ESM::Skill::Length; ++i) + { + npc.mNpdt52.mSkills[i] = stats->getBaseSkill(i); + } + + npc.mNpdt52.mHealth = stats->getHealth(); + npc.mNpdt52.mMana = stats->getMana(); + npc.mNpdt52.mFatigue = stats->getFatigue(); + npc.mNpdt52.mDisposition = npc.mNpdt12.mDisposition; + npc.mNpdt52.mReputation = npc.mNpdt12.mReputation; + npc.mNpdt52.mRank = npc.mNpdt12.mRank; + npc.mNpdt52.mGold = npc.mNpdt12.mGold; + + // TODO: add spells from autogenerated list like vanilla (but excluding any + // race powers or abilities) + } + else + { + npc.mNpdtType = ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS; + npc.mNpdt12.mLevel = npc.mNpdt52.mLevel; // for NPC's loaded as non-autocalc + mData.npcAutoCalculate(npc); + } + } } else { diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index acdc124eb..4a8288fa4 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -807,10 +807,11 @@ namespace CSMWorld class NpcRefIdAdapter : public ActorRefIdAdapter { NpcColumns mColumns; + const Data& mData; public: - NpcRefIdAdapter (const NpcColumns& columns); + NpcRefIdAdapter (const NpcColumns& columns, const Data& data); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index d5232db63..fc52fe388 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -620,7 +620,7 @@ CSMWorld::RefIdCollection::RefIdCollection(const CSMWorld::Data& data) mAdapters.insert (std::make_pair (UniversalId::Type_Miscellaneous, new MiscRefIdAdapter (inventoryColumns, key))); mAdapters.insert (std::make_pair (UniversalId::Type_Npc, - new NpcRefIdAdapter (npcColumns))); + new NpcRefIdAdapter (npcColumns, data))); mAdapters.insert (std::make_pair (UniversalId::Type_Probe, new ToolRefIdAdapter (UniversalId::Type_Probe, toolsColumns))); mAdapters.insert (std::make_pair (UniversalId::Type_Repair,