Skip to content

Commit

Permalink
Bugfix: Stoneguardians will no longer cause newworld.zen to crash
Browse files Browse the repository at this point in the history
  • Loading branch information
ataulien committed Aug 4, 2019
1 parent ce17f15 commit fd900b6
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 15 deletions.
48 changes: 33 additions & 15 deletions src/components/CharacterAI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,9 @@ namespace REGoth

bool CharacterAI::tryPlayTransitionAnimationTo(const bs::String& anim)
{
// Cannot play animations if the character has no model yet
if (!mVisual->hasVisual()) return false;

bs::String playingNow = mVisual->getPlayingAnimationName();
auto clipPlayingNow = mVisual->findAnimationClip(playingNow);

Expand Down Expand Up @@ -499,30 +502,45 @@ namespace REGoth

bool CharacterAI::changeWeaponMode(AI::WeaponMode mode)
{
bs::String stateTarget = AnimationState::constructStateAnimationName(mode, mWalkMode, "");

bool wasAllowed = tryPlayTransitionAnimationTo(stateTarget);

if (wasAllowed)
if (!mVisual->hasVisual())
{
// If the model hasn't been set up yet, just make it start in the target mode.
// This happens on the Stone-Guardians in Gothic 2, which call NPC_SetToFistMode() before
// calling MDL_SetVisual().

mWeaponMode = mode;
}

if (!wasAllowed)
return true;
}
else
{
// FIXME: We're missing some aniAliases, for example, "T_RUN_2_SNEAK" exists,
// and "T_SNEAK_2_RUN" is just the same animation but in reverse. This
// is defined using an aniAlias, which does not seem to be implemented.
auto c = mVisual->findAnimationClip(stateTarget);
// Model exists, check if the state transition is possible

if (c)
bs::String stateTarget = AnimationState::constructStateAnimationName(mode, mWalkMode, "");

bool wasAllowed = tryPlayTransitionAnimationTo(stateTarget);

if (wasAllowed)
{
mVisual->playAnimationClip(c);
mWeaponMode = mode;
}
}

return wasAllowed;
if (!wasAllowed)
{
// FIXME: We're missing some aniAliases, for example, "T_RUN_2_SNEAK" exists,
// and "T_SNEAK_2_RUN" is just the same animation but in reverse. This
// is defined using an aniAlias, which does not seem to be implemented.
auto c = mVisual->findAnimationClip(stateTarget);

if (c)
{
mVisual->playAnimationClip(c);
mWeaponMode = mode;
}
}

return wasAllowed;
}
}

void CharacterAI::tryToggleWalking()
Expand Down
11 changes: 11 additions & 0 deletions src/components/VisualSkeletalAnimation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,17 @@ namespace REGoth
useFirstMeshOfModelScript();
}

bool VisualSkeletalAnimation::hasVisual() const
{
if (!mModelScript)
return false;

if (!mMesh)
return false;

return true;
}

bs::Bounds VisualSkeletalAnimation::getBounds() const
{
return mSubRenderable ? mSubRenderable->getBounds() : bs::Bounds();
Expand Down
9 changes: 9 additions & 0 deletions src/components/VisualSkeletalAnimation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,15 @@ namespace REGoth
*/
void setVisual(const bs::String& visual);

/**
* @return Whether a visual has been assigned to this component, so that it can play animations.
*
* If no visual has been assigned, methods related to playing or querying animations might fail.
*
* @note Having a *Visual* assigned means that there is a model-script and a mesh set.
*/
bool hasVisual() const;

/**
* Calculates how far the characters animation has moved since the last
* call ot this function via animation.
Expand Down

0 comments on commit fd900b6

Please sign in to comment.