Don't trigger OnPcHitMe for friendly hits (Fixes #1950)

Don't consider actors as followers if they are also in combat with the follow target
deque
scrawl 10 years ago
parent 4b8ea25cf0
commit e868a48a63

@ -128,7 +128,8 @@ namespace MWBase
OffenseType type, int arg=0) = 0; OffenseType type, int arg=0) = 0;
virtual void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, virtual void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim,
OffenseType type, int arg=0) = 0; OffenseType type, int arg=0) = 0;
virtual void actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0; /// @return false if the attack was considered a "friendly hit" and forgiven
virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0;
/// Utility to check if taking this item is illegal and calling commitCrime if so /// Utility to check if taking this item is illegal and calling commitCrime if so
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, int count) = 0; virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, int count) = 0;
/// 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

@ -338,11 +338,12 @@ namespace MWClass
getCreatureStats(ptr).setAttacked(true); getCreatureStats(ptr).setAttacked(true);
// Self defense // Self defense
bool setOnPcHitMe = true; // Note OnPcHitMe is not set for friendly hits.
if ((canWalk(ptr) || canFly(ptr) || canSwim(ptr)) // No retaliation for totally static creatures if ((canWalk(ptr) || canFly(ptr) || canSwim(ptr)) // No retaliation for totally static creatures
// (they have no movement or attacks anyway) // (they have no movement or attacks anyway)
&& !attacker.isEmpty()) && !attacker.isEmpty())
{ {
MWBase::Environment::get().getMechanicsManager()->actorAttacked(ptr, attacker); setOnPcHitMe = MWBase::Environment::get().getMechanicsManager()->actorAttacked(ptr, attacker);
} }
if(!successful) if(!successful)
@ -357,7 +358,7 @@ namespace MWClass
if(!object.isEmpty()) if(!object.isEmpty())
getCreatureStats(ptr).setLastHitObject(object.getClass().getId(object)); getCreatureStats(ptr).setLastHitObject(object.getClass().getId(object));
if(!attacker.isEmpty() && attacker.getRefData().getHandle() == "player") if(setOnPcHitMe && !attacker.isEmpty() && attacker.getRefData().getHandle() == "player")
{ {
const std::string &script = ptr.get<ESM::Creature>()->mBase->mScript; const std::string &script = ptr.get<ESM::Creature>()->mBase->mScript;
/* Set the OnPCHitMe script variable. The script is responsible for clearing it. */ /* Set the OnPCHitMe script variable. The script is responsible for clearing it. */

@ -644,11 +644,13 @@ namespace MWClass
bool wasDead = getCreatureStats(ptr).isDead(); bool wasDead = getCreatureStats(ptr).isDead();
// Note OnPcHitMe is not set for friendly hits.
bool setOnPcHitMe = true;
if (!attacker.isEmpty() && !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(attacker)) if (!attacker.isEmpty() && !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(attacker))
{ {
getCreatureStats(ptr).setAttacked(true); getCreatureStats(ptr).setAttacked(true);
MWBase::Environment::get().getMechanicsManager()->actorAttacked(ptr, attacker); setOnPcHitMe = MWBase::Environment::get().getMechanicsManager()->actorAttacked(ptr, attacker);
} }
if(!successful) if(!successful)
@ -663,7 +665,7 @@ namespace MWClass
if(!object.isEmpty()) if(!object.isEmpty())
getCreatureStats(ptr).setLastHitObject(object.getClass().getId(object)); getCreatureStats(ptr).setLastHitObject(object.getClass().getId(object));
if(!attacker.isEmpty() && attacker.getRefData().getHandle() == "player") if(setOnPcHitMe && !attacker.isEmpty() && attacker.getRefData().getHandle() == "player")
{ {
const std::string &script = ptr.getClass().getScript(ptr); const std::string &script = ptr.getClass().getScript(ptr);
/* Set the OnPCHitMe script variable. The script is responsible for clearing it. */ /* Set the OnPCHitMe script variable. The script is responsible for clearing it. */

@ -323,8 +323,9 @@ namespace MWMechanics
for (std::list<MWWorld::Ptr>::const_iterator it = followers.begin(); it != followers.end(); ++it) for (std::list<MWWorld::Ptr>::const_iterator it = followers.begin(); it != followers.end(); ++it)
{ {
// need to check both ways since player doesn't use AI packages // need to check both ways since player doesn't use AI packages
if (creatureStats2.getAiSequence().isInCombat(*it) if ((creatureStats2.getAiSequence().isInCombat(*it)
|| it->getClass().getCreatureStats(*it).getAiSequence().isInCombat(actor2)) || it->getClass().getCreatureStats(*it).getAiSequence().isInCombat(actor2))
&& !creatureStats.getAiSequence().isInCombat(*it))
aggressive = true; aggressive = true;
} }
@ -337,6 +338,9 @@ namespace MWMechanics
if (followTarget.isEmpty()) if (followTarget.isEmpty())
continue; continue;
if (creatureStats.getAiSequence().isInCombat(followTarget))
continue;
// need to check both ways since player doesn't use AI packages // need to check both ways since player doesn't use AI packages
if (creatureStats2.getAiSequence().isInCombat(followTarget) if (creatureStats2.getAiSequence().isInCombat(followTarget)
|| followTarget.getClass().getCreatureStats(followTarget).getAiSequence().isInCombat(actor2)) || followTarget.getClass().getCreatureStats(followTarget).getAiSequence().isInCombat(actor2))

@ -1111,10 +1111,10 @@ namespace MWMechanics
} }
} }
void MechanicsManager::actorAttacked(const MWWorld::Ptr &ptr, const MWWorld::Ptr &attacker) bool MechanicsManager::actorAttacked(const MWWorld::Ptr &ptr, const MWWorld::Ptr &attacker)
{ {
if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr())
return; return false;
std::list<MWWorld::Ptr> followers = getActorsFollowing(attacker); std::list<MWWorld::Ptr> followers = getActorsFollowing(attacker);
if (std::find(followers.begin(), followers.end(), ptr) != followers.end()) if (std::find(followers.begin(), followers.end(), ptr) != followers.end())
@ -1124,7 +1124,7 @@ namespace MWMechanics
if (ptr.getClass().getCreatureStats(ptr).getFriendlyHits() < 4) if (ptr.getClass().getCreatureStats(ptr).getFriendlyHits() < 4)
{ {
MWBase::Environment::get().getDialogueManager()->say(ptr, "hit"); MWBase::Environment::get().getDialogueManager()->say(ptr, "hit");
return; return false;
} }
} }
@ -1153,6 +1153,8 @@ namespace MWMechanics
// Note: accidental or collateral damage attacks are ignored. // Note: accidental or collateral damage attacks are ignored.
startCombat(ptr, attacker); startCombat(ptr, attacker);
} }
return true;
} }
bool MechanicsManager::awarenessCheck(const MWWorld::Ptr &ptr, const MWWorld::Ptr &observer) bool MechanicsManager::awarenessCheck(const MWWorld::Ptr &ptr, const MWWorld::Ptr &observer)

@ -120,7 +120,8 @@ namespace MWMechanics
OffenseType type, int arg=0); OffenseType type, int arg=0);
virtual void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, virtual void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim,
OffenseType type, int arg=0); OffenseType type, int arg=0);
virtual void actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker); /// @return false if the attack was considered a "friendly hit" and forgiven
virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker);
/// Utility to check if taking this item is illegal and calling commitCrime if so /// Utility to check if taking this item is illegal and calling commitCrime if so
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, int count); virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, int count);
/// 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

Loading…
Cancel
Save