forked from mirror/openmw-tes3mp
Feature 1154 & 73: Crime and NPC reactions
This commit is contained in:
parent
4037f3705e
commit
50dac98a2b
8 changed files with 78 additions and 42 deletions
|
@ -513,6 +513,8 @@ namespace MWBase
|
|||
|
||||
virtual void explodeSpell (const Ogre::Vector3& origin, const MWWorld::Ptr& object, const ESM::EffectList& effects,
|
||||
const MWWorld::Ptr& caster, const std::string& id, const std::string& sourceName) = 0;
|
||||
|
||||
virtual void resetCrimes(const MWWorld::Ptr& ptr) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -812,7 +812,13 @@ namespace MWClass
|
|||
return boost::shared_ptr<MWWorld::Action>(new MWWorld::FailedAction("#{sActorInCombat}"));
|
||||
if(getCreatureStats(actor).getStance(MWMechanics::CreatureStats::Stance_Sneak))
|
||||
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr)); // stealing
|
||||
|
||||
// player got activated by another NPC
|
||||
if(ptr.getRefData().getHandle() == "player")
|
||||
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(actor));
|
||||
|
||||
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(ptr));
|
||||
|
||||
}
|
||||
|
||||
MWWorld::ContainerStore& Npc::getContainerStore (const MWWorld::Ptr& ptr)
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "steering.hpp"
|
||||
#include "movement.hpp"
|
||||
#include "creaturestats.hpp"
|
||||
|
||||
MWMechanics::AiActivate::AiActivate(const std::string &objectId, int arg)
|
||||
: mObjectId(objectId),
|
||||
|
@ -26,9 +27,8 @@ bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration)
|
|||
Movement &movement = actor.getClass().getMovementSettings(actor);
|
||||
const ESM::Cell *cell = actor.getCell()->getCell();
|
||||
|
||||
// Make guard chase player
|
||||
//if (mArg == 1)
|
||||
// actor.getClass().getNpcStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
|
||||
if (mArg == 1) // run to actor
|
||||
actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
|
||||
|
||||
MWWorld::Ptr player = world->getPlayerPtr();
|
||||
if(cell->mData.mX != player.getCell()->getCell()->mData.mX)
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace MWMechanics
|
|||
mAttacked (false), mHostile (false),
|
||||
mAttackingOrSpell(false),
|
||||
mIsWerewolf(false),
|
||||
mWitnesses(),
|
||||
mFallHeight(0), mRecalcDynamicStats(false), mKnockdown(false), mHitRecovery(false), mBlock(false),
|
||||
mMovementFlags(0), mDrawState (DrawState_Nothing), mAttackStrength(0.f)
|
||||
{
|
||||
|
@ -496,4 +497,17 @@ namespace MWMechanics
|
|||
{
|
||||
return mGoldPool;
|
||||
}
|
||||
|
||||
void CreatureStats::addPlayerWitnesses(std::vector<MWWorld::Ptr> witnesses)
|
||||
{
|
||||
mWitnesses.insert(mWitnesses.end(), witnesses.begin(), witnesses.end());
|
||||
}
|
||||
std::vector<MWWorld::Ptr> CreatureStats::getPlayerWitnesses() const
|
||||
{
|
||||
return mWitnesses;
|
||||
}
|
||||
void CreatureStats::resetPlayerWitnesses()
|
||||
{
|
||||
mWitnesses.clear();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,6 +59,8 @@ namespace MWMechanics
|
|||
|
||||
int mGoldPool; // the pool of merchant gold not in inventory
|
||||
|
||||
std::vector<MWWorld::Ptr> mWitnesses; // the witnesses to players crimes
|
||||
|
||||
protected:
|
||||
bool mIsWerewolf;
|
||||
AttributeValue mWerewolfAttributes[8];
|
||||
|
@ -233,6 +235,10 @@ namespace MWMechanics
|
|||
|
||||
void setGoldPool(int pool);
|
||||
int getGoldPool() const;
|
||||
|
||||
void addPlayerWitnesses(std::vector<MWWorld::Ptr> witnesses);
|
||||
std::vector<MWWorld::Ptr> getPlayerWitnesses() const;
|
||||
void resetPlayerWitnesses();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -826,6 +826,11 @@ namespace MWMechanics
|
|||
else if (type == OT_Theft)
|
||||
alarm = esmStore.get<ESM::GameSetting>().find("iAlarmStealing")->getInt();
|
||||
|
||||
// what is the bounty cutoff? To high the guards will attack
|
||||
float cutoff = float(esmStore.get<ESM::GameSetting>().find("iCrimeThreshold")->getInt()) *
|
||||
float(esmStore.get<ESM::GameSetting>().find("iCrimeThresholdMultiplier")->getInt()) *
|
||||
esmStore.get<ESM::GameSetting>().find("fCrimeGoldDiscountMult")->getFloat();
|
||||
|
||||
// Innocent until proven guilty
|
||||
bool reported = false;
|
||||
|
||||
|
@ -842,7 +847,7 @@ namespace MWMechanics
|
|||
|
||||
CreatureStats& creatureStats = MWWorld::Class::get(*it).getCreatureStats(*it);
|
||||
|
||||
// Did the witness see the crime?
|
||||
// Did a witness see the crime?
|
||||
if ( MWBase::Environment::get().getWorld()->getLOS(ptr, *it) && awarenessCheck(ptr, *it) )
|
||||
{
|
||||
// Say something!
|
||||
|
@ -853,65 +858,51 @@ namespace MWMechanics
|
|||
// Will the witness report the crime?
|
||||
if (creatureStats.getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm)
|
||||
{
|
||||
creatureStats.setAlarmed(true);
|
||||
reported = true;
|
||||
reportCrime(ptr, victim, type, arg);
|
||||
|
||||
// Is it a guard? Or will the witness fight?
|
||||
if (it->getClass().isClass(*it, "Guard"))
|
||||
{
|
||||
// TODO: Persue player, concider bounty?
|
||||
creatureStats.getAiSequence().stack(AiActivate(ptr.getClass().getId(ptr), 1));
|
||||
creatureStats.getAiSequence().execute(*it,0);
|
||||
}
|
||||
else if (creatureStats.getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm)
|
||||
{
|
||||
creatureStats.getAiSequence().stack(AiCombat(ptr));
|
||||
creatureStats.setHostile(true);
|
||||
creatureStats.getAiSequence().execute(*it,0);
|
||||
}
|
||||
else if (type == OT_Assault)
|
||||
{
|
||||
creatureStats.getAiSequence().stack(AiCombat(ptr));
|
||||
creatureStats.setHostile(true);
|
||||
creatureStats.getAiSequence().execute(*it,0);
|
||||
}
|
||||
|
||||
// Tell everyone else
|
||||
for (std::vector<MWWorld::Ptr>::iterator it1 = neighbors.begin(); it1 != neighbors.end(); ++it1)
|
||||
{
|
||||
if (it == it1 || // Don't tell the witness or the player
|
||||
ptr == *it1)
|
||||
if (*it1 == ptr) // Not the player
|
||||
continue;
|
||||
|
||||
// Is it a guard? Or will the witness fight?
|
||||
// was the witness alarmed?
|
||||
CreatureStats& creatureStats1 = MWWorld::Class::get(*it1).getCreatureStats(*it1);
|
||||
if (creatureStats1.getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm)
|
||||
creatureStats1.setAlarmed(true);
|
||||
|
||||
// was the witness a guard?
|
||||
if (it1->getClass().isClass(*it1, "Guard"))
|
||||
{
|
||||
// TODO: Persue player, concider bounty?
|
||||
creatureStats1.getAiSequence().stack(AiActivate(ptr.getClass().getId(ptr), 1));
|
||||
creatureStats1.getAiSequence().execute(*it1,0);
|
||||
continue;
|
||||
// will the guard try to kill the player?
|
||||
if (ptr.getClass().getNpcStats(ptr).getBounty() >= cutoff)
|
||||
{
|
||||
creatureStats1.getAiSequence().stack(AiCombat(ptr));
|
||||
creatureStats1.setHostile(true);
|
||||
creatureStats1.getAiSequence().execute(*it,0);
|
||||
}
|
||||
else if (creatureStats1.getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm)
|
||||
else // will the guard persue the player?
|
||||
{
|
||||
creatureStats1.getAiSequence().stack(AiActivate(ptr.getClass().getId(ptr), 1));
|
||||
creatureStats1.getAiSequence().execute(*it,0);
|
||||
}
|
||||
}
|
||||
// will the witness fight the player?
|
||||
else if (creatureStats1.getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm ||
|
||||
type == OT_Assault)
|
||||
{
|
||||
creatureStats1.getAiSequence().stack(AiCombat(ptr));
|
||||
creatureStats1.setHostile(true);
|
||||
creatureStats1.getAiSequence().execute(*it1,0);
|
||||
}
|
||||
else if (type == OT_Assault)
|
||||
{
|
||||
creatureStats.getAiSequence().stack(AiCombat(ptr));
|
||||
creatureStats.setHostile(true);
|
||||
creatureStats.getAiSequence().execute(*it,0);
|
||||
}
|
||||
}
|
||||
|
||||
break; // Someone saw the crime and everyone has been told
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (reported)
|
||||
ptr.getClass().getCreatureStats(ptr).addPlayerWitnesses(neighbors);
|
||||
return reported;
|
||||
}
|
||||
|
||||
|
|
|
@ -2762,12 +2762,28 @@ namespace MWWorld
|
|||
message += "\n" + skillMsg;
|
||||
}
|
||||
|
||||
resetCrimes(player);
|
||||
|
||||
std::vector<std::string> buttons;
|
||||
buttons.push_back("#{sOk}");
|
||||
MWBase::Environment::get().getWindowManager()->messageBox(message, buttons);
|
||||
}
|
||||
}
|
||||
|
||||
void World::resetCrimes(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
// Reset witnesses to the players crimes
|
||||
std::vector<MWWorld::Ptr> neighbors = ptr.getClass().getCreatureStats(ptr).getPlayerWitnesses();
|
||||
for (std::vector<MWWorld::Ptr>::iterator it = neighbors.begin(); it != neighbors.end(); ++it)
|
||||
{
|
||||
// This to reset for each witness:
|
||||
// TODO: More research is needed to complete this list
|
||||
it->getClass().getCreatureStats(*it).setHostile(false);
|
||||
it->getClass().getCreatureStats(*it).setAlarmed(false);
|
||||
}
|
||||
ptr.getClass().getCreatureStats(ptr).resetPlayerWitnesses();
|
||||
}
|
||||
|
||||
void World::spawnRandomCreature(const std::string &creatureList)
|
||||
{
|
||||
const ESM::CreatureLevList* list = getStore().get<ESM::CreatureLevList>().find(creatureList);
|
||||
|
|
|
@ -611,6 +611,7 @@ namespace MWWorld
|
|||
|
||||
virtual void explodeSpell (const Ogre::Vector3& origin, const MWWorld::Ptr& object, const ESM::EffectList& effects,
|
||||
const MWWorld::Ptr& caster, const std::string& id, const std::string& sourceName);
|
||||
virtual void resetCrimes(const MWWorld::Ptr& ptr);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue