forked from teamnwah/openmw-tes3coop
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.
|
||||
|
||||
|
@ -178,13 +178,19 @@ namespace MWClass
|
|||
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
|
||||
|
|
|
@ -44,7 +44,7 @@ namespace MWClass
|
|||
|
||||
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;
|
||||
|
||||
|
|
|
@ -346,10 +346,11 @@ namespace MWClass
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
bool healthdmg;
|
||||
float damage = 0.0f;
|
||||
if(!weapon.isEmpty())
|
||||
{
|
||||
|
@ -373,15 +374,43 @@ namespace MWClass
|
|||
}
|
||||
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")
|
||||
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.
|
||||
|
||||
if(!successful)
|
||||
|
@ -389,7 +418,7 @@ namespace MWClass
|
|||
// TODO: Handle HitAttemptOnMe script function
|
||||
|
||||
// Missed
|
||||
MWBase::Environment::get().getSoundManager()->playSound3D(ptr, "miss", 1.0f, 1.0f);
|
||||
sndMgr->playSound3D(ptr, "miss", 1.0f, 1.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -429,13 +458,14 @@ namespace MWClass
|
|||
};
|
||||
int hitslot = hitslots[(int)(::rand()/(RAND_MAX+1.0)*20.0)];
|
||||
|
||||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||
MWWorld::InventoryStore &inv = getInventoryStore(ptr);
|
||||
MWWorld::ContainerStoreIterator armorslot = inv.getSlot(hitslot);
|
||||
MWWorld::Ptr armor = ((armorslot != inv.end()) ? *armorslot : MWWorld::Ptr());
|
||||
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:
|
||||
sndMgr->playSound3D(ptr, "Light Armor Hit", 1.0f, 1.0f);
|
||||
|
@ -448,12 +478,23 @@ namespace MWClass
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sndMgr->playSound3D(ptr, "Health Damage", 1.0f, 1.0f);
|
||||
else if(object.isEmpty())
|
||||
sndMgr->playSound3D(ptr, "Hand To Hand Hit", 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
float health = getCreatureStats(ptr).getHealth().getCurrent() - damage;
|
||||
setActorHealth(ptr, health, attacker);
|
||||
if(ishealth)
|
||||
{
|
||||
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
|
||||
|
|
|
@ -70,7 +70,7 @@ namespace MWClass
|
|||
|
||||
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;
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ namespace MWWorld
|
|||
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");
|
||||
}
|
||||
|
|
|
@ -115,10 +115,11 @@ namespace MWWorld
|
|||
/// enums. ignored for creature attacks.
|
||||
/// (default implementation: throw an exceoption)
|
||||
|
||||
virtual void onHit(const Ptr& ptr, float damage, const Ptr &object, const Ptr &attacker, bool successful) const;
|
||||
///< Alerts \a ptr that it's being hit for \a damage health by \a object (sword, arrow,
|
||||
/// etc). \a attacker specifies the actor responsible for the attack, and \a successful
|
||||
/// specifies if the hit is successful or not.
|
||||
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 points to health if \a ishealth is
|
||||
/// true (else fatigue) by \a object (sword, arrow, etc). \a attacker specifies the
|
||||
/// 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;
|
||||
///< Sets a new current health value for the actor, optionally specifying the object causing
|
||||
|
|
Loading…
Reference in a new issue