mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-26 09:35:28 +00:00
Use real time to update spell effects instead of game timestamps (bug #5165)
This commit is contained in:
parent
3ebbe14a62
commit
b5833f3c59
@ -6,6 +6,7 @@
|
|||||||
Bug #3676: NiParticleColorModifier isn't applied properly
|
Bug #3676: NiParticleColorModifier isn't applied properly
|
||||||
Bug #4774: Guards are ignorant of an invisible player that tries to attack them
|
Bug #4774: Guards are ignorant of an invisible player that tries to attack them
|
||||||
Bug #5108: Savegame bloating due to inefficient fog textures format
|
Bug #5108: Savegame bloating due to inefficient fog textures format
|
||||||
|
Bug #5165: Active spells should use real time intead of timestamps
|
||||||
Bug #5358: ForceGreeting always resets the dialogue window completely
|
Bug #5358: ForceGreeting always resets the dialogue window completely
|
||||||
Bug #5363: Enchantment autocalc not always 0/1
|
Bug #5363: Enchantment autocalc not always 0/1
|
||||||
Bug #5364: Script fails/stops if trying to startscript an unknown script
|
Bug #5364: Script fails/stops if trying to startscript an unknown script
|
||||||
@ -188,8 +189,8 @@
|
|||||||
Bug #5158: Objects without a name don't fallback to their ID
|
Bug #5158: Objects without a name don't fallback to their ID
|
||||||
Bug #5159: NiMaterialColorController can only control the diffuse color
|
Bug #5159: NiMaterialColorController can only control the diffuse color
|
||||||
Bug #5161: Creature companions can't be activated when they are knocked down
|
Bug #5161: Creature companions can't be activated when they are knocked down
|
||||||
Bug #5164: Faction owned items handling is incorrect
|
|
||||||
Bug #5163: UserData is not copied during node cloning
|
Bug #5163: UserData is not copied during node cloning
|
||||||
|
Bug #5164: Faction owned items handling is incorrect
|
||||||
Bug #5166: Scripts still should be executed after player's death
|
Bug #5166: Scripts still should be executed after player's death
|
||||||
Bug #5167: Player can select and cast spells before magic menu is enabled
|
Bug #5167: Player can select and cast spells before magic menu is enabled
|
||||||
Bug #5168: Force1stPerson and Force3rdPerson commands are not really force view change
|
Bug #5168: Force1stPerson and Force3rdPerson commands are not really force view change
|
||||||
|
@ -12,14 +12,12 @@
|
|||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
void ActiveSpells::update() const
|
void ActiveSpells::update(float duration) const
|
||||||
{
|
{
|
||||||
bool rebuild = false;
|
bool rebuild = false;
|
||||||
|
|
||||||
MWWorld::TimeStamp now = MWBase::Environment::get().getWorld()->getTimeStamp();
|
|
||||||
|
|
||||||
// Erase no longer active spells and effects
|
// Erase no longer active spells and effects
|
||||||
if (mLastUpdate!=now)
|
if (duration > 0)
|
||||||
{
|
{
|
||||||
TContainer::iterator iter (mSpells.begin());
|
TContainer::iterator iter (mSpells.begin());
|
||||||
while (iter!=mSpells.end())
|
while (iter!=mSpells.end())
|
||||||
@ -34,21 +32,20 @@ namespace MWMechanics
|
|||||||
std::vector<ActiveEffect>& effects = iter->second.mEffects;
|
std::vector<ActiveEffect>& effects = iter->second.mEffects;
|
||||||
for (std::vector<ActiveEffect>::iterator effectIt = effects.begin(); effectIt != effects.end();)
|
for (std::vector<ActiveEffect>::iterator effectIt = effects.begin(); effectIt != effects.end();)
|
||||||
{
|
{
|
||||||
MWWorld::TimeStamp start = iter->second.mTimeStamp;
|
if (effectIt->mTimeLeft <= 0)
|
||||||
MWWorld::TimeStamp end = start + static_cast<double>(effectIt->mDuration)*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/(60*60);
|
|
||||||
if (end <= now)
|
|
||||||
{
|
{
|
||||||
effectIt = effects.erase(effectIt);
|
effectIt = effects.erase(effectIt);
|
||||||
rebuild = true;
|
rebuild = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
effectIt->mTimeLeft -= duration;
|
||||||
++effectIt;
|
++effectIt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
++iter;
|
++iter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mLastUpdate = now;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mSpellsChanged)
|
if (mSpellsChanged)
|
||||||
@ -63,24 +60,15 @@ namespace MWMechanics
|
|||||||
|
|
||||||
void ActiveSpells::rebuildEffects() const
|
void ActiveSpells::rebuildEffects() const
|
||||||
{
|
{
|
||||||
MWWorld::TimeStamp now = MWBase::Environment::get().getWorld()->getTimeStamp();
|
|
||||||
|
|
||||||
mEffects = MagicEffects();
|
mEffects = MagicEffects();
|
||||||
|
|
||||||
for (TIterator iter (begin()); iter!=end(); ++iter)
|
for (TIterator iter (begin()); iter!=end(); ++iter)
|
||||||
{
|
{
|
||||||
const MWWorld::TimeStamp& start = iter->second.mTimeStamp;
|
|
||||||
|
|
||||||
const std::vector<ActiveEffect>& effects = iter->second.mEffects;
|
const std::vector<ActiveEffect>& effects = iter->second.mEffects;
|
||||||
|
|
||||||
for (std::vector<ActiveEffect>::const_iterator effectIt = effects.begin(); effectIt != effects.end(); ++effectIt)
|
for (std::vector<ActiveEffect>::const_iterator effectIt = effects.begin(); effectIt != effects.end(); ++effectIt)
|
||||||
{
|
{
|
||||||
double duration = effectIt->mDuration;
|
if (effectIt->mTimeLeft > 0)
|
||||||
MWWorld::TimeStamp end = start;
|
|
||||||
end += duration *
|
|
||||||
MWBase::Environment::get().getWorld()->getTimeScaleFactor()/(60*60);
|
|
||||||
|
|
||||||
if (end>now)
|
|
||||||
mEffects.add(MWMechanics::EffectKey(effectIt->mEffectId, effectIt->mArg), MWMechanics::EffectParam(effectIt->mMagnitude));
|
mEffects.add(MWMechanics::EffectKey(effectIt->mEffectId, effectIt->mArg), MWMechanics::EffectParam(effectIt->mMagnitude));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,12 +76,11 @@ namespace MWMechanics
|
|||||||
|
|
||||||
ActiveSpells::ActiveSpells()
|
ActiveSpells::ActiveSpells()
|
||||||
: mSpellsChanged (false)
|
: mSpellsChanged (false)
|
||||||
, mLastUpdate (MWBase::Environment::get().getWorld()->getTimeStamp())
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
const MagicEffects& ActiveSpells::getMagicEffects() const
|
const MagicEffects& ActiveSpells::getMagicEffects() const
|
||||||
{
|
{
|
||||||
update();
|
update(0.f);
|
||||||
return mEffects;
|
return mEffects;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,19 +103,14 @@ namespace MWMechanics
|
|||||||
for (std::vector<ActiveEffect>::const_iterator iter (effects.begin());
|
for (std::vector<ActiveEffect>::const_iterator iter (effects.begin());
|
||||||
iter!=effects.end(); ++iter)
|
iter!=effects.end(); ++iter)
|
||||||
{
|
{
|
||||||
if (iter->mDuration > duration)
|
if (iter->mTimeLeft > duration)
|
||||||
duration = iter->mDuration;
|
duration = iter->mTimeLeft;
|
||||||
}
|
}
|
||||||
|
|
||||||
double scaledDuration = duration *
|
if (duration < 0)
|
||||||
MWBase::Environment::get().getWorld()->getTimeScaleFactor()/(60*60);
|
|
||||||
|
|
||||||
double usedUp = MWBase::Environment::get().getWorld()->getTimeStamp() - iterator->second.mTimeStamp;
|
|
||||||
|
|
||||||
if (usedUp>=scaledDuration)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return scaledDuration-usedUp;
|
return duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ActiveSpells::isSpellActive(const std::string& id) const
|
bool ActiveSpells::isSpellActive(const std::string& id) const
|
||||||
@ -152,7 +134,6 @@ namespace MWMechanics
|
|||||||
TContainer::iterator it(mSpells.find(id));
|
TContainer::iterator it(mSpells.find(id));
|
||||||
|
|
||||||
ActiveSpellParams params;
|
ActiveSpellParams params;
|
||||||
params.mTimeStamp = MWBase::Environment::get().getWorld()->getTimeStamp();
|
|
||||||
params.mEffects = effects;
|
params.mEffects = effects;
|
||||||
params.mDisplayName = displayName;
|
params.mDisplayName = displayName;
|
||||||
params.mCasterActorId = casterActorId;
|
params.mCasterActorId = casterActorId;
|
||||||
@ -211,19 +192,15 @@ namespace MWMechanics
|
|||||||
{
|
{
|
||||||
for (TContainer::const_iterator it = begin(); it != end(); ++it)
|
for (TContainer::const_iterator it = begin(); it != end(); ++it)
|
||||||
{
|
{
|
||||||
float timeScale = MWBase::Environment::get().getWorld()->getTimeScaleFactor();
|
|
||||||
|
|
||||||
for (std::vector<ActiveEffect>::const_iterator effectIt = it->second.mEffects.begin();
|
for (std::vector<ActiveEffect>::const_iterator effectIt = it->second.mEffects.begin();
|
||||||
effectIt != it->second.mEffects.end(); ++effectIt)
|
effectIt != it->second.mEffects.end(); ++effectIt)
|
||||||
{
|
{
|
||||||
std::string name = it->second.mDisplayName;
|
std::string name = it->second.mDisplayName;
|
||||||
|
|
||||||
float remainingTime = effectIt->mDuration +
|
|
||||||
static_cast<float>(it->second.mTimeStamp - MWBase::Environment::get().getWorld()->getTimeStamp())*3600/timeScale;
|
|
||||||
float magnitude = effectIt->mMagnitude;
|
float magnitude = effectIt->mMagnitude;
|
||||||
|
|
||||||
if (magnitude)
|
if (magnitude)
|
||||||
visitor.visit(MWMechanics::EffectKey(effectIt->mEffectId, effectIt->mArg), name, it->first, it->second.mCasterActorId, magnitude, remainingTime, effectIt->mDuration);
|
visitor.visit(MWMechanics::EffectKey(effectIt->mEffectId, effectIt->mArg), name, it->first, it->second.mCasterActorId, magnitude, effectIt->mTimeLeft, effectIt->mDuration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -316,7 +293,6 @@ namespace MWMechanics
|
|||||||
params.mEffects = it->second.mEffects;
|
params.mEffects = it->second.mEffects;
|
||||||
params.mCasterActorId = it->second.mCasterActorId;
|
params.mCasterActorId = it->second.mCasterActorId;
|
||||||
params.mDisplayName = it->second.mDisplayName;
|
params.mDisplayName = it->second.mDisplayName;
|
||||||
params.mTimeStamp = it->second.mTimeStamp.toEsm();
|
|
||||||
|
|
||||||
state.mSpells.insert (std::make_pair(it->first, params));
|
state.mSpells.insert (std::make_pair(it->first, params));
|
||||||
}
|
}
|
||||||
@ -331,7 +307,6 @@ namespace MWMechanics
|
|||||||
params.mEffects = it->second.mEffects;
|
params.mEffects = it->second.mEffects;
|
||||||
params.mCasterActorId = it->second.mCasterActorId;
|
params.mCasterActorId = it->second.mCasterActorId;
|
||||||
params.mDisplayName = it->second.mDisplayName;
|
params.mDisplayName = it->second.mDisplayName;
|
||||||
params.mTimeStamp = MWWorld::TimeStamp(it->second.mTimeStamp);
|
|
||||||
|
|
||||||
mSpells.insert (std::make_pair(it->first, params));
|
mSpells.insert (std::make_pair(it->first, params));
|
||||||
mSpellsChanged = true;
|
mSpellsChanged = true;
|
||||||
|
@ -44,15 +44,14 @@ namespace MWMechanics
|
|||||||
|
|
||||||
TIterator end() const;
|
TIterator end() const;
|
||||||
|
|
||||||
|
void update(float duration) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
mutable TContainer mSpells;
|
mutable TContainer mSpells;
|
||||||
mutable MagicEffects mEffects;
|
mutable MagicEffects mEffects;
|
||||||
mutable bool mSpellsChanged;
|
mutable bool mSpellsChanged;
|
||||||
mutable MWWorld::TimeStamp mLastUpdate;
|
|
||||||
|
|
||||||
void update() const;
|
|
||||||
|
|
||||||
void rebuildEffects() const;
|
void rebuildEffects() const;
|
||||||
|
|
||||||
/// Add any effects that are in "from" and not in "addTo" to "addTo"
|
/// Add any effects that are in "from" and not in "addTo" to "addTo"
|
||||||
|
@ -1622,6 +1622,8 @@ namespace MWMechanics
|
|||||||
player.getClass().getCreatureStats(player).setHitAttemptActorId(-1);
|
player.getClass().getCreatureStats(player).setHitAttemptActorId(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iter->first.getClass().getCreatureStats(iter->first).getActiveSpells().update(duration);
|
||||||
|
|
||||||
// For dead actors we need to remove looping spell particles
|
// For dead actors we need to remove looping spell particles
|
||||||
if (iter->first.getClass().getCreatureStats(iter->first).isDead())
|
if (iter->first.getClass().getCreatureStats(iter->first).isDead())
|
||||||
ctrl->updateContinuousVfx();
|
ctrl->updateContinuousVfx();
|
||||||
|
@ -183,6 +183,7 @@ namespace MWMechanics
|
|||||||
effect.mEffectId = effectIt->mEffectID;
|
effect.mEffectId = effectIt->mEffectID;
|
||||||
effect.mArg = MWMechanics::EffectKey(*effectIt).mArg;
|
effect.mArg = MWMechanics::EffectKey(*effectIt).mArg;
|
||||||
effect.mMagnitude = magnitude;
|
effect.mMagnitude = magnitude;
|
||||||
|
effect.mTimeLeft = 0.f;
|
||||||
|
|
||||||
// Avoid applying absorb effects if the caster is the target
|
// Avoid applying absorb effects if the caster is the target
|
||||||
// We still need the spell to be added
|
// We still need the spell to be added
|
||||||
@ -225,6 +226,8 @@ namespace MWMechanics
|
|||||||
{
|
{
|
||||||
effect.mDuration = hasDuration ? static_cast<float>(effectIt->mDuration) : 1.f;
|
effect.mDuration = hasDuration ? static_cast<float>(effectIt->mDuration) : 1.f;
|
||||||
|
|
||||||
|
effect.mTimeLeft = effect.mDuration;
|
||||||
|
|
||||||
targetEffects.add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(effect.mMagnitude));
|
targetEffects.add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(effect.mMagnitude));
|
||||||
|
|
||||||
// add to list of active effects, to apply in next frame
|
// add to list of active effects, to apply in next frame
|
||||||
|
@ -16,7 +16,6 @@ namespace ESM
|
|||||||
|
|
||||||
esm.writeHNT ("CAST", params.mCasterActorId);
|
esm.writeHNT ("CAST", params.mCasterActorId);
|
||||||
esm.writeHNString ("DISP", params.mDisplayName);
|
esm.writeHNString ("DISP", params.mDisplayName);
|
||||||
esm.writeHNT ("TIME", params.mTimeStamp);
|
|
||||||
|
|
||||||
for (std::vector<ActiveEffect>::const_iterator effectIt = params.mEffects.begin(); effectIt != params.mEffects.end(); ++effectIt)
|
for (std::vector<ActiveEffect>::const_iterator effectIt = params.mEffects.begin(); effectIt != params.mEffects.end(); ++effectIt)
|
||||||
{
|
{
|
||||||
@ -25,12 +24,15 @@ namespace ESM
|
|||||||
esm.writeHNT ("ARG_", effectIt->mArg);
|
esm.writeHNT ("ARG_", effectIt->mArg);
|
||||||
esm.writeHNT ("MAGN", effectIt->mMagnitude);
|
esm.writeHNT ("MAGN", effectIt->mMagnitude);
|
||||||
esm.writeHNT ("DURA", effectIt->mDuration);
|
esm.writeHNT ("DURA", effectIt->mDuration);
|
||||||
|
esm.writeHNT ("LEFT", effectIt->mTimeLeft);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActiveSpells::load(ESMReader &esm)
|
void ActiveSpells::load(ESMReader &esm)
|
||||||
{
|
{
|
||||||
|
int format = esm.getFormat();
|
||||||
|
|
||||||
while (esm.isNextSub("ID__"))
|
while (esm.isNextSub("ID__"))
|
||||||
{
|
{
|
||||||
std::string spellId = esm.getHString();
|
std::string spellId = esm.getHString();
|
||||||
@ -38,7 +40,10 @@ namespace ESM
|
|||||||
ActiveSpellParams params;
|
ActiveSpellParams params;
|
||||||
esm.getHNT (params.mCasterActorId, "CAST");
|
esm.getHNT (params.mCasterActorId, "CAST");
|
||||||
params.mDisplayName = esm.getHNString ("DISP");
|
params.mDisplayName = esm.getHNString ("DISP");
|
||||||
esm.getHNT (params.mTimeStamp, "TIME");
|
|
||||||
|
// spell casting timestamp, no longer used
|
||||||
|
if (esm.isNextSub("TIME"))
|
||||||
|
esm.skipHSub();
|
||||||
|
|
||||||
while (esm.isNextSub("MGEF"))
|
while (esm.isNextSub("MGEF"))
|
||||||
{
|
{
|
||||||
@ -48,6 +53,11 @@ namespace ESM
|
|||||||
esm.getHNOT(effect.mArg, "ARG_");
|
esm.getHNOT(effect.mArg, "ARG_");
|
||||||
esm.getHNT (effect.mMagnitude, "MAGN");
|
esm.getHNT (effect.mMagnitude, "MAGN");
|
||||||
esm.getHNT (effect.mDuration, "DURA");
|
esm.getHNT (effect.mDuration, "DURA");
|
||||||
|
if (format < 9)
|
||||||
|
effect.mTimeLeft = effect.mDuration;
|
||||||
|
else
|
||||||
|
esm.getHNT (effect.mTimeLeft, "LEFT");
|
||||||
|
|
||||||
params.mEffects.push_back(effect);
|
params.mEffects.push_back(effect);
|
||||||
}
|
}
|
||||||
mSpells.insert(std::make_pair(spellId, params));
|
mSpells.insert(std::make_pair(spellId, params));
|
||||||
|
@ -21,6 +21,7 @@ namespace ESM
|
|||||||
float mMagnitude;
|
float mMagnitude;
|
||||||
int mArg; // skill or attribute
|
int mArg; // skill or attribute
|
||||||
float mDuration;
|
float mDuration;
|
||||||
|
float mTimeLeft;
|
||||||
};
|
};
|
||||||
|
|
||||||
// format 0, saved games only
|
// format 0, saved games only
|
||||||
@ -29,7 +30,6 @@ namespace ESM
|
|||||||
struct ActiveSpellParams
|
struct ActiveSpellParams
|
||||||
{
|
{
|
||||||
std::vector<ActiveEffect> mEffects;
|
std::vector<ActiveEffect> mEffects;
|
||||||
ESM::TimeStamp mTimeStamp;
|
|
||||||
std::string mDisplayName;
|
std::string mDisplayName;
|
||||||
int mCasterActorId;
|
int mCasterActorId;
|
||||||
};
|
};
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
#include "defs.hpp"
|
#include "defs.hpp"
|
||||||
|
|
||||||
unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE;
|
unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE;
|
||||||
int ESM::SavedGame::sCurrentFormat = 8;
|
int ESM::SavedGame::sCurrentFormat = 9;
|
||||||
|
|
||||||
void ESM::SavedGame::load (ESMReader &esm)
|
void ESM::SavedGame::load (ESMReader &esm)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user