mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-07-10 07:51:35 +00:00
Add OpenMW commits up to 5 Sep 2019
# Conflicts: # apps/openmw/mwgui/container.cpp # apps/openmw/mwmechanics/actors.cpp # apps/openmw/mwworld/worldimp.hpp
This commit is contained in:
commit
ca67587b89
37 changed files with 287 additions and 192 deletions
|
@ -86,6 +86,7 @@ Programmers
|
||||||
Jacob Essex (Yacoby)
|
Jacob Essex (Yacoby)
|
||||||
Jake Westrip (16bitint)
|
Jake Westrip (16bitint)
|
||||||
James Carty (MrTopCat)
|
James Carty (MrTopCat)
|
||||||
|
James Stephens (james-h-stephens)
|
||||||
Jan-Peter Nilsson (peppe)
|
Jan-Peter Nilsson (peppe)
|
||||||
Jan Borsodi (am0s)
|
Jan Borsodi (am0s)
|
||||||
Jason Hooks (jhooks)
|
Jason Hooks (jhooks)
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
Bug #3894: Hostile spell effects not detected/present on first frame of OnPCHitMe
|
Bug #3894: Hostile spell effects not detected/present on first frame of OnPCHitMe
|
||||||
Bug #4202: Open .omwaddon files without needing toopen openmw-cs first
|
Bug #4202: Open .omwaddon files without needing toopen openmw-cs first
|
||||||
Bug #4240: Ash storm origin coordinates and hand shielding animation behavior are incorrect
|
Bug #4240: Ash storm origin coordinates and hand shielding animation behavior are incorrect
|
||||||
|
Bug #4270: Closing doors while they are obstructed desyncs closing sfx
|
||||||
Bug #4276: Resizing character window differs from vanilla
|
Bug #4276: Resizing character window differs from vanilla
|
||||||
Bug #4329: Removed birthsign abilities are restored after reloading the save
|
Bug #4329: Removed birthsign abilities are restored after reloading the save
|
||||||
Bug #4341: Error message about missing GDB is too vague
|
Bug #4341: Error message about missing GDB is too vague
|
||||||
|
@ -27,6 +28,7 @@
|
||||||
Bug #4540: Rain delay when exiting water
|
Bug #4540: Rain delay when exiting water
|
||||||
Bug #4600: Crash when no sound output is available or --no-sound is used.
|
Bug #4600: Crash when no sound output is available or --no-sound is used.
|
||||||
Bug #4639: Black screen after completing first mages guild mission + training
|
Bug #4639: Black screen after completing first mages guild mission + training
|
||||||
|
Bug #4650: Focus is lost after pressing ESC in confirmation dialog inside savegame dialog
|
||||||
Bug #4701: PrisonMarker record is not hardcoded like other markers
|
Bug #4701: PrisonMarker record is not hardcoded like other markers
|
||||||
Bug #4703: Editor: it's possible to preview levelled list records
|
Bug #4703: Editor: it's possible to preview levelled list records
|
||||||
Bug #4705: Editor: unable to open exterior cell views from Instances table
|
Bug #4705: Editor: unable to open exterior cell views from Instances table
|
||||||
|
@ -128,12 +130,13 @@
|
||||||
Bug #5106: Still can jump even when encumbered
|
Bug #5106: Still can jump even when encumbered
|
||||||
Bug #5110: ModRegion with a redundant numerical argument breaks script execution
|
Bug #5110: ModRegion with a redundant numerical argument breaks script execution
|
||||||
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 #5113: Unknown alchemy question mark not centered
|
||||||
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 #5126: Swimming creatures without RunForward animations are motionless during combat
|
||||||
Bug #5134: Doors rotation by "Lock" console command is inconsistent
|
Bug #5134: Doors rotation by "Lock" console command is inconsistent
|
||||||
Bug #5126: Swimming creatures without RunForward animations are motionless during combat
|
|
||||||
Bug #5137: Textures with Clamp Mode set to Clamp instead of Wrap are too dark outside the boundaries
|
Bug #5137: Textures with Clamp Mode set to Clamp instead of Wrap are too dark outside the boundaries
|
||||||
|
Bug #5149: Failing lock pick attempts isn't always a crime
|
||||||
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
|
||||||
|
@ -177,6 +180,8 @@
|
||||||
Feature #5122: Use magic glow for enchanted arrows
|
Feature #5122: Use magic glow for enchanted arrows
|
||||||
Feature #5131: Custom skeleton bones
|
Feature #5131: Custom skeleton bones
|
||||||
Feature #5132: Unique animations for different weapon types
|
Feature #5132: Unique animations for different weapon types
|
||||||
|
Feature #5146: Safe Dispose corpse
|
||||||
|
Feature #5147: Show spell magicka cost in spell buying window
|
||||||
Task #4686: Upgrade media decoder to a more current FFmpeg API
|
Task #4686: Upgrade media decoder to a more current FFmpeg API
|
||||||
Task #4695: Optimize Distant Terrain memory consumption
|
Task #4695: Optimize Distant Terrain memory consumption
|
||||||
Task #4789: Optimize cell transitions
|
Task #4789: Optimize cell transitions
|
||||||
|
|
|
@ -153,8 +153,8 @@ namespace MWBase
|
||||||
/// @param container The container the item is in; may be empty for an item in the world
|
/// @param container The container the item is in; may be empty for an item in the world
|
||||||
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container,
|
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container,
|
||||||
int count, bool alarm = true) = 0;
|
int count, bool alarm = true) = 0;
|
||||||
/// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so
|
/// Utility to check if unlocking this object is illegal and calling commitCrime if so
|
||||||
virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item) = 0;
|
virtual void unlockAttempted (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item) = 0;
|
||||||
/// Attempt sleeping in a bed. If this is illegal, call commitCrime.
|
/// Attempt sleeping in a bed. If this is illegal, call commitCrime.
|
||||||
/// @return was it illegal, and someone saw you doing it?
|
/// @return was it illegal, and someone saw you doing it?
|
||||||
virtual bool sleepInBed (const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed) = 0;
|
virtual bool sleepInBed (const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed) = 0;
|
||||||
|
@ -247,6 +247,8 @@ namespace MWBase
|
||||||
|
|
||||||
virtual float getActorsProcessingRange() const = 0;
|
virtual float getActorsProcessingRange() const = 0;
|
||||||
|
|
||||||
|
virtual void notifyDied(const MWWorld::Ptr& actor) = 0;
|
||||||
|
|
||||||
virtual bool onOpen(const MWWorld::Ptr& ptr) = 0;
|
virtual bool onOpen(const MWWorld::Ptr& ptr) = 0;
|
||||||
virtual void onClose(const MWWorld::Ptr& ptr) = 0;
|
virtual void onClose(const MWWorld::Ptr& ptr) = 0;
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
@ -571,14 +572,14 @@ 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;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Start of tes3mp addition
|
Start of tes3mp addition
|
||||||
|
|
||||||
Useful self-contained method for saving door states
|
Useful self-contained method for saving door states
|
||||||
*/
|
*/
|
||||||
virtual void saveDoorState(const MWWorld::Ptr& door, int state) = 0;
|
virtual void saveDoorState(const MWWorld::Ptr& door, MWWorld::DoorState state) = 0;
|
||||||
/*
|
/*
|
||||||
End of tes3mp addition
|
End of tes3mp addition
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -46,7 +46,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;
|
||||||
|
|
||||||
|
@ -83,7 +83,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);
|
||||||
}
|
}
|
||||||
|
@ -265,12 +265,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)
|
||||||
|
@ -429,20 +429,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");
|
||||||
|
@ -460,7 +460,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
|
||||||
|
@ -473,7 +473,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)
|
||||||
|
|
|
@ -40,14 +40,13 @@ namespace MWGui
|
||||||
|
|
||||||
bool ConfirmationDialog::exit()
|
bool ConfirmationDialog::exit()
|
||||||
{
|
{
|
||||||
|
setVisible(false);
|
||||||
eventCancelClicked();
|
eventCancelClicked();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfirmationDialog::onCancelButtonClicked(MyGUI::Widget* _sender)
|
void ConfirmationDialog::onCancelButtonClicked(MyGUI::Widget* _sender)
|
||||||
{
|
{
|
||||||
setVisible(false);
|
|
||||||
|
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,12 +22,15 @@
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
#include "../mwbase/scriptmanager.hpp"
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/inventorystore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
|
||||||
#include "../mwmechanics/creaturestats.hpp"
|
#include "../mwmechanics/creaturestats.hpp"
|
||||||
|
|
||||||
|
#include "../mwscript/interpretercontext.hpp"
|
||||||
|
|
||||||
#include "countdialog.hpp"
|
#include "countdialog.hpp"
|
||||||
#include "inventorywindow.hpp"
|
#include "inventorywindow.hpp"
|
||||||
|
|
||||||
|
@ -384,23 +387,46 @@ namespace MWGui
|
||||||
|
|
||||||
if (mPtr.getClass().isPersistent(mPtr))
|
if (mPtr.getClass().isPersistent(mPtr))
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sDisposeCorpseFail}");
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sDisposeCorpseFail}");
|
||||||
/*
|
|
||||||
Start of tes3mp change (major)
|
|
||||||
|
|
||||||
Instead of deleting the corpse on this client, simply send an ID_OBJECT_DELETE
|
|
||||||
packet to the server as a request for the deletion
|
|
||||||
*/
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
Start of tes3mp change (major)
|
||||||
|
|
||||||
|
Instead of deleting the corpse on this client, increasing the death count and
|
||||||
|
running the dead actor's sccript, simply send an ID_OBJECT_DELETE packet to the server
|
||||||
|
as a request for the deletion
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
MWMechanics::CreatureStats& creatureStats = mPtr.getClass().getCreatureStats(mPtr);
|
||||||
|
|
||||||
|
// If we dispose corpse before end of death animation, we should update death counter counter manually.
|
||||||
|
// Also we should run actor's script - it may react on actor's death.
|
||||||
|
if (creatureStats.isDead() && !creatureStats.isDeathAnimationFinished())
|
||||||
|
{
|
||||||
|
creatureStats.setDeathAnimationFinished(true);
|
||||||
|
MWBase::Environment::get().getMechanicsManager()->notifyDied(mPtr);
|
||||||
|
|
||||||
|
const std::string script = mPtr.getClass().getScript(mPtr);
|
||||||
|
if (!script.empty() && MWBase::Environment::get().getWorld()->getScriptsEnabled())
|
||||||
|
{
|
||||||
|
MWScript::InterpreterContext interpreterContext (&mPtr.getRefData().getLocals(), mPtr);
|
||||||
|
MWBase::Environment::get().getScriptManager()->run (script, interpreterContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MWBase::Environment::get().getWorld()->deleteObject(mPtr);
|
||||||
|
*/
|
||||||
|
|
||||||
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
|
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
|
||||||
objectList->reset();
|
objectList->reset();
|
||||||
objectList->packetOrigin = mwmp::CLIENT_GAMEPLAY;
|
objectList->packetOrigin = mwmp::CLIENT_GAMEPLAY;
|
||||||
objectList->addObjectDelete(mPtr);
|
objectList->addObjectDelete(mPtr);
|
||||||
objectList->sendObjectDelete();
|
objectList->sendObjectDelete();
|
||||||
|
/*
|
||||||
|
End of tes3mp change (major)
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
End of tes3mp change (major)
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,7 @@ namespace MWGui
|
||||||
toAdd->eventMouseWheel += MyGUI::newDelegate(this, &SpellBuyingWindow::onMouseWheel);
|
toAdd->eventMouseWheel += MyGUI::newDelegate(this, &SpellBuyingWindow::onMouseWheel);
|
||||||
toAdd->setUserString("ToolTipType", "Spell");
|
toAdd->setUserString("ToolTipType", "Spell");
|
||||||
toAdd->setUserString("Spell", spell.mId);
|
toAdd->setUserString("Spell", spell.mId);
|
||||||
|
toAdd->setUserString("SpellCost", std::to_string(spell.mData.mCost));
|
||||||
toAdd->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellBuyingWindow::onSpellButtonClick);
|
toAdd->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellBuyingWindow::onSpellButtonClick);
|
||||||
mSpellsWidgetMap.insert(std::make_pair (toAdd, spell.mId));
|
mSpellsWidgetMap.insert(std::make_pair (toAdd, spell.mId));
|
||||||
}
|
}
|
||||||
|
|
|
@ -249,6 +249,9 @@ namespace MWGui
|
||||||
int school = MWMechanics::getSpellSchool(spell, player);
|
int school = MWMechanics::getSpellSchool(spell, player);
|
||||||
info.text = "#{sSchool}: " + sSchoolNames[school];
|
info.text = "#{sSchool}: " + sSchoolNames[school];
|
||||||
}
|
}
|
||||||
|
std::string cost = focus->getUserString("SpellCost");
|
||||||
|
if (cost != "" && cost != "0")
|
||||||
|
info.text += MWGui::ToolTips::getValueString(spell->mData.mCost, "#{sCastCost}");
|
||||||
info.effects = effects;
|
info.effects = effects;
|
||||||
tooltipSize = createToolTip(info);
|
tooltipSize = createToolTip(info);
|
||||||
}
|
}
|
||||||
|
|
|
@ -375,7 +375,8 @@ namespace MWGui
|
||||||
if (!mEffectParams.mKnown)
|
if (!mEffectParams.mKnown)
|
||||||
{
|
{
|
||||||
mTextWidget->setCaption ("?");
|
mTextWidget->setCaption ("?");
|
||||||
mRequestedWidth = mTextWidget->getTextSize().width + 24;
|
mTextWidget->setCoord(sIconOffset / 2, mTextWidget->getCoord().top, mTextWidget->getCoord().width, mTextWidget->getCoord().height); // Compensates for the missing image when effect is not known
|
||||||
|
mRequestedWidth = mTextWidget->getTextSize().width + sIconOffset;
|
||||||
mImageWidget->setImageTexture ("");
|
mImageWidget->setImageTexture ("");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -466,7 +467,7 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
|
|
||||||
mTextWidget->setCaptionWithReplacing(spellLine);
|
mTextWidget->setCaptionWithReplacing(spellLine);
|
||||||
mRequestedWidth = mTextWidget->getTextSize().width + 24;
|
mRequestedWidth = mTextWidget->getTextSize().width + sIconOffset;
|
||||||
|
|
||||||
mImageWidget->setImageTexture(MWBase::Environment::get().getWindowManager()->correctIconPath(magicEffect->mIcon));
|
mImageWidget->setImageTexture(MWBase::Environment::get().getWindowManager()->correctIconPath(magicEffect->mIcon));
|
||||||
}
|
}
|
||||||
|
|
|
@ -268,6 +268,7 @@ namespace MWGui
|
||||||
virtual void initialiseOverride();
|
virtual void initialiseOverride();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static const int sIconOffset = 24;
|
||||||
|
|
||||||
void updateWidgets();
|
void updateWidgets();
|
||||||
|
|
||||||
|
|
|
@ -215,6 +215,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;
|
||||||
|
|
||||||
|
@ -242,13 +247,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)
|
||||||
|
@ -399,9 +401,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;
|
||||||
|
@ -419,8 +418,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 ();
|
||||||
|
@ -1025,9 +1023,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.
|
||||||
|
@ -1068,9 +1066,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.
|
||||||
|
@ -1169,37 +1165,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()->exitCurrentModal();
|
MWBase::Environment::get().getWindowManager()->toggleConsole();
|
||||||
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() {
|
||||||
|
@ -1611,7 +1589,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;
|
||||||
|
@ -1692,7 +1669,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";
|
||||||
|
@ -1830,7 +1806,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);
|
||||||
|
@ -1863,7 +1838,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
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1830,6 +1830,43 @@ namespace MWMechanics
|
||||||
updateCombatMusic();
|
updateCombatMusic();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Actors::notifyDied(const MWWorld::Ptr &actor)
|
||||||
|
{
|
||||||
|
actor.getClass().getCreatureStats(actor).notifyDied();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Start of tes3mp change (major)
|
||||||
|
|
||||||
|
Only increment death count for an actor if we are its authority, to avoid
|
||||||
|
situations where we increment it locally after having already received an
|
||||||
|
ID_WORLD_KILL_COUNT packet about it
|
||||||
|
*/
|
||||||
|
bool isLocalActor = mwmp::Main::get().getCellController()->isLocalActor(actor);
|
||||||
|
|
||||||
|
if (isLocalActor)
|
||||||
|
++mDeathCount[Misc::StringUtils::lowerCase(actor.getCellRef().getRefId())];
|
||||||
|
/*
|
||||||
|
End of tes3mp change (major)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
Send an ID_WORLD_KILL_COUNT packet every time the kill count changes,
|
||||||
|
as long as we are the authority over the actor's cell
|
||||||
|
*/
|
||||||
|
if (isLocalActor)
|
||||||
|
{
|
||||||
|
std::string refId = Misc::StringUtils::lowerCase(actor.getCellRef().getRefId());
|
||||||
|
int number = mDeathCount[refId];
|
||||||
|
|
||||||
|
mwmp::Main::get().getLocalPlayer()->sendKill(refId, number);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
End of tes3mp addition
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
void Actors::killDeadActors()
|
void Actors::killDeadActors()
|
||||||
{
|
{
|
||||||
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||||
|
@ -1873,39 +1910,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
else if (killResult == CharacterController::Result_DeathAnimJustFinished)
|
else if (killResult == CharacterController::Result_DeathAnimJustFinished)
|
||||||
{
|
{
|
||||||
iter->first.getClass().getCreatureStats(iter->first).notifyDied();
|
notifyDied(iter->first);
|
||||||
|
|
||||||
/*
|
|
||||||
Start of tes3mp change (major)
|
|
||||||
|
|
||||||
Only increment death count for an actor if we are its authority, to avoid
|
|
||||||
situations where we increment it locally after having already received an
|
|
||||||
ID_WORLD_KILL_COUNT packet about it
|
|
||||||
*/
|
|
||||||
bool isLocalActor = mwmp::Main::get().getCellController()->isLocalActor(iter->first);
|
|
||||||
|
|
||||||
if (isLocalActor)
|
|
||||||
++mDeathCount[Misc::StringUtils::lowerCase(iter->first.getCellRef().getRefId())];
|
|
||||||
/*
|
|
||||||
End of tes3mp change (major)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Start of tes3mp addition
|
|
||||||
|
|
||||||
Send an ID_WORLD_KILL_COUNT packet every time the kill count changes,
|
|
||||||
as long as we are the authority over the actor's cell
|
|
||||||
*/
|
|
||||||
if (isLocalActor)
|
|
||||||
{
|
|
||||||
std::string refId = Misc::StringUtils::lowerCase(iter->first.getCellRef().getRefId());
|
|
||||||
int number = mDeathCount[refId];
|
|
||||||
|
|
||||||
mwmp::Main::get().getLocalPlayer()->sendKill(refId, number);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
End of tes3mp addition
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Reset magic effects and recalculate derived effects
|
// Reset magic effects and recalculate derived effects
|
||||||
// One case where we need this is to make sure bound items are removed upon death
|
// One case where we need this is to make sure bound items are removed upon death
|
||||||
|
|
|
@ -71,6 +71,8 @@ namespace MWMechanics
|
||||||
PtrActorMap::const_iterator begin() { return mActors.begin(); }
|
PtrActorMap::const_iterator begin() { return mActors.begin(); }
|
||||||
PtrActorMap::const_iterator end() { return mActors.end(); }
|
PtrActorMap::const_iterator end() { return mActors.end(); }
|
||||||
|
|
||||||
|
void notifyDied(const MWWorld::Ptr &actor);
|
||||||
|
|
||||||
/// Check if the target actor was detected by an observer
|
/// Check if the target actor was detected by an observer
|
||||||
/// If the observer is a non-NPC, check all actors in AI processing distance as observers
|
/// If the observer is a non-NPC, check all actors in AI processing distance as observers
|
||||||
bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer);
|
bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer);
|
||||||
|
|
|
@ -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 ))
|
||||||
{
|
{
|
||||||
|
|
|
@ -2721,11 +2721,15 @@ void CharacterController::updateMagicEffects()
|
||||||
if (!mPtr.getClass().isActor())
|
if (!mPtr.getClass().isActor())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool vampire = mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Vampirism).getMagnitude() > 0.0f;
|
|
||||||
mAnimation->setVampire(vampire);
|
|
||||||
|
|
||||||
float light = mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Light).getMagnitude();
|
float light = mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Light).getMagnitude();
|
||||||
mAnimation->setLightEffect(light);
|
mAnimation->setLightEffect(light);
|
||||||
|
|
||||||
|
// If you're dead you don't care about whether you've started/stopped being a vampire or not
|
||||||
|
if (mPtr.getClass().getCreatureStats(mPtr).isDead())
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool vampire = mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Vampirism).getMagnitude() > 0.0f;
|
||||||
|
mAnimation->setVampire(vampire);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterController::setVisibility(float visibility)
|
void CharacterController::setVisibility(float visibility)
|
||||||
|
|
|
@ -468,6 +468,11 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MechanicsManager::notifyDied(const MWWorld::Ptr& actor)
|
||||||
|
{
|
||||||
|
mActors.notifyDied(actor);
|
||||||
|
}
|
||||||
|
|
||||||
float MechanicsManager::getActorsProcessingRange() const
|
float MechanicsManager::getActorsProcessingRange() const
|
||||||
{
|
{
|
||||||
return mActors.getProcessingRange();
|
return mActors.getProcessingRange();
|
||||||
|
@ -1091,7 +1096,7 @@ namespace MWMechanics
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MechanicsManager::objectOpened(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item)
|
void MechanicsManager::unlockAttempted(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item)
|
||||||
{
|
{
|
||||||
MWWorld::Ptr victim;
|
MWWorld::Ptr victim;
|
||||||
if (isAllowedToUse(ptr, item, victim))
|
if (isAllowedToUse(ptr, item, victim))
|
||||||
|
|
|
@ -152,8 +152,8 @@ namespace MWMechanics
|
||||||
/// @param container The container the item is in; may be empty for an item in the world
|
/// @param container The container the item is in; may be empty for an item in the world
|
||||||
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container,
|
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container,
|
||||||
int count, bool alarm = true) override;
|
int count, bool alarm = true) override;
|
||||||
/// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so
|
/// Utility to check if unlocking this object is illegal and calling commitCrime if so
|
||||||
virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item) override;
|
virtual void unlockAttempted (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item) override;
|
||||||
/// Attempt sleeping in a bed. If this is illegal, call commitCrime.
|
/// Attempt sleeping in a bed. If this is illegal, call commitCrime.
|
||||||
/// @return was it illegal, and someone saw you doing it? Also returns fail when enemies are nearby
|
/// @return was it illegal, and someone saw you doing it? Also returns fail when enemies are nearby
|
||||||
virtual bool sleepInBed (const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed) override;
|
virtual bool sleepInBed (const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed) override;
|
||||||
|
@ -221,6 +221,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
virtual float getActorsProcessingRange() const override;
|
virtual float getActorsProcessingRange() const override;
|
||||||
|
|
||||||
|
virtual void notifyDied(const MWWorld::Ptr& actor) override;
|
||||||
|
|
||||||
/// Check if the target actor was detected by an observer
|
/// Check if the target actor was detected by an observer
|
||||||
/// If the observer is a non-NPC, check all actors in AI processing distance as observers
|
/// If the observer is a non-NPC, check all actors in AI processing distance as observers
|
||||||
virtual bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer) override;
|
virtual bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer) override;
|
||||||
|
|
|
@ -52,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;
|
||||||
|
|
|
@ -62,7 +62,6 @@ namespace MWMechanics
|
||||||
resultMessage = "#{sLockImpossible}";
|
resultMessage = "#{sLockImpossible}";
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, lock);
|
|
||||||
if (Misc::Rng::roll0to99() <= x)
|
if (Misc::Rng::roll0to99() <= x)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -98,6 +97,7 @@ namespace MWMechanics
|
||||||
resultMessage = "#{sLockFail}";
|
resultMessage = "#{sLockFail}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MWBase::Environment::get().getMechanicsManager()->unlockAttempted(mActor, lock);
|
||||||
int uses = lockpick.getClass().getItemHealth(lockpick);
|
int uses = lockpick.getClass().getItemHealth(lockpick);
|
||||||
--uses;
|
--uses;
|
||||||
lockpick.getCellRef().setCharge(uses);
|
lockpick.getCellRef().setCharge(uses);
|
||||||
|
@ -127,7 +127,6 @@ namespace MWMechanics
|
||||||
resultMessage = "#{sTrapImpossible}";
|
resultMessage = "#{sTrapImpossible}";
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, trap);
|
|
||||||
if (Misc::Rng::roll0to99() <= x)
|
if (Misc::Rng::roll0to99() <= x)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -163,6 +162,7 @@ namespace MWMechanics
|
||||||
resultMessage = "#{sTrapFail}";
|
resultMessage = "#{sTrapFail}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MWBase::Environment::get().getMechanicsManager()->unlockAttempted(mActor, trap);
|
||||||
int uses = probe.getClass().getItemHealth(probe);
|
int uses = probe.getClass().getItemHealth(probe);
|
||||||
--uses;
|
--uses;
|
||||||
probe.getCellRef().setCharge(uses);
|
probe.getCellRef().setCharge(uses);
|
||||||
|
|
|
@ -790,9 +790,6 @@ namespace MWMechanics
|
||||||
if (target.getCellRef().getLockLevel() > 0)
|
if (target.getCellRef().getLockLevel() > 0)
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock", 1.f, 1.f);
|
MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock", 1.f, 1.f);
|
||||||
if (!caster.isEmpty())
|
|
||||||
MWBase::Environment::get().getMechanicsManager()->objectOpened(getPlayer(), target);
|
|
||||||
// Use the player instead of the caster for vanilla crime compatibility
|
|
||||||
|
|
||||||
if (caster == getPlayer())
|
if (caster == getPlayer())
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicOpenSuccess}");
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicOpenSuccess}");
|
||||||
|
@ -825,6 +822,10 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock Fail", 1.f, 1.f);
|
MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock Fail", 1.f, 1.f);
|
||||||
|
|
||||||
|
if (!caster.isEmpty())
|
||||||
|
MWBase::Environment::get().getMechanicsManager()->unlockAttempted(getPlayer(), target);
|
||||||
|
// Use the player instead of the caster for vanilla crime compatibility
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
#include "../mwbase/scriptmanager.hpp"
|
||||||
#include "../mwbase/soundmanager.hpp"
|
#include "../mwbase/soundmanager.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
|
||||||
|
@ -26,6 +27,8 @@
|
||||||
|
|
||||||
#include "../mwrender/animation.hpp"
|
#include "../mwrender/animation.hpp"
|
||||||
|
|
||||||
|
#include "../mwscript/interpretercontext.hpp"
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/containerstore.hpp"
|
#include "../mwworld/containerstore.hpp"
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
@ -483,6 +486,28 @@ void ObjectList::deleteObjects(MWWorld::CellStore* cellStore)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Is this a dying actor being deleted before its death animation has finished? If so,
|
||||||
|
// increase the death count for the actor if applicable and run the actor's script,
|
||||||
|
// which is the same as what happens in OpenMW's ContainerWindow::onDisposeCorpseButtonClicked()
|
||||||
|
// if an actor's corpse is disposed of before its death animation is finished
|
||||||
|
if (ptrFound.getClass().isActor())
|
||||||
|
{
|
||||||
|
MWMechanics::CreatureStats& creatureStats = ptrFound.getClass().getCreatureStats(ptrFound);
|
||||||
|
|
||||||
|
if (creatureStats.isDead() && !creatureStats.isDeathAnimationFinished())
|
||||||
|
{
|
||||||
|
creatureStats.setDeathAnimationFinished(true);
|
||||||
|
MWBase::Environment::get().getMechanicsManager()->notifyDied(ptrFound);
|
||||||
|
|
||||||
|
const std::string script = ptrFound.getClass().getScript(ptrFound);
|
||||||
|
if (!script.empty() && MWBase::Environment::get().getWorld()->getScriptsEnabled())
|
||||||
|
{
|
||||||
|
MWScript::InterpreterContext interpreterContext(&ptrFound.getRefData().getLocals(), ptrFound);
|
||||||
|
MWBase::Environment::get().getScriptManager()->run(script, interpreterContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->deleteObject(ptrFound);
|
MWBase::Environment::get().getWorld()->deleteObject(ptrFound);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -646,8 +671,10 @@ void ObjectList::activateDoors(MWWorld::CellStore* cellStore)
|
||||||
LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Found %s %i-%i", ptrFound.getCellRef().getRefId().c_str(),
|
LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Found %s %i-%i", ptrFound.getCellRef().getRefId().c_str(),
|
||||||
ptrFound.getCellRef().getRefNum(), ptrFound.getCellRef().getMpNum());
|
ptrFound.getCellRef().getRefNum(), ptrFound.getCellRef().getMpNum());
|
||||||
|
|
||||||
ptrFound.getClass().setDoorState(ptrFound, baseObject.doorState);
|
MWWorld::DoorState doorState = static_cast<MWWorld::DoorState>(baseObject.doorState);
|
||||||
MWBase::Environment::get().getWorld()->saveDoorState(ptrFound, baseObject.doorState);
|
|
||||||
|
ptrFound.getClass().setDoorState(ptrFound, doorState);
|
||||||
|
MWBase::Environment::get().getWorld()->saveDoorState(ptrFound, doorState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1054,7 +1081,7 @@ void ObjectList::addObjectAnimPlay(const MWWorld::Ptr& ptr, std::string group, i
|
||||||
addObject(baseObject);
|
addObject(baseObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectList::addDoorState(const MWWorld::Ptr& ptr, int state)
|
void ObjectList::addDoorState(const MWWorld::Ptr& ptr, MWWorld::DoorState state)
|
||||||
{
|
{
|
||||||
cell = *ptr.getCell()->getCell();
|
cell = *ptr.getCell()->getCell();
|
||||||
|
|
||||||
|
@ -1062,7 +1089,7 @@ void ObjectList::addDoorState(const MWWorld::Ptr& ptr, int state)
|
||||||
baseObject.refId = ptr.getCellRef().getRefId();
|
baseObject.refId = ptr.getCellRef().getRefId();
|
||||||
baseObject.refNum = ptr.getCellRef().getRefNum().mIndex;
|
baseObject.refNum = ptr.getCellRef().getRefNum().mIndex;
|
||||||
baseObject.mpNum = ptr.getCellRef().getMpNum();
|
baseObject.mpNum = ptr.getCellRef().getMpNum();
|
||||||
baseObject.doorState = state;
|
baseObject.doorState = static_cast<int>(state);
|
||||||
addObject(baseObject);
|
addObject(baseObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#define OPENMW_OBJECTLIST_HPP
|
#define OPENMW_OBJECTLIST_HPP
|
||||||
|
|
||||||
#include <components/openmw-mp/Base/BaseObject.hpp>
|
#include <components/openmw-mp/Base/BaseObject.hpp>
|
||||||
#include "../mwworld/cellstore.hpp"
|
#include "../mwworld/worldimp.hpp"
|
||||||
#include <RakNetTypes.h>
|
#include <RakNetTypes.h>
|
||||||
|
|
||||||
namespace mwmp
|
namespace mwmp
|
||||||
|
@ -61,7 +61,7 @@ namespace mwmp
|
||||||
void addObjectState(const MWWorld::Ptr& ptr, bool objectState);
|
void addObjectState(const MWWorld::Ptr& ptr, bool objectState);
|
||||||
void addObjectAnimPlay(const MWWorld::Ptr& ptr, std::string group, int mode);
|
void addObjectAnimPlay(const MWWorld::Ptr& ptr, std::string group, int mode);
|
||||||
|
|
||||||
void addDoorState(const MWWorld::Ptr& ptr, int state);
|
void addDoorState(const MWWorld::Ptr& ptr, MWWorld::DoorState state);
|
||||||
void addMusicPlay(std::string filename);
|
void addMusicPlay(std::string filename);
|
||||||
void addVideoPlay(std::string filename, bool allowSkipping);
|
void addVideoPlay(std::string filename, bool allowSkipping);
|
||||||
void addScriptLocalShort(const MWWorld::Ptr& ptr, int index, int shortVal);
|
void addScriptLocalShort(const MWWorld::Ptr& ptr, int index, int shortVal);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -247,7 +247,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -473,12 +473,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
|
||||||
{
|
{
|
||||||
|
@ -361,10 +362,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
|
|
@ -1847,7 +1847,7 @@ namespace MWWorld
|
||||||
return result.mHit;
|
return result.mHit;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool World::rotateDoor(const Ptr door, int state, float duration)
|
bool World::rotateDoor(const Ptr door, MWWorld::DoorState state, float duration)
|
||||||
{
|
{
|
||||||
const ESM::Position& objPos = door.getRefData().getPosition();
|
const ESM::Position& objPos = door.getRefData().getPosition();
|
||||||
float oldRot = objPos.rot[2];
|
float oldRot = objPos.rot[2];
|
||||||
|
@ -1856,17 +1856,20 @@ namespace MWWorld
|
||||||
float maxRot = minRot + osg::DegreesToRadians(90.f);
|
float maxRot = minRot + osg::DegreesToRadians(90.f);
|
||||||
|
|
||||||
float diff = duration * osg::DegreesToRadians(90.f);
|
float diff = duration * osg::DegreesToRadians(90.f);
|
||||||
float targetRot = std::min(std::max(minRot, oldRot + diff * (state == 1 ? 1 : -1)), maxRot);
|
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);
|
rotateObject(door, objPos.rot[0], objPos.rot[1], targetRot);
|
||||||
|
|
||||||
bool reached = (targetRot == maxRot && state) || targetRot == minRot;
|
bool reached = (targetRot == maxRot && state != MWWorld::DoorState::Idle) || targetRot == minRot;
|
||||||
|
|
||||||
/// \todo should use convexSweepTest here
|
/// \todo should use convexSweepTest here
|
||||||
|
bool collisionWithActor = false;
|
||||||
std::vector<MWWorld::Ptr> collisions = mPhysics->getCollisions(door, MWPhysics::CollisionType_Door, MWPhysics::CollisionType_Actor);
|
std::vector<MWWorld::Ptr> collisions = mPhysics->getCollisions(door, MWPhysics::CollisionType_Door, MWPhysics::CollisionType_Actor);
|
||||||
for (MWWorld::Ptr& ptr : collisions)
|
for (MWWorld::Ptr& ptr : collisions)
|
||||||
{
|
{
|
||||||
if (ptr.getClass().isActor())
|
if (ptr.getClass().isActor())
|
||||||
{
|
{
|
||||||
|
collisionWithActor = true;
|
||||||
|
|
||||||
// Collided with actor, ask actor to try to avoid door
|
// Collided with actor, ask actor to try to avoid door
|
||||||
if(ptr != getPlayerPtr() )
|
if(ptr != getPlayerPtr() )
|
||||||
{
|
{
|
||||||
|
@ -1881,6 +1884,25 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cancel door closing sound if collision with actor is detected
|
||||||
|
if (collisionWithActor)
|
||||||
|
{
|
||||||
|
const ESM::Door* ref = door.get<ESM::Door>()->mBase;
|
||||||
|
|
||||||
|
if (state == MWWorld::DoorState::Opening)
|
||||||
|
{
|
||||||
|
const std::string& openSound = ref->mOpenSound;
|
||||||
|
if (!openSound.empty() && MWBase::Environment::get().getSoundManager()->getSoundPlaying(door, openSound))
|
||||||
|
MWBase::Environment::get().getSoundManager()->stopSound3D(door, openSound);
|
||||||
|
}
|
||||||
|
else if (state == MWWorld::DoorState::Closing)
|
||||||
|
{
|
||||||
|
const std::string& closeSound = ref->mCloseSound;
|
||||||
|
if (!closeSound.empty() && MWBase::Environment::get().getSoundManager()->getSoundPlaying(door, closeSound))
|
||||||
|
MWBase::Environment::get().getSoundManager()->stopSound3D(door, closeSound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// the rotation order we want to use
|
// the rotation order we want to use
|
||||||
mWorldScene->updateObjectRotation(door, false);
|
mWorldScene->updateObjectRotation(door, false);
|
||||||
return reached;
|
return reached;
|
||||||
|
@ -1888,7 +1910,7 @@ namespace MWWorld
|
||||||
|
|
||||||
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())
|
||||||
|
@ -1905,7 +1927,7 @@ namespace MWWorld
|
||||||
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
|
||||||
|
@ -2802,21 +2824,21 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2838,7 +2860,7 @@ namespace MWWorld
|
||||||
mDoorStates[door] = state;
|
mDoorStates[door] = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::activateDoor(const Ptr &door, int state)
|
void World::activateDoor(const Ptr &door, MWWorld::DoorState state)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Start of tes3mp addition
|
Start of tes3mp addition
|
||||||
|
@ -2856,7 +2878,7 @@ namespace MWWorld
|
||||||
|
|
||||||
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);
|
rotateDoor(door, state, 1);
|
||||||
|
@ -2868,10 +2890,10 @@ namespace MWWorld
|
||||||
|
|
||||||
Allow the saving of door states without going through World::activateDoor()
|
Allow the saving of door states without going through World::activateDoor()
|
||||||
*/
|
*/
|
||||||
void World::saveDoorState(const Ptr &door, int state)
|
void World::saveDoorState(const Ptr &door, MWWorld::DoorState state)
|
||||||
{
|
{
|
||||||
mDoorStates[door] = state;
|
mDoorStates[door] = state;
|
||||||
if (state == 0)
|
if (state == MWWorld::DoorState::Idle)
|
||||||
mDoorStates.erase(door);
|
mDoorStates.erase(door);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -155,7 +155,7 @@ namespace MWWorld
|
||||||
void addContainerScripts(const Ptr& reference, CellStore* cell) override;
|
void addContainerScripts(const Ptr& reference, CellStore* cell) override;
|
||||||
void removeContainerScripts(const Ptr& reference) override;
|
void removeContainerScripts(const Ptr& reference) override;
|
||||||
private:
|
private:
|
||||||
bool rotateDoor(const Ptr door, int state, float duration);
|
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.
|
||||||
|
@ -680,14 +680,14 @@ 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;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Start of tes3mp addition
|
Start of tes3mp addition
|
||||||
|
|
||||||
Useful self-contained method for saving door states
|
Useful self-contained method for saving door states
|
||||||
*/
|
*/
|
||||||
void saveDoorState(const MWWorld::Ptr& door, int state) override;
|
void saveDoorState(const MWWorld::Ptr& door, MWWorld::DoorState state) override;
|
||||||
/*
|
/*
|
||||||
End of tes3mp addition
|
End of tes3mp addition
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1072,28 +1072,34 @@ 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);
|
||||||
const Nif::NiTriShapeData* data = triShape->data.getPtr();
|
if (!triShape->data.empty())
|
||||||
vertexColorsPresent = !data->colors.empty();
|
{
|
||||||
triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triShape->name);
|
const Nif::NiTriShapeData* data = triShape->data.getPtr();
|
||||||
if (!data->triangles.empty())
|
vertexColorsPresent = !data->colors.empty();
|
||||||
geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, data->triangles.size(),
|
triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triShape->name);
|
||||||
(unsigned short*)data->triangles.data()));
|
if (!data->triangles.empty())
|
||||||
|
geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, data->triangles.size(),
|
||||||
|
(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);
|
||||||
const Nif::NiTriStripsData* data = triStrips->data.getPtr();
|
if (!triStrips->data.empty())
|
||||||
vertexColorsPresent = !data->colors.empty();
|
|
||||||
triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triStrips->name);
|
|
||||||
if (!data->strips.empty())
|
|
||||||
{
|
{
|
||||||
for (const std::vector<unsigned short>& strip : data->strips)
|
const Nif::NiTriStripsData* data = triStrips->data.getPtr();
|
||||||
|
vertexColorsPresent = !data->colors.empty();
|
||||||
|
triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triStrips->name);
|
||||||
|
if (!data->strips.empty())
|
||||||
{
|
{
|
||||||
// Can't make a triangle from less than three vertices.
|
for (const std::vector<unsigned short>& strip : data->strips)
|
||||||
if (strip.size() < 3)
|
{
|
||||||
continue;
|
// Can't make a triangle from less than three vertices.
|
||||||
geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, strip.size(),
|
if (strip.size() < 3)
|
||||||
(unsigned short*)strip.data()));
|
continue;
|
||||||
|
geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, strip.size(),
|
||||||
|
(unsigned short*)strip.data()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,13 +72,10 @@ can loot during death animation
|
||||||
:Default: True
|
:Default: True
|
||||||
|
|
||||||
If this setting is true, the player is allowed to loot actors (e.g. summoned creatures) during death animation,
|
If this setting is true, the player is allowed to loot actors (e.g. summoned creatures) during death animation,
|
||||||
if they are not in combat. However disposing corpses during death animation is not recommended -
|
if they are not in combat. In this case we have to increment death counter and run disposed actor's script instantly.
|
||||||
death counter may not be incremented, and this behaviour can break quests.
|
|
||||||
This is how Morrowind behaves.
|
|
||||||
|
|
||||||
If this setting is false, player has to wait until end of death animation in all cases.
|
If this setting is false, player has to wait until end of death animation in all cases.
|
||||||
This case is more safe, but makes using of summoned creatures exploit
|
Makes using of summoned creatures exploit (looting summoned Dremoras and Golden Saints for expensive weapons) a lot harder.
|
||||||
(looting summoned Dremoras and Golden Saints for expensive weapons) a lot harder.
|
|
||||||
Conflicts with mannequin mods, which use SkipAnim to prevent end of death animation.
|
Conflicts with mannequin mods, which use SkipAnim to prevent end of death animation.
|
||||||
|
|
||||||
This setting can be toggled in Advanced tab of the launcher.
|
This setting can be toggled in Advanced tab of the launcher.
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="canLootDuringDeathAnimationCheckBox">
|
<widget class="QCheckBox" name="canLootDuringDeathAnimationCheckBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p>If this setting is true, the player is allowed to loot actors (e.g. summoned creatures) during death animation, if they are not in combat. However disposing corpses during death animation is not recommended - death counter may not be incremented, and this behaviour can break quests. This is how original Morrowind behaves.</p><p>If this setting is false, player has to wait until end of death animation in all cases. This case is more safe, but makes using of summoned creatures exploit (looting summoned Dremoras and Golden Saints for expensive weapons) a lot harder.</p></body></html></string>
|
<string><html><head/><body><p>If this setting is true, the player is allowed to loot actors (e.g. summoned creatures) during death animation, if they are not in combat. In this case we have to increment death counter and run disposed actor's script instantly.</p><p>If this setting is false, player has to wait until end of death animation in all cases. Makes using of summoned creatures exploit (looting summoned Dremoras and Golden Saints for expensive weapons) a lot harder. Conflicts with mannequin mods, which use SkipAnim to prevent end of death animation.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Can loot during death animation</string>
|
<string>Can loot during death animation</string>
|
||||||
|
|
Loading…
Reference in a new issue