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:
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 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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue