mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-25 11:26:37 +00:00 
			
		
		
		
	Implement disposition/distance based aggression (Fixes #1520)
This commit is contained in:
		
							parent
							
								
									d11a5e19f7
								
							
						
					
					
						commit
						28feb260eb
					
				
					 7 changed files with 42 additions and 17 deletions
				
			
		|  | @ -191,6 +191,8 @@ namespace MWBase | ||||||
|             virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; |             virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; | ||||||
| 
 | 
 | ||||||
|             virtual void clear() = 0; |             virtual void clear() = 0; | ||||||
|  | 
 | ||||||
|  |             virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target) = 0; | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -345,7 +345,7 @@ namespace MWClass | ||||||
|         getCreatureStats(ptr).setAttacked(true); |         getCreatureStats(ptr).setAttacked(true); | ||||||
| 
 | 
 | ||||||
|         // Self defense
 |         // Self defense
 | ||||||
|         if (!attacker.isEmpty() && ptr.getClass().getCreatureStats(ptr).getAiSetting(MWMechanics::CreatureStats::AI_Fight).getModified() < 80 |         if (!attacker.isEmpty() && !MWBase::Environment::get().getMechanicsManager()->isAggressive(ptr, attacker) | ||||||
|                 && (canWalk(ptr) || canFly(ptr) || canSwim(ptr))) // No retaliation for totally static creatures
 |                 && (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)
 | ||||||
|             MWBase::Environment::get().getMechanicsManager()->startCombat(ptr, attacker); |             MWBase::Environment::get().getMechanicsManager()->startCombat(ptr, attacker); | ||||||
|  |  | ||||||
|  | @ -624,9 +624,8 @@ namespace MWClass | ||||||
|         // NOTE: 'object' and/or 'attacker' may be empty.
 |         // NOTE: 'object' and/or 'attacker' may be empty.
 | ||||||
| 
 | 
 | ||||||
|         // Attacking peaceful NPCs is a crime
 |         // Attacking peaceful NPCs is a crime
 | ||||||
|         // anything below 80 is considered peaceful (see Actors::updateActor)
 |  | ||||||
|         if (!attacker.isEmpty() && !ptr.getClass().getCreatureStats(ptr).isHostile() && |         if (!attacker.isEmpty() && !ptr.getClass().getCreatureStats(ptr).isHostile() && | ||||||
|                 ptr.getClass().getCreatureStats(ptr).getAiSetting(MWMechanics::CreatureStats::AI_Fight).getModified() < 80) |                 !MWBase::Environment::get().getMechanicsManager()->isAggressive(ptr, attacker)) | ||||||
|             MWBase::Environment::get().getMechanicsManager()->commitCrime(attacker, ptr, MWBase::MechanicsManager::OT_Assault); |             MWBase::Environment::get().getMechanicsManager()->commitCrime(attacker, ptr, MWBase::MechanicsManager::OT_Assault); | ||||||
| 
 | 
 | ||||||
|         getCreatureStats(ptr).setAttacked(true); |         getCreatureStats(ptr).setAttacked(true); | ||||||
|  |  | ||||||
|  | @ -530,7 +530,8 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co | ||||||
| 
 | 
 | ||||||
|         case SelectWrapper::Function_ShouldAttack: |         case SelectWrapper::Function_ShouldAttack: | ||||||
| 
 | 
 | ||||||
|             return mActor.getClass().getCreatureStats(mActor).getAiSetting(MWMechanics::CreatureStats::AI_Fight).getModified() >= 80; |             return MWBase::Environment::get().getMechanicsManager()->isAggressive(mActor, | ||||||
|  |                     MWBase::Environment::get().getWorld()->getPlayerPtr()); | ||||||
| 
 | 
 | ||||||
|         case SelectWrapper::Function_CreatureTargetted: |         case SelectWrapper::Function_CreatureTargetted: | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -201,32 +201,28 @@ namespace MWMechanics | ||||||
|                 || (!actor1.getClass().canSwim(actor1) && MWBase::Environment::get().getWorld()->isSwimming(actor2)))) // creature can't swim to target
 |                 || (!actor1.getClass().canSwim(actor1) && MWBase::Environment::get().getWorld()->isSwimming(actor2)))) // creature can't swim to target
 | ||||||
|             return; |             return; | ||||||
| 
 | 
 | ||||||
|         float fight; |         bool aggressive; | ||||||
| 
 | 
 | ||||||
|         if (againstPlayer)  |         if (againstPlayer)  | ||||||
|             fight = actor1.getClass().getCreatureStats(actor1).getAiSetting(CreatureStats::AI_Fight).getModified(); |             aggressive = MWBase::Environment::get().getMechanicsManager()->isAggressive(actor1, actor2); | ||||||
|         else |         else | ||||||
|         { |         { | ||||||
|             fight = 0; |             aggressive = false; | ||||||
|             // if one of actors is creature then we should make a decision to start combat or not
 |             // if one of actors is creature then we should make a decision to start combat or not
 | ||||||
|             // NOTE: function doesn't take into account combat between 2 creatures
 |             // NOTE: function doesn't take into account combat between 2 creatures
 | ||||||
|             if (!actor1.getClass().isNpc()) |             if (!actor1.getClass().isNpc()) | ||||||
|             { |             { | ||||||
|                 // if creature is hostile then it is necessarily to start combat
 |                 // if creature is hostile then it is necessarily to start combat
 | ||||||
|                 if (creatureStats.isHostile()) fight = 100; |                 if (creatureStats.isHostile()) aggressive = true; | ||||||
|                 else fight = creatureStats.getAiSetting(CreatureStats::AI_Fight).getModified(); |                 else aggressive = MWBase::Environment::get().getMechanicsManager()->isAggressive(actor1, actor2); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         ESM::Position actor1Pos = actor1.getRefData().getPosition(); |         if(aggressive) | ||||||
|         ESM::Position actor2Pos = actor2.getRefData().getPosition(); |  | ||||||
|         float d = Ogre::Vector3(actor1Pos.pos).distance(Ogre::Vector3(actor2Pos.pos)); |  | ||||||
| 
 |  | ||||||
|         if(   (fight == 100 && d <= 5000) |  | ||||||
|             || (fight >= 95 && d <= 3000) |  | ||||||
|             || (fight >= 90 && d <= 2000) |  | ||||||
|             || (fight >= 80 && d <= 1000)) |  | ||||||
|         { |         { | ||||||
|  |             const ESM::Position& actor1Pos = actor2.getRefData().getPosition(); | ||||||
|  |             const ESM::Position& actor2Pos = actor2.getRefData().getPosition(); | ||||||
|  |             float d = Ogre::Vector3(actor1Pos.pos).distance(Ogre::Vector3(actor2Pos.pos)); | ||||||
|             if (againstPlayer || actor2.getClass().getCreatureStats(actor2).getAiSequence().canAddTarget(actor2Pos, d)) |             if (againstPlayer || actor2.getClass().getCreatureStats(actor2).getAiSequence().canAddTarget(actor2Pos, d)) | ||||||
|             { |             { | ||||||
|                 bool LOS = MWBase::Environment::get().getWorld()->getLOS(actor1, actor2); |                 bool LOS = MWBase::Environment::get().getWorld()->getLOS(actor1, actor2); | ||||||
|  |  | ||||||
|  | @ -1098,4 +1098,29 @@ namespace MWMechanics | ||||||
|     { |     { | ||||||
|         mActors.clear(); |         mActors.clear(); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     bool MechanicsManager::isAggressive(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target) | ||||||
|  |     { | ||||||
|  |         Ogre::Vector3 pos1 (ptr.getRefData().getPosition().pos); | ||||||
|  |         Ogre::Vector3 pos2 (target.getRefData().getPosition().pos); | ||||||
|  | 
 | ||||||
|  |         float d = pos1.distance(pos2); | ||||||
|  | 
 | ||||||
|  |         static int iFightDistanceBase = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find( | ||||||
|  |                     "iFightDistanceBase")->getInt(); | ||||||
|  |         static float fFightDistanceMultiplier = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find( | ||||||
|  |                     "fFightDistanceMultiplier")->getFloat(); | ||||||
|  |         static float fFightDispMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find( | ||||||
|  |                     "fFightDispMult")->getFloat(); | ||||||
|  | 
 | ||||||
|  |         int disposition = 50; | ||||||
|  |         if (ptr.getClass().isNpc()) | ||||||
|  |             disposition = getDerivedDisposition(ptr); | ||||||
|  | 
 | ||||||
|  |         int fight = ptr.getClass().getCreatureStats(ptr).getAiSetting(CreatureStats::AI_Fight).getModified() | ||||||
|  |                 + (iFightDistanceBase - fFightDistanceMultiplier * d) | ||||||
|  |                 + ((50 - disposition)  * fFightDispMult); | ||||||
|  | 
 | ||||||
|  |         return (fight >= 100); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -156,6 +156,8 @@ namespace MWMechanics | ||||||
|             virtual void readRecord (ESM::ESMReader& reader, int32_t type); |             virtual void readRecord (ESM::ESMReader& reader, int32_t type); | ||||||
| 
 | 
 | ||||||
|             virtual void clear(); |             virtual void clear(); | ||||||
|  | 
 | ||||||
|  |             virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target); | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue