mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-30 02:56:44 +00:00 
			
		
		
		
	Implement hand-to-hand attacks
This commit is contained in:
		
							parent
							
								
									b7e81dbc5b
								
							
						
					
					
						commit
						54f91d4b3a
					
				
					 6 changed files with 71 additions and 23 deletions
				
			
		|  | @ -154,7 +154,7 @@ namespace MWClass | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void Creature::onHit(const MWWorld::Ptr &ptr, float damage, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const |     void Creature::onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const | ||||||
|     { |     { | ||||||
|         // NOTE: 'object' and/or 'attacker' may be empty.
 |         // NOTE: 'object' and/or 'attacker' may be empty.
 | ||||||
| 
 | 
 | ||||||
|  | @ -178,13 +178,19 @@ namespace MWClass | ||||||
|                 ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1); |                 ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if(damage > 0.0f) |         if(ishealth) | ||||||
|         { |         { | ||||||
|             MWBase::Environment::get().getSoundManager()->playSound3D(ptr, "Health Damage", 1.0f, 1.0f); |             if(damage > 0.0f) | ||||||
|  |                 MWBase::Environment::get().getSoundManager()->playSound3D(ptr, "Health Damage", 1.0f, 1.0f); | ||||||
|  |             float health = getCreatureStats(ptr).getHealth().getCurrent() - damage; | ||||||
|  |             setActorHealth(ptr, health, attacker); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             MWMechanics::DynamicStat<float> fatigue(getCreatureStats(ptr).getFatigue()); | ||||||
|  |             fatigue.setCurrent(fatigue.getCurrent() - damage); | ||||||
|  |             getCreatureStats(ptr).setFatigue(fatigue); | ||||||
|         } |         } | ||||||
| 
 |  | ||||||
|         float health = getCreatureStats(ptr).getHealth().getCurrent() - damage; |  | ||||||
|         setActorHealth(ptr, health, attacker); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void Creature::setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const |     void Creature::setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const | ||||||
|  |  | ||||||
|  | @ -44,7 +44,7 @@ namespace MWClass | ||||||
| 
 | 
 | ||||||
|             virtual void hit(const MWWorld::Ptr& ptr, int type) const; |             virtual void hit(const MWWorld::Ptr& ptr, int type) const; | ||||||
| 
 | 
 | ||||||
|             virtual void onHit(const MWWorld::Ptr &ptr, float damage, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const; |             virtual void onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const; | ||||||
| 
 | 
 | ||||||
|             virtual void setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const; |             virtual void setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -346,10 +346,11 @@ namespace MWClass | ||||||
| 
 | 
 | ||||||
|         if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f) |         if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f) | ||||||
|         { |         { | ||||||
|             othercls.onHit(victim, 0.0f, weapon, ptr, false); |             othercls.onHit(victim, 0.0f, false, weapon, ptr, false); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         bool healthdmg; | ||||||
|         float damage = 0.0f; |         float damage = 0.0f; | ||||||
|         if(!weapon.isEmpty()) |         if(!weapon.isEmpty()) | ||||||
|         { |         { | ||||||
|  | @ -373,15 +374,43 @@ namespace MWClass | ||||||
|                 } |                 } | ||||||
|                 damage /= std::min(1.0f + othercls.getArmorRating(victim)/std::max(1.0f, damage), 4.0f); |                 damage /= std::min(1.0f + othercls.getArmorRating(victim)/std::max(1.0f, damage), 4.0f); | ||||||
|             } |             } | ||||||
|  |             healthdmg = true; | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             // Note: MCP contains an option to include Strength in hand-to-hand damage
 | ||||||
|  |             // calculations. Some mods recommend using it, so we may want to include am
 | ||||||
|  |             // option for it.
 | ||||||
|  |             float minstrike = gmst.find("fMinHandToHandMult")->getFloat(); | ||||||
|  |             float maxstrike = gmst.find("fMaxHandToHandMult")->getFloat(); | ||||||
|  |             damage  = npcstats.getSkill(weapskill).getModified(); | ||||||
|  |             damage *= minstrike + ((maxstrike-minstrike)*npcstats.getAttackStrength()); | ||||||
|  |             if(!othercls.hasDetected(victim, ptr)) | ||||||
|  |             { | ||||||
|  |                 damage *= gmst.find("fCombatCriticalStrikeMult")->getFloat(); | ||||||
|  |                 MWBase::Environment::get().getWindowManager()->messageBox("#{sTargetCriticalStrike}"); | ||||||
|  |                 MWBase::Environment::get().getSoundManager()->playSound3D(victim, "critical damage", 1.0f, 1.0f); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             healthdmg = (othercls.getCreatureStats(victim).getFatigue().getCurrent() < 1.0f || | ||||||
|  |                          npcstats.isWerewolf()); | ||||||
|  |             if(healthdmg) | ||||||
|  |             { | ||||||
|  |                 // Not sure this is right...
 | ||||||
|  |                 damage *= gmst.find("fHandtoHandHealthPer")->getFloat() * 1.5f; | ||||||
|  |                 damage /= othercls.getArmorRating(victim); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         if(ptr.getRefData().getHandle() == "player") |         if(ptr.getRefData().getHandle() == "player") | ||||||
|             skillUsageSucceeded(ptr, weapskill, 0); |             skillUsageSucceeded(ptr, weapskill, 0); | ||||||
| 
 | 
 | ||||||
|         othercls.onHit(victim, damage, weapon, ptr, true); |         othercls.onHit(victim, damage, healthdmg, weapon, ptr, true); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void Npc::onHit(const MWWorld::Ptr &ptr, float damage, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const |     void Npc::onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const | ||||||
|     { |     { | ||||||
|  |         MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); | ||||||
|  | 
 | ||||||
|         // NOTE: 'object' and/or 'attacker' may be empty.
 |         // NOTE: 'object' and/or 'attacker' may be empty.
 | ||||||
| 
 | 
 | ||||||
|         if(!successful) |         if(!successful) | ||||||
|  | @ -389,7 +418,7 @@ namespace MWClass | ||||||
|             // TODO: Handle HitAttemptOnMe script function
 |             // TODO: Handle HitAttemptOnMe script function
 | ||||||
| 
 | 
 | ||||||
|             // Missed
 |             // Missed
 | ||||||
|             MWBase::Environment::get().getSoundManager()->playSound3D(ptr, "miss", 1.0f, 1.0f); |             sndMgr->playSound3D(ptr, "miss", 1.0f, 1.0f); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -429,13 +458,14 @@ namespace MWClass | ||||||
|             }; |             }; | ||||||
|             int hitslot = hitslots[(int)(::rand()/(RAND_MAX+1.0)*20.0)]; |             int hitslot = hitslots[(int)(::rand()/(RAND_MAX+1.0)*20.0)]; | ||||||
| 
 | 
 | ||||||
|             MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); |  | ||||||
|             MWWorld::InventoryStore &inv = getInventoryStore(ptr); |             MWWorld::InventoryStore &inv = getInventoryStore(ptr); | ||||||
|             MWWorld::ContainerStoreIterator armorslot = inv.getSlot(hitslot); |             MWWorld::ContainerStoreIterator armorslot = inv.getSlot(hitslot); | ||||||
|             MWWorld::Ptr armor = ((armorslot != inv.end()) ? *armorslot : MWWorld::Ptr()); |             MWWorld::Ptr armor = ((armorslot != inv.end()) ? *armorslot : MWWorld::Ptr()); | ||||||
|             if(!armor.isEmpty() && armor.getTypeName() == typeid(ESM::Armor).name()) |             if(!armor.isEmpty() && armor.getTypeName() == typeid(ESM::Armor).name()) | ||||||
|             { |             { | ||||||
|                 switch(get(armor).getEquipmentSkill(armor)) |                 if(object.isEmpty()) | ||||||
|  |                     sndMgr->playSound3D(ptr, "Hand To Hand Hit", 1.0f, 1.0f); | ||||||
|  |                 else switch(get(armor).getEquipmentSkill(armor)) | ||||||
|                 { |                 { | ||||||
|                     case ESM::Skill::LightArmor: |                     case ESM::Skill::LightArmor: | ||||||
|                         sndMgr->playSound3D(ptr, "Light Armor Hit", 1.0f, 1.0f); |                         sndMgr->playSound3D(ptr, "Light Armor Hit", 1.0f, 1.0f); | ||||||
|  | @ -448,12 +478,23 @@ namespace MWClass | ||||||
|                         break; |                         break; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 |             else if(object.isEmpty()) | ||||||
|             sndMgr->playSound3D(ptr, "Health Damage", 1.0f, 1.0f); |                 sndMgr->playSound3D(ptr, "Hand To Hand Hit", 1.0f, 1.0f); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         float health = getCreatureStats(ptr).getHealth().getCurrent() - damage; |         if(ishealth) | ||||||
|         setActorHealth(ptr, health, attacker); |         { | ||||||
|  |             if(damage > 0.0f) | ||||||
|  |                 sndMgr->playSound3D(ptr, "Health Damage", 1.0f, 1.0f); | ||||||
|  |             float health = getCreatureStats(ptr).getHealth().getCurrent() - damage; | ||||||
|  |             setActorHealth(ptr, health, attacker); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             MWMechanics::DynamicStat<float> fatigue(getCreatureStats(ptr).getFatigue()); | ||||||
|  |             fatigue.setCurrent(fatigue.getCurrent() - damage); | ||||||
|  |             getCreatureStats(ptr).setFatigue(fatigue); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void Npc::setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const |     void Npc::setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const | ||||||
|  |  | ||||||
|  | @ -70,7 +70,7 @@ namespace MWClass | ||||||
| 
 | 
 | ||||||
|             virtual void hit(const MWWorld::Ptr& ptr, int type) const; |             virtual void hit(const MWWorld::Ptr& ptr, int type) const; | ||||||
| 
 | 
 | ||||||
|             virtual void onHit(const MWWorld::Ptr& ptr, float damage, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const; |             virtual void onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const; | ||||||
| 
 | 
 | ||||||
|             virtual void setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const; |             virtual void setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -96,7 +96,7 @@ namespace MWWorld | ||||||
|         throw std::runtime_error("class cannot hit"); |         throw std::runtime_error("class cannot hit"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void Class::onHit(const Ptr& ptr, float damage, const Ptr& object, const Ptr& attacker, bool successful) const |     void Class::onHit(const Ptr& ptr, float damage, bool ishealth, const Ptr& object, const Ptr& attacker, bool successful) const | ||||||
|     { |     { | ||||||
|         throw std::runtime_error("class cannot be hit"); |         throw std::runtime_error("class cannot be hit"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -115,10 +115,11 @@ namespace MWWorld | ||||||
|             ///               enums. ignored for creature attacks.
 |             ///               enums. ignored for creature attacks.
 | ||||||
|             /// (default implementation: throw an exceoption)
 |             /// (default implementation: throw an exceoption)
 | ||||||
| 
 | 
 | ||||||
|             virtual void onHit(const Ptr& ptr, float damage, const Ptr &object, const Ptr &attacker, bool successful) const; |             virtual void onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const; | ||||||
|             ///< Alerts \a ptr that it's being hit for \a damage health by \a object (sword, arrow,
 |             ///< Alerts \a ptr that it's being hit for \a damage points to health if \a ishealth is
 | ||||||
|             /// etc). \a attacker specifies the actor responsible for the attack, and \a successful
 |             /// true (else fatigue) by \a object (sword, arrow, etc). \a attacker specifies the
 | ||||||
|             /// specifies if the hit is successful or not.
 |             /// actor responsible for the attack, and \a successful specifies if the hit is
 | ||||||
|  |             /// successful or not.
 | ||||||
| 
 | 
 | ||||||
|             virtual void setActorHealth(const Ptr& ptr, float health, const Ptr& attacker=Ptr()) const; |             virtual void setActorHealth(const Ptr& ptr, float health, const Ptr& attacker=Ptr()) const; | ||||||
|             ///< Sets a new current health value for the actor, optionally specifying the object causing
 |             ///< Sets a new current health value for the actor, optionally specifying the object causing
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue