1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-03 13:45:34 +00:00

Add Bound & Summon effects (will need some adjustments later)

This commit is contained in:
scrawl 2013-11-21 03:39:55 +01:00
parent bf153e1c8e
commit 800a2845b0
6 changed files with 143 additions and 5 deletions

View file

@ -241,7 +241,7 @@ namespace MWBase
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).
virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false)

View file

@ -12,6 +12,8 @@
#include "../mwworld/class.hpp"
#include "../mwworld/inventorystore.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/manualref.hpp"
#include "../mwworld/actionequip.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
@ -27,6 +29,25 @@
#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
{
void Actors::updateActor (const MWWorld::Ptr& ptr, float duration)
@ -247,6 +268,118 @@ namespace MWMechanics
}
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)

View file

@ -171,6 +171,11 @@ namespace MWMechanics
void setLastHitObject(const std::string &objectid);
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;
};
}

View file

@ -92,8 +92,8 @@ namespace MWMechanics
MWWorld::Class::get(newItemPtr).applyEnchantment(newItemPtr, enchantmentPtr->mId, getGemCharge(), mNewItemName);
// Add the new item to player inventory and remove the old one
store.add(newItemPtr, player);
store.remove(mOldItemPtr, 1, player);
store.add(newItemPtr, player);
if(!mSelfEnchanting)
payForEnchantment();

View file

@ -1084,9 +1084,9 @@ namespace MWWorld
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

View file

@ -302,7 +302,7 @@ namespace MWWorld
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.
virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false)