1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-03-12 04:14:05 +00:00

Fix for bug #1080, can't read/repair/make potions/use soul gems/rest/sleep while in combat.

The radius for being in combat with the player is fAlarmDistance, which looked like the only pertinent thing.
This commit is contained in:
Thomas 2014-04-24 22:47:45 -04:00
parent 5b681e2199
commit f3272c941f
13 changed files with 114 additions and 25 deletions

View File

@ -161,9 +161,14 @@ namespace MWBase
virtual void getObjectsInRange (const Ogre::Vector3& position, float radius, std::vector<MWWorld::Ptr>& objects) = 0; virtual void getObjectsInRange (const Ogre::Vector3& position, float radius, std::vector<MWWorld::Ptr>& objects) = 0;
///return the list of actors which are following the given actor (ie AiFollow is active and the target is the actor) ///return the list of actors which are following the given actor
/**ie AiFollow is active and the target is the actor**/
virtual std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor) = 0; virtual std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor) = 0;
///Returns a list of actors who are fighting the given actor within the fAlarmDistance
/** ie AiCombat is active and the target is the actor **/
virtual std::list<MWWorld::Ptr> getActorsFighting(const MWWorld::Ptr& actor) = 0;
virtual void playerLoaded() = 0; virtual void playerLoaded() = 0;
}; };
} }

View File

@ -19,6 +19,7 @@
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
#include "../mwbase/statemanager.hpp" #include "../mwbase/statemanager.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwworld/player.hpp" #include "../mwworld/player.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
@ -693,8 +694,12 @@ namespace MWInput
if (!MWBase::Environment::get().getWindowManager()->getRestEnabled () || MWBase::Environment::get().getWindowManager()->isGuiMode ()) if (!MWBase::Environment::get().getWindowManager()->getRestEnabled () || MWBase::Environment::get().getWindowManager()->isGuiMode ())
return; return;
/// \todo check if resting is currently allowed (enemies nearby?) if(mPlayer->isInCombat()) {//Check if in combat
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_Rest); MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage2}"); //Nope,
return;
}
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_Rest); //Open rest GUI
} }
void InputManager::screenshot() void InputManager::screenshot()

View File

@ -176,7 +176,7 @@ namespace MWMechanics
adjustMagicEffects (ptr); adjustMagicEffects (ptr);
if (ptr.getClass().getCreatureStats(ptr).needToRecalcDynamicStats()) if (ptr.getClass().getCreatureStats(ptr).needToRecalcDynamicStats())
calculateDynamicStats (ptr); calculateDynamicStats (ptr);
calculateCreatureStatModifiers (ptr, duration); calculateCreatureStatModifiers (ptr, duration);
// AI // AI
@ -764,7 +764,7 @@ namespace MWMechanics
creatureStats.setHostile(false); creatureStats.setHostile(false);
creatureStats.setAttacked(false); creatureStats.setAttacked(false);
creatureStats.setAlarmed(false); creatureStats.setAlarmed(false);
// Update witness crime id // Update witness crime id
npcStats.setCrimeId(-1); npcStats.setCrimeId(-1);
} }
@ -1038,4 +1038,26 @@ namespace MWMechanics
} }
return list; return list;
} }
std::list<MWWorld::Ptr> Actors::getActorsFighting(const MWWorld::Ptr& actor) {
std::list<MWWorld::Ptr> list;
std::vector<MWWorld::Ptr> neighbors;
Ogre::Vector3 position = Ogre::Vector3(actor.getRefData().getPosition().pos);
getObjectsInRange(position,
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fAlarmRadius")->getFloat(),
neighbors); //only care about those within the alarm disance
for(std::vector<MWWorld::Ptr>::iterator iter(neighbors.begin());iter != neighbors.end();iter++)
{
const MWWorld::Class &cls = MWWorld::Class::get(*iter);
CreatureStats &stats = cls.getCreatureStats(*iter);
if(stats.getAiSequence().getTypeId() == AiPackage::TypeIdCombat)
{
MWMechanics::AiCombat* package = static_cast<MWMechanics::AiCombat*>(stats.getAiSequence().getActivePackage());
if(package->getTargetId() == actor.getCellRef().mRefID)
list.push_front(*iter);
}
}
return list;
}
} }

View File

@ -98,8 +98,13 @@ namespace MWMechanics
void getObjectsInRange(const Ogre::Vector3& position, float radius, std::vector<MWWorld::Ptr>& out); void getObjectsInRange(const Ogre::Vector3& position, float radius, std::vector<MWWorld::Ptr>& out);
///Returns the list of actors which are following the given actor
/**ie AiFollow is active and the target is the actor **/
std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor); std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor);
///<return the list of actors which are following the given actor (ie AiFollow is active and the target is the actor)
///Returns the list of actors which are fighting the given actor
/**ie AiCombat is active and the target is the actor **/
std::list<MWWorld::Ptr> getActorsFighting(const MWWorld::Ptr& actor);
private: private:
PtrControllerMap mActors; PtrControllerMap mActors;

View File

@ -772,6 +772,11 @@ namespace MWMechanics
bool MechanicsManager::sleepInBed(const MWWorld::Ptr &ptr, const MWWorld::Ptr &bed) bool MechanicsManager::sleepInBed(const MWWorld::Ptr &ptr, const MWWorld::Ptr &bed)
{ {
if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) {
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage2}");
return true;
}
MWWorld::Ptr victim; MWWorld::Ptr victim;
if (isAllowedToUse(ptr, bed, victim)) if (isAllowedToUse(ptr, bed, victim))
return false; return false;
@ -832,17 +837,17 @@ namespace MWMechanics
// Find all the NPCs within the alarm radius // Find all the NPCs within the alarm radius
std::vector<MWWorld::Ptr> neighbors; std::vector<MWWorld::Ptr> neighbors;
mActors.getObjectsInRange(Ogre::Vector3(ptr.getRefData().getPosition().pos), mActors.getObjectsInRange(Ogre::Vector3(ptr.getRefData().getPosition().pos),
esmStore.get<ESM::GameSetting>().find("fAlarmRadius")->getInt(), neighbors); esmStore.get<ESM::GameSetting>().find("fAlarmRadius")->getInt(), neighbors);
// Find an actor who witnessed the crime // Find an actor who witnessed the crime
for (std::vector<MWWorld::Ptr>::iterator it = neighbors.begin(); it != neighbors.end(); ++it) for (std::vector<MWWorld::Ptr>::iterator it = neighbors.begin(); it != neighbors.end(); ++it)
{ {
if (*it == ptr) continue; // not the player if (*it == ptr) continue; // not the player
// Was the crime seen? // Was the crime seen?
if ( ( MWBase::Environment::get().getWorld()->getLOS(ptr, *it) && awarenessCheck(ptr, *it) ) || if ( ( MWBase::Environment::get().getWorld()->getLOS(ptr, *it) && awarenessCheck(ptr, *it) ) ||
type == OT_Assault ) type == OT_Assault )
{ {
// Will the witness report the crime? // Will the witness report the crime?
@ -853,7 +858,7 @@ namespace MWMechanics
// Tell everyone, including yourself // Tell everyone, including yourself
for (std::vector<MWWorld::Ptr>::iterator it1 = neighbors.begin(); it1 != neighbors.end(); ++it1) for (std::vector<MWWorld::Ptr>::iterator it1 = neighbors.begin(); it1 != neighbors.end(); ++it1)
{ {
if (*it1 == ptr) continue; // not the player if (*it1 == ptr) continue; // not the player
// TODO: Add more messages // TODO: Add more messages
@ -861,9 +866,9 @@ namespace MWMechanics
MWBase::Environment::get().getDialogueManager()->say(*it1, "thief"); MWBase::Environment::get().getDialogueManager()->say(*it1, "thief");
else if (type == OT_Assault) else if (type == OT_Assault)
MWBase::Environment::get().getDialogueManager()->say(*it1, "attack"); MWBase::Environment::get().getDialogueManager()->say(*it1, "attack");
// Will other witnesses paticipate in crime // Will other witnesses paticipate in crime
if ( it1->getClass().getCreatureStats(*it1).getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm if ( it1->getClass().getCreatureStats(*it1).getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm
|| type == OT_Assault ) || type == OT_Assault )
{ {
it1->getClass().getNpcStats(*it1).setCrimeId(id); it1->getClass().getNpcStats(*it1).setCrimeId(id);
@ -884,7 +889,7 @@ namespace MWMechanics
void MechanicsManager::reportCrime(const MWWorld::Ptr &ptr, const MWWorld::Ptr &victim, OffenseType type, int arg) void MechanicsManager::reportCrime(const MWWorld::Ptr &ptr, const MWWorld::Ptr &victim, OffenseType type, int arg)
{ {
const MWWorld::Store<ESM::GameSetting>& store = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>(); const MWWorld::Store<ESM::GameSetting>& store = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
// Bounty for each type of crime // Bounty for each type of crime
if (type == OT_Trespassing || type == OT_SleepingInOwnedBed) if (type == OT_Trespassing || type == OT_SleepingInOwnedBed)
arg = store.find("iCrimeTresspass")->getInt(); arg = store.find("iCrimeTresspass")->getInt();
@ -993,4 +998,8 @@ namespace MWMechanics
{ {
return mActors.getActorsFollowing(actor); return mActors.getActorsFollowing(actor);
} }
std::list<MWWorld::Ptr> MechanicsManager::getActorsFighting(const MWWorld::Ptr& actor) {
return mActors.getActorsFighting(actor);
}
} }

View File

@ -120,7 +120,7 @@ namespace MWMechanics
/// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so /// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so
virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item); virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item);
/// 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? Also returns fail when enemies are nearby
virtual bool sleepInBed (const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed); virtual bool sleepInBed (const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed);
virtual void forceStateUpdate(const MWWorld::Ptr &ptr); virtual void forceStateUpdate(const MWWorld::Ptr &ptr);
@ -137,6 +137,8 @@ namespace MWMechanics
virtual std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor); virtual std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor);
virtual std::list<MWWorld::Ptr> getActorsFighting(const MWWorld::Ptr& actor);
virtual bool toggleAI(); virtual bool toggleAI();
virtual bool isAIActive(); virtual bool isAIActive();

View File

@ -235,9 +235,12 @@ void MWState::StateManager::quickSave(std::string name) {
if (it->mProfile.mDescription == name) if (it->mProfile.mDescription == name)
slot = &*it; slot = &*it;
} }
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage4}"); //Saving...
MWBase::Environment::get().getStateManager()->saveGame(name, slot); MWBase::Environment::get().getStateManager()->saveGame(name, slot);
} }
} }
else
MWBase::Environment::get().getWindowManager()->messageBox("#{sSaveGameDenied}"); //You can not save your game right now
} }
void MWState::StateManager::loadGame (const Character *character, const Slot *slot) void MWState::StateManager::loadGame (const Character *character, const Slot *slot)
@ -351,6 +354,7 @@ void MWState::StateManager::quickLoad() {
if(mCurrentCharacter) { //Ensure a current character exists if(mCurrentCharacter) { //Ensure a current character exists
const MWState::Slot* slot = &*mCurrentCharacter->begin(); //Get newest save const MWState::Slot* slot = &*mCurrentCharacter->begin(); //Get newest save
if(slot) //Don't even try loading it if there's no prior save. if(slot) //Don't even try loading it if there's no prior save.
//MWBase::Environment::get().getWindowManager()->messageBox("#{sLoadingMessage14}"); //it overlaps
MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, slot); //load newest save. That was easy! MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, slot); //load newest save. That was easy!
} }
} }

View File

@ -2,11 +2,19 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/player.hpp"
namespace MWWorld namespace MWWorld
{ {
void ActionAlchemy::executeImp (const Ptr& actor) void ActionAlchemy::executeImp (const Ptr& actor)
{ {
if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { //Ensure we're not in combat
MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage3}");
return;
}
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Alchemy); MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Alchemy);
} }
} }

View File

@ -3,6 +3,9 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/player.hpp"
#include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/npcstats.hpp"
@ -19,8 +22,13 @@ namespace MWWorld
{ {
} }
void ActionRead::executeImp (const MWWorld::Ptr& actor) void ActionRead::executeImp (const MWWorld::Ptr& actor) {
{
if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { //Ensure we're not in combat
MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage4}");
return;
}
LiveCellRef<ESM::Book> *ref = getTarget().get<ESM::Book>(); LiveCellRef<ESM::Book> *ref = getTarget().get<ESM::Book>();
if (ref->mBase->mData.mIsScroll) if (ref->mBase->mData.mIsScroll)

View File

@ -2,6 +2,8 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/player.hpp"
namespace MWWorld namespace MWWorld
{ {
@ -12,6 +14,11 @@ namespace MWWorld
void ActionRepair::executeImp (const Ptr& actor) void ActionRepair::executeImp (const Ptr& actor)
{ {
if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) {
MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage2}");
return;
}
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Repair); MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Repair);
MWBase::Environment::get().getWindowManager()->startRepairItem(getTarget()); MWBase::Environment::get().getWindowManager()->startRepairItem(getTarget());
} }

View File

@ -2,20 +2,26 @@
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/player.hpp"
namespace MWWorld namespace MWWorld
{ {
ActionSoulgem::ActionSoulgem(const Ptr &object) ActionSoulgem::ActionSoulgem(const Ptr &object)
: Action(false, object) : Action(false, object)
{ {
} }
void ActionSoulgem::executeImp(const Ptr &actor) void ActionSoulgem::executeImp(const Ptr &actor)
{ {
MWBase::Environment::get().getWindowManager()->showSoulgemDialog(getTarget()); if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { //Ensure we're not in combat
} MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage5}");
return;
}
MWBase::Environment::get().getWindowManager()->showSoulgemDialog(getTarget());
}
} }

View File

@ -13,6 +13,7 @@
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwmechanics/movement.hpp" #include "../mwmechanics/movement.hpp"
#include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/npcstats.hpp"
@ -166,6 +167,10 @@ namespace MWWorld
mTeleported = teleported; mTeleported = teleported;
} }
bool Player::isInCombat() {
return MWBase::Environment::get().getMechanicsManager()->getActorsFighting(getPlayer()).size() != 0;
}
void Player::markPosition(CellStore *markedCell, ESM::Position markedPosition) void Player::markPosition(CellStore *markedCell, ESM::Position markedPosition)
{ {
mMarkedCell = markedCell; mMarkedCell = markedCell;

View File

@ -44,7 +44,7 @@ namespace MWWorld
int mCurrentCrimeId; // the id assigned witnesses int mCurrentCrimeId; // the id assigned witnesses
int mPayedCrimeId; // the last id payed off (0 bounty) int mPayedCrimeId; // the last id payed off (0 bounty)
public: public:
Player(const ESM::NPC *player, const MWBase::World& world); Player(const ESM::NPC *player, const MWBase::World& world);
@ -90,6 +90,9 @@ namespace MWWorld
bool wasTeleported() const; bool wasTeleported() const;
void setTeleported(bool teleported); void setTeleported(bool teleported);
///Checks all actors to see if anyone has an aipackage against you
bool isInCombat();
void clear(); void clear();
void write (ESM::ESMWriter& writer) const; void write (ESM::ESMWriter& writer) const;