Commit 0c8d4d9b authored by Chris Robinson's avatar Chris Robinson

Add beginnings of melee hits

parent 45302f9e
......@@ -148,6 +148,39 @@ namespace MWClass
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mCreatureStats;
}
void Creature::attack(const MWWorld::Ptr& ptr, int type) const
{
}
void Creature::setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const
{
MWMechanics::CreatureStats &crstats = getCreatureStats(ptr);
float diff = health - crstats.getHealth().getCurrent();
if(diff < 0.0f)
{
// actor is losing health. Alert the character controller, scripts, etc.
// NOTE: 'attacker' may be empty.
}
bool wasDead = crstats.isDead();
MWMechanics::DynamicStat<float> stat(crstats.getHealth());
stat.setCurrent(health);
crstats.setHealth(stat);
if(!wasDead && crstats.isDead())
{
// actor was just killed
}
else if(wasDead && !crstats.isDead())
{
// actor was just resurrected
}
}
boost::shared_ptr<MWWorld::Action> Creature::activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor) const
{
......
......@@ -42,6 +42,10 @@ namespace MWClass
virtual MWMechanics::CreatureStats& getCreatureStats (const MWWorld::Ptr& ptr) const;
///< Return creature stats
virtual void attack(const MWWorld::Ptr& ptr, int type) 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,
const MWWorld::Ptr& actor) const;
///< Generate action for activation
......
......@@ -288,6 +288,74 @@ namespace MWClass
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mNpcStats;
}
void Npc::attack(const MWWorld::Ptr& ptr, int type) const
{
// FIXME: Detect what was hit
MWWorld::Ptr victim;
if(victim.isEmpty()) // Didn't hit anything
return;
const MWWorld::Class &othercls = MWWorld::Class::get(victim);
if(!othercls.isActor() || othercls.getCreatureStats(victim).isDead())
{
// Can't hit non-actors, or dead actors
return;
}
// Get the weapon used
MWWorld::LiveCellRef<ESM::Weapon> *weapon = NULL;
MWWorld::InventoryStore &inv = Npc::getInventoryStore(ptr);
MWWorld::ContainerStoreIterator iter = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
if(iter != inv.end() && iter->getTypeName() == typeid(ESM::Weapon).name())
weapon = iter->get<ESM::Weapon>();
// TODO: Check weapon skill against victim's armor skill (if !weapon, attacker is using
// hand-to-hand, which damages fatique unless in werewolf form).
if(weapon)
{
float health = othercls.getCreatureStats(victim).getHealth().getCurrent();
// FIXME: Modify damage based on strength?
if(type == MWMechanics::CreatureStats::AT_Chop)
health -= weapon->mBase->mData.mChop[1];
else if(type == MWMechanics::CreatureStats::AT_Slash)
health -= weapon->mBase->mData.mSlash[1];
else if(type == MWMechanics::CreatureStats::AT_Thrust)
health -= weapon->mBase->mData.mThrust[1];
othercls.setActorHealth(victim, std::max(health, 0.0f), ptr);
}
}
void Npc::setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const
{
MWMechanics::CreatureStats &crstats = getCreatureStats(ptr);
float diff = health - crstats.getHealth().getCurrent();
if(diff < 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.
}
bool wasDead = crstats.isDead();
MWMechanics::DynamicStat<float> stat(crstats.getHealth());
stat.setCurrent(health);
crstats.setHealth(stat);
if(!wasDead && crstats.isDead())
{
// actor was just killed
}
else if(wasDead && !crstats.isDead())
{
// actor was just resurrected
}
}
boost::shared_ptr<MWWorld::Action> Npc::activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor) const
{
......
......@@ -68,6 +68,10 @@ namespace MWClass
virtual MWWorld::InventoryStore& getInventoryStore (const MWWorld::Ptr& ptr) const;
///< Return inventory store
virtual void attack(const MWWorld::Ptr& ptr, int type) 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,
const MWWorld::Ptr& actor) const;
///< Generate action for activation
......
......@@ -14,6 +14,7 @@
#include "../mwbase/world.hpp"
#include "../mwmechanics/character.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "../mwworld/class.hpp"
namespace MWRender
......@@ -548,6 +549,14 @@ bool Animation::handleTextKey(AnimState &state, const std::string &groupname, co
showWeapons(true);
else if(evt.compare(off, len, "unequip detach") == 0)
showWeapons(false);
else if(evt.compare(off, len, "chop hit") == 0)
MWWorld::Class::get(mPtr).attack(mPtr, MWMechanics::CreatureStats::AT_Chop);
else if(evt.compare(off, len, "slash hit") == 0)
MWWorld::Class::get(mPtr).attack(mPtr, MWMechanics::CreatureStats::AT_Slash);
else if(evt.compare(off, len, "thrust hit") == 0)
MWWorld::Class::get(mPtr).attack(mPtr, MWMechanics::CreatureStats::AT_Thrust);
else if(evt.compare(off, len, "hit") == 0)
MWWorld::Class::get(mPtr).attack(mPtr, -1);
return true;
}
......
......@@ -77,6 +77,16 @@ namespace MWWorld
throw std::runtime_error ("class does not have item health");
}
void Class::attack(const Ptr& ptr, int type) const
{
throw std::runtime_error("class cannot attack");
}
void Class::setActorHealth(const Ptr& ptr, float health, const Ptr& attacker) const
{
throw std::runtime_error("class does not have actor health");
}
boost::shared_ptr<Action> Class::activate (const Ptr& ptr, const Ptr& actor) const
{
return boost::shared_ptr<Action> (new NullAction);
......
......@@ -105,6 +105,19 @@ namespace MWWorld
///< Return item max health or throw an exception, if class does not have item health
/// (default implementation: throw an exceoption)
virtual void attack(const Ptr& ptr, int type) const;
///< Execute a melee hit, using the current weapon. This will check the relevant skills
/// of the given attacker, and whoever is hit.
/// \a type - type of attack, one of the MWMechanics::CreatureStats::AttackType enums.
/// ignored for creature attacks.
/// (default implementation: throw an exceoption)
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
/// correct dialog and actor states are properly handled when being hurt or healed.
/// (default implementation: throw an exceoption)
virtual boost::shared_ptr<Action> activate (const Ptr& ptr, const Ptr& actor) const;
///< Generate action for activation (default implementation: return a null action).
......
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