mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-18 13:12:50 +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 #4774: Guards are ignorant of an invisible player that tries to attack them
|
||||
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 #5363: Enchantment autocalc not always 0/1
|
||||
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 #5159: NiMaterialColorController can only control the diffuse color
|
||||
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 #5164: Faction owned items handling is incorrect
|
||||
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 #5168: Force1stPerson and Force3rdPerson commands are not really force view change
|
||||
|
@ -12,14 +12,12 @@
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
void ActiveSpells::update() const
|
||||
void ActiveSpells::update(float duration) const
|
||||
{
|
||||
bool rebuild = false;
|
||||
|
||||
MWWorld::TimeStamp now = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
|
||||
// Erase no longer active spells and effects
|
||||
if (mLastUpdate!=now)
|
||||
if (duration > 0)
|
||||
{
|
||||
TContainer::iterator iter (mSpells.begin());
|
||||
while (iter!=mSpells.end())
|
||||
@ -34,21 +32,20 @@ namespace MWMechanics
|
||||
std::vector<ActiveEffect>& effects = iter->second.mEffects;
|
||||
for (std::vector<ActiveEffect>::iterator effectIt = effects.begin(); effectIt != effects.end();)
|
||||
{
|
||||
MWWorld::TimeStamp start = iter->second.mTimeStamp;
|
||||
MWWorld::TimeStamp end = start + static_cast<double>(effectIt->mDuration)*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/(60*60);
|
||||
if (end <= now)
|
||||
if (effectIt->mTimeLeft <= 0)
|
||||
{
|
||||
effectIt = effects.erase(effectIt);
|
||||
rebuild = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
effectIt->mTimeLeft -= duration;
|
||||
++effectIt;
|
||||
}
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
mLastUpdate = now;
|
||||
}
|
||||
|
||||
if (mSpellsChanged)
|
||||
@ -63,24 +60,15 @@ namespace MWMechanics
|
||||
|
||||
void ActiveSpells::rebuildEffects() const
|
||||
{
|
||||
MWWorld::TimeStamp now = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
|
||||
mEffects = MagicEffects();
|
||||
|
||||
for (TIterator iter (begin()); iter!=end(); ++iter)
|
||||
{
|
||||
const MWWorld::TimeStamp& start = iter->second.mTimeStamp;
|
||||
|
||||
const std::vector<ActiveEffect>& effects = iter->second.mEffects;
|
||||
|
||||
for (std::vector<ActiveEffect>::const_iterator effectIt = effects.begin(); effectIt != effects.end(); ++effectIt)
|
||||
{
|
||||
double duration = effectIt->mDuration;
|
||||
MWWorld::TimeStamp end = start;
|
||||
end += duration *
|
||||
MWBase::Environment::get().getWorld()->getTimeScaleFactor()/(60*60);
|
||||
|
||||
if (end>now)
|
||||
if (effectIt->mTimeLeft > 0)
|
||||
mEffects.add(MWMechanics::EffectKey(effectIt->mEffectId, effectIt->mArg), MWMechanics::EffectParam(effectIt->mMagnitude));
|
||||
}
|
||||
}
|
||||
@ -88,12 +76,11 @@ namespace MWMechanics
|
||||
|
||||
ActiveSpells::ActiveSpells()
|
||||
: mSpellsChanged (false)
|
||||
, mLastUpdate (MWBase::Environment::get().getWorld()->getTimeStamp())
|
||||
{}
|
||||
|
||||
const MagicEffects& ActiveSpells::getMagicEffects() const
|
||||
{
|
||||
update();
|
||||
update(0.f);
|
||||
return mEffects;
|
||||
}
|
||||
|
||||
@ -116,19 +103,14 @@ namespace MWMechanics
|
||||
for (std::vector<ActiveEffect>::const_iterator iter (effects.begin());
|
||||
iter!=effects.end(); ++iter)
|
||||
{
|
||||
if (iter->mDuration > duration)
|
||||
duration = iter->mDuration;
|
||||
if (iter->mTimeLeft > duration)
|
||||
duration = iter->mTimeLeft;
|
||||
}
|
||||
|
||||
double scaledDuration = duration *
|
||||
MWBase::Environment::get().getWorld()->getTimeScaleFactor()/(60*60);
|
||||
|
||||
double usedUp = MWBase::Environment::get().getWorld()->getTimeStamp() - iterator->second.mTimeStamp;
|
||||
|
||||
if (usedUp>=scaledDuration)
|
||||
if (duration < 0)
|
||||
return 0;
|
||||
|
||||
return scaledDuration-usedUp;
|
||||
return duration;
|
||||
}
|
||||
|
||||
bool ActiveSpells::isSpellActive(const std::string& id) const
|
||||
@ -152,7 +134,6 @@ namespace MWMechanics
|
||||
TContainer::iterator it(mSpells.find(id));
|
||||
|
||||
ActiveSpellParams params;
|
||||
params.mTimeStamp = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
params.mEffects = effects;
|
||||
params.mDisplayName = displayName;
|
||||
params.mCasterActorId = casterActorId;
|
||||
@ -211,19 +192,15 @@ namespace MWMechanics
|
||||
{
|
||||
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();
|
||||
effectIt != it->second.mEffects.end(); ++effectIt)
|
||||
{
|
||||
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;
|
||||
|
||||
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.mCasterActorId = it->second.mCasterActorId;
|
||||
params.mDisplayName = it->second.mDisplayName;
|
||||
params.mTimeStamp = it->second.mTimeStamp.toEsm();
|
||||
|
||||
state.mSpells.insert (std::make_pair(it->first, params));
|
||||
}
|
||||
@ -331,7 +307,6 @@ namespace MWMechanics
|
||||
params.mEffects = it->second.mEffects;
|
||||
params.mCasterActorId = it->second.mCasterActorId;
|
||||
params.mDisplayName = it->second.mDisplayName;
|
||||
params.mTimeStamp = MWWorld::TimeStamp(it->second.mTimeStamp);
|
||||
|
||||
mSpells.insert (std::make_pair(it->first, params));
|
||||
mSpellsChanged = true;
|
||||
|
@ -44,15 +44,14 @@ namespace MWMechanics
|
||||
|
||||
TIterator end() const;
|
||||
|
||||
void update(float duration) const;
|
||||
|
||||
private:
|
||||
|
||||
mutable TContainer mSpells;
|
||||
mutable MagicEffects mEffects;
|
||||
mutable bool mSpellsChanged;
|
||||
mutable MWWorld::TimeStamp mLastUpdate;
|
||||
|
||||
void update() const;
|
||||
|
||||
void rebuildEffects() const;
|
||||
|
||||
/// 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);
|
||||
}
|
||||
|
||||
iter->first.getClass().getCreatureStats(iter->first).getActiveSpells().update(duration);
|
||||
|
||||
// For dead actors we need to remove looping spell particles
|
||||
if (iter->first.getClass().getCreatureStats(iter->first).isDead())
|
||||
ctrl->updateContinuousVfx();
|
||||
|
@ -183,6 +183,7 @@ namespace MWMechanics
|
||||
effect.mEffectId = effectIt->mEffectID;
|
||||
effect.mArg = MWMechanics::EffectKey(*effectIt).mArg;
|
||||
effect.mMagnitude = magnitude;
|
||||
effect.mTimeLeft = 0.f;
|
||||
|
||||
// Avoid applying absorb effects if the caster is the target
|
||||
// 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.mTimeLeft = effect.mDuration;
|
||||
|
||||
targetEffects.add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(effect.mMagnitude));
|
||||
|
||||
// add to list of active effects, to apply in next frame
|
||||
|
@ -16,7 +16,6 @@ namespace ESM
|
||||
|
||||
esm.writeHNT ("CAST", params.mCasterActorId);
|
||||
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)
|
||||
{
|
||||
@ -25,12 +24,15 @@ namespace ESM
|
||||
esm.writeHNT ("ARG_", effectIt->mArg);
|
||||
esm.writeHNT ("MAGN", effectIt->mMagnitude);
|
||||
esm.writeHNT ("DURA", effectIt->mDuration);
|
||||
esm.writeHNT ("LEFT", effectIt->mTimeLeft);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ActiveSpells::load(ESMReader &esm)
|
||||
{
|
||||
int format = esm.getFormat();
|
||||
|
||||
while (esm.isNextSub("ID__"))
|
||||
{
|
||||
std::string spellId = esm.getHString();
|
||||
@ -38,7 +40,10 @@ namespace ESM
|
||||
ActiveSpellParams params;
|
||||
esm.getHNT (params.mCasterActorId, "CAST");
|
||||
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"))
|
||||
{
|
||||
@ -48,6 +53,11 @@ namespace ESM
|
||||
esm.getHNOT(effect.mArg, "ARG_");
|
||||
esm.getHNT (effect.mMagnitude, "MAGN");
|
||||
esm.getHNT (effect.mDuration, "DURA");
|
||||
if (format < 9)
|
||||
effect.mTimeLeft = effect.mDuration;
|
||||
else
|
||||
esm.getHNT (effect.mTimeLeft, "LEFT");
|
||||
|
||||
params.mEffects.push_back(effect);
|
||||
}
|
||||
mSpells.insert(std::make_pair(spellId, params));
|
||||
|
@ -21,6 +21,7 @@ namespace ESM
|
||||
float mMagnitude;
|
||||
int mArg; // skill or attribute
|
||||
float mDuration;
|
||||
float mTimeLeft;
|
||||
};
|
||||
|
||||
// format 0, saved games only
|
||||
@ -29,7 +30,6 @@ namespace ESM
|
||||
struct ActiveSpellParams
|
||||
{
|
||||
std::vector<ActiveEffect> mEffects;
|
||||
ESM::TimeStamp mTimeStamp;
|
||||
std::string mDisplayName;
|
||||
int mCasterActorId;
|
||||
};
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "defs.hpp"
|
||||
|
||||
unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE;
|
||||
int ESM::SavedGame::sCurrentFormat = 8;
|
||||
int ESM::SavedGame::sCurrentFormat = 9;
|
||||
|
||||
void ESM::SavedGame::load (ESMReader &esm)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user