forked from mirror/openmw-tes3mp
Merge pull request #128 from OpenMW/master while resolving conflicts
# Conflicts: # apps/openmw/mwmechanics/combat.cpp
This commit is contained in:
commit
fa8650f99a
9 changed files with 116 additions and 127 deletions
|
@ -537,8 +537,9 @@ namespace MWBase
|
||||||
|
|
||||||
virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos) = 0;
|
virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos) = 0;
|
||||||
|
|
||||||
virtual void explodeSpell (const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster,
|
virtual void explodeSpell(const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster,
|
||||||
const MWWorld::Ptr& ignore, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) = 0;
|
const MWWorld::Ptr& ignore, ESM::RangeType rangeType, const std::string& id,
|
||||||
|
const std::string& sourceName, const bool fromProjectile=false) = 0;
|
||||||
|
|
||||||
virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0;
|
virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0;
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ float signedAngleRadians (const osg::Vec3f& v1, const osg::Vec3f& v2, const osg:
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
|
||||||
bool applyOnStrikeEnchantment (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, const MWWorld::Ptr& object, const osg::Vec3f& hitPosition)
|
bool applyOnStrikeEnchantment(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, const MWWorld::Ptr& object, const osg::Vec3f& hitPosition, const bool fromProjectile)
|
||||||
{
|
{
|
||||||
std::string enchantmentName = !object.isEmpty() ? object.getClass().getEnchantment(object) : "";
|
std::string enchantmentName = !object.isEmpty() ? object.getClass().getEnchantment(object) : "";
|
||||||
if (!enchantmentName.empty())
|
if (!enchantmentName.empty())
|
||||||
|
@ -47,7 +47,7 @@ namespace MWMechanics
|
||||||
enchantmentName);
|
enchantmentName);
|
||||||
if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes)
|
if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes)
|
||||||
{
|
{
|
||||||
MWMechanics::CastSpell cast(attacker, victim);
|
MWMechanics::CastSpell cast(attacker, victim, fromProjectile);
|
||||||
cast.mHitPosition = hitPosition;
|
cast.mHitPosition = hitPosition;
|
||||||
cast.cast(object, false);
|
cast.cast(object, false);
|
||||||
return true;
|
return true;
|
||||||
|
@ -180,7 +180,7 @@ namespace MWMechanics
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResistsWeapons}");
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResistsWeapons}");
|
||||||
}
|
}
|
||||||
|
|
||||||
void projectileHit(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, MWWorld::Ptr weapon, const MWWorld::Ptr &projectile,
|
void projectileHit(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, MWWorld::Ptr weapon, const MWWorld::Ptr& projectile,
|
||||||
const osg::Vec3f& hitPosition, float attackStrength)
|
const osg::Vec3f& hitPosition, float attackStrength)
|
||||||
{
|
{
|
||||||
if (mwmp::Main::get().getNetworking()->isDedicatedPlayer(attacker))
|
if (mwmp::Main::get().getNetworking()->isDedicatedPlayer(attacker))
|
||||||
|
@ -188,68 +188,68 @@ namespace MWMechanics
|
||||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
|
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
|
||||||
|
|
||||||
if(victim.isEmpty() || !victim.getClass().isActor() || victim.getClass().getCreatureStats(victim).isDead())
|
bool validVictim = !victim.isEmpty() && victim.getClass().isActor();
|
||||||
// Can't hit non-actors or dead actors
|
|
||||||
{
|
|
||||||
reduceWeaponCondition(0.f, false, weapon, attacker);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(attacker == getPlayer())
|
float damage = 0.f;
|
||||||
MWBase::Environment::get().getWindowManager()->setEnemy(victim);
|
if (validVictim)
|
||||||
|
|
||||||
int weapskill = ESM::Skill::Marksman;
|
|
||||||
if(!weapon.isEmpty())
|
|
||||||
weapskill = weapon.getClass().getEquipmentSkill(weapon);
|
|
||||||
|
|
||||||
int skillValue = attacker.getClass().getSkill(attacker,
|
|
||||||
weapon.getClass().getEquipmentSkill(weapon));
|
|
||||||
|
|
||||||
if (attacker == MWBase::Environment::get().getWorld()->getPlayerPtr())
|
|
||||||
mwmp::Main::get().getLocalPlayer()->getAttack()->success = true;
|
|
||||||
|
|
||||||
if (Misc::Rng::roll0to99() >= getHitChance(attacker, victim, skillValue))
|
|
||||||
{
|
{
|
||||||
if (attacker == getPlayer())
|
if (attacker == getPlayer())
|
||||||
mwmp::Main::get().getLocalPlayer()->getAttack()->success = false;
|
MWBase::Environment::get().getWindowManager()->setEnemy(victim);
|
||||||
victim.getClass().onHit(victim, 0.0f, false, projectile, attacker, osg::Vec3f(), false);
|
|
||||||
MWMechanics::reduceWeaponCondition(0.f, false, weapon, attacker);
|
int weaponSkill = ESM::Skill::Marksman;
|
||||||
return;
|
if (!weapon.isEmpty())
|
||||||
|
weaponSkill = weapon.getClass().getEquipmentSkill(weapon);
|
||||||
|
|
||||||
|
int skillValue = attacker.getClass().getSkill(attacker, weapon.getClass().getEquipmentSkill(weapon));
|
||||||
|
|
||||||
|
if (attacker == MWBase::Environment::get().getWorld()->getPlayerPtr())
|
||||||
|
mwmp::Main::get().getLocalPlayer()->getAttack()->success = true;
|
||||||
|
|
||||||
|
if (Misc::Rng::roll0to99() >= getHitChance(attacker, victim, skillValue))
|
||||||
|
{
|
||||||
|
if (attacker == getPlayer())
|
||||||
|
mwmp::Main::get().getLocalPlayer()->getAttack()->success = false;
|
||||||
|
victim.getClass().onHit(victim, damage, false, projectile, attacker, osg::Vec3f(), false);
|
||||||
|
MWMechanics::reduceWeaponCondition(damage, false, weapon, attacker);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned char* attack = weapon.get<ESM::Weapon>()->mBase->mData.mChop;
|
||||||
|
damage = attack[0] + ((attack[1] - attack[0]) * attackStrength); // Bow/crossbow damage
|
||||||
|
|
||||||
|
// Arrow/bolt damage
|
||||||
|
// NB in case of thrown weapons, we are applying the damage twice since projectile == weapon
|
||||||
|
attack = projectile.get<ESM::Weapon>()->mBase->mData.mChop;
|
||||||
|
damage += attack[0] + ((attack[1] - attack[0]) * attackStrength);
|
||||||
|
|
||||||
|
adjustWeaponDamage(damage, weapon, attacker);
|
||||||
|
|
||||||
|
if(attacker == getPlayer())
|
||||||
|
attacker.getClass().skillUsageSucceeded(attacker, weaponSkill, 0);
|
||||||
|
|
||||||
|
if (victim.getClass().getCreatureStats(victim).getKnockedDown())
|
||||||
|
damage *= gmst.find("fCombatKODamageMult")->getFloat();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reduceWeaponCondition(damage, validVictim, weapon, attacker);
|
||||||
|
|
||||||
const unsigned char* attack = weapon.get<ESM::Weapon>()->mBase->mData.mChop;
|
// Apply "On hit" effect of the weapon & projectile
|
||||||
float damage = attack[0] + ((attack[1]-attack[0])*attackStrength); // Bow/crossbow damage
|
bool appliedEnchantment = applyOnStrikeEnchantment(attacker, victim, weapon, hitPosition, true);
|
||||||
|
|
||||||
// Arrow/bolt damage
|
|
||||||
// NB in case of thrown weapons, we are applying the damage twice since projectile == weapon
|
|
||||||
attack = projectile.get<ESM::Weapon>()->mBase->mData.mChop;
|
|
||||||
damage += attack[0] + ((attack[1]-attack[0])*attackStrength);
|
|
||||||
|
|
||||||
adjustWeaponDamage(damage, weapon, attacker);
|
|
||||||
reduceWeaponCondition(damage, true, weapon, attacker);
|
|
||||||
|
|
||||||
if(attacker == getPlayer())
|
|
||||||
attacker.getClass().skillUsageSucceeded(attacker, weapskill, 0);
|
|
||||||
|
|
||||||
if (victim.getClass().getCreatureStats(victim).getKnockedDown())
|
|
||||||
damage *= gmst.find("fCombatKODamageMult")->getFloat();
|
|
||||||
|
|
||||||
// Apply "On hit" effect of the weapon
|
|
||||||
bool appliedEnchantment = applyOnStrikeEnchantment(attacker, victim, weapon, hitPosition);
|
|
||||||
if (weapon != projectile)
|
if (weapon != projectile)
|
||||||
appliedEnchantment = applyOnStrikeEnchantment(attacker, victim, projectile, hitPosition);
|
appliedEnchantment = applyOnStrikeEnchantment(attacker, victim, projectile, hitPosition, true);
|
||||||
|
|
||||||
// Non-enchanted arrows shot at enemies have a chance to turn up in their inventory
|
if (validVictim)
|
||||||
if (victim != getPlayer()
|
|
||||||
&& !appliedEnchantment)
|
|
||||||
{
|
{
|
||||||
float fProjectileThrownStoreChance = gmst.find("fProjectileThrownStoreChance")->getFloat();
|
// Non-enchanted arrows shot at enemies have a chance to turn up in their inventory
|
||||||
if (Misc::Rng::rollProbability() < fProjectileThrownStoreChance / 100.f)
|
if (victim != getPlayer() && !appliedEnchantment)
|
||||||
victim.getClass().getContainerStore(victim).add(projectile, 1, victim);
|
{
|
||||||
}
|
float fProjectileThrownStoreChance = gmst.find("fProjectileThrownStoreChance")->getFloat();
|
||||||
|
if (Misc::Rng::rollProbability() < fProjectileThrownStoreChance / 100.f)
|
||||||
|
victim.getClass().getContainerStore(victim).add(projectile, 1, victim);
|
||||||
|
}
|
||||||
|
|
||||||
victim.getClass().onHit(victim, damage, true, projectile, attacker, hitPosition, true);
|
victim.getClass().onHit(victim, damage, true, projectile, attacker, hitPosition, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float getHitChance(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, int skillValue)
|
float getHitChance(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, int skillValue)
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
|
||||||
bool applyOnStrikeEnchantment(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, const MWWorld::Ptr& object, const osg::Vec3f& hitPosition);
|
bool applyOnStrikeEnchantment(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, const MWWorld::Ptr& object, const osg::Vec3f& hitPosition,
|
||||||
|
const bool fromProjectile=false);
|
||||||
|
|
||||||
/// @return can we block the attack?
|
/// @return can we block the attack?
|
||||||
bool blockMeleeAttack (const MWWorld::Ptr& attacker, const MWWorld::Ptr& blocker, const MWWorld::Ptr& weapon, float damage, float attackStrength);
|
bool blockMeleeAttack (const MWWorld::Ptr& attacker, const MWWorld::Ptr& blocker, const MWWorld::Ptr& weapon, float damage, float attackStrength);
|
||||||
|
|
|
@ -278,12 +278,13 @@ namespace MWMechanics
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CastSpell::CastSpell(const MWWorld::Ptr &caster, const MWWorld::Ptr &target)
|
CastSpell::CastSpell(const MWWorld::Ptr &caster, const MWWorld::Ptr &target, const bool fromProjectile)
|
||||||
: mCaster(caster)
|
: mCaster(caster)
|
||||||
, mTarget(target)
|
, mTarget(target)
|
||||||
, mStack(false)
|
, mStack(false)
|
||||||
, mHitPosition(0,0,0)
|
, mHitPosition(0,0,0)
|
||||||
, mAlwaysSucceed(false)
|
, mAlwaysSucceed(false)
|
||||||
|
, mFromProjectile(fromProjectile)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,7 +306,7 @@ namespace MWMechanics
|
||||||
void CastSpell::inflict(const MWWorld::Ptr &target, const MWWorld::Ptr &caster,
|
void CastSpell::inflict(const MWWorld::Ptr &target, const MWWorld::Ptr &caster,
|
||||||
const ESM::EffectList &effects, ESM::RangeType range, bool reflected, bool exploded)
|
const ESM::EffectList &effects, ESM::RangeType range, bool reflected, bool exploded)
|
||||||
{
|
{
|
||||||
if (target.getClass().isActor() && target.getClass().getCreatureStats(target).isDead())
|
if (!target.isEmpty() && target.getClass().isActor() && target.getClass().getCreatureStats(target).isDead())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// If none of the effects need to apply, we can early-out
|
// If none of the effects need to apply, we can early-out
|
||||||
|
@ -323,7 +324,7 @@ namespace MWMechanics
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search (mId);
|
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search (mId);
|
||||||
if (spell && (spell->mData.mType == ESM::Spell::ST_Disease || spell->mData.mType == ESM::Spell::ST_Blight))
|
if (spell && !target.isEmpty() && (spell->mData.mType == ESM::Spell::ST_Disease || spell->mData.mType == ESM::Spell::ST_Blight))
|
||||||
{
|
{
|
||||||
int requiredResistance = (spell->mData.mType == ESM::Spell::ST_Disease) ?
|
int requiredResistance = (spell->mData.mType == ESM::Spell::ST_Disease) ?
|
||||||
ESM::MagicEffect::ResistCommonDisease
|
ESM::MagicEffect::ResistCommonDisease
|
||||||
|
@ -346,13 +347,13 @@ namespace MWMechanics
|
||||||
// This is required for Weakness effects in a spell to apply to any subsequent effects in the spell.
|
// This is required for Weakness effects in a spell to apply to any subsequent effects in the spell.
|
||||||
// Otherwise, they'd only apply after the whole spell was added.
|
// Otherwise, they'd only apply after the whole spell was added.
|
||||||
MagicEffects targetEffects;
|
MagicEffects targetEffects;
|
||||||
if (target.getClass().isActor())
|
if (!target.isEmpty() && target.getClass().isActor())
|
||||||
targetEffects += target.getClass().getCreatureStats(target).getMagicEffects();
|
targetEffects += target.getClass().getCreatureStats(target).getMagicEffects();
|
||||||
|
|
||||||
bool castByPlayer = (!caster.isEmpty() && caster == getPlayer());
|
bool castByPlayer = (!caster.isEmpty() && caster == getPlayer());
|
||||||
|
|
||||||
ActiveSpells targetSpells;
|
ActiveSpells targetSpells;
|
||||||
if (target.getClass().isActor())
|
if (!target.isEmpty() && target.getClass().isActor())
|
||||||
targetSpells = target.getClass().getCreatureStats(target).getActiveSpells();
|
targetSpells = target.getClass().getCreatureStats(target).getActiveSpells();
|
||||||
|
|
||||||
bool canCastAnEffect = false; // For bound equipment.If this remains false
|
bool canCastAnEffect = false; // For bound equipment.If this remains false
|
||||||
|
@ -360,7 +361,7 @@ namespace MWMechanics
|
||||||
// effects, we display a "can't re-cast" message
|
// effects, we display a "can't re-cast" message
|
||||||
|
|
||||||
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt (effects.mList.begin());
|
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt (effects.mList.begin());
|
||||||
effectIt!=effects.mList.end(); ++effectIt)
|
!target.isEmpty() && effectIt != effects.mList.end(); ++effectIt)
|
||||||
{
|
{
|
||||||
if (effectIt->mRange != range)
|
if (effectIt->mRange != range)
|
||||||
continue;
|
continue;
|
||||||
|
@ -569,18 +570,20 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!exploded)
|
if (!exploded)
|
||||||
MWBase::Environment::get().getWorld()->explodeSpell(mHitPosition, effects, caster, target, range, mId, mSourceName);
|
MWBase::Environment::get().getWorld()->explodeSpell(mHitPosition, effects, caster, target, range, mId, mSourceName, mFromProjectile);
|
||||||
|
|
||||||
if (!reflectedEffects.mList.empty())
|
if (!target.isEmpty()) {
|
||||||
inflict(caster, target, reflectedEffects, range, true, exploded);
|
if (!reflectedEffects.mList.empty())
|
||||||
|
inflict(caster, target, reflectedEffects, range, true, exploded);
|
||||||
|
|
||||||
if (!appliedLastingEffects.empty())
|
if (!appliedLastingEffects.empty())
|
||||||
{
|
{
|
||||||
int casterActorId = -1;
|
int casterActorId = -1;
|
||||||
if (!caster.isEmpty() && caster.getClass().isActor())
|
if (!caster.isEmpty() && caster.getClass().isActor())
|
||||||
casterActorId = caster.getClass().getCreatureStats(caster).getActorId();
|
casterActorId = caster.getClass().getCreatureStats(caster).getActorId();
|
||||||
target.getClass().getCreatureStats(target).getActiveSpells().addSpell(mId, mStack, appliedLastingEffects,
|
target.getClass().getCreatureStats(target).getActiveSpells().addSpell(mId, mStack, appliedLastingEffects,
|
||||||
mSourceName, casterActorId);
|
mSourceName, casterActorId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -761,14 +764,19 @@ namespace MWMechanics
|
||||||
|
|
||||||
inflict(mCaster, mCaster, enchantment->mEffects, ESM::RT_Self);
|
inflict(mCaster, mCaster, enchantment->mEffects, ESM::RT_Self);
|
||||||
|
|
||||||
if (!mTarget.isEmpty())
|
bool isProjectile = false;
|
||||||
|
if (item.getTypeName() == typeid(ESM::Weapon).name())
|
||||||
{
|
{
|
||||||
inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch);
|
const MWWorld::LiveCellRef<ESM::Weapon> *ref = item.get<ESM::Weapon>();
|
||||||
|
isProjectile = ref->mBase->mData.mType == ESM::Weapon::Arrow || ref->mBase->mData.mType == ESM::Weapon::Bolt || ref->mBase->mData.mType == ESM::Weapon::MarksmanThrown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isProjectile || !mTarget.isEmpty())
|
||||||
|
inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch);
|
||||||
|
|
||||||
if (launchProjectile)
|
if (launchProjectile)
|
||||||
launchMagicBolt(enchantment->mEffects);
|
launchMagicBolt(enchantment->mEffects);
|
||||||
else if (!mTarget.isEmpty())
|
else if (isProjectile || !mTarget.isEmpty())
|
||||||
inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Target);
|
inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Target);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -78,9 +78,10 @@ namespace MWMechanics
|
||||||
std::string mSourceName; // Display name for spell, potion, etc
|
std::string mSourceName; // Display name for spell, potion, etc
|
||||||
osg::Vec3f mHitPosition; // Used for spawning area orb
|
osg::Vec3f mHitPosition; // Used for spawning area orb
|
||||||
bool mAlwaysSucceed; // Always succeed spells casted by NPCs/creatures regardless of their chance (default: false)
|
bool mAlwaysSucceed; // Always succeed spells casted by NPCs/creatures regardless of their chance (default: false)
|
||||||
|
bool mFromProjectile; // True if spell is cast by enchantment of some projectile (arrow, bolt or thrown weapon)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CastSpell(const MWWorld::Ptr& caster, const MWWorld::Ptr& target);
|
CastSpell(const MWWorld::Ptr& caster, const MWWorld::Ptr& target, const bool fromProjectile=false);
|
||||||
|
|
||||||
bool cast (const ESM::Spell* spell);
|
bool cast (const ESM::Spell* spell);
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
#include <components/nifosg/controller.hpp>
|
#include <components/nifosg/controller.hpp>
|
||||||
#include <components/sceneutil/controller.hpp>
|
#include <components/sceneutil/controller.hpp>
|
||||||
|
|
||||||
|
#include <components/shader/shadermanager.hpp>
|
||||||
|
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
#include <components/esm/loadcell.hpp>
|
#include <components/esm/loadcell.hpp>
|
||||||
|
@ -189,29 +191,6 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
osg::ref_ptr<osg::Shader> readShader (osg::Shader::Type type, const std::string& file, const std::map<std::string, std::string>& defineMap = std::map<std::string, std::string>())
|
|
||||||
{
|
|
||||||
osg::ref_ptr<osg::Shader> shader (new osg::Shader(type));
|
|
||||||
|
|
||||||
// use boost in favor of osg::Shader::readShaderFile, to handle utf-8 path issues on Windows
|
|
||||||
boost::filesystem::ifstream inStream;
|
|
||||||
inStream.open(boost::filesystem::path(file));
|
|
||||||
std::stringstream strstream;
|
|
||||||
strstream << inStream.rdbuf();
|
|
||||||
|
|
||||||
std::string shaderSource = strstream.str();
|
|
||||||
|
|
||||||
for (std::map<std::string, std::string>::const_iterator it = defineMap.begin(); it != defineMap.end(); ++it)
|
|
||||||
{
|
|
||||||
size_t pos = shaderSource.find(it->first);
|
|
||||||
if (pos != std::string::npos)
|
|
||||||
shaderSource.replace(pos, it->first.length(), it->second);
|
|
||||||
}
|
|
||||||
|
|
||||||
shader->setShaderSource(shaderSource);
|
|
||||||
return shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
osg::ref_ptr<osg::Image> readPngImage (const std::string& file)
|
osg::ref_ptr<osg::Image> readPngImage (const std::string& file)
|
||||||
{
|
{
|
||||||
// use boost in favor of osgDB::readImage, to handle utf-8 path issues on Windows
|
// use boost in favor of osgDB::readImage, to handle utf-8 path issues on Windows
|
||||||
|
@ -524,10 +503,11 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R
|
||||||
{
|
{
|
||||||
// use a define map to conditionally compile the shader
|
// use a define map to conditionally compile the shader
|
||||||
std::map<std::string, std::string> defineMap;
|
std::map<std::string, std::string> defineMap;
|
||||||
defineMap.insert(std::make_pair(std::string("@refraction_enabled"), std::string(refraction ? "1" : "0")));
|
defineMap.insert(std::make_pair(std::string("refraction_enabled"), std::string(refraction ? "1" : "0")));
|
||||||
|
|
||||||
osg::ref_ptr<osg::Shader> vertexShader (readShader(osg::Shader::VERTEX, mResourcePath + "/shaders/water_vertex.glsl", defineMap));
|
Shader::ShaderManager& shaderMgr = mResourceSystem->getSceneManager()->getShaderManager();
|
||||||
osg::ref_ptr<osg::Shader> fragmentShader (readShader(osg::Shader::FRAGMENT, mResourcePath + "/shaders/water_fragment.glsl", defineMap));
|
osg::ref_ptr<osg::Shader> vertexShader (shaderMgr.getShader("water_vertex.glsl", defineMap, osg::Shader::VERTEX));
|
||||||
|
osg::ref_ptr<osg::Shader> fragmentShader (shaderMgr.getShader("water_fragment.glsl", defineMap, osg::Shader::FRAGMENT));
|
||||||
|
|
||||||
osg::ref_ptr<osg::Texture2D> normalMap (new osg::Texture2D(readPngImage(mResourcePath + "/shaders/water_nm.png")));
|
osg::ref_ptr<osg::Texture2D> normalMap (new osg::Texture2D(readPngImage(mResourcePath + "/shaders/water_nm.png")));
|
||||||
if (normalMap->getImage())
|
if (normalMap->getImage())
|
||||||
|
|
|
@ -411,26 +411,23 @@ namespace MWWorld
|
||||||
bool underwater = MWBase::Environment::get().getWorld()->isUnderwater(MWMechanics::getPlayer().getCell(), newPos);
|
bool underwater = MWBase::Environment::get().getWorld()->isUnderwater(MWMechanics::getPlayer().getCell(), newPos);
|
||||||
if (result.mHit || underwater)
|
if (result.mHit || underwater)
|
||||||
{
|
{
|
||||||
if (result.mHit)
|
MWWorld::ManualRef projectileRef(MWBase::Environment::get().getWorld()->getStore(), it->mIdArrow);
|
||||||
|
|
||||||
|
// Try to get a Ptr to the bow that was used. It might no longer exist.
|
||||||
|
MWWorld::Ptr bow = projectileRef.getPtr();
|
||||||
|
if (!caster.isEmpty() && it->mIdArrow != it->mBowId)
|
||||||
{
|
{
|
||||||
MWWorld::ManualRef projectileRef(MWBase::Environment::get().getWorld()->getStore(), it->mIdArrow);
|
MWWorld::InventoryStore& inv = caster.getClass().getInventoryStore(caster);
|
||||||
|
MWWorld::ContainerStoreIterator invIt = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||||
// Try to get a Ptr to the bow that was used. It might no longer exist.
|
if (invIt != inv.end() && Misc::StringUtils::ciEqual(invIt->getCellRef().getRefId(), it->mBowId))
|
||||||
MWWorld::Ptr bow = projectileRef.getPtr();
|
bow = *invIt;
|
||||||
if (!caster.isEmpty() && it->mIdArrow != it->mBowId)
|
|
||||||
{
|
|
||||||
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 = result.mHitObject;
|
|
||||||
|
|
||||||
MWMechanics::projectileHit(caster, result.mHitObject, bow, projectileRef.getPtr(), result.mHitPos, it->mAttackStrength);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (caster.isEmpty())
|
||||||
|
caster = result.mHitObject;
|
||||||
|
|
||||||
|
MWMechanics::projectileHit(caster, result.mHitObject, bow, projectileRef.getPtr(), result.mHit ? result.mHitPos : newPos, it->mAttackStrength);
|
||||||
|
|
||||||
if (underwater)
|
if (underwater)
|
||||||
mRendering->emitWaterRipple(newPos);
|
mRendering->emitWaterRipple(newPos);
|
||||||
|
|
||||||
|
|
|
@ -3268,8 +3268,8 @@ namespace MWWorld
|
||||||
mRendering->spawnEffect(model, textureOverride, worldPos);
|
mRendering->spawnEffect(model, textureOverride, worldPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::explodeSpell(const osg::Vec3f &origin, const ESM::EffectList &effects, const Ptr &caster, const Ptr& ignore,
|
void World::explodeSpell(const osg::Vec3f& origin, const ESM::EffectList& effects, const Ptr& caster, const Ptr& ignore, ESM::RangeType rangeType,
|
||||||
ESM::RangeType rangeType, const std::string& id, const std::string& sourceName)
|
const std::string& id, const std::string& sourceName, const bool fromProjectile)
|
||||||
{
|
{
|
||||||
std::map<MWWorld::Ptr, std::vector<ESM::ENAMstruct> > toApply;
|
std::map<MWWorld::Ptr, std::vector<ESM::ENAMstruct> > toApply;
|
||||||
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt = effects.mList.begin();
|
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt = effects.mList.begin();
|
||||||
|
@ -3280,8 +3280,8 @@ namespace MWWorld
|
||||||
if (effectIt->mRange != rangeType || (effectIt->mArea <= 0 && !ignore.isEmpty() && ignore.getClass().isActor()))
|
if (effectIt->mRange != rangeType || (effectIt->mArea <= 0 && !ignore.isEmpty() && ignore.getClass().isActor()))
|
||||||
continue; // Not right range type, or not area effect and hit an actor
|
continue; // Not right range type, or not area effect and hit an actor
|
||||||
|
|
||||||
if (effectIt->mRange == ESM::RT_Touch && (!ignore.isEmpty()) && (!ignore.getClass().isActor() && !ignore.getClass().canBeActivated(ignore)))
|
if (!fromProjectile && effectIt->mRange == ESM::RT_Touch && (!ignore.isEmpty()) && (!ignore.getClass().isActor() && !ignore.getClass().canBeActivated(ignore)))
|
||||||
continue; // Don't play explosion for touch spells on non-activatable objects
|
continue; // Don't play explosion for touch spells on non-activatable objects except when spell is from the projectile enchantment
|
||||||
|
|
||||||
// Spawn the explosion orb effect
|
// Spawn the explosion orb effect
|
||||||
const ESM::Static* areaStatic;
|
const ESM::Static* areaStatic;
|
||||||
|
|
|
@ -640,8 +640,9 @@ namespace MWWorld
|
||||||
|
|
||||||
virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos);
|
virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos);
|
||||||
|
|
||||||
virtual void explodeSpell (const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster,
|
virtual void explodeSpell(const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const MWWorld::Ptr& ignore,
|
||||||
const MWWorld::Ptr& ignore, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName);
|
ESM::RangeType rangeType, const std::string& id, const std::string& sourceName,
|
||||||
|
const bool fromProjectile=false);
|
||||||
|
|
||||||
virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor);
|
virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue