1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-21 03:23:54 +00:00
openmw/apps/opencs/model/world/nestedcoladapterimp.cpp
florent.teppe 65cdd489fb create a specific esm reader function for RefID to avoid allocation for string and then again for RefId
Fixed some types

removed useless header

applied clang format

fixed compile tests

fixed clang tidy, and closer to logic before this MR

Removed hardcoded refids

unless there is a returned value we don't use static RefIds
can use == between RefId and hardcoded string

Fix clang format

Fixed a few instances where std::string was used, when only const std::string& was needed

removed unused variable
2022-12-27 19:15:57 +01:00

1288 lines
43 KiB
C++

#include "nestedcoladapterimp.hpp"
#include <map>
#include <stdint.h>
#include <type_traits>
#include <utility>
#include <variant>
#include <apps/opencs/model/world/cell.hpp>
#include <apps/opencs/model/world/nestedtablewrapper.hpp>
#include <apps/opencs/model/world/record.hpp>
#include <components/esm/attr.hpp>
#include <components/esm3/loadcell.hpp>
#include <components/esm3/loadfact.hpp>
#include <components/esm3/loadinfo.hpp>
#include <components/esm3/loadpgrd.hpp>
#include <components/esm3/loadrace.hpp>
#include <components/esm3/loadregn.hpp>
#include <components/esm3/variant.hpp>
#include "info.hpp"
#include "infoselectwrapper.hpp"
#include "pathgrid.hpp"
namespace CSMWorld
{
PathgridPointListAdapter::PathgridPointListAdapter() {}
void PathgridPointListAdapter::addRow(Record<Pathgrid>& record, int position) const
{
Pathgrid pathgrid = record.get();
ESM::Pathgrid::PointList& points = pathgrid.mPoints;
// blank row
ESM::Pathgrid::Point point;
point.mX = 0;
point.mY = 0;
point.mZ = 0;
point.mAutogenerated = 0;
point.mConnectionNum = 0;
point.mUnknown = 0;
points.insert(points.begin() + position, point);
pathgrid.mData.mS2 = pathgrid.mPoints.size();
record.setModified(pathgrid);
}
void PathgridPointListAdapter::removeRow(Record<Pathgrid>& record, int rowToRemove) const
{
Pathgrid pathgrid = record.get();
ESM::Pathgrid::PointList& points = pathgrid.mPoints;
if (rowToRemove < 0 || rowToRemove >= static_cast<int>(points.size()))
throw std::runtime_error("index out of range");
// Do not remove dangling edges, does not work with current undo mechanism
// Do not automatically adjust indices, what would be done with dangling edges?
points.erase(points.begin() + rowToRemove);
pathgrid.mData.mS2 = pathgrid.mPoints.size();
record.setModified(pathgrid);
}
void PathgridPointListAdapter::setTable(Record<Pathgrid>& record, const NestedTableWrapperBase& nestedTable) const
{
Pathgrid pathgrid = record.get();
pathgrid.mPoints = static_cast<const NestedTableWrapper<ESM::Pathgrid::PointList>&>(nestedTable).mNestedTable;
pathgrid.mData.mS2 = pathgrid.mPoints.size();
record.setModified(pathgrid);
}
NestedTableWrapperBase* PathgridPointListAdapter::table(const Record<Pathgrid>& record) const
{
// deleted by dtor of NestedTableStoring
return new NestedTableWrapper<ESM::Pathgrid::PointList>(record.get().mPoints);
}
QVariant PathgridPointListAdapter::getData(const Record<Pathgrid>& record, int subRowIndex, int subColIndex) const
{
ESM::Pathgrid::Point point = record.get().mPoints[subRowIndex];
switch (subColIndex)
{
case 0:
return subRowIndex;
case 1:
return point.mX;
case 2:
return point.mY;
case 3:
return point.mZ;
default:
throw std::runtime_error("Pathgrid point subcolumn index out of range");
}
}
void PathgridPointListAdapter::setData(
Record<Pathgrid>& record, const QVariant& value, int subRowIndex, int subColIndex) const
{
Pathgrid pathgrid = record.get();
ESM::Pathgrid::Point point = pathgrid.mPoints[subRowIndex];
switch (subColIndex)
{
case 0:
return; // return without saving
case 1:
point.mX = value.toInt();
break;
case 2:
point.mY = value.toInt();
break;
case 3:
point.mZ = value.toInt();
break;
default:
throw std::runtime_error("Pathgrid point subcolumn index out of range");
}
pathgrid.mPoints[subRowIndex] = point;
record.setModified(pathgrid);
}
int PathgridPointListAdapter::getColumnsCount(const Record<Pathgrid>& record) const
{
return 4;
}
int PathgridPointListAdapter::getRowsCount(const Record<Pathgrid>& record) const
{
return static_cast<int>(record.get().mPoints.size());
}
PathgridEdgeListAdapter::PathgridEdgeListAdapter() {}
void PathgridEdgeListAdapter::addRow(Record<Pathgrid>& record, int position) const
{
Pathgrid pathgrid = record.get();
ESM::Pathgrid::EdgeList& edges = pathgrid.mEdges;
// blank row
ESM::Pathgrid::Edge edge;
edge.mV0 = 0;
edge.mV1 = 0;
// NOTE: inserting a blank edge does not really make sense, perhaps this should be a
// logic_error exception
//
// Currently the code assumes that the end user to know what he/she is doing.
// e.g. Edges come in pairs, from points a->b and b->a
edges.insert(edges.begin() + position, edge);
record.setModified(pathgrid);
}
void PathgridEdgeListAdapter::removeRow(Record<Pathgrid>& record, int rowToRemove) const
{
Pathgrid pathgrid = record.get();
ESM::Pathgrid::EdgeList& edges = pathgrid.mEdges;
if (rowToRemove < 0 || rowToRemove >= static_cast<int>(edges.size()))
throw std::runtime_error("index out of range");
edges.erase(edges.begin() + rowToRemove);
record.setModified(pathgrid);
}
void PathgridEdgeListAdapter::setTable(Record<Pathgrid>& record, const NestedTableWrapperBase& nestedTable) const
{
Pathgrid pathgrid = record.get();
pathgrid.mEdges = static_cast<const NestedTableWrapper<ESM::Pathgrid::EdgeList>&>(nestedTable).mNestedTable;
record.setModified(pathgrid);
}
NestedTableWrapperBase* PathgridEdgeListAdapter::table(const Record<Pathgrid>& record) const
{
// deleted by dtor of NestedTableStoring
return new NestedTableWrapper<ESM::Pathgrid::EdgeList>(record.get().mEdges);
}
QVariant PathgridEdgeListAdapter::getData(const Record<Pathgrid>& record, int subRowIndex, int subColIndex) const
{
Pathgrid pathgrid = record.get();
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(pathgrid.mEdges.size()))
throw std::runtime_error("index out of range");
ESM::Pathgrid::Edge edge = pathgrid.mEdges[subRowIndex];
switch (subColIndex)
{
case 0:
return subRowIndex;
case 1:
return edge.mV0;
case 2:
return edge.mV1;
default:
throw std::runtime_error("Pathgrid edge subcolumn index out of range");
}
}
void PathgridEdgeListAdapter::setData(
Record<Pathgrid>& record, const QVariant& value, int subRowIndex, int subColIndex) const
{
Pathgrid pathgrid = record.get();
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(pathgrid.mEdges.size()))
throw std::runtime_error("index out of range");
ESM::Pathgrid::Edge edge = pathgrid.mEdges[subRowIndex];
switch (subColIndex)
{
case 0:
return; // return without saving
case 1:
edge.mV0 = value.toInt();
break;
case 2:
edge.mV1 = value.toInt();
break;
default:
throw std::runtime_error("Pathgrid edge subcolumn index out of range");
}
pathgrid.mEdges[subRowIndex] = edge;
record.setModified(pathgrid);
}
int PathgridEdgeListAdapter::getColumnsCount(const Record<Pathgrid>& record) const
{
return 3;
}
int PathgridEdgeListAdapter::getRowsCount(const Record<Pathgrid>& record) const
{
return static_cast<int>(record.get().mEdges.size());
}
FactionReactionsAdapter::FactionReactionsAdapter() {}
void FactionReactionsAdapter::addRow(Record<ESM::Faction>& record, int position) const
{
ESM::Faction faction = record.get();
std::map<ESM::RefId, int>& reactions = faction.mReactions;
// blank row
reactions.insert(std::make_pair(ESM::RefId::sEmpty, 0));
record.setModified(faction);
}
void FactionReactionsAdapter::removeRow(Record<ESM::Faction>& record, int rowToRemove) const
{
ESM::Faction faction = record.get();
std::map<ESM::RefId, int>& reactions = faction.mReactions;
if (rowToRemove < 0 || rowToRemove >= static_cast<int>(reactions.size()))
throw std::runtime_error("index out of range");
// FIXME: how to ensure that the map entries correspond to table indicies?
// WARNING: Assumed that the table view has the same order as std::map
auto iter = reactions.begin();
for (int i = 0; i < rowToRemove; ++i)
++iter;
reactions.erase(iter);
record.setModified(faction);
}
void FactionReactionsAdapter::setTable(
Record<ESM::Faction>& record, const NestedTableWrapperBase& nestedTable) const
{
ESM::Faction faction = record.get();
faction.mReactions
= static_cast<const NestedTableWrapper<std::map<ESM::RefId, int>>&>(nestedTable).mNestedTable;
record.setModified(faction);
}
NestedTableWrapperBase* FactionReactionsAdapter::table(const Record<ESM::Faction>& record) const
{
// deleted by dtor of NestedTableStoring
return new NestedTableWrapper<std::map<ESM::RefId, int>>(record.get().mReactions);
}
QVariant FactionReactionsAdapter::getData(
const Record<ESM::Faction>& record, int subRowIndex, int subColIndex) const
{
ESM::Faction faction = record.get();
std::map<ESM::RefId, int>& reactions = faction.mReactions;
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(reactions.size()))
throw std::runtime_error("index out of range");
// FIXME: how to ensure that the map entries correspond to table indicies?
// WARNING: Assumed that the table view has the same order as std::map
auto iter = reactions.begin();
for (int i = 0; i < subRowIndex; ++i)
++iter;
switch (subColIndex)
{
case 0:
return QString((*iter).first.getRefIdString().c_str());
case 1:
return (*iter).second;
default:
throw std::runtime_error("Faction reactions subcolumn index out of range");
}
}
void FactionReactionsAdapter::setData(
Record<ESM::Faction>& record, const QVariant& value, int subRowIndex, int subColIndex) const
{
ESM::Faction faction = record.get();
std::map<ESM::RefId, int>& reactions = faction.mReactions;
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(reactions.size()))
throw std::runtime_error("index out of range");
// FIXME: how to ensure that the map entries correspond to table indicies?
// WARNING: Assumed that the table view has the same order as std::map
auto iter = reactions.begin();
for (int i = 0; i < subRowIndex; ++i)
++iter;
ESM::RefId factionId = (*iter).first;
int reaction = (*iter).second;
switch (subColIndex)
{
case 0:
{
reactions.erase(iter);
reactions.insert(
std::make_pair(ESM::RefId::stringRefId(value.toString().toUtf8().constData()), reaction));
break;
}
case 1:
{
reactions[factionId] = value.toInt();
break;
}
default:
throw std::runtime_error("Faction reactions subcolumn index out of range");
}
record.setModified(faction);
}
int FactionReactionsAdapter::getColumnsCount(const Record<ESM::Faction>& record) const
{
return 2;
}
int FactionReactionsAdapter::getRowsCount(const Record<ESM::Faction>& record) const
{
return static_cast<int>(record.get().mReactions.size());
}
RegionSoundListAdapter::RegionSoundListAdapter() {}
void RegionSoundListAdapter::addRow(Record<ESM::Region>& record, int position) const
{
ESM::Region region = record.get();
std::vector<ESM::Region::SoundRef>& soundList = region.mSoundList;
// blank row
ESM::Region::SoundRef soundRef;
soundRef.mSound = ESM::RefId::sEmpty;
soundRef.mChance = 0;
soundList.insert(soundList.begin() + position, soundRef);
record.setModified(region);
}
void RegionSoundListAdapter::removeRow(Record<ESM::Region>& record, int rowToRemove) const
{
ESM::Region region = record.get();
std::vector<ESM::Region::SoundRef>& soundList = region.mSoundList;
if (rowToRemove < 0 || rowToRemove >= static_cast<int>(soundList.size()))
throw std::runtime_error("index out of range");
soundList.erase(soundList.begin() + rowToRemove);
record.setModified(region);
}
void RegionSoundListAdapter::setTable(Record<ESM::Region>& record, const NestedTableWrapperBase& nestedTable) const
{
ESM::Region region = record.get();
region.mSoundList
= static_cast<const NestedTableWrapper<std::vector<ESM::Region::SoundRef>>&>(nestedTable).mNestedTable;
record.setModified(region);
}
NestedTableWrapperBase* RegionSoundListAdapter::table(const Record<ESM::Region>& record) const
{
// deleted by dtor of NestedTableStoring
return new NestedTableWrapper<std::vector<ESM::Region::SoundRef>>(record.get().mSoundList);
}
QVariant RegionSoundListAdapter::getData(const Record<ESM::Region>& record, int subRowIndex, int subColIndex) const
{
ESM::Region region = record.get();
std::vector<ESM::Region::SoundRef>& soundList = region.mSoundList;
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(soundList.size()))
throw std::runtime_error("index out of range");
ESM::Region::SoundRef soundRef = soundList[subRowIndex];
switch (subColIndex)
{
case 0:
return QString(soundRef.mSound.getRefIdString().c_str());
case 1:
return soundRef.mChance;
default:
throw std::runtime_error("Region sounds subcolumn index out of range");
}
}
void RegionSoundListAdapter::setData(
Record<ESM::Region>& record, const QVariant& value, int subRowIndex, int subColIndex) const
{
ESM::Region region = record.get();
std::vector<ESM::Region::SoundRef>& soundList = region.mSoundList;
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(soundList.size()))
throw std::runtime_error("index out of range");
ESM::Region::SoundRef soundRef = soundList[subRowIndex];
switch (subColIndex)
{
case 0:
soundRef.mSound = ESM::RefId::stringRefId(value.toString().toUtf8().constData());
break;
case 1:
soundRef.mChance = static_cast<unsigned char>(value.toInt());
break;
default:
throw std::runtime_error("Region sounds subcolumn index out of range");
}
region.mSoundList[subRowIndex] = soundRef;
record.setModified(region);
}
int RegionSoundListAdapter::getColumnsCount(const Record<ESM::Region>& record) const
{
return 2;
}
int RegionSoundListAdapter::getRowsCount(const Record<ESM::Region>& record) const
{
return static_cast<int>(record.get().mSoundList.size());
}
InfoListAdapter::InfoListAdapter() {}
void InfoListAdapter::addRow(Record<Info>& record, int position) const
{
throw std::logic_error("cannot add a row to a fixed table");
}
void InfoListAdapter::removeRow(Record<Info>& record, int rowToRemove) const
{
throw std::logic_error("cannot remove a row to a fixed table");
}
void InfoListAdapter::setTable(Record<Info>& record, const NestedTableWrapperBase& nestedTable) const
{
throw std::logic_error("table operation not supported");
}
NestedTableWrapperBase* InfoListAdapter::table(const Record<Info>& record) const
{
throw std::logic_error("table operation not supported");
}
QVariant InfoListAdapter::getData(const Record<Info>& record, int subRowIndex, int subColIndex) const
{
Info info = record.get();
if (subColIndex == 0)
return QString(info.mResultScript.c_str());
else
throw std::runtime_error("Trying to access non-existing column in the nested table!");
}
void InfoListAdapter::setData(Record<Info>& record, const QVariant& value, int subRowIndex, int subColIndex) const
{
Info info = record.get();
if (subColIndex == 0)
info.mResultScript = value.toString().toStdString();
else
throw std::runtime_error("Trying to access non-existing column in the nested table!");
record.setModified(info);
}
int InfoListAdapter::getColumnsCount(const Record<Info>& record) const
{
return 1;
}
int InfoListAdapter::getRowsCount(const Record<Info>& record) const
{
return 1; // fixed at size 1
}
InfoConditionAdapter::InfoConditionAdapter() {}
void InfoConditionAdapter::addRow(Record<Info>& record, int position) const
{
Info info = record.get();
std::vector<ESM::DialInfo::SelectStruct>& conditions = info.mSelects;
// default row
ESM::DialInfo::SelectStruct condStruct;
condStruct.mSelectRule = "01000";
condStruct.mValue = ESM::Variant();
condStruct.mValue.setType(ESM::VT_Int);
conditions.insert(conditions.begin() + position, condStruct);
record.setModified(info);
}
void InfoConditionAdapter::removeRow(Record<Info>& record, int rowToRemove) const
{
Info info = record.get();
std::vector<ESM::DialInfo::SelectStruct>& conditions = info.mSelects;
if (rowToRemove < 0 || rowToRemove >= static_cast<int>(conditions.size()))
throw std::runtime_error("index out of range");
conditions.erase(conditions.begin() + rowToRemove);
record.setModified(info);
}
void InfoConditionAdapter::setTable(Record<Info>& record, const NestedTableWrapperBase& nestedTable) const
{
Info info = record.get();
info.mSelects = static_cast<const NestedTableWrapper<std::vector<ESM::DialInfo::SelectStruct>>&>(nestedTable)
.mNestedTable;
record.setModified(info);
}
NestedTableWrapperBase* InfoConditionAdapter::table(const Record<Info>& record) const
{
// deleted by dtor of NestedTableStoring
return new NestedTableWrapper<std::vector<ESM::DialInfo::SelectStruct>>(record.get().mSelects);
}
QVariant InfoConditionAdapter::getData(const Record<Info>& record, int subRowIndex, int subColIndex) const
{
Info info = record.get();
std::vector<ESM::DialInfo::SelectStruct>& conditions = info.mSelects;
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(conditions.size()))
throw std::runtime_error("index out of range");
ConstInfoSelectWrapper infoSelectWrapper(conditions[subRowIndex]);
switch (subColIndex)
{
case 0:
{
return infoSelectWrapper.getFunctionName();
}
case 1:
{
if (infoSelectWrapper.hasVariable())
return QString(infoSelectWrapper.getVariableName().c_str());
else
return "";
}
case 2:
{
return infoSelectWrapper.getRelationType();
}
case 3:
{
switch (infoSelectWrapper.getVariant().getType())
{
case ESM::VT_Int:
{
return infoSelectWrapper.getVariant().getInteger();
}
case ESM::VT_Float:
{
return infoSelectWrapper.getVariant().getFloat();
}
default:
return QVariant();
}
}
default:
throw std::runtime_error("Info condition subcolumn index out of range");
}
}
void InfoConditionAdapter::setData(
Record<Info>& record, const QVariant& value, int subRowIndex, int subColIndex) const
{
Info info = record.get();
std::vector<ESM::DialInfo::SelectStruct>& conditions = info.mSelects;
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(conditions.size()))
throw std::runtime_error("index out of range");
InfoSelectWrapper infoSelectWrapper(conditions[subRowIndex]);
bool conversionResult = false;
switch (subColIndex)
{
case 0: // Function
{
infoSelectWrapper.setFunctionName(static_cast<ConstInfoSelectWrapper::FunctionName>(value.toInt()));
if (infoSelectWrapper.getComparisonType() != ConstInfoSelectWrapper::Comparison_Numeric
&& infoSelectWrapper.getVariant().getType() != ESM::VT_Int)
{
infoSelectWrapper.getVariant().setType(ESM::VT_Int);
}
infoSelectWrapper.update();
break;
}
case 1: // Variable
{
infoSelectWrapper.setVariableName(value.toString().toUtf8().constData());
infoSelectWrapper.update();
break;
}
case 2: // Relation
{
infoSelectWrapper.setRelationType(static_cast<ConstInfoSelectWrapper::RelationType>(value.toInt()));
infoSelectWrapper.update();
break;
}
case 3: // Value
{
switch (infoSelectWrapper.getComparisonType())
{
case ConstInfoSelectWrapper::Comparison_Numeric:
{
// QVariant seems to have issues converting 0
if ((value.toInt(&conversionResult) && conversionResult) || value.toString().compare("0") == 0)
{
infoSelectWrapper.getVariant().setType(ESM::VT_Int);
infoSelectWrapper.getVariant().setInteger(value.toInt());
}
else if (value.toFloat(&conversionResult) && conversionResult)
{
infoSelectWrapper.getVariant().setType(ESM::VT_Float);
infoSelectWrapper.getVariant().setFloat(value.toFloat());
}
break;
}
case ConstInfoSelectWrapper::Comparison_Boolean:
case ConstInfoSelectWrapper::Comparison_Integer:
{
if ((value.toInt(&conversionResult) && conversionResult) || value.toString().compare("0") == 0)
{
infoSelectWrapper.getVariant().setType(ESM::VT_Int);
infoSelectWrapper.getVariant().setInteger(value.toInt());
}
break;
}
default:
break;
}
break;
}
default:
throw std::runtime_error("Info condition subcolumn index out of range");
}
record.setModified(info);
}
int InfoConditionAdapter::getColumnsCount(const Record<Info>& record) const
{
return 4;
}
int InfoConditionAdapter::getRowsCount(const Record<Info>& record) const
{
return static_cast<int>(record.get().mSelects.size());
}
RaceAttributeAdapter::RaceAttributeAdapter() {}
void RaceAttributeAdapter::addRow(Record<ESM::Race>& record, int position) const
{
// Do nothing, this table cannot be changed by the user
}
void RaceAttributeAdapter::removeRow(Record<ESM::Race>& record, int rowToRemove) const
{
// Do nothing, this table cannot be changed by the user
}
void RaceAttributeAdapter::setTable(Record<ESM::Race>& record, const NestedTableWrapperBase& nestedTable) const
{
ESM::Race race = record.get();
race.mData = static_cast<const NestedTableWrapper<std::vector<ESM::Race::RADTstruct>>&>(nestedTable)
.mNestedTable.at(0);
record.setModified(race);
}
NestedTableWrapperBase* RaceAttributeAdapter::table(const Record<ESM::Race>& record) const
{
std::vector<ESM::Race::RADTstruct> wrap;
wrap.push_back(record.get().mData);
// deleted by dtor of NestedTableStoring
return new NestedTableWrapper<std::vector<ESM::Race::RADTstruct>>(wrap);
}
QVariant RaceAttributeAdapter::getData(const Record<ESM::Race>& record, int subRowIndex, int subColIndex) const
{
ESM::Race race = record.get();
if (subRowIndex < 0 || subRowIndex >= ESM::Attribute::Length)
throw std::runtime_error("index out of range");
switch (subColIndex)
{
case 0:
return subRowIndex;
case 1:
return race.mData.mAttributeValues[subRowIndex].mMale;
case 2:
return race.mData.mAttributeValues[subRowIndex].mFemale;
default:
throw std::runtime_error("Race Attribute subcolumn index out of range");
}
}
void RaceAttributeAdapter::setData(
Record<ESM::Race>& record, const QVariant& value, int subRowIndex, int subColIndex) const
{
ESM::Race race = record.get();
if (subRowIndex < 0 || subRowIndex >= ESM::Attribute::Length)
throw std::runtime_error("index out of range");
switch (subColIndex)
{
case 0:
return; // throw an exception here?
case 1:
race.mData.mAttributeValues[subRowIndex].mMale = value.toInt();
break;
case 2:
race.mData.mAttributeValues[subRowIndex].mFemale = value.toInt();
break;
default:
throw std::runtime_error("Race Attribute subcolumn index out of range");
}
record.setModified(race);
}
int RaceAttributeAdapter::getColumnsCount(const Record<ESM::Race>& record) const
{
return 3; // attrib, male, female
}
int RaceAttributeAdapter::getRowsCount(const Record<ESM::Race>& record) const
{
return ESM::Attribute::Length; // there are 8 attributes
}
RaceSkillsBonusAdapter::RaceSkillsBonusAdapter() {}
void RaceSkillsBonusAdapter::addRow(Record<ESM::Race>& record, int position) const
{
// Do nothing, this table cannot be changed by the user
}
void RaceSkillsBonusAdapter::removeRow(Record<ESM::Race>& record, int rowToRemove) const
{
// Do nothing, this table cannot be changed by the user
}
void RaceSkillsBonusAdapter::setTable(Record<ESM::Race>& record, const NestedTableWrapperBase& nestedTable) const
{
ESM::Race race = record.get();
race.mData = static_cast<const NestedTableWrapper<std::vector<ESM::Race::RADTstruct>>&>(nestedTable)
.mNestedTable.at(0);
record.setModified(race);
}
NestedTableWrapperBase* RaceSkillsBonusAdapter::table(const Record<ESM::Race>& record) const
{
std::vector<ESM::Race::RADTstruct> wrap;
wrap.push_back(record.get().mData);
// deleted by dtor of NestedTableStoring
return new NestedTableWrapper<std::vector<ESM::Race::RADTstruct>>(wrap);
}
QVariant RaceSkillsBonusAdapter::getData(const Record<ESM::Race>& record, int subRowIndex, int subColIndex) const
{
ESM::Race race = record.get();
if (subRowIndex < 0
|| subRowIndex >= static_cast<int>(sizeof(race.mData.mBonus) / sizeof(race.mData.mBonus[0])))
throw std::runtime_error("index out of range");
switch (subColIndex)
{
case 0:
return race.mData.mBonus[subRowIndex].mSkill; // can be -1
case 1:
return race.mData.mBonus[subRowIndex].mBonus;
default:
throw std::runtime_error("Race skill bonus subcolumn index out of range");
}
}
void RaceSkillsBonusAdapter::setData(
Record<ESM::Race>& record, const QVariant& value, int subRowIndex, int subColIndex) const
{
ESM::Race race = record.get();
if (subRowIndex < 0
|| subRowIndex >= static_cast<int>(sizeof(race.mData.mBonus) / sizeof(race.mData.mBonus[0])))
throw std::runtime_error("index out of range");
switch (subColIndex)
{
case 0:
race.mData.mBonus[subRowIndex].mSkill = value.toInt();
break; // can be -1
case 1:
race.mData.mBonus[subRowIndex].mBonus = value.toInt();
break;
default:
throw std::runtime_error("Race skill bonus subcolumn index out of range");
}
record.setModified(race);
}
int RaceSkillsBonusAdapter::getColumnsCount(const Record<ESM::Race>& record) const
{
return 2; // skill, bonus
}
int RaceSkillsBonusAdapter::getRowsCount(const Record<ESM::Race>& record) const
{
// there are 7 skill bonuses
return static_cast<int>(sizeof(record.get().mData.mBonus) / sizeof(record.get().mData.mBonus[0]));
}
CellListAdapter::CellListAdapter() {}
void CellListAdapter::addRow(Record<CSMWorld::Cell>& record, int position) const
{
throw std::logic_error("cannot add a row to a fixed table");
}
void CellListAdapter::removeRow(Record<CSMWorld::Cell>& record, int rowToRemove) const
{
throw std::logic_error("cannot remove a row to a fixed table");
}
void CellListAdapter::setTable(Record<CSMWorld::Cell>& record, const NestedTableWrapperBase& nestedTable) const
{
throw std::logic_error("table operation not supported");
}
NestedTableWrapperBase* CellListAdapter::table(const Record<CSMWorld::Cell>& record) const
{
throw std::logic_error("table operation not supported");
}
QVariant CellListAdapter::getData(const Record<CSMWorld::Cell>& record, int subRowIndex, int subColIndex) const
{
CSMWorld::Cell cell = record.get();
bool isInterior = (cell.mData.mFlags & ESM::Cell::Interior) != 0;
bool behaveLikeExterior = (cell.mData.mFlags & ESM::Cell::QuasiEx) != 0;
bool interiorWater = (cell.mData.mFlags & ESM::Cell::HasWater) != 0;
switch (subColIndex)
{
case 0:
return isInterior;
// While the ambient information is not necessarily valid if the subrecord wasn't loaded,
// the user should still be allowed to edit it
case 1:
return (isInterior && !behaveLikeExterior) ? cell.mAmbi.mAmbient : QVariant(QVariant::UserType);
case 2:
return (isInterior && !behaveLikeExterior) ? cell.mAmbi.mSunlight : QVariant(QVariant::UserType);
case 3:
return (isInterior && !behaveLikeExterior) ? cell.mAmbi.mFog : QVariant(QVariant::UserType);
case 4:
return (isInterior && !behaveLikeExterior) ? cell.mAmbi.mFogDensity : QVariant(QVariant::UserType);
case 5:
{
if (isInterior && interiorWater)
return cell.mWater;
else
return QVariant(QVariant::UserType);
}
case 6:
return isInterior ? QVariant(QVariant::UserType) : cell.mMapColor; // TODO: how to select?
// case 7: return isInterior ?
// behaveLikeExterior : QVariant(QVariant::UserType);
default:
throw std::runtime_error("Cell subcolumn index out of range");
}
}
void CellListAdapter::setData(
Record<CSMWorld::Cell>& record, const QVariant& value, int subRowIndex, int subColIndex) const
{
CSMWorld::Cell cell = record.get();
bool isInterior = (cell.mData.mFlags & ESM::Cell::Interior) != 0;
bool behaveLikeExterior = (cell.mData.mFlags & ESM::Cell::QuasiEx) != 0;
bool interiorWater = (cell.mData.mFlags & ESM::Cell::HasWater) != 0;
switch (subColIndex)
{
case 0:
{
if (value.toBool())
cell.mData.mFlags |= ESM::Cell::Interior;
else
cell.mData.mFlags &= ~ESM::Cell::Interior;
break;
}
case 1:
{
if (isInterior && !behaveLikeExterior)
{
cell.mAmbi.mAmbient = static_cast<int32_t>(value.toInt());
cell.setHasAmbient(true);
}
else
return; // return without saving
break;
}
case 2:
{
if (isInterior && !behaveLikeExterior)
{
cell.mAmbi.mSunlight = static_cast<int32_t>(value.toInt());
cell.setHasAmbient(true);
}
else
return; // return without saving
break;
}
case 3:
{
if (isInterior && !behaveLikeExterior)
{
cell.mAmbi.mFog = static_cast<int32_t>(value.toInt());
cell.setHasAmbient(true);
}
else
return; // return without saving
break;
}
case 4:
{
if (isInterior && !behaveLikeExterior)
{
cell.mAmbi.mFogDensity = value.toFloat();
cell.setHasAmbient(true);
}
else
return; // return without saving
break;
}
case 5:
{
if (isInterior && interiorWater)
cell.mWater = value.toFloat();
else
return; // return without saving
break;
}
case 6:
{
if (!isInterior)
cell.mMapColor = value.toInt();
else
return; // return without saving
break;
}
#if 0
// redundant since this flag is shown in the main table as "Interior Sky"
// keep here for documenting the logic based on vanilla
case 7:
{
if (isInterior)
{
if (value.toBool())
cell.mData.mFlags |= ESM::Cell::QuasiEx;
else
cell.mData.mFlags &= ~ESM::Cell::QuasiEx;
}
else
return; // return without saving
break;
}
#endif
default:
throw std::runtime_error("Cell subcolumn index out of range");
}
record.setModified(cell);
}
int CellListAdapter::getColumnsCount(const Record<CSMWorld::Cell>& record) const
{
return 7;
}
int CellListAdapter::getRowsCount(const Record<CSMWorld::Cell>& record) const
{
return 1; // fixed at size 1
}
RegionWeatherAdapter::RegionWeatherAdapter() {}
void RegionWeatherAdapter::addRow(Record<ESM::Region>& record, int position) const
{
throw std::logic_error("cannot add a row to a fixed table");
}
void RegionWeatherAdapter::removeRow(Record<ESM::Region>& record, int rowToRemove) const
{
throw std::logic_error("cannot remove a row from a fixed table");
}
void RegionWeatherAdapter::setTable(Record<ESM::Region>& record, const NestedTableWrapperBase& nestedTable) const
{
throw std::logic_error("table operation not supported");
}
NestedTableWrapperBase* RegionWeatherAdapter::table(const Record<ESM::Region>& record) const
{
throw std::logic_error("table operation not supported");
}
QVariant RegionWeatherAdapter::getData(const Record<ESM::Region>& record, int subRowIndex, int subColIndex) const
{
const char* WeatherNames[]
= { "Clear", "Cloudy", "Fog", "Overcast", "Rain", "Thunder", "Ash", "Blight", "Snow", "Blizzard" };
const ESM::Region& region = record.get();
if (subColIndex == 0 && subRowIndex >= 0 && subRowIndex < 10)
{
return WeatherNames[subRowIndex];
}
else if (subColIndex == 1)
{
switch (subRowIndex)
{
case 0:
return region.mData.mClear;
case 1:
return region.mData.mCloudy;
case 2:
return region.mData.mFoggy;
case 3:
return region.mData.mOvercast;
case 4:
return region.mData.mRain;
case 5:
return region.mData.mThunder;
case 6:
return region.mData.mAsh;
case 7:
return region.mData.mBlight;
case 8:
return region.mData.mSnow;
case 9:
return region.mData.mBlizzard;
default:
break;
}
}
throw std::runtime_error("index out of range");
}
void RegionWeatherAdapter::setData(
Record<ESM::Region>& record, const QVariant& value, int subRowIndex, int subColIndex) const
{
ESM::Region region = record.get();
unsigned char chance = static_cast<unsigned char>(value.toInt());
if (subColIndex == 1)
{
switch (subRowIndex)
{
case 0:
region.mData.mClear = chance;
break;
case 1:
region.mData.mCloudy = chance;
break;
case 2:
region.mData.mFoggy = chance;
break;
case 3:
region.mData.mOvercast = chance;
break;
case 4:
region.mData.mRain = chance;
break;
case 5:
region.mData.mThunder = chance;
break;
case 6:
region.mData.mAsh = chance;
break;
case 7:
region.mData.mBlight = chance;
break;
case 8:
region.mData.mSnow = chance;
break;
case 9:
region.mData.mBlizzard = chance;
break;
default:
throw std::runtime_error("index out of range");
}
record.setModified(region);
}
}
int RegionWeatherAdapter::getColumnsCount(const Record<ESM::Region>& record) const
{
return 2;
}
int RegionWeatherAdapter::getRowsCount(const Record<ESM::Region>& record) const
{
return 10;
}
FactionRanksAdapter::FactionRanksAdapter() {}
void FactionRanksAdapter::addRow(Record<ESM::Faction>& record, int position) const
{
throw std::logic_error("cannot add a row to a fixed table");
}
void FactionRanksAdapter::removeRow(Record<ESM::Faction>& record, int rowToRemove) const
{
throw std::logic_error("cannot remove a row from a fixed table");
}
void FactionRanksAdapter::setTable(Record<ESM::Faction>& record, const NestedTableWrapperBase& nestedTable) const
{
throw std::logic_error("table operation not supported");
}
NestedTableWrapperBase* FactionRanksAdapter::table(const Record<ESM::Faction>& record) const
{
throw std::logic_error("table operation not supported");
}
QVariant FactionRanksAdapter::getData(const Record<ESM::Faction>& record, int subRowIndex, int subColIndex) const
{
ESM::Faction faction = record.get();
if (subRowIndex < 0
|| subRowIndex >= static_cast<int>(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.mPrimarySkill;
case 4:
return rankData.mFavouredSkill;
case 5:
return rankData.mFactReaction;
default:
throw std::runtime_error("Rank subcolumn index out of range");
}
}
void FactionRanksAdapter::setData(
Record<ESM::Faction>& record, const QVariant& value, int subRowIndex, int subColIndex) const
{
ESM::Faction faction = record.get();
if (subRowIndex < 0
|| subRowIndex >= static_cast<int>(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.mPrimarySkill = value.toInt();
break;
case 4:
rankData.mFavouredSkill = 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<ESM::Faction>& record) const
{
return 6;
}
int FactionRanksAdapter::getRowsCount(const Record<ESM::Faction>& record) const
{
return 10;
}
}