forked from teamnwah/openmw-tes3coop
Implement weapon condition damage for ranged weapons (Fixes #1746)
This commit is contained in:
parent
eb1888a540
commit
216ebac2e9
5 changed files with 76 additions and 100 deletions
|
@ -255,23 +255,7 @@ namespace MWClass
|
|||
if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f)
|
||||
{
|
||||
victim.getClass().onHit(victim, 0.0f, false, MWWorld::Ptr(), ptr, false);
|
||||
|
||||
// Weapon health is reduced by 1 even if the attack misses
|
||||
const bool weaphashealth = !weapon.isEmpty() && weapon.getClass().hasItemHealth(weapon);
|
||||
if(weaphashealth)
|
||||
{
|
||||
int weaphealth = weapon.getClass().getItemHealth(weapon);
|
||||
|
||||
if (!MWBase::Environment::get().getWorld()->getGodModeState())
|
||||
{
|
||||
weaphealth -= std::min(1, weaphealth);
|
||||
weapon.getCellRef().setCharge(weaphealth);
|
||||
}
|
||||
|
||||
// Weapon broken? unequip it
|
||||
if (weapon.getCellRef().getCharge() == 0)
|
||||
weapon = *getInventoryStore(ptr).unequipItem(weapon, ptr);
|
||||
}
|
||||
MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -298,7 +282,6 @@ namespace MWClass
|
|||
|
||||
if (!weapon.isEmpty())
|
||||
{
|
||||
const bool weaphashealth = weapon.getClass().hasItemHealth(weapon);
|
||||
const unsigned char *attack = NULL;
|
||||
if(type == ESM::Weapon::AT_Chop)
|
||||
attack = weapon.get<ESM::Weapon>()->mBase->mData.mChop;
|
||||
|
@ -309,26 +292,10 @@ namespace MWClass
|
|||
if(attack)
|
||||
{
|
||||
damage = attack[0] + ((attack[1]-attack[0])*stats.getAttackStrength());
|
||||
damage *= 0.5f + (stats.getAttribute(ESM::Attribute::Luck).getModified() / 100.0f);
|
||||
if(weaphashealth)
|
||||
{
|
||||
int weapmaxhealth = weapon.getClass().getItemMaxHealth(weapon);
|
||||
int weaphealth = weapon.getClass().getItemHealth(weapon);
|
||||
damage *= float(weaphealth) / weapmaxhealth;
|
||||
|
||||
if (!MWBase::Environment::get().getWorld()->getGodModeState())
|
||||
{
|
||||
// Reduce weapon charge by at least one, but cap at 0
|
||||
weaphealth -= std::min(std::max(1,
|
||||
(int)(damage * gmst.find("fWeaponDamageMult")->getFloat())), weaphealth);
|
||||
|
||||
weapon.getCellRef().setCharge(weaphealth);
|
||||
}
|
||||
|
||||
// Weapon broken? unequip it
|
||||
if (weapon.getCellRef().getCharge() == 0)
|
||||
weapon = *getInventoryStore(ptr).unequipItem(weapon, ptr);
|
||||
}
|
||||
damage *= gmst.find("fDamageStrengthBase")->getFloat() +
|
||||
(stats.getAttribute(ESM::Attribute::Strength).getModified() * gmst.find("fDamageStrengthMult")->getFloat() * 0.1);
|
||||
MWMechanics::adjustWeaponDamage(damage, weapon);
|
||||
MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr);
|
||||
}
|
||||
|
||||
// Apply "On hit" enchanted weapons
|
||||
|
|
|
@ -529,24 +529,7 @@ namespace MWClass
|
|||
if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f)
|
||||
{
|
||||
othercls.onHit(victim, 0.0f, false, weapon, ptr, false);
|
||||
|
||||
// Weapon health is reduced by 1 even if the attack misses
|
||||
const bool weaphashealth = !weapon.isEmpty() && weapon.getClass().hasItemHealth(weapon);
|
||||
if(weaphashealth)
|
||||
{
|
||||
int weaphealth = weapon.getClass().getItemHealth(weapon);
|
||||
|
||||
if (!MWBase::Environment::get().getWorld()->getGodModeState())
|
||||
{
|
||||
weaphealth -= std::min(1, weaphealth);
|
||||
weapon.getCellRef().setCharge(weaphealth);
|
||||
}
|
||||
|
||||
// Weapon broken? unequip it
|
||||
if (weaphealth == 0)
|
||||
weapon = *inv.unequipItem(weapon, ptr);
|
||||
}
|
||||
|
||||
MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -555,7 +538,6 @@ namespace MWClass
|
|||
MWMechanics::NpcStats &stats = getNpcStats(ptr);
|
||||
if(!weapon.isEmpty())
|
||||
{
|
||||
const bool weaphashealth = weapon.getClass().hasItemHealth(weapon);
|
||||
const unsigned char *attack = NULL;
|
||||
if(type == ESM::Weapon::AT_Chop)
|
||||
attack = weapon.get<ESM::Weapon>()->mBase->mData.mChop;
|
||||
|
@ -568,27 +550,9 @@ namespace MWClass
|
|||
damage = attack[0] + ((attack[1]-attack[0])*stats.getAttackStrength());
|
||||
damage *= gmst.fDamageStrengthBase->getFloat() +
|
||||
(stats.getAttribute(ESM::Attribute::Strength).getModified() * gmst.fDamageStrengthMult->getFloat() * 0.1);
|
||||
if(weaphashealth)
|
||||
{
|
||||
int weapmaxhealth = weapon.getClass().getItemMaxHealth(weapon);
|
||||
int weaphealth = weapon.getClass().getItemHealth(weapon);
|
||||
|
||||
damage *= float(weaphealth) / weapmaxhealth;
|
||||
|
||||
if (!MWBase::Environment::get().getWorld()->getGodModeState())
|
||||
{
|
||||
// Reduce weapon charge by at least one, but cap at 0
|
||||
weaphealth -= std::min(std::max(1,
|
||||
(int)(damage * store.find("fWeaponDamageMult")->getFloat())), weaphealth);
|
||||
|
||||
weapon.getCellRef().setCharge(weaphealth);
|
||||
}
|
||||
|
||||
// Weapon broken? unequip it
|
||||
if (weaphealth == 0)
|
||||
weapon = *inv.unequipItem(weapon, ptr);
|
||||
}
|
||||
}
|
||||
MWMechanics::adjustWeaponDamage(damage, weapon);
|
||||
MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr);
|
||||
healthdmg = true;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -169,12 +169,12 @@ namespace MWMechanics
|
|||
|
||||
MWMechanics::CreatureStats& attackerStats = attacker.getClass().getCreatureStats(attacker);
|
||||
|
||||
const MWWorld::Class &othercls = victim.getClass();
|
||||
if(!othercls.isActor()) // Can't hit non-actors
|
||||
return;
|
||||
MWMechanics::CreatureStats &otherstats = victim.getClass().getCreatureStats(victim);
|
||||
if(otherstats.isDead()) // Can't hit dead actors
|
||||
if(victim.isEmpty() || !victim.getClass().isActor() || victim.getClass().getCreatureStats(victim).isDead())
|
||||
// Can't hit non-actors or dead actors
|
||||
{
|
||||
reduceWeaponCondition(0.f, false, weapon, attacker);
|
||||
return;
|
||||
}
|
||||
|
||||
if(attacker.getRefData().getHandle() == "player")
|
||||
MWBase::Environment::get().getWindowManager()->setEnemy(victim);
|
||||
|
@ -189,6 +189,7 @@ namespace MWMechanics
|
|||
if((::rand()/(RAND_MAX+1.0)) > getHitChance(attacker, victim, skillValue)/100.0f)
|
||||
{
|
||||
victim.getClass().onHit(victim, 0.0f, false, projectile, attacker, false);
|
||||
MWMechanics::reduceWeaponCondition(0.f, false, weapon, attacker);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -209,6 +210,8 @@ namespace MWMechanics
|
|||
damage *= fDamageStrengthBase +
|
||||
(attackerStats.getAttribute(ESM::Attribute::Strength).getModified() * fDamageStrengthMult * 0.1);
|
||||
|
||||
adjustWeaponDamage(damage, weapon);
|
||||
reduceWeaponCondition(damage, true, weapon, attacker);
|
||||
|
||||
if(attacker.getRefData().getHandle() == "player")
|
||||
attacker.getClass().skillUsageSucceeded(attacker, weapskill, 0);
|
||||
|
@ -295,4 +298,42 @@ namespace MWMechanics
|
|||
}
|
||||
}
|
||||
|
||||
void reduceWeaponCondition(float damage, bool hit, MWWorld::Ptr &weapon, const MWWorld::Ptr &attacker)
|
||||
{
|
||||
if (weapon.isEmpty())
|
||||
return;
|
||||
|
||||
if (!hit)
|
||||
damage = 0.f;
|
||||
|
||||
const bool weaphashealth = weapon.getClass().hasItemHealth(weapon);
|
||||
if(weaphashealth)
|
||||
{
|
||||
int weaphealth = weapon.getClass().getItemHealth(weapon);
|
||||
|
||||
const float fWeaponDamageMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fWeaponDamageMult")->getFloat();
|
||||
float x = std::max(1.f, fWeaponDamageMult * damage);
|
||||
|
||||
weaphealth -= std::min(int(x), weaphealth);
|
||||
weapon.getCellRef().setCharge(weaphealth);
|
||||
|
||||
// Weapon broken? unequip it
|
||||
if (weaphealth == 0)
|
||||
weapon = *attacker.getClass().getInventoryStore(attacker).unequipItem(weapon, attacker);
|
||||
}
|
||||
}
|
||||
|
||||
void adjustWeaponDamage(float &damage, const MWWorld::Ptr &weapon)
|
||||
{
|
||||
if (weapon.isEmpty())
|
||||
return;
|
||||
|
||||
const bool weaphashealth = weapon.getClass().hasItemHealth(weapon);
|
||||
if(weaphashealth)
|
||||
{
|
||||
int weaphealth = weapon.getClass().getItemHealth(weapon);
|
||||
int weapmaxhealth = weapon.getClass().getItemMaxHealth(weapon);
|
||||
damage *= (float(weaphealth) / weapmaxhealth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ bool blockMeleeAttack (const MWWorld::Ptr& attacker, const MWWorld::Ptr& blocker
|
|||
void resistNormalWeapon (const MWWorld::Ptr& actor, const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon, float& damage);
|
||||
|
||||
/// @note for a thrown weapon, \a weapon == \a projectile, for bows/crossbows, \a projectile is the arrow/bolt
|
||||
/// @note \a victim may be empty (e.g. for a hit on terrain), a non-actor (environment objects) or an actor
|
||||
void projectileHit (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, MWWorld::Ptr weapon, const MWWorld::Ptr& projectile,
|
||||
const Ogre::Vector3& hitPosition);
|
||||
|
||||
|
@ -22,6 +23,15 @@ float getHitChance (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, in
|
|||
/// Applies damage to attacker based on the victim's elemental shields.
|
||||
void applyElementalShields(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim);
|
||||
|
||||
/// @param damage Unmitigated weapon damage of the attack
|
||||
/// @param hit Was the attack successful?
|
||||
/// @param weapon The weapon used.
|
||||
/// @note if the weapon is unequipped as result of condition damage, a new Ptr will be assigned to \a weapon.
|
||||
void reduceWeaponCondition (float damage, bool hit, MWWorld::Ptr& weapon, const MWWorld::Ptr& attacker);
|
||||
|
||||
/// Adjust weapon damage based on its condition. A used weapon will be less effective.
|
||||
void adjustWeaponDamage (float& damage, const MWWorld::Ptr& weapon);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -247,29 +247,23 @@ namespace MWWorld
|
|||
if (obstacle == caster)
|
||||
continue;
|
||||
|
||||
if (obstacle.isEmpty())
|
||||
MWWorld::ManualRef projectileRef(MWBase::Environment::get().getWorld()->getStore(), it->mId);
|
||||
|
||||
// Try to get a Ptr to the bow that was used. It might no longer exist.
|
||||
MWWorld::Ptr bow = projectileRef.getPtr();
|
||||
if (!caster.isEmpty())
|
||||
{
|
||||
// Terrain
|
||||
MWWorld::InventoryStore& inv = caster.getClass().getInventoryStore(caster);
|
||||
MWWorld::ContainerStoreIterator invIt = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
if (invIt != inv.end() && Misc::StringUtils::ciEqual(invIt->getCellRef().getRefId(), it->mBowId))
|
||||
bow = *invIt;
|
||||
}
|
||||
else if (obstacle.getClass().isActor())
|
||||
{
|
||||
MWWorld::ManualRef projectileRef(MWBase::Environment::get().getWorld()->getStore(), it->mId);
|
||||
|
||||
// Try to get a Ptr to the bow that was used. It might no longer exist.
|
||||
MWWorld::Ptr bow = projectileRef.getPtr();
|
||||
if (!caster.isEmpty())
|
||||
{
|
||||
MWWorld::InventoryStore& inv = caster.getClass().getInventoryStore(caster);
|
||||
MWWorld::ContainerStoreIterator invIt = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
if (invIt != inv.end() && Misc::StringUtils::ciEqual(invIt->getCellRef().getRefId(), it->mBowId))
|
||||
bow = *invIt;
|
||||
}
|
||||
if (caster.isEmpty())
|
||||
caster = obstacle;
|
||||
|
||||
if (caster.isEmpty())
|
||||
caster = obstacle;
|
||||
MWMechanics::projectileHit(caster, obstacle, bow, projectileRef.getPtr(), pos + (newPos - pos) * cIt->first);
|
||||
|
||||
MWMechanics::projectileHit(caster, obstacle, bow, projectileRef.getPtr(), pos + (newPos - pos) * cIt->first);
|
||||
}
|
||||
hit = true;
|
||||
}
|
||||
if (hit)
|
||||
|
|
Loading…
Reference in a new issue