diff --git a/CHANGELOG.md b/CHANGELOG.md index d28da21ce..05746a548 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Feature #2229: Improve pathfinding AI Feature #3442: Default values for fallbacks from ini file Feature #3610: Option to invert X axis + Feature #4209: Editor: Faction rank sub-table Feature #4673: Weapon sheathing Feature #4730: Native animated containers support Task #4686: Upgrade media decoder to a more current FFmpeg API diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 1f16c9695..cf333c1b1 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -30,6 +30,7 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_Skill, Display_Class, Display_Faction, + Display_Rank, Display_Race, Display_Sound, Display_Region, diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index df37afe60..94ebbef55 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -46,6 +46,7 @@ namespace CSMWorld Display_Skill, Display_Class, Display_Faction, + Display_Rank, Display_Race, Display_Sound, Display_Region, diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 109708ab0..a04281ea6 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -234,9 +234,17 @@ namespace CSMWorld { ColumnId_SoundChance, "Chance" }, { ColumnId_FactionReactions, "Reactions" }, + { ColumnId_FactionRanks, "Ranks" }, //{ ColumnId_FactionID, "Faction ID" }, { ColumnId_FactionReaction, "Reaction" }, + { ColumnId_FactionAttrib1, "Attrib 1" }, + { ColumnId_FactionAttrib2, "Attrib 2" }, + { ColumnId_FactionPrimSkill, "Prim Skill" }, + { ColumnId_FactionFavSkill, "Fav Skill" }, + { ColumnId_FactionRep, "Fact Rep" }, + { ColumnId_RankName, "Rank Name" }, + { ColumnId_EffectList, "Effects" }, { ColumnId_EffectId, "Effect" }, //{ ColumnId_EffectAttribute, "Attrib" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index f9ba5725a..528d210a4 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -338,6 +338,14 @@ namespace CSMWorld ColumnId_LandColoursIndex = 304, ColumnId_LandTexturesIndex = 305, + ColumnId_RankName = 306, + ColumnId_FactionRanks = 307, + ColumnId_FactionPrimSkill = 308, + ColumnId_FactionFavSkill = 309, + ColumnId_FactionRep = 310, + ColumnId_FactionAttrib1 = 311, + ColumnId_FactionAttrib2 = 312, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 53bd04147..199f1a347 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -132,6 +132,23 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat mFactions.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_FactionReaction, ColumnBase::Display_Integer)); + // Faction Ranks + mFactions.addColumn (new NestedParentColumn (Columns::ColumnId_FactionRanks)); + index = mFactions.getColumns()-1; + mFactions.addAdapter (std::make_pair(&mFactions.getColumn(index), new FactionRanksAdapter ())); + mFactions.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_RankName, ColumnBase::Display_Rank)); + mFactions.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_FactionAttrib1, ColumnBase::Display_Integer)); + mFactions.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_FactionAttrib2, ColumnBase::Display_Integer)); + mFactions.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_FactionPrimSkill, ColumnBase::Display_Integer)); + mFactions.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_FactionFavSkill, ColumnBase::Display_Integer)); + mFactions.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_FactionRep, ColumnBase::Display_Integer)); + mRaces.addColumn (new StringIdColumn); mRaces.addColumn (new RecordStateColumn); mRaces.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Race)); diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index 464757cd4..5ae0dabaf 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -1090,4 +1090,83 @@ namespace CSMWorld { return 10; } + + FactionRanksAdapter::FactionRanksAdapter () {} + + void FactionRanksAdapter::addRow(Record& record, int position) const + { + throw std::logic_error ("cannot add a row to a fixed table"); + } + + void FactionRanksAdapter::removeRow(Record& record, int rowToRemove) const + { + throw std::logic_error ("cannot remove a row from a fixed table"); + } + + void FactionRanksAdapter::setTable(Record& record, + const NestedTableWrapperBase& nestedTable) const + { + throw std::logic_error ("table operation not supported"); + } + + NestedTableWrapperBase* FactionRanksAdapter::table(const Record& record) const + { + throw std::logic_error ("table operation not supported"); + } + + QVariant FactionRanksAdapter::getData(const Record& record, + int subRowIndex, int subColIndex) const + { + ESM::Faction faction = record.get(); + + if (subRowIndex < 0 || subRowIndex >= static_cast(sizeof(faction.mData.mRankData)/sizeof(faction.mData.mRankData[0]))) + throw std::runtime_error ("index out of range"); + + auto& rankData = faction.mData.mRankData[subRowIndex]; + + switch (subColIndex) + { + case 0: return QString(faction.mRanks[subRowIndex].c_str()); + case 1: return rankData.mAttribute1; + case 2: return rankData.mAttribute2; + case 3: return rankData.mSkill1; + case 4: return rankData.mSkill2; + case 5: return rankData.mFactReaction; + default: throw std::runtime_error("Rank subcolumn index out of range"); + } + } + + void FactionRanksAdapter::setData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const + { + ESM::Faction faction = record.get(); + + if (subRowIndex < 0 || subRowIndex >= static_cast(sizeof(faction.mData.mRankData)/sizeof(faction.mData.mRankData[0]))) + throw std::runtime_error ("index out of range"); + + auto& rankData = faction.mData.mRankData[subRowIndex]; + + switch (subColIndex) + { + case 0: faction.mRanks[subRowIndex] = value.toString().toUtf8().constData(); break; + case 1: rankData.mAttribute1 = value.toInt(); break; + case 2: rankData.mAttribute2 = value.toInt(); break; + case 3: rankData.mSkill1 = value.toInt(); break; + case 4: rankData.mSkill2 = value.toInt(); break; + case 5: rankData.mFactReaction = value.toInt(); break; + default: throw std::runtime_error("Rank index out of range"); + } + + record.setModified (faction); + } + + int FactionRanksAdapter::getColumnsCount(const Record& record) const + { + return 6; + } + + int FactionRanksAdapter::getRowsCount(const Record& record) const + { + return 10; + } } diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 131f547a5..60d983098 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -100,6 +100,31 @@ namespace CSMWorld virtual int getRowsCount(const Record& record) const; }; + class FactionRanksAdapter : public NestedColumnAdapter + { + public: + FactionRanksAdapter (); + + virtual void addRow(Record& record, int position) const; + + virtual void removeRow(Record& record, int rowToRemove) const; + + virtual void setTable(Record& record, + const NestedTableWrapperBase& nestedTable) const; + + virtual NestedTableWrapperBase* table(const Record& record) const; + + virtual QVariant getData(const Record& record, + int subRowIndex, int subColIndex) const; + + virtual void setData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual int getColumnsCount(const Record& record) const; + + virtual int getRowsCount(const Record& record) const; + }; + class RegionSoundListAdapter : public NestedColumnAdapter { public: