1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-15 21:19:57 +00:00
openmw-tes3mp/apps/opencs/model/world/nestedcoladapterimp.cpp

944 lines
37 KiB
C++

#include "nestedcoladapterimp.hpp"
#include <components/esm/loadregn.hpp>
#include <components/esm/loadfact.hpp>
#include "idcollection.hpp"
#include "pathgrid.hpp"
#include "info.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;
// inserting a point should trigger re-indexing of the edges
//
// FIXME: does not auto refresh edges table view
std::vector<ESM::Pathgrid::Edge>::iterator iter = pathgrid.mEdges.begin();
for (;iter != pathgrid.mEdges.end(); ++iter)
{
if ((*iter).mV0 >= position)
(*iter).mV0++;
if ((*iter).mV1 >= position)
(*iter).mV1++;
}
points.insert(points.begin()+position, point);
pathgrid.mData.mS2 += 1; // increment the number of points
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");
// deleting a point should trigger re-indexing of the edges
// dangling edges are not allowed and hence removed
//
// FIXME: does not auto refresh edges table view
std::vector<ESM::Pathgrid::Edge>::iterator iter = pathgrid.mEdges.begin();
for (; iter != pathgrid.mEdges.end();)
{
if (((*iter).mV0 == rowToRemove) || ((*iter).mV1 == rowToRemove))
iter = pathgrid.mEdges.erase(iter);
else
{
if ((*iter).mV0 > rowToRemove)
(*iter).mV0--;
if ((*iter).mV1 > rowToRemove)
(*iter).mV1--;
++iter;
}
}
points.erase(points.begin()+rowToRemove);
pathgrid.mData.mS2 -= 1; // decrement the number of points
record.setModified (pathgrid);
}
void PathgridPointListAdapter::setTable(Record<Pathgrid>& record,
const NestedTableWrapperBase& nestedTable) const
{
Pathgrid pathgrid = record.get();
pathgrid.mPoints =
static_cast<const PathgridPointsWrap &>(nestedTable).mRecord.mPoints;
pathgrid.mData.mS2 =
static_cast<const PathgridPointsWrap &>(nestedTable).mRecord.mData.mS2;
// also update edges in case points were added/removed
pathgrid.mEdges =
static_cast<const PathgridPointsWrap &>(nestedTable).mRecord.mEdges;
record.setModified (pathgrid);
}
NestedTableWrapperBase* PathgridPointListAdapter::table(const Record<Pathgrid>& record) const
{
// deleted by dtor of NestedTableStoring
return new PathgridPointsWrap(record.get());
}
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 () {}
// ToDo: seems to be auto-sorted in the dialog table display after insertion
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");
}
}
// ToDo: detect duplicates in mEdges
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<std::string, int>& reactions = faction.mReactions;
// blank row
reactions.insert(std::make_pair("", 0));
record.setModified (faction);
}
void FactionReactionsAdapter::removeRow(Record<ESM::Faction>& record, int rowToRemove) const
{
ESM::Faction faction = record.get();
std::map<std::string, 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
std::map<std::string, int>::iterator 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<std::string, 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<std::string, int> >(record.get().mReactions);
}
QVariant FactionReactionsAdapter::getData(const Record<ESM::Faction>& record,
int subRowIndex, int subColIndex) const
{
ESM::Faction faction = record.get();
std::map<std::string, 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
std::map<std::string, int>::const_iterator iter = reactions.begin();
for(int i = 0; i < subRowIndex; ++i)
iter++;
switch (subColIndex)
{
case 0: return QString((*iter).first.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<std::string, 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
std::map<std::string, int>::iterator iter = reactions.begin();
for(int i = 0; i < subRowIndex; ++i)
iter++;
std::string factionId = (*iter).first;
int reaction = (*iter).second;
switch (subColIndex)
{
case 0:
{
reactions.erase(iter);
reactions.insert(std::make_pair(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.assign("");
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.toString().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.assign(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 add 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
}
// ESM::DialInfo::SelectStruct.mSelectRule
// 012345...
// ^^^ ^^
// ||| ||
// ||| |+------------- condition variable string
// ||| +-------------- comparison type, ['0'..'5']; e.g. !=, <, >=, etc
// ||+---------------- function index (encoded, where function == '1')
// |+----------------- function, ['1'..'C']; e.g. Global, Local, Not ID, etc
// +------------------ unknown
//
InfoConditionAdapter::InfoConditionAdapter () {}
void InfoConditionAdapter::addRow(Record<Info>& record, int position) const
{
Info info = record.get();
std::vector<ESM::DialInfo::SelectStruct>& conditions = info.mSelects;
// blank row
ESM::DialInfo::SelectStruct condStruct;
condStruct.mSelectRule = "00000";
condStruct.mValue = ESM::Variant();
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);
}
// See the mappings in MWDialogue::SelectWrapper::getArgument
// from ESM::Attribute, ESM::Skill and MWMechanics::CreatureStats (for AI)
static const std::map<const std::string, const std::string> sEncToInfoFunc =
{
std::make_pair( "00", "Rank Low" ),
std::make_pair( "01", "Rank High" ),
std::make_pair( "02", "Rank Requirement" ),
std::make_pair( "03", "Reputation" ),
std::make_pair( "04", "Health Percent" ),
std::make_pair( "05", "PC Reputation" ),
std::make_pair( "06", "PC Level" ),
std::make_pair( "07", "PC Health Percent" ),
std::make_pair( "08", "PC Magicka" ), // dynamic stat
std::make_pair( "09", "PC Fatigue" ), // dynamic stat
std::make_pair( "10", "PC Strength" ), // attrib
std::make_pair( "11", "PC Block" ),
std::make_pair( "12", "PC Armoror" ),
std::make_pair( "13", "PC Medium Armor" ),
std::make_pair( "14", "PC Heavy Armor" ),
std::make_pair( "15", "PC Blunt Weapon" ),
std::make_pair( "16", "PC Long Blade" ),
std::make_pair( "17", "PC Axe" ),
std::make_pair( "18", "PC Spear" ),
std::make_pair( "19", "PC Athletics" ),
std::make_pair( "20", "PC Enchant" ),
std::make_pair( "21", "PC Destruction" ),
std::make_pair( "22", "PC Alteration" ),
std::make_pair( "23", "PC Illusion" ),
std::make_pair( "24", "PC Conjuration" ),
std::make_pair( "25", "PC Mysticism" ),
std::make_pair( "26", "PC Restoration" ),
std::make_pair( "27", "PC Alchemy" ),
std::make_pair( "28", "PC Unarmored" ),
std::make_pair( "29", "PC Security" ),
std::make_pair( "30", "PC Sneak" ),
std::make_pair( "31", "PC Acrobatics" ),
std::make_pair( "32", "PC Light Armor" ),
std::make_pair( "33", "PC Short Blade" ),
std::make_pair( "34", "PC Marksman" ),
std::make_pair( "35", "PC Merchantile" ),
std::make_pair( "36", "PC Speechcraft" ),
std::make_pair( "37", "PC Hand To Hand" ),
std::make_pair( "38", "PC Sex" ),
std::make_pair( "39", "PC Expelled" ),
std::make_pair( "40", "PC Common Disease" ),
std::make_pair( "41", "PC Blight Disease" ),
std::make_pair( "42", "PC Clothing Modifier" ),
std::make_pair( "43", "PC Crime Level" ),
std::make_pair( "44", "Same Sex" ),
std::make_pair( "45", "Same Race" ),
std::make_pair( "46", "Same Faction" ),
std::make_pair( "47", "Faction Rank Difference" ),
std::make_pair( "48", "Detected" ),
std::make_pair( "49", "Alarmed" ),
std::make_pair( "50", "Choice" ),
std::make_pair( "51", "PC Intelligence" ), // attrib
std::make_pair( "52", "PC Willpower" ), // attrib
std::make_pair( "53", "PC Agility" ), // attrib
std::make_pair( "54", "PC Speed" ), // attrib
std::make_pair( "55", "PC Endurance" ), // attrib
std::make_pair( "56", "PC Personality" ), // attrib
std::make_pair( "57", "PC Luck" ), // attrib
std::make_pair( "58", "PC Corpus" ),
std::make_pair( "59", "Weather" ),
std::make_pair( "60", "PC Vampire" ),
std::make_pair( "61", "Level" ),
std::make_pair( "62", "Attacked" ),
std::make_pair( "63", "Talked To PC" ),
std::make_pair( "64", "PC Health" ), // dynamic stat
std::make_pair( "65", "Creature Target" ),
std::make_pair( "66", "Friend Hit" ),
std::make_pair( "67", "Fight" ), // AI
std::make_pair( "68", "Hello" ), // AI
std::make_pair( "69", "Alarm" ), // AI
std::make_pair( "70", "Flee" ), // AI
std::make_pair( "71", "Should Attack" ),
std::make_pair( "72", "Werewolf" ),
std::make_pair( "73", "PC Werewolf Kills" )
};
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");
switch (subColIndex)
{
case 0:
{
char condType = conditions[subRowIndex].mSelectRule[1];
switch (condType)
{
case '1': return 1; // Function
case '2': return 2; // Global
case '3': return 3; // Local
case '4': return 4; // Journal
case '5': return 5; // Item
case '6': return 6; // Dead
case '7': return 7; // Not ID
case '8': return 8; // Not Factio
case '9': return 9; // Not Class
case 'A': return 10; // Not Race
case 'B': return 11; // Not Cell
case 'C': return 12; // Not Local
default: return QVariant(); // TODO: log an error?
}
}
case 1:
{
if (conditions[subRowIndex].mSelectRule[1] == '1')
{
// throws an exception if the encoding is not found
return sEncToInfoFunc.at(conditions[subRowIndex].mSelectRule.substr(2, 2)).c_str();
}
else
return QString(conditions[subRowIndex].mSelectRule.substr(5).c_str());
}
case 2:
{
char compType = conditions[subRowIndex].mSelectRule[4];
switch (compType)
{
case '0': return 3; // =
case '1': return 0; // !=
case '2': return 4; // >
case '3': return 5; // >=
case '4': return 1; // <
case '5': return 2; // <=
default: return QVariant(); // TODO: log an error?
}
}
case 3:
{
switch (conditions[subRowIndex].mValue.getType())
{
case ESM::VT_String:
{
return QString::fromUtf8 (conditions[subRowIndex].mValue.getString().c_str());
}
case ESM::VT_Int:
case ESM::VT_Short:
case ESM::VT_Long:
{
return conditions[subRowIndex].mValue.getInteger();
}
case ESM::VT_Float:
{
return conditions[subRowIndex].mValue.getFloat();
}
default: return QVariant();
}
}
default: throw std::runtime_error("Info condition subcolumn index out of range");
}
}
static const std::map<const std::string, const std::string> sInfoFuncToEnc =
{
std::make_pair( "Alarm", "69" ), // AI
std::make_pair( "Alarmed", "49" ),
std::make_pair( "Attacked", "62" ),
std::make_pair( "Choice", "50" ),
std::make_pair( "Creature Target", "65" ),
std::make_pair( "Detected", "48" ),
std::make_pair( "Faction Rank Difference", "47" ),
std::make_pair( "Fight", "67" ), // AI
std::make_pair( "Flee", "70" ), // AI
std::make_pair( "Friend Hit", "66" ),
std::make_pair( "Health Percent", "04" ),
std::make_pair( "Hello", "68" ), // AI
std::make_pair( "Level", "61" ),
std::make_pair( "PC Acrobatics", "31" ),
std::make_pair( "PC Agility", "53" ), // attrib
std::make_pair( "PC Alchemy", "27" ),
std::make_pair( "PC Alteration", "22" ),
std::make_pair( "PC Armoror", "12" ),
std::make_pair( "PC Athletics", "19" ),
std::make_pair( "PC Axe", "17" ),
std::make_pair( "PC Blight Disease", "41" ),
std::make_pair( "PC Block", "11" ),
std::make_pair( "PC Blunt Weapon", "15" ),
std::make_pair( "PC Clothing Modifier", "42" ),
std::make_pair( "PC Common Disease", "40" ),
std::make_pair( "PC Conjuration", "24" ),
std::make_pair( "PC Corpus", "58" ),
std::make_pair( "PC Crime Level", "43" ),
std::make_pair( "PC Destruction", "21" ),
std::make_pair( "PC Enchant", "20" ),
std::make_pair( "PC Endurance", "55" ), // attrib
std::make_pair( "PC Expelled", "39" ),
std::make_pair( "PC Fatigue", "09" ), // dynamic stat
std::make_pair( "PC Hand To Hand", "37" ),
std::make_pair( "PC Health", "64" ), // dynamic stat
std::make_pair( "PC Health Percent", "07" ),
std::make_pair( "PC Heavy Armor", "14" ),
std::make_pair( "PC Illusion", "23" ),
std::make_pair( "PC Intelligence", "51" ), // attrib
std::make_pair( "PC Level", "06" ),
std::make_pair( "PC Light Armor", "32" ),
std::make_pair( "PC Long Blade", "16" ),
std::make_pair( "PC Luck", "57" ), // attrib
std::make_pair( "PC Magicka", "08" ), // dynamic stat
std::make_pair( "PC Marksman", "34" ),
std::make_pair( "PC Medium Armor", "13" ),
std::make_pair( "PC Merchantile", "35" ),
std::make_pair( "PC Mysticism", "25" ),
std::make_pair( "PC Personality", "56" ), // attrib
std::make_pair( "PC Reputation", "05" ),
std::make_pair( "PC Restoration", "26" ),
std::make_pair( "PC Security", "29" ),
std::make_pair( "PC Sex", "38" ),
std::make_pair( "PC Short Blade", "33" ),
std::make_pair( "PC Sneak", "30" ),
std::make_pair( "PC Spear", "18" ),
std::make_pair( "PC Speechcraft", "36" ),
std::make_pair( "PC Speed", "54" ), // attrib
std::make_pair( "PC Strength", "10" ), // attrib
std::make_pair( "PC Unarmored", "28" ),
std::make_pair( "PC Vampire", "60" ),
std::make_pair( "PC Werewolf Kills", "73" ),
std::make_pair( "PC Willpower", "52" ), // attrib
std::make_pair( "Rank Requirement", "02" ),
std::make_pair( "Rank High", "01" ),
std::make_pair( "Rank Low", "00" ),
std::make_pair( "Reputation", "03" ),
std::make_pair( "Same Faction", "46" ),
std::make_pair( "Same Race", "45" ),
std::make_pair( "Same Sex", "44" ),
std::make_pair( "Should Attack", "71" ),
std::make_pair( "Talked To PC", "63" ),
std::make_pair( "Weather", "59" ),
std::make_pair( "Werewolf", "72" )
};
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");
switch (subColIndex)
{
case 0:
{
// See sInfoCondFunc in columns.cpp for the enum values
switch (value.toInt())
{
// FIXME: when these change the values of the other columns need to change
// correspondingly (and automatically)
case 1: conditions[subRowIndex].mSelectRule[1] = '1'; break; // Function
case 2: conditions[subRowIndex].mSelectRule[1] = '2'; break; // Global
case 3: conditions[subRowIndex].mSelectRule[1] = '3'; break; // Local
case 4: conditions[subRowIndex].mSelectRule[1] = '4'; break; // Journal
case 5: conditions[subRowIndex].mSelectRule[1] = '5'; break; // Item
case 6: conditions[subRowIndex].mSelectRule[1] = '6'; break; // Dead
case 7: conditions[subRowIndex].mSelectRule[1] = '7'; break; // Not ID
case 8: conditions[subRowIndex].mSelectRule[1] = '8'; break; // Not Faction
case 9: conditions[subRowIndex].mSelectRule[1] = '9'; break; // Not Class
case 10: conditions[subRowIndex].mSelectRule[1] = 'A'; break; // Not Race
case 11: conditions[subRowIndex].mSelectRule[1] = 'B'; break; // Not Cell
case 12: conditions[subRowIndex].mSelectRule[1] = 'C'; break; // Not Local
default: return; // return without saving
}
break;
}
case 1:
{
if (conditions[subRowIndex].mSelectRule[1] == '1')
{
// throws an exception if the function is not found
const std::map<const std::string, const std::string>::const_iterator it = sInfoFuncToEnc.find(
value.toString().toUtf8().constData());
if (it != sInfoFuncToEnc.end())
{
std::string rule = conditions[subRowIndex].mSelectRule.substr(0, 2);
rule.append(it->second);
rule.append(std::string(1, conditions[subRowIndex].mSelectRule[4]));
conditions[subRowIndex].mSelectRule = rule.append(value.toString().toUtf8().constData());
}
else
return; // return without saving; TODO: maybe log an error here
}
else
{
// FIXME: validate the string values before saving, based on the current function
std::string rule = conditions[subRowIndex].mSelectRule.substr(0, 5);
conditions[subRowIndex].mSelectRule = rule.append(value.toString().toUtf8().constData());
}
break;
}
case 2:
{
// See sInfoCondComp in columns.cpp for the enum values
switch (value.toInt())
{
case 0: conditions[subRowIndex].mSelectRule[4] = '1'; break; // !=
case 1: conditions[subRowIndex].mSelectRule[4] = '4'; break; // <
case 2: conditions[subRowIndex].mSelectRule[4] = '5'; break; // <=
case 3: conditions[subRowIndex].mSelectRule[4] = '0'; break; // =
case 4: conditions[subRowIndex].mSelectRule[4] = '2'; break; // >
case 5: conditions[subRowIndex].mSelectRule[4] = '3'; break; // >=
default: return; // return without saving
}
break;
}
case 3:
{
switch (conditions[subRowIndex].mValue.getType())
{
case ESM::VT_String:
{
conditions[subRowIndex].mValue.setString (value.toString().toUtf8().constData());
break;
}
case ESM::VT_Int:
case ESM::VT_Short:
case ESM::VT_Long:
{
conditions[subRowIndex].mValue.setInteger (value.toInt());
break;
}
case ESM::VT_Float:
{
conditions[subRowIndex].mValue.setFloat (value.toFloat());
break;
}
default: 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());
}
}