Merge branch 'master' into goodbye

pull/456/head
Capostrophic 7 years ago committed by GitHub
commit dd2a11b243
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,9 +1,13 @@
0.45.0
------
Bug #2835: Player able to slowly move when overencumbered
Bug #3897: Have Goodbye give all choices the effects of Goodbye
Bug #4221: Characters get stuck in V-shaped terrain
Bug #4293: Faction members are not aware of faction ownerships in barter
Bug #4327: Missing animations during spell/weapon stance switching
Bug #4426: RotateWorld behavior is incorrect
Bug #4433: Guard behaviour is incorrect with Alarm = 0
Feature #4444: Per-group KF-animation files support
0.44.0
------

@ -1,5 +1,22 @@
#!/bin/bash
MISSINGTOOLS=0
command -v 7z >/dev/null 2>&1 || { echo "Error: 7z (7zip) is not on the path."; MISSINGTOOLS=1; }
command -v cmake >/dev/null 2>&1 || { echo "Error: cmake (CMake) is not on the path."; MISSINGTOOLS=1; }
if [ $MISSINGTOOLS -ne 0 ]; then
exit 1
fi
WORKINGDIR="$(pwd)"
case "$WORKINGDIR" in
*[[:space:]]*)
echo "Error: Working directory contains spaces."
exit 1
;;
esac
set -euo pipefail
APPVEYOR=${APPVEYOR:-}

@ -1,7 +1,7 @@
OpenMW
======
[![Build Status](https://api.travis-ci.org/OpenMW/openmw.svg)](https://travis-ci.org/OpenMW/openmw) [![Build status](https://ci.appveyor.com/api/projects/status/e6bqw8oouy8ufd46?svg=true)](https://ci.appveyor.com/project/scrawl/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740)
[![Build Status](https://api.travis-ci.org/OpenMW/openmw.svg)](https://travis-ci.org/OpenMW/openmw) [![Build status](https://ci.appveyor.com/api/projects/status/github/openmw/openmw?svg=true)](https://ci.appveyor.com/project/psi29a/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740)
OpenMW is a recreation of the engine for the popular role-playing game Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work.

@ -431,9 +431,11 @@ namespace MWDialogue
void DialogueManager::addChoice (const std::string& text, int choice)
{
mIsInChoice = true;
mChoices.push_back(std::make_pair(text, choice));
if (!mGoodbye)
{
mIsInChoice = true;
mChoices.push_back(std::make_pair(text, choice));
}
}
const std::vector<std::pair<std::string, int> >& DialogueManager::getChoices()
@ -448,8 +450,8 @@ namespace MWDialogue
void DialogueManager::goodbye()
{
mIsInChoice = false;
mGoodbye = true;
if (!mIsInChoice)
mGoodbye = true;
}
void DialogueManager::persuade(int type, ResponseCallback* callback)

@ -749,6 +749,7 @@ void CharacterController::playRandomDeath(float startpoint)
CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim)
: mPtr(ptr)
, mWeapon(MWWorld::Ptr())
, mAnimation(anim)
, mIdleState(CharState_None)
, mMovementState(CharState_None)
@ -1156,17 +1157,26 @@ bool CharacterController::updateWeaponState()
const bool isWerewolf = cls.isNpc() && cls.getNpcStats(mPtr).isWerewolf();
std::string soundid;
std::string upSoundId;
std::string downSoundId;
if (mPtr.getClass().hasInventoryStore(mPtr))
{
MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr);
MWWorld::ConstContainerStoreIterator weapon = getActiveWeapon(stats, inv, &weaptype);
if(weapon != inv.end() && !(weaptype == WeapType_None && mWeaponType == WeapType_Spell))
{
soundid = (weaptype == WeapType_None) ?
weapon->getClass().getDownSoundId(*weapon) :
weapon->getClass().getUpSoundId(*weapon);
}
MWWorld::ContainerStoreIterator weapon = getActiveWeapon(stats, inv, &weaptype);
if(stats.getDrawState() == DrawState_Spell)
weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
if(weapon != inv.end() && mWeaponType != WeapType_HandToHand && weaptype > WeapType_HandToHand && weaptype < WeapType_Spell)
upSoundId = weapon->getClass().getUpSoundId(*weapon);
if(weapon != inv.end() && mWeaponType > WeapType_HandToHand && mWeaponType < WeapType_Spell)
downSoundId = weapon->getClass().getDownSoundId(*weapon);
// weapon->HtH switch: weapon is empty already, so we need to take sound from previous weapon
if(weapon == inv.end() && !mWeapon.isEmpty() && weaptype == WeapType_HandToHand && mWeaponType != WeapType_Spell)
downSoundId = mWeapon.getClass().getDownSoundId(mWeapon);
mWeapon = weapon != inv.end() ? *weapon : MWWorld::Ptr();
}
MWRender::Animation::AnimPriority priorityWeapon(Priority_Weapon);
@ -1181,34 +1191,51 @@ bool CharacterController::updateWeaponState()
if(weaptype != mWeaponType && !isKnockedOut() &&
!isKnockedDown() && !isRecovery())
{
forcestateupdate = true;
mAnimation->showCarriedLeft(updateCarriedLeftVisible(weaptype));
std::string weapgroup;
if(weaptype == WeapType_None)
if ((!isWerewolf || mWeaponType != WeapType_Spell)
&& mUpperBodyState != UpperCharState_UnEquipingWeap
&& !isStillWeapon)
{
if (!isWerewolf || mWeaponType != WeapType_Spell)
// Note: we do not disable unequipping animation automatically to avoid body desync
getWeaponGroup(mWeaponType, weapgroup);
mAnimation->play(weapgroup, priorityWeapon,
MWRender::Animation::BlendMask_All, false,
1.0f, "unequip start", "unequip stop", 0.0f, 0);
mUpperBodyState = UpperCharState_UnEquipingWeap;
if(!downSoundId.empty())
{
getWeaponGroup(mWeaponType, weapgroup);
mAnimation->play(weapgroup, priorityWeapon,
MWRender::Animation::BlendMask_All, true,
1.0f, "unequip start", "unequip stop", 0.0f, 0);
mUpperBodyState = UpperCharState_UnEquipingWeap;
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
sndMgr->playSound3D(mPtr, downSoundId, 1.0f, 1.0f);
}
}
else
float complete;
bool animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete);
if (!animPlaying || complete >= 1.0f)
{
mUpperBodyState = UpperCharState_Nothing;
forcestateupdate = true;
mAnimation->showCarriedLeft(updateCarriedLeftVisible(weaptype));
getWeaponGroup(weaptype, weapgroup);
mAnimation->setWeaponGroup(weapgroup);
if (!isStillWeapon)
{
mAnimation->showWeapons(false);
mAnimation->play(weapgroup, priorityWeapon,
MWRender::Animation::BlendMask_All, true,
1.0f, "equip start", "equip stop", 0.0f, 0);
mUpperBodyState = UpperCharState_EquipingWeap;
if (weaptype == WeapType_None)
{
// Disable current weapon animation manually
mAnimation->disable(mCurrentWeapon);
}
else
{
mAnimation->showWeapons(false);
mAnimation->play(weapgroup, priorityWeapon,
MWRender::Animation::BlendMask_All, true,
1.0f, "equip start", "equip stop", 0.0f, 0);
mUpperBodyState = UpperCharState_EquipingWeap;
}
}
if(isWerewolf)
@ -1221,16 +1248,16 @@ bool CharacterController::updateWeaponState()
sndMgr->playSound3D(mPtr, sound->mId, 1.0f, 1.0f);
}
}
}
if(!soundid.empty() && !isStillWeapon)
{
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
sndMgr->playSound3D(mPtr, soundid, 1.0f, 1.0f);
}
mWeaponType = weaptype;
getWeaponGroup(mWeaponType, mCurrentWeapon);
mWeaponType = weaptype;
getWeaponGroup(mWeaponType, mCurrentWeapon);
if(!upSoundId.empty() && !isStillWeapon)
{
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
sndMgr->playSound3D(mPtr, upSoundId, 1.0f, 1.0f);
}
}
}
if(isWerewolf)

@ -152,6 +152,7 @@ struct WeaponInfo;
class CharacterController : public MWRender::Animation::TextKeyListener
{
MWWorld::Ptr mPtr;
MWWorld::Ptr mWeapon;
MWRender::Animation *mAnimation;
struct AnimationQueueEntry

@ -308,6 +308,7 @@ namespace MWPhysics
float swimlevel = waterlevel + halfExtents.z() - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale);
ActorTracer tracer;
osg::Vec3f inertia = physicActor->getInertialForce();
osg::Vec3f velocity;
@ -320,10 +321,11 @@ namespace MWPhysics
{
velocity = (osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))) * movement;
if (velocity.z() > 0.f && physicActor->getOnGround() && !physicActor->getOnSlope())
if ((velocity.z() > 0.f && physicActor->getOnGround() && !physicActor->getOnSlope())
|| (velocity.z() > 0.f && velocity.z() + inertia.z() <= -velocity.z() && physicActor->getOnSlope()))
inertia = velocity;
else if(!physicActor->getOnGround() || physicActor->getOnSlope())
velocity = velocity + physicActor->getInertialForce();
else if (!physicActor->getOnGround() || physicActor->getOnSlope())
velocity = velocity + inertia;
}
// dead actors underwater will float to the surface, if the CharacterController tells us to do so

@ -31,6 +31,8 @@
#include <components/sceneutil/skeleton.hpp>
#include <components/sceneutil/positionattitudetransform.hpp>
#include <components/settings/settings.hpp>
#include <components/fallback/fallback.hpp>
#include "../mwbase/environment.hpp"
@ -466,6 +468,8 @@ namespace MWRender
mAnimationTimePtr[i].reset(new AnimationTime);
mLightListCallback = new SceneUtil::LightListCallback;
mUseAdditionalSources = Settings::Manager::getBool ("use additional anim sources", "Game");
}
Animation::~Animation()
@ -536,6 +540,35 @@ namespace MWRender
return mKeyframes->mTextKeys;
}
void Animation::loadAllAnimationsInFolder(const std::string &model, const std::string &baseModel)
{
const std::map<std::string, VFS::File*>& index = mResourceSystem->getVFS()->getIndex();
std::string animationPath = model;
if (animationPath.find("meshes") == 0)
{
animationPath.replace(0, 6, "animations");
}
animationPath.replace(animationPath.size()-3, 3, "/");
mResourceSystem->getVFS()->normalizeFilename(animationPath);
std::map<std::string, VFS::File*>::const_iterator found = index.lower_bound(animationPath);
while (found != index.end())
{
const std::string& name = found->first;
if (name.size() >= animationPath.size() && name.substr(0, animationPath.size()) == animationPath)
{
size_t pos = name.find_last_of('.');
if (pos != std::string::npos && name.compare(pos, name.size()-pos, ".kf") == 0)
addSingleAnimSource(name, baseModel);
}
else
break;
++found;
}
}
void Animation::addAnimSource(const std::string &model, const std::string& baseModel)
{
std::string kfname = model;
@ -546,6 +579,14 @@ namespace MWRender
else
return;
addSingleAnimSource(kfname, baseModel);
if (mUseAdditionalSources)
loadAllAnimationsInFolder(kfname, baseModel);
}
void Animation::addSingleAnimSource(const std::string &kfname, const std::string& baseModel)
{
if(!mResourceSystem->getVFS()->exists(kfname))
return;

@ -275,6 +275,8 @@ protected:
osg::ref_ptr<SceneUtil::LightListCallback> mLightListCallback;
bool mUseAdditionalSources;
const NodeMap& getNodeMap() const;
/* Sets the appropriate animations on the bone groups based on priority.
@ -309,12 +311,15 @@ protected:
*/
void setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature);
void loadAllAnimationsInFolder(const std::string &model, const std::string &baseModel);
/** Adds the keyframe controllers in the specified model as a new animation source.
* @note Later added animation sources have the highest priority when it comes to finding a particular animation.
* @param model The file to add the keyframes for. Note that the .nif file extension will be replaced with .kf.
* @param baseModel The filename of the mObjectRoot, only used for error messages.
*/
void addAnimSource(const std::string &model, const std::string& baseModel);
void addSingleAnimSource(const std::string &model, const std::string& baseModel);
/** Adds an additional light to the given node using the specified ESM record. */
void addExtraLight(osg::ref_ptr<osg::Group> parent, const ESM::Light *light);

@ -22,7 +22,7 @@ General introduction to normal map conversion
This page has general information and tutorials on how normal mapping works in OpenMW and how you can make mods using the old fake normal mapping technique (such as `Netch Bump mapped`_ and `Hlaalu Bump mapped`_, and maybe the most (in)famous one to give shiny rocks in OpenMW, the mod `On the Rocks`_!, featured in MGSO and Morrowind Rebirth) work in OpenMW.
*Note:* The conversion made in the `Converting Apel's Various Things - Sacks`_-part of this tutorial require the use of the application NifSkope. There are binaries available for Windows, but not for Mac or Linux. Reports say that NifSkope versions 1.X will compile on Linux as long as you have Qt packages installed, while the later 2.X versions will not compile.
*Note:* The conversion made in the `Converting Apel's Various Things - Sacks`_-part of this tutorial require the use of the application NifSkope_.
*Another note:* I will use the terms bump mapping and normal mapping simultaneously. Normal mapping is one form of bump mapping. In other words, normal mapping is bump mapping, but bump mapping isn't necessarily normal mapping. There are several techniques for bump mapping, and normal mapping is the most common one today.
@ -160,8 +160,6 @@ Converting Apel's Various Things - Sacks
In part one of this tutorial, we converted a mod that only included modified Morrowind model (``.nif``) files so that the normal maps could be loaded in Morrowind with MCP. We ignored those model files since they are not needed with OpenMW. In this tutorial however, we will convert a mod that includes new, custom made models. In other words, we cannot just ignore those files this time.
Before we begin, you need to know that unless you want to build the NifSkope application from source yourself, you will be needing a Windows OS to do this part, since the application only has binaries available for Windows.
Tutorial - MCP, Part 2
**********************
@ -196,7 +194,7 @@ Since these models have one or two textures applied to them, the fix was not tha
.. _`Multiple data folders`: https://wiki.openmw.org/index.php?title=Mod_installation
.. _`Various Things - Sacks`: https://www.nexusmods.com/morrowind/mods/42558/?
.. _Lead: https://imgur.com/bwpcYlc
.. _NifSkope: http://niftools.sourceforge.net/wiki/NifSkope
.. _NifSkope: https://wiki.openmw.org/index.php?title=Tools#NifSkope
.. _Blocks: https://imgur.com/VmQC0WG
.. _`no longer have shiny models`: https://imgur.com/vu1k7n1
.. _`we are done`: https://imgur.com/yyZxlTw

@ -157,3 +157,16 @@ Otherwise they wait for the enemies or the player to do an attack first.
Please note this setting has not been extensively tested and could have side effects with certain quests.
This setting can only be configured by editing the settings configuration file.
use additional anim sources
---------------------------
:Type: boolean
:Range: True/False
:Default: False
Allow to load additional animation sources when enabled.
For example, if the main animation mesh has name Meshes/x.nif, an engine will load all KF-files from Animations/x folder and its child folders.
Can be useful if you want to use several animation replacers without merging them.
Attention: animations from AnimKit have own format and are not supposed to be directly loaded in-game!
This setting can only be configured by editing the settings configuration file.

@ -219,6 +219,9 @@ can loot during death animation = true
# Makes the value of filled soul gems dependent only on soul magnitude (with formula from the Morrowind Code Patch)
rebalance soul gem values = false
# Allow to load per-group KF-files from Animations folder
use additional anim sources = false
[General]
# Anisotropy reduces distortion in textures at low angles (e.g. 0 to 16).

Loading…
Cancel
Save