mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-28 16:39:39 +00:00
Merge branch 'master' into HEAD
This commit is contained in:
commit
cb0a609d59
55 changed files with 469 additions and 365 deletions
|
@ -98,6 +98,7 @@
|
||||||
Bug #4984: "Friendly hits" feature should be used only for player's followers
|
Bug #4984: "Friendly hits" feature should be used only for player's followers
|
||||||
Bug #4989: Object dimension-dependent VFX scaling behavior is inconsistent
|
Bug #4989: Object dimension-dependent VFX scaling behavior is inconsistent
|
||||||
Bug #4990: Dead bodies prevent you from hitting
|
Bug #4990: Dead bodies prevent you from hitting
|
||||||
|
Bug #4991: Jumping occasionally takes too much fatigue
|
||||||
Bug #4999: Drop instruction behaves differently from vanilla
|
Bug #4999: Drop instruction behaves differently from vanilla
|
||||||
Bug #5001: Possible data race in the Animation::setAlpha()
|
Bug #5001: Possible data race in the Animation::setAlpha()
|
||||||
Bug #5004: Werewolves shield their eyes during storm
|
Bug #5004: Werewolves shield their eyes during storm
|
||||||
|
@ -115,11 +116,13 @@
|
||||||
Bug #5069: Blocking creatures' attacks doesn't degrade shields
|
Bug #5069: Blocking creatures' attacks doesn't degrade shields
|
||||||
Bug #5074: Paralyzed actors greet the player
|
Bug #5074: Paralyzed actors greet the player
|
||||||
Bug #5075: Enchanting cast style can be changed if there's no object
|
Bug #5075: Enchanting cast style can be changed if there's no object
|
||||||
|
Bug #5078: DisablePlayerLooking is broken
|
||||||
Bug #5082: Scrolling with controller in GUI mode is broken
|
Bug #5082: Scrolling with controller in GUI mode is broken
|
||||||
Bug #5089: Swimming/Underwater creatures only swim around ground level
|
Bug #5089: Swimming/Underwater creatures only swim around ground level
|
||||||
Bug #5092: NPCs with enchanted weapons play sound when out of charges
|
Bug #5092: NPCs with enchanted weapons play sound when out of charges
|
||||||
Bug #5093: Hand to hand sound plays on knocked out enemies
|
Bug #5093: Hand to hand sound plays on knocked out enemies
|
||||||
Bug #5099: Non-swimming enemies will enter water if player is water walking
|
Bug #5099: Non-swimming enemies will enter water if player is water walking
|
||||||
|
Bug #5103: Sneaking state behavior is still inconsistent
|
||||||
Bug #5104: Black Dart's enchantment doesn't trigger at low Enchant levels
|
Bug #5104: Black Dart's enchantment doesn't trigger at low Enchant levels
|
||||||
Bug #5105: NPCs start combat with werewolves from any distance
|
Bug #5105: NPCs start combat with werewolves from any distance
|
||||||
Bug #5106: Still can jump even when encumbered
|
Bug #5106: Still can jump even when encumbered
|
||||||
|
@ -127,6 +130,9 @@
|
||||||
Bug #5112: Insufficient magicka for current spell not reflected on HUD icon
|
Bug #5112: Insufficient magicka for current spell not reflected on HUD icon
|
||||||
Bug #5123: Script won't run on respawn
|
Bug #5123: Script won't run on respawn
|
||||||
Bug #5124: Arrow remains attached to actor if pulling animation was cancelled
|
Bug #5124: Arrow remains attached to actor if pulling animation was cancelled
|
||||||
|
Bug #5126: Swimming creatures without RunForward animations are motionless during combat
|
||||||
|
Bug #5134: Doors rotation by "Lock" console command is inconsistent
|
||||||
|
Bug #5137: Textures with Clamp Mode set to Clamp instead of Wrap are too dark outside the boundaries
|
||||||
Feature #1774: Handle AvoidNode
|
Feature #1774: Handle AvoidNode
|
||||||
Feature #2229: Improve pathfinding AI
|
Feature #2229: Improve pathfinding AI
|
||||||
Feature #3025: Analogue gamepad movement controls
|
Feature #3025: Analogue gamepad movement controls
|
||||||
|
@ -147,6 +153,7 @@
|
||||||
Feature #4812: Support NiSwitchNode
|
Feature #4812: Support NiSwitchNode
|
||||||
Feature #4836: Daytime node switch
|
Feature #4836: Daytime node switch
|
||||||
Feature #4859: Make water reflections more configurable
|
Feature #4859: Make water reflections more configurable
|
||||||
|
Feature #4882: Support for NiPalette node
|
||||||
Feature #4887: Add openmw command option to set initial random seed
|
Feature #4887: Add openmw command option to set initial random seed
|
||||||
Feature #4890: Make Distant Terrain configurable
|
Feature #4890: Make Distant Terrain configurable
|
||||||
Feature #4958: Support eight blood types
|
Feature #4958: Support eight blood types
|
||||||
|
@ -162,6 +169,7 @@
|
||||||
Feature #5036: Allow scripted faction leaving
|
Feature #5036: Allow scripted faction leaving
|
||||||
Feature #5046: Gamepad thumbstick cursor speed
|
Feature #5046: Gamepad thumbstick cursor speed
|
||||||
Feature #5051: Provide a separate textures for scrollbars
|
Feature #5051: Provide a separate textures for scrollbars
|
||||||
|
Feature #5091: Human-readable light source duration
|
||||||
Feature #5094: Unix like console hotkeys
|
Feature #5094: Unix like console hotkeys
|
||||||
Feature #5098: Allow user controller bindings
|
Feature #5098: Allow user controller bindings
|
||||||
Feature #5121: Handle NiTriStrips and NiTriStripsData
|
Feature #5121: Handle NiTriStrips and NiTriStripsData
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <components/esm/cellid.hpp>
|
#include <components/esm/cellid.hpp>
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
|
#include "../mwworld/doorstate.hpp"
|
||||||
|
|
||||||
#include "../mwrender/rendermode.hpp"
|
#include "../mwrender/rendermode.hpp"
|
||||||
|
|
||||||
|
@ -407,7 +408,6 @@ namespace MWBase
|
||||||
virtual void togglePreviewMode(bool enable) = 0;
|
virtual void togglePreviewMode(bool enable) = 0;
|
||||||
virtual bool toggleVanityMode(bool enable) = 0;
|
virtual bool toggleVanityMode(bool enable) = 0;
|
||||||
virtual void allowVanityMode(bool allow) = 0;
|
virtual void allowVanityMode(bool allow) = 0;
|
||||||
virtual void togglePlayerLooking(bool enable) = 0;
|
|
||||||
virtual void changeVanityModeScale(float factor) = 0;
|
virtual void changeVanityModeScale(float factor) = 0;
|
||||||
virtual bool vanityRotateCamera(float * rot) = 0;
|
virtual bool vanityRotateCamera(float * rot) = 0;
|
||||||
virtual void setCameraDistance(float dist, bool adjust = false, bool override = true)=0;
|
virtual void setCameraDistance(float dist, bool adjust = false, bool override = true)=0;
|
||||||
|
@ -420,7 +420,7 @@ namespace MWBase
|
||||||
/// update movement state of a non-teleport door as specified
|
/// update movement state of a non-teleport door as specified
|
||||||
/// @param state see MWClass::setDoorState
|
/// @param state see MWClass::setDoorState
|
||||||
/// @note throws an exception when invoked on a teleport door
|
/// @note throws an exception when invoked on a teleport door
|
||||||
virtual void activateDoor(const MWWorld::Ptr& door, int state) = 0;
|
virtual void activateDoor(const MWWorld::Ptr& door, MWWorld::DoorState state) = 0;
|
||||||
|
|
||||||
virtual void getActorsStandingOn (const MWWorld::ConstPtr& object, std::vector<MWWorld::Ptr> &actors) = 0; ///< get a list of actors standing on \a object
|
virtual void getActorsStandingOn (const MWWorld::ConstPtr& object, std::vector<MWWorld::Ptr> &actors) = 0; ///< get a list of actors standing on \a object
|
||||||
virtual bool getPlayerStandingOn (const MWWorld::ConstPtr& object) = 0; ///< @return true if the player is standing on \a object
|
virtual bool getPlayerStandingOn (const MWWorld::ConstPtr& object) = 0; ///< @return true if the player is standing on \a object
|
||||||
|
|
|
@ -103,7 +103,7 @@ namespace MWClass
|
||||||
const MWWorld::LiveCellRef<ESM::Activator> *ref = ptr.get<ESM::Activator>();
|
const MWWorld::LiveCellRef<ESM::Activator> *ref = ptr.get<ESM::Activator>();
|
||||||
|
|
||||||
MWGui::ToolTipInfo info;
|
MWGui::ToolTipInfo info;
|
||||||
info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count);
|
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||||
|
|
||||||
std::string text;
|
std::string text;
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||||
|
|
|
@ -105,7 +105,7 @@ namespace MWClass
|
||||||
const MWWorld::LiveCellRef<ESM::Apparatus> *ref = ptr.get<ESM::Apparatus>();
|
const MWWorld::LiveCellRef<ESM::Apparatus> *ref = ptr.get<ESM::Apparatus>();
|
||||||
|
|
||||||
MWGui::ToolTipInfo info;
|
MWGui::ToolTipInfo info;
|
||||||
info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count);
|
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||||
info.icon = ref->mBase->mIcon;
|
info.icon = ref->mBase->mIcon;
|
||||||
|
|
||||||
std::string text;
|
std::string text;
|
||||||
|
|
|
@ -211,7 +211,7 @@ namespace MWClass
|
||||||
const MWWorld::LiveCellRef<ESM::Armor> *ref = ptr.get<ESM::Armor>();
|
const MWWorld::LiveCellRef<ESM::Armor> *ref = ptr.get<ESM::Armor>();
|
||||||
|
|
||||||
MWGui::ToolTipInfo info;
|
MWGui::ToolTipInfo info;
|
||||||
info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count);
|
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||||
info.icon = ref->mBase->mIcon;
|
info.icon = ref->mBase->mIcon;
|
||||||
|
|
||||||
std::string text;
|
std::string text;
|
||||||
|
|
|
@ -121,7 +121,7 @@ namespace MWClass
|
||||||
const MWWorld::LiveCellRef<ESM::Book> *ref = ptr.get<ESM::Book>();
|
const MWWorld::LiveCellRef<ESM::Book> *ref = ptr.get<ESM::Book>();
|
||||||
|
|
||||||
MWGui::ToolTipInfo info;
|
MWGui::ToolTipInfo info;
|
||||||
info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count);
|
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||||
info.icon = ref->mBase->mIcon;
|
info.icon = ref->mBase->mIcon;
|
||||||
|
|
||||||
std::string text;
|
std::string text;
|
||||||
|
|
|
@ -169,7 +169,7 @@ namespace MWClass
|
||||||
const MWWorld::LiveCellRef<ESM::Clothing> *ref = ptr.get<ESM::Clothing>();
|
const MWWorld::LiveCellRef<ESM::Clothing> *ref = ptr.get<ESM::Clothing>();
|
||||||
|
|
||||||
MWGui::ToolTipInfo info;
|
MWGui::ToolTipInfo info;
|
||||||
info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count);
|
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||||
info.icon = ref->mBase->mIcon;
|
info.icon = ref->mBase->mIcon;
|
||||||
|
|
||||||
std::string text;
|
std::string text;
|
||||||
|
|
|
@ -271,7 +271,7 @@ namespace MWClass
|
||||||
const MWWorld::LiveCellRef<ESM::Container> *ref = ptr.get<ESM::Container>();
|
const MWWorld::LiveCellRef<ESM::Container> *ref = ptr.get<ESM::Container>();
|
||||||
|
|
||||||
MWGui::ToolTipInfo info;
|
MWGui::ToolTipInfo info;
|
||||||
info.caption = ref->mBase->mName;
|
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName);
|
||||||
|
|
||||||
std::string text;
|
std::string text;
|
||||||
int lockLevel = ptr.getCellRef().getLockLevel();
|
int lockLevel = ptr.getCellRef().getLockLevel();
|
||||||
|
|
|
@ -586,7 +586,7 @@ namespace MWClass
|
||||||
const MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
|
const MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
|
||||||
|
|
||||||
MWGui::ToolTipInfo info;
|
MWGui::ToolTipInfo info;
|
||||||
info.caption = ref->mBase->mName;
|
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName);
|
||||||
|
|
||||||
std::string text;
|
std::string text;
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||||
|
|
|
@ -34,7 +34,7 @@ namespace MWClass
|
||||||
class DoorCustomData : public MWWorld::CustomData
|
class DoorCustomData : public MWWorld::CustomData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
int mDoorState; // 0 = nothing, 1 = opening, 2 = closing
|
MWWorld::DoorState mDoorState;
|
||||||
|
|
||||||
virtual MWWorld::CustomData *clone() const;
|
virtual MWWorld::CustomData *clone() const;
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ namespace MWClass
|
||||||
if (ptr.getRefData().getCustomData())
|
if (ptr.getRefData().getCustomData())
|
||||||
{
|
{
|
||||||
const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData();
|
const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData();
|
||||||
if (customData.mDoorState > 0)
|
if (customData.mDoorState != MWWorld::DoorState::Idle)
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWorld()->activateDoor(ptr, customData.mDoorState);
|
MWBase::Environment::get().getWorld()->activateDoor(ptr, customData.mDoorState);
|
||||||
}
|
}
|
||||||
|
@ -201,12 +201,12 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
// animated door
|
// animated door
|
||||||
std::shared_ptr<MWWorld::Action> action(new MWWorld::ActionDoor(ptr));
|
std::shared_ptr<MWWorld::Action> action(new MWWorld::ActionDoor(ptr));
|
||||||
int doorstate = getDoorState(ptr);
|
const auto doorState = getDoorState(ptr);
|
||||||
bool opening = true;
|
bool opening = true;
|
||||||
float doorRot = ptr.getRefData().getPosition().rot[2] - ptr.getCellRef().getPosition().rot[2];
|
float doorRot = ptr.getRefData().getPosition().rot[2] - ptr.getCellRef().getPosition().rot[2];
|
||||||
if (doorstate == 1)
|
if (doorState == MWWorld::DoorState::Opening)
|
||||||
opening = false;
|
opening = false;
|
||||||
if (doorstate == 0 && doorRot != 0)
|
if (doorState == MWWorld::DoorState::Idle && doorRot != 0)
|
||||||
opening = false;
|
opening = false;
|
||||||
|
|
||||||
if (opening)
|
if (opening)
|
||||||
|
@ -293,7 +293,7 @@ namespace MWClass
|
||||||
const MWWorld::LiveCellRef<ESM::Door> *ref = ptr.get<ESM::Door>();
|
const MWWorld::LiveCellRef<ESM::Door> *ref = ptr.get<ESM::Door>();
|
||||||
|
|
||||||
MWGui::ToolTipInfo info;
|
MWGui::ToolTipInfo info;
|
||||||
info.caption = ref->mBase->mName;
|
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName);
|
||||||
|
|
||||||
std::string text;
|
std::string text;
|
||||||
|
|
||||||
|
@ -365,20 +365,20 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
std::unique_ptr<DoorCustomData> data(new DoorCustomData);
|
std::unique_ptr<DoorCustomData> data(new DoorCustomData);
|
||||||
|
|
||||||
data->mDoorState = 0;
|
data->mDoorState = MWWorld::DoorState::Idle;
|
||||||
ptr.getRefData().setCustomData(data.release());
|
ptr.getRefData().setCustomData(data.release());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int Door::getDoorState (const MWWorld::ConstPtr &ptr) const
|
MWWorld::DoorState Door::getDoorState (const MWWorld::ConstPtr &ptr) const
|
||||||
{
|
{
|
||||||
if (!ptr.getRefData().getCustomData())
|
if (!ptr.getRefData().getCustomData())
|
||||||
return 0;
|
return MWWorld::DoorState::Idle;
|
||||||
const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData();
|
const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData();
|
||||||
return customData.mDoorState;
|
return customData.mDoorState;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Door::setDoorState (const MWWorld::Ptr &ptr, int state) const
|
void Door::setDoorState (const MWWorld::Ptr &ptr, MWWorld::DoorState state) const
|
||||||
{
|
{
|
||||||
if (ptr.getCellRef().getTeleport())
|
if (ptr.getCellRef().getTeleport())
|
||||||
throw std::runtime_error("load doors can't be moved");
|
throw std::runtime_error("load doors can't be moved");
|
||||||
|
@ -396,7 +396,7 @@ namespace MWClass
|
||||||
DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData();
|
DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData();
|
||||||
|
|
||||||
const ESM::DoorState& state2 = dynamic_cast<const ESM::DoorState&>(state);
|
const ESM::DoorState& state2 = dynamic_cast<const ESM::DoorState&>(state);
|
||||||
customData.mDoorState = state2.mDoorState;
|
customData.mDoorState = static_cast<MWWorld::DoorState>(state2.mDoorState);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Door::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const
|
void Door::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const
|
||||||
|
@ -409,7 +409,7 @@ namespace MWClass
|
||||||
const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData();
|
const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData();
|
||||||
|
|
||||||
ESM::DoorState& state2 = dynamic_cast<ESM::DoorState&>(state);
|
ESM::DoorState& state2 = dynamic_cast<ESM::DoorState&>(state);
|
||||||
state2.mDoorState = customData.mDoorState;
|
state2.mDoorState = static_cast<int>(customData.mDoorState);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,10 +59,9 @@ namespace MWClass
|
||||||
|
|
||||||
virtual std::string getModel(const MWWorld::ConstPtr &ptr) const;
|
virtual std::string getModel(const MWWorld::ConstPtr &ptr) const;
|
||||||
|
|
||||||
/// 0 = nothing, 1 = opening, 2 = closing
|
virtual MWWorld::DoorState getDoorState (const MWWorld::ConstPtr &ptr) const;
|
||||||
virtual int getDoorState (const MWWorld::ConstPtr &ptr) const;
|
|
||||||
/// This does not actually cause the door to move. Use World::activateDoor instead.
|
/// This does not actually cause the door to move. Use World::activateDoor instead.
|
||||||
virtual void setDoorState (const MWWorld::Ptr &ptr, int state) const;
|
virtual void setDoorState (const MWWorld::Ptr &ptr, MWWorld::DoorState state) const;
|
||||||
|
|
||||||
|
|
||||||
virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||||
|
|
|
@ -117,7 +117,7 @@ namespace MWClass
|
||||||
const MWWorld::LiveCellRef<ESM::Ingredient> *ref = ptr.get<ESM::Ingredient>();
|
const MWWorld::LiveCellRef<ESM::Ingredient> *ref = ptr.get<ESM::Ingredient>();
|
||||||
|
|
||||||
MWGui::ToolTipInfo info;
|
MWGui::ToolTipInfo info;
|
||||||
info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count);
|
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||||
info.icon = ref->mBase->mIcon;
|
info.icon = ref->mBase->mIcon;
|
||||||
|
|
||||||
std::string text;
|
std::string text;
|
||||||
|
|
|
@ -151,18 +151,14 @@ namespace MWClass
|
||||||
const MWWorld::LiveCellRef<ESM::Light> *ref = ptr.get<ESM::Light>();
|
const MWWorld::LiveCellRef<ESM::Light> *ref = ptr.get<ESM::Light>();
|
||||||
|
|
||||||
MWGui::ToolTipInfo info;
|
MWGui::ToolTipInfo info;
|
||||||
info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count);
|
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||||
info.icon = ref->mBase->mIcon;
|
info.icon = ref->mBase->mIcon;
|
||||||
|
|
||||||
std::string text;
|
std::string text;
|
||||||
|
|
||||||
if (Settings::Manager::getBool("show effect duration","Game"))
|
// Don't show duration for infinite light sources.
|
||||||
{
|
if (Settings::Manager::getBool("show effect duration","Game") && ptr.getClass().getRemainingUsageTime(ptr) != -1)
|
||||||
// -1 is infinite light source, so duration makes no sense here. Other negative values are treated as 0.
|
text += MWGui::ToolTips::getDurationString(ptr.getClass().getRemainingUsageTime(ptr), "\n#{sDuration}");
|
||||||
float remainingTime = ptr.getClass().getRemainingUsageTime(ptr);
|
|
||||||
if (remainingTime != -1.0f)
|
|
||||||
text += "\n#{sDuration}: " + MWGui::ToolTips::toString(std::max(0.f, remainingTime));
|
|
||||||
}
|
|
||||||
|
|
||||||
text += MWGui::ToolTips::getWeightString(ref->mBase->mData.mWeight, "#{sWeight}");
|
text += MWGui::ToolTips::getWeightString(ref->mBase->mData.mWeight, "#{sWeight}");
|
||||||
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
|
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
|
||||||
|
|
|
@ -116,7 +116,7 @@ namespace MWClass
|
||||||
const MWWorld::LiveCellRef<ESM::Lockpick> *ref = ptr.get<ESM::Lockpick>();
|
const MWWorld::LiveCellRef<ESM::Lockpick> *ref = ptr.get<ESM::Lockpick>();
|
||||||
|
|
||||||
MWGui::ToolTipInfo info;
|
MWGui::ToolTipInfo info;
|
||||||
info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count);
|
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||||
info.icon = ref->mBase->mIcon;
|
info.icon = ref->mBase->mIcon;
|
||||||
|
|
||||||
std::string text;
|
std::string text;
|
||||||
|
|
|
@ -159,7 +159,7 @@ namespace MWClass
|
||||||
else // gold displays its count also if it's 1.
|
else // gold displays its count also if it's 1.
|
||||||
countString = " (" + std::to_string(count) + ")";
|
countString = " (" + std::to_string(count) + ")";
|
||||||
|
|
||||||
info.caption = ref->mBase->mName + countString;
|
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + countString;
|
||||||
info.icon = ref->mBase->mIcon;
|
info.icon = ref->mBase->mIcon;
|
||||||
|
|
||||||
if (ref->mRef.getSoul() != "")
|
if (ref->mRef.getSoul() != "")
|
||||||
|
|
|
@ -940,10 +940,9 @@ namespace MWClass
|
||||||
const float normalizedEncumbrance = getNormalizedEncumbrance(ptr);
|
const float normalizedEncumbrance = getNormalizedEncumbrance(ptr);
|
||||||
|
|
||||||
bool swimming = world->isSwimming(ptr);
|
bool swimming = world->isSwimming(ptr);
|
||||||
bool inair = !world->isOnGround(ptr) && !swimming && !world->isFlying(ptr);
|
bool sneaking = MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr);
|
||||||
bool sneaking = stats.getStance(MWMechanics::CreatureStats::Stance_Sneak);
|
|
||||||
sneaking = sneaking && (inair || MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr));
|
|
||||||
bool running = stats.getStance(MWMechanics::CreatureStats::Stance_Run);
|
bool running = stats.getStance(MWMechanics::CreatureStats::Stance_Run);
|
||||||
|
bool inair = !world->isOnGround(ptr) && !swimming && !world->isFlying(ptr);
|
||||||
running = running && (inair || MWBase::Environment::get().getMechanicsManager()->isRunning(ptr));
|
running = running && (inair || MWBase::Environment::get().getMechanicsManager()->isRunning(ptr));
|
||||||
|
|
||||||
float walkSpeed = gmst.fMinWalkSpeed->mValue.getFloat() + 0.01f*npcdata->mNpcStats.getAttribute(ESM::Attribute::Speed).getModified()*
|
float walkSpeed = gmst.fMinWalkSpeed->mValue.getFloat() + 0.01f*npcdata->mNpcStats.getAttribute(ESM::Attribute::Speed).getModified()*
|
||||||
|
@ -1071,11 +1070,11 @@ namespace MWClass
|
||||||
bool fullHelp = MWBase::Environment::get().getWindowManager()->getFullHelp();
|
bool fullHelp = MWBase::Environment::get().getWindowManager()->getFullHelp();
|
||||||
MWGui::ToolTipInfo info;
|
MWGui::ToolTipInfo info;
|
||||||
|
|
||||||
info.caption = getName(ptr);
|
info.caption = MyGUI::TextIterator::toTagsString(getName(ptr));
|
||||||
if(fullHelp && ptr.getRefData().getCustomData() && ptr.getRefData().getCustomData()->asNpcCustomData().mNpcStats.isWerewolf())
|
if(fullHelp && ptr.getRefData().getCustomData() && ptr.getRefData().getCustomData()->asNpcCustomData().mNpcStats.isWerewolf())
|
||||||
{
|
{
|
||||||
info.caption += " (";
|
info.caption += " (";
|
||||||
info.caption += ref->mBase->mName;
|
info.caption += MyGUI::TextIterator::toTagsString(ref->mBase->mName);
|
||||||
info.caption += ")";
|
info.caption += ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,7 +110,7 @@ namespace MWClass
|
||||||
const MWWorld::LiveCellRef<ESM::Potion> *ref = ptr.get<ESM::Potion>();
|
const MWWorld::LiveCellRef<ESM::Potion> *ref = ptr.get<ESM::Potion>();
|
||||||
|
|
||||||
MWGui::ToolTipInfo info;
|
MWGui::ToolTipInfo info;
|
||||||
info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count);
|
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||||
info.icon = ref->mBase->mIcon;
|
info.icon = ref->mBase->mIcon;
|
||||||
|
|
||||||
std::string text;
|
std::string text;
|
||||||
|
|
|
@ -116,7 +116,7 @@ namespace MWClass
|
||||||
const MWWorld::LiveCellRef<ESM::Probe> *ref = ptr.get<ESM::Probe>();
|
const MWWorld::LiveCellRef<ESM::Probe> *ref = ptr.get<ESM::Probe>();
|
||||||
|
|
||||||
MWGui::ToolTipInfo info;
|
MWGui::ToolTipInfo info;
|
||||||
info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count);
|
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||||
info.icon = ref->mBase->mIcon;
|
info.icon = ref->mBase->mIcon;
|
||||||
|
|
||||||
std::string text;
|
std::string text;
|
||||||
|
|
|
@ -117,7 +117,7 @@ namespace MWClass
|
||||||
const MWWorld::LiveCellRef<ESM::Repair> *ref = ptr.get<ESM::Repair>();
|
const MWWorld::LiveCellRef<ESM::Repair> *ref = ptr.get<ESM::Repair>();
|
||||||
|
|
||||||
MWGui::ToolTipInfo info;
|
MWGui::ToolTipInfo info;
|
||||||
info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count);
|
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||||
info.icon = ref->mBase->mIcon;
|
info.icon = ref->mBase->mIcon;
|
||||||
|
|
||||||
std::string text;
|
std::string text;
|
||||||
|
|
|
@ -168,7 +168,7 @@ namespace MWClass
|
||||||
const ESM::WeaponType* weaponType = MWMechanics::getWeaponType(ref->mBase->mData.mType);
|
const ESM::WeaponType* weaponType = MWMechanics::getWeaponType(ref->mBase->mData.mType);
|
||||||
|
|
||||||
MWGui::ToolTipInfo info;
|
MWGui::ToolTipInfo info;
|
||||||
info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count);
|
info.caption = MyGUI::TextIterator::toTagsString(ref->mBase->mName) + MWGui::ToolTips::getCountString(count);
|
||||||
info.icon = ref->mBase->mIcon;
|
info.icon = ref->mBase->mIcon;
|
||||||
|
|
||||||
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
||||||
|
|
|
@ -137,27 +137,8 @@ namespace MWGui
|
||||||
MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", "") );
|
MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", "") );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (effectInfo.mRemainingTime > -1 &&
|
if (effectInfo.mRemainingTime > -1 && Settings::Manager::getBool("show effect duration","Game"))
|
||||||
Settings::Manager::getBool("show effect duration","Game")) {
|
sourcesDescription += MWGui::ToolTips::getDurationString(effectInfo.mRemainingTime, " #{sDuration}");
|
||||||
sourcesDescription += " #{sDuration}: ";
|
|
||||||
float duration = effectInfo.mRemainingTime;
|
|
||||||
if (duration > 3600)
|
|
||||||
{
|
|
||||||
int hour = duration / 3600;
|
|
||||||
duration -= hour*3600;
|
|
||||||
sourcesDescription += MWGui::ToolTips::toString(hour) + "h";
|
|
||||||
}
|
|
||||||
if (duration > 60)
|
|
||||||
{
|
|
||||||
int minute = duration / 60;
|
|
||||||
duration -= minute*60;
|
|
||||||
sourcesDescription += MWGui::ToolTips::toString(minute) + "m";
|
|
||||||
}
|
|
||||||
if (duration > 0.1)
|
|
||||||
{
|
|
||||||
sourcesDescription += MWGui::ToolTips::toString(duration) + "s";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
addNewLine = true;
|
addNewLine = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -667,6 +667,60 @@ namespace MWGui
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string ToolTips::getDurationString(float duration, const std::string& prefix)
|
||||||
|
{
|
||||||
|
std::string ret;
|
||||||
|
ret = prefix + ": ";
|
||||||
|
|
||||||
|
if (duration < 1.f)
|
||||||
|
{
|
||||||
|
ret += "0 s";
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr int secondsPerMinute = 60; // 60 seconds
|
||||||
|
constexpr int secondsPerHour = secondsPerMinute * 60; // 60 minutes
|
||||||
|
constexpr int secondsPerDay = secondsPerHour * 24; // 24 hours
|
||||||
|
constexpr int secondsPerMonth = secondsPerDay * 30; // 30 days
|
||||||
|
constexpr int secondsPerYear = secondsPerDay * 365;
|
||||||
|
int fullDuration = static_cast<int>(duration);
|
||||||
|
int units = 0;
|
||||||
|
int years = fullDuration / secondsPerYear;
|
||||||
|
int months = fullDuration % secondsPerYear / secondsPerMonth;
|
||||||
|
int days = fullDuration % secondsPerYear % secondsPerMonth / secondsPerDay; // Because a year is not exactly 12 "months"
|
||||||
|
int hours = fullDuration % secondsPerDay / secondsPerHour;
|
||||||
|
int minutes = fullDuration % secondsPerHour / secondsPerMinute;
|
||||||
|
int seconds = fullDuration % secondsPerMinute;
|
||||||
|
if (years)
|
||||||
|
{
|
||||||
|
units++;
|
||||||
|
ret += toString(years) + " y ";
|
||||||
|
}
|
||||||
|
if (months)
|
||||||
|
{
|
||||||
|
units++;
|
||||||
|
ret += toString(months) + " mo ";
|
||||||
|
}
|
||||||
|
if (units < 2 && days)
|
||||||
|
{
|
||||||
|
units++;
|
||||||
|
ret += toString(days) + " d ";
|
||||||
|
}
|
||||||
|
if (units < 2 && hours)
|
||||||
|
{
|
||||||
|
units++;
|
||||||
|
ret += toString(hours) + " h ";
|
||||||
|
}
|
||||||
|
if (units >= 2)
|
||||||
|
return ret;
|
||||||
|
if (minutes)
|
||||||
|
ret += toString(minutes) + " min ";
|
||||||
|
if (seconds)
|
||||||
|
ret += toString(seconds) + " s ";
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
bool ToolTips::toggleFullHelp()
|
bool ToolTips::toggleFullHelp()
|
||||||
{
|
{
|
||||||
mFullHelp = !mFullHelp;
|
mFullHelp = !mFullHelp;
|
||||||
|
|
|
@ -84,6 +84,9 @@ namespace MWGui
|
||||||
static std::string getCellRefString(const MWWorld::CellRef& cellref);
|
static std::string getCellRefString(const MWWorld::CellRef& cellref);
|
||||||
///< Returns a string containing debug tooltip information about the given cellref.
|
///< Returns a string containing debug tooltip information about the given cellref.
|
||||||
|
|
||||||
|
static std::string getDurationString (float duration, const std::string& prefix);
|
||||||
|
///< Returns duration as two largest time units, rounded down. Note: not localized; no line break.
|
||||||
|
|
||||||
// these do not create an actual tooltip, but they fill in the data that is required so the tooltip
|
// these do not create an actual tooltip, but they fill in the data that is required so the tooltip
|
||||||
// system knows what to show in case this widget is hovered
|
// system knows what to show in case this widget is hovered
|
||||||
static void createSkillToolTip(MyGUI::Widget* widget, int skillId);
|
static void createSkillToolTip(MyGUI::Widget* widget, int skillId);
|
||||||
|
|
|
@ -202,6 +202,11 @@ namespace MWInput
|
||||||
|
|
||||||
void InputManager::handleGuiArrowKey(int action)
|
void InputManager::handleGuiArrowKey(int action)
|
||||||
{
|
{
|
||||||
|
// This is currently keyboard-specific code
|
||||||
|
// TODO: see if GUI controls can be refactored into a single function
|
||||||
|
if (mJoystickLastUsed)
|
||||||
|
return;
|
||||||
|
|
||||||
if (SDL_IsTextInputActive())
|
if (SDL_IsTextInputActive())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -229,13 +234,10 @@ namespace MWInput
|
||||||
MWBase::Environment::get().getWindowManager()->injectKeyPress(key, 0, false);
|
MWBase::Environment::get().getWindowManager()->injectKeyPress(key, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InputManager::gamepadToGuiControl(const SDL_ControllerButtonEvent &arg, bool release=false)
|
bool InputManager::gamepadToGuiControl(const SDL_ControllerButtonEvent &arg)
|
||||||
{
|
{
|
||||||
// Presumption of GUI mode will be removed in the future.
|
// Presumption of GUI mode will be removed in the future.
|
||||||
// MyGUI KeyCodes *may* change.
|
// MyGUI KeyCodes *may* change.
|
||||||
// Currently button releases are ignored.
|
|
||||||
if (release)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
MyGUI::KeyCode key = MyGUI::KeyCode::None;
|
MyGUI::KeyCode key = MyGUI::KeyCode::None;
|
||||||
switch (arg.button)
|
switch (arg.button)
|
||||||
|
@ -386,9 +388,6 @@ namespace MWInput
|
||||||
case A_GameMenu:
|
case A_GameMenu:
|
||||||
toggleMainMenu ();
|
toggleMainMenu ();
|
||||||
break;
|
break;
|
||||||
case A_OptionsMenu:
|
|
||||||
toggleOptionsMenu();
|
|
||||||
break;
|
|
||||||
case A_Screenshot:
|
case A_Screenshot:
|
||||||
screenshot();
|
screenshot();
|
||||||
break;
|
break;
|
||||||
|
@ -406,8 +405,7 @@ namespace MWInput
|
||||||
case A_MoveRight:
|
case A_MoveRight:
|
||||||
case A_MoveForward:
|
case A_MoveForward:
|
||||||
case A_MoveBackward:
|
case A_MoveBackward:
|
||||||
// Temporary shut-down of this function until deemed necessary.
|
handleGuiArrowKey(action);
|
||||||
//handleGuiArrowKey(action);
|
|
||||||
break;
|
break;
|
||||||
case A_Journal:
|
case A_Journal:
|
||||||
toggleJournal ();
|
toggleJournal ();
|
||||||
|
@ -594,7 +592,7 @@ namespace MWInput
|
||||||
rot[2] = xAxis * (dt * 100.0f) * 10.0f * mCameraSensitivity * (1.0f/256.f) * (mInvertX ? -1 : 1);
|
rot[2] = xAxis * (dt * 100.0f) * 10.0f * mCameraSensitivity * (1.0f/256.f) * (mInvertX ? -1 : 1);
|
||||||
|
|
||||||
// Only actually turn player when we're not in vanity mode
|
// Only actually turn player when we're not in vanity mode
|
||||||
if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot))
|
if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot) && mControlSwitch["playerlooking"])
|
||||||
{
|
{
|
||||||
mPlayer->yaw(rot[2]);
|
mPlayer->yaw(rot[2]);
|
||||||
mPlayer->pitch(rot[0]);
|
mPlayer->pitch(rot[0]);
|
||||||
|
@ -832,9 +830,6 @@ namespace MWInput
|
||||||
|
|
||||||
void InputManager::toggleControlSwitch (const std::string& sw, bool value)
|
void InputManager::toggleControlSwitch (const std::string& sw, bool value)
|
||||||
{
|
{
|
||||||
if (mControlSwitch[sw] == value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/// \note 7 switches at all, if-else is relevant
|
/// \note 7 switches at all, if-else is relevant
|
||||||
if (sw == "playercontrols" && !value) {
|
if (sw == "playercontrols" && !value) {
|
||||||
mPlayer->setLeftRight(0);
|
mPlayer->setLeftRight(0);
|
||||||
|
@ -846,8 +841,8 @@ namespace MWInput
|
||||||
mPlayer->setUpDown(0);
|
mPlayer->setUpDown(0);
|
||||||
} else if (sw == "vanitymode") {
|
} else if (sw == "vanitymode") {
|
||||||
MWBase::Environment::get().getWorld()->allowVanityMode(value);
|
MWBase::Environment::get().getWorld()->allowVanityMode(value);
|
||||||
} else if (sw == "playerlooking") {
|
} else if (sw == "playerlooking" && !value) {
|
||||||
MWBase::Environment::get().getWorld()->togglePlayerLooking(value);
|
MWBase::Environment::get().getWorld()->rotateObject(mPlayer->getPlayer(), 0.f, 0.f, 0.f);
|
||||||
}
|
}
|
||||||
mControlSwitch[sw] = value;
|
mControlSwitch[sw] = value;
|
||||||
}
|
}
|
||||||
|
@ -981,7 +976,7 @@ namespace MWInput
|
||||||
rot[2] = -x;
|
rot[2] = -x;
|
||||||
|
|
||||||
// Only actually turn player when we're not in vanity mode
|
// Only actually turn player when we're not in vanity mode
|
||||||
if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot))
|
if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot) && mControlSwitch["playerlooking"])
|
||||||
{
|
{
|
||||||
mPlayer->yaw(x);
|
mPlayer->yaw(x);
|
||||||
mPlayer->pitch(y);
|
mPlayer->pitch(y);
|
||||||
|
@ -1005,9 +1000,9 @@ namespace MWInput
|
||||||
mJoystickLastUsed = true;
|
mJoystickLastUsed = true;
|
||||||
if (MWBase::Environment::get().getWindowManager()->isGuiMode())
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||||
{
|
{
|
||||||
if (gamepadToGuiControl(arg, false))
|
if (gamepadToGuiControl(arg))
|
||||||
return;
|
return;
|
||||||
else if (mGamepadGuiCursorEnabled)
|
if (mGamepadGuiCursorEnabled)
|
||||||
{
|
{
|
||||||
// Temporary mouse binding until keyboard controls are available:
|
// Temporary mouse binding until keyboard controls are available:
|
||||||
if (arg.button == SDL_CONTROLLER_BUTTON_A) // We'll pretend that A is left click.
|
if (arg.button == SDL_CONTROLLER_BUTTON_A) // We'll pretend that A is left click.
|
||||||
|
@ -1048,9 +1043,7 @@ namespace MWInput
|
||||||
mJoystickLastUsed = true;
|
mJoystickLastUsed = true;
|
||||||
if (MWBase::Environment::get().getWindowManager()->isGuiMode())
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||||
{
|
{
|
||||||
if (gamepadToGuiControl(arg, true))
|
if (mGamepadGuiCursorEnabled)
|
||||||
return;
|
|
||||||
else if (mGamepadGuiCursorEnabled)
|
|
||||||
{
|
{
|
||||||
// Temporary mouse binding until keyboard controls are available:
|
// Temporary mouse binding until keyboard controls are available:
|
||||||
if (arg.button == SDL_CONTROLLER_BUTTON_A) // We'll pretend that A is left click.
|
if (arg.button == SDL_CONTROLLER_BUTTON_A) // We'll pretend that A is left click.
|
||||||
|
@ -1149,37 +1142,19 @@ namespace MWInput
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->isConsoleMode())
|
if (MWBase::Environment::get().getWindowManager()->isConsoleMode())
|
||||||
return;
|
|
||||||
|
|
||||||
bool inGame = MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_NoGame;
|
|
||||||
MWGui::GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode();
|
|
||||||
|
|
||||||
if ((inGame && mode == MWGui::GM_MainMenu) || mode == MWGui::GM_Settings)
|
|
||||||
MWBase::Environment::get().getWindowManager()->popGuiMode();
|
|
||||||
|
|
||||||
if (inGame && mode != MWGui::GM_MainMenu)
|
|
||||||
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_MainMenu);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InputManager::toggleOptionsMenu()
|
|
||||||
{
|
{
|
||||||
if (MyGUI::InputManager::getInstance().isModalAny())
|
MWBase::Environment::get().getWindowManager()->toggleConsole();
|
||||||
{
|
|
||||||
MWBase::Environment::get().getWindowManager()->exitCurrentModal();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->isConsoleMode())
|
if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) //No open GUIs, open up the MainMenu
|
||||||
return;
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
|
||||||
MWGui::GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode();
|
}
|
||||||
bool inGame = MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_NoGame;
|
else //Close current GUI
|
||||||
|
{
|
||||||
if ((inGame && mode == MWGui::GM_MainMenu) || mode == MWGui::GM_Settings)
|
MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode();
|
||||||
MWBase::Environment::get().getWindowManager()->popGuiMode();
|
}
|
||||||
|
|
||||||
if (inGame && mode != MWGui::GM_Settings)
|
|
||||||
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Settings);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputManager::quickLoad() {
|
void InputManager::quickLoad() {
|
||||||
|
@ -1534,7 +1509,6 @@ namespace MWInput
|
||||||
defaultButtonBindings[A_TogglePOV] = SDL_CONTROLLER_BUTTON_RIGHTSTICK;
|
defaultButtonBindings[A_TogglePOV] = SDL_CONTROLLER_BUTTON_RIGHTSTICK;
|
||||||
defaultButtonBindings[A_Inventory] = SDL_CONTROLLER_BUTTON_B;
|
defaultButtonBindings[A_Inventory] = SDL_CONTROLLER_BUTTON_B;
|
||||||
defaultButtonBindings[A_GameMenu] = SDL_CONTROLLER_BUTTON_START;
|
defaultButtonBindings[A_GameMenu] = SDL_CONTROLLER_BUTTON_START;
|
||||||
defaultButtonBindings[A_OptionsMenu] = SDL_CONTROLLER_BUTTON_BACK;
|
|
||||||
defaultButtonBindings[A_QuickSave] = SDL_CONTROLLER_BUTTON_GUIDE;
|
defaultButtonBindings[A_QuickSave] = SDL_CONTROLLER_BUTTON_GUIDE;
|
||||||
defaultButtonBindings[A_MoveForward] = SDL_CONTROLLER_BUTTON_DPAD_UP;
|
defaultButtonBindings[A_MoveForward] = SDL_CONTROLLER_BUTTON_DPAD_UP;
|
||||||
defaultButtonBindings[A_MoveLeft] = SDL_CONTROLLER_BUTTON_DPAD_LEFT;
|
defaultButtonBindings[A_MoveLeft] = SDL_CONTROLLER_BUTTON_DPAD_LEFT;
|
||||||
|
@ -1615,7 +1589,6 @@ namespace MWInput
|
||||||
descriptions[A_Journal] = "sJournal";
|
descriptions[A_Journal] = "sJournal";
|
||||||
descriptions[A_Rest] = "sRestKey";
|
descriptions[A_Rest] = "sRestKey";
|
||||||
descriptions[A_Inventory] = "sInventory";
|
descriptions[A_Inventory] = "sInventory";
|
||||||
descriptions[A_OptionsMenu] = "sPreferences";
|
|
||||||
descriptions[A_TogglePOV] = "sTogglePOVCmd";
|
descriptions[A_TogglePOV] = "sTogglePOVCmd";
|
||||||
descriptions[A_QuickKeysMenu] = "sQuickMenu";
|
descriptions[A_QuickKeysMenu] = "sQuickMenu";
|
||||||
descriptions[A_QuickKey1] = "sQuick1Cmd";
|
descriptions[A_QuickKey1] = "sQuick1Cmd";
|
||||||
|
@ -1753,7 +1726,6 @@ namespace MWInput
|
||||||
ret.push_back(A_Inventory);
|
ret.push_back(A_Inventory);
|
||||||
ret.push_back(A_Journal);
|
ret.push_back(A_Journal);
|
||||||
ret.push_back(A_Rest);
|
ret.push_back(A_Rest);
|
||||||
ret.push_back(A_OptionsMenu);
|
|
||||||
ret.push_back(A_Console);
|
ret.push_back(A_Console);
|
||||||
ret.push_back(A_QuickSave);
|
ret.push_back(A_QuickSave);
|
||||||
ret.push_back(A_QuickLoad);
|
ret.push_back(A_QuickLoad);
|
||||||
|
@ -1786,7 +1758,6 @@ namespace MWInput
|
||||||
ret.push_back(A_Inventory);
|
ret.push_back(A_Inventory);
|
||||||
ret.push_back(A_Journal);
|
ret.push_back(A_Journal);
|
||||||
ret.push_back(A_Rest);
|
ret.push_back(A_Rest);
|
||||||
ret.push_back(A_OptionsMenu);
|
|
||||||
ret.push_back(A_QuickSave);
|
ret.push_back(A_QuickSave);
|
||||||
ret.push_back(A_QuickLoad);
|
ret.push_back(A_QuickLoad);
|
||||||
ret.push_back(A_Screenshot);
|
ret.push_back(A_Screenshot);
|
||||||
|
|
|
@ -226,7 +226,7 @@ namespace MWInput
|
||||||
void setPlayerControlsEnabled(bool enabled);
|
void setPlayerControlsEnabled(bool enabled);
|
||||||
void handleGuiArrowKey(int action);
|
void handleGuiArrowKey(int action);
|
||||||
// Return true if GUI consumes input.
|
// Return true if GUI consumes input.
|
||||||
bool gamepadToGuiControl(const SDL_ControllerButtonEvent &arg, bool release);
|
bool gamepadToGuiControl(const SDL_ControllerButtonEvent &arg);
|
||||||
bool gamepadToGuiControl(const SDL_ControllerAxisEvent &arg);
|
bool gamepadToGuiControl(const SDL_ControllerAxisEvent &arg);
|
||||||
|
|
||||||
void updateCursorMode();
|
void updateCursorMode();
|
||||||
|
@ -235,7 +235,6 @@ namespace MWInput
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void toggleMainMenu();
|
void toggleMainMenu();
|
||||||
void toggleOptionsMenu();
|
|
||||||
void toggleSpell();
|
void toggleSpell();
|
||||||
void toggleWeapon();
|
void toggleWeapon();
|
||||||
void toggleInventory();
|
void toggleInventory();
|
||||||
|
@ -328,8 +327,6 @@ namespace MWInput
|
||||||
A_MoveForwardBackward,
|
A_MoveForwardBackward,
|
||||||
A_MoveLeftRight,
|
A_MoveLeftRight,
|
||||||
|
|
||||||
A_OptionsMenu,
|
|
||||||
|
|
||||||
A_Last // Marker for the last item
|
A_Last // Marker for the last item
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1785,14 +1785,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
MWWorld::Ptr player = getPlayer();
|
MWWorld::Ptr player = getPlayer();
|
||||||
|
|
||||||
CreatureStats& stats = player.getClass().getCreatureStats(player);
|
if (!MWBase::Environment::get().getMechanicsManager()->isSneaking(player))
|
||||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
|
||||||
|
|
||||||
bool sneaking = stats.getStance(MWMechanics::CreatureStats::Stance_Sneak);
|
|
||||||
bool inair = !world->isOnGround(player) && !world->isSwimming(player) && !world->isFlying(player);
|
|
||||||
sneaking = sneaking && (ctrl->isSneaking() || inair);
|
|
||||||
|
|
||||||
if (!sneaking)
|
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWindowManager()->setSneakVisibility(false);
|
MWBase::Environment::get().getWindowManager()->setSneakVisibility(false);
|
||||||
return;
|
return;
|
||||||
|
@ -1800,6 +1793,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
static float sneakSkillTimer = 0.f; // Times sneak skill progress from "avoid notice"
|
static float sneakSkillTimer = 0.f; // Times sneak skill progress from "avoid notice"
|
||||||
|
|
||||||
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
const MWWorld::Store<ESM::GameSetting>& gmst = world->getStore().get<ESM::GameSetting>();
|
const MWWorld::Store<ESM::GameSetting>& gmst = world->getStore().get<ESM::GameSetting>();
|
||||||
static const float fSneakUseDist = gmst.find("fSneakUseDist")->mValue.getFloat();
|
static const float fSneakUseDist = gmst.find("fSneakUseDist")->mValue.getFloat();
|
||||||
static const float fSneakUseDelay = gmst.find("fSneakUseDelay")->mValue.getFloat();
|
static const float fSneakUseDelay = gmst.find("fSneakUseDelay")->mValue.getFloat();
|
||||||
|
|
|
@ -44,7 +44,7 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, CharacterCont
|
||||||
return true; // We have tried backing up for more than one second, we've probably cleared it
|
return true; // We have tried backing up for more than one second, we've probably cleared it
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mDoorPtr.getClass().getDoorState(mDoorPtr))
|
if (mDoorPtr.getClass().getDoorState(mDoorPtr) == MWWorld::DoorState::Idle)
|
||||||
return true; //Door is no longer opening
|
return true; //Door is no longer opening
|
||||||
|
|
||||||
ESM::Position tPos = mDoorPtr.getRefData().getPosition(); //Position of the door
|
ESM::Position tPos = mDoorPtr.getRefData().getPosition(); //Position of the door
|
||||||
|
|
|
@ -232,7 +232,7 @@ void MWMechanics::AiPackage::openDoors(const MWWorld::Ptr& actor)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// note: AiWander currently does not open doors
|
// note: AiWander currently does not open doors
|
||||||
if (getTypeId() != TypeIdWander && !door.getCellRef().getTeleport() && door.getClass().getDoorState(door) == 0)
|
if (getTypeId() != TypeIdWander && !door.getCellRef().getTeleport() && door.getClass().getDoorState(door) == MWWorld::DoorState::Idle)
|
||||||
{
|
{
|
||||||
if ((door.getCellRef().getTrap().empty() && door.getCellRef().getLockLevel() <= 0 ))
|
if ((door.getCellRef().getTrap().empty() && door.getCellRef().getLockLevel() <= 0 ))
|
||||||
{
|
{
|
||||||
|
|
|
@ -529,19 +529,7 @@ void CharacterController::refreshMovementAnims(const std::string& weapShortGroup
|
||||||
if(!mAnimation->hasAnimation(movementAnimName))
|
if(!mAnimation->hasAnimation(movementAnimName))
|
||||||
{
|
{
|
||||||
std::string::size_type swimpos = movementAnimName.find("swim");
|
std::string::size_type swimpos = movementAnimName.find("swim");
|
||||||
if(swimpos == std::string::npos)
|
if (swimpos != std::string::npos)
|
||||||
{
|
|
||||||
std::string::size_type runpos = movementAnimName.find("run");
|
|
||||||
if (runpos != std::string::npos)
|
|
||||||
{
|
|
||||||
movementAnimName.replace(runpos, runpos+3, "walk");
|
|
||||||
if (!mAnimation->hasAnimation(movementAnimName))
|
|
||||||
movementAnimName.clear();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
movementAnimName.clear();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
movementAnimName.erase(swimpos, 4);
|
movementAnimName.erase(swimpos, 4);
|
||||||
if (!weapShortGroup.empty())
|
if (!weapShortGroup.empty())
|
||||||
|
@ -552,10 +540,20 @@ void CharacterController::refreshMovementAnims(const std::string& weapShortGroup
|
||||||
else
|
else
|
||||||
movementAnimName = fallbackShortWeaponGroup(movementAnimName, &movemask);
|
movementAnimName = fallbackShortWeaponGroup(movementAnimName, &movemask);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (swimpos == std::string::npos || !mAnimation->hasAnimation(movementAnimName))
|
||||||
|
{
|
||||||
|
std::string::size_type runpos = movementAnimName.find("run");
|
||||||
|
if (runpos != std::string::npos)
|
||||||
|
{
|
||||||
|
movementAnimName.replace(runpos, runpos+3, "walk");
|
||||||
if (!mAnimation->hasAnimation(movementAnimName))
|
if (!mAnimation->hasAnimation(movementAnimName))
|
||||||
movementAnimName.clear();
|
movementAnimName.clear();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
movementAnimName.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -570,10 +568,6 @@ void CharacterController::refreshMovementAnims(const std::string& weapShortGroup
|
||||||
mCurrentMovement = movementAnimName;
|
mCurrentMovement = movementAnimName;
|
||||||
if(!mCurrentMovement.empty())
|
if(!mCurrentMovement.empty())
|
||||||
{
|
{
|
||||||
bool isflying = MWBase::Environment::get().getWorld()->isFlying(mPtr);
|
|
||||||
bool isrunning = mPtr.getClass().getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Run) && !isflying;
|
|
||||||
bool issneaking = mPtr.getClass().getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Sneak) && !isflying;
|
|
||||||
|
|
||||||
// For non-flying creatures, MW uses the Walk animation to calculate the animation velocity
|
// For non-flying creatures, MW uses the Walk animation to calculate the animation velocity
|
||||||
// even if we are running. This must be replicated, otherwise the observed speed would differ drastically.
|
// even if we are running. This must be replicated, otherwise the observed speed would differ drastically.
|
||||||
std::string anim = mCurrentMovement;
|
std::string anim = mCurrentMovement;
|
||||||
|
@ -606,7 +600,7 @@ void CharacterController::refreshMovementAnims(const std::string& weapShortGroup
|
||||||
// The first person anims don't have any velocity to calculate a speed multiplier from.
|
// The first person anims don't have any velocity to calculate a speed multiplier from.
|
||||||
// We use the third person velocities instead.
|
// We use the third person velocities instead.
|
||||||
// FIXME: should be pulled from the actual animation, but it is not presently loaded.
|
// FIXME: should be pulled from the actual animation, but it is not presently loaded.
|
||||||
mMovementAnimSpeed = (issneaking ? 33.5452f : (isrunning ? 222.857f : 154.064f));
|
mMovementAnimSpeed = (isSneaking() ? 33.5452f : (isRunning() ? 222.857f : 154.064f));
|
||||||
mMovementAnimationControlled = false;
|
mMovementAnimationControlled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2048,28 +2042,6 @@ void CharacterController::update(float duration, bool animationOnly)
|
||||||
lat.normalize();
|
lat.normalize();
|
||||||
vec = osg::Vec3f(lat.x(), lat.y(), 1.0f) * z * 0.707f;
|
vec = osg::Vec3f(lat.x(), lat.y(), 1.0f) * z * 0.707f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// advance acrobatics
|
|
||||||
// also set jumping flag to allow GetPCJumping works
|
|
||||||
if (isPlayer)
|
|
||||||
{
|
|
||||||
cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 0);
|
|
||||||
MWBase::Environment::get().getWorld()->getPlayer().setJumping(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// decrease fatigue
|
|
||||||
const float fatigueJumpBase = gmst.find("fFatigueJumpBase")->mValue.getFloat();
|
|
||||||
const float fatigueJumpMult = gmst.find("fFatigueJumpMult")->mValue.getFloat();
|
|
||||||
float normalizedEncumbrance = mPtr.getClass().getNormalizedEncumbrance(mPtr);
|
|
||||||
if (normalizedEncumbrance > 1)
|
|
||||||
normalizedEncumbrance = 1;
|
|
||||||
const float fatigueDecrease = fatigueJumpBase + normalizedEncumbrance * fatigueJumpMult;
|
|
||||||
|
|
||||||
if (!godmode)
|
|
||||||
{
|
|
||||||
fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease);
|
|
||||||
cls.getCreatureStats(mPtr).setFatigue(fatigue);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(mJumpState == JumpState_InAir && !inwater && !flying && solid)
|
else if(mJumpState == JumpState_InAir && !inwater && !flying && solid)
|
||||||
|
@ -2282,7 +2254,9 @@ void CharacterController::update(float duration, bool animationOnly)
|
||||||
|
|
||||||
movement = vec;
|
movement = vec;
|
||||||
cls.getMovementSettings(mPtr).mPosition[0] = cls.getMovementSettings(mPtr).mPosition[1] = 0;
|
cls.getMovementSettings(mPtr).mPosition[0] = cls.getMovementSettings(mPtr).mPosition[1] = 0;
|
||||||
// Can't reset jump state (mPosition[2]) here; we don't know for sure whether the PhysicSystem will actually handle it in this frame
|
if (movement.z() == 0.f)
|
||||||
|
cls.getMovementSettings(mPtr).mPosition[2] = 0;
|
||||||
|
// Can't reset jump state (mPosition[2]) here in full; we don't know for sure whether the PhysicSystem will actually handle it in this frame
|
||||||
// due to the fixed minimum timestep used for the physics update. It will be reset in PhysicSystem::move once the jump is handled.
|
// due to the fixed minimum timestep used for the physics update. It will be reset in PhysicSystem::move once the jump is handled.
|
||||||
|
|
||||||
if (!mSkipAnim)
|
if (!mSkipAnim)
|
||||||
|
|
|
@ -477,7 +477,12 @@ namespace MWMechanics
|
||||||
|
|
||||||
bool MechanicsManager::isSneaking(const MWWorld::Ptr& ptr)
|
bool MechanicsManager::isSneaking(const MWWorld::Ptr& ptr)
|
||||||
{
|
{
|
||||||
return mActors.isSneaking(ptr);
|
CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
|
||||||
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
|
bool animActive = mActors.isSneaking(ptr);
|
||||||
|
bool stanceOn = stats.getStance(MWMechanics::CreatureStats::Stance_Sneak);
|
||||||
|
bool inair = !world->isOnGround(ptr) && !world->isSwimming(ptr) && !world->isFlying(ptr);
|
||||||
|
return stanceOn && (animActive || inair);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MechanicsManager::rest(double hours, bool sleep)
|
void MechanicsManager::rest(double hours, bool sleep)
|
||||||
|
@ -965,8 +970,7 @@ namespace MWMechanics
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// check if a player tries to pickpocket a target NPC
|
// check if a player tries to pickpocket a target NPC
|
||||||
if(ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Sneak)
|
if (target.getClass().getCreatureStats(target).getKnockedDown() || isSneaking(ptr))
|
||||||
|| target.getClass().getCreatureStats(target).getKnockedDown())
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1586,9 +1590,7 @@ namespace MWMechanics
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
float sneakTerm = 0;
|
float sneakTerm = 0;
|
||||||
if (ptr.getClass().getCreatureStats(ptr).getStance(CreatureStats::Stance_Sneak)
|
if (isSneaking(ptr))
|
||||||
&& !MWBase::Environment::get().getWorld()->isSwimming(ptr)
|
|
||||||
&& MWBase::Environment::get().getWorld()->isOnGround(ptr))
|
|
||||||
{
|
{
|
||||||
static float fSneakSkillMult = store.find("fSneakSkillMult")->mValue.getFloat();
|
static float fSneakSkillMult = store.find("fSneakSkillMult")->mValue.getFloat();
|
||||||
static float fSneakBootMult = store.find("fSneakBootMult")->mValue.getFloat();
|
static float fSneakBootMult = store.find("fSneakBootMult")->mValue.getFloat();
|
||||||
|
@ -1596,7 +1598,7 @@ namespace MWMechanics
|
||||||
int agility = stats.getAttribute(ESM::Attribute::Agility).getModified();
|
int agility = stats.getAttribute(ESM::Attribute::Agility).getModified();
|
||||||
int luck = stats.getAttribute(ESM::Attribute::Luck).getModified();
|
int luck = stats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||||
float bootWeight = 0;
|
float bootWeight = 0;
|
||||||
if (ptr.getClass().isNpc())
|
if (ptr.getClass().isNpc() && MWBase::Environment::get().getWorld()->isOnGround(ptr))
|
||||||
{
|
{
|
||||||
const MWWorld::InventoryStore& inv = ptr.getClass().getInventoryStore(ptr);
|
const MWWorld::InventoryStore& inv = ptr.getClass().getInventoryStore(ptr);
|
||||||
MWWorld::ConstContainerStoreIterator it = inv.getSlot(MWWorld::InventoryStore::Slot_Boots);
|
MWWorld::ConstContainerStoreIterator it = inv.getSlot(MWWorld::InventoryStore::Slot_Boots);
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||||
|
|
||||||
#include "../mwbase/world.hpp"
|
|
||||||
#include "../mwbase/environment.hpp"
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/cellstore.hpp"
|
#include "../mwworld/cellstore.hpp"
|
||||||
|
|
||||||
|
@ -54,10 +52,10 @@ namespace MWMechanics
|
||||||
// FIXME: cast
|
// FIXME: cast
|
||||||
const MWWorld::Ptr doorPtr = MWWorld::Ptr(&const_cast<MWWorld::LiveCellRef<ESM::Door> &>(ref), actor.getCell());
|
const MWWorld::Ptr doorPtr = MWWorld::Ptr(&const_cast<MWWorld::LiveCellRef<ESM::Door> &>(ref), actor.getCell());
|
||||||
|
|
||||||
int doorState = doorPtr.getClass().getDoorState(doorPtr);
|
const auto doorState = doorPtr.getClass().getDoorState(doorPtr);
|
||||||
float doorRot = ref.mData.getPosition().rot[2] - doorPtr.getCellRef().getPosition().rot[2];
|
float doorRot = ref.mData.getPosition().rot[2] - doorPtr.getCellRef().getPosition().rot[2];
|
||||||
|
|
||||||
if (doorState != 0 || doorRot != 0)
|
if (doorState != MWWorld::DoorState::Idle || doorRot != 0)
|
||||||
continue; // the door is already opened/opening
|
continue; // the door is already opened/opening
|
||||||
|
|
||||||
doorPos.z() = 0;
|
doorPos.z() = 0;
|
||||||
|
@ -78,10 +76,8 @@ namespace MWMechanics
|
||||||
return MWWorld::Ptr(); // none found
|
return MWWorld::Ptr(); // none found
|
||||||
}
|
}
|
||||||
|
|
||||||
ObstacleCheck::ObstacleCheck():
|
ObstacleCheck::ObstacleCheck()
|
||||||
mPrevX(0) // to see if the moved since last time
|
: mWalkState(State_Norm)
|
||||||
, mPrevY(0)
|
|
||||||
, mWalkState(State_Norm)
|
|
||||||
, mStuckDuration(0)
|
, mStuckDuration(0)
|
||||||
, mEvadeDuration(0)
|
, mEvadeDuration(0)
|
||||||
, mDistSameSpot(-1) // avoid calculating it each time
|
, mDistSameSpot(-1) // avoid calculating it each time
|
||||||
|
@ -125,21 +121,15 @@ namespace MWMechanics
|
||||||
*/
|
*/
|
||||||
void ObstacleCheck::update(const MWWorld::Ptr& actor, float duration)
|
void ObstacleCheck::update(const MWWorld::Ptr& actor, float duration)
|
||||||
{
|
{
|
||||||
const ESM::Position pos = actor.getRefData().getPosition();
|
const osg::Vec3f pos = actor.getRefData().getPosition().asVec3();
|
||||||
|
|
||||||
if (mDistSameSpot == -1)
|
if (mDistSameSpot == -1)
|
||||||
{
|
mDistSameSpot = DIST_SAME_SPOT * actor.getClass().getSpeed(actor);
|
||||||
const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getHalfExtents(actor);
|
|
||||||
mDistSameSpot = DIST_SAME_SPOT * actor.getClass().getSpeed(actor) + 1.2 * std::max(halfExtents.x(), halfExtents.y());
|
|
||||||
}
|
|
||||||
|
|
||||||
const float distSameSpot = mDistSameSpot * duration;
|
const float distSameSpot = mDistSameSpot * duration;
|
||||||
const float squaredMovedDistance = (osg::Vec2f(pos.pos[0], pos.pos[1]) - osg::Vec2f(mPrevX, mPrevY)).length2();
|
const bool samePosition = (pos - mPrev).length2() < distSameSpot * distSameSpot;
|
||||||
const bool samePosition = squaredMovedDistance < distSameSpot * distSameSpot;
|
|
||||||
|
|
||||||
// update position
|
mPrev = pos;
|
||||||
mPrevX = pos.pos[0];
|
|
||||||
mPrevY = pos.pos[1];
|
|
||||||
|
|
||||||
switch(mWalkState)
|
switch(mWalkState)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef OPENMW_MECHANICS_OBSTACLE_H
|
#ifndef OPENMW_MECHANICS_OBSTACLE_H
|
||||||
#define OPENMW_MECHANICS_OBSTACLE_H
|
#define OPENMW_MECHANICS_OBSTACLE_H
|
||||||
|
|
||||||
|
#include <osg/Vec3f>
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
class Ptr;
|
class Ptr;
|
||||||
|
@ -37,9 +39,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// for checking if we're stuck (ignoring Z axis)
|
// for checking if we're stuck
|
||||||
float mPrevX;
|
osg::Vec3f mPrev;
|
||||||
float mPrevY;
|
|
||||||
|
|
||||||
// directions to try moving in when get stuck
|
// directions to try moving in when get stuck
|
||||||
static const float evadeDirections[NUM_EVADE_DIRECTIONS][2];
|
static const float evadeDirections[NUM_EVADE_DIRECTIONS][2];
|
||||||
|
|
|
@ -238,7 +238,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
/* short group */ "",
|
/* short group */ "",
|
||||||
/* long group */ "",
|
/* long group */ "",
|
||||||
/* sound ID */ "Item Weapon Ammo",
|
/* sound ID */ "Item Ammo",
|
||||||
/* attach bone */ "ArrowBone",
|
/* attach bone */ "ArrowBone",
|
||||||
/* sheath bone */ "",
|
/* sheath bone */ "",
|
||||||
/* usage skill */ ESM::Skill::Marksman,
|
/* usage skill */ ESM::Skill::Marksman,
|
||||||
|
@ -252,7 +252,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
/* short group */ "",
|
/* short group */ "",
|
||||||
/* long group */ "",
|
/* long group */ "",
|
||||||
/* sound ID */ "Item Weapon Ammo",
|
/* sound ID */ "Item Ammo",
|
||||||
/* attach bone */ "ArrowBone",
|
/* attach bone */ "ArrowBone",
|
||||||
/* sheath bone */ "",
|
/* sheath bone */ "",
|
||||||
/* usage skill */ ESM::Skill::Marksman,
|
/* usage skill */ ESM::Skill::Marksman,
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
|
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
#include "../mwworld/cellstore.hpp"
|
#include "../mwworld/cellstore.hpp"
|
||||||
|
#include "../mwworld/player.hpp"
|
||||||
|
|
||||||
#include "../mwrender/bulletdebugdraw.hpp"
|
#include "../mwrender/bulletdebugdraw.hpp"
|
||||||
|
|
||||||
|
@ -326,7 +327,30 @@ namespace MWPhysics
|
||||||
if (movement.z() > 0 && ptr.getClass().getCreatureStats(ptr).isDead() && position.z() < swimlevel)
|
if (movement.z() > 0 && ptr.getClass().getCreatureStats(ptr).isDead() && position.z() < swimlevel)
|
||||||
velocity = osg::Vec3f(0,0,1) * 25;
|
velocity = osg::Vec3f(0,0,1) * 25;
|
||||||
|
|
||||||
|
if (ptr.getClass().getMovementSettings(ptr).mPosition[2])
|
||||||
|
{
|
||||||
|
const bool isPlayer = (ptr == MWMechanics::getPlayer());
|
||||||
|
// Advance acrobatics and set flag for GetPCJumping
|
||||||
|
if (isPlayer)
|
||||||
|
{
|
||||||
|
ptr.getClass().skillUsageSucceeded(ptr, ESM::Skill::Acrobatics, 0);
|
||||||
|
MWBase::Environment::get().getWorld()->getPlayer().setJumping(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrease fatigue
|
||||||
|
if (!isPlayer || !MWBase::Environment::get().getWorld()->getGodModeState())
|
||||||
|
{
|
||||||
|
const MWWorld::Store<ESM::GameSetting> &gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
|
const float fFatigueJumpBase = gmst.find("fFatigueJumpBase")->mValue.getFloat();
|
||||||
|
const float fFatigueJumpMult = gmst.find("fFatigueJumpMult")->mValue.getFloat();
|
||||||
|
const float normalizedEncumbrance = std::min(1.f, ptr.getClass().getNormalizedEncumbrance(ptr));
|
||||||
|
const float fatigueDecrease = fFatigueJumpBase + normalizedEncumbrance * fFatigueJumpMult;
|
||||||
|
MWMechanics::DynamicStat<float> fatigue = ptr.getClass().getCreatureStats(ptr).getFatigue();
|
||||||
|
fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease);
|
||||||
|
ptr.getClass().getCreatureStats(ptr).setFatigue(fatigue);
|
||||||
|
}
|
||||||
ptr.getClass().getMovementSettings(ptr).mPosition[2] = 0;
|
ptr.getClass().getMovementSettings(ptr).mPosition[2] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Now that we have the effective movement vector, apply wind forces to it
|
// Now that we have the effective movement vector, apply wind forces to it
|
||||||
if (MWBase::Environment::get().getWorld()->isInStorm())
|
if (MWBase::Environment::get().getWorld()->isInStorm())
|
||||||
|
|
|
@ -64,7 +64,7 @@ ActorAnimation::~ActorAnimation()
|
||||||
mScabbard.reset();
|
mScabbard.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
PartHolderPtr ActorAnimation::getWeaponPart(const std::string& model, const std::string& bonename, bool enchantedGlow, osg::Vec4f* glowColor)
|
PartHolderPtr ActorAnimation::attachMesh(const std::string& model, const std::string& bonename, bool enchantedGlow, osg::Vec4f* glowColor)
|
||||||
{
|
{
|
||||||
osg::Group* parent = getBoneByName(bonename);
|
osg::Group* parent = getBoneByName(bonename);
|
||||||
if (!parent)
|
if (!parent)
|
||||||
|
@ -160,7 +160,7 @@ void ActorAnimation::updateHolsteredWeapon(bool showHolsteredWeapons)
|
||||||
if (showHolsteredWeapons)
|
if (showHolsteredWeapons)
|
||||||
{
|
{
|
||||||
osg::Vec4f glowColor = weapon->getClass().getEnchantmentColor(*weapon);
|
osg::Vec4f glowColor = weapon->getClass().getEnchantmentColor(*weapon);
|
||||||
mScabbard = getWeaponPart(mesh, boneName, isEnchanted, &glowColor);
|
mScabbard = attachMesh(mesh, boneName, isEnchanted, &glowColor);
|
||||||
if (mScabbard)
|
if (mScabbard)
|
||||||
resetControllers(mScabbard->getNode());
|
resetControllers(mScabbard->getNode());
|
||||||
}
|
}
|
||||||
|
@ -168,7 +168,7 @@ void ActorAnimation::updateHolsteredWeapon(bool showHolsteredWeapons)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mScabbard = getWeaponPart(scabbardName, boneName);
|
mScabbard = attachMesh(scabbardName, boneName);
|
||||||
|
|
||||||
osg::Group* weaponNode = getBoneByName("Bip01 Weapon");
|
osg::Group* weaponNode = getBoneByName("Bip01 Weapon");
|
||||||
if (!weaponNode)
|
if (!weaponNode)
|
||||||
|
|
|
@ -44,11 +44,11 @@ class ActorAnimation : public Animation, public MWWorld::ContainerStoreListener
|
||||||
virtual void updateHolsteredWeapon(bool showHolsteredWeapons);
|
virtual void updateHolsteredWeapon(bool showHolsteredWeapons);
|
||||||
virtual void updateQuiver();
|
virtual void updateQuiver();
|
||||||
virtual std::string getHolsteredWeaponBoneName(const MWWorld::ConstPtr& weapon);
|
virtual std::string getHolsteredWeaponBoneName(const MWWorld::ConstPtr& weapon);
|
||||||
virtual PartHolderPtr getWeaponPart(const std::string& model, const std::string& bonename, bool enchantedGlow, osg::Vec4f* glowColor);
|
virtual PartHolderPtr attachMesh(const std::string& model, const std::string& bonename, bool enchantedGlow, osg::Vec4f* glowColor);
|
||||||
virtual PartHolderPtr getWeaponPart(const std::string& model, const std::string& bonename)
|
virtual PartHolderPtr attachMesh(const std::string& model, const std::string& bonename)
|
||||||
{
|
{
|
||||||
osg::Vec4f stubColor = osg::Vec4f(0,0,0,0);
|
osg::Vec4f stubColor = osg::Vec4f(0,0,0,0);
|
||||||
return getWeaponPart(model, bonename, false, &stubColor);
|
return attachMesh(model, bonename, false, &stubColor);
|
||||||
};
|
};
|
||||||
|
|
||||||
PartHolderPtr mScabbard;
|
PartHolderPtr mScabbard;
|
||||||
|
|
|
@ -18,12 +18,14 @@
|
||||||
#include <components/resource/keyframemanager.hpp>
|
#include <components/resource/keyframemanager.hpp>
|
||||||
|
|
||||||
#include <components/misc/constants.hpp>
|
#include <components/misc/constants.hpp>
|
||||||
|
#include <components/misc/resourcehelpers.hpp>
|
||||||
|
|
||||||
#include <components/nifosg/nifloader.hpp> // KeyframeHolder
|
#include <components/nifosg/nifloader.hpp> // KeyframeHolder
|
||||||
#include <components/nifosg/controller.hpp>
|
#include <components/nifosg/controller.hpp>
|
||||||
|
|
||||||
#include <components/vfs/manager.hpp>
|
#include <components/vfs/manager.hpp>
|
||||||
|
|
||||||
|
#include <components/sceneutil/actorutil.hpp>
|
||||||
#include <components/sceneutil/statesetupdater.hpp>
|
#include <components/sceneutil/statesetupdater.hpp>
|
||||||
#include <components/sceneutil/visitor.hpp>
|
#include <components/sceneutil/visitor.hpp>
|
||||||
#include <components/sceneutil/lightmanager.hpp>
|
#include <components/sceneutil/lightmanager.hpp>
|
||||||
|
@ -245,7 +247,10 @@ namespace
|
||||||
void apply(osg::Node& node)
|
void apply(osg::Node& node)
|
||||||
{
|
{
|
||||||
if (SceneUtil::hasUserDescription(&node, "CustomBone"))
|
if (SceneUtil::hasUserDescription(&node, "CustomBone"))
|
||||||
|
{
|
||||||
mFoundBones.emplace_back(&node, node.getParent(0));
|
mFoundBones.emplace_back(&node, node.getParent(0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
traverse(node);
|
traverse(node);
|
||||||
}
|
}
|
||||||
|
@ -1378,6 +1383,9 @@ namespace MWRender
|
||||||
|
|
||||||
void injectCustomBones(osg::ref_ptr<osg::Node>& node, const std::string& model, Resource::ResourceSystem* resourceSystem)
|
void injectCustomBones(osg::ref_ptr<osg::Node>& node, const std::string& model, Resource::ResourceSystem* resourceSystem)
|
||||||
{
|
{
|
||||||
|
if (model.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
const std::map<std::string, VFS::File*>& index = resourceSystem->getVFS()->getIndex();
|
const std::map<std::string, VFS::File*>& index = resourceSystem->getVFS()->getIndex();
|
||||||
|
|
||||||
std::string animationPath = model;
|
std::string animationPath = model;
|
||||||
|
@ -1405,14 +1413,7 @@ namespace MWRender
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum InjectType
|
osg::ref_ptr<osg::Node> getModelInstance(Resource::ResourceSystem* resourceSystem, const std::string& model, bool baseonly, bool inject, const std::string& defaultSkeleton)
|
||||||
{
|
|
||||||
None,
|
|
||||||
Model,
|
|
||||||
ModelWithFallback
|
|
||||||
};
|
|
||||||
|
|
||||||
osg::ref_ptr<osg::Node> getModelInstance(Resource::ResourceSystem* resourceSystem, const std::string& model, bool baseonly, InjectType inject)
|
|
||||||
{
|
{
|
||||||
Resource::SceneManager* sceneMgr = resourceSystem->getSceneManager();
|
Resource::SceneManager* sceneMgr = resourceSystem->getSceneManager();
|
||||||
if (baseonly)
|
if (baseonly)
|
||||||
|
@ -1424,11 +1425,11 @@ namespace MWRender
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::Node> created = sceneMgr->getInstance(model);
|
osg::ref_ptr<osg::Node> created = sceneMgr->getInstance(model);
|
||||||
|
|
||||||
if (inject == InjectType::ModelWithFallback)
|
if (inject)
|
||||||
injectCustomBones(created, "meshes\\xbase_anim.nif", resourceSystem);
|
{
|
||||||
|
injectCustomBones(created, defaultSkeleton, resourceSystem);
|
||||||
if (inject != InjectType::None)
|
|
||||||
injectCustomBones(created, model, resourceSystem);
|
injectCustomBones(created, model, resourceSystem);
|
||||||
|
}
|
||||||
|
|
||||||
SceneUtil::CleanObjectRootVisitor removeDrawableVisitor;
|
SceneUtil::CleanObjectRootVisitor removeDrawableVisitor;
|
||||||
created->accept(removeDrawableVisitor);
|
created->accept(removeDrawableVisitor);
|
||||||
|
@ -1445,11 +1446,11 @@ namespace MWRender
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::Node> created = sceneMgr->getInstance(model);
|
osg::ref_ptr<osg::Node> created = sceneMgr->getInstance(model);
|
||||||
|
|
||||||
if (inject == InjectType::ModelWithFallback)
|
if (inject)
|
||||||
injectCustomBones(created, "meshes\\xbase_anim.nif", resourceSystem);
|
{
|
||||||
|
injectCustomBones(created, defaultSkeleton, resourceSystem);
|
||||||
if (inject != InjectType::None)
|
|
||||||
injectCustomBones(created, model, resourceSystem);
|
injectCustomBones(created, model, resourceSystem);
|
||||||
|
}
|
||||||
|
|
||||||
return created;
|
return created;
|
||||||
}
|
}
|
||||||
|
@ -1475,17 +1476,44 @@ namespace MWRender
|
||||||
mAccumCtrl = nullptr;
|
mAccumCtrl = nullptr;
|
||||||
|
|
||||||
static const bool useAdditionalSources = Settings::Manager::getBool ("use additional anim sources", "Game");
|
static const bool useAdditionalSources = Settings::Manager::getBool ("use additional anim sources", "Game");
|
||||||
InjectType inject = useAdditionalSources && mPtr.getClass().isActor() ? InjectType::Model : InjectType::None;
|
std::string defaultSkeleton;
|
||||||
if (inject != InjectType::None && isCreature)
|
bool inject = false;
|
||||||
|
|
||||||
|
if (useAdditionalSources && mPtr.getClass().isActor())
|
||||||
|
{
|
||||||
|
if (isCreature)
|
||||||
{
|
{
|
||||||
MWWorld::LiveCellRef<ESM::Creature> *ref = mPtr.get<ESM::Creature>();
|
MWWorld::LiveCellRef<ESM::Creature> *ref = mPtr.get<ESM::Creature>();
|
||||||
if(ref->mBase->mFlags & ESM::Creature::Bipedal)
|
if(ref->mBase->mFlags & ESM::Creature::Bipedal)
|
||||||
inject = InjectType::ModelWithFallback;
|
{
|
||||||
|
defaultSkeleton = "meshes\\xbase_anim.nif";
|
||||||
|
inject = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inject = true;
|
||||||
|
MWWorld::LiveCellRef<ESM::NPC> *ref = mPtr.get<ESM::NPC>();
|
||||||
|
if (!ref->mBase->mModel.empty())
|
||||||
|
{
|
||||||
|
// If NPC has a custom animation model attached, we should inject bones from default skeleton for given race and gender as well
|
||||||
|
// Since it is a quite rare case, there should not be a noticable performance loss
|
||||||
|
// Note: consider that player and werewolves have no custom animation files attached for now
|
||||||
|
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||||
|
const ESM::Race *race = store.get<ESM::Race>().find(ref->mBase->mRace);
|
||||||
|
|
||||||
|
bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0;
|
||||||
|
bool isFemale = !ref->mBase->isMale();
|
||||||
|
|
||||||
|
defaultSkeleton = SceneUtil::getActorSkeleton(false, isFemale, isBeast, false);
|
||||||
|
defaultSkeleton = Misc::ResourceHelpers::correctActorModelPath(defaultSkeleton, mResourceSystem->getVFS());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!forceskeleton)
|
if (!forceskeleton)
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::Node> created = getModelInstance(mResourceSystem, model, baseonly, inject);
|
osg::ref_ptr<osg::Node> created = getModelInstance(mResourceSystem, model, baseonly, inject, defaultSkeleton);
|
||||||
mInsert->addChild(created);
|
mInsert->addChild(created);
|
||||||
mObjectRoot = created->asGroup();
|
mObjectRoot = created->asGroup();
|
||||||
if (!mObjectRoot)
|
if (!mObjectRoot)
|
||||||
|
@ -1501,7 +1529,7 @@ namespace MWRender
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::Node> created = getModelInstance(mResourceSystem, model, baseonly, inject);
|
osg::ref_ptr<osg::Node> created = getModelInstance(mResourceSystem, model, baseonly, inject, defaultSkeleton);
|
||||||
osg::ref_ptr<SceneUtil::Skeleton> skel = dynamic_cast<SceneUtil::Skeleton*>(created.get());
|
osg::ref_ptr<SceneUtil::Skeleton> skel = dynamic_cast<SceneUtil::Skeleton*>(created.get());
|
||||||
if (!skel)
|
if (!skel)
|
||||||
{
|
{
|
||||||
|
|
|
@ -48,7 +48,6 @@ namespace MWRender
|
||||||
mAnimation(nullptr),
|
mAnimation(nullptr),
|
||||||
mFirstPersonView(true),
|
mFirstPersonView(true),
|
||||||
mPreviewMode(false),
|
mPreviewMode(false),
|
||||||
mFreeLook(true),
|
|
||||||
mNearest(30.f),
|
mNearest(30.f),
|
||||||
mFurthest(800.f),
|
mFurthest(800.f),
|
||||||
mIsNearest(false),
|
mIsNearest(false),
|
||||||
|
@ -393,11 +392,6 @@ namespace MWRender
|
||||||
camera = focal + offset;
|
camera = focal + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Camera::togglePlayerLooking(bool enable)
|
|
||||||
{
|
|
||||||
mFreeLook = enable;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Camera::isVanityOrPreviewModeEnabled()
|
bool Camera::isVanityOrPreviewModeEnabled()
|
||||||
{
|
{
|
||||||
return mPreviewMode || mVanity.enabled;
|
return mPreviewMode || mVanity.enabled;
|
||||||
|
|
|
@ -37,7 +37,6 @@ namespace MWRender
|
||||||
|
|
||||||
bool mFirstPersonView;
|
bool mFirstPersonView;
|
||||||
bool mPreviewMode;
|
bool mPreviewMode;
|
||||||
bool mFreeLook;
|
|
||||||
float mNearest;
|
float mNearest;
|
||||||
float mFurthest;
|
float mFurthest;
|
||||||
bool mIsNearest;
|
bool mIsNearest;
|
||||||
|
@ -119,8 +118,6 @@ namespace MWRender
|
||||||
/// Stores focal and camera world positions in passed arguments
|
/// Stores focal and camera world positions in passed arguments
|
||||||
void getPosition(osg::Vec3f &focal, osg::Vec3f &camera);
|
void getPosition(osg::Vec3f &focal, osg::Vec3f &camera);
|
||||||
|
|
||||||
void togglePlayerLooking(bool enable);
|
|
||||||
|
|
||||||
bool isVanityOrPreviewModeEnabled();
|
bool isVanityOrPreviewModeEnabled();
|
||||||
|
|
||||||
bool isNearest();
|
bool isNearest();
|
||||||
|
|
|
@ -1353,11 +1353,6 @@ namespace MWRender
|
||||||
mCamera->allowVanityMode(allow);
|
mCamera->allowVanityMode(allow);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingManager::togglePlayerLooking(bool enable)
|
|
||||||
{
|
|
||||||
mCamera->togglePlayerLooking(enable);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RenderingManager::changeVanityModeScale(float factor)
|
void RenderingManager::changeVanityModeScale(float factor)
|
||||||
{
|
{
|
||||||
if(mCamera->isVanityOrPreviewModeEnabled())
|
if(mCamera->isVanityOrPreviewModeEnabled())
|
||||||
|
|
|
@ -208,7 +208,6 @@ namespace MWRender
|
||||||
void togglePreviewMode(bool enable);
|
void togglePreviewMode(bool enable);
|
||||||
bool toggleVanityMode(bool enable);
|
bool toggleVanityMode(bool enable);
|
||||||
void allowVanityMode(bool allow);
|
void allowVanityMode(bool allow);
|
||||||
void togglePlayerLooking(bool enable);
|
|
||||||
void changeVanityModeScale(float factor);
|
void changeVanityModeScale(float factor);
|
||||||
|
|
||||||
/// temporarily override the field of view with given value.
|
/// temporarily override the field of view with given value.
|
||||||
|
|
|
@ -186,14 +186,7 @@ namespace MWScript
|
||||||
virtual void execute (Interpreter::Runtime& runtime)
|
virtual void execute (Interpreter::Runtime& runtime)
|
||||||
{
|
{
|
||||||
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
|
runtime.push(MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr));
|
||||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
|
||||||
|
|
||||||
bool stanceOn = stats.getStance(MWMechanics::CreatureStats::Stance_Sneak);
|
|
||||||
bool sneaking = MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr);
|
|
||||||
bool inair = !world->isOnGround(ptr) && !world->isSwimming(ptr) && !world->isFlying(ptr);
|
|
||||||
|
|
||||||
runtime.push(stanceOn && (sneaking || inair));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -188,13 +188,7 @@ namespace MWScript
|
||||||
// This is done when using Lock in scripts, but not when using Lock spells.
|
// This is done when using Lock in scripts, but not when using Lock spells.
|
||||||
if (ptr.getTypeName() == typeid(ESM::Door).name() && !ptr.getCellRef().getTeleport())
|
if (ptr.getTypeName() == typeid(ESM::Door).name() && !ptr.getCellRef().getTeleport())
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWorld()->activateDoor(ptr, 0);
|
MWBase::Environment::get().getWorld()->activateDoor(ptr, MWWorld::DoorState::Idle);
|
||||||
|
|
||||||
float xr = ptr.getCellRef().getPosition().rot[0];
|
|
||||||
float yr = ptr.getCellRef().getPosition().rot[1];
|
|
||||||
float zr = ptr.getCellRef().getPosition().rot[2];
|
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->rotateObject(ptr, xr, yr, zr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -798,7 +798,7 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname
|
||||||
if(alGetError() == AL_NO_ERROR)
|
if(alGetError() == AL_NO_ERROR)
|
||||||
Log(Debug::Info) << "Standard Reverb supported";
|
Log(Debug::Info) << "Standard Reverb supported";
|
||||||
}
|
}
|
||||||
EFXEAXREVERBPROPERTIES props = EFX_REVERB_PRESET_GENERIC;
|
EFXEAXREVERBPROPERTIES props = EFX_REVERB_PRESET_LIVINGROOM;
|
||||||
props.flGain = 0.0f;
|
props.flGain = 0.0f;
|
||||||
LoadEffect(mDefaultEffect, props);
|
LoadEffect(mDefaultEffect, props);
|
||||||
}
|
}
|
||||||
|
|
|
@ -460,12 +460,12 @@ namespace MWWorld
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Class::getDoorState (const MWWorld::ConstPtr &ptr) const
|
MWWorld::DoorState Class::getDoorState (const MWWorld::ConstPtr &ptr) const
|
||||||
{
|
{
|
||||||
throw std::runtime_error("this is not a door");
|
throw std::runtime_error("this is not a door");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Class::setDoorState (const MWWorld::Ptr &ptr, int state) const
|
void Class::setDoorState (const MWWorld::Ptr &ptr, MWWorld::DoorState state) const
|
||||||
{
|
{
|
||||||
throw std::runtime_error("this is not a door");
|
throw std::runtime_error("this is not a door");
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <osg/Vec4f>
|
#include <osg/Vec4f>
|
||||||
|
|
||||||
#include "ptr.hpp"
|
#include "ptr.hpp"
|
||||||
|
#include "doorstate.hpp"
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
|
@ -350,10 +351,9 @@ namespace MWWorld
|
||||||
|
|
||||||
virtual bool isClass(const MWWorld::ConstPtr& ptr, const std::string &className) const;
|
virtual bool isClass(const MWWorld::ConstPtr& ptr, const std::string &className) const;
|
||||||
|
|
||||||
/// 0 = nothing, 1 = opening, 2 = closing
|
virtual DoorState getDoorState (const MWWorld::ConstPtr &ptr) const;
|
||||||
virtual int getDoorState (const MWWorld::ConstPtr &ptr) const;
|
|
||||||
/// This does not actually cause the door to move. Use World::activateDoor instead.
|
/// This does not actually cause the door to move. Use World::activateDoor instead.
|
||||||
virtual void setDoorState (const MWWorld::Ptr &ptr, int state) const;
|
virtual void setDoorState (const MWWorld::Ptr &ptr, DoorState state) const;
|
||||||
|
|
||||||
virtual void respawn (const MWWorld::Ptr& ptr) const {}
|
virtual void respawn (const MWWorld::Ptr& ptr) const {}
|
||||||
|
|
||||||
|
|
14
apps/openmw/mwworld/doorstate.hpp
Normal file
14
apps/openmw/mwworld/doorstate.hpp
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef GAME_MWWORLD_DOORSTATE_H
|
||||||
|
#define GAME_MWWORLD_DOORSTATE_H
|
||||||
|
|
||||||
|
namespace MWWorld
|
||||||
|
{
|
||||||
|
enum class DoorState
|
||||||
|
{
|
||||||
|
Idle = 0,
|
||||||
|
Opening = 1,
|
||||||
|
Closing = 2,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -1458,6 +1458,9 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
mRendering->rotateObject(ptr, rotate);
|
mRendering->rotateObject(ptr, rotate);
|
||||||
mPhysics->updateRotation(ptr);
|
mPhysics->updateRotation(ptr);
|
||||||
|
|
||||||
|
if (const auto object = mPhysics->getObject(ptr))
|
||||||
|
updateNavigatorObject(object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1614,9 +1617,48 @@ namespace MWWorld
|
||||||
return result.mHit;
|
return result.mHit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool World::rotateDoor(const Ptr door, MWWorld::DoorState state, float duration)
|
||||||
|
{
|
||||||
|
const ESM::Position& objPos = door.getRefData().getPosition();
|
||||||
|
float oldRot = objPos.rot[2];
|
||||||
|
|
||||||
|
float minRot = door.getCellRef().getPosition().rot[2];
|
||||||
|
float maxRot = minRot + osg::DegreesToRadians(90.f);
|
||||||
|
|
||||||
|
float diff = duration * osg::DegreesToRadians(90.f);
|
||||||
|
float targetRot = std::min(std::max(minRot, oldRot + diff * (state == MWWorld::DoorState::Opening ? 1 : -1)), maxRot);
|
||||||
|
rotateObject(door, objPos.rot[0], objPos.rot[1], targetRot);
|
||||||
|
|
||||||
|
bool reached = (targetRot == maxRot && state != MWWorld::DoorState::Idle) || targetRot == minRot;
|
||||||
|
|
||||||
|
/// \todo should use convexSweepTest here
|
||||||
|
std::vector<MWWorld::Ptr> collisions = mPhysics->getCollisions(door, MWPhysics::CollisionType_Door, MWPhysics::CollisionType_Actor);
|
||||||
|
for (MWWorld::Ptr& ptr : collisions)
|
||||||
|
{
|
||||||
|
if (ptr.getClass().isActor())
|
||||||
|
{
|
||||||
|
// Collided with actor, ask actor to try to avoid door
|
||||||
|
if(ptr != getPlayerPtr() )
|
||||||
|
{
|
||||||
|
MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence();
|
||||||
|
if(seq.getTypeId() != MWMechanics::AiPackage::TypeIdAvoidDoor) //Only add it once
|
||||||
|
seq.stack(MWMechanics::AiAvoidDoor(door),ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// we need to undo the rotation
|
||||||
|
rotateObject(door, objPos.rot[0], objPos.rot[1], oldRot);
|
||||||
|
reached = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the rotation order we want to use
|
||||||
|
mWorldScene->updateObjectRotation(door, false);
|
||||||
|
return reached;
|
||||||
|
}
|
||||||
|
|
||||||
void World::processDoors(float duration)
|
void World::processDoors(float duration)
|
||||||
{
|
{
|
||||||
std::map<MWWorld::Ptr, int>::iterator it = mDoorStates.begin();
|
auto it = mDoorStates.begin();
|
||||||
while (it != mDoorStates.end())
|
while (it != mDoorStates.end())
|
||||||
{
|
{
|
||||||
if (!mWorldScene->isCellActive(*it->first.getCell()) || !it->first.getRefData().getBaseNode())
|
if (!mWorldScene->isCellActive(*it->first.getCell()) || !it->first.getRefData().getBaseNode())
|
||||||
|
@ -1628,45 +1670,12 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const ESM::Position& objPos = it->first.getRefData().getPosition();
|
bool reached = rotateDoor(it->first, it->second, duration);
|
||||||
float oldRot = objPos.rot[2];
|
|
||||||
|
|
||||||
float minRot = it->first.getCellRef().getPosition().rot[2];
|
|
||||||
float maxRot = minRot + osg::DegreesToRadians(90.f);
|
|
||||||
|
|
||||||
float diff = duration * osg::DegreesToRadians(90.f);
|
|
||||||
float targetRot = std::min(std::max(minRot, oldRot + diff * (it->second == 1 ? 1 : -1)), maxRot);
|
|
||||||
rotateObject(it->first, objPos.rot[0], objPos.rot[1], targetRot);
|
|
||||||
|
|
||||||
bool reached = (targetRot == maxRot && it->second) || targetRot == minRot;
|
|
||||||
|
|
||||||
/// \todo should use convexSweepTest here
|
|
||||||
std::vector<MWWorld::Ptr> collisions = mPhysics->getCollisions(it->first, MWPhysics::CollisionType_Door, MWPhysics::CollisionType_Actor);
|
|
||||||
for (MWWorld::Ptr& ptr : collisions)
|
|
||||||
{
|
|
||||||
if (ptr.getClass().isActor())
|
|
||||||
{
|
|
||||||
// Collided with actor, ask actor to try to avoid door
|
|
||||||
if(ptr != getPlayerPtr() )
|
|
||||||
{
|
|
||||||
MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence();
|
|
||||||
if(seq.getTypeId() != MWMechanics::AiPackage::TypeIdAvoidDoor) //Only add it once
|
|
||||||
seq.stack(MWMechanics::AiAvoidDoor(it->first),ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// we need to undo the rotation
|
|
||||||
rotateObject(it->first, objPos.rot[0], objPos.rot[1], oldRot);
|
|
||||||
reached = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// the rotation order we want to use
|
|
||||||
mWorldScene->updateObjectRotation(it->first, false);
|
|
||||||
|
|
||||||
if (reached)
|
if (reached)
|
||||||
{
|
{
|
||||||
// Mark as non-moving
|
// Mark as non-moving
|
||||||
it->first.getClass().setDoorState(it->first, 0);
|
it->first.getClass().setDoorState(it->first, MWWorld::DoorState::Idle);
|
||||||
mDoorStates.erase(it++);
|
mDoorStates.erase(it++);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2389,11 +2398,6 @@ namespace MWWorld
|
||||||
mRendering->allowVanityMode(allow);
|
mRendering->allowVanityMode(allow);
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::togglePlayerLooking(bool enable)
|
|
||||||
{
|
|
||||||
mRendering->togglePlayerLooking(enable);
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::changeVanityModeScale(float factor)
|
void World::changeVanityModeScale(float factor)
|
||||||
{
|
{
|
||||||
mRendering->changeVanityModeScale(factor);
|
mRendering->changeVanityModeScale(factor);
|
||||||
|
@ -2506,33 +2510,36 @@ namespace MWWorld
|
||||||
|
|
||||||
void World::activateDoor(const MWWorld::Ptr& door)
|
void World::activateDoor(const MWWorld::Ptr& door)
|
||||||
{
|
{
|
||||||
int state = door.getClass().getDoorState(door);
|
auto state = door.getClass().getDoorState(door);
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case 0:
|
case MWWorld::DoorState::Idle:
|
||||||
if (door.getRefData().getPosition().rot[2] == door.getCellRef().getPosition().rot[2])
|
if (door.getRefData().getPosition().rot[2] == door.getCellRef().getPosition().rot[2])
|
||||||
state = 1; // if closed, then open
|
state = MWWorld::DoorState::Opening; // if closed, then open
|
||||||
else
|
else
|
||||||
state = 2; // if open, then close
|
state = MWWorld::DoorState::Closing; // if open, then close
|
||||||
break;
|
break;
|
||||||
case 2:
|
case MWWorld::DoorState::Closing:
|
||||||
state = 1; // if closing, then open
|
state = MWWorld::DoorState::Opening; // if closing, then open
|
||||||
break;
|
break;
|
||||||
case 1:
|
case MWWorld::DoorState::Opening:
|
||||||
default:
|
default:
|
||||||
state = 2; // if opening, then close
|
state = MWWorld::DoorState::Closing; // if opening, then close
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
door.getClass().setDoorState(door, state);
|
door.getClass().setDoorState(door, state);
|
||||||
mDoorStates[door] = state;
|
mDoorStates[door] = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::activateDoor(const Ptr &door, int state)
|
void World::activateDoor(const Ptr &door, MWWorld::DoorState state)
|
||||||
{
|
{
|
||||||
door.getClass().setDoorState(door, state);
|
door.getClass().setDoorState(door, state);
|
||||||
mDoorStates[door] = state;
|
mDoorStates[door] = state;
|
||||||
if (state == 0)
|
if (state == MWWorld::DoorState::Idle)
|
||||||
|
{
|
||||||
mDoorStates.erase(door);
|
mDoorStates.erase(door);
|
||||||
|
rotateDoor(door, state, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool World::getPlayerStandingOn (const MWWorld::ConstPtr& object)
|
bool World::getPlayerStandingOn (const MWWorld::ConstPtr& object)
|
||||||
|
|
|
@ -118,7 +118,7 @@ namespace MWWorld
|
||||||
|
|
||||||
int mActivationDistanceOverride;
|
int mActivationDistanceOverride;
|
||||||
|
|
||||||
std::map<MWWorld::Ptr, int> mDoorStates;
|
std::map<MWWorld::Ptr, MWWorld::DoorState> mDoorStates;
|
||||||
///< only holds doors that are currently moving. 1 = opening, 2 = closing
|
///< only holds doors that are currently moving. 1 = opening, 2 = closing
|
||||||
|
|
||||||
std::string mStartCell;
|
std::string mStartCell;
|
||||||
|
@ -146,6 +146,8 @@ namespace MWWorld
|
||||||
private:
|
private:
|
||||||
void PCDropped (const Ptr& item);
|
void PCDropped (const Ptr& item);
|
||||||
|
|
||||||
|
bool rotateDoor(const Ptr door, DoorState state, float duration);
|
||||||
|
|
||||||
void processDoors(float duration);
|
void processDoors(float duration);
|
||||||
///< Run physics simulation and modify \a world accordingly.
|
///< Run physics simulation and modify \a world accordingly.
|
||||||
|
|
||||||
|
@ -526,8 +528,6 @@ namespace MWWorld
|
||||||
|
|
||||||
void allowVanityMode(bool allow) override;
|
void allowVanityMode(bool allow) override;
|
||||||
|
|
||||||
void togglePlayerLooking(bool enable) override;
|
|
||||||
|
|
||||||
void changeVanityModeScale(float factor) override;
|
void changeVanityModeScale(float factor) override;
|
||||||
|
|
||||||
bool vanityRotateCamera(float * rot) override;
|
bool vanityRotateCamera(float * rot) override;
|
||||||
|
@ -542,7 +542,7 @@ namespace MWWorld
|
||||||
/// update movement state of a non-teleport door as specified
|
/// update movement state of a non-teleport door as specified
|
||||||
/// @param state see MWClass::setDoorState
|
/// @param state see MWClass::setDoorState
|
||||||
/// @note throws an exception when invoked on a teleport door
|
/// @note throws an exception when invoked on a teleport door
|
||||||
void activateDoor(const MWWorld::Ptr& door, int state) override;
|
void activateDoor(const MWWorld::Ptr& door, MWWorld::DoorState state) override;
|
||||||
|
|
||||||
void getActorsStandingOn (const MWWorld::ConstPtr& object, std::vector<MWWorld::Ptr> &actors) override; ///< get a list of actors standing on \a object
|
void getActorsStandingOn (const MWWorld::ConstPtr& object, std::vector<MWWorld::Ptr> &actors) override; ///< get a list of actors standing on \a object
|
||||||
bool getPlayerStandingOn (const MWWorld::ConstPtr& object) override; ///< @return true if the player is standing on \a object
|
bool getPlayerStandingOn (const MWWorld::ConstPtr& object) override; ///< @return true if the player is standing on \a object
|
||||||
|
|
|
@ -163,22 +163,23 @@ void NiPixelData::read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
fmt = (Format)nif->getUInt();
|
fmt = (Format)nif->getUInt();
|
||||||
|
|
||||||
rmask = nif->getInt(); // usually 0xff
|
rmask = nif->getUInt(); // usually 0xff
|
||||||
gmask = nif->getInt(); // usually 0xff00
|
gmask = nif->getUInt(); // usually 0xff00
|
||||||
bmask = nif->getInt(); // usually 0xff0000
|
bmask = nif->getUInt(); // usually 0xff0000
|
||||||
amask = nif->getInt(); // usually 0xff000000 or zero
|
amask = nif->getUInt(); // usually 0xff000000 or zero
|
||||||
|
|
||||||
bpp = nif->getInt();
|
bpp = nif->getUInt();
|
||||||
|
|
||||||
// Unknown
|
// 8 bytes of "Old Fast Compare". Whatever that means.
|
||||||
nif->skip(12);
|
nif->skip(8);
|
||||||
|
palette.read(nif);
|
||||||
|
|
||||||
numberOfMipmaps = nif->getInt();
|
numberOfMipmaps = nif->getUInt();
|
||||||
|
|
||||||
// Bytes per pixel, should be bpp * 8
|
// Bytes per pixel, should be bpp * 8
|
||||||
/* int bytes = */ nif->getInt();
|
/* int bytes = */ nif->getUInt();
|
||||||
|
|
||||||
for(int i=0; i<numberOfMipmaps; i++)
|
for(unsigned int i=0; i<numberOfMipmaps; i++)
|
||||||
{
|
{
|
||||||
// Image size and offset in the following data field
|
// Image size and offset in the following data field
|
||||||
Mipmap m;
|
Mipmap m;
|
||||||
|
@ -189,12 +190,17 @@ void NiPixelData::read(NIFStream *nif)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the data
|
// Read the data
|
||||||
unsigned int dataSize = nif->getInt();
|
unsigned int dataSize = nif->getUInt();
|
||||||
data.reserve(dataSize);
|
data.reserve(dataSize);
|
||||||
for (unsigned i=0; i<dataSize; ++i)
|
for (unsigned i=0; i<dataSize; ++i)
|
||||||
data.push_back((unsigned char)nif->getChar());
|
data.push_back((unsigned char)nif->getChar());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NiPixelData::post(NIFFile *nif)
|
||||||
|
{
|
||||||
|
palette.post(nif);
|
||||||
|
}
|
||||||
|
|
||||||
void NiColorData::read(NIFStream *nif)
|
void NiColorData::read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
mKeyMap = std::make_shared<Vector4KeyMap>();
|
mKeyMap = std::make_shared<Vector4KeyMap>();
|
||||||
|
@ -278,4 +284,14 @@ void NiKeyframeData::read(NIFStream *nif)
|
||||||
mScales->read(nif);
|
mScales->read(nif);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NiPalette::read(NIFStream *nif)
|
||||||
|
{
|
||||||
|
unsigned int alphaMask = !nif->getChar() ? 0xFF000000 : 0;
|
||||||
|
// Fill the entire palette with black even if there isn't enough entries.
|
||||||
|
colors.resize(256);
|
||||||
|
unsigned int numEntries = nif->getUInt();
|
||||||
|
for (unsigned int i = 0; i < numEntries; i++)
|
||||||
|
colors[i] = nif->getUInt() | alphaMask;
|
||||||
|
}
|
||||||
|
|
||||||
} // Namespace
|
} // Namespace
|
||||||
|
|
|
@ -116,6 +116,7 @@ public:
|
||||||
NIPXFMT_RGB8,
|
NIPXFMT_RGB8,
|
||||||
NIPXFMT_RGBA8,
|
NIPXFMT_RGBA8,
|
||||||
NIPXFMT_PAL8,
|
NIPXFMT_PAL8,
|
||||||
|
NIPXFMT_PALA8,
|
||||||
NIPXFMT_DXT1,
|
NIPXFMT_DXT1,
|
||||||
NIPXFMT_DXT3,
|
NIPXFMT_DXT3,
|
||||||
NIPXFMT_DXT5,
|
NIPXFMT_DXT5,
|
||||||
|
@ -123,8 +124,10 @@ public:
|
||||||
};
|
};
|
||||||
Format fmt;
|
Format fmt;
|
||||||
|
|
||||||
unsigned int rmask, gmask, bmask, amask;
|
unsigned int rmask, gmask, bmask, amask, bpp;
|
||||||
int bpp, numberOfMipmaps;
|
|
||||||
|
NiPalettePtr palette;
|
||||||
|
unsigned int numberOfMipmaps;
|
||||||
|
|
||||||
struct Mipmap
|
struct Mipmap
|
||||||
{
|
{
|
||||||
|
@ -136,6 +139,7 @@ public:
|
||||||
std::vector<unsigned char> data;
|
std::vector<unsigned char> data;
|
||||||
|
|
||||||
void read(NIFStream *nif);
|
void read(NIFStream *nif);
|
||||||
|
void post(NIFFile *nif);
|
||||||
};
|
};
|
||||||
|
|
||||||
class NiColorData : public Record
|
class NiColorData : public Record
|
||||||
|
@ -219,5 +223,14 @@ struct NiKeyframeData : public Record
|
||||||
void read(NIFStream *nif);
|
void read(NIFStream *nif);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class NiPalette : public Record
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// 32-bit RGBA colors that correspond to 8-bit indices
|
||||||
|
std::vector<unsigned int> colors;
|
||||||
|
|
||||||
|
void read(NIFStream *nif);
|
||||||
|
};
|
||||||
|
|
||||||
} // Namespace
|
} // Namespace
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -112,6 +112,7 @@ static std::map<std::string,RecordFactoryEntry> makeFactory()
|
||||||
newFactory.insert(makeEntry("NiSourceTexture", &construct <NiSourceTexture> , RC_NiSourceTexture ));
|
newFactory.insert(makeEntry("NiSourceTexture", &construct <NiSourceTexture> , RC_NiSourceTexture ));
|
||||||
newFactory.insert(makeEntry("NiSkinInstance", &construct <NiSkinInstance> , RC_NiSkinInstance ));
|
newFactory.insert(makeEntry("NiSkinInstance", &construct <NiSkinInstance> , RC_NiSkinInstance ));
|
||||||
newFactory.insert(makeEntry("NiLookAtController", &construct <NiLookAtController> , RC_NiLookAtController ));
|
newFactory.insert(makeEntry("NiLookAtController", &construct <NiLookAtController> , RC_NiLookAtController ));
|
||||||
|
newFactory.insert(makeEntry("NiPalette", &construct <NiPalette> , RC_NiPalette ));
|
||||||
return newFactory;
|
return newFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,7 +97,8 @@ enum RecordType
|
||||||
RC_NiSkinInstance,
|
RC_NiSkinInstance,
|
||||||
RC_RootCollisionNode,
|
RC_RootCollisionNode,
|
||||||
RC_NiSphericalCollider,
|
RC_NiSphericalCollider,
|
||||||
RC_NiLookAtController
|
RC_NiLookAtController,
|
||||||
|
RC_NiPalette
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Base class for all records
|
/// Base class for all records
|
||||||
|
|
|
@ -140,6 +140,7 @@ class NiSkinInstance;
|
||||||
class NiSourceTexture;
|
class NiSourceTexture;
|
||||||
class NiRotatingParticlesData;
|
class NiRotatingParticlesData;
|
||||||
class NiAutoNormalParticlesData;
|
class NiAutoNormalParticlesData;
|
||||||
|
class NiPalette;
|
||||||
|
|
||||||
typedef RecordPtrT<Node> NodePtr;
|
typedef RecordPtrT<Node> NodePtr;
|
||||||
typedef RecordPtrT<Extra> ExtraPtr;
|
typedef RecordPtrT<Extra> ExtraPtr;
|
||||||
|
@ -160,6 +161,7 @@ typedef RecordPtrT<NiSkinInstance> NiSkinInstancePtr;
|
||||||
typedef RecordPtrT<NiSourceTexture> NiSourceTexturePtr;
|
typedef RecordPtrT<NiSourceTexture> NiSourceTexturePtr;
|
||||||
typedef RecordPtrT<NiRotatingParticlesData> NiRotatingParticlesDataPtr;
|
typedef RecordPtrT<NiRotatingParticlesData> NiRotatingParticlesDataPtr;
|
||||||
typedef RecordPtrT<NiAutoNormalParticlesData> NiAutoNormalParticlesDataPtr;
|
typedef RecordPtrT<NiAutoNormalParticlesData> NiAutoNormalParticlesDataPtr;
|
||||||
|
typedef RecordPtrT<NiPalette> NiPalettePtr;
|
||||||
|
|
||||||
typedef RecordListT<Node> NodeList;
|
typedef RecordListT<Node> NodeList;
|
||||||
typedef RecordListT<Property> PropertyList;
|
typedef RecordListT<Property> PropertyList;
|
||||||
|
|
|
@ -408,8 +408,8 @@ namespace NifOsg
|
||||||
unsigned int clamp = static_cast<unsigned int>(textureEffect->clamp);
|
unsigned int clamp = static_cast<unsigned int>(textureEffect->clamp);
|
||||||
int wrapT = (clamp) & 0x1;
|
int wrapT = (clamp) & 0x1;
|
||||||
int wrapS = (clamp >> 1) & 0x1;
|
int wrapS = (clamp >> 1) & 0x1;
|
||||||
texture2d->setWrap(osg::Texture::WRAP_S, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP);
|
texture2d->setWrap(osg::Texture::WRAP_S, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP_TO_EDGE);
|
||||||
texture2d->setWrap(osg::Texture::WRAP_T, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP);
|
texture2d->setWrap(osg::Texture::WRAP_T, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP_TO_EDGE);
|
||||||
|
|
||||||
osg::ref_ptr<osg::TexEnvCombine> texEnv = new osg::TexEnvCombine;
|
osg::ref_ptr<osg::TexEnvCombine> texEnv = new osg::TexEnvCombine;
|
||||||
texEnv->setCombine_Alpha(osg::TexEnvCombine::REPLACE);
|
texEnv->setCombine_Alpha(osg::TexEnvCombine::REPLACE);
|
||||||
|
@ -777,8 +777,8 @@ namespace NifOsg
|
||||||
|
|
||||||
// inherit wrap settings from the target slot
|
// inherit wrap settings from the target slot
|
||||||
osg::Texture2D* inherit = dynamic_cast<osg::Texture2D*>(stateset->getTextureAttribute(flipctrl->mTexSlot, osg::StateAttribute::TEXTURE));
|
osg::Texture2D* inherit = dynamic_cast<osg::Texture2D*>(stateset->getTextureAttribute(flipctrl->mTexSlot, osg::StateAttribute::TEXTURE));
|
||||||
osg::Texture2D::WrapMode wrapS = osg::Texture2D::CLAMP;
|
osg::Texture2D::WrapMode wrapS = osg::Texture2D::CLAMP_TO_EDGE;
|
||||||
osg::Texture2D::WrapMode wrapT = osg::Texture2D::CLAMP;
|
osg::Texture2D::WrapMode wrapT = osg::Texture2D::CLAMP_TO_EDGE;
|
||||||
if (inherit)
|
if (inherit)
|
||||||
{
|
{
|
||||||
wrapS = inherit->getWrap(osg::Texture2D::WRAP_S);
|
wrapS = inherit->getWrap(osg::Texture2D::WRAP_S);
|
||||||
|
@ -1072,6 +1072,8 @@ namespace NifOsg
|
||||||
if (nifNode->recType == Nif::RC_NiTriShape)
|
if (nifNode->recType == Nif::RC_NiTriShape)
|
||||||
{
|
{
|
||||||
const Nif::NiTriShape* triShape = static_cast<const Nif::NiTriShape*>(nifNode);
|
const Nif::NiTriShape* triShape = static_cast<const Nif::NiTriShape*>(nifNode);
|
||||||
|
if (!triShape->data.empty())
|
||||||
|
{
|
||||||
const Nif::NiTriShapeData* data = triShape->data.getPtr();
|
const Nif::NiTriShapeData* data = triShape->data.getPtr();
|
||||||
vertexColorsPresent = !data->colors.empty();
|
vertexColorsPresent = !data->colors.empty();
|
||||||
triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triShape->name);
|
triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triShape->name);
|
||||||
|
@ -1079,9 +1081,12 @@ namespace NifOsg
|
||||||
geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, data->triangles.size(),
|
geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, data->triangles.size(),
|
||||||
(unsigned short*)data->triangles.data()));
|
(unsigned short*)data->triangles.data()));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const Nif::NiTriStrips* triStrips = static_cast<const Nif::NiTriStrips*>(nifNode);
|
const Nif::NiTriStrips* triStrips = static_cast<const Nif::NiTriStrips*>(nifNode);
|
||||||
|
if (!triStrips->data.empty())
|
||||||
|
{
|
||||||
const Nif::NiTriStripsData* data = triStrips->data.getPtr();
|
const Nif::NiTriStripsData* data = triStrips->data.getPtr();
|
||||||
vertexColorsPresent = !data->colors.empty();
|
vertexColorsPresent = !data->colors.empty();
|
||||||
triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triStrips->name);
|
triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triStrips->name);
|
||||||
|
@ -1097,6 +1102,7 @@ namespace NifOsg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// osg::Material properties are handled here for two reasons:
|
// osg::Material properties are handled here for two reasons:
|
||||||
// - if there are no vertex colors, we need to disable colorMode.
|
// - if there are no vertex colors, we need to disable colorMode.
|
||||||
|
@ -1276,9 +1282,11 @@ namespace NifOsg
|
||||||
switch (pixelData->fmt)
|
switch (pixelData->fmt)
|
||||||
{
|
{
|
||||||
case Nif::NiPixelData::NIPXFMT_RGB8:
|
case Nif::NiPixelData::NIPXFMT_RGB8:
|
||||||
|
case Nif::NiPixelData::NIPXFMT_PAL8:
|
||||||
pixelformat = GL_RGB;
|
pixelformat = GL_RGB;
|
||||||
break;
|
break;
|
||||||
case Nif::NiPixelData::NIPXFMT_RGBA8:
|
case Nif::NiPixelData::NIPXFMT_RGBA8:
|
||||||
|
case Nif::NiPixelData::NIPXFMT_PALA8:
|
||||||
pixelformat = GL_RGBA;
|
pixelformat = GL_RGBA;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -1293,7 +1301,7 @@ namespace NifOsg
|
||||||
int height = 0;
|
int height = 0;
|
||||||
|
|
||||||
std::vector<unsigned int> mipmapVector;
|
std::vector<unsigned int> mipmapVector;
|
||||||
for (unsigned int i=0; i<pixelData->mipmaps.size()-3; ++i)
|
for (unsigned int i=0; i<pixelData->mipmaps.size(); ++i)
|
||||||
{
|
{
|
||||||
const Nif::NiPixelData::Mipmap& mip = pixelData->mipmaps[i];
|
const Nif::NiPixelData::Mipmap& mip = pixelData->mipmaps[i];
|
||||||
|
|
||||||
|
@ -1319,10 +1327,59 @@ namespace NifOsg
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char* data = new unsigned char[pixelData->data.size()];
|
const std::vector<unsigned char>& pixels = pixelData->data;
|
||||||
memcpy(data, pixelData->data.data(), pixelData->data.size());
|
switch (pixelData->fmt)
|
||||||
|
{
|
||||||
|
case Nif::NiPixelData::NIPXFMT_RGB8:
|
||||||
|
case Nif::NiPixelData::NIPXFMT_RGBA8:
|
||||||
|
{
|
||||||
|
unsigned char* data = new unsigned char[pixels.size()];
|
||||||
|
memcpy(data, pixels.data(), pixels.size());
|
||||||
image->setImage(width, height, 1, pixelformat, pixelformat, GL_UNSIGNED_BYTE, data, osg::Image::USE_NEW_DELETE);
|
image->setImage(width, height, 1, pixelformat, pixelformat, GL_UNSIGNED_BYTE, data, osg::Image::USE_NEW_DELETE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Nif::NiPixelData::NIPXFMT_PAL8:
|
||||||
|
case Nif::NiPixelData::NIPXFMT_PALA8:
|
||||||
|
{
|
||||||
|
if (pixelData->palette.empty() || pixelData->bpp != 8)
|
||||||
|
{
|
||||||
|
Log(Debug::Info) << "Palettized texture in " << mFilename << " is invalid, ignoring";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
// We're going to convert the indices that pixel data contains
|
||||||
|
// into real colors using the palette.
|
||||||
|
const std::vector<unsigned int>& palette = pixelData->palette->colors;
|
||||||
|
if (pixelData->fmt == Nif::NiPixelData::NIPXFMT_PAL8)
|
||||||
|
{
|
||||||
|
unsigned char* data = new unsigned char[pixels.size() * 3];
|
||||||
|
for (size_t i = 0; i < pixels.size(); i++)
|
||||||
|
{
|
||||||
|
unsigned int color = palette[pixels[i]];
|
||||||
|
data[i * 3 + 0] = (color >> 0) & 0xFF;
|
||||||
|
data[i * 3 + 1] = (color >> 8) & 0xFF;
|
||||||
|
data[i * 3 + 2] = (color >> 16) & 0xFF;
|
||||||
|
}
|
||||||
|
image->setImage(width, height, 1, pixelformat, pixelformat, GL_UNSIGNED_BYTE, data, osg::Image::USE_NEW_DELETE);
|
||||||
|
}
|
||||||
|
else // if (fmt = NIPXFMT_PALA8)
|
||||||
|
{
|
||||||
|
unsigned char* data = new unsigned char[pixels.size() * 4];
|
||||||
|
for (size_t i = 0; i < pixels.size(); i++)
|
||||||
|
{
|
||||||
|
unsigned int color = palette[pixels[i]];
|
||||||
|
data[i * 4 + 0] = (color >> 0) & 0xFF;
|
||||||
|
data[i * 4 + 1] = (color >> 8) & 0xFF;
|
||||||
|
data[i * 4 + 2] = (color >> 16) & 0xFF;
|
||||||
|
data[i * 4 + 3] = (color >> 24) & 0xFF;
|
||||||
|
}
|
||||||
|
image->setImage(width, height, 1, pixelformat, pixelformat, GL_UNSIGNED_BYTE, data, osg::Image::USE_NEW_DELETE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
image->setMipmapLevels(mipmapVector);
|
image->setMipmapLevels(mipmapVector);
|
||||||
image->flipVertical();
|
image->flipVertical();
|
||||||
|
|
||||||
|
@ -1392,8 +1449,8 @@ namespace NifOsg
|
||||||
int wrapT = (clamp) & 0x1;
|
int wrapT = (clamp) & 0x1;
|
||||||
int wrapS = (clamp >> 1) & 0x1;
|
int wrapS = (clamp >> 1) & 0x1;
|
||||||
|
|
||||||
texture2d->setWrap(osg::Texture::WRAP_S, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP);
|
texture2d->setWrap(osg::Texture::WRAP_S, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP_TO_EDGE);
|
||||||
texture2d->setWrap(osg::Texture::WRAP_T, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP);
|
texture2d->setWrap(osg::Texture::WRAP_T, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP_TO_EDGE);
|
||||||
|
|
||||||
int texUnit = boundTextures.size();
|
int texUnit = boundTextures.size();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue