Commit dd6edd21 authored by Chris Robinson's avatar Chris Robinson

Add a separate on-hit method to handle objects being hit

parent aa14656f
......@@ -310,12 +310,13 @@ namespace MWClass
// Get the weapon used (if hand-to-hand, weapon = inv.end())
MWWorld::InventoryStore &inv = getInventoryStore(ptr);
MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
if(weapon != inv.end() && weapon->getTypeName() != typeid(ESM::Weapon).name())
weapon = inv.end();
MWWorld::ContainerStoreIterator weaponslot = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
MWWorld::Ptr weapon = ((weaponslot != inv.end()) ? *weaponslot : MWWorld::Ptr());
if(!weapon.isEmpty() && weapon.getTypeName() != typeid(ESM::Weapon).name())
weapon = MWWorld::Ptr();
float dist = 100.0f * ((weapon != inv.end()) ?
weapon->get<ESM::Weapon>()->mBase->mData.mReach :
float dist = 100.0f * (!weapon.isEmpty() ?
weapon.get<ESM::Weapon>()->mBase->mData.mReach :
gmst.find("fHandToHandReach")->getFloat());
MWWorld::Ptr victim = world->getFacedObject(ptr, dist);
if(victim.isEmpty()) // Didn't hit anything
......@@ -329,8 +330,8 @@ namespace MWClass
}
int weapskill = ESM::Skill::HandToHand;
if(weapon != inv.end())
weapskill = MWWorld::Class::get(*weapon).getEquipmentSkill(*weapon);
if(!weapon.isEmpty())
weapskill = MWWorld::Class::get(weapon).getEquipmentSkill(weapon);
MWMechanics::CreatureStats &crstats = getCreatureStats(ptr);
MWMechanics::NpcStats &npcstats = getNpcStats(ptr);
......@@ -345,24 +346,23 @@ namespace MWClass
if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f)
{
// Missed
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
sndMgr->playSound3D(victim, "miss", 1.0f, 1.0f);
othercls.onHit(victim, 0.0f, weapon, ptr, false);
return;
}
if(weapon != inv.end())
float damage = 0.0f;
if(!weapon.isEmpty())
{
const unsigned char *attack = NULL;
if(type == MWMechanics::CreatureStats::AT_Chop)
attack = weapon->get<ESM::Weapon>()->mBase->mData.mChop;
attack = weapon.get<ESM::Weapon>()->mBase->mData.mChop;
else if(type == MWMechanics::CreatureStats::AT_Slash)
attack = weapon->get<ESM::Weapon>()->mBase->mData.mSlash;
attack = weapon.get<ESM::Weapon>()->mBase->mData.mSlash;
else if(type == MWMechanics::CreatureStats::AT_Thrust)
attack = weapon->get<ESM::Weapon>()->mBase->mData.mThrust;
attack = weapon.get<ESM::Weapon>()->mBase->mData.mThrust;
if(attack)
{
float damage = attack[0] + ((attack[1]-attack[0])*npcstats.getAttackStrength());
damage = attack[0] + ((attack[1]-attack[0])*npcstats.getAttackStrength());
damage *= 0.5f + (crstats.getAttribute(ESM::Attribute::Luck).getModified() / 100.0f);
//damage *= weapon_current_health / weapon_max_health;
if(!othercls.hasDetected(victim, ptr))
......@@ -370,30 +370,44 @@ namespace MWClass
damage *= gmst.find("fCombatCriticalStrikeMult")->getFloat();
MWBase::Environment::get().getWindowManager()->messageBox("#{sTargetCriticalStrike}");
}
damage /= std::min(1.0f + othercls.getArmorRating(victim) / std::max(1.0f, damage), 4.0f);
float health = othercls.getCreatureStats(victim).getHealth().getCurrent() - damage;
othercls.setActorHealth(victim, health, ptr);
damage /= std::min(1.0f + othercls.getArmorRating(victim)/std::max(1.0f, damage), 4.0f);
}
}
skillUsageSucceeded(ptr, weapskill, 0);
othercls.onHit(victim, damage, weapon, ptr, true);
}
void Npc::setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const
void Npc::onHit(const MWWorld::Ptr &ptr, float damage, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const
{
MWMechanics::CreatureStats &crstats = getCreatureStats(ptr);
float diff = health - crstats.getHealth().getCurrent();
// NOTE: 'object' and/or 'attacker' may be empty.
if(!successful)
{
// TODO: Handle HitAttemptOnMe script function
// Missed
MWBase::Environment::get().getSoundManager()->playSound3D(ptr, "miss", 1.0f, 1.0f);
return;
}
if(diff < 0.0f)
// TODO: Handle HitOnMe script function and OnPCHitMe script variable.
if(damage > 0.0f)
{
// 'ptr' is losing health. Play a 'hit' voiced dialog entry if not already saying
// something, alert the character controller, scripts, etc.
// NOTE: 'attacker' may be empty.
MWBase::Environment::get().getDialogueManager()->say(ptr, "hit");
}
float health = getCreatureStats(ptr).getHealth().getCurrent() - damage;
setActorHealth(ptr, health, attacker);
}
void Npc::setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const
{
MWMechanics::CreatureStats &crstats = getCreatureStats(ptr);
bool wasDead = crstats.isDead();
MWMechanics::DynamicStat<float> stat(crstats.getHealth());
......
......@@ -70,6 +70,8 @@ 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 setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const;
virtual boost::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
......
......@@ -96,6 +96,11 @@ 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
{
throw std::runtime_error("class cannot be hit");
}
void Class::setActorHealth(const Ptr& ptr, float health, const Ptr& attacker) const
{
throw std::runtime_error("class does not have actor health");
......
......@@ -115,6 +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 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
/// the change. Use this instead of using CreatureStats directly as this will make sure the
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment