1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-19 20:53:52 +00:00
openmw/apps/opencs/model/world/refidadapterimp.cpp
2024-11-07 17:12:00 +01:00

1623 lines
55 KiB
C++

#include "refidadapterimp.hpp"
#include <stdexcept>
#include <apps/opencs/model/world/columnbase.hpp>
#include <apps/opencs/model/world/disabletag.hpp>
#include <apps/opencs/model/world/record.hpp>
#include <apps/opencs/model/world/refiddata.hpp>
#include <apps/opencs/model/world/universalid.hpp>
#include <components/esm/attr.hpp>
#include <components/esm3/loadcont.hpp>
#include <components/esm3/loadmgef.hpp>
#include <components/esm3/loadskil.hpp>
#include "nestedtablewrapper.hpp"
CSMWorld::PotionColumns::PotionColumns(const InventoryColumns& columns)
: InventoryColumns(columns)
, mEffects(nullptr)
{
}
CSMWorld::PotionRefIdAdapter::PotionRefIdAdapter(const PotionColumns& columns, const RefIdColumn* autoCalc)
: InventoryRefIdAdapter<ESM::Potion>(UniversalId::Type_Potion, columns)
, mColumns(columns)
, mAutoCalc(autoCalc)
{
}
QVariant CSMWorld::PotionRefIdAdapter::getData(const RefIdColumn* column, const RefIdData& data, int index) const
{
const Record<ESM::Potion>& record = static_cast<const Record<ESM::Potion>&>(
data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Potion)));
if (column == mAutoCalc)
return record.get().mData.mFlags & ESM::Potion::Autocalc;
// to show nested tables in dialogue subview, see IdTree::hasChildren()
if (column == mColumns.mEffects)
return QVariant::fromValue(ColumnBase::TableEdit_Full);
return InventoryRefIdAdapter<ESM::Potion>::getData(column, data, index);
}
void CSMWorld::PotionRefIdAdapter::setData(
const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const
{
Record<ESM::Potion>& record
= static_cast<Record<ESM::Potion>&>(data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Potion)));
ESM::Potion potion = record.get();
if (column == mAutoCalc)
potion.mData.mFlags = value.toBool();
else
{
InventoryRefIdAdapter<ESM::Potion>::setData(column, data, index, value);
return;
}
record.setModified(potion);
}
CSMWorld::IngredientColumns::IngredientColumns(const InventoryColumns& columns)
: InventoryColumns(columns)
, mEffects(nullptr)
{
}
CSMWorld::IngredientRefIdAdapter::IngredientRefIdAdapter(const IngredientColumns& columns)
: InventoryRefIdAdapter<ESM::Ingredient>(UniversalId::Type_Ingredient, columns)
, mColumns(columns)
{
}
QVariant CSMWorld::IngredientRefIdAdapter::getData(const RefIdColumn* column, const RefIdData& data, int index) const
{
if (column == mColumns.mEffects)
return QVariant::fromValue(ColumnBase::TableEdit_FixedRows);
return InventoryRefIdAdapter<ESM::Ingredient>::getData(column, data, index);
}
void CSMWorld::IngredientRefIdAdapter::setData(
const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const
{
InventoryRefIdAdapter<ESM::Ingredient>::setData(column, data, index, value);
return;
}
CSMWorld::IngredEffectRefIdAdapter::IngredEffectRefIdAdapter()
: mType(UniversalId::Type_Ingredient)
{
}
void CSMWorld::IngredEffectRefIdAdapter::addNestedRow(
const RefIdColumn* column, RefIdData& data, int index, int position) const
{
// Do nothing, this table cannot be changed by the user
}
void CSMWorld::IngredEffectRefIdAdapter::removeNestedRow(
const RefIdColumn* column, RefIdData& data, int index, int rowToRemove) const
{
// Do nothing, this table cannot be changed by the user
}
void CSMWorld::IngredEffectRefIdAdapter::setNestedTable(
const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const
{
Record<ESM::Ingredient>& record
= static_cast<Record<ESM::Ingredient>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
ESM::Ingredient ingredient = record.get();
ingredient.mData = static_cast<const NestedTableWrapper<std::vector<ESM::Ingredient::IRDTstruct>>&>(nestedTable)
.mNestedTable.at(0);
record.setModified(ingredient);
}
CSMWorld::NestedTableWrapperBase* CSMWorld::IngredEffectRefIdAdapter::nestedTable(
const RefIdColumn* column, const RefIdData& data, int index) const
{
const Record<ESM::Ingredient>& record
= static_cast<const Record<ESM::Ingredient>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
// return the whole struct
std::vector<ESM::Ingredient::IRDTstruct> wrap;
wrap.push_back(record.get().mData);
// deleted by dtor of NestedTableStoring
return new NestedTableWrapper<std::vector<ESM::Ingredient::IRDTstruct>>(wrap);
}
QVariant CSMWorld::IngredEffectRefIdAdapter::getNestedData(
const RefIdColumn* column, const RefIdData& data, int index, int subRowIndex, int subColIndex) const
{
const Record<ESM::Ingredient>& record
= static_cast<const Record<ESM::Ingredient>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
if (subRowIndex < 0 || subRowIndex >= 4)
throw std::runtime_error("index out of range");
switch (subColIndex)
{
case 0:
return record.get().mData.mEffectID[subRowIndex];
case 1:
{
switch (record.get().mData.mEffectID[subRowIndex])
{
case ESM::MagicEffect::DrainSkill:
case ESM::MagicEffect::DamageSkill:
case ESM::MagicEffect::RestoreSkill:
case ESM::MagicEffect::FortifySkill:
case ESM::MagicEffect::AbsorbSkill:
return record.get().mData.mSkills[subRowIndex];
default:
return QVariant();
}
}
case 2:
{
switch (record.get().mData.mEffectID[subRowIndex])
{
case ESM::MagicEffect::DrainAttribute:
case ESM::MagicEffect::DamageAttribute:
case ESM::MagicEffect::RestoreAttribute:
case ESM::MagicEffect::FortifyAttribute:
case ESM::MagicEffect::AbsorbAttribute:
return record.get().mData.mAttributes[subRowIndex];
default:
return QVariant();
}
}
default:
throw std::runtime_error("Trying to access non-existing column in the nested table!");
}
}
void CSMWorld::IngredEffectRefIdAdapter::setNestedData(
const RefIdColumn* column, RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const
{
Record<ESM::Ingredient>& record
= static_cast<Record<ESM::Ingredient>&>(data.getRecord(RefIdData::LocalIndex(row, mType)));
ESM::Ingredient ingredient = record.get();
if (subRowIndex < 0 || subRowIndex >= 4)
throw std::runtime_error("index out of range");
switch (subColIndex)
{
case 0:
ingredient.mData.mEffectID[subRowIndex] = value.toInt();
switch (ingredient.mData.mEffectID[subRowIndex])
{
case ESM::MagicEffect::DrainSkill:
case ESM::MagicEffect::DamageSkill:
case ESM::MagicEffect::RestoreSkill:
case ESM::MagicEffect::FortifySkill:
case ESM::MagicEffect::AbsorbSkill:
ingredient.mData.mAttributes[subRowIndex] = -1;
break;
case ESM::MagicEffect::DrainAttribute:
case ESM::MagicEffect::DamageAttribute:
case ESM::MagicEffect::RestoreAttribute:
case ESM::MagicEffect::FortifyAttribute:
case ESM::MagicEffect::AbsorbAttribute:
ingredient.mData.mSkills[subRowIndex] = -1;
break;
default:
ingredient.mData.mSkills[subRowIndex] = -1;
ingredient.mData.mAttributes[subRowIndex] = -1;
}
break;
case 1:
ingredient.mData.mSkills[subRowIndex] = value.toInt();
break;
case 2:
ingredient.mData.mAttributes[subRowIndex] = value.toInt();
break;
default:
throw std::runtime_error("Trying to access non-existing column in the nested table!");
}
record.setModified(ingredient);
}
int CSMWorld::IngredEffectRefIdAdapter::getNestedColumnsCount(const RefIdColumn* column, const RefIdData& data) const
{
return 3; // effect, skill, attribute
}
int CSMWorld::IngredEffectRefIdAdapter::getNestedRowsCount(
const RefIdColumn* column, const RefIdData& data, int index) const
{
return 4; // up to 4 effects
}
CSMWorld::ApparatusRefIdAdapter::ApparatusRefIdAdapter(
const InventoryColumns& columns, const RefIdColumn* type, const RefIdColumn* quality)
: InventoryRefIdAdapter<ESM::Apparatus>(UniversalId::Type_Apparatus, columns)
, mType(type)
, mQuality(quality)
{
}
QVariant CSMWorld::ApparatusRefIdAdapter::getData(const RefIdColumn* column, const RefIdData& data, int index) const
{
const Record<ESM::Apparatus>& record = static_cast<const Record<ESM::Apparatus>&>(
data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Apparatus)));
if (column == mType)
return record.get().mData.mType;
if (column == mQuality)
return record.get().mData.mQuality;
return InventoryRefIdAdapter<ESM::Apparatus>::getData(column, data, index);
}
void CSMWorld::ApparatusRefIdAdapter::setData(
const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const
{
Record<ESM::Apparatus>& record = static_cast<Record<ESM::Apparatus>&>(
data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Apparatus)));
ESM::Apparatus apparatus = record.get();
if (column == mType)
apparatus.mData.mType = value.toInt();
else if (column == mQuality)
apparatus.mData.mQuality = value.toFloat();
else
{
InventoryRefIdAdapter<ESM::Apparatus>::setData(column, data, index, value);
return;
}
record.setModified(apparatus);
}
CSMWorld::ArmorRefIdAdapter::ArmorRefIdAdapter(const EnchantableColumns& columns, const RefIdColumn* type,
const RefIdColumn* health, const RefIdColumn* armor, const RefIdColumn* partRef)
: EnchantableRefIdAdapter<ESM::Armor>(UniversalId::Type_Armor, columns)
, mType(type)
, mHealth(health)
, mArmor(armor)
, mPartRef(partRef)
{
}
QVariant CSMWorld::ArmorRefIdAdapter::getData(const RefIdColumn* column, const RefIdData& data, int index) const
{
const Record<ESM::Armor>& record
= static_cast<const Record<ESM::Armor>&>(data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Armor)));
if (column == mType)
return record.get().mData.mType;
if (column == mHealth)
return record.get().mData.mHealth;
if (column == mArmor)
return record.get().mData.mArmor;
if (column == mPartRef)
return QVariant::fromValue(ColumnBase::TableEdit_Full);
return EnchantableRefIdAdapter<ESM::Armor>::getData(column, data, index);
}
void CSMWorld::ArmorRefIdAdapter::setData(
const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const
{
Record<ESM::Armor>& record
= static_cast<Record<ESM::Armor>&>(data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Armor)));
ESM::Armor armor = record.get();
if (column == mType)
armor.mData.mType = value.toInt();
else if (column == mHealth)
armor.mData.mHealth = value.toInt();
else if (column == mArmor)
armor.mData.mArmor = value.toInt();
else
{
EnchantableRefIdAdapter<ESM::Armor>::setData(column, data, index, value);
return;
}
record.setModified(armor);
}
CSMWorld::BookRefIdAdapter::BookRefIdAdapter(
const EnchantableColumns& columns, const RefIdColumn* bookType, const RefIdColumn* skill, const RefIdColumn* text)
: EnchantableRefIdAdapter<ESM::Book>(UniversalId::Type_Book, columns)
, mBookType(bookType)
, mSkill(skill)
, mText(text)
{
}
QVariant CSMWorld::BookRefIdAdapter::getData(const RefIdColumn* column, const RefIdData& data, int index) const
{
const Record<ESM::Book>& record
= static_cast<const Record<ESM::Book>&>(data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Book)));
if (column == mBookType)
return record.get().mData.mIsScroll;
if (column == mSkill)
return record.get().mData.mSkillId;
if (column == mText)
return QString::fromUtf8(record.get().mText.c_str());
return EnchantableRefIdAdapter<ESM::Book>::getData(column, data, index);
}
void CSMWorld::BookRefIdAdapter::setData(
const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const
{
Record<ESM::Book>& record
= static_cast<Record<ESM::Book>&>(data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Book)));
ESM::Book book = record.get();
if (column == mBookType)
book.mData.mIsScroll = value.toInt();
else if (column == mSkill)
book.mData.mSkillId = value.toInt();
else if (column == mText)
book.mText = value.toString().toUtf8().data();
else
{
EnchantableRefIdAdapter<ESM::Book>::setData(column, data, index, value);
return;
}
record.setModified(book);
}
CSMWorld::ClothingRefIdAdapter::ClothingRefIdAdapter(
const EnchantableColumns& columns, const RefIdColumn* type, const RefIdColumn* partRef)
: EnchantableRefIdAdapter<ESM::Clothing>(UniversalId::Type_Clothing, columns)
, mType(type)
, mPartRef(partRef)
{
}
QVariant CSMWorld::ClothingRefIdAdapter::getData(const RefIdColumn* column, const RefIdData& data, int index) const
{
const Record<ESM::Clothing>& record = static_cast<const Record<ESM::Clothing>&>(
data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Clothing)));
if (column == mType)
return record.get().mData.mType;
if (column == mPartRef)
return QVariant::fromValue(ColumnBase::TableEdit_Full);
return EnchantableRefIdAdapter<ESM::Clothing>::getData(column, data, index);
}
void CSMWorld::ClothingRefIdAdapter::setData(
const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const
{
Record<ESM::Clothing>& record
= static_cast<Record<ESM::Clothing>&>(data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Clothing)));
ESM::Clothing clothing = record.get();
if (column == mType)
clothing.mData.mType = value.toInt();
else
{
EnchantableRefIdAdapter<ESM::Clothing>::setData(column, data, index, value);
return;
}
record.setModified(clothing);
}
CSMWorld::ContainerRefIdAdapter::ContainerRefIdAdapter(const NameColumns& columns, const RefIdColumn* weight,
const RefIdColumn* organic, const RefIdColumn* respawn, const RefIdColumn* content)
: NameRefIdAdapter<ESM::Container>(UniversalId::Type_Container, columns)
, mWeight(weight)
, mOrganic(organic)
, mRespawn(respawn)
, mContent(content)
{
}
QVariant CSMWorld::ContainerRefIdAdapter::getData(const RefIdColumn* column, const RefIdData& data, int index) const
{
const Record<ESM::Container>& record = static_cast<const Record<ESM::Container>&>(
data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Container)));
if (column == mWeight)
return record.get().mWeight;
if (column == mOrganic)
return (record.get().mFlags & ESM::Container::Organic) != 0;
if (column == mRespawn)
return (record.get().mFlags & ESM::Container::Respawn) != 0;
if (column == mContent)
return QVariant::fromValue(ColumnBase::TableEdit_Full);
return NameRefIdAdapter<ESM::Container>::getData(column, data, index);
}
void CSMWorld::ContainerRefIdAdapter::setData(
const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const
{
Record<ESM::Container>& record = static_cast<Record<ESM::Container>&>(
data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Container)));
ESM::Container container = record.get();
if (column == mWeight)
container.mWeight = value.toFloat();
else if (column == mOrganic)
{
if (value.toInt())
container.mFlags |= ESM::Container::Organic;
else
container.mFlags &= ~ESM::Container::Organic;
}
else if (column == mRespawn)
{
if (value.toInt())
container.mFlags |= ESM::Container::Respawn;
else
container.mFlags &= ~ESM::Container::Respawn;
}
else
{
NameRefIdAdapter<ESM::Container>::setData(column, data, index, value);
return;
}
record.setModified(container);
}
CSMWorld::CreatureColumns::CreatureColumns(const ActorColumns& actorColumns)
: ActorColumns(actorColumns)
, mType(nullptr)
, mScale(nullptr)
, mOriginal(nullptr)
, mAttributes(nullptr)
, mAttacks(nullptr)
, mMisc(nullptr)
, mBloodType(nullptr)
{
}
CSMWorld::CreatureRefIdAdapter::CreatureRefIdAdapter(const CreatureColumns& columns)
: ActorRefIdAdapter<ESM::Creature>(UniversalId::Type_Creature, columns)
, mColumns(columns)
{
}
QVariant CSMWorld::CreatureRefIdAdapter::getData(const RefIdColumn* column, const RefIdData& data, int index) const
{
const Record<ESM::Creature>& record = static_cast<const Record<ESM::Creature>&>(
data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Creature)));
if (column == mColumns.mType)
return record.get().mData.mType;
if (column == mColumns.mScale)
return record.get().mScale;
if (column == mColumns.mOriginal)
return QString::fromUtf8(record.get().mOriginal.getRefIdString().c_str());
if (column == mColumns.mAttributes)
return QVariant::fromValue(ColumnBase::TableEdit_FixedRows);
if (column == mColumns.mAttacks)
return QVariant::fromValue(ColumnBase::TableEdit_FixedRows);
if (column == mColumns.mMisc)
return QVariant::fromValue(ColumnBase::TableEdit_Full);
if (column == mColumns.mBloodType)
return record.get().mBloodType;
{
std::map<const RefIdColumn*, unsigned int>::const_iterator iter = mColumns.mFlags.find(column);
if (iter != mColumns.mFlags.end())
return (record.get().mFlags & iter->second) != 0;
}
{
std::map<const RefIdColumn*, unsigned int>::const_iterator iter = mColumns.mServices.find(column);
if (iter != mColumns.mServices.end() && iter->second == ESM::NPC::Training)
return QVariant();
}
return ActorRefIdAdapter<ESM::Creature>::getData(column, data, index);
}
void CSMWorld::CreatureRefIdAdapter::setData(
const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const
{
Record<ESM::Creature>& record
= static_cast<Record<ESM::Creature>&>(data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Creature)));
ESM::Creature creature = record.get();
if (column == mColumns.mType)
creature.mData.mType = value.toInt();
else if (column == mColumns.mScale)
creature.mScale = value.toFloat();
else if (column == mColumns.mOriginal)
creature.mOriginal = ESM::RefId::stringRefId(value.toString().toUtf8().constData());
else if (column == mColumns.mBloodType)
creature.mBloodType = value.toInt();
else
{
std::map<const RefIdColumn*, unsigned int>::const_iterator iter = mColumns.mFlags.find(column);
if (iter != mColumns.mFlags.end())
{
if (value.toInt() != 0)
creature.mFlags |= iter->second;
else
creature.mFlags &= ~iter->second;
}
else
{
ActorRefIdAdapter<ESM::Creature>::setData(column, data, index, value);
return;
}
}
record.setModified(creature);
}
CSMWorld::DoorRefIdAdapter::DoorRefIdAdapter(
const NameColumns& columns, const RefIdColumn* openSound, const RefIdColumn* closeSound)
: NameRefIdAdapter<ESM::Door>(UniversalId::Type_Door, columns)
, mOpenSound(openSound)
, mCloseSound(closeSound)
{
}
QVariant CSMWorld::DoorRefIdAdapter::getData(const RefIdColumn* column, const RefIdData& data, int index) const
{
const Record<ESM::Door>& record
= static_cast<const Record<ESM::Door>&>(data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Door)));
if (column == mOpenSound)
return QString::fromUtf8(record.get().mOpenSound.getRefIdString().c_str());
if (column == mCloseSound)
return QString::fromUtf8(record.get().mCloseSound.getRefIdString().c_str());
return NameRefIdAdapter<ESM::Door>::getData(column, data, index);
}
void CSMWorld::DoorRefIdAdapter::setData(
const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const
{
Record<ESM::Door>& record
= static_cast<Record<ESM::Door>&>(data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Door)));
ESM::Door door = record.get();
if (column == mOpenSound)
door.mOpenSound = ESM::RefId::stringRefId(value.toString().toUtf8().constData());
else if (column == mCloseSound)
door.mCloseSound = ESM::RefId::stringRefId(value.toString().toUtf8().constData());
else
{
NameRefIdAdapter<ESM::Door>::setData(column, data, index, value);
return;
}
record.setModified(door);
}
CSMWorld::LightColumns::LightColumns(const InventoryColumns& columns)
: InventoryColumns(columns)
, mTime(nullptr)
, mRadius(nullptr)
, mColor(nullptr)
, mSound(nullptr)
, mEmitterType(nullptr)
{
}
CSMWorld::LightRefIdAdapter::LightRefIdAdapter(const LightColumns& columns)
: InventoryRefIdAdapter<ESM::Light>(UniversalId::Type_Light, columns)
, mColumns(columns)
{
}
QVariant CSMWorld::LightRefIdAdapter::getData(const RefIdColumn* column, const RefIdData& data, int index) const
{
const Record<ESM::Light>& record
= static_cast<const Record<ESM::Light>&>(data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Light)));
if (column == mColumns.mTime)
return record.get().mData.mTime;
if (column == mColumns.mRadius)
return record.get().mData.mRadius;
if (column == mColumns.mColor)
return record.get().mData.mColor;
if (column == mColumns.mSound)
return QString::fromUtf8(record.get().mSound.getRefIdString().c_str());
if (column == mColumns.mEmitterType)
{
int mask = ESM::Light::Flicker | ESM::Light::FlickerSlow | ESM::Light::Pulse | ESM::Light::PulseSlow;
if ((record.get().mData.mFlags & mask) == ESM::Light::Flicker)
return 1;
if ((record.get().mData.mFlags & mask) == ESM::Light::FlickerSlow)
return 2;
if ((record.get().mData.mFlags & mask) == ESM::Light::Pulse)
return 3;
if ((record.get().mData.mFlags & mask) == ESM::Light::PulseSlow)
return 4;
return 0;
}
std::map<const RefIdColumn*, unsigned int>::const_iterator iter = mColumns.mFlags.find(column);
if (iter != mColumns.mFlags.end())
return (record.get().mData.mFlags & iter->second) != 0;
return InventoryRefIdAdapter<ESM::Light>::getData(column, data, index);
}
void CSMWorld::LightRefIdAdapter::setData(
const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const
{
Record<ESM::Light>& record
= static_cast<Record<ESM::Light>&>(data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Light)));
ESM::Light light = record.get();
if (column == mColumns.mTime)
light.mData.mTime = value.toInt();
else if (column == mColumns.mRadius)
light.mData.mRadius = value.toInt();
else if (column == mColumns.mColor)
light.mData.mColor = value.toInt();
else if (column == mColumns.mSound)
light.mSound = ESM::RefId::stringRefId(value.toString().toUtf8().constData());
else if (column == mColumns.mEmitterType)
{
int mask = ~(ESM::Light::Flicker | ESM::Light::FlickerSlow | ESM::Light::Pulse | ESM::Light::PulseSlow);
if (value.toInt() == 0)
light.mData.mFlags = light.mData.mFlags & mask;
else if (value.toInt() == 1)
light.mData.mFlags = (light.mData.mFlags & mask) | ESM::Light::Flicker;
else if (value.toInt() == 2)
light.mData.mFlags = (light.mData.mFlags & mask) | ESM::Light::FlickerSlow;
else if (value.toInt() == 3)
light.mData.mFlags = (light.mData.mFlags & mask) | ESM::Light::Pulse;
else
light.mData.mFlags = (light.mData.mFlags & mask) | ESM::Light::PulseSlow;
}
else
{
std::map<const RefIdColumn*, unsigned int>::const_iterator iter = mColumns.mFlags.find(column);
if (iter != mColumns.mFlags.end())
{
if (value.toInt() != 0)
light.mData.mFlags |= iter->second;
else
light.mData.mFlags &= ~iter->second;
}
else
{
InventoryRefIdAdapter<ESM::Light>::setData(column, data, index, value);
return;
}
}
record.setModified(light);
}
CSMWorld::MiscRefIdAdapter::MiscRefIdAdapter(const InventoryColumns& columns, const RefIdColumn* key)
: InventoryRefIdAdapter<ESM::Miscellaneous>(UniversalId::Type_Miscellaneous, columns)
, mKey(key)
{
}
QVariant CSMWorld::MiscRefIdAdapter::getData(const RefIdColumn* column, const RefIdData& data, int index) const
{
const Record<ESM::Miscellaneous>& record = static_cast<const Record<ESM::Miscellaneous>&>(
data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Miscellaneous)));
if (column == mKey)
return bool(record.get().mData.mFlags & ESM::Miscellaneous::Key);
return InventoryRefIdAdapter<ESM::Miscellaneous>::getData(column, data, index);
}
void CSMWorld::MiscRefIdAdapter::setData(
const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const
{
Record<ESM::Miscellaneous>& record = static_cast<Record<ESM::Miscellaneous>&>(
data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Miscellaneous)));
ESM::Miscellaneous misc = record.get();
if (column == mKey)
misc.mData.mFlags = value.toInt();
else
{
InventoryRefIdAdapter<ESM::Miscellaneous>::setData(column, data, index, value);
return;
}
record.setModified(misc);
}
CSMWorld::NpcColumns::NpcColumns(const ActorColumns& actorColumns)
: ActorColumns(actorColumns)
, mRace(nullptr)
, mClass(nullptr)
, mFaction(nullptr)
, mHair(nullptr)
, mHead(nullptr)
, mAttributes(nullptr)
, mSkills(nullptr)
, mMisc(nullptr)
, mBloodType(nullptr)
, mGender(nullptr)
{
}
CSMWorld::NpcRefIdAdapter::NpcRefIdAdapter(const NpcColumns& columns)
: ActorRefIdAdapter<ESM::NPC>(UniversalId::Type_Npc, columns)
, mColumns(columns)
{
}
QVariant CSMWorld::NpcRefIdAdapter::getData(const RefIdColumn* column, const RefIdData& data, int index) const
{
const Record<ESM::NPC>& record
= static_cast<const Record<ESM::NPC>&>(data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Npc)));
if (column == mColumns.mRace)
return QString::fromUtf8(record.get().mRace.getRefIdString().c_str());
if (column == mColumns.mClass)
return QString::fromUtf8(record.get().mClass.getRefIdString().c_str());
if (column == mColumns.mFaction)
return QString::fromUtf8(record.get().mFaction.getRefIdString().c_str());
if (column == mColumns.mHair)
return QString::fromUtf8(record.get().mHair.getRefIdString().c_str());
if (column == mColumns.mHead)
return QString::fromUtf8(record.get().mHead.getRefIdString().c_str());
if (column == mColumns.mAttributes || column == mColumns.mSkills)
{
if ((record.get().mFlags & ESM::NPC::Autocalc) != 0)
return QVariant::fromValue(ColumnBase::TableEdit_None);
else
return QVariant::fromValue(ColumnBase::TableEdit_FixedRows);
}
if (column == mColumns.mMisc)
return QVariant::fromValue(ColumnBase::TableEdit_Full);
if (column == mColumns.mBloodType)
return record.get().mBloodType;
if (column == mColumns.mGender)
{
// Implemented this way to allow additional gender types in the future.
if ((record.get().mFlags & ESM::NPC::Female) == ESM::NPC::Female)
return 1;
return 0;
}
std::map<const RefIdColumn*, unsigned int>::const_iterator iter = mColumns.mFlags.find(column);
if (iter != mColumns.mFlags.end())
return (record.get().mFlags & iter->second) != 0;
return ActorRefIdAdapter<ESM::NPC>::getData(column, data, index);
}
void CSMWorld::NpcRefIdAdapter::setData(
const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const
{
Record<ESM::NPC>& record
= static_cast<Record<ESM::NPC>&>(data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Npc)));
ESM::NPC npc = record.get();
if (column == mColumns.mRace)
npc.mRace = ESM::RefId::stringRefId(value.toString().toUtf8().constData());
else if (column == mColumns.mClass)
npc.mClass = ESM::RefId::stringRefId(value.toString().toUtf8().constData());
else if (column == mColumns.mFaction)
npc.mFaction = ESM::RefId::stringRefId(value.toString().toUtf8().constData());
else if (column == mColumns.mHair)
npc.mHair = ESM::RefId::stringRefId(value.toString().toUtf8().constData());
else if (column == mColumns.mHead)
npc.mHead = ESM::RefId::stringRefId(value.toString().toUtf8().constData());
else if (column == mColumns.mBloodType)
npc.mBloodType = value.toInt();
else if (column == mColumns.mGender)
{
// Implemented this way to allow additional gender types in the future.
if (value.toInt() == 1)
npc.mFlags = (npc.mFlags & ~ESM::NPC::Female) | ESM::NPC::Female;
else
npc.mFlags = npc.mFlags & ~ESM::NPC::Female;
}
else
{
std::map<const RefIdColumn*, unsigned int>::const_iterator iter = mColumns.mFlags.find(column);
if (iter != mColumns.mFlags.end())
{
if (value.toInt() != 0)
npc.mFlags |= iter->second;
else
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;
}
else
{
ActorRefIdAdapter<ESM::NPC>::setData(column, data, index, value);
return;
}
}
record.setModified(npc);
}
void CSMWorld::NpcAttributesRefIdAdapter::addNestedRow(
const RefIdColumn* column, RefIdData& data, int index, int position) const
{
// Do nothing, this table cannot be changed by the user
}
void CSMWorld::NpcAttributesRefIdAdapter::removeNestedRow(
const RefIdColumn* column, RefIdData& data, int index, int rowToRemove) const
{
// Do nothing, this table cannot be changed by the user
}
void CSMWorld::NpcAttributesRefIdAdapter::setNestedTable(
const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const
{
Record<ESM::NPC>& record
= static_cast<Record<ESM::NPC>&>(data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Npc)));
ESM::NPC npc = record.get();
// store the whole struct
npc.mNpdt
= static_cast<const NestedTableWrapper<std::vector<ESM::NPC::NPDTstruct52>>&>(nestedTable).mNestedTable.at(0);
record.setModified(npc);
}
CSMWorld::NestedTableWrapperBase* CSMWorld::NpcAttributesRefIdAdapter::nestedTable(
const RefIdColumn* column, const RefIdData& data, int index) const
{
const Record<ESM::NPC>& record
= static_cast<const Record<ESM::NPC>&>(data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Npc)));
// return the whole struct
std::vector<ESM::NPC::NPDTstruct52> wrap;
wrap.push_back(record.get().mNpdt);
// deleted by dtor of NestedTableStoring
return new NestedTableWrapper<std::vector<ESM::NPC::NPDTstruct52>>(wrap);
}
QVariant CSMWorld::NpcAttributesRefIdAdapter::getNestedData(
const RefIdColumn* column, const RefIdData& data, int index, int subRowIndex, int subColIndex) const
{
const Record<ESM::NPC>& record
= static_cast<const Record<ESM::NPC>&>(data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Npc)));
const ESM::NPC::NPDTstruct52& npcStruct = record.get().mNpdt;
if (subColIndex == 0)
return subRowIndex;
else if (subColIndex == 1 && subRowIndex >= 0 && subRowIndex < ESM::Attribute::Length)
return static_cast<int>(npcStruct.mAttributes[subRowIndex]);
return QVariant(); // throw an exception here?
}
void CSMWorld::NpcAttributesRefIdAdapter::setNestedData(
const RefIdColumn* column, RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const
{
Record<ESM::NPC>& record
= static_cast<Record<ESM::NPC>&>(data.getRecord(RefIdData::LocalIndex(row, UniversalId::Type_Npc)));
ESM::NPC npc = record.get();
ESM::NPC::NPDTstruct52& npcStruct = npc.mNpdt;
if (subColIndex == 1 && subRowIndex >= 0 && subRowIndex < ESM::Attribute::Length)
npcStruct.mAttributes[subRowIndex] = static_cast<unsigned char>(value.toInt());
else
return; // throw an exception here?
record.setModified(npc);
}
int CSMWorld::NpcAttributesRefIdAdapter::getNestedColumnsCount(const RefIdColumn* column, const RefIdData& data) const
{
return 2;
}
int CSMWorld::NpcAttributesRefIdAdapter::getNestedRowsCount(
const RefIdColumn* column, const RefIdData& data, int index) const
{
return ESM::Attribute::Length;
}
void CSMWorld::NpcSkillsRefIdAdapter::addNestedRow(
const RefIdColumn* column, RefIdData& data, int index, int position) const
{
// Do nothing, this table cannot be changed by the user
}
void CSMWorld::NpcSkillsRefIdAdapter::removeNestedRow(
const RefIdColumn* column, RefIdData& data, int index, int rowToRemove) const
{
// Do nothing, this table cannot be changed by the user
}
void CSMWorld::NpcSkillsRefIdAdapter::setNestedTable(
const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const
{
Record<ESM::NPC>& record
= static_cast<Record<ESM::NPC>&>(data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Npc)));
ESM::NPC npc = record.get();
// store the whole struct
npc.mNpdt
= static_cast<const NestedTableWrapper<std::vector<ESM::NPC::NPDTstruct52>>&>(nestedTable).mNestedTable.at(0);
record.setModified(npc);
}
CSMWorld::NestedTableWrapperBase* CSMWorld::NpcSkillsRefIdAdapter::nestedTable(
const RefIdColumn* column, const RefIdData& data, int index) const
{
const Record<ESM::NPC>& record
= static_cast<const Record<ESM::NPC>&>(data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Npc)));
// return the whole struct
std::vector<ESM::NPC::NPDTstruct52> wrap;
wrap.push_back(record.get().mNpdt);
// deleted by dtor of NestedTableStoring
return new NestedTableWrapper<std::vector<ESM::NPC::NPDTstruct52>>(wrap);
}
QVariant CSMWorld::NpcSkillsRefIdAdapter::getNestedData(
const RefIdColumn* column, const RefIdData& data, int index, int subRowIndex, int subColIndex) const
{
const Record<ESM::NPC>& record
= static_cast<const Record<ESM::NPC>&>(data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Npc)));
const ESM::NPC::NPDTstruct52& npcStruct = record.get().mNpdt;
if (subRowIndex < 0 || subRowIndex >= ESM::Skill::Length)
throw std::runtime_error("index out of range");
if (subColIndex == 0)
return subRowIndex;
else if (subColIndex == 1)
return static_cast<int>(npcStruct.mSkills[subRowIndex]);
else
return QVariant(); // throw an exception here?
}
void CSMWorld::NpcSkillsRefIdAdapter::setNestedData(
const RefIdColumn* column, RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const
{
Record<ESM::NPC>& record
= static_cast<Record<ESM::NPC>&>(data.getRecord(RefIdData::LocalIndex(row, UniversalId::Type_Npc)));
ESM::NPC npc = record.get();
ESM::NPC::NPDTstruct52& npcStruct = npc.mNpdt;
if (subRowIndex < 0 || subRowIndex >= ESM::Skill::Length)
throw std::runtime_error("index out of range");
if (subColIndex == 1)
npcStruct.mSkills[subRowIndex] = static_cast<unsigned char>(value.toInt());
else
return; // throw an exception here?
record.setModified(npc);
}
int CSMWorld::NpcSkillsRefIdAdapter::getNestedColumnsCount(const RefIdColumn* column, const RefIdData& data) const
{
return 2;
}
int CSMWorld::NpcSkillsRefIdAdapter::getNestedRowsCount(
const RefIdColumn* column, const RefIdData& data, int index) const
{
// There are 27 skills
return ESM::Skill::Length;
}
void CSMWorld::NpcMiscRefIdAdapter::addNestedRow(
const RefIdColumn* column, RefIdData& data, int index, int position) const
{
throw std::logic_error("cannot add a row to a fixed table");
}
void CSMWorld::NpcMiscRefIdAdapter::removeNestedRow(
const RefIdColumn* column, RefIdData& data, int index, int rowToRemove) const
{
throw std::logic_error("cannot remove a row to a fixed table");
}
void CSMWorld::NpcMiscRefIdAdapter::setNestedTable(
const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const
{
throw std::logic_error("table operation not supported");
}
CSMWorld::NestedTableWrapperBase* CSMWorld::NpcMiscRefIdAdapter::nestedTable(
const RefIdColumn* column, const RefIdData& data, int index) const
{
throw std::logic_error("table operation not supported");
}
QVariant CSMWorld::NpcMiscRefIdAdapter::getNestedData(
const RefIdColumn* column, const RefIdData& data, int index, int subRowIndex, int subColIndex) const
{
const Record<ESM::NPC>& record
= static_cast<const Record<ESM::NPC>&>(data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Npc)));
bool autoCalc = (record.get().mFlags & ESM::NPC::Autocalc) != 0;
if (autoCalc)
switch (subColIndex)
{
case 0:
return static_cast<int>(record.get().mNpdt.mLevel);
case 1:
return CSMWorld::DisableTag::getVariant();
case 2:
return CSMWorld::DisableTag::getVariant();
case 3:
return CSMWorld::DisableTag::getVariant();
case 4:
return static_cast<int>(record.get().mNpdt.mDisposition);
case 5:
return static_cast<int>(record.get().mNpdt.mReputation);
case 6:
return static_cast<int>(record.get().mNpdt.mRank);
case 7:
return record.get().mNpdt.mGold;
default:
return QVariant(); // throw an exception here?
}
else
switch (subColIndex)
{
case 0:
return static_cast<int>(record.get().mNpdt.mLevel);
case 1:
return static_cast<int>(record.get().mNpdt.mHealth);
case 2:
return static_cast<int>(record.get().mNpdt.mMana);
case 3:
return static_cast<int>(record.get().mNpdt.mFatigue);
case 4:
return static_cast<int>(record.get().mNpdt.mDisposition);
case 5:
return static_cast<int>(record.get().mNpdt.mReputation);
case 6:
return static_cast<int>(record.get().mNpdt.mRank);
case 7:
return record.get().mNpdt.mGold;
default:
return QVariant(); // throw an exception here?
}
}
void CSMWorld::NpcMiscRefIdAdapter::setNestedData(
const RefIdColumn* column, RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const
{
Record<ESM::NPC>& record
= static_cast<Record<ESM::NPC>&>(data.getRecord(RefIdData::LocalIndex(row, UniversalId::Type_Npc)));
ESM::NPC npc = record.get();
bool autoCalc = (record.get().mFlags & ESM::NPC::Autocalc) != 0;
if (autoCalc)
switch (subColIndex)
{
case 0:
npc.mNpdt.mLevel = static_cast<short>(value.toInt());
break;
case 1:
return;
case 2:
return;
case 3:
return;
case 4:
npc.mNpdt.mDisposition = static_cast<signed char>(value.toInt());
break;
case 5:
npc.mNpdt.mReputation = static_cast<signed char>(value.toInt());
break;
case 6:
npc.mNpdt.mRank = static_cast<signed char>(value.toInt());
break;
case 7:
npc.mNpdt.mGold = value.toInt();
break;
default:
return; // throw an exception here?
}
else
switch (subColIndex)
{
case 0:
npc.mNpdt.mLevel = static_cast<short>(value.toInt());
break;
case 1:
npc.mNpdt.mHealth = static_cast<unsigned short>(value.toInt());
break;
case 2:
npc.mNpdt.mMana = static_cast<unsigned short>(value.toInt());
break;
case 3:
npc.mNpdt.mFatigue = static_cast<unsigned short>(value.toInt());
break;
case 4:
npc.mNpdt.mDisposition = static_cast<signed char>(value.toInt());
break;
case 5:
npc.mNpdt.mReputation = static_cast<signed char>(value.toInt());
break;
case 6:
npc.mNpdt.mRank = static_cast<signed char>(value.toInt());
break;
case 7:
npc.mNpdt.mGold = value.toInt();
break;
default:
return; // throw an exception here?
}
record.setModified(npc);
}
int CSMWorld::NpcMiscRefIdAdapter::getNestedColumnsCount(const RefIdColumn* column, const RefIdData& data) const
{
return 8; // Level, Health, Mana, Fatigue, Disposition, Reputation, Rank, Gold
}
int CSMWorld::NpcMiscRefIdAdapter::getNestedRowsCount(const RefIdColumn* column, const RefIdData& data, int index) const
{
return 1; // fixed at size 1
}
void CSMWorld::CreatureAttributesRefIdAdapter::addNestedRow(
const RefIdColumn* column, RefIdData& data, int index, int position) const
{
// Do nothing, this table cannot be changed by the user
}
void CSMWorld::CreatureAttributesRefIdAdapter::removeNestedRow(
const RefIdColumn* column, RefIdData& data, int index, int rowToRemove) const
{
// Do nothing, this table cannot be changed by the user
}
void CSMWorld::CreatureAttributesRefIdAdapter::setNestedTable(
const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const
{
Record<ESM::Creature>& record
= static_cast<Record<ESM::Creature>&>(data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Creature)));
ESM::Creature creature = record.get();
// store the whole struct
creature.mData = static_cast<const NestedTableWrapper<std::vector<ESM::Creature::NPDTstruct>>&>(nestedTable)
.mNestedTable.at(0);
record.setModified(creature);
}
CSMWorld::NestedTableWrapperBase* CSMWorld::CreatureAttributesRefIdAdapter::nestedTable(
const RefIdColumn* column, const RefIdData& data, int index) const
{
const Record<ESM::Creature>& record = static_cast<const Record<ESM::Creature>&>(
data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Creature)));
// return the whole struct
std::vector<ESM::Creature::NPDTstruct> wrap;
wrap.push_back(record.get().mData);
// deleted by dtor of NestedTableStoring
return new NestedTableWrapper<std::vector<ESM::Creature::NPDTstruct>>(wrap);
}
QVariant CSMWorld::CreatureAttributesRefIdAdapter::getNestedData(
const RefIdColumn* column, const RefIdData& data, int index, int subRowIndex, int subColIndex) const
{
const Record<ESM::Creature>& record = static_cast<const Record<ESM::Creature>&>(
data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Creature)));
const ESM::Creature& creature = record.get();
if (subColIndex == 0)
return subRowIndex;
else if (subColIndex == 1 && subRowIndex >= 0 && subRowIndex < ESM::Attribute::Length)
return creature.mData.mAttributes[subRowIndex];
return QVariant(); // throw an exception here?
}
void CSMWorld::CreatureAttributesRefIdAdapter::setNestedData(
const RefIdColumn* column, RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const
{
Record<ESM::Creature>& record
= static_cast<Record<ESM::Creature>&>(data.getRecord(RefIdData::LocalIndex(row, UniversalId::Type_Creature)));
if (subColIndex == 1 && subRowIndex >= 0 && subRowIndex < ESM::Attribute::Length)
{
ESM::Creature creature = record.get();
creature.mData.mAttributes[subRowIndex] = value.toInt();
record.setModified(creature);
}
// throw an exception here?
}
int CSMWorld::CreatureAttributesRefIdAdapter::getNestedColumnsCount(
const RefIdColumn* column, const RefIdData& data) const
{
return 2;
}
int CSMWorld::CreatureAttributesRefIdAdapter::getNestedRowsCount(
const RefIdColumn* column, const RefIdData& data, int index) const
{
return ESM::Attribute::Length;
}
void CSMWorld::CreatureAttackRefIdAdapter::addNestedRow(
const RefIdColumn* column, RefIdData& data, int index, int position) const
{
// Do nothing, this table cannot be changed by the user
}
void CSMWorld::CreatureAttackRefIdAdapter::removeNestedRow(
const RefIdColumn* column, RefIdData& data, int index, int rowToRemove) const
{
// Do nothing, this table cannot be changed by the user
}
void CSMWorld::CreatureAttackRefIdAdapter::setNestedTable(
const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const
{
Record<ESM::Creature>& record
= static_cast<Record<ESM::Creature>&>(data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Creature)));
ESM::Creature creature = record.get();
// store the whole struct
creature.mData = static_cast<const NestedTableWrapper<std::vector<ESM::Creature::NPDTstruct>>&>(nestedTable)
.mNestedTable.at(0);
record.setModified(creature);
}
CSMWorld::NestedTableWrapperBase* CSMWorld::CreatureAttackRefIdAdapter::nestedTable(
const RefIdColumn* column, const RefIdData& data, int index) const
{
const Record<ESM::Creature>& record = static_cast<const Record<ESM::Creature>&>(
data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Creature)));
// return the whole struct
std::vector<ESM::Creature::NPDTstruct> wrap;
wrap.push_back(record.get().mData);
// deleted by dtor of NestedTableStoring
return new NestedTableWrapper<std::vector<ESM::Creature::NPDTstruct>>(wrap);
}
QVariant CSMWorld::CreatureAttackRefIdAdapter::getNestedData(
const RefIdColumn* column, const RefIdData& data, int index, int subRowIndex, int subColIndex) const
{
const Record<ESM::Creature>& record = static_cast<const Record<ESM::Creature>&>(
data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Creature)));
const ESM::Creature& creature = record.get();
if (subRowIndex < 0 || subRowIndex > 2)
throw std::runtime_error("index out of range");
if (subColIndex == 0)
return subRowIndex + 1;
else if (subColIndex == 1 || subColIndex == 2)
return creature.mData.mAttack[(subRowIndex * 2) + (subColIndex - 1)];
else
throw std::runtime_error("index out of range");
}
void CSMWorld::CreatureAttackRefIdAdapter::setNestedData(
const RefIdColumn* column, RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const
{
Record<ESM::Creature>& record
= static_cast<Record<ESM::Creature>&>(data.getRecord(RefIdData::LocalIndex(row, UniversalId::Type_Creature)));
ESM::Creature creature = record.get();
if (subRowIndex < 0 || subRowIndex > 2)
throw std::runtime_error("index out of range");
if (subColIndex == 1 || subColIndex == 2)
creature.mData.mAttack[(subRowIndex * 2) + (subColIndex - 1)] = value.toInt();
else
return; // throw an exception here?
record.setModified(creature);
}
int CSMWorld::CreatureAttackRefIdAdapter::getNestedColumnsCount(const RefIdColumn* column, const RefIdData& data) const
{
return 3;
}
int CSMWorld::CreatureAttackRefIdAdapter::getNestedRowsCount(
const RefIdColumn* column, const RefIdData& data, int index) const
{
// There are 3 attacks
return 3;
}
void CSMWorld::CreatureMiscRefIdAdapter::addNestedRow(
const RefIdColumn* column, RefIdData& data, int index, int position) const
{
throw std::logic_error("cannot add a row to a fixed table");
}
void CSMWorld::CreatureMiscRefIdAdapter::removeNestedRow(
const RefIdColumn* column, RefIdData& data, int index, int rowToRemove) const
{
throw std::logic_error("cannot remove a row to a fixed table");
}
void CSMWorld::CreatureMiscRefIdAdapter::setNestedTable(
const RefIdColumn* column, RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const
{
throw std::logic_error("table operation not supported");
}
CSMWorld::NestedTableWrapperBase* CSMWorld::CreatureMiscRefIdAdapter::nestedTable(
const RefIdColumn* column, const RefIdData& data, int index) const
{
throw std::logic_error("table operation not supported");
}
QVariant CSMWorld::CreatureMiscRefIdAdapter::getNestedData(
const RefIdColumn* column, const RefIdData& data, int index, int subRowIndex, int subColIndex) const
{
const Record<ESM::Creature>& record = static_cast<const Record<ESM::Creature>&>(
data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Creature)));
const ESM::Creature& creature = record.get();
switch (subColIndex)
{
case 0:
return creature.mData.mLevel;
case 1:
return creature.mData.mHealth;
case 2:
return creature.mData.mMana;
case 3:
return creature.mData.mFatigue;
case 4:
return creature.mData.mSoul;
case 5:
return creature.mData.mCombat;
case 6:
return creature.mData.mMagic;
case 7:
return creature.mData.mStealth;
case 8:
return creature.mData.mGold;
default:
return QVariant(); // throw an exception here?
}
}
void CSMWorld::CreatureMiscRefIdAdapter::setNestedData(
const RefIdColumn* column, RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const
{
Record<ESM::Creature>& record
= static_cast<Record<ESM::Creature>&>(data.getRecord(RefIdData::LocalIndex(row, UniversalId::Type_Creature)));
ESM::Creature creature = record.get();
switch (subColIndex)
{
case 0:
creature.mData.mLevel = value.toInt();
break;
case 1:
creature.mData.mHealth = value.toInt();
break;
case 2:
creature.mData.mMana = value.toInt();
break;
case 3:
creature.mData.mFatigue = value.toInt();
break;
case 4:
creature.mData.mSoul = value.toInt();
break;
case 5:
creature.mData.mCombat = value.toInt();
break;
case 6:
creature.mData.mMagic = value.toInt();
break;
case 7:
creature.mData.mStealth = value.toInt();
break;
case 8:
creature.mData.mGold = value.toInt();
break;
default:
return; // throw an exception here?
}
record.setModified(creature);
}
int CSMWorld::CreatureMiscRefIdAdapter::getNestedColumnsCount(const RefIdColumn* column, const RefIdData& data) const
{
return 9; // Level, Health, Mana, Fatigue, Soul, Combat, Magic, Steath, Gold
}
int CSMWorld::CreatureMiscRefIdAdapter::getNestedRowsCount(
const RefIdColumn* column, const RefIdData& data, int index) const
{
return 1; // fixed at size 1
}
CSMWorld::WeaponColumns::WeaponColumns(const EnchantableColumns& columns)
: EnchantableColumns(columns)
, mType(nullptr)
, mHealth(nullptr)
, mSpeed(nullptr)
, mReach(nullptr)
, mChop{ nullptr }
, mSlash{ nullptr }
, mThrust{ nullptr }
{
}
CSMWorld::WeaponRefIdAdapter::WeaponRefIdAdapter(const WeaponColumns& columns)
: EnchantableRefIdAdapter<ESM::Weapon>(UniversalId::Type_Weapon, columns)
, mColumns(columns)
{
}
QVariant CSMWorld::WeaponRefIdAdapter::getData(const RefIdColumn* column, const RefIdData& data, int index) const
{
const Record<ESM::Weapon>& record = static_cast<const Record<ESM::Weapon>&>(
data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Weapon)));
if (column == mColumns.mType)
return record.get().mData.mType;
if (column == mColumns.mHealth)
return record.get().mData.mHealth;
if (column == mColumns.mSpeed)
return record.get().mData.mSpeed;
if (column == mColumns.mReach)
return record.get().mData.mReach;
for (int i = 0; i < 2; ++i)
{
if (column == mColumns.mChop[i])
return record.get().mData.mChop[i];
if (column == mColumns.mSlash[i])
return record.get().mData.mSlash[i];
if (column == mColumns.mThrust[i])
return record.get().mData.mThrust[i];
}
std::map<const RefIdColumn*, unsigned int>::const_iterator iter = mColumns.mFlags.find(column);
if (iter != mColumns.mFlags.end())
return (record.get().mData.mFlags & iter->second) != 0;
return EnchantableRefIdAdapter<ESM::Weapon>::getData(column, data, index);
}
void CSMWorld::WeaponRefIdAdapter::setData(
const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const
{
Record<ESM::Weapon>& record
= static_cast<Record<ESM::Weapon>&>(data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Weapon)));
ESM::Weapon weapon = record.get();
if (column == mColumns.mType)
weapon.mData.mType = value.toInt();
else if (column == mColumns.mHealth)
weapon.mData.mHealth = value.toInt();
else if (column == mColumns.mSpeed)
weapon.mData.mSpeed = value.toFloat();
else if (column == mColumns.mReach)
weapon.mData.mReach = value.toFloat();
else if (column == mColumns.mChop[0])
weapon.mData.mChop[0] = value.toInt();
else if (column == mColumns.mChop[1])
weapon.mData.mChop[1] = value.toInt();
else if (column == mColumns.mSlash[0])
weapon.mData.mSlash[0] = value.toInt();
else if (column == mColumns.mSlash[1])
weapon.mData.mSlash[1] = value.toInt();
else if (column == mColumns.mThrust[0])
weapon.mData.mThrust[0] = value.toInt();
else if (column == mColumns.mThrust[1])
weapon.mData.mThrust[1] = value.toInt();
else
{
std::map<const RefIdColumn*, unsigned int>::const_iterator iter = mColumns.mFlags.find(column);
if (iter != mColumns.mFlags.end())
{
if (value.toInt() != 0)
weapon.mData.mFlags |= iter->second;
else
weapon.mData.mFlags &= ~iter->second;
}
else
{
EnchantableRefIdAdapter<ESM::Weapon>::setData(column, data, index, value);
return; // Don't overwrite changes made by base class
}
}
record.setModified(weapon);
}