forked from mirror/openmw-tes3mp
commit
4d2ca20445
14 changed files with 176 additions and 84 deletions
|
@ -101,6 +101,7 @@ Programmers
|
||||||
Nikolay Kasyanov (corristo)
|
Nikolay Kasyanov (corristo)
|
||||||
nobrakal
|
nobrakal
|
||||||
Nolan Poe (nopoe)
|
Nolan Poe (nopoe)
|
||||||
|
Oleg Chkan (mrcheko)
|
||||||
Paul Cercueil (pcercuei)
|
Paul Cercueil (pcercuei)
|
||||||
Paul McElroy (Greendogo)
|
Paul McElroy (Greendogo)
|
||||||
Pi03k
|
Pi03k
|
||||||
|
|
65
CHANGELOG.md
65
CHANGELOG.md
|
@ -1,3 +1,68 @@
|
||||||
|
0.40.0
|
||||||
|
------
|
||||||
|
|
||||||
|
Bug #1320: AiWander - Creatures in cells without pathgrids do not wander
|
||||||
|
Bug #1873: Death events are triggered at the beginning of the death animation
|
||||||
|
Bug #1996: Resting interrupts magic effects
|
||||||
|
Bug #2399: Vampires can rest in broad daylight and survive the experience
|
||||||
|
Bug #2604: Incorrect magicka recalculation
|
||||||
|
Bug #2721: Telekinesis extends interaction range where it shouldn't
|
||||||
|
Bug #2981: When waiting, NPCs can go where they wouldn't go normally.
|
||||||
|
Bug #3045: Esp files containing the letter '#' in the file name cannot be loaded on startup
|
||||||
|
Bug #3071: Slowfall does not stop momentum when jumping
|
||||||
|
Bug #3085: Plugins can not replace parent cell references with a cell reference of different type
|
||||||
|
Bug #3145: Bug with AI Cliff Racer. He will not attack you, unless you put in front of him.
|
||||||
|
Bug #3149: Editor: Weather tables were missing from regions
|
||||||
|
Bug #3201: Netch shoots over your head
|
||||||
|
Bug #3269: If you deselect a mod and try to load a save made inside a cell added by it, you end bellow the terrain in the grid 0/0
|
||||||
|
Bug #3286: Editor: Script editor tab width
|
||||||
|
Bug #3329: Teleportation spells cause crash to desktop after build update from 0.37 to 0.38.0
|
||||||
|
Bug #3331: Editor: Start Scripts table: Adding a script doesn't refresh the list of Start Scripts and allows to add a single script multiple times
|
||||||
|
Bug #3332: Editor: Scene view: Tool tips only occur when holding the left mouse button
|
||||||
|
Bug #3340: ESS-Importer does not separate item stacks
|
||||||
|
Bug #3342: Editor: Creation of pathgrids did not check if the pathgrid already existed
|
||||||
|
Bug #3346: "Talked to PC" is always 0 for "Hello" dialogue
|
||||||
|
Bug #3349: AITravel doesn't repeat
|
||||||
|
Bug #3370: NPCs wandering to invalid locations after training
|
||||||
|
Bug #3378: "StopCombat" command does not function in vanilla quest
|
||||||
|
Bug #3384: Battle at Nchurdamz - Larienna Macrina does not stop combat after killing Hrelvesuu
|
||||||
|
Bug #3388: Monster Respawn tied to Quicksave
|
||||||
|
Bug #3390: Strange visual effect in Dagoth Ur's chamber
|
||||||
|
Bug #3391: Inappropriate Blight weather behavior at end of main quest
|
||||||
|
Bug #3394: Replaced dialogue inherits some of its old data
|
||||||
|
Bug #3397: Actors that start the game dead always have the same death pose
|
||||||
|
Bug #3401: Sirollus Saccus sells not glass arrows
|
||||||
|
Bug #3402: Editor: Weapon data not being properly set
|
||||||
|
Bug #3405: Mulvisic Othril will not use her chitin throwing stars
|
||||||
|
Bug #3407: Tanisie Verethi will immediately detect the player
|
||||||
|
Bug #3408: Improper behavior of ashmire particles
|
||||||
|
Bug #3412: Ai Wander start time resets when saving/loading the game
|
||||||
|
Bug #3416: 1st person and 3rd person camera isn't converted from .ess correctly
|
||||||
|
Bug #3421: Idling long enough while paralyzed sometimes causes character to get stuck
|
||||||
|
Bug #3423: Sleep interruption inside dungeons too agressive
|
||||||
|
Bug #3424: Pickpocketing sometimes won't work
|
||||||
|
Bug #3432: AiFollow / AiEscort durations handled incorrectly
|
||||||
|
Bug #3434: Dead NPC's and Creatures still contribute to sneak skill increases
|
||||||
|
Bug #3437: Weather-conditioned dialogue should not play in interiors
|
||||||
|
Bug #3439: Effects cast by summon stick around after their death
|
||||||
|
Bug #3440: Parallax maps looks weird
|
||||||
|
Bug #3443: Class graphic for custom class should be Acrobat
|
||||||
|
Bug #3446: OpenMW segfaults when using Atrayonis's "Anthology Solstheim: Tomb of the Snow Prince" mod
|
||||||
|
Bug #3448: After dispelled, invisibility icon is still displayed
|
||||||
|
Bug #3453: First couple of seconds of NPC speech is muted
|
||||||
|
Bug #3455: Portable house mods lock player and npc movement up exiting house.
|
||||||
|
Bug #3456: Equipping an item will undo dispel of constant effect invisibility
|
||||||
|
Bug #3458: Constant effect restore health doesn't work during Wait
|
||||||
|
Bug #3466: It is possible to stack multiple scroll effects of the same type
|
||||||
|
Bug #3471: When two mods delete the same references, many references are not disabled by the engine.
|
||||||
|
Bug #3473: 3rd person camera can be glitched
|
||||||
|
Feature #1424: NPC "Face" function
|
||||||
|
Feature #2974: Editor: Multiple Deletion of Subrecords
|
||||||
|
Feature #3044: Editor: Render path grid v2
|
||||||
|
Feature #3362: Editor: Configurable key bindings
|
||||||
|
Feature #3375: Make sun / moon reflections weather dependent
|
||||||
|
Feature #3386: Editor: Edit pathgrid
|
||||||
|
|
||||||
0.39.0
|
0.39.0
|
||||||
------
|
------
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ endif()
|
||||||
message(STATUS "Configuring OpenMW...")
|
message(STATUS "Configuring OpenMW...")
|
||||||
|
|
||||||
set(OPENMW_VERSION_MAJOR 0)
|
set(OPENMW_VERSION_MAJOR 0)
|
||||||
set(OPENMW_VERSION_MINOR 39)
|
set(OPENMW_VERSION_MINOR 40)
|
||||||
set(OPENMW_VERSION_RELEASE 0)
|
set(OPENMW_VERSION_RELEASE 0)
|
||||||
|
|
||||||
set(OPENMW_VERSION_COMMITHASH "")
|
set(OPENMW_VERSION_COMMITHASH "")
|
||||||
|
|
|
@ -15,6 +15,7 @@ namespace CSMPrefs
|
||||||
ModifierSetting::ModifierSetting(Category* parent, Settings::Manager* values, QMutex* mutex, const std::string& key,
|
ModifierSetting::ModifierSetting(Category* parent, Settings::Manager* values, QMutex* mutex, const std::string& key,
|
||||||
const std::string& label)
|
const std::string& label)
|
||||||
: Setting(parent, values, mutex, key, label)
|
: Setting(parent, values, mutex, key, label)
|
||||||
|
, mButton(0)
|
||||||
, mEditorActive(false)
|
, mEditorActive(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ namespace CSMPrefs
|
||||||
ShortcutSetting::ShortcutSetting(Category* parent, Settings::Manager* values, QMutex* mutex, const std::string& key,
|
ShortcutSetting::ShortcutSetting(Category* parent, Settings::Manager* values, QMutex* mutex, const std::string& key,
|
||||||
const std::string& label)
|
const std::string& label)
|
||||||
: Setting(parent, values, mutex, key, label)
|
: Setting(parent, values, mutex, key, label)
|
||||||
|
, mButton(0)
|
||||||
, mEditorActive(false)
|
, mEditorActive(false)
|
||||||
, mEditorPos(0)
|
, mEditorPos(0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -74,7 +74,9 @@ osg::Vec3f CSVRender::InstanceMode::getSelectionCenter(const std::vector<osg::re
|
||||||
++objectCount;
|
++objectCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
center /= objectCount;
|
|
||||||
|
if (objectCount > 0)
|
||||||
|
center /= objectCount;
|
||||||
|
|
||||||
return center;
|
return center;
|
||||||
}
|
}
|
||||||
|
@ -92,7 +94,7 @@ osg::Vec3f CSVRender::InstanceMode::getScreenCoords(const osg::Vec3f& pos)
|
||||||
CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent)
|
CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent)
|
||||||
: EditMode (worldspaceWidget, QIcon (":placeholder"), Mask_Reference, "Instance editing",
|
: EditMode (worldspaceWidget, QIcon (":placeholder"), Mask_Reference, "Instance editing",
|
||||||
parent), mSubMode (0), mSubModeId ("move"), mSelectionMode (0), mDragMode (DragMode_None),
|
parent), mSubMode (0), mSubModeId ("move"), mSelectionMode (0), mDragMode (DragMode_None),
|
||||||
mDragAxis (-1), mLocked (false)
|
mDragAxis (-1), mLocked (false), mUnitScaleDist(1)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,7 +124,7 @@ namespace MWClass
|
||||||
int index = ESM::MagicEffect::effectStringToId("sEffectTelekinesis");
|
int index = ESM::MagicEffect::effectStringToId("sEffectTelekinesis");
|
||||||
const ESM::MagicEffect *effect = store.get<ESM::MagicEffect>().find(index);
|
const ESM::MagicEffect *effect = store.get<ESM::MagicEffect>().find(index);
|
||||||
|
|
||||||
animation->addSpellCastGlow(effect); // TODO: Telekinesis glow should only be as long as the door animation
|
animation->addSpellCastGlow(effect, 1); // 1 second glow to match the time taken for a door opening or closing
|
||||||
}
|
}
|
||||||
|
|
||||||
// make key id lowercase
|
// make key id lowercase
|
||||||
|
|
|
@ -1524,6 +1524,26 @@ bool CharacterController::updateWeaponState()
|
||||||
return forcestateupdate;
|
return forcestateupdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CharacterController::updateAnimQueue()
|
||||||
|
{
|
||||||
|
if(mAnimQueue.size() > 1)
|
||||||
|
{
|
||||||
|
if(mAnimation->isPlaying(mAnimQueue.front().mGroup) == false)
|
||||||
|
{
|
||||||
|
mAnimation->disable(mAnimQueue.front().mGroup);
|
||||||
|
mAnimQueue.pop_front();
|
||||||
|
|
||||||
|
bool loopfallback = (mAnimQueue.front().mGroup.compare(0,4,"idle") == 0);
|
||||||
|
mAnimation->play(mAnimQueue.front().mGroup, Priority_Default,
|
||||||
|
MWRender::Animation::BlendMask_All, false,
|
||||||
|
1.0f, "start", "stop", 0.0f, mAnimQueue.front().mLoopCount, loopfallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!mAnimQueue.empty())
|
||||||
|
mAnimation->setLoopingEnabled(mAnimQueue.front().mGroup, mAnimQueue.size() <= 1);
|
||||||
|
}
|
||||||
|
|
||||||
void CharacterController::update(float duration)
|
void CharacterController::update(float duration)
|
||||||
{
|
{
|
||||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
|
@ -1534,21 +1554,7 @@ void CharacterController::update(float duration)
|
||||||
updateMagicEffects();
|
updateMagicEffects();
|
||||||
|
|
||||||
if(!cls.isActor())
|
if(!cls.isActor())
|
||||||
{
|
updateAnimQueue();
|
||||||
if(mAnimQueue.size() > 1)
|
|
||||||
{
|
|
||||||
if(mAnimation->isPlaying(mAnimQueue.front().mGroup) == false)
|
|
||||||
{
|
|
||||||
mAnimation->disable(mAnimQueue.front().mGroup);
|
|
||||||
mAnimQueue.pop_front();
|
|
||||||
|
|
||||||
bool loopfallback = (mAnimQueue.front().mGroup.compare(0,4,"idle") == 0);
|
|
||||||
mAnimation->play(mAnimQueue.front().mGroup, Priority_Default,
|
|
||||||
MWRender::Animation::BlendMask_All, false,
|
|
||||||
1.0f, "start", "stop", 0.0f, mAnimQueue.front().mLoopCount, loopfallback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(!cls.getCreatureStats(mPtr).isDead())
|
else if(!cls.getCreatureStats(mPtr).isDead())
|
||||||
{
|
{
|
||||||
bool onground = world->isOnGround(mPtr);
|
bool onground = world->isOnGround(mPtr);
|
||||||
|
@ -1816,19 +1822,8 @@ void CharacterController::update(float duration)
|
||||||
{
|
{
|
||||||
idlestate = (inwater ? CharState_IdleSwim : (sneak && !inJump ? CharState_IdleSneak : CharState_Idle));
|
idlestate = (inwater ? CharState_IdleSwim : (sneak && !inJump ? CharState_IdleSneak : CharState_Idle));
|
||||||
}
|
}
|
||||||
else if(mAnimQueue.size() > 1)
|
else
|
||||||
{
|
updateAnimQueue();
|
||||||
if(mAnimation->isPlaying(mAnimQueue.front().mGroup) == false)
|
|
||||||
{
|
|
||||||
mAnimation->disable(mAnimQueue.front().mGroup);
|
|
||||||
mAnimQueue.pop_front();
|
|
||||||
|
|
||||||
bool loopfallback = (mAnimQueue.front().mGroup.compare(0,4,"idle") == 0);
|
|
||||||
mAnimation->play(mAnimQueue.front().mGroup, Priority_Default,
|
|
||||||
MWRender::Animation::BlendMask_All, false,
|
|
||||||
1.0f, "start", "stop", 0.0f, mAnimQueue.front().mLoopCount, loopfallback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mSkipAnim)
|
if (!mSkipAnim)
|
||||||
{
|
{
|
||||||
|
@ -1994,9 +1989,10 @@ void CharacterController::unpersistAnimationState()
|
||||||
mCurrentIdle.clear();
|
mCurrentIdle.clear();
|
||||||
mIdleState = CharState_SpecialIdle;
|
mIdleState = CharState_SpecialIdle;
|
||||||
|
|
||||||
|
bool loopfallback = (mAnimQueue.front().mGroup.compare(0,4,"idle") == 0);
|
||||||
mAnimation->play(anim.mGroup,
|
mAnimation->play(anim.mGroup,
|
||||||
Priority_Default, MWRender::Animation::BlendMask_All, false, 1.0f,
|
Priority_Default, MWRender::Animation::BlendMask_All, false, 1.0f,
|
||||||
"start", "stop", complete, anim.mLoopCount);
|
"start", "stop", complete, anim.mLoopCount, loopfallback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2009,6 +2005,27 @@ bool CharacterController::playGroup(const std::string &groupname, int mode, int
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// If the given animation is a looped animation, is already playing
|
||||||
|
// and has not yet reached its Loop Stop key, make it the only animation
|
||||||
|
// in the queue, and retain the loop count from the animation that was
|
||||||
|
// already playing. This emulates observed behavior from the original
|
||||||
|
// engine and allows banners to animate correctly.
|
||||||
|
if (!mAnimQueue.empty() && mAnimQueue.front().mGroup == groupname &&
|
||||||
|
mAnimation->getTextKeyTime(mAnimQueue.front().mGroup+": loop start") >= 0)
|
||||||
|
{
|
||||||
|
float endOfLoop = mAnimation->getTextKeyTime(mAnimQueue.front().mGroup+": loop stop");
|
||||||
|
|
||||||
|
if (endOfLoop < 0) // if no Loop Stop key was found, use the Stop key
|
||||||
|
endOfLoop = mAnimation->getTextKeyTime(mAnimQueue.front().mGroup+": stop");
|
||||||
|
|
||||||
|
if (endOfLoop > 0 && (mAnimation->getCurrentTime(mAnimQueue.front().mGroup) < endOfLoop))
|
||||||
|
{
|
||||||
|
mAnimation->setLoopingEnabled(mAnimQueue.front().mGroup, true);
|
||||||
|
mAnimQueue.resize(1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
count = std::max(count, 1);
|
count = std::max(count, 1);
|
||||||
|
|
||||||
AnimationQueueEntry entry;
|
AnimationQueueEntry entry;
|
||||||
|
@ -2032,8 +2049,6 @@ bool CharacterController::playGroup(const std::string &groupname, int mode, int
|
||||||
}
|
}
|
||||||
else if(mode == 0)
|
else if(mode == 0)
|
||||||
{
|
{
|
||||||
if (!mAnimQueue.empty())
|
|
||||||
mAnimation->stopLooping(mAnimQueue.front().mGroup);
|
|
||||||
mAnimQueue.resize(1);
|
mAnimQueue.resize(1);
|
||||||
mAnimQueue.push_back(entry);
|
mAnimQueue.push_back(entry);
|
||||||
}
|
}
|
||||||
|
|
|
@ -212,6 +212,8 @@ class CharacterController : public MWRender::Animation::TextKeyListener
|
||||||
bool updateCreatureState();
|
bool updateCreatureState();
|
||||||
void updateIdleStormState(bool inwater);
|
void updateIdleStormState(bool inwater);
|
||||||
|
|
||||||
|
void updateAnimQueue();
|
||||||
|
|
||||||
void updateHeadTracking(float duration);
|
void updateHeadTracking(float duration);
|
||||||
|
|
||||||
void updateMagicEffects();
|
void updateMagicEffects();
|
||||||
|
|
|
@ -873,16 +873,6 @@ namespace MWRender
|
||||||
addControllers();
|
addControllers();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animation::stopLooping(const std::string& groupname)
|
|
||||||
{
|
|
||||||
AnimStateMap::iterator stateiter = mStates.find(groupname);
|
|
||||||
if(stateiter != mStates.end())
|
|
||||||
{
|
|
||||||
stateiter->second.mLoopCount = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Animation::adjustSpeedMult(const std::string &groupname, float speedmult)
|
void Animation::adjustSpeedMult(const std::string &groupname, float speedmult)
|
||||||
{
|
{
|
||||||
AnimStateMap::iterator state(mStates.find(groupname));
|
AnimStateMap::iterator state(mStates.find(groupname));
|
||||||
|
@ -1023,35 +1013,33 @@ namespace MWRender
|
||||||
{
|
{
|
||||||
float targetTime;
|
float targetTime;
|
||||||
|
|
||||||
if(state.getTime() >= state.mLoopStopTime && state.mLoopCount > 0)
|
if (!state.shouldLoop())
|
||||||
goto handle_loop;
|
|
||||||
|
|
||||||
targetTime = state.getTime() + timepassed;
|
|
||||||
if(textkey == textkeys.end() || textkey->first > targetTime)
|
|
||||||
{
|
{
|
||||||
if(mAccumCtrl && state.mTime == mAnimationTimePtr[0]->getTimePtr())
|
targetTime = state.getTime() + timepassed;
|
||||||
updatePosition(state.getTime(), targetTime, movement);
|
if(textkey == textkeys.end() || textkey->first > targetTime)
|
||||||
state.setTime(std::min(targetTime, state.mStopTime));
|
{
|
||||||
|
if(mAccumCtrl && state.mTime == mAnimationTimePtr[0]->getTimePtr())
|
||||||
|
updatePosition(state.getTime(), targetTime, movement);
|
||||||
|
state.setTime(std::min(targetTime, state.mStopTime));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(mAccumCtrl && state.mTime == mAnimationTimePtr[0]->getTimePtr())
|
||||||
|
updatePosition(state.getTime(), textkey->first, movement);
|
||||||
|
state.setTime(textkey->first);
|
||||||
|
}
|
||||||
|
|
||||||
|
state.mPlaying = (state.getTime() < state.mStopTime);
|
||||||
|
timepassed = targetTime - state.getTime();
|
||||||
|
|
||||||
|
while(textkey != textkeys.end() && textkey->first <= state.getTime())
|
||||||
|
{
|
||||||
|
handleTextKey(state, stateiter->first, textkey, textkeys);
|
||||||
|
++textkey;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
if(state.shouldLoop())
|
||||||
{
|
{
|
||||||
if(mAccumCtrl && state.mTime == mAnimationTimePtr[0]->getTimePtr())
|
|
||||||
updatePosition(state.getTime(), textkey->first, movement);
|
|
||||||
state.setTime(textkey->first);
|
|
||||||
}
|
|
||||||
|
|
||||||
state.mPlaying = (state.getTime() < state.mStopTime);
|
|
||||||
timepassed = targetTime - state.getTime();
|
|
||||||
|
|
||||||
while(textkey != textkeys.end() && textkey->first <= state.getTime())
|
|
||||||
{
|
|
||||||
handleTextKey(state, stateiter->first, textkey, textkeys);
|
|
||||||
++textkey;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(state.getTime() >= state.mLoopStopTime && state.mLoopCount > 0)
|
|
||||||
{
|
|
||||||
handle_loop:
|
|
||||||
state.mLoopCount--;
|
state.mLoopCount--;
|
||||||
state.setTime(state.mLoopStartTime);
|
state.setTime(state.mLoopStartTime);
|
||||||
state.mPlaying = true;
|
state.mPlaying = true;
|
||||||
|
@ -1065,7 +1053,7 @@ namespace MWRender
|
||||||
|
|
||||||
if(state.getTime() >= state.mLoopStopTime)
|
if(state.getTime() >= state.mLoopStopTime)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(timepassed <= 0.0f)
|
if(timepassed <= 0.0f)
|
||||||
break;
|
break;
|
||||||
|
@ -1095,6 +1083,13 @@ namespace MWRender
|
||||||
return movement;
|
return movement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Animation::setLoopingEnabled(const std::string &groupname, bool enabled)
|
||||||
|
{
|
||||||
|
AnimStateMap::iterator state(mStates.find(groupname));
|
||||||
|
if(state != mStates.end())
|
||||||
|
state->second.mLoopingEnabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
void Animation::setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature)
|
void Animation::setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature)
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::StateSet> previousStateset;
|
osg::ref_ptr<osg::StateSet> previousStateset;
|
||||||
|
@ -1192,7 +1187,7 @@ namespace MWRender
|
||||||
int mLowestUnusedTexUnit;
|
int mLowestUnusedTexUnit;
|
||||||
};
|
};
|
||||||
|
|
||||||
void Animation::addSpellCastGlow(const ESM::MagicEffect *effect)
|
void Animation::addSpellCastGlow(const ESM::MagicEffect *effect, float glowDuration)
|
||||||
{
|
{
|
||||||
osg::Vec4f glowColor(1,1,1,1);
|
osg::Vec4f glowColor(1,1,1,1);
|
||||||
glowColor.x() = effect->mData.mRed / 255.f;
|
glowColor.x() = effect->mData.mRed / 255.f;
|
||||||
|
@ -1207,10 +1202,10 @@ namespace MWRender
|
||||||
if (mGlowUpdater && mGlowUpdater->isPermanentGlowUpdater())
|
if (mGlowUpdater && mGlowUpdater->isPermanentGlowUpdater())
|
||||||
{
|
{
|
||||||
mGlowUpdater->setColor(glowColor);
|
mGlowUpdater->setColor(glowColor);
|
||||||
mGlowUpdater->setDuration(1.5); // Glow length measured from original engine as about 1.5 seconds
|
mGlowUpdater->setDuration(glowDuration);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
addGlow(mObjectRoot, glowColor, 1.5);
|
addGlow(mObjectRoot, glowColor, glowDuration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -183,6 +183,7 @@ protected:
|
||||||
float mSpeedMult;
|
float mSpeedMult;
|
||||||
|
|
||||||
bool mPlaying;
|
bool mPlaying;
|
||||||
|
bool mLoopingEnabled;
|
||||||
size_t mLoopCount;
|
size_t mLoopCount;
|
||||||
|
|
||||||
AnimPriority mPriority;
|
AnimPriority mPriority;
|
||||||
|
@ -190,8 +191,8 @@ protected:
|
||||||
bool mAutoDisable;
|
bool mAutoDisable;
|
||||||
|
|
||||||
AnimState() : mStartTime(0.0f), mLoopStartTime(0.0f), mLoopStopTime(0.0f), mStopTime(0.0f),
|
AnimState() : mStartTime(0.0f), mLoopStartTime(0.0f), mLoopStopTime(0.0f), mStopTime(0.0f),
|
||||||
mTime(new float), mSpeedMult(1.0f), mPlaying(false), mLoopCount(0),
|
mTime(new float), mSpeedMult(1.0f), mPlaying(false), mLoopingEnabled(true),
|
||||||
mPriority(0), mBlendMask(0), mAutoDisable(true)
|
mLoopCount(0), mPriority(0), mBlendMask(0), mAutoDisable(true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
~AnimState();
|
~AnimState();
|
||||||
|
@ -204,6 +205,11 @@ protected:
|
||||||
{
|
{
|
||||||
*mTime = time;
|
*mTime = time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool shouldLoop() const
|
||||||
|
{
|
||||||
|
return getTime() >= mLoopStopTime && mLoopingEnabled && mLoopCount > 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
typedef std::map<std::string,AnimState> AnimStateMap;
|
typedef std::map<std::string,AnimState> AnimStateMap;
|
||||||
AnimStateMap mStates;
|
AnimStateMap mStates;
|
||||||
|
@ -354,7 +360,9 @@ public:
|
||||||
void removeEffect (int effectId);
|
void removeEffect (int effectId);
|
||||||
void getLoopingEffects (std::vector<int>& out) const;
|
void getLoopingEffects (std::vector<int>& out) const;
|
||||||
|
|
||||||
void addSpellCastGlow(const ESM::MagicEffect *effect);
|
// Add a spell casting glow to an object. From measuring video taken from the original engine,
|
||||||
|
// the glow seems to be about 1.5 seconds except for telekinesis, which is 1 second.
|
||||||
|
void addSpellCastGlow(const ESM::MagicEffect *effect, float glowDuration = 1.5);
|
||||||
|
|
||||||
virtual void updatePtr(const MWWorld::Ptr &ptr);
|
virtual void updatePtr(const MWWorld::Ptr &ptr);
|
||||||
|
|
||||||
|
@ -389,10 +397,6 @@ public:
|
||||||
float speedmult, const std::string &start, const std::string &stop,
|
float speedmult, const std::string &start, const std::string &stop,
|
||||||
float startpoint, size_t loops, bool loopfallback=false);
|
float startpoint, size_t loops, bool loopfallback=false);
|
||||||
|
|
||||||
/** If the given animation group is currently playing, set its remaining loop count to '0'.
|
|
||||||
*/
|
|
||||||
void stopLooping(const std::string& groupName);
|
|
||||||
|
|
||||||
/** Adjust the speed multiplier of an already playing animation.
|
/** Adjust the speed multiplier of an already playing animation.
|
||||||
*/
|
*/
|
||||||
void adjustSpeedMult (const std::string& groupname, float speedmult);
|
void adjustSpeedMult (const std::string& groupname, float speedmult);
|
||||||
|
@ -432,6 +436,8 @@ public:
|
||||||
|
|
||||||
virtual osg::Vec3f runAnimation(float duration);
|
virtual osg::Vec3f runAnimation(float duration);
|
||||||
|
|
||||||
|
void setLoopingEnabled(const std::string &groupname, bool enabled);
|
||||||
|
|
||||||
/// This is typically called as part of runAnimation, but may be called manually if needed.
|
/// This is typically called as part of runAnimation, but may be called manually if needed.
|
||||||
void updateEffects(float duration);
|
void updateEffects(float duration);
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace Files
|
||||||
const int escape_hash_filter::sEscapeIdentifier = 'a';
|
const int escape_hash_filter::sEscapeIdentifier = 'a';
|
||||||
const int escape_hash_filter::sHashIdentifier = 'h';
|
const int escape_hash_filter::sHashIdentifier = 'h';
|
||||||
|
|
||||||
escape_hash_filter::escape_hash_filter() : mNext(), mSeenNonWhitespace(false), mFinishLine(false)
|
escape_hash_filter::escape_hash_filter() : mNext(), mPrevious(), mSeenNonWhitespace(false), mFinishLine(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,4 +137,4 @@ namespace Files
|
||||||
|
|
||||||
return istream;
|
return istream;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
namespace Misc
|
namespace Misc
|
||||||
{
|
{
|
||||||
|
MessageFormatParser::~MessageFormatParser() {}
|
||||||
|
|
||||||
void MessageFormatParser::process(const std::string& m)
|
void MessageFormatParser::process(const std::string& m)
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < m.size(); ++i)
|
for (unsigned int i = 0; i < m.size(); ++i)
|
||||||
|
|
|
@ -19,6 +19,8 @@ namespace Misc
|
||||||
virtual void visitedCharacter(char c) = 0;
|
virtual void visitedCharacter(char c) = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
virtual ~MessageFormatParser();
|
||||||
|
|
||||||
virtual void process(const std::string& message);
|
virtual void process(const std::string& message);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue