forked from teamnwah/openmw-tes3coop
Add Bound & Summon effects (will need some adjustments later)
This commit is contained in:
parent
bf153e1c8e
commit
800a2845b0
6 changed files with 143 additions and 5 deletions
|
@ -241,7 +241,7 @@ namespace MWBase
|
||||||
|
|
||||||
virtual void localRotateObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0;
|
virtual void localRotateObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0;
|
||||||
|
|
||||||
virtual void safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos) = 0;
|
virtual MWWorld::Ptr safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos) = 0;
|
||||||
///< place an object in a "safe" location (ie not in the void, etc).
|
///< place an object in a "safe" location (ie not in the void, etc).
|
||||||
|
|
||||||
virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false)
|
virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false)
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/inventorystore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
#include "../mwworld/player.hpp"
|
#include "../mwworld/player.hpp"
|
||||||
|
#include "../mwworld/manualref.hpp"
|
||||||
|
#include "../mwworld/actionequip.hpp"
|
||||||
|
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
@ -27,6 +29,25 @@
|
||||||
|
|
||||||
#include "aicombat.hpp"
|
#include "aicombat.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& ptr)
|
||||||
|
{
|
||||||
|
if (bound)
|
||||||
|
{
|
||||||
|
MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), item, 1);
|
||||||
|
MWWorld::ActionEquip action(*ptr.getClass().getContainerStore(ptr).add(ref.getPtr(), ptr));
|
||||||
|
action.execute(ptr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ptr.getClass().getContainerStore(ptr).remove(item, 1, ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
void Actors::updateActor (const MWWorld::Ptr& ptr, float duration)
|
void Actors::updateActor (const MWWorld::Ptr& ptr, float duration)
|
||||||
|
@ -247,6 +268,118 @@ namespace MWMechanics
|
||||||
|
|
||||||
}
|
}
|
||||||
creatureStats.setHealth(health);
|
creatureStats.setHealth(health);
|
||||||
|
|
||||||
|
// TODO: dirty flag for magic effects to avoid some unnecessary work below?
|
||||||
|
|
||||||
|
// Update bound effects
|
||||||
|
static std::map<int, std::string> boundItemsMap;
|
||||||
|
if (boundItemsMap.empty())
|
||||||
|
{
|
||||||
|
boundItemsMap[ESM::MagicEffect::BoundBattleAxe] = "battle_axe";
|
||||||
|
boundItemsMap[ESM::MagicEffect::BoundBoots] = "boots";
|
||||||
|
boundItemsMap[ESM::MagicEffect::BoundCuirass] = "cuirass";
|
||||||
|
boundItemsMap[ESM::MagicEffect::BoundDagger] = "dagger";
|
||||||
|
boundItemsMap[ESM::MagicEffect::BoundGloves] = "gauntlet"; // Note: needs both _left and _right variants, see below
|
||||||
|
boundItemsMap[ESM::MagicEffect::BoundHelm] = "helm";
|
||||||
|
boundItemsMap[ESM::MagicEffect::BoundLongbow] = "longbow";
|
||||||
|
boundItemsMap[ESM::MagicEffect::BoundLongsword] = "longsword";
|
||||||
|
boundItemsMap[ESM::MagicEffect::BoundMace] = "mace";
|
||||||
|
boundItemsMap[ESM::MagicEffect::BoundShield] = "shield";
|
||||||
|
boundItemsMap[ESM::MagicEffect::BoundSpear] = "spear";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::map<int, std::string>::iterator it = boundItemsMap.begin(); it != boundItemsMap.end(); ++it)
|
||||||
|
{
|
||||||
|
bool found = creatureStats.mBoundItems.find(it->first) != creatureStats.mBoundItems.end();
|
||||||
|
int magnitude = creatureStats.getMagicEffects().get(EffectKey(it->first)).mMagnitude;
|
||||||
|
if (found != (magnitude > 0))
|
||||||
|
{
|
||||||
|
std::string item = "bound_" + it->second;
|
||||||
|
if (it->first == ESM::MagicEffect::BoundGloves)
|
||||||
|
{
|
||||||
|
adjustBoundItem(item + "_left", magnitude > 0, ptr);
|
||||||
|
adjustBoundItem(item + "_right", magnitude > 0, ptr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
adjustBoundItem(item, magnitude > 0, ptr);
|
||||||
|
|
||||||
|
if (magnitude > 0)
|
||||||
|
creatureStats.mBoundItems.insert(it->first);
|
||||||
|
else
|
||||||
|
creatureStats.mBoundItems.erase(it->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update summon effects
|
||||||
|
static std::map<int, std::string> summonMap;
|
||||||
|
if (summonMap.empty())
|
||||||
|
{
|
||||||
|
summonMap[ESM::MagicEffect::SummonAncestralGhost] = "ancestor_ghost_summon";
|
||||||
|
summonMap[ESM::MagicEffect::SummonBear] = "BM_bear_black_summon";
|
||||||
|
summonMap[ESM::MagicEffect::SummonBonelord] = "bonelord_summon";
|
||||||
|
summonMap[ESM::MagicEffect::SummonBonewalker] = "bonewalker_summon";
|
||||||
|
summonMap[ESM::MagicEffect::SummonBonewolf] = "BM_wolf_bone_summon";
|
||||||
|
summonMap[ESM::MagicEffect::SummonCenturionSphere] = "centurion_sphere_summon";
|
||||||
|
summonMap[ESM::MagicEffect::SummonClannfear] = "clannfear_summon";
|
||||||
|
summonMap[ESM::MagicEffect::SummonDaedroth] = "daedroth_summon";
|
||||||
|
summonMap[ESM::MagicEffect::SummonDremora] = "dremora_summon";
|
||||||
|
summonMap[ESM::MagicEffect::SummonFabricant] = "fabricant_summon";
|
||||||
|
summonMap[ESM::MagicEffect::SummonFlameAtronach] = "atronach_flame_summon";
|
||||||
|
summonMap[ESM::MagicEffect::SummonFrostAtronach] = "atronach_frost_summon";
|
||||||
|
summonMap[ESM::MagicEffect::SummonGoldenSaint] = "golden saint_summon";
|
||||||
|
summonMap[ESM::MagicEffect::SummonGreaterBonewalker] = "bonewalker_greater_summ";
|
||||||
|
summonMap[ESM::MagicEffect::SummonHunger] = "hunger_summon";
|
||||||
|
summonMap[ESM::MagicEffect::SummonScamp] = "scamp_summon";
|
||||||
|
summonMap[ESM::MagicEffect::SummonSkeletalMinion] = "skeleton_summon";
|
||||||
|
summonMap[ESM::MagicEffect::SummonStormAtronach] = "atronach_storm_summon";
|
||||||
|
summonMap[ESM::MagicEffect::SummonWingedTwilight] = "winged twilight_summon";
|
||||||
|
summonMap[ESM::MagicEffect::SummonWolf] = "BM_wolf_grey_summon";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::map<int, std::string>::iterator it = summonMap.begin(); it != summonMap.end(); ++it)
|
||||||
|
{
|
||||||
|
bool found = creatureStats.mSummonedCreatures.find(it->first) != creatureStats.mSummonedCreatures.end();
|
||||||
|
int magnitude = creatureStats.getMagicEffects().get(EffectKey(it->first)).mMagnitude;
|
||||||
|
if (found != (magnitude > 0))
|
||||||
|
{
|
||||||
|
if (magnitude > 0)
|
||||||
|
{
|
||||||
|
ESM::Position ipos = ptr.getRefData().getPosition();
|
||||||
|
Ogre::Vector3 pos(ipos.pos[0],ipos.pos[1],ipos.pos[2]);
|
||||||
|
Ogre::Quaternion rot(Ogre::Radian(-ipos.rot[2]), Ogre::Vector3::UNIT_Z);
|
||||||
|
const float distance = 50;
|
||||||
|
pos = pos + distance*rot.yAxis();
|
||||||
|
ipos.pos[0] = pos.x;
|
||||||
|
ipos.pos[1] = pos.y;
|
||||||
|
ipos.pos[2] = pos.z;
|
||||||
|
ipos.rot[0] = 0;
|
||||||
|
ipos.rot[1] = 0;
|
||||||
|
ipos.rot[2] = 0;
|
||||||
|
|
||||||
|
MWWorld::CellStore* store = ptr.getCell();
|
||||||
|
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), it->second, 1);
|
||||||
|
ref.getPtr().getCellRef().mPos = ipos;
|
||||||
|
|
||||||
|
// TODO: Add AI to follow player and fight for him
|
||||||
|
|
||||||
|
creatureStats.mSummonedCreatures.insert(std::make_pair(it->first,
|
||||||
|
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,ipos).getRefData().getHandle()));
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string handle = creatureStats.mSummonedCreatures[it->first];
|
||||||
|
// TODO: Show death animation before deleting? We shouldn't allow looting the corpse while the animation
|
||||||
|
// plays though, which is a rather lame exploit in vanilla.
|
||||||
|
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaHandle(handle);
|
||||||
|
if (!ptr.isEmpty())
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWorld()->deleteObject(ptr);
|
||||||
|
creatureStats.mSummonedCreatures.erase(it->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Actors::calculateNpcStatModifiers (const MWWorld::Ptr& ptr)
|
void Actors::calculateNpcStatModifiers (const MWWorld::Ptr& ptr)
|
||||||
|
|
|
@ -171,6 +171,11 @@ namespace MWMechanics
|
||||||
|
|
||||||
void setLastHitObject(const std::string &objectid);
|
void setLastHitObject(const std::string &objectid);
|
||||||
const std::string &getLastHitObject() const;
|
const std::string &getLastHitObject() const;
|
||||||
|
|
||||||
|
// Note, this is just a cache to avoid checking the whole container store every frame TODO: Put it somewhere else?
|
||||||
|
std::set<int> mBoundItems;
|
||||||
|
// Same as above
|
||||||
|
std::map<int, std::string> mSummonedCreatures;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,8 +92,8 @@ namespace MWMechanics
|
||||||
MWWorld::Class::get(newItemPtr).applyEnchantment(newItemPtr, enchantmentPtr->mId, getGemCharge(), mNewItemName);
|
MWWorld::Class::get(newItemPtr).applyEnchantment(newItemPtr, enchantmentPtr->mId, getGemCharge(), mNewItemName);
|
||||||
|
|
||||||
// Add the new item to player inventory and remove the old one
|
// Add the new item to player inventory and remove the old one
|
||||||
store.add(newItemPtr, player);
|
|
||||||
store.remove(mOldItemPtr, 1, player);
|
store.remove(mOldItemPtr, 1, player);
|
||||||
|
store.add(newItemPtr, player);
|
||||||
|
|
||||||
if(!mSelfEnchanting)
|
if(!mSelfEnchanting)
|
||||||
payForEnchantment();
|
payForEnchantment();
|
||||||
|
|
|
@ -1084,9 +1084,9 @@ namespace MWWorld
|
||||||
adjust);
|
adjust);
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos)
|
MWWorld::Ptr World::safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos)
|
||||||
{
|
{
|
||||||
copyObjectToCell(ptr,Cell,pos);
|
return copyObjectToCell(ptr,Cell,pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::indexToPosition (int cellX, int cellY, float &x, float &y, bool centre) const
|
void World::indexToPosition (int cellX, int cellY, float &x, float &y, bool centre) const
|
||||||
|
|
|
@ -302,7 +302,7 @@ namespace MWWorld
|
||||||
|
|
||||||
virtual void localRotateObject (const Ptr& ptr, float x, float y, float z);
|
virtual void localRotateObject (const Ptr& ptr, float x, float y, float z);
|
||||||
|
|
||||||
virtual void safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos);
|
virtual MWWorld::Ptr safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos);
|
||||||
///< place an object in a "safe" location (ie not in the void, etc). Makes a copy of the Ptr.
|
///< place an object in a "safe" location (ie not in the void, etc). Makes a copy of the Ptr.
|
||||||
|
|
||||||
virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false)
|
virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false)
|
||||||
|
|
Loading…
Reference in a new issue