Merge branch 'allthatglitters' into 'master'

Use NAM9 for stack count

Closes #2566

See merge request OpenMW/openmw!3698
macos_ci_fix
jvoisin 4 months ago
commit 31ac993374

@ -118,6 +118,7 @@
Bug #7723: Assaulting vampires and werewolves shouldn't be a crime
Bug #7724: Guards don't help vs werewolves
Bug #7742: Governing attribute training limit should use the modified attribute
Feature #2566: Handle NAM9 records for manual cell references
Feature #3537: Shader-based water ripples
Feature #5173: Support for NiFogProperty
Feature #5492: Let rain and snow collide with statics

@ -265,7 +265,7 @@ namespace
std::cout << " Faction rank: " << ref.mFactionRank << '\n';
std::cout << " Enchantment charge: " << ref.mEnchantmentCharge << '\n';
std::cout << " Uses/health: " << ref.mChargeInt << '\n';
std::cout << " Gold value: " << ref.mGoldValue << '\n';
std::cout << " Count: " << ref.mCount << '\n';
std::cout << " Blocked: " << static_cast<int>(ref.mReferenceBlocked) << '\n';
std::cout << " Deleted: " << deleted << '\n';
if (!ref.mKey.empty())

@ -34,7 +34,7 @@ namespace
objstate.mPosition = cellref.mPos;
objstate.mRef.mRefNum = cellref.mRefNum;
if (cellref.mDeleted)
objstate.mCount = 0;
objstate.mRef.mCount = 0;
convertSCRI(cellref.mActorData.mSCRI, objstate.mLocals);
objstate.mHasLocals = !objstate.mLocals.mVariables.empty();

@ -16,7 +16,7 @@ namespace ESSImport
objstate.blank();
objstate.mRef = item;
objstate.mRef.mRefID = ESM::RefId::stringRefId(item.mId);
objstate.mCount = item.mCount;
objstate.mRef.mCount = item.mCount;
state.mItems.push_back(objstate);
if (item.mRelativeEquipmentSlot != -1)
// Note we should really write the absolute slot here, which we do not know about

@ -98,9 +98,8 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages& message
if (cellRef.mEnchantmentCharge < -1)
messages.add(id, "Negative number of enchantment points", "", CSMDoc::Message::Severity_Error);
// Check if gold value isn't negative
if (cellRef.mGoldValue < 0)
messages.add(id, "Negative gold value", "", CSMDoc::Message::Severity_Error);
if (cellRef.mCount < 1)
messages.add(id, "Reference without count", {}, CSMDoc::Message::Severity_Error);
}
int CSMTools::ReferenceCheckStage::setup()

@ -1111,19 +1111,19 @@ namespace CSMWorld
};
template <typename ESXRecordT>
struct GoldValueColumn : public Column<ESXRecordT>
struct StackSizeColumn : public Column<ESXRecordT>
{
GoldValueColumn()
: Column<ESXRecordT>(Columns::ColumnId_CoinValue, ColumnBase::Display_Integer)
StackSizeColumn()
: Column<ESXRecordT>(Columns::ColumnId_StackCount, ColumnBase::Display_Integer)
{
}
QVariant get(const Record<ESXRecordT>& record) const override { return record.get().mGoldValue; }
QVariant get(const Record<ESXRecordT>& record) const override { return record.get().mCount; }
void set(Record<ESXRecordT>& record, const QVariant& data) override
{
ESXRecordT record2 = record.get();
record2.mGoldValue = data.toInt();
record2.mCount = data.toInt();
record.setModified(record2);
}

@ -56,7 +56,7 @@ namespace CSMWorld
{ ColumnId_FactionIndex, "Faction Index" },
{ ColumnId_Charges, "Charges" },
{ ColumnId_Enchantment, "Enchantment" },
{ ColumnId_CoinValue, "Coin Value" },
{ ColumnId_StackCount, "Count" },
{ ColumnId_Teleport, "Teleport" },
{ ColumnId_TeleportCell, "Teleport Cell" },
{ ColumnId_LockLevel, "Lock Level" },

@ -45,7 +45,7 @@ namespace CSMWorld
ColumnId_FactionIndex = 31,
ColumnId_Charges = 32,
ColumnId_Enchantment = 33,
ColumnId_CoinValue = 34,
ColumnId_StackCount = 34,
ColumnId_Teleport = 35,
ColumnId_TeleportCell = 36,
ColumnId_LockLevel = 37,

@ -587,7 +587,7 @@ CSMWorld::Data::Data(ToUTF8::FromType encoding, const Files::PathContainer& data
mRefs.addColumn(new FactionIndexColumn<CellRef>);
mRefs.addColumn(new ChargesColumn<CellRef>);
mRefs.addColumn(new EnchantmentChargesColumn<CellRef>);
mRefs.addColumn(new GoldValueColumn<CellRef>);
mRefs.addColumn(new StackSizeColumn<CellRef>);
mRefs.addColumn(new TeleportColumn<CellRef>);
mRefs.addColumn(new TeleportCellColumn<CellRef>);
mRefs.addColumn(new PosColumn<CellRef>(&CellRef::mDoorDest, 0, true));

@ -97,7 +97,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
inventoryColumns.mIcon = &mColumns.back();
mColumns.emplace_back(Columns::ColumnId_Weight, ColumnBase::Display_Float);
inventoryColumns.mWeight = &mColumns.back();
mColumns.emplace_back(Columns::ColumnId_CoinValue, ColumnBase::Display_Integer);
mColumns.emplace_back(Columns::ColumnId_StackCount, ColumnBase::Display_Integer);
inventoryColumns.mValue = &mColumns.back();
IngredientColumns ingredientColumns(inventoryColumns);

@ -185,7 +185,7 @@ namespace MWBase
virtual std::string_view getCellName(const ESM::Cell* cell) const = 0;
virtual void removeRefScript(MWWorld::RefData* ref) = 0;
virtual void removeRefScript(const MWWorld::CellRef* ref) = 0;
//< Remove the script attached to ref from mLocalScripts
virtual MWWorld::Ptr getPtr(const ESM::RefId& name, bool activeOnly) = 0;

@ -828,7 +828,7 @@ namespace MWClass
}
const CreatureCustomData& customData = ptr.getRefData().getCustomData()->asCreatureCustomData();
if (ptr.getRefData().getCount() <= 0
if (ptr.getCellRef().getCount() <= 0
&& (!isFlagBitSet(ptr, ESM::Creature::Respawn) || !customData.mCreatureStats.isDead()))
{
state.mHasCustomState = false;
@ -848,7 +848,7 @@ namespace MWClass
void Creature::respawn(const MWWorld::Ptr& ptr) const
{
const MWMechanics::CreatureStats& creatureStats = getCreatureStats(ptr);
if (ptr.getRefData().getCount() > 0 && !creatureStats.isDead())
if (ptr.getCellRef().getCount() > 0 && !creatureStats.isDead())
return;
if (!creatureStats.isDeathAnimationFinished())
@ -860,16 +860,16 @@ namespace MWClass
static const float fCorpseClearDelay = gmst.find("fCorpseClearDelay")->mValue.getFloat();
float delay
= ptr.getRefData().getCount() == 0 ? fCorpseClearDelay : std::min(fCorpseRespawnDelay, fCorpseClearDelay);
= ptr.getCellRef().getCount() == 0 ? fCorpseClearDelay : std::min(fCorpseRespawnDelay, fCorpseClearDelay);
if (isFlagBitSet(ptr, ESM::Creature::Respawn)
&& creatureStats.getTimeOfDeath() + delay <= MWBase::Environment::get().getWorld()->getTimeStamp())
{
if (ptr.getCellRef().hasContentFile())
{
if (ptr.getRefData().getCount() == 0)
if (ptr.getCellRef().getCount() == 0)
{
ptr.getRefData().setCount(1);
ptr.getCellRef().setCount(1);
const ESM::RefId& script = getScript(ptr);
if (!script.empty())
MWBase::Environment::get().getWorld()->getLocalScripts().add(script, ptr);

@ -81,7 +81,7 @@ namespace MWClass
if (!creature.isEmpty())
{
const MWMechanics::CreatureStats& creatureStats = creature.getClass().getCreatureStats(creature);
if (creature.getRefData().getCount() == 0)
if (creature.getCellRef().getCount() == 0)
customData.mSpawn = true;
else if (creatureStats.isDead())
{

@ -79,8 +79,8 @@ namespace MWClass
const MWWorld::LiveCellRef<ESM::Miscellaneous>* ref = ptr.get<ESM::Miscellaneous>();
int value = ref->mBase->mData.mValue;
if (ptr.getCellRef().getGoldValue() > 1 && ptr.getRefData().getCount() == 1)
value = ptr.getCellRef().getGoldValue();
if (isGold(ptr) && ptr.getCellRef().getCount() != 1)
value = 1;
if (!ptr.getCellRef().getSoul().empty())
{
@ -189,8 +189,7 @@ namespace MWClass
const MWWorld::LiveCellRef<ESM::Miscellaneous>* ref = newRef.getPtr().get<ESM::Miscellaneous>();
MWWorld::Ptr ptr(cell.insert(ref), &cell);
ptr.getCellRef().setGoldValue(goldAmount);
ptr.getRefData().setCount(1);
ptr.getCellRef().setCount(goldAmount);
return ptr;
}
@ -203,7 +202,7 @@ namespace MWClass
{
const MWWorld::LiveCellRef<ESM::Miscellaneous>* ref = ptr.get<ESM::Miscellaneous>();
newPtr = MWWorld::Ptr(cell.insert(ref), &cell);
newPtr.getRefData().setCount(count);
newPtr.getCellRef().setCount(count);
}
newPtr.getCellRef().unsetRefNum();
newPtr.getRefData().setLuaScripts(nullptr);
@ -216,10 +215,9 @@ namespace MWClass
MWWorld::Ptr newPtr;
if (isGold(ptr))
{
newPtr = createGold(cell, getValue(ptr) * ptr.getRefData().getCount());
newPtr = createGold(cell, getValue(ptr) * ptr.getCellRef().getCount());
newPtr.getRefData() = ptr.getRefData();
newPtr.getCellRef().setRefNum(ptr.getCellRef().getRefNum());
newPtr.getRefData().setCount(1);
}
else
{

@ -1358,7 +1358,7 @@ namespace MWClass
}
const NpcCustomData& customData = ptr.getRefData().getCustomData()->asNpcCustomData();
if (ptr.getRefData().getCount() <= 0
if (ptr.getCellRef().getCount() <= 0
&& (!(ptr.get<ESM::NPC>()->mBase->mFlags & ESM::NPC::Respawn) || !customData.mNpcStats.isDead()))
{
state.mHasCustomState = false;
@ -1395,7 +1395,7 @@ namespace MWClass
void Npc::respawn(const MWWorld::Ptr& ptr) const
{
const MWMechanics::CreatureStats& creatureStats = getCreatureStats(ptr);
if (ptr.getRefData().getCount() > 0 && !creatureStats.isDead())
if (ptr.getCellRef().getCount() > 0 && !creatureStats.isDead())
return;
if (!creatureStats.isDeathAnimationFinished())
@ -1407,16 +1407,16 @@ namespace MWClass
static const float fCorpseClearDelay = gmst.find("fCorpseClearDelay")->mValue.getFloat();
float delay
= ptr.getRefData().getCount() == 0 ? fCorpseClearDelay : std::min(fCorpseRespawnDelay, fCorpseClearDelay);
= ptr.getCellRef().getCount() == 0 ? fCorpseClearDelay : std::min(fCorpseRespawnDelay, fCorpseClearDelay);
if (ptr.get<ESM::NPC>()->mBase->mFlags & ESM::NPC::Respawn
&& creatureStats.getTimeOfDeath() + delay <= MWBase::Environment::get().getWorld()->getTimeStamp())
{
if (ptr.getCellRef().hasContentFile())
{
if (ptr.getRefData().getCount() == 0)
if (ptr.getCellRef().getCount() == 0)
{
ptr.getRefData().setCount(1);
ptr.getCellRef().setCount(1);
const ESM::RefId& script = getScript(ptr);
if (!script.empty())
MWBase::Environment::get().getWorld()->getLocalScripts().add(script, ptr);

@ -151,7 +151,7 @@ namespace MWGui
if (mIngredients[i]->isUserString("ToolTipType"))
{
MWWorld::Ptr ingred = *mIngredients[i]->getUserData<MWWorld::Ptr>();
if (ingred.getRefData().getCount() == 0)
if (ingred.getCellRef().getCount() == 0)
mAlchemy->removeIngredient(i);
}
@ -413,7 +413,7 @@ namespace MWGui
}
if (!item.isEmpty())
mSortModel->addDragItem(item, item.getRefData().getCount());
mSortModel->addDragItem(item, item.getCellRef().getCount());
if (ingredient->getChildCount())
MyGUI::Gui::getInstance().destroyWidget(ingredient->getChildAt(0));
@ -428,7 +428,7 @@ namespace MWGui
ingredient->setUserString("ToolTipType", "ItemPtr");
ingredient->setUserData(MWWorld::Ptr(item));
ingredient->setCount(item.getRefData().getCount());
ingredient->setCount(item.getCellRef().getCount());
}
mItemView->update();

@ -129,7 +129,7 @@ namespace MWGui
{
if (stacks(*it, item.mBase))
{
int quantity = it->mRef->mData.getCount(false);
int quantity = it->mRef->mRef.getCount(false);
// If this is a restocking quantity, just don't remove it
if (quantity < 0 && mTrading)
toRemove += quantity;
@ -144,11 +144,11 @@ namespace MWGui
{
if (stacks(source, item.mBase))
{
int refCount = source.getRefData().getCount();
int refCount = source.getCellRef().getCount();
if (refCount - toRemove <= 0)
MWBase::Environment::get().getWorld()->deleteObject(source);
else
source.getRefData().setCount(std::max(0, refCount - toRemove));
source.getCellRef().setCount(std::max(0, refCount - toRemove));
toRemove -= refCount;
if (toRemove <= 0)
return;
@ -176,7 +176,7 @@ namespace MWGui
if (stacks(*it, itemStack.mBase))
{
// we already have an item stack of this kind, add to it
itemStack.mCount += it->getRefData().getCount();
itemStack.mCount += it->getCellRef().getCount();
found = true;
break;
}
@ -185,7 +185,7 @@ namespace MWGui
if (!found)
{
// no stack yet, create one
ItemStack newItem(*it, this, it->getRefData().getCount());
ItemStack newItem(*it, this, it->getCellRef().getCount());
mItems.push_back(newItem);
}
}
@ -198,7 +198,7 @@ namespace MWGui
if (stacks(source, itemStack.mBase))
{
// we already have an item stack of this kind, add to it
itemStack.mCount += source.getRefData().getCount();
itemStack.mCount += source.getCellRef().getCount();
found = true;
break;
}
@ -207,7 +207,7 @@ namespace MWGui
if (!found)
{
// no stack yet, create one
ItemStack newItem(source, this, source.getRefData().getCount());
ItemStack newItem(source, this, source.getCellRef().getCount());
mItems.push_back(newItem);
}
}

@ -126,7 +126,7 @@ namespace MWGui
void DragAndDrop::onFrame()
{
if (mIsOnDragAndDrop && mItem.mBase.getRefData().getCount() == 0)
if (mIsOnDragAndDrop && mItem.mBase.getCellRef().getCount() == 0)
finish();
}

@ -373,7 +373,7 @@ namespace MWGui
{
MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("enchant fail"));
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage34}");
if (!mEnchanting.getGem().isEmpty() && !mEnchanting.getGem().getRefData().getCount())
if (!mEnchanting.getGem().isEmpty() && !mEnchanting.getGem().getCellRef().getCount())
{
setSoulGem(MWWorld::Ptr());
mEnchanting.nextCastStyle();

@ -115,7 +115,7 @@ namespace MWGui
if (!item.getClass().showsInInventory(item))
continue;
ItemStack newItem(item, this, item.getRefData().getCount());
ItemStack newItem(item, this, item.getCellRef().getCount());
if (mActor.getClass().hasInventoryStore(mActor))
{

@ -560,7 +560,7 @@ namespace MWGui
if (mEquippedStackableCount.has_value())
{
// the count to unequip
int count = ptr.getRefData().getCount() - mDragAndDrop->mDraggedCount - mEquippedStackableCount.value();
int count = ptr.getCellRef().getCount() - mDragAndDrop->mDraggedCount - mEquippedStackableCount.value();
if (count > 0)
{
MWWorld::InventoryStore& invStore = mPtr.getClass().getInventoryStore(mPtr);
@ -604,7 +604,7 @@ namespace MWGui
// Save the currently equipped count before useItem()
if (slotIt != invStore.end() && slotIt->getCellRef().getRefId() == ptr.getCellRef().getRefId())
mEquippedStackableCount = slotIt->getRefData().getCount();
mEquippedStackableCount = slotIt->getCellRef().getCount();
else
mEquippedStackableCount = 0;
}
@ -735,7 +735,7 @@ namespace MWGui
if (!object.getClass().hasToolTip(object))
return;
int count = object.getRefData().getCount();
int count = object.getCellRef().getCount();
if (object.getClass().isGold(object))
count *= object.getClass().getValue(object);
@ -755,8 +755,7 @@ namespace MWGui
// add to player inventory
// can't use ActionTake here because we need an MWWorld::Ptr to the newly inserted object
MWWorld::Ptr newObject
= *player.getClass().getContainerStore(player).add(object, object.getRefData().getCount());
MWWorld::Ptr newObject = *player.getClass().getContainerStore(player).add(object, count);
// remove from world
MWBase::Environment::get().getWorld()->deleteObject(object);

@ -58,7 +58,7 @@ namespace MWGui
MWWorld::Ptr ItemModel::moveItem(const ItemStack& item, size_t count, ItemModel* otherModel, bool allowAutoEquip)
{
MWWorld::Ptr ret = MWWorld::Ptr();
if (static_cast<size_t>(item.mBase.getRefData().getCount()) <= count)
if (static_cast<size_t>(item.mBase.getCellRef().getCount()) <= count)
{
// We are moving the full stack
ret = otherModel->addItem(item, count, allowAutoEquip);

@ -85,7 +85,7 @@ namespace MWGui
{
MWWorld::Ptr item = *mKey[index].button->getUserData<MWWorld::Ptr>();
// Make sure the item is available and is not broken
if (item.isEmpty() || item.getRefData().getCount() < 1
if (item.isEmpty() || item.getCellRef().getCount() < 1
|| (item.getClass().hasItemHealth(item) && item.getClass().getItemHealth(item) <= 0))
{
// Try searching for a compatible replacement
@ -383,12 +383,12 @@ namespace MWGui
item = nullptr;
// check the item is available and not broken
if (item.isEmpty() || item.getRefData().getCount() < 1
if (item.isEmpty() || item.getCellRef().getCount() < 1
|| (item.getClass().hasItemHealth(item) && item.getClass().getItemHealth(item) <= 0))
{
item = store.findReplacement(key->id);
if (item.isEmpty() || item.getRefData().getCount() < 1)
if (item.isEmpty() || item.getCellRef().getCount() < 1)
{
MWBase::Environment::get().getWindowManager()->messageBox("#{sQuickMenu5} " + key->name);

@ -75,7 +75,7 @@ namespace MWGui
mChargeLabel->setCaptionWithReplacing("#{sCharges} " + MyGUI::utility::toString(creature->mData.mSoul));
bool toolBoxVisible = (gem.getRefData().getCount() != 0);
bool toolBoxVisible = gem.getCellRef().getCount() != 0;
mGemBox->setVisible(toolBoxVisible);
mGemBox->setUserString("Hidden", toolBoxVisible ? "false" : "true");

@ -2,14 +2,14 @@
namespace MWGui
{
ReferenceInterface::ReferenceInterface() {}
ReferenceInterface::ReferenceInterface() = default;
ReferenceInterface::~ReferenceInterface() {}
ReferenceInterface::~ReferenceInterface() = default;
void ReferenceInterface::checkReferenceAvailable()
{
// check if count of the reference has become 0
if (!mPtr.isEmpty() && mPtr.getRefData().getCount() == 0)
if (!mPtr.isEmpty() && mPtr.getCellRef().getCount() == 0)
{
mPtr = MWWorld::Ptr();
onReferenceUnavailable();

@ -86,7 +86,7 @@ namespace MWGui
mUsesLabel->setCaptionWithReplacing("#{sUses} " + MyGUI::utility::toString(uses));
mQualityLabel->setCaptionWithReplacing("#{sQuality} " + qualityStr.str());
bool toolBoxVisible = (mRepair.getTool().getRefData().getCount() != 0);
bool toolBoxVisible = (mRepair.getTool().getCellRef().getCount() != 0);
mToolBox->setVisible(toolBoxVisible);
mToolBox->setUserString("Hidden", toolBoxVisible ? "false" : "true");
@ -142,7 +142,7 @@ namespace MWGui
void Repair::onRepairItem(MyGUI::Widget* /*sender*/, const MWWorld::Ptr& ptr)
{
if (!mRepair.getTool().getRefData().getCount())
if (!mRepair.getTool().getCellRef().getCount())
return;
mRepair.repair(ptr);

@ -137,7 +137,7 @@ namespace MWGui
newSpell.mItem = item;
newSpell.mId = item.getCellRef().getRefId();
newSpell.mName = item.getClass().getName(item);
newSpell.mCount = item.getRefData().getCount();
newSpell.mCount = item.getCellRef().getCount();
newSpell.mType = Spell::Type_EnchantedItem;
newSpell.mSelected = invStore.getSelectedEnchantItem() == it;

@ -120,7 +120,7 @@ namespace MWGui
tooltipSize = createToolTip(info, checkOwned());
}
else
tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), true);
tooltipSize = getToolTipViaPtr(mFocusObject.getCellRef().getCount(), true);
MyGUI::IntPoint tooltipPosition = MyGUI::InputManager::getInstance().getMousePosition();
position(tooltipPosition, tooltipSize, viewSize);
@ -187,7 +187,7 @@ namespace MWGui
if (mFocusObject.isEmpty())
return;
tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), false, checkOwned());
tooltipSize = getToolTipViaPtr(mFocusObject.getCellRef().getCount(), false, checkOwned());
}
else if (type == "ItemModelIndex")
{
@ -211,7 +211,7 @@ namespace MWGui
mFocusObject = item;
if (!mFocusObject.isEmpty())
tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), false);
tooltipSize = getToolTipViaPtr(mFocusObject.getCellRef().getCount(), false);
}
else if (type == "Spell")
{
@ -306,7 +306,7 @@ namespace MWGui
{
if (!mFocusObject.isEmpty())
{
MyGUI::IntSize tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), true, checkOwned());
MyGUI::IntSize tooltipSize = getToolTipViaPtr(mFocusObject.getCellRef().getCount(), true, checkOwned());
setCoord(viewSize.width / 2 - tooltipSize.width / 2,
std::max(0, int(mFocusToolTipY * viewSize.height - tooltipSize.height)), tooltipSize.width,

@ -121,7 +121,7 @@ namespace MWLua
cell.mStore->load();
ObjectIdList res = std::make_shared<std::vector<ObjectId>>();
auto visitor = [&](const MWWorld::Ptr& ptr) {
if (ptr.getRefData().isDeleted())
if (ptr.mRef->isDeleted())
return true;
MWBase::Environment::get().getWorldModel()->registerPtr(ptr);
if (getLiveCellRefType(ptr.mRef) == ptr.getType())

@ -140,9 +140,8 @@ namespace MWLua
mObjectLists.update();
std::erase_if(mActiveLocalScripts, [](const LocalScripts* l) {
return l->getPtrOrEmpty().isEmpty() || l->getPtrOrEmpty().getRefData().isDeleted();
});
std::erase_if(mActiveLocalScripts,
[](const LocalScripts* l) { return l->getPtrOrEmpty().isEmpty() || l->getPtrOrEmpty().mRef->isDeleted(); });
mGlobalScripts.statsNextFrame();
for (LocalScripts* scripts : mActiveLocalScripts)

@ -124,7 +124,7 @@ namespace MWLua
newPtr = cls.moveToCell(ptr, *destCell, toPos(pos, rot));
ptr.getCellRef().unsetRefNum();
ptr.getRefData().setLuaScripts(nullptr);
ptr.getRefData().setCount(0);
ptr.getCellRef().setCount(0);
ESM::RefId script = cls.getScript(newPtr);
if (!script.empty())
world->getLocalScripts().add(script, newPtr);
@ -256,7 +256,7 @@ namespace MWLua
[types = getTypeToPackageTable(context.mLua->sol())](
const ObjectT& o) mutable { return types[getLiveCellRefType(o.ptr().mRef)]; });
objectT["count"] = sol::readonly_property([](const ObjectT& o) { return o.ptr().getRefData().getCount(); });
objectT["count"] = sol::readonly_property([](const ObjectT& o) { return o.ptr().getCellRef().getCount(); });
objectT[sol::meta_function::equal_to] = [](const ObjectT& a, const ObjectT& b) { return a.id() == b.id(); };
objectT[sol::meta_function::to_string] = &ObjectT::toString;
objectT["sendEvent"] = [context](const ObjectT& dest, std::string eventName, const sol::object& eventData) {
@ -340,10 +340,10 @@ namespace MWLua
auto isEnabled = [](const ObjectT& o) { return o.ptr().getRefData().isEnabled(); };
auto setEnabled = [context](const GObject& object, bool enable) {
if (enable && object.ptr().getRefData().isDeleted())
if (enable && object.ptr().mRef->isDeleted())
throw std::runtime_error("Object is removed");
context.mLuaManager->addAction([object, enable] {
if (object.ptr().getRefData().isDeleted())
if (object.ptr().mRef->isDeleted())
return;
if (object.ptr().isInCell())
{
@ -417,20 +417,20 @@ namespace MWLua
using DelayedRemovalFn = std::function<void(MWWorld::Ptr)>;
auto removeFn = [](const MWWorld::Ptr ptr, int countToRemove) -> std::optional<DelayedRemovalFn> {
int rawCount = ptr.getRefData().getCount(false);
int rawCount = ptr.getCellRef().getCount(false);
int currentCount = std::abs(rawCount);
int signedCountToRemove = (rawCount < 0 ? -1 : 1) * countToRemove;
if (countToRemove <= 0 || countToRemove > currentCount)
throw std::runtime_error("Can't remove " + std::to_string(countToRemove) + " of "
+ std::to_string(currentCount) + " items");
ptr.getRefData().setCount(rawCount - signedCountToRemove); // Immediately change count
ptr.getCellRef().setCount(rawCount - signedCountToRemove); // Immediately change count
if (!ptr.getContainerStore() && currentCount > countToRemove)
return std::nullopt;
// Delayed action to trigger side effects
return [signedCountToRemove](MWWorld::Ptr ptr) {
// Restore the original count
ptr.getRefData().setCount(ptr.getRefData().getCount(false) + signedCountToRemove);
ptr.getCellRef().setCount(ptr.getCellRef().getCount(false) + signedCountToRemove);
// And now remove properly
if (ptr.getContainerStore())
ptr.getContainerStore()->remove(ptr, std::abs(signedCountToRemove), false);
@ -443,7 +443,7 @@ namespace MWLua
};
objectT["remove"] = [removeFn, context](const GObject& object, sol::optional<int> count) {
std::optional<DelayedRemovalFn> delayed
= removeFn(object.ptr(), count.value_or(object.ptr().getRefData().getCount()));
= removeFn(object.ptr(), count.value_or(object.ptr().getCellRef().getCount()));
if (delayed.has_value())
context.mLuaManager->addAction([fn = *delayed, object] { fn(object.ptr()); });
};
@ -463,7 +463,7 @@ namespace MWLua
};
objectT["moveInto"] = [removeFn, context](const GObject& object, const sol::object& dest) {
const MWWorld::Ptr& ptr = object.ptr();
int count = ptr.getRefData().getCount();
int count = ptr.getCellRef().getCount();
MWWorld::Ptr destPtr;
if (dest.is<GObject>())
destPtr = dest.as<GObject>().ptr();
@ -474,9 +474,9 @@ namespace MWLua
std::optional<DelayedRemovalFn> delayedRemovalFn = removeFn(ptr, count);
context.mLuaManager->addAction([item = object, count, cont = GObject(destPtr), delayedRemovalFn] {
const MWWorld::Ptr& oldPtr = item.ptr();
auto& refData = oldPtr.getRefData();
auto& refData = oldPtr.getCellRef();
refData.setCount(count); // temporarily undo removal to run ContainerStore::add
refData.enable();
oldPtr.getRefData().enable();
cont.ptr().getClass().getContainerStore(cont.ptr()).add(oldPtr, count, false);
refData.setCount(0);
if (delayedRemovalFn.has_value())
@ -487,7 +487,7 @@ namespace MWLua
const osg::Vec3f& pos, const sol::object& options) {
MWWorld::CellStore* cell = findCell(cellOrName, pos);
MWWorld::Ptr ptr = object.ptr();
int count = ptr.getRefData().getCount();
int count = ptr.getCellRef().getCount();
if (count == 0)
throw std::runtime_error("Object is either removed or already in the process of teleporting");
osg::Vec3f rot = ptr.getRefData().getPosition().asRotationVec3();
@ -508,9 +508,9 @@ namespace MWLua
context.mLuaManager->addAction(
[object, cell, pos, rot, count, delayedRemovalFn, placeOnGround] {
MWWorld::Ptr oldPtr = object.ptr();
oldPtr.getRefData().setCount(count);
oldPtr.getCellRef().setCount(count);
MWWorld::Ptr newPtr = oldPtr.getClass().moveToCell(oldPtr, *cell);
oldPtr.getRefData().setCount(0);
oldPtr.getCellRef().setCount(0);
newPtr.getRefData().disable();
teleportNotPlayer(newPtr, cell, pos, rot, placeOnGround);
delayedRemovalFn(oldPtr);
@ -522,10 +522,10 @@ namespace MWLua
[cell, pos, rot, placeOnGround] { teleportPlayer(cell, pos, rot, placeOnGround); });
else
{
ptr.getRefData().setCount(0);
ptr.getCellRef().setCount(0);
context.mLuaManager->addAction(
[object, cell, pos, rot, count, placeOnGround] {
object.ptr().getRefData().setCount(count);
object.ptr().getCellRef().setCount(count);
teleportNotPlayer(object.ptr(), cell, pos, rot, placeOnGround);
},
"TeleportAction");

@ -37,7 +37,7 @@ namespace MWLua
itemPtr = MWBase::Environment::get().getWorldModel()->getPtr(std::get<ObjectId>(item));
if (old_it != store.end() && *old_it == itemPtr)
return { old_it, true }; // already equipped
if (itemPtr.isEmpty() || itemPtr.getRefData().getCount() == 0
if (itemPtr.isEmpty() || itemPtr.getCellRef().getCount() == 0
|| itemPtr.getContainerStore() != static_cast<const MWWorld::ContainerStore*>(&store))
{
Log(Debug::Warning) << "Object" << std::get<ObjectId>(item).toString() << " is not in inventory";
@ -51,7 +51,7 @@ namespace MWLua
if (old_it != store.end() && old_it->getCellRef().getRefId() == recordId)
return { old_it, true }; // already equipped
itemPtr = store.search(recordId);
if (itemPtr.isEmpty() || itemPtr.getRefData().getCount() == 0)
if (itemPtr.isEmpty() || itemPtr.getCellRef().getCount() == 0)
{
Log(Debug::Warning) << "There is no object with recordId='" << stringId << "' in inventory";
return { store.end(), false };

@ -15,7 +15,7 @@ namespace MWLua
item["setEnchantmentCharge"]
= [](const GObject& object, float charge) { object.ptr().getCellRef().setEnchantmentCharge(charge); };
item["isRestocking"]
= [](const Object& object) -> bool { return object.ptr().getRefData().getCount(false) < 0; };
= [](const Object& object) -> bool { return object.ptr().getCellRef().getCount(false) < 0; };
addItemDataBindings(item, context);
}

@ -30,7 +30,7 @@ namespace MWMechanics
// Stop if the target doesn't exist
// Really we should be checking whether the target is currently registered with the MechanicsManager
if (target == MWWorld::Ptr() || !target.getRefData().getCount() || !target.getRefData().isEnabled())
if (target == MWWorld::Ptr() || !target.getCellRef().getCount() || !target.getRefData().isEnabled())
return true;
// Turn to target and move to it directly, without pathfinding.

@ -115,7 +115,7 @@ namespace MWMechanics
if (target.isEmpty())
return true;
if (!target.getRefData().getCount()
if (!target.getCellRef().getCount()
|| !target.getRefData().isEnabled() // Really we should be checking whether the target is currently
// registered with the MechanicsManager
|| target.getClass().getCreatureStats(target).isDead())
@ -478,8 +478,7 @@ namespace MWMechanics
MWWorld::Ptr AiCombat::getTarget() const
{
if (mCachedTarget.isEmpty() || mCachedTarget.getRefData().isDeleted()
|| !mCachedTarget.getRefData().isEnabled())
if (mCachedTarget.isEmpty() || mCachedTarget.mRef->isDeleted() || !mCachedTarget.getRefData().isEnabled())
{
mCachedTarget = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId);
}

@ -99,7 +99,7 @@ namespace MWMechanics
// Target is not here right now, wait for it to return
// Really we should be checking whether the target is currently registered with the MechanicsManager
if (target == MWWorld::Ptr() || !target.getRefData().getCount() || !target.getRefData().isEnabled())
if (target == MWWorld::Ptr() || !target.getCellRef().getCount() || !target.getRefData().isEnabled())
return false;
actor.getClass().getCreatureStats(actor).setDrawState(DrawState::Nothing);

@ -63,7 +63,7 @@ MWWorld::Ptr MWMechanics::AiPackage::getTarget() const
{
if (!mCachedTarget.isEmpty())
{
if (mCachedTarget.getRefData().isDeleted() || !mCachedTarget.getRefData().isEnabled())
if (mCachedTarget.mRef->isDeleted() || !mCachedTarget.getRefData().isEnabled())
mCachedTarget = MWWorld::Ptr();
else
return mCachedTarget;

@ -38,7 +38,7 @@ namespace MWMechanics
// Stop if the target doesn't exist
// Really we should be checking whether the target is currently registered with the MechanicsManager
if (target == MWWorld::Ptr() || !target.getRefData().getCount() || !target.getRefData().isEnabled())
if (target == MWWorld::Ptr() || !target.getCellRef().getCount() || !target.getRefData().isEnabled())
return true;
if (isTargetMagicallyHidden(target)
@ -83,7 +83,7 @@ namespace MWMechanics
{
if (!mCachedTarget.isEmpty())
{
if (mCachedTarget.getRefData().isDeleted() || !mCachedTarget.getRefData().isEnabled())
if (mCachedTarget.mRef->isDeleted() || !mCachedTarget.getRefData().isEnabled())
mCachedTarget = MWWorld::Ptr();
else
return mCachedTarget;

@ -289,7 +289,7 @@ void MWMechanics::Alchemy::removeIngredients()
{
iter->getContainerStore()->remove(*iter, 1);
if (iter->getRefData().getCount() < 1)
if (iter->getCellRef().getCount() < 1)
*iter = MWWorld::Ptr();
}
@ -369,7 +369,7 @@ int MWMechanics::Alchemy::countPotionsToBrew() const
for (TIngredientsIterator iter(beginIngredients()); iter != endIngredients(); ++iter)
if (!iter->isEmpty())
{
int count = iter->getRefData().getCount();
int count = iter->getCellRef().getCount();
if ((count > 0 && count < toBrew) || toBrew < 0)
toBrew = count;
}

@ -1022,7 +1022,7 @@ namespace MWMechanics
if (stolenIt == mStolenItems.end())
continue;
OwnerMap& owners = stolenIt->second;
int itemCount = it->getRefData().getCount();
int itemCount = it->getCellRef().getCount();
for (OwnerMap::iterator ownerIt = owners.begin(); ownerIt != owners.end();)
{
int toRemove = std::min(itemCount, ownerIt->second);
@ -1034,7 +1034,7 @@ namespace MWMechanics
++ownerIt;
}
int toMove = it->getRefData().getCount() - itemCount;
int toMove = it->getCellRef().getCount() - itemCount;
containerStore.add(*it, toMove);
store.remove(*it, toMove);
@ -1084,15 +1084,21 @@ namespace MWMechanics
}
}
if (!(item.getCellRef().getRefId() == MWWorld::ContainerStore::sGoldId))
const bool isGold = item.getClass().isGold(item);
if (!isGold)
{
if (victim.isEmpty()
|| (victim.getClass().isActor() && victim.getRefData().getCount() > 0
|| (victim.getClass().isActor() && victim.getCellRef().getCount() > 0
&& !victim.getClass().getCreatureStats(victim).isDead()))
mStolenItems[item.getCellRef().getRefId()][owner] += count;
}
if (alarm)
commitCrime(ptr, victim, OT_Theft, ownerCellRef->getFaction(), item.getClass().getValue(item) * count);
{
int value = count;
if (!isGold)
value *= item.getClass().getValue(item);
commitCrime(ptr, victim, OT_Theft, ownerCellRef->getFaction(), value);
}
}
bool MechanicsManager::commitCrime(const MWWorld::Ptr& player, const MWWorld::Ptr& victim, OffenseType type,

@ -38,7 +38,7 @@ namespace MWMechanics
bool rechargeItem(const MWWorld::Ptr& item, const MWWorld::Ptr& gem)
{
if (!gem.getRefData().getCount())
if (!gem.getCellRef().getCount())
return false;
MWWorld::Ptr player = MWMechanics::getPlayer();
@ -87,7 +87,7 @@ namespace MWMechanics
player.getClass().skillUsageSucceeded(player, ESM::Skill::Enchant, 0);
gem.getContainerStore()->remove(gem, 1);
if (gem.getRefData().getCount() == 0)
if (gem.getCellRef().getCount() == 0)
{
std::string message = MWBase::Environment::get()
.getESMStore()

@ -426,7 +426,7 @@ namespace MWRender
const auto& weaponType = MWMechanics::getWeaponType(type);
if (weaponType->mWeaponClass == ESM::WeaponType::Thrown)
{
ammoCount = ammo->getRefData().getCount();
ammoCount = ammo->getCellRef().getCount();
osg::Group* throwingWeaponNode = getBoneByName(weaponType->mAttachBone);
if (throwingWeaponNode && throwingWeaponNode->getNumChildren())
ammoCount--;
@ -439,7 +439,7 @@ namespace MWRender
if (ammo == inv.end())
return;
ammoCount = ammo->getRefData().getCount();
ammoCount = ammo->getCellRef().getCount();
bool arrowAttached = isArrowAttached();
if (arrowAttached)
ammoCount--;
@ -514,7 +514,7 @@ namespace MWRender
ItemLightMap::iterator iter = mItemLights.find(item);
if (iter != mItemLights.end())
{
if (!item.getRefData().getCount())
if (!item.getCellRef().getCount())
{
removeHiddenItemLight(item);
}

@ -109,7 +109,7 @@ namespace MWScript
return;
if (item == "gold_005" || item == "gold_010" || item == "gold_025" || item == "gold_100")
item = ESM::RefId::stringRefId("gold_001");
item = MWWorld::ContainerStore::sGoldId;
// Check if "item" can be placed in a container
MWWorld::ManualRef manualRef(*MWBase::Environment::get().getESMStore(), item, 1);
@ -195,7 +195,7 @@ namespace MWScript
runtime.pop();
if (item == "gold_005" || item == "gold_010" || item == "gold_025" || item == "gold_100")
item = ESM::RefId::stringRefId("gold_001");
item = MWWorld::ContainerStore::sGoldId;
MWWorld::ContainerStore& store = ptr.getClass().getContainerStore(ptr);
@ -231,7 +231,7 @@ namespace MWScript
return;
if (item == "gold_005" || item == "gold_010" || item == "gold_025" || item == "gold_100")
item = ESM::RefId::stringRefId("gold_001");
item = MWWorld::ContainerStore::sGoldId;
// Explicit calls to non-unique actors affect the base record
if (!R::implicit && ptr.getClass().isActor()
@ -460,7 +460,7 @@ namespace MWScript
it != invStore.cend(); ++it)
{
if (it->getCellRef().getSoul() == name)
count += it->getRefData().getCount();
count += it->getCellRef().getCount();
}
runtime.push(count);
}

@ -715,7 +715,7 @@ namespace MWScript
MWWorld::ConstContainerStoreIterator it = store.getSlot(slot);
if (it != store.end() && it->getCellRef().getRefId() == item)
{
numNotEquipped -= it->getRefData().getCount();
numNotEquipped -= it->getCellRef().getCount();
}
}
@ -724,7 +724,7 @@ namespace MWScript
MWWorld::ContainerStoreIterator it = store.getSlot(slot);
if (it != store.end() && it->getCellRef().getRefId() == item)
{
int numToRemove = std::min(amount - numNotEquipped, it->getRefData().getCount());
int numToRemove = std::min(amount - numNotEquipped, it->getCellRef().getCount());
store.unequipItemQuantity(*it, numToRemove);
numNotEquipped += numToRemove;
}
@ -1418,7 +1418,7 @@ namespace MWScript
if (ptr.getRefData().isDeletedByContentFile())
msg << "[Deleted by content file]" << std::endl;
if (!ptr.getRefData().getCount())
if (!ptr.getCellRef().getCount())
msg << "[Deleted]" << std::endl;
msg << "RefID: " << ptr.getCellRef().getRefId() << std::endl;

@ -37,7 +37,7 @@ namespace MWWorld
if (!it->getClass().showsInInventory(*it))
continue;
int itemCount = it->getRefData().getCount();
int itemCount = it->getCellRef().getCount();
// Note: it is important to check for crime before move an item from container. Otherwise owner check will
// not work for a last item in the container - empty harvested containers are considered as "allowed to
// use".

@ -30,10 +30,12 @@ namespace MWWorld
}
}
MWBase::Environment::get().getMechanicsManager()->itemTaken(
actor, getTarget(), MWWorld::Ptr(), getTarget().getRefData().getCount());
MWWorld::Ptr newitem
= *actor.getClass().getContainerStore(actor).add(getTarget(), getTarget().getRefData().getCount());
int count = getTarget().getCellRef().getCount();
if (getTarget().getClass().isGold(getTarget()))
count *= getTarget().getClass().getValue(getTarget());
MWBase::Environment::get().getMechanicsManager()->itemTaken(actor, getTarget(), MWWorld::Ptr(), count);
MWWorld::Ptr newitem = *actor.getClass().getContainerStore(actor).add(getTarget(), count);
MWBase::Environment::get().getWorld()->deleteObject(getTarget());
setTarget(newitem);
}

@ -377,17 +377,19 @@ namespace MWWorld
}
}
void CellRef::setGoldValue(int value)
void CellRef::setCount(int value)
{
if (value != getGoldValue())
if (value != getCount(false))
{
mChanged = true;
std::visit(ESM::VisitOverload{
[&](ESM4::Reference& /*ref*/) {},
[&](ESM4::ActorCharacter&) {},
[&](ESM::CellRef& ref) { ref.mGoldValue = value; },
[&](ESM4::Reference& ref) { ref.mCount = value; },
[&](ESM4::ActorCharacter& ref) { ref.mCount = value; },
[&](ESM::CellRef& ref) { ref.mCount = value; },
},
mCellRef.mVariant);
if (value == 0)
MWBase::Environment::get().getWorld()->removeRefScript(this);
}
}

@ -231,18 +231,20 @@ namespace MWWorld
}
void setTrap(const ESM::RefId& trap);
// This is 5 for Gold_005 references, 100 for Gold_100 and so on.
int getGoldValue() const
int getCount(bool absolute = true) const
{
struct Visitor
{
int operator()(const ESM::CellRef& ref) { return ref.mGoldValue; }
int operator()(const ESM4::Reference& /*ref*/) { return 0; }
int operator()(const ESM4::ActorCharacter&) { throw std::logic_error("Not applicable"); }
int operator()(const ESM::CellRef& ref) { return ref.mCount; }
int operator()(const ESM4::Reference& ref) { return ref.mCount; }
int operator()(const ESM4::ActorCharacter& ref) { return ref.mCount; }
};
return std::visit(Visitor(), mCellRef.mVariant);
int count = std::visit(Visitor(), mCellRef.mVariant);
if (absolute)
return std::abs(count);
return count;
}
void setGoldValue(int value);
void setCount(int value);
// Write the content of this CellRef into the given ObjectState
void writeState(ESM::ObjectState& state) const;

@ -152,7 +152,7 @@ namespace
if (toIgnore.find(&*iter) != toIgnore.end())
continue;
if (actor.getClass().getCreatureStats(actor).matchesActorId(actorId) && actor.getRefData().getCount() > 0)
if (actor.getClass().getCreatureStats(actor).matchesActorId(actorId) && actor.getCellRef().getCount() > 0)
return actor;
}
@ -175,7 +175,7 @@ namespace
// Reference that came from a content file and has not been changed -> ignore
continue;
}
if (liveCellRef.mData.getCount() == 0 && !liveCellRef.mRef.hasContentFile())
if (liveCellRef.mRef.getCount() == 0 && !liveCellRef.mRef.hasContentFile())
{
// Deleted reference that did not come from a content file -> ignore
continue;
@ -201,8 +201,8 @@ namespace
{
for (auto& item : state.mInventory.mItems)
{
if (item.mCount > 0 && baseItem.mItem == item.mRef.mRefID)
item.mCount = -item.mCount;
if (item.mRef.mCount > 0 && baseItem.mItem == item.mRef.mRefID)
item.mRef.mCount = -item.mRef.mCount;
}
}
}
@ -298,9 +298,9 @@ namespace
// instance is invalid. But non-storable item are always stored in saves together with their original cell.
// If a non-storable item references a content file, but is not found in this content file,
// we should drop it. Likewise if this stack is empty.
if (!MWWorld::ContainerStore::isStorableType<T>() || !state.mCount)
if (!MWWorld::ContainerStore::isStorableType<T>() || !state.mRef.mCount)
{
if (state.mCount)
if (state.mRef.mCount)
Log(Debug::Warning) << "Warning: Dropping reference to " << state.mRef.mRefID
<< " (invalid content file link)";
return;
@ -676,7 +676,7 @@ namespace MWWorld
MWWorld::Ptr actor(base, this);
if (!actor.getClass().isActor())
continue;
if (actor.getClass().getCreatureStats(actor).matchesActorId(id) && actor.getRefData().getCount() > 0)
if (actor.getClass().getCreatureStats(actor).matchesActorId(id) && actor.getCellRef().getCount() > 0)
return actor;
}
@ -1042,7 +1042,7 @@ namespace MWWorld
for (const auto& [base, store] : mMovedToAnotherCell)
{
ESM::RefNum refNum = base->mRef.getRefNum();
if (base->mData.isDeleted() && !refNum.hasContentFile())
if (base->isDeleted() && !refNum.hasContentFile())
continue; // filtered out in writeReferenceCollection
ESM::RefId movedTo = store->getCell()->getId();
@ -1168,20 +1168,18 @@ namespace MWWorld
{
if (mState == State_Loaded)
{
for (CellRefList<ESM::Creature>::List::iterator it(get<ESM::Creature>().mList.begin());
it != get<ESM::Creature>().mList.end(); ++it)
for (MWWorld::LiveCellRef<ESM::Creature>& creature : get<ESM::Creature>().mList)
{
Ptr ptr = getCurrentPtr(&*it);
if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0)
Ptr ptr = getCurrentPtr(&creature);
if (!ptr.isEmpty() && ptr.getCellRef().getCount() > 0)
{
MWBase::Environment::get().getMechanicsManager()->restoreDynamicStats(ptr, hours, true);
}
}
for (CellRefList<ESM::NPC>::List::iterator it(get<ESM::NPC>().mList.begin());
it != get<ESM::NPC>().mList.end(); ++it)
for (MWWorld::LiveCellRef<ESM::NPC>& npc : get<ESM::NPC>().mList)
{
Ptr ptr = getCurrentPtr(&*it);
if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0)
Ptr ptr = getCurrentPtr(&npc);
if (!ptr.isEmpty() && ptr.getCellRef().getCount() > 0)
{
MWBase::Environment::get().getMechanicsManager()->restoreDynamicStats(ptr, hours, true);
}
@ -1196,29 +1194,26 @@ namespace MWWorld
if (mState == State_Loaded)
{
for (CellRefList<ESM::Creature>::List::iterator it(get<ESM::Creature>().mList.begin());
it != get<ESM::Creature>().mList.end(); ++it)
for (MWWorld::LiveCellRef<ESM::Creature>& creature : get<ESM::Creature>().mList)
{
Ptr ptr = getCurrentPtr(&*it);
if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0)
Ptr ptr = getCurrentPtr(&creature);
if (!ptr.isEmpty() && ptr.getCellRef().getCount() > 0)
{
ptr.getClass().getContainerStore(ptr).rechargeItems(duration);
}
}
for (CellRefList<ESM::NPC>::List::iterator it(get<ESM::NPC>().mList.begin());
it != get<ESM::NPC>().mList.end(); ++it)
for (MWWorld::LiveCellRef<ESM::NPC>& npc : get<ESM::NPC>().mList)
{
Ptr ptr = getCurrentPtr(&*it);
if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0)
Ptr ptr = getCurrentPtr(&npc);
if (!ptr.isEmpty() && ptr.getCellRef().getCount() > 0)
{
ptr.getClass().getContainerStore(ptr).rechargeItems(duration);
}
}
for (CellRefList<ESM::Container>::List::iterator it(get<ESM::Container>().mList.begin());
it != get<ESM::Container>().mList.end(); ++it)
for (MWWorld::LiveCellRef<ESM::Container>& container : get<ESM::Container>().mList)
{
Ptr ptr = getCurrentPtr(&*it);
if (!ptr.isEmpty() && ptr.getRefData().getCustomData() != nullptr && ptr.getRefData().getCount() > 0
Ptr ptr = getCurrentPtr(&container);
if (!ptr.isEmpty() && ptr.getRefData().getCustomData() != nullptr && ptr.getCellRef().getCount() > 0
&& ptr.getClass().getContainerStore(ptr).isResolved())
{
ptr.getClass().getContainerStore(ptr).rechargeItems(duration);
@ -1262,7 +1257,7 @@ namespace MWWorld
}
forEachType<ESM::CreatureLevList>([](Ptr ptr) {
// no need to clearCorpse, handled as part of get<ESM::Creature>()
if (!ptr.getRefData().isDeleted())
if (!ptr.mRef->isDeleted())
ptr.getClass().respawn(ptr);
return true;
});
@ -1290,7 +1285,7 @@ namespace MWWorld
for (auto& item : list)
{
Ptr ptr = getCurrentPtr(&item);
if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0)
if (!ptr.isEmpty() && ptr.getCellRef().getCount() > 0)
{
checkItem(ptr);
}

@ -118,7 +118,7 @@ namespace MWWorld
/// scripting compatibility, and the fact that objects may be "un-deleted" in the original game).
static bool isAccessible(const MWWorld::RefData& refdata, const MWWorld::CellRef& cref)
{
return !refdata.isDeletedByContentFile() && (cref.hasContentFile() || refdata.getCount() > 0);
return !refdata.isDeletedByContentFile() && (cref.hasContentFile() || cref.getCount() > 0);
}
/// Moves object from this cell to the given cell.

@ -373,7 +373,7 @@ namespace MWWorld
{
Ptr newPtr = copyToCellImpl(ptr, cell);
newPtr.getCellRef().unsetRefNum(); // This RefNum is only valid within the original cell of the reference
newPtr.getRefData().setCount(count);
newPtr.getCellRef().setCount(count);
newPtr.getRefData().setLuaScripts(nullptr);
MWBase::Environment::get().getWorldModel()->registerPtr(newPtr);
return newPtr;

@ -51,7 +51,7 @@ namespace
for (const MWWorld::LiveCellRef<T>& liveCellRef : cellRefList.mList)
{
if (const int count = liveCellRef.mData.getCount(); count > 0)
if (const int count = liveCellRef.mRef.getCount(); count > 0)
sum += count * liveCellRef.mBase->mData.mWeight;
}
@ -65,7 +65,7 @@ namespace
for (MWWorld::LiveCellRef<T>& liveCellRef : list.mList)
{
if ((liveCellRef.mBase->mId == id) && liveCellRef.mData.getCount())
if ((liveCellRef.mBase->mId == id) && liveCellRef.mRef.getCount())
{
MWWorld::Ptr ptr(&liveCellRef, nullptr);
ptr.setContainerStore(store);
@ -132,7 +132,7 @@ void MWWorld::ContainerStore::storeStates(
{
for (const LiveCellRef<T>& liveCellRef : collection.mList)
{
if (liveCellRef.mData.getCount() == 0)
if (liveCellRef.mRef.getCount() == 0)
continue;
ESM::ObjectState state;
storeState(liveCellRef, state);
@ -192,7 +192,7 @@ int MWWorld::ContainerStore::count(const ESM::RefId& id) const
int total = 0;
for (const auto&& iter : *this)
if (iter.getCellRef().getRefId() == id)
total += iter.getRefData().getCount();
total += iter.getCellRef().getCount();
return total;
}
@ -219,9 +219,9 @@ void MWWorld::ContainerStore::setContListener(MWWorld::ContainerStoreListener* l
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::unstack(const Ptr& ptr, int count)
{
resolve();
if (ptr.getRefData().getCount() <= count)
if (ptr.getCellRef().getCount() <= count)
return end();
MWWorld::ContainerStoreIterator it = addNewStack(ptr, subtractItems(ptr.getRefData().getCount(false), count));
MWWorld::ContainerStoreIterator it = addNewStack(ptr, subtractItems(ptr.getCellRef().getCount(false), count));
MWWorld::Ptr newPtr = *it;
newPtr.getCellRef().unsetRefNum();
@ -232,7 +232,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::unstack(const Ptr& ptr,
if (!script.empty())
MWBase::Environment::get().getWorld()->getLocalScripts().add(script, *it);
remove(ptr, ptr.getRefData().getCount() - count);
remove(ptr, ptr.getCellRef().getCount() - count);
return it;
}
@ -257,9 +257,9 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::restack(const MWWorld::
{
if (stacks(*iter, item))
{
iter->getRefData().setCount(
addItems(iter->getRefData().getCount(false), item.getRefData().getCount(false)));
item.getRefData().setCount(0);
iter->getCellRef().setCount(
addItems(iter->getCellRef().getCount(false), item.getCellRef().getCount(false)));
item.getCellRef().setCount(0);
retval = iter;
break;
}
@ -385,22 +385,24 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp(const Ptr& ptr,
// gold needs special handling: when it is inserted into a container, the base object automatically becomes Gold_001
// this ensures that gold piles of different sizes stack with each other (also, several scripts rely on Gold_001 for
// detecting player gold)
// Note that adding 1 gold_100 is equivalent to adding 1 gold_001. Morrowind.exe resolves gold in leveled lists to
// gold_001 and TESCS disallows adding gold other than gold_001 to inventories. If a content file defines a
// container containing gold_100 anyway, the item is not turned to gold_001 until the player puts it down in the
// world and picks it up again. We just turn it into gold_001 here and ignore that oddity.
if (ptr.getClass().isGold(ptr))
{
int realCount = count * ptr.getClass().getValue(ptr);
for (MWWorld::ContainerStoreIterator iter(begin(type)); iter != end(); ++iter)
{
if (iter->getCellRef().getRefId() == MWWorld::ContainerStore::sGoldId)
{
iter->getRefData().setCount(addItems(iter->getRefData().getCount(false), realCount));
iter->getCellRef().setCount(addItems(iter->getCellRef().getCount(false), count));
flagAsModified();
return iter;
}
}
MWWorld::ManualRef ref(esmStore, MWWorld::ContainerStore::sGoldId, realCount);
return addNewStack(ref.getPtr(), realCount);
MWWorld::ManualRef ref(esmStore, MWWorld::ContainerStore::sGoldId, count);
return addNewStack(ref.getPtr(), count);
}
// determine whether to stack or not
@ -414,7 +416,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp(const Ptr& ptr,
if (stacks(*iter, ptr))
{
// stack
iter->getRefData().setCount(addItems(iter->getRefData().getCount(false), count));
iter->getCellRef().setCount(addItems(iter->getCellRef().getCount(false), count));
flagAsModified();
return iter;
@ -480,7 +482,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addNewStack(const Const
break;
}
it->getRefData().setCount(count);
it->getCellRef().setCount(count);
flagAsModified();
return it;
@ -562,7 +564,7 @@ int MWWorld::ContainerStore::remove(const Ptr& item, int count, bool equipReplac
resolve();
int toRemove = count;
RefData& itemRef = item.getRefData();
CellRef& itemRef = item.getCellRef();
if (itemRef.getCount() <= toRemove)
{
@ -667,7 +669,7 @@ void MWWorld::ContainerStore::addInitialItemImp(
void MWWorld::ContainerStore::clear()
{
for (auto&& iter : *this)
iter.getRefData().setCount(0);
iter.getCellRef().setCount(0);
flagAsModified();
mModified = true;
@ -690,7 +692,7 @@ void MWWorld::ContainerStore::resolve()
if (!mResolved && !container.isEmpty() && container.getType() == ESM::REC_CONT)
{
for (const auto&& ptr : *this)
ptr.getRefData().setCount(0);
ptr.getCellRef().setCount(0);
Misc::Rng::Generator prng{ mSeed };
fill(container.get<ESM::Container>()->mBase->mInventory, ESM::RefId(), prng);
addScripts(*this, container.mCell);
@ -712,7 +714,7 @@ MWWorld::ResolutionHandle MWWorld::ContainerStore::resolveTemporarily()
if (!mResolved && !container.isEmpty() && container.getType() == ESM::REC_CONT)
{
for (const auto&& ptr : *this)
ptr.getRefData().setCount(0);
ptr.getCellRef().setCount(0);
Misc::Rng::Generator prng{ mSeed };
fill(container.get<ESM::Container>()->mBase->mInventory, ESM::RefId(), prng);
addScripts(*this, container.mCell);
@ -729,7 +731,7 @@ void MWWorld::ContainerStore::unresolve()
if (mResolved && !container.isEmpty() && container.getType() == ESM::REC_CONT)
{
for (const auto&& ptr : *this)
ptr.getRefData().setCount(0);
ptr.getCellRef().setCount(0);
fillNonRandom(container.get<ESM::Container>()->mBase->mInventory, ESM::RefId(), mSeed);
addScripts(*this, container.mCell);
mResolved = false;
@ -1332,7 +1334,7 @@ MWWorld::ContainerStoreIteratorBase<PtrType>& MWWorld::ContainerStoreIteratorBas
{
if (incIterator())
nextType();
} while (mType != -1 && !(**this).getRefData().getCount());
} while (mType != -1 && !(**this).getCellRef().getCount());
return *this;
}
@ -1384,7 +1386,7 @@ MWWorld::ContainerStoreIteratorBase<PtrType>::ContainerStoreIteratorBase(int mas
{
nextType();
if (mType == -1 || (**this).getRefData().getCount())
if (mType == -1 || (**this).getCellRef().getCount())
return;
++*this;

@ -79,11 +79,11 @@ void MWWorld::InventoryStore::readEquipmentState(
slot = allowedSlots.first.front();
// unstack if required
if (!allowedSlots.second && iter->getRefData().getCount() > 1)
if (!allowedSlots.second && iter->getCellRef().getCount() > 1)
{
int count = iter->getRefData().getCount(false);
int count = iter->getCellRef().getCount(false);
MWWorld::ContainerStoreIterator newIter = addNewStack(*iter, count > 0 ? 1 : -1);
iter->getRefData().setCount(subtractItems(count, 1));
iter->getCellRef().setCount(subtractItems(count, 1));
mSlots[slot] = newIter;
}
else
@ -171,7 +171,7 @@ void MWWorld::InventoryStore::equip(int slot, const ContainerStoreIterator& iter
// unstack item pointed to by iterator if required
if (iterator != end() && !slots_.second
&& iterator->getRefData().getCount() > 1) // if slots.second is true, item can stay stacked when equipped
&& iterator->getCellRef().getCount() > 1) // if slots.second is true, item can stay stacked when equipped
{
unstack(*iterator);
}
@ -355,7 +355,7 @@ void MWWorld::InventoryStore::autoEquipWeapon(TSlots& slots_)
{
if (!itemsSlots.second)
{
if (weapon->getRefData().getCount() > 1)
if (weapon->getCellRef().getCount() > 1)
{
unstack(*weapon);
}
@ -478,7 +478,7 @@ void MWWorld::InventoryStore::autoEquipArmor(TSlots& slots_)
if (!itemsSlots.second) // if itemsSlots.second is true, item can stay stacked when equipped
{
// unstack item pointed to by iterator if required
if (iter->getRefData().getCount() > 1)
if (iter->getCellRef().getCount() > 1)
{
unstack(*iter);
}
@ -590,7 +590,7 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, bool equipReplac
int retCount = ContainerStore::remove(item, count, equipReplacement, resolve);
bool wasEquipped = false;
if (!item.getRefData().getCount())
if (!item.getCellRef().getCount())
{
for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot)
{
@ -618,7 +618,7 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, bool equipReplac
autoEquip();
}
if (item.getRefData().getCount() == 0 && mSelectedEnchantItem != end() && *mSelectedEnchantItem == item)
if (item.getCellRef().getCount() == 0 && mSelectedEnchantItem != end() && *mSelectedEnchantItem == item)
{
mSelectedEnchantItem = end();
}
@ -643,7 +643,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipSlot(int slot, b
// empty this slot
mSlots[slot] = end();
if (it->getRefData().getCount())
if (it->getCellRef().getCount())
{
retval = restack(*it);
@ -690,10 +690,10 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipItemQuantity(con
throw std::runtime_error("attempt to unequip an item that is not currently equipped");
if (count <= 0)
throw std::runtime_error("attempt to unequip nothing (count <= 0)");
if (count > item.getRefData().getCount())
if (count > item.getCellRef().getCount())
throw std::runtime_error("attempt to unequip more items than equipped");
if (count == item.getRefData().getCount())
if (count == item.getCellRef().getCount())
return unequipItem(item);
// Move items to an existing stack if possible, otherwise split count items out into a new stack.
@ -702,13 +702,13 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipItemQuantity(con
{
if (stacks(*iter, item) && !isEquipped(*iter))
{
iter->getRefData().setCount(addItems(iter->getRefData().getCount(false), count));
item.getRefData().setCount(subtractItems(item.getRefData().getCount(false), count));
iter->getCellRef().setCount(addItems(iter->getCellRef().getCount(false), count));
item.getCellRef().setCount(subtractItems(item.getCellRef().getCount(false), count));
return iter;
}
}
return unstack(item, item.getRefData().getCount() - count);
return unstack(item, item.getCellRef().getCount() - count);
}
MWWorld::InventoryStoreListener* MWWorld::InventoryStore::getInvListener() const

@ -106,6 +106,11 @@ unsigned int MWWorld::LiveCellRefBase::getType() const
return mClass->getType();
}
bool MWWorld::LiveCellRefBase::isDeleted() const
{
return mData.isDeletedByContentFile() || mRef.getCount(false) == 0;
}
namespace MWWorld
{
std::string makeDynamicCastErrorMessage(const LiveCellRefBase* value, std::string_view recordType)

@ -59,6 +59,9 @@ namespace MWWorld
template <class T>
static LiveCellRef<T>* dynamicCast(LiveCellRefBase* value);
/// Returns true if the object was either deleted by the content file or by gameplay.
bool isDeleted() const;
protected:
void loadImp(const ESM::ObjectState& state);
///< Load state into a LiveCellRef, that has already been initialised with base and

@ -24,7 +24,7 @@ namespace
bool operator()(const MWWorld::Ptr& ptr)
{
if (ptr.getRefData().isDeleted())
if (ptr.mRef->isDeleted())
return true;
const ESM::RefId& script = ptr.getClass().getScript(ptr);
@ -152,10 +152,10 @@ void MWWorld::LocalScripts::clearCell(CellStore* cell)
}
}
void MWWorld::LocalScripts::remove(RefData* ref)
void MWWorld::LocalScripts::remove(const MWWorld::CellRef* ref)
{
for (auto iter = mScripts.begin(); iter != mScripts.end(); ++iter)
if (&(iter->second.getRefData()) == ref)
if (&(iter->second.getCellRef()) == ref)
{
if (iter == mIter)
++mIter;

@ -41,7 +41,7 @@ namespace MWWorld
void clearCell(CellStore* cell);
///< Remove all scripts belonging to \a cell.
void remove(RefData* ref);
void remove(const MWWorld::CellRef* ref);
void remove(const Ptr& ptr);
///< Remove script for given reference (ignored if reference does not have a script listed).

@ -101,5 +101,5 @@ MWWorld::ManualRef::ManualRef(const MWWorld::ESMStore& store, const ESM::RefId&
throw std::logic_error("failed to create manual cell ref for " + name.toDebugString() + " (unknown type)");
}
mPtr.getRefData().setCount(count);
mPtr.getCellRef().setCount(count);
}

@ -434,7 +434,7 @@ namespace MWWorld
MWWorld::Ptr caster = magicBoltState.getCaster();
if (!caster.isEmpty() && caster.getClass().isActor())
{
if (caster.getRefData().getCount() <= 0 || caster.getClass().getCreatureStats(caster).isDead())
if (caster.getCellRef().getCount() <= 0 || caster.getClass().getCreatureStats(caster).isDead())
{
cleanupMagicBolt(magicBoltState);
continue;

@ -10,7 +10,7 @@ namespace MWWorld
std::string Ptr::toString() const
{
std::string res = "object";
if (getRefData().isDeleted())
if (mRef->isDeleted())
res = "deleted object";
res.append(getCellRef().getRefNum().toString());
res.append(" (");

@ -37,7 +37,6 @@ namespace MWWorld
mBaseNode = refData.mBaseNode;
mLocals = refData.mLocals;
mEnabled = refData.mEnabled;
mCount = refData.mCount;
mPosition = refData.mPosition;
mChanged = refData.mChanged;
mDeletedByContentFile = refData.mDeletedByContentFile;
@ -62,7 +61,6 @@ namespace MWWorld
, mDeletedByContentFile(false)
, mEnabled(true)
, mPhysicsPostponed(false)
, mCount(1)
, mCustomData(nullptr)
, mChanged(false)
, mFlags(0)
@ -79,7 +77,6 @@ namespace MWWorld
, mDeletedByContentFile(false)
, mEnabled(true)
, mPhysicsPostponed(false)
, mCount(1)
, mPosition(cellRef.mPos)
, mCustomData(nullptr)
, mChanged(false)
@ -92,7 +89,6 @@ namespace MWWorld
, mDeletedByContentFile(ref.mFlags & ESM4::Rec_Deleted)
, mEnabled(!(ref.mFlags & ESM4::Rec_Disabled))
, mPhysicsPostponed(false)
, mCount(ref.mCount)
, mPosition(ref.mPos)
, mCustomData(nullptr)
, mChanged(false)
@ -105,7 +101,6 @@ namespace MWWorld
, mDeletedByContentFile(ref.mFlags & ESM4::Rec_Deleted)
, mEnabled(!(ref.mFlags & ESM4::Rec_Disabled))
, mPhysicsPostponed(false)
, mCount(mDeletedByContentFile ? 0 : 1)
, mPosition(ref.mPos)
, mCustomData(nullptr)
, mChanged(false)
@ -118,7 +113,6 @@ namespace MWWorld
, mDeletedByContentFile(deletedByContentFile)
, mEnabled(objectState.mEnabled != 0)
, mPhysicsPostponed(false)
, mCount(objectState.mCount)
, mPosition(objectState.mPosition)
, mAnimationState(objectState.mAnimationState)
, mCustomData(nullptr)
@ -153,7 +147,6 @@ namespace MWWorld
objectState.mHasLocals = mLocals.write(objectState.mLocals, scriptId);
objectState.mEnabled = mEnabled;
objectState.mCount = mCount;
objectState.mPosition = mPosition;
objectState.mFlags = mFlags;
@ -205,39 +198,17 @@ namespace MWWorld
return mBaseNode;
}
int RefData::getCount(bool absolute) const
{
if (absolute)
return std::abs(mCount);
return mCount;
}
void RefData::setLocals(const ESM::Script& script)
{
if (mLocals.configure(script) && !mLocals.isEmpty())
mChanged = true;
}
void RefData::setCount(int count)
{
if (count == 0)
MWBase::Environment::get().getWorld()->removeRefScript(this);
mChanged = true;
mCount = count;
}
void RefData::setDeletedByContentFile(bool deleted)
{
mDeletedByContentFile = deleted;
}
bool RefData::isDeleted() const
{
return mDeletedByContentFile || mCount == 0;
}
bool RefData::isDeletedByContentFile() const
{
return mDeletedByContentFile;

@ -58,9 +58,6 @@ namespace MWWorld
bool mPhysicsPostponed : 1;
private:
/// 0: deleted
int mCount;
ESM::Position mPosition;
ESM::AnimationState mAnimationState;
@ -110,26 +107,15 @@ namespace MWWorld
/// Set base node (can be a null pointer).
void setBaseNode(osg::ref_ptr<SceneUtil::PositionAttitudeTransform> base);
int getCount(bool absolute = true) const;
void setLocals(const ESM::Script& script);
MWLua::LocalScripts* getLuaScripts() { return mLuaScripts.get(); }
void setLuaScripts(std::shared_ptr<MWLua::LocalScripts>&&);
void setCount(int count);
///< Set object count (an object pile is a simple object with a count >1).
///
/// \warning Do not call setCount() to add or remove objects from a
/// container or an actor's inventory. Call ContainerStore::add() or
/// ContainerStore::remove() instead.
/// This flag is only used for content stack loading and will not be stored in the savegame.
/// If the object was deleted by gameplay, then use setCount(0) instead.
void setDeletedByContentFile(bool deleted);
/// Returns true if the object was either deleted by the content file or by gameplay.
bool isDeleted() const;
/// Returns true if the object was deleted by a content file.
bool isDeletedByContentFile() const;

@ -226,7 +226,7 @@ namespace
{
for (MWWorld::Ptr& ptr : mToInsert)
{
if (!ptr.getRefData().isDeleted() && ptr.getRefData().isEnabled())
if (!ptr.mRef->isDeleted() && ptr.getRefData().isEnabled())
{
try
{
@ -648,7 +648,7 @@ namespace MWWorld
if (ptr.mRef->mData.mPhysicsPostponed)
{
ptr.mRef->mData.mPhysicsPostponed = false;
if (ptr.mRef->mData.isEnabled() && ptr.mRef->mData.getCount() > 0)
if (ptr.mRef->mData.isEnabled() && ptr.mRef->mRef.getCount() > 0)
{
std::string model = getModel(ptr);
if (!model.empty())

@ -685,7 +685,7 @@ namespace MWWorld
return mStore.get<ESM::GameSetting>().find("sDefaultCellname")->mValue.getString();
}
void World::removeRefScript(MWWorld::RefData* ref)
void World::removeRefScript(const MWWorld::CellRef* ref)
{
mLocalScripts.remove(ref);
}
@ -827,7 +827,7 @@ namespace MWWorld
reference.getRefData().enable();
if (mWorldScene->getActiveCells().find(reference.getCell()) != mWorldScene->getActiveCells().end()
&& reference.getRefData().getCount())
&& reference.getCellRef().getCount())
mWorldScene->addObjectToScene(reference);
if (reference.getCellRef().getRefNum().hasContentFile())
@ -879,7 +879,7 @@ namespace MWWorld
}
if (mWorldScene->getActiveCells().find(reference.getCell()) != mWorldScene->getActiveCells().end()
&& reference.getRefData().getCount())
&& reference.getCellRef().getCount())
{
mWorldScene->removeObjectFromScene(reference);
mWorldScene->addPostponedPhysicsObjects();
@ -1039,12 +1039,12 @@ namespace MWWorld
void World::deleteObject(const Ptr& ptr)
{
if (!ptr.getRefData().isDeleted() && ptr.getContainerStore() == nullptr)
if (!ptr.mRef->isDeleted() && ptr.getContainerStore() == nullptr)
{
if (ptr == getPlayerPtr())
throw std::runtime_error("can not delete player object");
ptr.getRefData().setCount(0);
ptr.getCellRef().setCount(0);
if (ptr.isInCell()
&& mWorldScene->getActiveCells().find(ptr.getCell()) != mWorldScene->getActiveCells().end()
@ -1061,9 +1061,9 @@ namespace MWWorld
{
if (!ptr.getCellRef().hasContentFile())
return;
if (ptr.getRefData().isDeleted())
if (ptr.mRef->isDeleted())
{
ptr.getRefData().setCount(1);
ptr.getCellRef().setCount(1);
if (mWorldScene->getActiveCells().find(ptr.getCell()) != mWorldScene->getActiveCells().end()
&& ptr.getRefData().isEnabled())
{
@ -1392,7 +1392,7 @@ namespace MWWorld
MWWorld::Ptr World::placeObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, const ESM::Position& pos)
{
return copyObjectToCell(ptr, cell, pos, ptr.getRefData().getCount(), false);
return copyObjectToCell(ptr, cell, pos, ptr.getCellRef().getCount(), false);
}
MWWorld::Ptr World::safePlaceObject(const ConstPtr& ptr, const ConstPtr& referenceObject,
@ -1443,7 +1443,7 @@ namespace MWWorld
ipos.rot[1] = 0;
}
MWWorld::Ptr placed = copyObjectToCell(ptr, referenceCell, ipos, ptr.getRefData().getCount(), false);
MWWorld::Ptr placed = copyObjectToCell(ptr, referenceCell, ipos, ptr.getCellRef().getCount(), false);
adjustPosition(placed, true); // snap to ground
return placed;
}
@ -1893,7 +1893,7 @@ namespace MWWorld
{
MWWorld::LiveCellRef<ESM::Door>& ref = *static_cast<MWWorld::LiveCellRef<ESM::Door>*>(ptr.getBase());
if (!ref.mData.isEnabled() || ref.mData.isDeleted())
if (!ref.mData.isEnabled() || ref.isDeleted())
return true;
if (ref.mRef.getTeleport())
@ -2541,7 +2541,7 @@ namespace MWWorld
bool operator()(const MWWorld::Ptr& ptr)
{
if (ptr.getRefData().isDeleted())
if (ptr.mRef->isDeleted())
return true;
// vanilla Morrowind does not allow to sell items from containers with zero capacity
@ -3337,7 +3337,7 @@ namespace MWWorld
>= mSquaredDist)
return true;
if (!ptr.getRefData().isEnabled() || ptr.getRefData().isDeleted())
if (!ptr.getRefData().isEnabled() || ptr.mRef->isDeleted())
return true;
// Consider references inside containers as well (except if we are looking for a Creature, they cannot be in

@ -275,7 +275,7 @@ namespace MWWorld
std::string_view getCellName(const MWWorld::Cell& cell) const override;
std::string_view getCellName(const ESM::Cell* cell) const override;
void removeRefScript(MWWorld::RefData* ref) override;
void removeRefScript(const MWWorld::CellRef* ref) override;
//< Remove the script attached to ref from mLocalScripts
Ptr getPtr(const ESM::RefId& name, bool activeOnly) override;

@ -292,7 +292,7 @@ namespace ESM
record.mFactionRank = std::numeric_limits<int>::max();
record.mChargeInt = std::numeric_limits<int>::max();
record.mEnchantmentCharge = std::numeric_limits<float>::max();
record.mGoldValue = std::numeric_limits<int>::max();
record.mCount = std::numeric_limits<int>::max();
record.mTeleport = true;
generateArray(record.mDoorDest.pos);
generateArray(record.mDoorDest.rot);
@ -317,7 +317,7 @@ namespace ESM
EXPECT_EQ(record.mFactionRank, result.mFactionRank);
EXPECT_EQ(record.mChargeInt, result.mChargeInt);
EXPECT_EQ(record.mEnchantmentCharge, result.mEnchantmentCharge);
EXPECT_EQ(record.mGoldValue, result.mGoldValue);
EXPECT_EQ(record.mCount, result.mCount);
EXPECT_EQ(record.mTeleport, result.mTeleport);
EXPECT_EQ(record.mDoorDest, result.mDoorDest);
EXPECT_EQ(record.mDestCell, result.mDestCell);

@ -107,7 +107,7 @@ namespace ESM
getHTOrSkip(cellRef.mChargeInt);
break;
case fourCC("NAM9"):
getHTOrSkip(cellRef.mGoldValue);
getHTOrSkip(cellRef.mCount);
break;
case fourCC("DODT"):
if constexpr (load)
@ -219,8 +219,8 @@ namespace ESM
if (mChargeInt != -1)
esm.writeHNT("INTV", mChargeInt);
if (mGoldValue > 1)
esm.writeHNT("NAM9", mGoldValue);
if (mCount != 1)
esm.writeHNT("NAM9", mCount);
if (!inInventory && mTeleport)
{
@ -259,7 +259,7 @@ namespace ESM
mChargeInt = -1;
mChargeIntRemainder = 0.0f;
mEnchantmentCharge = -1;
mGoldValue = 1;
mCount = 1;
mDestCell.clear();
mLockLevel = 0;
mIsLocked = false;

@ -65,8 +65,7 @@ namespace ESM
// Remaining enchantment charge. This could be -1 if the charge was not touched yet (i.e. full).
float mEnchantmentCharge;
// This is 5 for Gold_005 references, 100 for Gold_100 and so on.
int32_t mGoldValue;
int32_t mCount;
// For doors - true if this door teleports to somewhere else, false
// if it should open through animation.

@ -24,7 +24,8 @@ namespace ESM
inline constexpr FormatVersion MaxNameIsRefIdOnlyFormatVersion = 25;
inline constexpr FormatVersion MaxUseEsmCellIdFormatVersion = 26;
inline constexpr FormatVersion MaxActiveSpellSlotIndexFormatVersion = 27;
inline constexpr FormatVersion CurrentSaveGameFormatVersion = 30;
inline constexpr FormatVersion MaxOldCountFormatVersion = 30;
inline constexpr FormatVersion CurrentSaveGameFormatVersion = 31;
inline constexpr FormatVersion MinSupportedSaveGameFormatVersion = 4;
inline constexpr FormatVersion OpenMW0_48SaveGameFormatVersion = 21;

@ -24,7 +24,7 @@ namespace ESM
state.mRef.loadId(esm, true);
state.load(esm);
if (state.mCount == 0)
if (state.mRef.mCount == 0)
continue;
mItems.push_back(state);
@ -43,7 +43,7 @@ namespace ESM
if (!esm.applyContentFileMapping(state.mRef.mRefNum))
state.mRef.mRefNum = FormId(); // content file removed; unset refnum, but keep object.
if (state.mCount == 0)
if (state.mRef.mCount == 0)
continue;
mItems.push_back(state);
@ -117,8 +117,8 @@ namespace ESM
const int count = entry.second;
for (auto& item : mItems)
{
if (item.mCount == count && id == item.mRef.mRefID)
item.mCount = -count;
if (item.mRef.mCount == count && id == item.mRef.mRefID)
item.mRef.mCount = -count;
}
}
}

@ -29,8 +29,11 @@ namespace ESM
mEnabled = 1;
esm.getHNOT(mEnabled, "ENAB");
mCount = 1;
esm.getHNOT(mCount, "COUN");
if (mVersion <= MaxOldCountFormatVersion)
{
mRef.mCount = 1;
esm.getHNOT(mRef.mCount, "COUN");
}
mPosition = mRef.mPos;
esm.getHNOT("POS_", mPosition.pos, mPosition.rot);
@ -60,9 +63,6 @@ namespace ESM
if (!mEnabled && !inInventory)
esm.writeHNT("ENAB", mEnabled);
if (mCount != 1)
esm.writeHNT("COUN", mCount);
if (!inInventory && mPosition != mRef.mPos)
{
std::array<float, 6> pos;
@ -85,7 +85,6 @@ namespace ESM
mRef.blank();
mHasLocals = 0;
mEnabled = false;
mCount = 1;
for (int i = 0; i < 3; ++i)
{
mPosition.pos[i] = 0;

@ -32,7 +32,6 @@ namespace ESM
Locals mLocals;
LuaScripts mLuaScripts;
unsigned char mEnabled;
int32_t mCount;
Position mPosition;
uint32_t mFlags;
@ -46,7 +45,6 @@ namespace ESM
ObjectState()
: mHasLocals(0)
, mEnabled(0)
, mCount(0)
, mFlags(0)
, mHasCustomState(true)
{

@ -82,6 +82,11 @@ void ESM4::ActorCharacter::load(ESM4::Reader& reader)
reader.getFormId(mEsp.parent);
reader.get(mEsp.flags);
break;
case ESM4::SUB_XCNT:
{
reader.get(mCount);
break;
}
case ESM4::SUB_XRGD: // ragdoll
case ESM4::SUB_XRGB: // ragdoll biped
case ESM4::SUB_XHRS: // horse formId
@ -113,7 +118,6 @@ void ESM4::ActorCharacter::load(ESM4::Reader& reader)
case ESM4::SUB_XATO: // FONV
case ESM4::SUB_MNAM: // FO4
case ESM4::SUB_XATP: // FO4
case ESM4::SUB_XCNT: // FO4
case ESM4::SUB_XEMI: // FO4
case ESM4::SUB_XFVC: // FO4
case ESM4::SUB_XHLT: // FO4

@ -57,6 +57,8 @@ namespace ESM4
EnableParent mEsp;
std::int32_t mCount = 1;
void load(ESM4::Reader& reader);
// void save(ESM4::Writer& writer) const;

@ -268,6 +268,11 @@ void ESM4::Reference::load(ESM4::Reader& reader)
break;
}
case ESM4::SUB_XCNT:
{
reader.get(mCount);
break;
}
// lighting
case ESM4::SUB_LNAM: // lighting template formId
case ESM4::SUB_XLIG: // struct, FOV, fade, etc
@ -279,7 +284,6 @@ void ESM4::Reference::load(ESM4::Reader& reader)
//
case ESM4::SUB_XPCI: // formId
case ESM4::SUB_XLCM:
case ESM4::SUB_XCNT:
case ESM4::SUB_ONAM:
case ESM4::SUB_VMAD:
case ESM4::SUB_XPRM:

@ -97,7 +97,7 @@ namespace ESM4
EnableParent mEsp;
std::uint32_t mCount = 1; // only if > 1
std::int32_t mCount = 1; // only if > 1
ESM::FormId mAudioLocation;

Loading…
Cancel
Save