mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-03-25 16:43:33 +00:00
Implement hand-to-hand attacks
This commit is contained in:
parent
b7e81dbc5b
commit
54f91d4b3a
@ -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…
x
Reference in New Issue
Block a user