mirror of
https://github.com/OpenMW/openmw.git
synced 2025-03-01 10:39:42 +00:00
Merge branch 'refnum-for-items-in-spellcast' into 'master'
Use refnum instead of slot for items during spellcast Closes #4508 See merge request OpenMW/openmw!3244
This commit is contained in:
commit
488657d9b4
18 changed files with 86 additions and 55 deletions
|
@ -491,7 +491,7 @@ namespace ESSImport
|
|||
|
||||
out.mSpellId = ESM::RefId::stringRefId(it->mSPDT.mId.toString());
|
||||
out.mSpeed = pnam.mSpeed * 0.001f; // not sure where this factor comes from
|
||||
out.mSlot = 0;
|
||||
out.mItem = ESM::RefNum();
|
||||
|
||||
esm.startRecord(ESM::REC_MPRJ);
|
||||
out.save(esm);
|
||||
|
|
|
@ -483,8 +483,8 @@ namespace MWBase
|
|||
|
||||
virtual void castSpell(const MWWorld::Ptr& actor, bool manualSpell = false) = 0;
|
||||
|
||||
virtual void launchMagicBolt(
|
||||
const ESM::RefId& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection, int slot)
|
||||
virtual void launchMagicBolt(const ESM::RefId& spellId, const MWWorld::Ptr& caster,
|
||||
const osg::Vec3f& fallbackDirection, ESM::RefNum item)
|
||||
= 0;
|
||||
virtual void launchProjectile(MWWorld::Ptr& actor, MWWorld::Ptr& projectile, const osg::Vec3f& worldPos,
|
||||
const osg::Quat& orient, MWWorld::Ptr& bow, float speed, float attackStrength)
|
||||
|
|
|
@ -85,7 +85,7 @@ namespace MWMechanics
|
|||
: mId(cast.mId)
|
||||
, mDisplayName(cast.mSourceName)
|
||||
, mCasterActorId(-1)
|
||||
, mSlot(cast.mSlot)
|
||||
, mItem(cast.mItem)
|
||||
, mType(cast.mType)
|
||||
, mWorsenings(-1)
|
||||
{
|
||||
|
@ -98,7 +98,6 @@ namespace MWMechanics
|
|||
: mId(spell->mId)
|
||||
, mDisplayName(spell->mName)
|
||||
, mCasterActorId(actor.getClass().getCreatureStats(actor).getActorId())
|
||||
, mSlot(0)
|
||||
, mType(spell->mData.mType == ESM::Spell::ST_Ability ? ESM::ActiveSpells::Type_Ability
|
||||
: ESM::ActiveSpells::Type_Permanent)
|
||||
, mWorsenings(-1)
|
||||
|
@ -108,11 +107,11 @@ namespace MWMechanics
|
|||
}
|
||||
|
||||
ActiveSpells::ActiveSpellParams::ActiveSpellParams(
|
||||
const MWWorld::ConstPtr& item, const ESM::Enchantment* enchantment, int slotIndex, const MWWorld::Ptr& actor)
|
||||
const MWWorld::ConstPtr& item, const ESM::Enchantment* enchantment, const MWWorld::Ptr& actor)
|
||||
: mId(item.getCellRef().getRefId())
|
||||
, mDisplayName(item.getClass().getName(item))
|
||||
, mCasterActorId(actor.getClass().getCreatureStats(actor).getActorId())
|
||||
, mSlot(slotIndex)
|
||||
, mItem(item.getCellRef().getRefNum())
|
||||
, mType(ESM::ActiveSpells::Type_Enchantment)
|
||||
, mWorsenings(-1)
|
||||
{
|
||||
|
@ -125,7 +124,7 @@ namespace MWMechanics
|
|||
, mEffects(params.mEffects)
|
||||
, mDisplayName(params.mDisplayName)
|
||||
, mCasterActorId(params.mCasterActorId)
|
||||
, mSlot(params.mItem.isSet() ? params.mItem.mIndex : 0)
|
||||
, mItem(params.mItem)
|
||||
, mType(params.mType)
|
||||
, mWorsenings(params.mWorsenings)
|
||||
, mNextWorsening({ params.mNextWorsening })
|
||||
|
@ -136,7 +135,7 @@ namespace MWMechanics
|
|||
: mId(params.mId)
|
||||
, mDisplayName(params.mDisplayName)
|
||||
, mCasterActorId(actor.getClass().getCreatureStats(actor).getActorId())
|
||||
, mSlot(params.mSlot)
|
||||
, mItem(params.mItem)
|
||||
, mType(params.mType)
|
||||
, mWorsenings(-1)
|
||||
{
|
||||
|
@ -149,12 +148,7 @@ namespace MWMechanics
|
|||
params.mEffects = mEffects;
|
||||
params.mDisplayName = mDisplayName;
|
||||
params.mCasterActorId = mCasterActorId;
|
||||
if (mSlot)
|
||||
{
|
||||
// Note that we're storing the inventory slot as a RefNum instead of an int as a matter of future proofing
|
||||
// mSlot needs to be replaced with a RefNum once inventory items get persistent RefNum (#4508 #6148)
|
||||
params.mItem = { static_cast<unsigned int>(mSlot), 0 };
|
||||
}
|
||||
params.mItem = mItem;
|
||||
params.mType = mType;
|
||||
params.mWorsenings = mWorsenings;
|
||||
params.mNextWorsening = mNextWorsening.toEsm();
|
||||
|
@ -254,7 +248,8 @@ namespace MWMechanics
|
|||
continue;
|
||||
if (std::find_if(mSpells.begin(), mSpells.end(),
|
||||
[&](const ActiveSpellParams& params) {
|
||||
return params.mSlot == slotIndex && params.mType == ESM::ActiveSpells::Type_Enchantment
|
||||
return params.mItem == slot->getCellRef().getRefNum()
|
||||
&& params.mType == ESM::ActiveSpells::Type_Enchantment
|
||||
&& params.mId == slot->getCellRef().getRefId();
|
||||
})
|
||||
!= mSpells.end())
|
||||
|
@ -264,7 +259,7 @@ namespace MWMechanics
|
|||
purgeEffect(ptr, ESM::MagicEffect::Invisibility);
|
||||
applyPurges(ptr);
|
||||
const ActiveSpellParams& params
|
||||
= mSpells.emplace_back(ActiveSpellParams{ *slot, enchantment, slotIndex, ptr });
|
||||
= mSpells.emplace_back(ActiveSpellParams{ *slot, enchantment, ptr });
|
||||
for (const auto& effect : params.mEffects)
|
||||
MWMechanics::playEffects(
|
||||
ptr, *world->getStore().get<ESM::MagicEffect>().find(effect.mEffectId), playNonLooping);
|
||||
|
@ -351,9 +346,19 @@ namespace MWMechanics
|
|||
}
|
||||
else if (spellIt->mType == ESM::ActiveSpells::Type_Enchantment)
|
||||
{
|
||||
// Remove constant effect enchantments that have been unequipped
|
||||
const auto& store = ptr.getClass().getInventoryStore(ptr);
|
||||
auto slot = store.getSlot(spellIt->mSlot);
|
||||
remove = slot == store.end() || slot->getCellRef().getRefId() != spellIt->mId;
|
||||
remove = true;
|
||||
for (int slotIndex = 0; slotIndex < MWWorld::InventoryStore::Slots; slotIndex++)
|
||||
{
|
||||
auto slot = store.getSlot(slotIndex);
|
||||
if (slot != store.end() && slot->getCellRef().getRefNum().isSet()
|
||||
&& slot->getCellRef().getRefNum() == spellIt->mItem)
|
||||
{
|
||||
remove = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (remove)
|
||||
{
|
||||
|
@ -382,7 +387,7 @@ namespace MWMechanics
|
|||
{
|
||||
auto found = std::find_if(mSpells.begin(), mSpells.end(), [&](const auto& existing) {
|
||||
return spell.mId == existing.mId && spell.mCasterActorId == existing.mCasterActorId
|
||||
&& spell.mSlot == existing.mSlot;
|
||||
&& spell.mItem == existing.mItem;
|
||||
});
|
||||
if (found != mSpells.end())
|
||||
{
|
||||
|
|
|
@ -37,17 +37,18 @@ namespace MWMechanics
|
|||
std::vector<ActiveEffect> mEffects;
|
||||
std::string mDisplayName;
|
||||
int mCasterActorId;
|
||||
int mSlot;
|
||||
ESM::RefNum mItem;
|
||||
ESM::ActiveSpells::EffectType mType;
|
||||
int mWorsenings;
|
||||
MWWorld::TimeStamp mNextWorsening;
|
||||
MWWorld::Ptr mSource;
|
||||
|
||||
ActiveSpellParams(const ESM::ActiveSpells::ActiveSpellParams& params);
|
||||
|
||||
ActiveSpellParams(const ESM::Spell* spell, const MWWorld::Ptr& actor, bool ignoreResistances = false);
|
||||
|
||||
ActiveSpellParams(const MWWorld::ConstPtr& item, const ESM::Enchantment* enchantment, int slotIndex,
|
||||
const MWWorld::Ptr& actor);
|
||||
ActiveSpellParams(
|
||||
const MWWorld::ConstPtr& item, const ESM::Enchantment* enchantment, const MWWorld::Ptr& actor);
|
||||
|
||||
ActiveSpellParams(const ActiveSpellParams& params, const MWWorld::Ptr& actor);
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace MWMechanics
|
|||
{
|
||||
MWMechanics::CastSpell cast(attacker, victim, fromProjectile);
|
||||
cast.mHitPosition = hitPosition;
|
||||
cast.cast(object, 0, false);
|
||||
cast.cast(object, false);
|
||||
// Apply magic effects directly instead of waiting a frame to allow soul trap to work on one-hit kills
|
||||
if (!victim.isEmpty() && victim.getClass().isActor())
|
||||
MWBase::Environment::get().getMechanicsManager()->updateMagicEffects(victim);
|
||||
|
|
|
@ -146,7 +146,7 @@ namespace MWMechanics
|
|||
fallbackDirection = (mTarget.getRefData().getPosition().asVec3() + offset)
|
||||
- (mCaster.getRefData().getPosition().asVec3());
|
||||
|
||||
MWBase::Environment::get().getWorld()->launchMagicBolt(mId, mCaster, fallbackDirection, mSlot);
|
||||
MWBase::Environment::get().getWorld()->launchMagicBolt(mId, mCaster, fallbackDirection, mItem);
|
||||
}
|
||||
|
||||
void CastSpell::inflict(
|
||||
|
@ -290,7 +290,7 @@ namespace MWMechanics
|
|||
throw std::runtime_error("ID type cannot be casted");
|
||||
}
|
||||
|
||||
bool CastSpell::cast(const MWWorld::Ptr& item, int slot, bool launchProjectile)
|
||||
bool CastSpell::cast(const MWWorld::Ptr& item, bool launchProjectile)
|
||||
{
|
||||
const ESM::RefId& enchantmentName = item.getClass().getEnchantment(item);
|
||||
if (enchantmentName.empty())
|
||||
|
@ -302,7 +302,10 @@ namespace MWMechanics
|
|||
const auto& store = MWBase::Environment::get().getESMStore();
|
||||
const ESM::Enchantment* enchantment = store->get<ESM::Enchantment>().find(enchantmentName);
|
||||
|
||||
mSlot = slot;
|
||||
// CastOnce enchantments (i.e. scrolls) never stack and the item is immediately destroyed,
|
||||
// so don't track the source item.
|
||||
if (enchantment->mData.mType != ESM::Enchantment::CastOnce)
|
||||
mItem = item.getCellRef().getRefNum();
|
||||
|
||||
bool godmode = mCaster == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState();
|
||||
bool isProjectile = false;
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace MWMechanics
|
|||
bool mFromProjectile; // True if spell is cast by enchantment of some projectile (arrow, bolt or thrown weapon)
|
||||
bool mManualSpell; // True if spell is casted from script and ignores some checks (mana level, success chance,
|
||||
// etc.)
|
||||
int mSlot{ 0 };
|
||||
ESM::RefNum mItem;
|
||||
ESM::ActiveSpells::EffectType mType{ ESM::ActiveSpells::Type_Temporary };
|
||||
|
||||
CastSpell(const MWWorld::Ptr& caster, const MWWorld::Ptr& target, const bool fromProjectile = false,
|
||||
|
@ -54,7 +54,7 @@ namespace MWMechanics
|
|||
/// @note mCaster must be an actor
|
||||
/// @param launchProjectile If set to false, "on target" effects are directly applied instead of being launched
|
||||
/// as projectile originating from the caster.
|
||||
bool cast(const MWWorld::Ptr& item, int slot, bool launchProjectile = true);
|
||||
bool cast(const MWWorld::Ptr& item, bool launchProjectile = true);
|
||||
|
||||
/// @note mCaster must be an NPC
|
||||
bool cast(const ESM::Ingredient* ingredient);
|
||||
|
|
|
@ -104,8 +104,10 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::getState(
|
|||
LiveCellRef<T> ref(record);
|
||||
ref.load(state);
|
||||
collection.mList.push_back(ref);
|
||||
auto it = ContainerStoreIterator(this, --collection.mList.end());
|
||||
MWBase::Environment::get().getWorldModel()->registerPtr(*it);
|
||||
|
||||
return ContainerStoreIterator(this, --collection.mList.end());
|
||||
return it;
|
||||
}
|
||||
|
||||
void MWWorld::ContainerStore::storeEquipmentState(
|
||||
|
@ -155,7 +157,12 @@ MWWorld::ContainerStore::ContainerStore()
|
|||
{
|
||||
}
|
||||
|
||||
MWWorld::ContainerStore::~ContainerStore() {}
|
||||
MWWorld::ContainerStore::~ContainerStore()
|
||||
{
|
||||
MWWorld::WorldModel* worldModel = MWBase::Environment::get().getWorldModel();
|
||||
for (MWWorld::ContainerStoreIterator iter(begin()); iter != end(); ++iter)
|
||||
worldModel->deregisterPtr(*iter);
|
||||
}
|
||||
|
||||
MWWorld::ConstContainerStoreIterator MWWorld::ContainerStore::cbegin(int mask) const
|
||||
{
|
||||
|
@ -196,10 +203,14 @@ int MWWorld::ContainerStore::count(const ESM::RefId& id) const
|
|||
return total;
|
||||
}
|
||||
|
||||
void MWWorld::ContainerStore::clearRefNums()
|
||||
void MWWorld::ContainerStore::updateRefNums()
|
||||
{
|
||||
for (const auto& iter : *this)
|
||||
{
|
||||
iter.getCellRef().unsetRefNum();
|
||||
iter.getRefData().setLuaScripts(nullptr);
|
||||
MWBase::Environment::get().getWorldModel()->registerPtr(iter);
|
||||
}
|
||||
}
|
||||
|
||||
MWWorld::ContainerStoreListener* MWWorld::ContainerStore::getContListener() const
|
||||
|
@ -656,7 +667,8 @@ void MWWorld::ContainerStore::addInitialItemImp(
|
|||
else
|
||||
{
|
||||
ptr.getCellRef().setOwner(owner);
|
||||
addImp(ptr, count, false);
|
||||
MWWorld::ContainerStoreIterator it = addImp(ptr, count, false);
|
||||
MWBase::Environment::get().getWorldModel()->registerPtr(*it);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -117,7 +117,7 @@ namespace MWWorld
|
|||
|
||||
// Used in clone() to unset refnums of copies.
|
||||
// (RefNum should be unique, copy can not have the same RefNum).
|
||||
void clearRefNums();
|
||||
void updateRefNums();
|
||||
|
||||
// (item, max charge)
|
||||
typedef std::vector<std::pair<ContainerStoreIterator, float>> TRechargingItems;
|
||||
|
@ -185,7 +185,7 @@ namespace MWWorld
|
|||
virtual std::unique_ptr<ContainerStore> clone()
|
||||
{
|
||||
auto res = std::make_unique<ContainerStore>(*this);
|
||||
res->clearRefNums();
|
||||
res->updateRefNums();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ namespace MWWorld
|
|||
std::unique_ptr<ContainerStore> clone() override
|
||||
{
|
||||
auto res = std::make_unique<InventoryStore>(*this);
|
||||
res->clearRefNums();
|
||||
res->updateRefNums();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -263,7 +263,7 @@ namespace MWWorld
|
|||
}
|
||||
|
||||
void ProjectileManager::launchMagicBolt(
|
||||
const ESM::RefId& spellId, const Ptr& caster, const osg::Vec3f& fallbackDirection, int slot)
|
||||
const ESM::RefId& spellId, const Ptr& caster, const osg::Vec3f& fallbackDirection, ESM::RefNum item)
|
||||
{
|
||||
osg::Vec3f pos = caster.getRefData().getPosition().asVec3();
|
||||
if (caster.getClass().isActor())
|
||||
|
@ -287,7 +287,7 @@ namespace MWWorld
|
|||
MagicBoltState state;
|
||||
state.mSpellId = spellId;
|
||||
state.mCasterHandle = caster;
|
||||
state.mSlot = slot;
|
||||
state.mItem = item;
|
||||
if (caster.getClass().isActor())
|
||||
state.mActorId = caster.getClass().getCreatureStats(caster).getActorId();
|
||||
else
|
||||
|
@ -575,7 +575,7 @@ namespace MWWorld
|
|||
cast.mHitPosition = Misc::Convert::toOsg(projectile->getHitPosition());
|
||||
cast.mId = magicBoltState.mSpellId;
|
||||
cast.mSourceName = magicBoltState.mSourceName;
|
||||
cast.mSlot = magicBoltState.mSlot;
|
||||
cast.mItem = magicBoltState.mItem;
|
||||
// Grab original effect list so the indices are correct
|
||||
const ESM::EffectList* effects;
|
||||
if (const ESM::Spell* spell = esmStore.get<ESM::Spell>().search(magicBoltState.mSpellId))
|
||||
|
@ -669,7 +669,7 @@ namespace MWWorld
|
|||
state.mPosition = ESM::Vector3(osg::Vec3f(it->mNode->getPosition()));
|
||||
state.mOrientation = ESM::Quaternion(osg::Quat(it->mNode->getAttitude()));
|
||||
state.mActorId = it->mActorId;
|
||||
state.mSlot = it->mSlot;
|
||||
state.mItem = it->mItem;
|
||||
state.mSpellId = it->mSpellId;
|
||||
state.mSpeed = it->mSpeed;
|
||||
|
||||
|
@ -727,7 +727,7 @@ namespace MWWorld
|
|||
state.mSpellId = esm.mSpellId;
|
||||
state.mActorId = esm.mActorId;
|
||||
state.mToDelete = false;
|
||||
state.mSlot = esm.mSlot;
|
||||
state.mItem = esm.mItem;
|
||||
std::string texture;
|
||||
|
||||
try
|
||||
|
|
|
@ -49,8 +49,8 @@ namespace MWWorld
|
|||
MWRender::RenderingManager* rendering, MWPhysics::PhysicsSystem* physics);
|
||||
|
||||
/// If caster is an actor, the actor's facing orientation is used. Otherwise fallbackDirection is used.
|
||||
void launchMagicBolt(
|
||||
const ESM::RefId& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection, int slot);
|
||||
void launchMagicBolt(const ESM::RefId& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection,
|
||||
ESM::RefNum item);
|
||||
|
||||
void launchProjectile(const MWWorld::Ptr& actor, const MWWorld::ConstPtr& projectile, const osg::Vec3f& pos,
|
||||
const osg::Quat& orient, const MWWorld::Ptr& bow, float speed, float attackStrength);
|
||||
|
@ -108,7 +108,8 @@ namespace MWWorld
|
|||
ESM::EffectList mEffects;
|
||||
|
||||
float mSpeed;
|
||||
int mSlot;
|
||||
// Refnum of the casting item
|
||||
ESM::RefNum mItem;
|
||||
|
||||
std::vector<MWBase::Sound*> mSounds;
|
||||
std::set<ESM::RefId> mSoundIds;
|
||||
|
|
|
@ -3136,9 +3136,9 @@ namespace MWWorld
|
|||
}
|
||||
|
||||
void World::launchMagicBolt(
|
||||
const ESM::RefId& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection, int slot)
|
||||
const ESM::RefId& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection, ESM::RefNum item)
|
||||
{
|
||||
mProjectileManager->launchMagicBolt(spellId, caster, fallbackDirection, slot);
|
||||
mProjectileManager->launchMagicBolt(spellId, caster, fallbackDirection, item);
|
||||
}
|
||||
|
||||
void World::updateProjectilesCasters()
|
||||
|
|
|
@ -578,7 +578,7 @@ namespace MWWorld
|
|||
void castSpell(const MWWorld::Ptr& actor, bool manualSpell = false) override;
|
||||
|
||||
void launchMagicBolt(const ESM::RefId& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection,
|
||||
int slot) override;
|
||||
ESM::RefNum item) override;
|
||||
void launchProjectile(MWWorld::Ptr& actor, MWWorld::Ptr& projectile, const osg::Vec3f& worldPos,
|
||||
const osg::Quat& orient, MWWorld::Ptr& bow, float speed, float attackStrength) override;
|
||||
void updateProjectilesCasters() override;
|
||||
|
|
|
@ -56,7 +56,14 @@ namespace ESM
|
|||
{
|
||||
esm.getHNT(params.mType, "TYPE");
|
||||
if (esm.peekNextSub("ITEM"))
|
||||
params.mItem = esm.getFormId(true, "ITEM");
|
||||
{
|
||||
if (format <= MaxActiveSpellSlotIndexFormatVersion)
|
||||
// Previous versions saved slot index in this record.
|
||||
// Ignore these values as we can't use them
|
||||
esm.getFormId(true, "ITEM");
|
||||
else
|
||||
params.mItem = esm.getFormId(true, "ITEM");
|
||||
}
|
||||
}
|
||||
if (esm.isNextSub("WORS"))
|
||||
{
|
||||
|
|
|
@ -24,7 +24,8 @@ namespace ESM
|
|||
inline constexpr FormatVersion MaxSavedGameCellNameAsRefIdFormatVersion = 24;
|
||||
inline constexpr FormatVersion MaxNameIsRefIdOnlyFormatVersion = 25;
|
||||
inline constexpr FormatVersion MaxUseEsmCellIdFormatVersion = 26;
|
||||
inline constexpr FormatVersion CurrentSaveGameFormatVersion = 27;
|
||||
inline constexpr FormatVersion MaxActiveSpellSlotIndexFormatVersion = 27;
|
||||
inline constexpr FormatVersion CurrentSaveGameFormatVersion = 28;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -28,7 +28,8 @@ namespace ESM
|
|||
|
||||
esm.writeHNRefId("SPEL", mSpellId);
|
||||
esm.writeHNT("SPED", mSpeed);
|
||||
esm.writeHNT("SLOT", mSlot);
|
||||
if (mItem.isSet())
|
||||
esm.writeFormId(mItem, true, "ITEM");
|
||||
}
|
||||
|
||||
void MagicBoltState::load(ESMReader& esm)
|
||||
|
@ -40,10 +41,10 @@ namespace ESM
|
|||
esm.skipHSub();
|
||||
EffectList().load(esm); // for backwards compatibility
|
||||
esm.getHNT(mSpeed, "SPED");
|
||||
if (esm.getFormatVersion() <= MaxClearModifiersFormatVersion)
|
||||
mSlot = 0;
|
||||
else
|
||||
esm.getHNT(mSlot, "SLOT");
|
||||
if (esm.peekNextSub("ITEM"))
|
||||
mItem = esm.getFormId(true, "ITEM");
|
||||
if (esm.isNextSub("SLOT")) // for backwards compatibility
|
||||
esm.skipHSub();
|
||||
if (esm.isNextSub("STCK")) // for backwards compatibility
|
||||
esm.skipHSub();
|
||||
if (esm.isNextSub("SOUN")) // for backwards compatibility
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace ESM
|
|||
{
|
||||
RefId mSpellId;
|
||||
float mSpeed;
|
||||
int mSlot;
|
||||
RefNum mItem;
|
||||
|
||||
void load(ESMReader& esm);
|
||||
void save(ESMWriter& esm) const;
|
||||
|
|
Loading…
Reference in a new issue